Merge remote-tracking branch 'tip/x86/cpufeature' into kvm-next
This commit is contained in:
commit
8494bd0e86
|
@ -196,13 +196,6 @@ chmod 0644 /dev/cpu/microcode
|
||||||
as root before you can use this. You'll probably also want to
|
as root before you can use this. You'll probably also want to
|
||||||
get the user-space microcode_ctl utility to use with this.
|
get the user-space microcode_ctl utility to use with this.
|
||||||
|
|
||||||
Powertweak
|
|
||||||
----------
|
|
||||||
|
|
||||||
If you are running v0.1.17 or earlier, you should upgrade to
|
|
||||||
version v0.99.0 or higher. Running old versions may cause problems
|
|
||||||
with programs using shared memory.
|
|
||||||
|
|
||||||
udev
|
udev
|
||||||
----
|
----
|
||||||
udev is a userspace application for populating /dev dynamically with
|
udev is a userspace application for populating /dev dynamically with
|
||||||
|
@ -366,10 +359,6 @@ Intel P6 microcode
|
||||||
------------------
|
------------------
|
||||||
o <http://www.urbanmyth.org/microcode/>
|
o <http://www.urbanmyth.org/microcode/>
|
||||||
|
|
||||||
Powertweak
|
|
||||||
----------
|
|
||||||
o <http://powertweak.sourceforge.net/>
|
|
||||||
|
|
||||||
udev
|
udev
|
||||||
----
|
----
|
||||||
o <http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html>
|
o <http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html>
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
</sect1>
|
</sect1>
|
||||||
<sect1><title>Wait queues and Wake events</title>
|
<sect1><title>Wait queues and Wake events</title>
|
||||||
!Iinclude/linux/wait.h
|
!Iinclude/linux/wait.h
|
||||||
!Ekernel/wait.c
|
!Ekernel/sched/wait.c
|
||||||
</sect1>
|
</sect1>
|
||||||
<sect1><title>High-resolution timers</title>
|
<sect1><title>High-resolution timers</title>
|
||||||
!Iinclude/linux/ktime.h
|
!Iinclude/linux/ktime.h
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
I2C for OMAP platforms
|
I2C for OMAP platforms
|
||||||
|
|
||||||
Required properties :
|
Required properties :
|
||||||
- compatible : Must be "ti,omap3-i2c" or "ti,omap4-i2c"
|
- compatible : Must be "ti,omap2420-i2c", "ti,omap2430-i2c", "ti,omap3-i2c"
|
||||||
|
or "ti,omap4-i2c"
|
||||||
- ti,hwmods : Must be "i2c<n>", n being the instance number (1-based)
|
- ti,hwmods : Must be "i2c<n>", n being the instance number (1-based)
|
||||||
- #address-cells = <1>;
|
- #address-cells = <1>;
|
||||||
- #size-cells = <0>;
|
- #size-cells = <0>;
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
Qualcomm MSM pseudo random number generator.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
|
||||||
|
- compatible : should be "qcom,prng"
|
||||||
|
- reg : specifies base physical address and size of the registers map
|
||||||
|
- clocks : phandle to clock-controller plus clock-specifier pair
|
||||||
|
- clock-names : "core" clocks all registers, FIFO and circuits in PRNG IP block
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
rng@f9bff000 {
|
||||||
|
compatible = "qcom,prng";
|
||||||
|
reg = <0xf9bff000 0x200>;
|
||||||
|
clocks = <&clock GCC_PRNG_AHB_CLK>;
|
||||||
|
clock-names = "core";
|
||||||
|
};
|
|
@ -0,0 +1,115 @@
|
||||||
|
GPIO Mappings
|
||||||
|
=============
|
||||||
|
|
||||||
|
This document explains how GPIOs can be assigned to given devices and functions.
|
||||||
|
Note that it only applies to the new descriptor-based interface. For a
|
||||||
|
description of the deprecated integer-based GPIO interface please refer to
|
||||||
|
gpio-legacy.txt (actually, there is no real mapping possible with the old
|
||||||
|
interface; you just fetch an integer from somewhere and request the
|
||||||
|
corresponding GPIO.
|
||||||
|
|
||||||
|
Platforms that make use of GPIOs must select ARCH_REQUIRE_GPIOLIB (if GPIO usage
|
||||||
|
is mandatory) or ARCH_WANT_OPTIONAL_GPIOLIB (if GPIO support can be omitted) in
|
||||||
|
their Kconfig. Then, how GPIOs are mapped depends on what the platform uses to
|
||||||
|
describe its hardware layout. Currently, mappings can be defined through device
|
||||||
|
tree, ACPI, and platform data.
|
||||||
|
|
||||||
|
Device Tree
|
||||||
|
-----------
|
||||||
|
GPIOs can easily be mapped to devices and functions in the device tree. The
|
||||||
|
exact way to do it depends on the GPIO controller providing the GPIOs, see the
|
||||||
|
device tree bindings for your controller.
|
||||||
|
|
||||||
|
GPIOs mappings are defined in the consumer device's node, in a property named
|
||||||
|
<function>-gpios, where <function> is the function the driver will request
|
||||||
|
through gpiod_get(). For example:
|
||||||
|
|
||||||
|
foo_device {
|
||||||
|
compatible = "acme,foo";
|
||||||
|
...
|
||||||
|
led-gpios = <&gpio 15 GPIO_ACTIVE_HIGH>, /* red */
|
||||||
|
<&gpio 16 GPIO_ACTIVE_HIGH>, /* green */
|
||||||
|
<&gpio 17 GPIO_ACTIVE_HIGH>; /* blue */
|
||||||
|
|
||||||
|
power-gpio = <&gpio 1 GPIO_ACTIVE_LOW>;
|
||||||
|
};
|
||||||
|
|
||||||
|
This property will make GPIOs 15, 16 and 17 available to the driver under the
|
||||||
|
"led" function, and GPIO 1 as the "power" GPIO:
|
||||||
|
|
||||||
|
struct gpio_desc *red, *green, *blue, *power;
|
||||||
|
|
||||||
|
red = gpiod_get_index(dev, "led", 0);
|
||||||
|
green = gpiod_get_index(dev, "led", 1);
|
||||||
|
blue = gpiod_get_index(dev, "led", 2);
|
||||||
|
|
||||||
|
power = gpiod_get(dev, "power");
|
||||||
|
|
||||||
|
The led GPIOs will be active-high, while the power GPIO will be active-low (i.e.
|
||||||
|
gpiod_is_active_low(power) will be true).
|
||||||
|
|
||||||
|
ACPI
|
||||||
|
----
|
||||||
|
ACPI does not support function names for GPIOs. Therefore, only the "idx"
|
||||||
|
argument of gpiod_get_index() is useful to discriminate between GPIOs assigned
|
||||||
|
to a device. The "con_id" argument can still be set for debugging purposes (it
|
||||||
|
will appear under error messages as well as debug and sysfs nodes).
|
||||||
|
|
||||||
|
Platform Data
|
||||||
|
-------------
|
||||||
|
Finally, GPIOs can be bound to devices and functions using platform data. Board
|
||||||
|
files that desire to do so need to include the following header:
|
||||||
|
|
||||||
|
#include <linux/gpio/driver.h>
|
||||||
|
|
||||||
|
GPIOs are mapped by the means of tables of lookups, containing instances of the
|
||||||
|
gpiod_lookup structure. Two macros are defined to help declaring such mappings:
|
||||||
|
|
||||||
|
GPIO_LOOKUP(chip_label, chip_hwnum, dev_id, con_id, flags)
|
||||||
|
GPIO_LOOKUP_IDX(chip_label, chip_hwnum, dev_id, con_id, idx, flags)
|
||||||
|
|
||||||
|
where
|
||||||
|
|
||||||
|
- chip_label is the label of the gpiod_chip instance providing the GPIO
|
||||||
|
- chip_hwnum is the hardware number of the GPIO within the chip
|
||||||
|
- dev_id is the identifier of the device that will make use of this GPIO. If
|
||||||
|
NULL, the GPIO will be available to all devices.
|
||||||
|
- con_id is the name of the GPIO function from the device point of view. It
|
||||||
|
can be NULL.
|
||||||
|
- idx is the index of the GPIO within the function.
|
||||||
|
- flags is defined to specify the following properties:
|
||||||
|
* GPIOF_ACTIVE_LOW - to configure the GPIO as active-low
|
||||||
|
* GPIOF_OPEN_DRAIN - GPIO pin is open drain type.
|
||||||
|
* GPIOF_OPEN_SOURCE - GPIO pin is open source type.
|
||||||
|
|
||||||
|
In the future, these flags might be extended to support more properties.
|
||||||
|
|
||||||
|
Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0.
|
||||||
|
|
||||||
|
A lookup table can then be defined as follows:
|
||||||
|
|
||||||
|
struct gpiod_lookup gpios_table[] = {
|
||||||
|
GPIO_LOOKUP_IDX("gpio.0", 15, "foo.0", "led", 0, GPIO_ACTIVE_HIGH),
|
||||||
|
GPIO_LOOKUP_IDX("gpio.0", 16, "foo.0", "led", 1, GPIO_ACTIVE_HIGH),
|
||||||
|
GPIO_LOOKUP_IDX("gpio.0", 17, "foo.0", "led", 2, GPIO_ACTIVE_HIGH),
|
||||||
|
GPIO_LOOKUP("gpio.0", 1, "foo.0", "power", GPIO_ACTIVE_LOW),
|
||||||
|
};
|
||||||
|
|
||||||
|
And the table can be added by the board code as follows:
|
||||||
|
|
||||||
|
gpiod_add_table(gpios_table, ARRAY_SIZE(gpios_table));
|
||||||
|
|
||||||
|
The driver controlling "foo.0" will then be able to obtain its GPIOs as follows:
|
||||||
|
|
||||||
|
struct gpio_desc *red, *green, *blue, *power;
|
||||||
|
|
||||||
|
red = gpiod_get_index(dev, "led", 0);
|
||||||
|
green = gpiod_get_index(dev, "led", 1);
|
||||||
|
blue = gpiod_get_index(dev, "led", 2);
|
||||||
|
|
||||||
|
power = gpiod_get(dev, "power");
|
||||||
|
gpiod_direction_output(power, 1);
|
||||||
|
|
||||||
|
Since the "power" GPIO is mapped as active-low, its actual signal will be 0
|
||||||
|
after this code. Contrary to the legacy integer GPIO interface, the active-low
|
||||||
|
property is handled during mapping and is thus transparent to GPIO consumers.
|
|
@ -0,0 +1,197 @@
|
||||||
|
GPIO Descriptor Consumer Interface
|
||||||
|
==================================
|
||||||
|
|
||||||
|
This document describes the consumer interface of the GPIO framework. Note that
|
||||||
|
it describes the new descriptor-based interface. For a description of the
|
||||||
|
deprecated integer-based GPIO interface please refer to gpio-legacy.txt.
|
||||||
|
|
||||||
|
|
||||||
|
Guidelines for GPIOs consumers
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Drivers that can't work without standard GPIO calls should have Kconfig entries
|
||||||
|
that depend on GPIOLIB. The functions that allow a driver to obtain and use
|
||||||
|
GPIOs are available by including the following file:
|
||||||
|
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
|
|
||||||
|
All the functions that work with the descriptor-based GPIO interface are
|
||||||
|
prefixed with gpiod_. The gpio_ prefix is used for the legacy interface. No
|
||||||
|
other function in the kernel should use these prefixes.
|
||||||
|
|
||||||
|
|
||||||
|
Obtaining and Disposing GPIOs
|
||||||
|
=============================
|
||||||
|
|
||||||
|
With the descriptor-based interface, GPIOs are identified with an opaque,
|
||||||
|
non-forgeable handler that must be obtained through a call to one of the
|
||||||
|
gpiod_get() functions. Like many other kernel subsystems, gpiod_get() takes the
|
||||||
|
device that will use the GPIO and the function the requested GPIO is supposed to
|
||||||
|
fulfill:
|
||||||
|
|
||||||
|
struct gpio_desc *gpiod_get(struct device *dev, const char *con_id)
|
||||||
|
|
||||||
|
If a function is implemented by using several GPIOs together (e.g. a simple LED
|
||||||
|
device that displays digits), an additional index argument can be specified:
|
||||||
|
|
||||||
|
struct gpio_desc *gpiod_get_index(struct device *dev,
|
||||||
|
const char *con_id, unsigned int idx)
|
||||||
|
|
||||||
|
Both functions return either a valid GPIO descriptor, or an error code checkable
|
||||||
|
with IS_ERR(). They will never return a NULL pointer.
|
||||||
|
|
||||||
|
Device-managed variants of these functions are also defined:
|
||||||
|
|
||||||
|
struct gpio_desc *devm_gpiod_get(struct device *dev, const char *con_id)
|
||||||
|
|
||||||
|
struct gpio_desc *devm_gpiod_get_index(struct device *dev,
|
||||||
|
const char *con_id,
|
||||||
|
unsigned int idx)
|
||||||
|
|
||||||
|
A GPIO descriptor can be disposed of using the gpiod_put() function:
|
||||||
|
|
||||||
|
void gpiod_put(struct gpio_desc *desc)
|
||||||
|
|
||||||
|
It is strictly forbidden to use a descriptor after calling this function. The
|
||||||
|
device-managed variant is, unsurprisingly:
|
||||||
|
|
||||||
|
void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
|
||||||
|
|
||||||
|
|
||||||
|
Using GPIOs
|
||||||
|
===========
|
||||||
|
|
||||||
|
Setting Direction
|
||||||
|
-----------------
|
||||||
|
The first thing a driver must do with a GPIO is setting its direction. This is
|
||||||
|
done by invoking one of the gpiod_direction_*() functions:
|
||||||
|
|
||||||
|
int gpiod_direction_input(struct gpio_desc *desc)
|
||||||
|
int gpiod_direction_output(struct gpio_desc *desc, int value)
|
||||||
|
|
||||||
|
The return value is zero for success, else a negative errno. It should be
|
||||||
|
checked, since the get/set calls don't return errors and since misconfiguration
|
||||||
|
is possible. You should normally issue these calls from a task context. However,
|
||||||
|
for spinlock-safe GPIOs it is OK to use them before tasking is enabled, as part
|
||||||
|
of early board setup.
|
||||||
|
|
||||||
|
For output GPIOs, the value provided becomes the initial output value. This
|
||||||
|
helps avoid signal glitching during system startup.
|
||||||
|
|
||||||
|
A driver can also query the current direction of a GPIO:
|
||||||
|
|
||||||
|
int gpiod_get_direction(const struct gpio_desc *desc)
|
||||||
|
|
||||||
|
This function will return either GPIOF_DIR_IN or GPIOF_DIR_OUT.
|
||||||
|
|
||||||
|
Be aware that there is no default direction for GPIOs. Therefore, **using a GPIO
|
||||||
|
without setting its direction first is illegal and will result in undefined
|
||||||
|
behavior!**
|
||||||
|
|
||||||
|
|
||||||
|
Spinlock-Safe GPIO Access
|
||||||
|
-------------------------
|
||||||
|
Most GPIO controllers can be accessed with memory read/write instructions. Those
|
||||||
|
don't need to sleep, and can safely be done from inside hard (non-threaded) IRQ
|
||||||
|
handlers and similar contexts.
|
||||||
|
|
||||||
|
Use the following calls to access GPIOs from an atomic context:
|
||||||
|
|
||||||
|
int gpiod_get_value(const struct gpio_desc *desc);
|
||||||
|
void gpiod_set_value(struct gpio_desc *desc, int value);
|
||||||
|
|
||||||
|
The values are boolean, zero for low, nonzero for high. When reading the value
|
||||||
|
of an output pin, the value returned should be what's seen on the pin. That
|
||||||
|
won't always match the specified output value, because of issues including
|
||||||
|
open-drain signaling and output latencies.
|
||||||
|
|
||||||
|
The get/set calls do not return errors because "invalid GPIO" should have been
|
||||||
|
reported earlier from gpiod_direction_*(). However, note that not all platforms
|
||||||
|
can read the value of output pins; those that can't should always return zero.
|
||||||
|
Also, using these calls for GPIOs that can't safely be accessed without sleeping
|
||||||
|
(see below) is an error.
|
||||||
|
|
||||||
|
|
||||||
|
GPIO Access That May Sleep
|
||||||
|
--------------------------
|
||||||
|
Some GPIO controllers must be accessed using message based buses like I2C or
|
||||||
|
SPI. Commands to read or write those GPIO values require waiting to get to the
|
||||||
|
head of a queue to transmit a command and get its response. This requires
|
||||||
|
sleeping, which can't be done from inside IRQ handlers.
|
||||||
|
|
||||||
|
Platforms that support this type of GPIO distinguish them from other GPIOs by
|
||||||
|
returning nonzero from this call:
|
||||||
|
|
||||||
|
int gpiod_cansleep(const struct gpio_desc *desc)
|
||||||
|
|
||||||
|
To access such GPIOs, a different set of accessors is defined:
|
||||||
|
|
||||||
|
int gpiod_get_value_cansleep(const struct gpio_desc *desc)
|
||||||
|
void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
|
||||||
|
|
||||||
|
Accessing such GPIOs requires a context which may sleep, for example a threaded
|
||||||
|
IRQ handler, and those accessors must be used instead of spinlock-safe
|
||||||
|
accessors without the cansleep() name suffix.
|
||||||
|
|
||||||
|
Other than the fact that these accessors might sleep, and will work on GPIOs
|
||||||
|
that can't be accessed from hardIRQ handlers, these calls act the same as the
|
||||||
|
spinlock-safe calls.
|
||||||
|
|
||||||
|
|
||||||
|
Active-low State and Raw GPIO Values
|
||||||
|
------------------------------------
|
||||||
|
Device drivers like to manage the logical state of a GPIO, i.e. the value their
|
||||||
|
device will actually receive, no matter what lies between it and the GPIO line.
|
||||||
|
In some cases, it might make sense to control the actual GPIO line value. The
|
||||||
|
following set of calls ignore the active-low property of a GPIO and work on the
|
||||||
|
raw line value:
|
||||||
|
|
||||||
|
int gpiod_get_raw_value(const struct gpio_desc *desc)
|
||||||
|
void gpiod_set_raw_value(struct gpio_desc *desc, int value)
|
||||||
|
int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
|
||||||
|
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value)
|
||||||
|
|
||||||
|
The active-low state of a GPIO can also be queried using the following call:
|
||||||
|
|
||||||
|
int gpiod_is_active_low(const struct gpio_desc *desc)
|
||||||
|
|
||||||
|
Note that these functions should only be used with great moderation ; a driver
|
||||||
|
should not have to care about the physical line level.
|
||||||
|
|
||||||
|
GPIOs mapped to IRQs
|
||||||
|
--------------------
|
||||||
|
GPIO lines can quite often be used as IRQs. You can get the IRQ number
|
||||||
|
corresponding to a given GPIO using the following call:
|
||||||
|
|
||||||
|
int gpiod_to_irq(const struct gpio_desc *desc)
|
||||||
|
|
||||||
|
It will return an IRQ number, or an negative errno code if the mapping can't be
|
||||||
|
done (most likely because that particular GPIO cannot be used as IRQ). It is an
|
||||||
|
unchecked error to use a GPIO that wasn't set up as an input using
|
||||||
|
gpiod_direction_input(), or to use an IRQ number that didn't originally come
|
||||||
|
from gpiod_to_irq(). gpiod_to_irq() is not allowed to sleep.
|
||||||
|
|
||||||
|
Non-error values returned from gpiod_to_irq() can be passed to request_irq() or
|
||||||
|
free_irq(). They will often be stored into IRQ resources for platform devices,
|
||||||
|
by the board-specific initialization code. Note that IRQ trigger options are
|
||||||
|
part of the IRQ interface, e.g. IRQF_TRIGGER_FALLING, as are system wakeup
|
||||||
|
capabilities.
|
||||||
|
|
||||||
|
|
||||||
|
Interacting With the Legacy GPIO Subsystem
|
||||||
|
==========================================
|
||||||
|
Many kernel subsystems still handle GPIOs using the legacy integer-based
|
||||||
|
interface. Although it is strongly encouraged to upgrade them to the safer
|
||||||
|
descriptor-based API, the following two functions allow you to convert a GPIO
|
||||||
|
descriptor into the GPIO integer namespace and vice-versa:
|
||||||
|
|
||||||
|
int desc_to_gpio(const struct gpio_desc *desc)
|
||||||
|
struct gpio_desc *gpio_to_desc(unsigned gpio)
|
||||||
|
|
||||||
|
The GPIO number returned by desc_to_gpio() can be safely used as long as the
|
||||||
|
GPIO descriptor has not been freed. All the same, a GPIO number passed to
|
||||||
|
gpio_to_desc() must have been properly acquired, and usage of the returned GPIO
|
||||||
|
descriptor is only possible after the GPIO number has been released.
|
||||||
|
|
||||||
|
Freeing a GPIO obtained by one API with the other API is forbidden and an
|
||||||
|
unchecked error.
|
|
@ -0,0 +1,75 @@
|
||||||
|
GPIO Descriptor Driver Interface
|
||||||
|
================================
|
||||||
|
|
||||||
|
This document serves as a guide for GPIO chip drivers writers. Note that it
|
||||||
|
describes the new descriptor-based interface. For a description of the
|
||||||
|
deprecated integer-based GPIO interface please refer to gpio-legacy.txt.
|
||||||
|
|
||||||
|
Each GPIO controller driver needs to include the following header, which defines
|
||||||
|
the structures used to define a GPIO driver:
|
||||||
|
|
||||||
|
#include <linux/gpio/driver.h>
|
||||||
|
|
||||||
|
|
||||||
|
Internal Representation of GPIOs
|
||||||
|
================================
|
||||||
|
|
||||||
|
Inside a GPIO driver, individual GPIOs are identified by their hardware number,
|
||||||
|
which is a unique number between 0 and n, n being the number of GPIOs managed by
|
||||||
|
the chip. This number is purely internal: the hardware number of a particular
|
||||||
|
GPIO descriptor is never made visible outside of the driver.
|
||||||
|
|
||||||
|
On top of this internal number, each GPIO also need to have a global number in
|
||||||
|
the integer GPIO namespace so that it can be used with the legacy GPIO
|
||||||
|
interface. Each chip must thus have a "base" number (which can be automatically
|
||||||
|
assigned), and for each GPIO the global number will be (base + hardware number).
|
||||||
|
Although the integer representation is considered deprecated, it still has many
|
||||||
|
users and thus needs to be maintained.
|
||||||
|
|
||||||
|
So for example one platform could use numbers 32-159 for GPIOs, with a
|
||||||
|
controller defining 128 GPIOs at a "base" of 32 ; while another platform uses
|
||||||
|
numbers 0..63 with one set of GPIO controllers, 64-79 with another type of GPIO
|
||||||
|
controller, and on one particular board 80-95 with an FPGA. The numbers need not
|
||||||
|
be contiguous; either of those platforms could also use numbers 2000-2063 to
|
||||||
|
identify GPIOs in a bank of I2C GPIO expanders.
|
||||||
|
|
||||||
|
|
||||||
|
Controller Drivers: gpio_chip
|
||||||
|
=============================
|
||||||
|
|
||||||
|
In the gpiolib framework each GPIO controller is packaged as a "struct
|
||||||
|
gpio_chip" (see linux/gpio/driver.h for its complete definition) with members
|
||||||
|
common to each controller of that type:
|
||||||
|
|
||||||
|
- methods to establish GPIO direction
|
||||||
|
- methods used to access GPIO values
|
||||||
|
- method to return the IRQ number associated to a given GPIO
|
||||||
|
- flag saying whether calls to its methods may sleep
|
||||||
|
- optional debugfs dump method (showing extra state like pullup config)
|
||||||
|
- optional base number (will be automatically assigned if omitted)
|
||||||
|
- label for diagnostics and GPIOs mapping using platform data
|
||||||
|
|
||||||
|
The code implementing a gpio_chip should support multiple instances of the
|
||||||
|
controller, possibly using the driver model. That code will configure each
|
||||||
|
gpio_chip and issue gpiochip_add(). Removing a GPIO controller should be rare;
|
||||||
|
use gpiochip_remove() when it is unavoidable.
|
||||||
|
|
||||||
|
Most often a gpio_chip is part of an instance-specific structure with state not
|
||||||
|
exposed by the GPIO interfaces, such as addressing, power management, and more.
|
||||||
|
Chips such as codecs will have complex non-GPIO state.
|
||||||
|
|
||||||
|
Any debugfs dump method should normally ignore signals which haven't been
|
||||||
|
requested as GPIOs. They can use gpiochip_is_requested(), which returns either
|
||||||
|
NULL or the label associated with that GPIO when it was requested.
|
||||||
|
|
||||||
|
Locking IRQ usage
|
||||||
|
-----------------
|
||||||
|
Input GPIOs can be used as IRQ signals. When this happens, a driver is requested
|
||||||
|
to mark the GPIO as being used as an IRQ:
|
||||||
|
|
||||||
|
int gpiod_lock_as_irq(struct gpio_desc *desc)
|
||||||
|
|
||||||
|
This will prevent the use of non-irq related GPIO APIs until the GPIO IRQ lock
|
||||||
|
is released:
|
||||||
|
|
||||||
|
void gpiod_unlock_as_irq(struct gpio_desc *desc)
|
|
@ -0,0 +1,119 @@
|
||||||
|
GPIO Interfaces
|
||||||
|
===============
|
||||||
|
|
||||||
|
The documents in this directory give detailed instructions on how to access
|
||||||
|
GPIOs in drivers, and how to write a driver for a device that provides GPIOs
|
||||||
|
itself.
|
||||||
|
|
||||||
|
Due to the history of GPIO interfaces in the kernel, there are two different
|
||||||
|
ways to obtain and use GPIOs:
|
||||||
|
|
||||||
|
- The descriptor-based interface is the preferred way to manipulate GPIOs,
|
||||||
|
and is described by all the files in this directory excepted gpio-legacy.txt.
|
||||||
|
- The legacy integer-based interface which is considered deprecated (but still
|
||||||
|
usable for compatibility reasons) is documented in gpio-legacy.txt.
|
||||||
|
|
||||||
|
The remainder of this document applies to the new descriptor-based interface.
|
||||||
|
gpio-legacy.txt contains the same information applied to the legacy
|
||||||
|
integer-based interface.
|
||||||
|
|
||||||
|
|
||||||
|
What is a GPIO?
|
||||||
|
===============
|
||||||
|
|
||||||
|
A "General Purpose Input/Output" (GPIO) is a flexible software-controlled
|
||||||
|
digital signal. They are provided from many kinds of chip, and are familiar
|
||||||
|
to Linux developers working with embedded and custom hardware. Each GPIO
|
||||||
|
represents a bit connected to a particular pin, or "ball" on Ball Grid Array
|
||||||
|
(BGA) packages. Board schematics show which external hardware connects to
|
||||||
|
which GPIOs. Drivers can be written generically, so that board setup code
|
||||||
|
passes such pin configuration data to drivers.
|
||||||
|
|
||||||
|
System-on-Chip (SOC) processors heavily rely on GPIOs. In some cases, every
|
||||||
|
non-dedicated pin can be configured as a GPIO; and most chips have at least
|
||||||
|
several dozen of them. Programmable logic devices (like FPGAs) can easily
|
||||||
|
provide GPIOs; multifunction chips like power managers, and audio codecs
|
||||||
|
often have a few such pins to help with pin scarcity on SOCs; and there are
|
||||||
|
also "GPIO Expander" chips that connect using the I2C or SPI serial buses.
|
||||||
|
Most PC southbridges have a few dozen GPIO-capable pins (with only the BIOS
|
||||||
|
firmware knowing how they're used).
|
||||||
|
|
||||||
|
The exact capabilities of GPIOs vary between systems. Common options:
|
||||||
|
|
||||||
|
- Output values are writable (high=1, low=0). Some chips also have
|
||||||
|
options about how that value is driven, so that for example only one
|
||||||
|
value might be driven, supporting "wire-OR" and similar schemes for the
|
||||||
|
other value (notably, "open drain" signaling).
|
||||||
|
|
||||||
|
- Input values are likewise readable (1, 0). Some chips support readback
|
||||||
|
of pins configured as "output", which is very useful in such "wire-OR"
|
||||||
|
cases (to support bidirectional signaling). GPIO controllers may have
|
||||||
|
input de-glitch/debounce logic, sometimes with software controls.
|
||||||
|
|
||||||
|
- Inputs can often be used as IRQ signals, often edge triggered but
|
||||||
|
sometimes level triggered. Such IRQs may be configurable as system
|
||||||
|
wakeup events, to wake the system from a low power state.
|
||||||
|
|
||||||
|
- Usually a GPIO will be configurable as either input or output, as needed
|
||||||
|
by different product boards; single direction ones exist too.
|
||||||
|
|
||||||
|
- Most GPIOs can be accessed while holding spinlocks, but those accessed
|
||||||
|
through a serial bus normally can't. Some systems support both types.
|
||||||
|
|
||||||
|
On a given board each GPIO is used for one specific purpose like monitoring
|
||||||
|
MMC/SD card insertion/removal, detecting card write-protect status, driving
|
||||||
|
a LED, configuring a transceiver, bit-banging a serial bus, poking a hardware
|
||||||
|
watchdog, sensing a switch, and so on.
|
||||||
|
|
||||||
|
|
||||||
|
Common GPIO Properties
|
||||||
|
======================
|
||||||
|
|
||||||
|
These properties are met through all the other documents of the GPIO interface
|
||||||
|
and it is useful to understand them, especially if you need to define GPIO
|
||||||
|
mappings.
|
||||||
|
|
||||||
|
Active-High and Active-Low
|
||||||
|
--------------------------
|
||||||
|
It is natural to assume that a GPIO is "active" when its output signal is 1
|
||||||
|
("high"), and inactive when it is 0 ("low"). However in practice the signal of a
|
||||||
|
GPIO may be inverted before is reaches its destination, or a device could decide
|
||||||
|
to have different conventions about what "active" means. Such decisions should
|
||||||
|
be transparent to device drivers, therefore it is possible to define a GPIO as
|
||||||
|
being either active-high ("1" means "active", the default) or active-low ("0"
|
||||||
|
means "active") so that drivers only need to worry about the logical signal and
|
||||||
|
not about what happens at the line level.
|
||||||
|
|
||||||
|
Open Drain and Open Source
|
||||||
|
--------------------------
|
||||||
|
Sometimes shared signals need to use "open drain" (where only the low signal
|
||||||
|
level is actually driven), or "open source" (where only the high signal level is
|
||||||
|
driven) signaling. That term applies to CMOS transistors; "open collector" is
|
||||||
|
used for TTL. A pullup or pulldown resistor causes the high or low signal level.
|
||||||
|
This is sometimes called a "wire-AND"; or more practically, from the negative
|
||||||
|
logic (low=true) perspective this is a "wire-OR".
|
||||||
|
|
||||||
|
One common example of an open drain signal is a shared active-low IRQ line.
|
||||||
|
Also, bidirectional data bus signals sometimes use open drain signals.
|
||||||
|
|
||||||
|
Some GPIO controllers directly support open drain and open source outputs; many
|
||||||
|
don't. When you need open drain signaling but your hardware doesn't directly
|
||||||
|
support it, there's a common idiom you can use to emulate it with any GPIO pin
|
||||||
|
that can be used as either an input or an output:
|
||||||
|
|
||||||
|
LOW: gpiod_direction_output(gpio, 0) ... this drives the signal and overrides
|
||||||
|
the pullup.
|
||||||
|
|
||||||
|
HIGH: gpiod_direction_input(gpio) ... this turns off the output, so the pullup
|
||||||
|
(or some other device) controls the signal.
|
||||||
|
|
||||||
|
The same logic can be applied to emulate open source signaling, by driving the
|
||||||
|
high signal and configuring the GPIO as input for low. This open drain/open
|
||||||
|
source emulation can be handled transparently by the GPIO framework.
|
||||||
|
|
||||||
|
If you are "driving" the signal high but gpiod_get_value(gpio) reports a low
|
||||||
|
value (after the appropriate rise time passes), you know some other component is
|
||||||
|
driving the shared signal low. That's not necessarily an error. As one common
|
||||||
|
example, that's how I2C clocks are stretched: a slave that needs a slower clock
|
||||||
|
delays the rising edge of SCK, and the I2C master adjusts its signaling rate
|
||||||
|
accordingly.
|
|
@ -0,0 +1,155 @@
|
||||||
|
GPIO Sysfs Interface for Userspace
|
||||||
|
==================================
|
||||||
|
|
||||||
|
Platforms which use the "gpiolib" implementors framework may choose to
|
||||||
|
configure a sysfs user interface to GPIOs. This is different from the
|
||||||
|
debugfs interface, since it provides control over GPIO direction and
|
||||||
|
value instead of just showing a gpio state summary. Plus, it could be
|
||||||
|
present on production systems without debugging support.
|
||||||
|
|
||||||
|
Given appropriate hardware documentation for the system, userspace could
|
||||||
|
know for example that GPIO #23 controls the write protect line used to
|
||||||
|
protect boot loader segments in flash memory. System upgrade procedures
|
||||||
|
may need to temporarily remove that protection, first importing a GPIO,
|
||||||
|
then changing its output state, then updating the code before re-enabling
|
||||||
|
the write protection. In normal use, GPIO #23 would never be touched,
|
||||||
|
and the kernel would have no need to know about it.
|
||||||
|
|
||||||
|
Again depending on appropriate hardware documentation, on some systems
|
||||||
|
userspace GPIO can be used to determine system configuration data that
|
||||||
|
standard kernels won't know about. And for some tasks, simple userspace
|
||||||
|
GPIO drivers could be all that the system really needs.
|
||||||
|
|
||||||
|
Note that standard kernel drivers exist for common "LEDs and Buttons"
|
||||||
|
GPIO tasks: "leds-gpio" and "gpio_keys", respectively. Use those
|
||||||
|
instead of talking directly to the GPIOs; they integrate with kernel
|
||||||
|
frameworks better than your userspace code could.
|
||||||
|
|
||||||
|
|
||||||
|
Paths in Sysfs
|
||||||
|
--------------
|
||||||
|
There are three kinds of entry in /sys/class/gpio:
|
||||||
|
|
||||||
|
- Control interfaces used to get userspace control over GPIOs;
|
||||||
|
|
||||||
|
- GPIOs themselves; and
|
||||||
|
|
||||||
|
- GPIO controllers ("gpio_chip" instances).
|
||||||
|
|
||||||
|
That's in addition to standard files including the "device" symlink.
|
||||||
|
|
||||||
|
The control interfaces are write-only:
|
||||||
|
|
||||||
|
/sys/class/gpio/
|
||||||
|
|
||||||
|
"export" ... Userspace may ask the kernel to export control of
|
||||||
|
a GPIO to userspace by writing its number to this file.
|
||||||
|
|
||||||
|
Example: "echo 19 > export" will create a "gpio19" node
|
||||||
|
for GPIO #19, if that's not requested by kernel code.
|
||||||
|
|
||||||
|
"unexport" ... Reverses the effect of exporting to userspace.
|
||||||
|
|
||||||
|
Example: "echo 19 > unexport" will remove a "gpio19"
|
||||||
|
node exported using the "export" file.
|
||||||
|
|
||||||
|
GPIO signals have paths like /sys/class/gpio/gpio42/ (for GPIO #42)
|
||||||
|
and have the following read/write attributes:
|
||||||
|
|
||||||
|
/sys/class/gpio/gpioN/
|
||||||
|
|
||||||
|
"direction" ... reads as either "in" or "out". This value may
|
||||||
|
normally be written. Writing as "out" defaults to
|
||||||
|
initializing the value as low. To ensure glitch free
|
||||||
|
operation, values "low" and "high" may be written to
|
||||||
|
configure the GPIO as an output with that initial value.
|
||||||
|
|
||||||
|
Note that this attribute *will not exist* if the kernel
|
||||||
|
doesn't support changing the direction of a GPIO, or
|
||||||
|
it was exported by kernel code that didn't explicitly
|
||||||
|
allow userspace to reconfigure this GPIO's direction.
|
||||||
|
|
||||||
|
"value" ... reads as either 0 (low) or 1 (high). If the GPIO
|
||||||
|
is configured as an output, this value may be written;
|
||||||
|
any nonzero value is treated as high.
|
||||||
|
|
||||||
|
If the pin can be configured as interrupt-generating interrupt
|
||||||
|
and if it has been configured to generate interrupts (see the
|
||||||
|
description of "edge"), you can poll(2) on that file and
|
||||||
|
poll(2) will return whenever the interrupt was triggered. If
|
||||||
|
you use poll(2), set the events POLLPRI and POLLERR. If you
|
||||||
|
use select(2), set the file descriptor in exceptfds. After
|
||||||
|
poll(2) returns, either lseek(2) to the beginning of the sysfs
|
||||||
|
file and read the new value or close the file and re-open it
|
||||||
|
to read the value.
|
||||||
|
|
||||||
|
"edge" ... reads as either "none", "rising", "falling", or
|
||||||
|
"both". Write these strings to select the signal edge(s)
|
||||||
|
that will make poll(2) on the "value" file return.
|
||||||
|
|
||||||
|
This file exists only if the pin can be configured as an
|
||||||
|
interrupt generating input pin.
|
||||||
|
|
||||||
|
"active_low" ... reads as either 0 (false) or 1 (true). Write
|
||||||
|
any nonzero value to invert the value attribute both
|
||||||
|
for reading and writing. Existing and subsequent
|
||||||
|
poll(2) support configuration via the edge attribute
|
||||||
|
for "rising" and "falling" edges will follow this
|
||||||
|
setting.
|
||||||
|
|
||||||
|
GPIO controllers have paths like /sys/class/gpio/gpiochip42/ (for the
|
||||||
|
controller implementing GPIOs starting at #42) and have the following
|
||||||
|
read-only attributes:
|
||||||
|
|
||||||
|
/sys/class/gpio/gpiochipN/
|
||||||
|
|
||||||
|
"base" ... same as N, the first GPIO managed by this chip
|
||||||
|
|
||||||
|
"label" ... provided for diagnostics (not always unique)
|
||||||
|
|
||||||
|
"ngpio" ... how many GPIOs this manges (N to N + ngpio - 1)
|
||||||
|
|
||||||
|
Board documentation should in most cases cover what GPIOs are used for
|
||||||
|
what purposes. However, those numbers are not always stable; GPIOs on
|
||||||
|
a daughtercard might be different depending on the base board being used,
|
||||||
|
or other cards in the stack. In such cases, you may need to use the
|
||||||
|
gpiochip nodes (possibly in conjunction with schematics) to determine
|
||||||
|
the correct GPIO number to use for a given signal.
|
||||||
|
|
||||||
|
|
||||||
|
Exporting from Kernel code
|
||||||
|
--------------------------
|
||||||
|
Kernel code can explicitly manage exports of GPIOs which have already been
|
||||||
|
requested using gpio_request():
|
||||||
|
|
||||||
|
/* export the GPIO to userspace */
|
||||||
|
int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
|
||||||
|
|
||||||
|
/* reverse gpio_export() */
|
||||||
|
void gpiod_unexport(struct gpio_desc *desc);
|
||||||
|
|
||||||
|
/* create a sysfs link to an exported GPIO node */
|
||||||
|
int gpiod_export_link(struct device *dev, const char *name,
|
||||||
|
struct gpio_desc *desc);
|
||||||
|
|
||||||
|
/* change the polarity of a GPIO node in sysfs */
|
||||||
|
int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value);
|
||||||
|
|
||||||
|
After a kernel driver requests a GPIO, it may only be made available in
|
||||||
|
the sysfs interface by gpiod_export(). The driver can control whether the
|
||||||
|
signal direction may change. This helps drivers prevent userspace code
|
||||||
|
from accidentally clobbering important system state.
|
||||||
|
|
||||||
|
This explicit exporting can help with debugging (by making some kinds
|
||||||
|
of experiments easier), or can provide an always-there interface that's
|
||||||
|
suitable for documenting as part of a board support package.
|
||||||
|
|
||||||
|
After the GPIO has been exported, gpiod_export_link() allows creating
|
||||||
|
symlinks from elsewhere in sysfs to the GPIO sysfs node. Drivers can
|
||||||
|
use this to provide the interface under their own device in sysfs with
|
||||||
|
a descriptive name.
|
||||||
|
|
||||||
|
Drivers can use gpiod_sysfs_set_active_low() to hide GPIO line polarity
|
||||||
|
differences between boards from user space. Polarity change can be done both
|
||||||
|
before and after gpiod_export(), and previously enabled poll(2) support for
|
||||||
|
either rising or falling edge will be reconfigured to follow this setting.
|
2
Makefile
2
Makefile
|
@ -1,7 +1,7 @@
|
||||||
VERSION = 3
|
VERSION = 3
|
||||||
PATCHLEVEL = 13
|
PATCHLEVEL = 13
|
||||||
SUBLEVEL = 0
|
SUBLEVEL = 0
|
||||||
EXTRAVERSION = -rc1
|
EXTRAVERSION = -rc2
|
||||||
NAME = One Giant Leap for Frogkind
|
NAME = One Giant Leap for Frogkind
|
||||||
|
|
||||||
# *DOCUMENTATION*
|
# *DOCUMENTATION*
|
||||||
|
|
|
@ -85,6 +85,8 @@
|
||||||
reg = <0x7e205000 0x1000>;
|
reg = <0x7e205000 0x1000>;
|
||||||
interrupts = <2 21>;
|
interrupts = <2 21>;
|
||||||
clocks = <&clk_i2c>;
|
clocks = <&clk_i2c>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -93,6 +95,8 @@
|
||||||
reg = <0x7e804000 0x1000>;
|
reg = <0x7e804000 0x1000>;
|
||||||
interrupts = <2 21>;
|
interrupts = <2 21>;
|
||||||
clocks = <&clk_i2c>;
|
clocks = <&clk_i2c>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,13 @@
|
||||||
i2c2_bus: i2c2-bus {
|
i2c2_bus: i2c2-bus {
|
||||||
samsung,pin-pud = <0>;
|
samsung,pin-pud = <0>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
max77686_irq: max77686-irq {
|
||||||
|
samsung,pins = "gpx3-2";
|
||||||
|
samsung,pin-function = <0>;
|
||||||
|
samsung,pin-pud = <0>;
|
||||||
|
samsung,pin-drv = <0>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
i2c@12C60000 {
|
i2c@12C60000 {
|
||||||
|
@ -35,6 +42,11 @@
|
||||||
|
|
||||||
max77686@09 {
|
max77686@09 {
|
||||||
compatible = "maxim,max77686";
|
compatible = "maxim,max77686";
|
||||||
|
interrupt-parent = <&gpx3>;
|
||||||
|
interrupts = <2 0>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&max77686_irq>;
|
||||||
|
wakeup-source;
|
||||||
reg = <0x09>;
|
reg = <0x09>;
|
||||||
|
|
||||||
voltage-regulators {
|
voltage-regulators {
|
||||||
|
|
|
@ -161,7 +161,7 @@
|
||||||
clocks = <&clks 197>, <&clks 3>,
|
clocks = <&clks 197>, <&clks 3>,
|
||||||
<&clks 197>, <&clks 107>,
|
<&clks 197>, <&clks 107>,
|
||||||
<&clks 0>, <&clks 118>,
|
<&clks 0>, <&clks 118>,
|
||||||
<&clks 62>, <&clks 139>,
|
<&clks 0>, <&clks 139>,
|
||||||
<&clks 0>;
|
<&clks 0>;
|
||||||
clock-names = "core", "rxtx0",
|
clock-names = "core", "rxtx0",
|
||||||
"rxtx1", "rxtx2",
|
"rxtx1", "rxtx2",
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
* they probably share the same GPIO IRQ
|
* they probably share the same GPIO IRQ
|
||||||
* REVISIT: Add timing support from slls644g.pdf
|
* REVISIT: Add timing support from slls644g.pdf
|
||||||
*/
|
*/
|
||||||
8250@3,0 {
|
uart@3,0 {
|
||||||
compatible = "ns16550a";
|
compatible = "ns16550a";
|
||||||
reg = <3 0 0x100>;
|
reg = <3 0 0x100>;
|
||||||
bank-width = <2>;
|
bank-width = <2>;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <dt-bindings/gpio/gpio.h>
|
#include <dt-bindings/gpio/gpio.h>
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
#include <dt-bindings/pinctrl/omap.h>
|
#include <dt-bindings/pinctrl/omap.h>
|
||||||
|
|
||||||
#include "skeleton.dtsi"
|
#include "skeleton.dtsi"
|
||||||
|
@ -21,6 +22,8 @@
|
||||||
serial0 = &uart1;
|
serial0 = &uart1;
|
||||||
serial1 = &uart2;
|
serial1 = &uart2;
|
||||||
serial2 = &uart3;
|
serial2 = &uart3;
|
||||||
|
i2c0 = &i2c1;
|
||||||
|
i2c1 = &i2c2;
|
||||||
};
|
};
|
||||||
|
|
||||||
cpus {
|
cpus {
|
||||||
|
@ -53,6 +56,28 @@
|
||||||
ranges;
|
ranges;
|
||||||
ti,hwmods = "l3_main";
|
ti,hwmods = "l3_main";
|
||||||
|
|
||||||
|
aes: aes@480a6000 {
|
||||||
|
compatible = "ti,omap2-aes";
|
||||||
|
ti,hwmods = "aes";
|
||||||
|
reg = <0x480a6000 0x50>;
|
||||||
|
dmas = <&sdma 9 &sdma 10>;
|
||||||
|
dma-names = "tx", "rx";
|
||||||
|
};
|
||||||
|
|
||||||
|
hdq1w: 1w@480b2000 {
|
||||||
|
compatible = "ti,omap2420-1w";
|
||||||
|
ti,hwmods = "hdq1w";
|
||||||
|
reg = <0x480b2000 0x1000>;
|
||||||
|
interrupts = <58>;
|
||||||
|
};
|
||||||
|
|
||||||
|
mailbox: mailbox@48094000 {
|
||||||
|
compatible = "ti,omap2-mailbox";
|
||||||
|
ti,hwmods = "mailbox";
|
||||||
|
reg = <0x48094000 0x200>;
|
||||||
|
interrupts = <26>;
|
||||||
|
};
|
||||||
|
|
||||||
intc: interrupt-controller@1 {
|
intc: interrupt-controller@1 {
|
||||||
compatible = "ti,omap2-intc";
|
compatible = "ti,omap2-intc";
|
||||||
interrupt-controller;
|
interrupt-controller;
|
||||||
|
@ -63,6 +88,7 @@
|
||||||
|
|
||||||
sdma: dma-controller@48056000 {
|
sdma: dma-controller@48056000 {
|
||||||
compatible = "ti,omap2430-sdma", "ti,omap2420-sdma";
|
compatible = "ti,omap2430-sdma", "ti,omap2420-sdma";
|
||||||
|
ti,hwmods = "dma";
|
||||||
reg = <0x48056000 0x1000>;
|
reg = <0x48056000 0x1000>;
|
||||||
interrupts = <12>,
|
interrupts = <12>,
|
||||||
<13>,
|
<13>,
|
||||||
|
@ -73,21 +99,91 @@
|
||||||
#dma-requests = <64>;
|
#dma-requests = <64>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
i2c1: i2c@48070000 {
|
||||||
|
compatible = "ti,omap2-i2c";
|
||||||
|
ti,hwmods = "i2c1";
|
||||||
|
reg = <0x48070000 0x80>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
interrupts = <56>;
|
||||||
|
dmas = <&sdma 27 &sdma 28>;
|
||||||
|
dma-names = "tx", "rx";
|
||||||
|
};
|
||||||
|
|
||||||
|
i2c2: i2c@48072000 {
|
||||||
|
compatible = "ti,omap2-i2c";
|
||||||
|
ti,hwmods = "i2c2";
|
||||||
|
reg = <0x48072000 0x80>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
interrupts = <57>;
|
||||||
|
dmas = <&sdma 29 &sdma 30>;
|
||||||
|
dma-names = "tx", "rx";
|
||||||
|
};
|
||||||
|
|
||||||
|
mcspi1: mcspi@48098000 {
|
||||||
|
compatible = "ti,omap2-mcspi";
|
||||||
|
ti,hwmods = "mcspi1";
|
||||||
|
reg = <0x48098000 0x100>;
|
||||||
|
interrupts = <65>;
|
||||||
|
dmas = <&sdma 35 &sdma 36 &sdma 37 &sdma 38
|
||||||
|
&sdma 39 &sdma 40 &sdma 41 &sdma 42>;
|
||||||
|
dma-names = "tx0", "rx0", "tx1", "rx1",
|
||||||
|
"tx2", "rx2", "tx3", "rx3";
|
||||||
|
};
|
||||||
|
|
||||||
|
mcspi2: mcspi@4809a000 {
|
||||||
|
compatible = "ti,omap2-mcspi";
|
||||||
|
ti,hwmods = "mcspi2";
|
||||||
|
reg = <0x4809a000 0x100>;
|
||||||
|
interrupts = <66>;
|
||||||
|
dmas = <&sdma 43 &sdma 44 &sdma 45 &sdma 46>;
|
||||||
|
dma-names = "tx0", "rx0", "tx1", "rx1";
|
||||||
|
};
|
||||||
|
|
||||||
|
rng: rng@480a0000 {
|
||||||
|
compatible = "ti,omap2-rng";
|
||||||
|
ti,hwmods = "rng";
|
||||||
|
reg = <0x480a0000 0x50>;
|
||||||
|
interrupts = <36>;
|
||||||
|
};
|
||||||
|
|
||||||
|
sham: sham@480a4000 {
|
||||||
|
compatible = "ti,omap2-sham";
|
||||||
|
ti,hwmods = "sham";
|
||||||
|
reg = <0x480a4000 0x64>;
|
||||||
|
interrupts = <51>;
|
||||||
|
dmas = <&sdma 13>;
|
||||||
|
dma-names = "rx";
|
||||||
|
};
|
||||||
|
|
||||||
uart1: serial@4806a000 {
|
uart1: serial@4806a000 {
|
||||||
compatible = "ti,omap2-uart";
|
compatible = "ti,omap2-uart";
|
||||||
ti,hwmods = "uart1";
|
ti,hwmods = "uart1";
|
||||||
|
reg = <0x4806a000 0x2000>;
|
||||||
|
interrupts = <72>;
|
||||||
|
dmas = <&sdma 49 &sdma 50>;
|
||||||
|
dma-names = "tx", "rx";
|
||||||
clock-frequency = <48000000>;
|
clock-frequency = <48000000>;
|
||||||
};
|
};
|
||||||
|
|
||||||
uart2: serial@4806c000 {
|
uart2: serial@4806c000 {
|
||||||
compatible = "ti,omap2-uart";
|
compatible = "ti,omap2-uart";
|
||||||
ti,hwmods = "uart2";
|
ti,hwmods = "uart2";
|
||||||
|
reg = <0x4806c000 0x400>;
|
||||||
|
interrupts = <73>;
|
||||||
|
dmas = <&sdma 51 &sdma 52>;
|
||||||
|
dma-names = "tx", "rx";
|
||||||
clock-frequency = <48000000>;
|
clock-frequency = <48000000>;
|
||||||
};
|
};
|
||||||
|
|
||||||
uart3: serial@4806e000 {
|
uart3: serial@4806e000 {
|
||||||
compatible = "ti,omap2-uart";
|
compatible = "ti,omap2-uart";
|
||||||
ti,hwmods = "uart3";
|
ti,hwmods = "uart3";
|
||||||
|
reg = <0x4806e000 0x400>;
|
||||||
|
interrupts = <74>;
|
||||||
|
dmas = <&sdma 53 &sdma 54>;
|
||||||
|
dma-names = "tx", "rx";
|
||||||
clock-frequency = <48000000>;
|
clock-frequency = <48000000>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,15 @@
|
||||||
dma-names = "tx", "rx";
|
dma-names = "tx", "rx";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
msdi1: mmc@4809c000 {
|
||||||
|
compatible = "ti,omap2420-mmc";
|
||||||
|
ti,hwmods = "msdi1";
|
||||||
|
reg = <0x4809c000 0x80>;
|
||||||
|
interrupts = <83>;
|
||||||
|
dmas = <&sdma 61 &sdma 62>;
|
||||||
|
dma-names = "tx", "rx";
|
||||||
|
};
|
||||||
|
|
||||||
timer1: timer@48028000 {
|
timer1: timer@48028000 {
|
||||||
compatible = "ti,omap2420-timer";
|
compatible = "ti,omap2420-timer";
|
||||||
reg = <0x48028000 0x400>;
|
reg = <0x48028000 0x400>;
|
||||||
|
@ -121,5 +130,19 @@
|
||||||
ti,hwmods = "timer1";
|
ti,hwmods = "timer1";
|
||||||
ti,timer-alwon;
|
ti,timer-alwon;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
wd_timer2: wdt@48022000 {
|
||||||
|
compatible = "ti,omap2-wdt";
|
||||||
|
ti,hwmods = "wd_timer2";
|
||||||
|
reg = <0x48022000 0x80>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&i2c1 {
|
||||||
|
compatible = "ti,omap2420-i2c";
|
||||||
|
};
|
||||||
|
|
||||||
|
&i2c2 {
|
||||||
|
compatible = "ti,omap2420-i2c";
|
||||||
|
};
|
||||||
|
|
|
@ -175,6 +175,25 @@
|
||||||
dma-names = "tx", "rx";
|
dma-names = "tx", "rx";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mmc1: mmc@4809c000 {
|
||||||
|
compatible = "ti,omap2-hsmmc";
|
||||||
|
reg = <0x4809c000 0x200>;
|
||||||
|
interrupts = <83>;
|
||||||
|
ti,hwmods = "mmc1";
|
||||||
|
ti,dual-volt;
|
||||||
|
dmas = <&sdma 61>, <&sdma 62>;
|
||||||
|
dma-names = "tx", "rx";
|
||||||
|
};
|
||||||
|
|
||||||
|
mmc2: mmc@480b4000 {
|
||||||
|
compatible = "ti,omap2-hsmmc";
|
||||||
|
reg = <0x480b4000 0x200>;
|
||||||
|
interrupts = <86>;
|
||||||
|
ti,hwmods = "mmc2";
|
||||||
|
dmas = <&sdma 47>, <&sdma 48>;
|
||||||
|
dma-names = "tx", "rx";
|
||||||
|
};
|
||||||
|
|
||||||
timer1: timer@49018000 {
|
timer1: timer@49018000 {
|
||||||
compatible = "ti,omap2420-timer";
|
compatible = "ti,omap2420-timer";
|
||||||
reg = <0x49018000 0x400>;
|
reg = <0x49018000 0x400>;
|
||||||
|
@ -182,5 +201,35 @@
|
||||||
ti,hwmods = "timer1";
|
ti,hwmods = "timer1";
|
||||||
ti,timer-alwon;
|
ti,timer-alwon;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mcspi3: mcspi@480b8000 {
|
||||||
|
compatible = "ti,omap2-mcspi";
|
||||||
|
ti,hwmods = "mcspi3";
|
||||||
|
reg = <0x480b8000 0x100>;
|
||||||
|
interrupts = <91>;
|
||||||
|
dmas = <&sdma 15 &sdma 16 &sdma 23 &sdma 24>;
|
||||||
|
dma-names = "tx0", "rx0", "tx1", "rx1";
|
||||||
|
};
|
||||||
|
|
||||||
|
usb_otg_hs: usb_otg_hs@480ac000 {
|
||||||
|
compatible = "ti,omap2-musb";
|
||||||
|
ti,hwmods = "usb_otg_hs";
|
||||||
|
reg = <0x480ac000 0x1000>;
|
||||||
|
interrupts = <93>;
|
||||||
|
};
|
||||||
|
|
||||||
|
wd_timer2: wdt@49016000 {
|
||||||
|
compatible = "ti,omap2-wdt";
|
||||||
|
ti,hwmods = "wd_timer2";
|
||||||
|
reg = <0x49016000 0x80>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&i2c1 {
|
||||||
|
compatible = "ti,omap2430-i2c";
|
||||||
|
};
|
||||||
|
|
||||||
|
&i2c2 {
|
||||||
|
compatible = "ti,omap2430-i2c";
|
||||||
|
};
|
||||||
|
|
|
@ -19,11 +19,11 @@ secure-common = omap-smc.o omap-secure.o
|
||||||
|
|
||||||
obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common)
|
obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common)
|
||||||
obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(hwmod-common) $(secure-common)
|
obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(hwmod-common) $(secure-common)
|
||||||
obj-$(CONFIG_ARCH_OMAP4) += prm44xx.o $(hwmod-common) $(secure-common)
|
obj-$(CONFIG_ARCH_OMAP4) += $(hwmod-common) $(secure-common)
|
||||||
obj-$(CONFIG_SOC_AM33XX) += irq.o $(hwmod-common)
|
obj-$(CONFIG_SOC_AM33XX) += irq.o $(hwmod-common)
|
||||||
obj-$(CONFIG_SOC_OMAP5) += prm44xx.o $(hwmod-common) $(secure-common)
|
obj-$(CONFIG_SOC_OMAP5) += $(hwmod-common) $(secure-common)
|
||||||
obj-$(CONFIG_SOC_AM43XX) += $(hwmod-common) $(secure-common)
|
obj-$(CONFIG_SOC_AM43XX) += $(hwmod-common) $(secure-common)
|
||||||
obj-$(CONFIG_SOC_DRA7XX) += prm44xx.o $(hwmod-common) $(secure-common)
|
obj-$(CONFIG_SOC_DRA7XX) += $(hwmod-common) $(secure-common)
|
||||||
|
|
||||||
ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),)
|
ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),)
|
||||||
obj-y += mcbsp.o
|
obj-y += mcbsp.o
|
||||||
|
|
|
@ -299,7 +299,6 @@ struct omap_sdrc_params;
|
||||||
extern void omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
|
extern void omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
|
||||||
struct omap_sdrc_params *sdrc_cs1);
|
struct omap_sdrc_params *sdrc_cs1);
|
||||||
struct omap2_hsmmc_info;
|
struct omap2_hsmmc_info;
|
||||||
extern int omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers);
|
|
||||||
extern void omap_reserve(void);
|
extern void omap_reserve(void);
|
||||||
|
|
||||||
struct omap_hwmod;
|
struct omap_hwmod;
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
|
|
||||||
#include "soc.h"
|
#include "soc.h"
|
||||||
#include "iomap.h"
|
#include "iomap.h"
|
||||||
#include "mux.h"
|
|
||||||
#include "control.h"
|
#include "control.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "prm.h"
|
#include "prm.h"
|
||||||
|
@ -102,90 +101,13 @@ static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initconst = {
|
||||||
{ "dss_hdmi", "omapdss_hdmi", -1 },
|
{ "dss_hdmi", "omapdss_hdmi", -1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __init omap4_tpd12s015_mux_pads(void)
|
|
||||||
{
|
|
||||||
omap_mux_init_signal("hdmi_cec",
|
|
||||||
OMAP_PIN_INPUT_PULLUP);
|
|
||||||
omap_mux_init_signal("hdmi_ddc_scl",
|
|
||||||
OMAP_PIN_INPUT_PULLUP);
|
|
||||||
omap_mux_init_signal("hdmi_ddc_sda",
|
|
||||||
OMAP_PIN_INPUT_PULLUP);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __init omap4_hdmi_mux_pads(enum omap_hdmi_flags flags)
|
|
||||||
{
|
|
||||||
u32 reg;
|
|
||||||
u16 control_i2c_1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CONTROL_I2C_1: HDMI_DDC_SDA_PULLUPRESX (bit 28) and
|
|
||||||
* HDMI_DDC_SCL_PULLUPRESX (bit 24) are set to disable
|
|
||||||
* internal pull up resistor.
|
|
||||||
*/
|
|
||||||
if (flags & OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP) {
|
|
||||||
control_i2c_1 = OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_1;
|
|
||||||
reg = omap4_ctrl_pad_readl(control_i2c_1);
|
|
||||||
reg |= (OMAP4_HDMI_DDC_SDA_PULLUPRESX_MASK |
|
|
||||||
OMAP4_HDMI_DDC_SCL_PULLUPRESX_MASK);
|
|
||||||
omap4_ctrl_pad_writel(reg, control_i2c_1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int omap4_dsi_mux_pads(int dsi_id, unsigned lanes)
|
|
||||||
{
|
|
||||||
u32 enable_mask, enable_shift;
|
|
||||||
u32 pipd_mask, pipd_shift;
|
|
||||||
u32 reg;
|
|
||||||
|
|
||||||
if (dsi_id == 0) {
|
|
||||||
enable_mask = OMAP4_DSI1_LANEENABLE_MASK;
|
|
||||||
enable_shift = OMAP4_DSI1_LANEENABLE_SHIFT;
|
|
||||||
pipd_mask = OMAP4_DSI1_PIPD_MASK;
|
|
||||||
pipd_shift = OMAP4_DSI1_PIPD_SHIFT;
|
|
||||||
} else if (dsi_id == 1) {
|
|
||||||
enable_mask = OMAP4_DSI2_LANEENABLE_MASK;
|
|
||||||
enable_shift = OMAP4_DSI2_LANEENABLE_SHIFT;
|
|
||||||
pipd_mask = OMAP4_DSI2_PIPD_MASK;
|
|
||||||
pipd_shift = OMAP4_DSI2_PIPD_SHIFT;
|
|
||||||
} else {
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
reg = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_DSIPHY);
|
|
||||||
|
|
||||||
reg &= ~enable_mask;
|
|
||||||
reg &= ~pipd_mask;
|
|
||||||
|
|
||||||
reg |= (lanes << enable_shift) & enable_mask;
|
|
||||||
reg |= (lanes << pipd_shift) & pipd_mask;
|
|
||||||
|
|
||||||
omap4_ctrl_pad_writel(reg, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_DSIPHY);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int __init omap_hdmi_init(enum omap_hdmi_flags flags)
|
|
||||||
{
|
|
||||||
if (cpu_is_omap44xx()) {
|
|
||||||
omap4_hdmi_mux_pads(flags);
|
|
||||||
omap4_tpd12s015_mux_pads();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int omap_dsi_enable_pads(int dsi_id, unsigned lane_mask)
|
static int omap_dsi_enable_pads(int dsi_id, unsigned lane_mask)
|
||||||
{
|
{
|
||||||
if (cpu_is_omap44xx())
|
|
||||||
return omap4_dsi_mux_pads(dsi_id, lane_mask);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void omap_dsi_disable_pads(int dsi_id, unsigned lane_mask)
|
static void omap_dsi_disable_pads(int dsi_id, unsigned lane_mask)
|
||||||
{
|
{
|
||||||
if (cpu_is_omap44xx())
|
|
||||||
omap4_dsi_mux_pads(dsi_id, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int omap_dss_set_min_bus_tput(struct device *dev, unsigned long tput)
|
static int omap_dss_set_min_bus_tput(struct device *dev, unsigned long tput)
|
||||||
|
|
|
@ -1501,6 +1501,22 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For some GPMC devices we still need to rely on the bootloader
|
||||||
|
* timings because the devices can be connected via FPGA. So far
|
||||||
|
* the list is smc91x on the omap2 SDP boards, and 8250 on zooms.
|
||||||
|
* REVISIT: Add timing support from slls644g.pdf and from the
|
||||||
|
* lan91c96 manual.
|
||||||
|
*/
|
||||||
|
if (of_device_is_compatible(child, "ns16550a") ||
|
||||||
|
of_device_is_compatible(child, "smsc,lan91c94") ||
|
||||||
|
of_device_is_compatible(child, "smsc,lan91c111")) {
|
||||||
|
dev_warn(&pdev->dev,
|
||||||
|
"%s using bootloader timings on CS%d\n",
|
||||||
|
child->name, cs);
|
||||||
|
goto no_timings;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME: gpmc_cs_request() will map the CS to an arbitary
|
* FIXME: gpmc_cs_request() will map the CS to an arbitary
|
||||||
* location in the gpmc address space. When booting with
|
* location in the gpmc address space. When booting with
|
||||||
|
@ -1529,6 +1545,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
|
||||||
gpmc_read_timings_dt(child, &gpmc_t);
|
gpmc_read_timings_dt(child, &gpmc_t);
|
||||||
gpmc_cs_set_timings(cs, &gpmc_t);
|
gpmc_cs_set_timings(cs, &gpmc_t);
|
||||||
|
|
||||||
|
no_timings:
|
||||||
if (of_platform_device_create(child, NULL, &pdev->dev))
|
if (of_platform_device_create(child, NULL, &pdev->dev))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1541,42 +1558,6 @@ err:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* REVISIT: Add timing support from slls644g.pdf
|
|
||||||
*/
|
|
||||||
static int gpmc_probe_8250(struct platform_device *pdev,
|
|
||||||
struct device_node *child)
|
|
||||||
{
|
|
||||||
struct resource res;
|
|
||||||
unsigned long base;
|
|
||||||
int ret, cs;
|
|
||||||
|
|
||||||
if (of_property_read_u32(child, "reg", &cs) < 0) {
|
|
||||||
dev_err(&pdev->dev, "%s has no 'reg' property\n",
|
|
||||||
child->full_name);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (of_address_to_resource(child, 0, &res) < 0) {
|
|
||||||
dev_err(&pdev->dev, "%s has malformed 'reg' property\n",
|
|
||||||
child->full_name);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gpmc_cs_request(cs, resource_size(&res), &base);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (of_platform_device_create(child, NULL, &pdev->dev))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name);
|
|
||||||
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gpmc_probe_dt(struct platform_device *pdev)
|
static int gpmc_probe_dt(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -1618,10 +1599,9 @@ static int gpmc_probe_dt(struct platform_device *pdev)
|
||||||
else if (of_node_cmp(child->name, "onenand") == 0)
|
else if (of_node_cmp(child->name, "onenand") == 0)
|
||||||
ret = gpmc_probe_onenand_child(pdev, child);
|
ret = gpmc_probe_onenand_child(pdev, child);
|
||||||
else if (of_node_cmp(child->name, "ethernet") == 0 ||
|
else if (of_node_cmp(child->name, "ethernet") == 0 ||
|
||||||
of_node_cmp(child->name, "nor") == 0)
|
of_node_cmp(child->name, "nor") == 0 ||
|
||||||
|
of_node_cmp(child->name, "uart") == 0)
|
||||||
ret = gpmc_probe_generic_child(pdev, child);
|
ret = gpmc_probe_generic_child(pdev, child);
|
||||||
else if (of_node_cmp(child->name, "8250") == 0)
|
|
||||||
ret = gpmc_probe_8250(pdev, child);
|
|
||||||
|
|
||||||
if (WARN(ret < 0, "%s: probing gpmc child %s failed\n",
|
if (WARN(ret < 0, "%s: probing gpmc child %s failed\n",
|
||||||
__func__, child->full_name))
|
__func__, child->full_name))
|
||||||
|
|
|
@ -76,6 +76,13 @@ static inline void omap_barrier_reserve_memblock(void)
|
||||||
{ }
|
{ }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_SOC_HAS_REALTIME_COUNTER
|
||||||
void set_cntfreq(void);
|
void set_cntfreq(void);
|
||||||
|
#else
|
||||||
|
static inline void set_cntfreq(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __ASSEMBLER__ */
|
#endif /* __ASSEMBLER__ */
|
||||||
#endif /* OMAP_ARCH_OMAP_SECURE_H */
|
#endif /* OMAP_ARCH_OMAP_SECURE_H */
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
#include "iomap.h"
|
#include "iomap.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "mmc.h"
|
#include "mmc.h"
|
||||||
#include "hsmmc.h"
|
|
||||||
#include "prminst44xx.h"
|
#include "prminst44xx.h"
|
||||||
#include "prcm_mpu44xx.h"
|
#include "prcm_mpu44xx.h"
|
||||||
#include "omap4-sar-layout.h"
|
#include "omap4-sar-layout.h"
|
||||||
|
@ -284,59 +283,3 @@ skip_errata_init:
|
||||||
omap_wakeupgen_init();
|
omap_wakeupgen_init();
|
||||||
irqchip_init();
|
irqchip_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
|
|
||||||
static int omap4_twl6030_hsmmc_late_init(struct device *dev)
|
|
||||||
{
|
|
||||||
int irq = 0;
|
|
||||||
struct platform_device *pdev = container_of(dev,
|
|
||||||
struct platform_device, dev);
|
|
||||||
struct omap_mmc_platform_data *pdata = dev->platform_data;
|
|
||||||
|
|
||||||
/* Setting MMC1 Card detect Irq */
|
|
||||||
if (pdev->id == 0) {
|
|
||||||
irq = twl6030_mmc_card_detect_config();
|
|
||||||
if (irq < 0) {
|
|
||||||
dev_err(dev, "%s: Error card detect config(%d)\n",
|
|
||||||
__func__, irq);
|
|
||||||
return irq;
|
|
||||||
}
|
|
||||||
pdata->slots[0].card_detect_irq = irq;
|
|
||||||
pdata->slots[0].card_detect = twl6030_mmc_card_detect;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
|
|
||||||
{
|
|
||||||
struct omap_mmc_platform_data *pdata;
|
|
||||||
|
|
||||||
/* dev can be null if CONFIG_MMC_OMAP_HS is not set */
|
|
||||||
if (!dev) {
|
|
||||||
pr_err("Failed %s\n", __func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pdata = dev->platform_data;
|
|
||||||
pdata->init = omap4_twl6030_hsmmc_late_init;
|
|
||||||
}
|
|
||||||
|
|
||||||
int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers)
|
|
||||||
{
|
|
||||||
struct omap2_hsmmc_info *c;
|
|
||||||
|
|
||||||
omap_hsmmc_init(controllers);
|
|
||||||
for (c = controllers; c->mmc; c++) {
|
|
||||||
/* pdev can be null if CONFIG_MMC_OMAP_HS is not set */
|
|
||||||
if (!c->pdev)
|
|
||||||
continue;
|
|
||||||
omap4_twl6030_hsmmc_set_late_init(&c->pdev->dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -120,7 +120,7 @@ static void omap3_save_secure_ram_context(void)
|
||||||
* will hang the system.
|
* will hang the system.
|
||||||
*/
|
*/
|
||||||
pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
|
pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
|
||||||
ret = _omap_save_secure_sram((u32 *)
|
ret = _omap_save_secure_sram((u32 *)(unsigned long)
|
||||||
__pa(omap3_secure_ram_storage));
|
__pa(omap3_secure_ram_storage));
|
||||||
pwrdm_set_next_pwrst(mpu_pwrdm, mpu_next_state);
|
pwrdm_set_next_pwrst(mpu_pwrdm, mpu_next_state);
|
||||||
/* Following is for error tracking, it should not happen */
|
/* Following is for error tracking, it should not happen */
|
||||||
|
|
|
@ -43,7 +43,7 @@ extern void omap4_prm_vcvp_write(u32 val, u8 offset);
|
||||||
extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
|
extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
|
||||||
|
|
||||||
#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
|
#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
|
||||||
defined(CONFIG_SOC_DRA7XX)
|
defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM43XX)
|
||||||
void omap44xx_prm_reconfigure_io_chain(void);
|
void omap44xx_prm_reconfigure_io_chain(void);
|
||||||
#else
|
#else
|
||||||
static inline void omap44xx_prm_reconfigure_io_chain(void)
|
static inline void omap44xx_prm_reconfigure_io_chain(void)
|
||||||
|
|
|
@ -209,13 +209,3 @@ void __init tegra_init_fuse(void)
|
||||||
tegra_sku_id, tegra_cpu_process_id,
|
tegra_sku_id, tegra_cpu_process_id,
|
||||||
tegra_core_process_id);
|
tegra_core_process_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long long tegra_chip_uid(void)
|
|
||||||
{
|
|
||||||
unsigned long long lo, hi;
|
|
||||||
|
|
||||||
lo = tegra_fuse_readl(FUSE_UID_LOW);
|
|
||||||
hi = tegra_fuse_readl(FUSE_UID_HIGH);
|
|
||||||
return (hi << 32ull) | lo;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(tegra_chip_uid);
|
|
||||||
|
|
|
@ -53,6 +53,11 @@
|
||||||
#define A15_BX_ADDR0 0x68
|
#define A15_BX_ADDR0 0x68
|
||||||
#define A7_BX_ADDR0 0x78
|
#define A7_BX_ADDR0 0x78
|
||||||
|
|
||||||
|
/* SPC CPU/cluster reset statue */
|
||||||
|
#define STANDBYWFI_STAT 0x3c
|
||||||
|
#define STANDBYWFI_STAT_A15_CPU_MASK(cpu) (1 << (cpu))
|
||||||
|
#define STANDBYWFI_STAT_A7_CPU_MASK(cpu) (1 << (3 + (cpu)))
|
||||||
|
|
||||||
/* SPC system config interface registers */
|
/* SPC system config interface registers */
|
||||||
#define SYSCFG_WDATA 0x70
|
#define SYSCFG_WDATA 0x70
|
||||||
#define SYSCFG_RDATA 0x74
|
#define SYSCFG_RDATA 0x74
|
||||||
|
@ -213,6 +218,41 @@ void ve_spc_powerdown(u32 cluster, bool enable)
|
||||||
writel_relaxed(enable, info->baseaddr + pwdrn_reg);
|
writel_relaxed(enable, info->baseaddr + pwdrn_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 standbywfi_cpu_mask(u32 cpu, u32 cluster)
|
||||||
|
{
|
||||||
|
return cluster_is_a15(cluster) ?
|
||||||
|
STANDBYWFI_STAT_A15_CPU_MASK(cpu)
|
||||||
|
: STANDBYWFI_STAT_A7_CPU_MASK(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ve_spc_cpu_in_wfi(u32 cpu, u32 cluster)
|
||||||
|
*
|
||||||
|
* @cpu: mpidr[7:0] bitfield describing CPU affinity level within cluster
|
||||||
|
* @cluster: mpidr[15:8] bitfield describing cluster affinity level
|
||||||
|
*
|
||||||
|
* @return: non-zero if and only if the specified CPU is in WFI
|
||||||
|
*
|
||||||
|
* Take care when interpreting the result of this function: a CPU might
|
||||||
|
* be in WFI temporarily due to idle, and is not necessarily safely
|
||||||
|
* parked.
|
||||||
|
*/
|
||||||
|
int ve_spc_cpu_in_wfi(u32 cpu, u32 cluster)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
u32 mask = standbywfi_cpu_mask(cpu, cluster);
|
||||||
|
|
||||||
|
if (cluster >= MAX_CLUSTERS)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
ret = readl_relaxed(info->baseaddr + STANDBYWFI_STAT);
|
||||||
|
|
||||||
|
pr_debug("%s: PCFGREG[0x%X] = 0x%08X, mask = 0x%X\n",
|
||||||
|
__func__, STANDBYWFI_STAT, ret, mask);
|
||||||
|
|
||||||
|
return ret & mask;
|
||||||
|
}
|
||||||
|
|
||||||
static int ve_spc_get_performance(int cluster, u32 *freq)
|
static int ve_spc_get_performance(int cluster, u32 *freq)
|
||||||
{
|
{
|
||||||
struct ve_spc_opp *opps = info->opps[cluster];
|
struct ve_spc_opp *opps = info->opps[cluster];
|
||||||
|
|
|
@ -20,5 +20,6 @@ void ve_spc_global_wakeup_irq(bool set);
|
||||||
void ve_spc_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set);
|
void ve_spc_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set);
|
||||||
void ve_spc_set_resume_addr(u32 cluster, u32 cpu, u32 addr);
|
void ve_spc_set_resume_addr(u32 cluster, u32 cpu, u32 addr);
|
||||||
void ve_spc_powerdown(u32 cluster, bool enable);
|
void ve_spc_powerdown(u32 cluster, bool enable);
|
||||||
|
int ve_spc_cpu_in_wfi(u32 cpu, u32 cluster);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
* published by the Free Software Foundation.
|
* published by the Free Software Foundation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
@ -32,11 +33,17 @@
|
||||||
#include "spc.h"
|
#include "spc.h"
|
||||||
|
|
||||||
/* SCC conf registers */
|
/* SCC conf registers */
|
||||||
|
#define RESET_CTRL 0x018
|
||||||
|
#define RESET_A15_NCORERESET(cpu) (1 << (2 + (cpu)))
|
||||||
|
#define RESET_A7_NCORERESET(cpu) (1 << (16 + (cpu)))
|
||||||
|
|
||||||
#define A15_CONF 0x400
|
#define A15_CONF 0x400
|
||||||
#define A7_CONF 0x500
|
#define A7_CONF 0x500
|
||||||
#define SYS_INFO 0x700
|
#define SYS_INFO 0x700
|
||||||
#define SPC_BASE 0xb00
|
#define SPC_BASE 0xb00
|
||||||
|
|
||||||
|
static void __iomem *scc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can't use regular spinlocks. In the switcher case, it is possible
|
* We can't use regular spinlocks. In the switcher case, it is possible
|
||||||
* for an outbound CPU to call power_down() after its inbound counterpart
|
* for an outbound CPU to call power_down() after its inbound counterpart
|
||||||
|
@ -190,6 +197,55 @@ static void tc2_pm_power_down(void)
|
||||||
tc2_pm_down(0);
|
tc2_pm_down(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tc2_core_in_reset(unsigned int cpu, unsigned int cluster)
|
||||||
|
{
|
||||||
|
u32 mask = cluster ?
|
||||||
|
RESET_A7_NCORERESET(cpu)
|
||||||
|
: RESET_A15_NCORERESET(cpu);
|
||||||
|
|
||||||
|
return !(readl_relaxed(scc + RESET_CTRL) & mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define POLL_MSEC 10
|
||||||
|
#define TIMEOUT_MSEC 1000
|
||||||
|
|
||||||
|
static int tc2_pm_power_down_finish(unsigned int cpu, unsigned int cluster)
|
||||||
|
{
|
||||||
|
unsigned tries;
|
||||||
|
|
||||||
|
pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
|
||||||
|
BUG_ON(cluster >= TC2_CLUSTERS || cpu >= TC2_MAX_CPUS_PER_CLUSTER);
|
||||||
|
|
||||||
|
for (tries = 0; tries < TIMEOUT_MSEC / POLL_MSEC; ++tries) {
|
||||||
|
/*
|
||||||
|
* Only examine the hardware state if the target CPU has
|
||||||
|
* caught up at least as far as tc2_pm_down():
|
||||||
|
*/
|
||||||
|
if (ACCESS_ONCE(tc2_pm_use_count[cpu][cluster]) == 0) {
|
||||||
|
pr_debug("%s(cpu=%u, cluster=%u): RESET_CTRL = 0x%08X\n",
|
||||||
|
__func__, cpu, cluster,
|
||||||
|
readl_relaxed(scc + RESET_CTRL));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need the CPU to reach WFI, but the power
|
||||||
|
* controller may put the cluster in reset and
|
||||||
|
* power it off as soon as that happens, before
|
||||||
|
* we have a chance to see STANDBYWFI.
|
||||||
|
*
|
||||||
|
* So we need to check for both conditions:
|
||||||
|
*/
|
||||||
|
if (tc2_core_in_reset(cpu, cluster) ||
|
||||||
|
ve_spc_cpu_in_wfi(cpu, cluster))
|
||||||
|
return 0; /* success: the CPU is halted */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, wait and retry: */
|
||||||
|
msleep(POLL_MSEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ETIMEDOUT; /* timeout */
|
||||||
|
}
|
||||||
|
|
||||||
static void tc2_pm_suspend(u64 residency)
|
static void tc2_pm_suspend(u64 residency)
|
||||||
{
|
{
|
||||||
unsigned int mpidr, cpu, cluster;
|
unsigned int mpidr, cpu, cluster;
|
||||||
|
@ -232,10 +288,11 @@ static void tc2_pm_powered_up(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct mcpm_platform_ops tc2_pm_power_ops = {
|
static const struct mcpm_platform_ops tc2_pm_power_ops = {
|
||||||
.power_up = tc2_pm_power_up,
|
.power_up = tc2_pm_power_up,
|
||||||
.power_down = tc2_pm_power_down,
|
.power_down = tc2_pm_power_down,
|
||||||
.suspend = tc2_pm_suspend,
|
.power_down_finish = tc2_pm_power_down_finish,
|
||||||
.powered_up = tc2_pm_powered_up,
|
.suspend = tc2_pm_suspend,
|
||||||
|
.powered_up = tc2_pm_powered_up,
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool __init tc2_pm_usage_count_init(void)
|
static bool __init tc2_pm_usage_count_init(void)
|
||||||
|
@ -269,7 +326,6 @@ static void __naked tc2_pm_power_up_setup(unsigned int affinity_level)
|
||||||
static int __init tc2_pm_init(void)
|
static int __init tc2_pm_init(void)
|
||||||
{
|
{
|
||||||
int ret, irq;
|
int ret, irq;
|
||||||
void __iomem *scc;
|
|
||||||
u32 a15_cluster_id, a7_cluster_id, sys_info;
|
u32 a15_cluster_id, a7_cluster_id, sys_info;
|
||||||
struct device_node *np;
|
struct device_node *np;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
|
/memreserve/ 0x80000000 0x00010000;
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
model = "Foundation-v8A";
|
model = "Foundation-v8A";
|
||||||
compatible = "arm,foundation-aarch64", "arm,vexpress";
|
compatible = "arm,foundation-aarch64", "arm,vexpress";
|
||||||
|
|
|
@ -56,6 +56,9 @@ static inline void arch_local_irq_disable(void)
|
||||||
#define local_fiq_enable() asm("msr daifclr, #1" : : : "memory")
|
#define local_fiq_enable() asm("msr daifclr, #1" : : : "memory")
|
||||||
#define local_fiq_disable() asm("msr daifset, #1" : : : "memory")
|
#define local_fiq_disable() asm("msr daifset, #1" : : : "memory")
|
||||||
|
|
||||||
|
#define local_async_enable() asm("msr daifclr, #4" : : : "memory")
|
||||||
|
#define local_async_disable() asm("msr daifset, #4" : : : "memory")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save the current interrupt enable state.
|
* Save the current interrupt enable state.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -25,10 +25,11 @@
|
||||||
* Software defined PTE bits definition.
|
* Software defined PTE bits definition.
|
||||||
*/
|
*/
|
||||||
#define PTE_VALID (_AT(pteval_t, 1) << 0)
|
#define PTE_VALID (_AT(pteval_t, 1) << 0)
|
||||||
#define PTE_PROT_NONE (_AT(pteval_t, 1) << 2) /* only when !PTE_VALID */
|
#define PTE_FILE (_AT(pteval_t, 1) << 2) /* only when !pte_present() */
|
||||||
#define PTE_FILE (_AT(pteval_t, 1) << 3) /* only when !pte_present() */
|
|
||||||
#define PTE_DIRTY (_AT(pteval_t, 1) << 55)
|
#define PTE_DIRTY (_AT(pteval_t, 1) << 55)
|
||||||
#define PTE_SPECIAL (_AT(pteval_t, 1) << 56)
|
#define PTE_SPECIAL (_AT(pteval_t, 1) << 56)
|
||||||
|
/* bit 57 for PMD_SECT_SPLITTING */
|
||||||
|
#define PTE_PROT_NONE (_AT(pteval_t, 1) << 58) /* only when !PTE_VALID */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VMALLOC and SPARSEMEM_VMEMMAP ranges.
|
* VMALLOC and SPARSEMEM_VMEMMAP ranges.
|
||||||
|
@ -254,7 +255,7 @@ static inline int has_transparent_hugepage(void)
|
||||||
#define pgprot_noncached(prot) \
|
#define pgprot_noncached(prot) \
|
||||||
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE))
|
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE))
|
||||||
#define pgprot_writecombine(prot) \
|
#define pgprot_writecombine(prot) \
|
||||||
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_GRE))
|
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC))
|
||||||
#define pgprot_dmacoherent(prot) \
|
#define pgprot_dmacoherent(prot) \
|
||||||
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC))
|
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC))
|
||||||
#define __HAVE_PHYS_MEM_ACCESS_PROT
|
#define __HAVE_PHYS_MEM_ACCESS_PROT
|
||||||
|
@ -357,18 +358,20 @@ extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Encode and decode a swap entry:
|
* Encode and decode a swap entry:
|
||||||
* bits 0, 2: present (must both be zero)
|
* bits 0-1: present (must be zero)
|
||||||
* bit 3: PTE_FILE
|
* bit 2: PTE_FILE
|
||||||
* bits 4-8: swap type
|
* bits 3-8: swap type
|
||||||
* bits 9-63: swap offset
|
* bits 9-57: swap offset
|
||||||
*/
|
*/
|
||||||
#define __SWP_TYPE_SHIFT 4
|
#define __SWP_TYPE_SHIFT 3
|
||||||
#define __SWP_TYPE_BITS 6
|
#define __SWP_TYPE_BITS 6
|
||||||
|
#define __SWP_OFFSET_BITS 49
|
||||||
#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1)
|
#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1)
|
||||||
#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
|
#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
|
||||||
|
#define __SWP_OFFSET_MASK ((1UL << __SWP_OFFSET_BITS) - 1)
|
||||||
|
|
||||||
#define __swp_type(x) (((x).val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK)
|
#define __swp_type(x) (((x).val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK)
|
||||||
#define __swp_offset(x) ((x).val >> __SWP_OFFSET_SHIFT)
|
#define __swp_offset(x) (((x).val >> __SWP_OFFSET_SHIFT) & __SWP_OFFSET_MASK)
|
||||||
#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << __SWP_TYPE_SHIFT) | ((offset) << __SWP_OFFSET_SHIFT) })
|
#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << __SWP_TYPE_SHIFT) | ((offset) << __SWP_OFFSET_SHIFT) })
|
||||||
|
|
||||||
#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
|
#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
|
||||||
|
@ -382,15 +385,15 @@ extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Encode and decode a file entry:
|
* Encode and decode a file entry:
|
||||||
* bits 0, 2: present (must both be zero)
|
* bits 0-1: present (must be zero)
|
||||||
* bit 3: PTE_FILE
|
* bit 2: PTE_FILE
|
||||||
* bits 4-63: file offset / PAGE_SIZE
|
* bits 3-57: file offset / PAGE_SIZE
|
||||||
*/
|
*/
|
||||||
#define pte_file(pte) (pte_val(pte) & PTE_FILE)
|
#define pte_file(pte) (pte_val(pte) & PTE_FILE)
|
||||||
#define pte_to_pgoff(x) (pte_val(x) >> 4)
|
#define pte_to_pgoff(x) (pte_val(x) >> 3)
|
||||||
#define pgoff_to_pte(x) __pte(((x) << 4) | PTE_FILE)
|
#define pgoff_to_pte(x) __pte(((x) << 3) | PTE_FILE)
|
||||||
|
|
||||||
#define PTE_FILE_MAX_BITS 60
|
#define PTE_FILE_MAX_BITS 55
|
||||||
|
|
||||||
extern int kern_addr_valid(unsigned long addr);
|
extern int kern_addr_valid(unsigned long addr);
|
||||||
|
|
||||||
|
|
|
@ -248,7 +248,8 @@ static int brk_handler(unsigned long addr, unsigned int esr,
|
||||||
int aarch32_break_handler(struct pt_regs *regs)
|
int aarch32_break_handler(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
siginfo_t info;
|
siginfo_t info;
|
||||||
unsigned int instr;
|
u32 arm_instr;
|
||||||
|
u16 thumb_instr;
|
||||||
bool bp = false;
|
bool bp = false;
|
||||||
void __user *pc = (void __user *)instruction_pointer(regs);
|
void __user *pc = (void __user *)instruction_pointer(regs);
|
||||||
|
|
||||||
|
@ -257,18 +258,21 @@ int aarch32_break_handler(struct pt_regs *regs)
|
||||||
|
|
||||||
if (compat_thumb_mode(regs)) {
|
if (compat_thumb_mode(regs)) {
|
||||||
/* get 16-bit Thumb instruction */
|
/* get 16-bit Thumb instruction */
|
||||||
get_user(instr, (u16 __user *)pc);
|
get_user(thumb_instr, (u16 __user *)pc);
|
||||||
if (instr == AARCH32_BREAK_THUMB2_LO) {
|
thumb_instr = le16_to_cpu(thumb_instr);
|
||||||
|
if (thumb_instr == AARCH32_BREAK_THUMB2_LO) {
|
||||||
/* get second half of 32-bit Thumb-2 instruction */
|
/* get second half of 32-bit Thumb-2 instruction */
|
||||||
get_user(instr, (u16 __user *)(pc + 2));
|
get_user(thumb_instr, (u16 __user *)(pc + 2));
|
||||||
bp = instr == AARCH32_BREAK_THUMB2_HI;
|
thumb_instr = le16_to_cpu(thumb_instr);
|
||||||
|
bp = thumb_instr == AARCH32_BREAK_THUMB2_HI;
|
||||||
} else {
|
} else {
|
||||||
bp = instr == AARCH32_BREAK_THUMB;
|
bp = thumb_instr == AARCH32_BREAK_THUMB;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* 32-bit ARM instruction */
|
/* 32-bit ARM instruction */
|
||||||
get_user(instr, (u32 __user *)pc);
|
get_user(arm_instr, (u32 __user *)pc);
|
||||||
bp = (instr & ~0xf0000000) == AARCH32_BREAK_ARM;
|
arm_instr = le32_to_cpu(arm_instr);
|
||||||
|
bp = (arm_instr & ~0xf0000000) == AARCH32_BREAK_ARM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bp)
|
if (!bp)
|
||||||
|
|
|
@ -309,15 +309,12 @@ el1_irq:
|
||||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||||
bl trace_hardirqs_off
|
bl trace_hardirqs_off
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
irq_handler
|
||||||
|
|
||||||
#ifdef CONFIG_PREEMPT
|
#ifdef CONFIG_PREEMPT
|
||||||
get_thread_info tsk
|
get_thread_info tsk
|
||||||
ldr w24, [tsk, #TI_PREEMPT] // get preempt count
|
ldr w24, [tsk, #TI_PREEMPT] // restore preempt count
|
||||||
add w0, w24, #1 // increment it
|
|
||||||
str w0, [tsk, #TI_PREEMPT]
|
|
||||||
#endif
|
|
||||||
irq_handler
|
|
||||||
#ifdef CONFIG_PREEMPT
|
|
||||||
str w24, [tsk, #TI_PREEMPT] // restore preempt count
|
|
||||||
cbnz w24, 1f // preempt count != 0
|
cbnz w24, 1f // preempt count != 0
|
||||||
ldr x0, [tsk, #TI_FLAGS] // get flags
|
ldr x0, [tsk, #TI_FLAGS] // get flags
|
||||||
tbz x0, #TIF_NEED_RESCHED, 1f // needs rescheduling?
|
tbz x0, #TIF_NEED_RESCHED, 1f // needs rescheduling?
|
||||||
|
@ -507,22 +504,10 @@ el0_irq_naked:
|
||||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||||
bl trace_hardirqs_off
|
bl trace_hardirqs_off
|
||||||
#endif
|
#endif
|
||||||
get_thread_info tsk
|
|
||||||
#ifdef CONFIG_PREEMPT
|
|
||||||
ldr w24, [tsk, #TI_PREEMPT] // get preempt count
|
|
||||||
add w23, w24, #1 // increment it
|
|
||||||
str w23, [tsk, #TI_PREEMPT]
|
|
||||||
#endif
|
|
||||||
irq_handler
|
irq_handler
|
||||||
#ifdef CONFIG_PREEMPT
|
get_thread_info tsk
|
||||||
ldr w0, [tsk, #TI_PREEMPT]
|
|
||||||
str w24, [tsk, #TI_PREEMPT]
|
|
||||||
cmp w0, w23
|
|
||||||
b.eq 1f
|
|
||||||
mov x1, #0
|
|
||||||
str x1, [x1] // BUG
|
|
||||||
1:
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||||
bl trace_hardirqs_on
|
bl trace_hardirqs_on
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -636,28 +636,27 @@ static int compat_gpr_get(struct task_struct *target,
|
||||||
|
|
||||||
for (i = 0; i < num_regs; ++i) {
|
for (i = 0; i < num_regs; ++i) {
|
||||||
unsigned int idx = start + i;
|
unsigned int idx = start + i;
|
||||||
void *reg;
|
compat_ulong_t reg;
|
||||||
|
|
||||||
switch (idx) {
|
switch (idx) {
|
||||||
case 15:
|
case 15:
|
||||||
reg = (void *)&task_pt_regs(target)->pc;
|
reg = task_pt_regs(target)->pc;
|
||||||
break;
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
reg = (void *)&task_pt_regs(target)->pstate;
|
reg = task_pt_regs(target)->pstate;
|
||||||
break;
|
break;
|
||||||
case 17:
|
case 17:
|
||||||
reg = (void *)&task_pt_regs(target)->orig_x0;
|
reg = task_pt_regs(target)->orig_x0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
reg = (void *)&task_pt_regs(target)->regs[idx];
|
reg = task_pt_regs(target)->regs[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = copy_to_user(ubuf, reg, sizeof(compat_ulong_t));
|
ret = copy_to_user(ubuf, ®, sizeof(reg));
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
else
|
|
||||||
ubuf += sizeof(compat_ulong_t);
|
ubuf += sizeof(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -685,28 +684,28 @@ static int compat_gpr_set(struct task_struct *target,
|
||||||
|
|
||||||
for (i = 0; i < num_regs; ++i) {
|
for (i = 0; i < num_regs; ++i) {
|
||||||
unsigned int idx = start + i;
|
unsigned int idx = start + i;
|
||||||
void *reg;
|
compat_ulong_t reg;
|
||||||
|
|
||||||
|
ret = copy_from_user(®, ubuf, sizeof(reg));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ubuf += sizeof(reg);
|
||||||
|
|
||||||
switch (idx) {
|
switch (idx) {
|
||||||
case 15:
|
case 15:
|
||||||
reg = (void *)&newregs.pc;
|
newregs.pc = reg;
|
||||||
break;
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
reg = (void *)&newregs.pstate;
|
newregs.pstate = reg;
|
||||||
break;
|
break;
|
||||||
case 17:
|
case 17:
|
||||||
reg = (void *)&newregs.orig_x0;
|
newregs.orig_x0 = reg;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
reg = (void *)&newregs.regs[idx];
|
newregs.regs[idx] = reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = copy_from_user(reg, ubuf, sizeof(compat_ulong_t));
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
goto out;
|
|
||||||
else
|
|
||||||
ubuf += sizeof(compat_ulong_t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valid_user_regs(&newregs.user_regs))
|
if (valid_user_regs(&newregs.user_regs))
|
||||||
|
@ -714,7 +713,6 @@ static int compat_gpr_set(struct task_struct *target,
|
||||||
else
|
else
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -205,6 +205,11 @@ u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID };
|
||||||
|
|
||||||
void __init setup_arch(char **cmdline_p)
|
void __init setup_arch(char **cmdline_p)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Unmask asynchronous aborts early to catch possible system errors.
|
||||||
|
*/
|
||||||
|
local_async_enable();
|
||||||
|
|
||||||
setup_processor();
|
setup_processor();
|
||||||
|
|
||||||
setup_machine_fdt(__fdt_pointer);
|
setup_machine_fdt(__fdt_pointer);
|
||||||
|
|
|
@ -160,6 +160,7 @@ asmlinkage void secondary_start_kernel(void)
|
||||||
|
|
||||||
local_irq_enable();
|
local_irq_enable();
|
||||||
local_fiq_enable();
|
local_fiq_enable();
|
||||||
|
local_async_enable();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OK, it's off to the idle thread for us
|
* OK, it's off to the idle thread for us
|
||||||
|
|
|
@ -75,8 +75,10 @@ LDEMULATION := lppc
|
||||||
GNUTARGET := powerpcle
|
GNUTARGET := powerpcle
|
||||||
MULTIPLEWORD := -mno-multiple
|
MULTIPLEWORD := -mno-multiple
|
||||||
else
|
else
|
||||||
|
ifeq ($(call cc-option-yn,-mbig-endian),y)
|
||||||
override CC += -mbig-endian
|
override CC += -mbig-endian
|
||||||
override AS += -mbig-endian
|
override AS += -mbig-endian
|
||||||
|
endif
|
||||||
override LD += -EB
|
override LD += -EB
|
||||||
LDEMULATION := ppc
|
LDEMULATION := ppc
|
||||||
GNUTARGET := powerpc
|
GNUTARGET := powerpc
|
||||||
|
@ -128,7 +130,12 @@ CFLAGS-$(CONFIG_POWER5_CPU) += $(call cc-option,-mcpu=power5)
|
||||||
CFLAGS-$(CONFIG_POWER6_CPU) += $(call cc-option,-mcpu=power6)
|
CFLAGS-$(CONFIG_POWER6_CPU) += $(call cc-option,-mcpu=power6)
|
||||||
CFLAGS-$(CONFIG_POWER7_CPU) += $(call cc-option,-mcpu=power7)
|
CFLAGS-$(CONFIG_POWER7_CPU) += $(call cc-option,-mcpu=power7)
|
||||||
|
|
||||||
|
# Altivec option not allowed with e500mc64 in GCC.
|
||||||
|
ifeq ($(CONFIG_ALTIVEC),y)
|
||||||
|
E5500_CPU := -mcpu=powerpc64
|
||||||
|
else
|
||||||
E5500_CPU := $(call cc-option,-mcpu=e500mc64,-mcpu=powerpc64)
|
E5500_CPU := $(call cc-option,-mcpu=e500mc64,-mcpu=powerpc64)
|
||||||
|
endif
|
||||||
CFLAGS-$(CONFIG_E5500_CPU) += $(E5500_CPU)
|
CFLAGS-$(CONFIG_E5500_CPU) += $(E5500_CPU)
|
||||||
CFLAGS-$(CONFIG_E6500_CPU) += $(call cc-option,-mcpu=e6500,$(E5500_CPU))
|
CFLAGS-$(CONFIG_E6500_CPU) += $(call cc-option,-mcpu=e6500,$(E5500_CPU))
|
||||||
|
|
||||||
|
|
|
@ -637,14 +637,14 @@
|
||||||
tlu@2f000 {
|
tlu@2f000 {
|
||||||
compatible = "fsl,mpc8572-tlu", "fsl_tlu";
|
compatible = "fsl,mpc8572-tlu", "fsl_tlu";
|
||||||
reg = <0x2f000 0x1000>;
|
reg = <0x2f000 0x1000>;
|
||||||
interupts = <61 2 >;
|
interrupts = <61 2>;
|
||||||
interrupt-parent = <&mpic>;
|
interrupt-parent = <&mpic>;
|
||||||
};
|
};
|
||||||
|
|
||||||
tlu@15000 {
|
tlu@15000 {
|
||||||
compatible = "fsl,mpc8572-tlu", "fsl_tlu";
|
compatible = "fsl,mpc8572-tlu", "fsl_tlu";
|
||||||
reg = <0x15000 0x1000>;
|
reg = <0x15000 0x1000>;
|
||||||
interupts = <75 2>;
|
interrupts = <75 2>;
|
||||||
interrupt-parent = <&mpic>;
|
interrupt-parent = <&mpic>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -547,14 +547,14 @@
|
||||||
tlu@2f000 {
|
tlu@2f000 {
|
||||||
compatible = "fsl,mpc8572-tlu", "fsl_tlu";
|
compatible = "fsl,mpc8572-tlu", "fsl_tlu";
|
||||||
reg = <0x2f000 0x1000>;
|
reg = <0x2f000 0x1000>;
|
||||||
interupts = <61 2 >;
|
interrupts = <61 2>;
|
||||||
interrupt-parent = <&mpic>;
|
interrupt-parent = <&mpic>;
|
||||||
};
|
};
|
||||||
|
|
||||||
tlu@15000 {
|
tlu@15000 {
|
||||||
compatible = "fsl,mpc8572-tlu", "fsl_tlu";
|
compatible = "fsl,mpc8572-tlu", "fsl_tlu";
|
||||||
reg = <0x15000 0x1000>;
|
reg = <0x15000 0x1000>;
|
||||||
interupts = <75 2>;
|
interrupts = <75 2>;
|
||||||
interrupt-parent = <&mpic>;
|
interrupt-parent = <&mpic>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -583,14 +583,14 @@
|
||||||
tlu@2f000 {
|
tlu@2f000 {
|
||||||
compatible = "fsl,mpc8572-tlu", "fsl_tlu";
|
compatible = "fsl,mpc8572-tlu", "fsl_tlu";
|
||||||
reg = <0x2f000 0x1000>;
|
reg = <0x2f000 0x1000>;
|
||||||
interupts = <61 2 >;
|
interrupts = <61 2>;
|
||||||
interrupt-parent = <&mpic>;
|
interrupt-parent = <&mpic>;
|
||||||
};
|
};
|
||||||
|
|
||||||
tlu@15000 {
|
tlu@15000 {
|
||||||
compatible = "fsl,mpc8572-tlu", "fsl_tlu";
|
compatible = "fsl,mpc8572-tlu", "fsl_tlu";
|
||||||
reg = <0x15000 0x1000>;
|
reg = <0x15000 0x1000>;
|
||||||
interupts = <75 2>;
|
interrupts = <75 2>;
|
||||||
interrupt-parent = <&mpic>;
|
interrupt-parent = <&mpic>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -545,14 +545,14 @@
|
||||||
tlu@2f000 {
|
tlu@2f000 {
|
||||||
compatible = "fsl,mpc8572-tlu", "fsl_tlu";
|
compatible = "fsl,mpc8572-tlu", "fsl_tlu";
|
||||||
reg = <0x2f000 0x1000>;
|
reg = <0x2f000 0x1000>;
|
||||||
interupts = <61 2 >;
|
interrupts = <61 2>;
|
||||||
interrupt-parent = <&mpic>;
|
interrupt-parent = <&mpic>;
|
||||||
};
|
};
|
||||||
|
|
||||||
tlu@15000 {
|
tlu@15000 {
|
||||||
compatible = "fsl,mpc8572-tlu", "fsl_tlu";
|
compatible = "fsl,mpc8572-tlu", "fsl_tlu";
|
||||||
reg = <0x15000 0x1000>;
|
reg = <0x15000 0x1000>;
|
||||||
interupts = <75 2>;
|
interrupts = <75 2>;
|
||||||
interrupt-parent = <&mpic>;
|
interrupt-parent = <&mpic>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -71,18 +71,32 @@ udelay:
|
||||||
add r4,r4,r5
|
add r4,r4,r5
|
||||||
addi r4,r4,-1
|
addi r4,r4,-1
|
||||||
divw r4,r4,r5 /* BUS ticks */
|
divw r4,r4,r5 /* BUS ticks */
|
||||||
|
#ifdef CONFIG_8xx
|
||||||
|
1: mftbu r5
|
||||||
|
mftb r6
|
||||||
|
mftbu r7
|
||||||
|
#else
|
||||||
1: mfspr r5, SPRN_TBRU
|
1: mfspr r5, SPRN_TBRU
|
||||||
mfspr r6, SPRN_TBRL
|
mfspr r6, SPRN_TBRL
|
||||||
mfspr r7, SPRN_TBRU
|
mfspr r7, SPRN_TBRU
|
||||||
|
#endif
|
||||||
cmpw 0,r5,r7
|
cmpw 0,r5,r7
|
||||||
bne 1b /* Get [synced] base time */
|
bne 1b /* Get [synced] base time */
|
||||||
addc r9,r6,r4 /* Compute end time */
|
addc r9,r6,r4 /* Compute end time */
|
||||||
addze r8,r5
|
addze r8,r5
|
||||||
|
#ifdef CONFIG_8xx
|
||||||
|
2: mftbu r5
|
||||||
|
#else
|
||||||
2: mfspr r5, SPRN_TBRU
|
2: mfspr r5, SPRN_TBRU
|
||||||
|
#endif
|
||||||
cmpw 0,r5,r8
|
cmpw 0,r5,r8
|
||||||
blt 2b
|
blt 2b
|
||||||
bgt 3f
|
bgt 3f
|
||||||
|
#ifdef CONFIG_8xx
|
||||||
|
mftb r6
|
||||||
|
#else
|
||||||
mfspr r6, SPRN_TBRL
|
mfspr r6, SPRN_TBRL
|
||||||
|
#endif
|
||||||
cmpw 0,r6,r9
|
cmpw 0,r6,r9
|
||||||
blt 2b
|
blt 2b
|
||||||
3: blr
|
3: blr
|
||||||
|
|
|
@ -16,6 +16,7 @@ struct vmemmap_backing {
|
||||||
unsigned long phys;
|
unsigned long phys;
|
||||||
unsigned long virt_addr;
|
unsigned long virt_addr;
|
||||||
};
|
};
|
||||||
|
extern struct vmemmap_backing *vmemmap_list;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Functions that deal with pagetables that could be at any level of
|
* Functions that deal with pagetables that could be at any level of
|
||||||
|
|
|
@ -366,6 +366,8 @@ BEGIN_FTR_SECTION_NESTED(96); \
|
||||||
cmpwi dest,0; \
|
cmpwi dest,0; \
|
||||||
beq- 90b; \
|
beq- 90b; \
|
||||||
END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96)
|
END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96)
|
||||||
|
#elif defined(CONFIG_8xx)
|
||||||
|
#define MFTB(dest) mftb dest
|
||||||
#else
|
#else
|
||||||
#define MFTB(dest) mfspr dest, SPRN_TBRL
|
#define MFTB(dest) mfspr dest, SPRN_TBRL
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1174,12 +1174,19 @@
|
||||||
|
|
||||||
#else /* __powerpc64__ */
|
#else /* __powerpc64__ */
|
||||||
|
|
||||||
|
#if defined(CONFIG_8xx)
|
||||||
|
#define mftbl() ({unsigned long rval; \
|
||||||
|
asm volatile("mftbl %0" : "=r" (rval)); rval;})
|
||||||
|
#define mftbu() ({unsigned long rval; \
|
||||||
|
asm volatile("mftbu %0" : "=r" (rval)); rval;})
|
||||||
|
#else
|
||||||
#define mftbl() ({unsigned long rval; \
|
#define mftbl() ({unsigned long rval; \
|
||||||
asm volatile("mfspr %0, %1" : "=r" (rval) : \
|
asm volatile("mfspr %0, %1" : "=r" (rval) : \
|
||||||
"i" (SPRN_TBRL)); rval;})
|
"i" (SPRN_TBRL)); rval;})
|
||||||
#define mftbu() ({unsigned long rval; \
|
#define mftbu() ({unsigned long rval; \
|
||||||
asm volatile("mfspr %0, %1" : "=r" (rval) : \
|
asm volatile("mfspr %0, %1" : "=r" (rval) : \
|
||||||
"i" (SPRN_TBRU)); rval;})
|
"i" (SPRN_TBRU)); rval;})
|
||||||
|
#endif
|
||||||
#endif /* !__powerpc64__ */
|
#endif /* !__powerpc64__ */
|
||||||
|
|
||||||
#define mttbl(v) asm volatile("mttbl %0":: "r"(v))
|
#define mttbl(v) asm volatile("mttbl %0":: "r"(v))
|
||||||
|
|
|
@ -29,7 +29,11 @@ static inline cycles_t get_cycles(void)
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
|
#ifdef CONFIG_8xx
|
||||||
|
"97: mftb %0\n"
|
||||||
|
#else
|
||||||
"97: mfspr %0, %2\n"
|
"97: mfspr %0, %2\n"
|
||||||
|
#endif
|
||||||
"99:\n"
|
"99:\n"
|
||||||
".section __ftr_fixup,\"a\"\n"
|
".section __ftr_fixup,\"a\"\n"
|
||||||
".align 2\n"
|
".align 2\n"
|
||||||
|
@ -41,7 +45,11 @@ static inline cycles_t get_cycles(void)
|
||||||
" .long 0\n"
|
" .long 0\n"
|
||||||
" .long 0\n"
|
" .long 0\n"
|
||||||
".previous"
|
".previous"
|
||||||
|
#ifdef CONFIG_8xx
|
||||||
|
: "=r" (ret) : "i" (CPU_FTR_601));
|
||||||
|
#else
|
||||||
: "=r" (ret) : "i" (CPU_FTR_601), "i" (SPRN_TBRL));
|
: "=r" (ret) : "i" (CPU_FTR_601), "i" (SPRN_TBRL));
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <linux/ftrace.h>
|
#include <linux/ftrace.h>
|
||||||
|
|
||||||
#include <asm/machdep.h>
|
#include <asm/machdep.h>
|
||||||
|
#include <asm/pgalloc.h>
|
||||||
#include <asm/prom.h>
|
#include <asm/prom.h>
|
||||||
#include <asm/sections.h>
|
#include <asm/sections.h>
|
||||||
|
|
||||||
|
@ -75,6 +76,17 @@ void arch_crash_save_vmcoreinfo(void)
|
||||||
#ifndef CONFIG_NEED_MULTIPLE_NODES
|
#ifndef CONFIG_NEED_MULTIPLE_NODES
|
||||||
VMCOREINFO_SYMBOL(contig_page_data);
|
VMCOREINFO_SYMBOL(contig_page_data);
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(CONFIG_PPC64) && defined(CONFIG_SPARSEMEM_VMEMMAP)
|
||||||
|
VMCOREINFO_SYMBOL(vmemmap_list);
|
||||||
|
VMCOREINFO_SYMBOL(mmu_vmemmap_psize);
|
||||||
|
VMCOREINFO_SYMBOL(mmu_psize_defs);
|
||||||
|
VMCOREINFO_STRUCT_SIZE(vmemmap_backing);
|
||||||
|
VMCOREINFO_OFFSET(vmemmap_backing, list);
|
||||||
|
VMCOREINFO_OFFSET(vmemmap_backing, phys);
|
||||||
|
VMCOREINFO_OFFSET(vmemmap_backing, virt_addr);
|
||||||
|
VMCOREINFO_STRUCT_SIZE(mmu_psize_def);
|
||||||
|
VMCOREINFO_OFFSET(mmu_psize_def, shift);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -210,7 +210,7 @@ static void __init nvram_print_partitions(char * label)
|
||||||
printk(KERN_WARNING "--------%s---------\n", label);
|
printk(KERN_WARNING "--------%s---------\n", label);
|
||||||
printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n");
|
printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n");
|
||||||
list_for_each_entry(tmp_part, &nvram_partitions, partition) {
|
list_for_each_entry(tmp_part, &nvram_partitions, partition) {
|
||||||
printk(KERN_WARNING "%4d \t%02x\t%02x\t%d\t%12s\n",
|
printk(KERN_WARNING "%4d \t%02x\t%02x\t%d\t%12.12s\n",
|
||||||
tmp_part->index, tmp_part->header.signature,
|
tmp_part->index, tmp_part->header.signature,
|
||||||
tmp_part->header.checksum, tmp_part->header.length,
|
tmp_part->header.checksum, tmp_part->header.length,
|
||||||
tmp_part->header.name);
|
tmp_part->header.name);
|
||||||
|
|
|
@ -445,6 +445,12 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
|
||||||
#endif /* CONFIG_ALTIVEC */
|
#endif /* CONFIG_ALTIVEC */
|
||||||
if (copy_fpr_to_user(&frame->mc_fregs, current))
|
if (copy_fpr_to_user(&frame->mc_fregs, current))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear the MSR VSX bit to indicate there is no valid state attached
|
||||||
|
* to this context, except in the specific case below where we set it.
|
||||||
|
*/
|
||||||
|
msr &= ~MSR_VSX;
|
||||||
#ifdef CONFIG_VSX
|
#ifdef CONFIG_VSX
|
||||||
/*
|
/*
|
||||||
* Copy VSR 0-31 upper half from thread_struct to local
|
* Copy VSR 0-31 upper half from thread_struct to local
|
||||||
|
@ -457,15 +463,7 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
|
||||||
if (copy_vsx_to_user(&frame->mc_vsregs, current))
|
if (copy_vsx_to_user(&frame->mc_vsregs, current))
|
||||||
return 1;
|
return 1;
|
||||||
msr |= MSR_VSX;
|
msr |= MSR_VSX;
|
||||||
} else if (!ctx_has_vsx_region)
|
}
|
||||||
/*
|
|
||||||
* With a small context structure we can't hold the VSX
|
|
||||||
* registers, hence clear the MSR value to indicate the state
|
|
||||||
* was not saved.
|
|
||||||
*/
|
|
||||||
msr &= ~MSR_VSX;
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* CONFIG_VSX */
|
#endif /* CONFIG_VSX */
|
||||||
#ifdef CONFIG_SPE
|
#ifdef CONFIG_SPE
|
||||||
/* save spe registers */
|
/* save spe registers */
|
||||||
|
|
|
@ -122,6 +122,12 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
|
||||||
flush_fp_to_thread(current);
|
flush_fp_to_thread(current);
|
||||||
/* copy fpr regs and fpscr */
|
/* copy fpr regs and fpscr */
|
||||||
err |= copy_fpr_to_user(&sc->fp_regs, current);
|
err |= copy_fpr_to_user(&sc->fp_regs, current);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear the MSR VSX bit to indicate there is no valid state attached
|
||||||
|
* to this context, except in the specific case below where we set it.
|
||||||
|
*/
|
||||||
|
msr &= ~MSR_VSX;
|
||||||
#ifdef CONFIG_VSX
|
#ifdef CONFIG_VSX
|
||||||
/*
|
/*
|
||||||
* Copy VSX low doubleword to local buffer for formatting,
|
* Copy VSX low doubleword to local buffer for formatting,
|
||||||
|
|
|
@ -232,9 +232,15 @@ __do_get_tspec:
|
||||||
lwz r6,(CFG_TB_ORIG_STAMP+4)(r9)
|
lwz r6,(CFG_TB_ORIG_STAMP+4)(r9)
|
||||||
|
|
||||||
/* Get a stable TB value */
|
/* Get a stable TB value */
|
||||||
|
#ifdef CONFIG_8xx
|
||||||
|
2: mftbu r3
|
||||||
|
mftbl r4
|
||||||
|
mftbu r0
|
||||||
|
#else
|
||||||
2: mfspr r3, SPRN_TBRU
|
2: mfspr r3, SPRN_TBRU
|
||||||
mfspr r4, SPRN_TBRL
|
mfspr r4, SPRN_TBRL
|
||||||
mfspr r0, SPRN_TBRU
|
mfspr r0, SPRN_TBRU
|
||||||
|
#endif
|
||||||
cmplw cr0,r3,r0
|
cmplw cr0,r3,r0
|
||||||
bne- 2b
|
bne- 2b
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,5 @@ void flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
|
||||||
struct hstate *hstate = hstate_file(vma->vm_file);
|
struct hstate *hstate = hstate_file(vma->vm_file);
|
||||||
unsigned long tsize = huge_page_shift(hstate) - 10;
|
unsigned long tsize = huge_page_shift(hstate) - 10;
|
||||||
|
|
||||||
__flush_tlb_page(vma ? vma->vm_mm : NULL, vmaddr, tsize, 0);
|
__flush_tlb_page(vma->vm_mm, vmaddr, tsize, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,7 +305,7 @@ void __flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
|
||||||
void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
|
void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_HUGETLB_PAGE
|
#ifdef CONFIG_HUGETLB_PAGE
|
||||||
if (is_vm_hugetlb_page(vma))
|
if (vma && is_vm_hugetlb_page(vma))
|
||||||
flush_hugetlb_page(vma, vmaddr);
|
flush_hugetlb_page(vma, vmaddr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -404,13 +404,27 @@ config PPC_DOORBELL
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
config CPU_LITTLE_ENDIAN
|
choice
|
||||||
bool "Build little endian kernel"
|
prompt "Endianness selection"
|
||||||
default n
|
default CPU_BIG_ENDIAN
|
||||||
help
|
help
|
||||||
This option selects whether a big endian or little endian kernel will
|
This option selects whether a big endian or little endian kernel will
|
||||||
be built.
|
be built.
|
||||||
|
|
||||||
|
config CPU_BIG_ENDIAN
|
||||||
|
bool "Build big endian kernel"
|
||||||
|
help
|
||||||
|
Build a big endian kernel.
|
||||||
|
|
||||||
|
If unsure, select this option.
|
||||||
|
|
||||||
|
config CPU_LITTLE_ENDIAN
|
||||||
|
bool "Build little endian kernel"
|
||||||
|
help
|
||||||
|
Build a little endian kernel.
|
||||||
|
|
||||||
Note that if cross compiling a little endian kernel,
|
Note that if cross compiling a little endian kernel,
|
||||||
CROSS_COMPILE must point to a toolchain capable of targeting
|
CROSS_COMPILE must point to a toolchain capable of targeting
|
||||||
little endian powerpc.
|
little endian powerpc.
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
|
@ -101,7 +101,7 @@ config S390
|
||||||
select GENERIC_CPU_DEVICES if !SMP
|
select GENERIC_CPU_DEVICES if !SMP
|
||||||
select GENERIC_FIND_FIRST_BIT
|
select GENERIC_FIND_FIRST_BIT
|
||||||
select GENERIC_SMP_IDLE_THREAD
|
select GENERIC_SMP_IDLE_THREAD
|
||||||
select GENERIC_TIME_VSYSCALL_OLD
|
select GENERIC_TIME_VSYSCALL
|
||||||
select HAVE_ALIGNED_STRUCT_PAGE if SLUB
|
select HAVE_ALIGNED_STRUCT_PAGE if SLUB
|
||||||
select HAVE_ARCH_JUMP_LABEL if !MARCH_G5
|
select HAVE_ARCH_JUMP_LABEL if !MARCH_G5
|
||||||
select HAVE_ARCH_SECCOMP_FILTER
|
select HAVE_ARCH_SECCOMP_FILTER
|
||||||
|
|
|
@ -35,7 +35,6 @@ static u8 *ctrblk;
|
||||||
static char keylen_flag;
|
static char keylen_flag;
|
||||||
|
|
||||||
struct s390_aes_ctx {
|
struct s390_aes_ctx {
|
||||||
u8 iv[AES_BLOCK_SIZE];
|
|
||||||
u8 key[AES_MAX_KEY_SIZE];
|
u8 key[AES_MAX_KEY_SIZE];
|
||||||
long enc;
|
long enc;
|
||||||
long dec;
|
long dec;
|
||||||
|
@ -441,30 +440,36 @@ static int cbc_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
|
||||||
return aes_set_key(tfm, in_key, key_len);
|
return aes_set_key(tfm, in_key, key_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cbc_aes_crypt(struct blkcipher_desc *desc, long func, void *param,
|
static int cbc_aes_crypt(struct blkcipher_desc *desc, long func,
|
||||||
struct blkcipher_walk *walk)
|
struct blkcipher_walk *walk)
|
||||||
{
|
{
|
||||||
|
struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
|
||||||
int ret = blkcipher_walk_virt(desc, walk);
|
int ret = blkcipher_walk_virt(desc, walk);
|
||||||
unsigned int nbytes = walk->nbytes;
|
unsigned int nbytes = walk->nbytes;
|
||||||
|
struct {
|
||||||
|
u8 iv[AES_BLOCK_SIZE];
|
||||||
|
u8 key[AES_MAX_KEY_SIZE];
|
||||||
|
} param;
|
||||||
|
|
||||||
if (!nbytes)
|
if (!nbytes)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
memcpy(param, walk->iv, AES_BLOCK_SIZE);
|
memcpy(param.iv, walk->iv, AES_BLOCK_SIZE);
|
||||||
|
memcpy(param.key, sctx->key, sctx->key_len);
|
||||||
do {
|
do {
|
||||||
/* only use complete blocks */
|
/* only use complete blocks */
|
||||||
unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1);
|
unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1);
|
||||||
u8 *out = walk->dst.virt.addr;
|
u8 *out = walk->dst.virt.addr;
|
||||||
u8 *in = walk->src.virt.addr;
|
u8 *in = walk->src.virt.addr;
|
||||||
|
|
||||||
ret = crypt_s390_kmc(func, param, out, in, n);
|
ret = crypt_s390_kmc(func, ¶m, out, in, n);
|
||||||
if (ret < 0 || ret != n)
|
if (ret < 0 || ret != n)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
nbytes &= AES_BLOCK_SIZE - 1;
|
nbytes &= AES_BLOCK_SIZE - 1;
|
||||||
ret = blkcipher_walk_done(desc, walk, nbytes);
|
ret = blkcipher_walk_done(desc, walk, nbytes);
|
||||||
} while ((nbytes = walk->nbytes));
|
} while ((nbytes = walk->nbytes));
|
||||||
memcpy(walk->iv, param, AES_BLOCK_SIZE);
|
memcpy(walk->iv, param.iv, AES_BLOCK_SIZE);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -481,7 +486,7 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc,
|
||||||
return fallback_blk_enc(desc, dst, src, nbytes);
|
return fallback_blk_enc(desc, dst, src, nbytes);
|
||||||
|
|
||||||
blkcipher_walk_init(&walk, dst, src, nbytes);
|
blkcipher_walk_init(&walk, dst, src, nbytes);
|
||||||
return cbc_aes_crypt(desc, sctx->enc, sctx->iv, &walk);
|
return cbc_aes_crypt(desc, sctx->enc, &walk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cbc_aes_decrypt(struct blkcipher_desc *desc,
|
static int cbc_aes_decrypt(struct blkcipher_desc *desc,
|
||||||
|
@ -495,7 +500,7 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc,
|
||||||
return fallback_blk_dec(desc, dst, src, nbytes);
|
return fallback_blk_dec(desc, dst, src, nbytes);
|
||||||
|
|
||||||
blkcipher_walk_init(&walk, dst, src, nbytes);
|
blkcipher_walk_init(&walk, dst, src, nbytes);
|
||||||
return cbc_aes_crypt(desc, sctx->dec, sctx->iv, &walk);
|
return cbc_aes_crypt(desc, sctx->dec, &walk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct crypto_alg cbc_aes_alg = {
|
static struct crypto_alg cbc_aes_alg = {
|
||||||
|
|
|
@ -48,33 +48,21 @@ static inline void clear_page(void *page)
|
||||||
: "memory", "cc");
|
: "memory", "cc");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* copy_page uses the mvcl instruction with 0xb0 padding byte in order to
|
||||||
|
* bypass caches when copying a page. Especially when copying huge pages
|
||||||
|
* this keeps L1 and L2 data caches alive.
|
||||||
|
*/
|
||||||
static inline void copy_page(void *to, void *from)
|
static inline void copy_page(void *to, void *from)
|
||||||
{
|
{
|
||||||
if (MACHINE_HAS_MVPG) {
|
register void *reg2 asm ("2") = to;
|
||||||
register unsigned long reg0 asm ("0") = 0;
|
register unsigned long reg3 asm ("3") = 0x1000;
|
||||||
asm volatile(
|
register void *reg4 asm ("4") = from;
|
||||||
" mvpg %0,%1"
|
register unsigned long reg5 asm ("5") = 0xb0001000;
|
||||||
: : "a" (to), "a" (from), "d" (reg0)
|
asm volatile(
|
||||||
: "memory", "cc");
|
" mvcl 2,4"
|
||||||
} else
|
: "+d" (reg2), "+d" (reg3), "+d" (reg4), "+d" (reg5)
|
||||||
asm volatile(
|
: : "memory", "cc");
|
||||||
" mvc 0(256,%0),0(%1)\n"
|
|
||||||
" mvc 256(256,%0),256(%1)\n"
|
|
||||||
" mvc 512(256,%0),512(%1)\n"
|
|
||||||
" mvc 768(256,%0),768(%1)\n"
|
|
||||||
" mvc 1024(256,%0),1024(%1)\n"
|
|
||||||
" mvc 1280(256,%0),1280(%1)\n"
|
|
||||||
" mvc 1536(256,%0),1536(%1)\n"
|
|
||||||
" mvc 1792(256,%0),1792(%1)\n"
|
|
||||||
" mvc 2048(256,%0),2048(%1)\n"
|
|
||||||
" mvc 2304(256,%0),2304(%1)\n"
|
|
||||||
" mvc 2560(256,%0),2560(%1)\n"
|
|
||||||
" mvc 2816(256,%0),2816(%1)\n"
|
|
||||||
" mvc 3072(256,%0),3072(%1)\n"
|
|
||||||
" mvc 3328(256,%0),3328(%1)\n"
|
|
||||||
" mvc 3584(256,%0),3584(%1)\n"
|
|
||||||
" mvc 3840(256,%0),3840(%1)\n"
|
|
||||||
: : "a" (to), "a" (from) : "memory");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define clear_user_page(page, vaddr, pg) clear_page(page)
|
#define clear_user_page(page, vaddr, pg) clear_page(page)
|
||||||
|
|
|
@ -26,8 +26,9 @@ struct vdso_data {
|
||||||
__u64 wtom_clock_nsec; /* 0x28 */
|
__u64 wtom_clock_nsec; /* 0x28 */
|
||||||
__u32 tz_minuteswest; /* Minutes west of Greenwich 0x30 */
|
__u32 tz_minuteswest; /* Minutes west of Greenwich 0x30 */
|
||||||
__u32 tz_dsttime; /* Type of dst correction 0x34 */
|
__u32 tz_dsttime; /* Type of dst correction 0x34 */
|
||||||
__u32 ectg_available;
|
__u32 ectg_available; /* ECTG instruction present 0x38 */
|
||||||
__u32 ntp_mult; /* NTP adjusted multiplier 0x3C */
|
__u32 tk_mult; /* Mult. used for xtime_nsec 0x3c */
|
||||||
|
__u32 tk_shift; /* Shift used for xtime_nsec 0x40 */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vdso_per_cpu_data {
|
struct vdso_per_cpu_data {
|
||||||
|
|
|
@ -65,7 +65,8 @@ int main(void)
|
||||||
DEFINE(__VDSO_WTOM_NSEC, offsetof(struct vdso_data, wtom_clock_nsec));
|
DEFINE(__VDSO_WTOM_NSEC, offsetof(struct vdso_data, wtom_clock_nsec));
|
||||||
DEFINE(__VDSO_TIMEZONE, offsetof(struct vdso_data, tz_minuteswest));
|
DEFINE(__VDSO_TIMEZONE, offsetof(struct vdso_data, tz_minuteswest));
|
||||||
DEFINE(__VDSO_ECTG_OK, offsetof(struct vdso_data, ectg_available));
|
DEFINE(__VDSO_ECTG_OK, offsetof(struct vdso_data, ectg_available));
|
||||||
DEFINE(__VDSO_NTP_MULT, offsetof(struct vdso_data, ntp_mult));
|
DEFINE(__VDSO_TK_MULT, offsetof(struct vdso_data, tk_mult));
|
||||||
|
DEFINE(__VDSO_TK_SHIFT, offsetof(struct vdso_data, tk_shift));
|
||||||
DEFINE(__VDSO_ECTG_BASE, offsetof(struct vdso_per_cpu_data, ectg_timer_base));
|
DEFINE(__VDSO_ECTG_BASE, offsetof(struct vdso_per_cpu_data, ectg_timer_base));
|
||||||
DEFINE(__VDSO_ECTG_USER, offsetof(struct vdso_per_cpu_data, ectg_user_time));
|
DEFINE(__VDSO_ECTG_USER, offsetof(struct vdso_per_cpu_data, ectg_user_time));
|
||||||
/* constants used by the vdso */
|
/* constants used by the vdso */
|
||||||
|
|
|
@ -194,7 +194,7 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */
|
/* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */
|
||||||
regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
|
regs->psw.mask = (regs->psw.mask & ~(PSW_MASK_USER | PSW_MASK_RI)) |
|
||||||
(__u64)(user_sregs.regs.psw.mask & PSW32_MASK_USER) << 32 |
|
(__u64)(user_sregs.regs.psw.mask & PSW32_MASK_USER) << 32 |
|
||||||
(__u64)(user_sregs.regs.psw.mask & PSW32_MASK_RI) << 32 |
|
(__u64)(user_sregs.regs.psw.mask & PSW32_MASK_RI) << 32 |
|
||||||
(__u64)(user_sregs.regs.psw.addr & PSW32_ADDR_AMODE);
|
(__u64)(user_sregs.regs.psw.addr & PSW32_ADDR_AMODE);
|
||||||
|
|
|
@ -78,7 +78,7 @@ PGM_CHECK_DEFAULT /* 34 */
|
||||||
PGM_CHECK_DEFAULT /* 35 */
|
PGM_CHECK_DEFAULT /* 35 */
|
||||||
PGM_CHECK_DEFAULT /* 36 */
|
PGM_CHECK_DEFAULT /* 36 */
|
||||||
PGM_CHECK_DEFAULT /* 37 */
|
PGM_CHECK_DEFAULT /* 37 */
|
||||||
PGM_CHECK_DEFAULT /* 38 */
|
PGM_CHECK_64BIT(do_dat_exception) /* 38 */
|
||||||
PGM_CHECK_64BIT(do_dat_exception) /* 39 */
|
PGM_CHECK_64BIT(do_dat_exception) /* 39 */
|
||||||
PGM_CHECK_64BIT(do_dat_exception) /* 3a */
|
PGM_CHECK_64BIT(do_dat_exception) /* 3a */
|
||||||
PGM_CHECK_64BIT(do_dat_exception) /* 3b */
|
PGM_CHECK_64BIT(do_dat_exception) /* 3b */
|
||||||
|
|
|
@ -94,7 +94,7 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */
|
/* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */
|
||||||
regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
|
regs->psw.mask = (regs->psw.mask & ~(PSW_MASK_USER | PSW_MASK_RI)) |
|
||||||
(user_sregs.regs.psw.mask & (PSW_MASK_USER | PSW_MASK_RI));
|
(user_sregs.regs.psw.mask & (PSW_MASK_USER | PSW_MASK_RI));
|
||||||
/* Check for invalid user address space control. */
|
/* Check for invalid user address space control. */
|
||||||
if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_HOME)
|
if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_HOME)
|
||||||
|
|
|
@ -108,20 +108,10 @@ static void fixup_clock_comparator(unsigned long long delta)
|
||||||
set_clock_comparator(S390_lowcore.clock_comparator);
|
set_clock_comparator(S390_lowcore.clock_comparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int s390_next_ktime(ktime_t expires,
|
static int s390_next_event(unsigned long delta,
|
||||||
struct clock_event_device *evt)
|
struct clock_event_device *evt)
|
||||||
{
|
{
|
||||||
struct timespec ts;
|
S390_lowcore.clock_comparator = get_tod_clock() + delta;
|
||||||
u64 nsecs;
|
|
||||||
|
|
||||||
ts.tv_sec = ts.tv_nsec = 0;
|
|
||||||
monotonic_to_bootbased(&ts);
|
|
||||||
nsecs = ktime_to_ns(ktime_add(timespec_to_ktime(ts), expires));
|
|
||||||
do_div(nsecs, 125);
|
|
||||||
S390_lowcore.clock_comparator = sched_clock_base_cc + (nsecs << 9);
|
|
||||||
/* Program the maximum value if we have an overflow (== year 2042) */
|
|
||||||
if (unlikely(S390_lowcore.clock_comparator < sched_clock_base_cc))
|
|
||||||
S390_lowcore.clock_comparator = -1ULL;
|
|
||||||
set_clock_comparator(S390_lowcore.clock_comparator);
|
set_clock_comparator(S390_lowcore.clock_comparator);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -146,15 +136,14 @@ void init_cpu_timer(void)
|
||||||
cpu = smp_processor_id();
|
cpu = smp_processor_id();
|
||||||
cd = &per_cpu(comparators, cpu);
|
cd = &per_cpu(comparators, cpu);
|
||||||
cd->name = "comparator";
|
cd->name = "comparator";
|
||||||
cd->features = CLOCK_EVT_FEAT_ONESHOT |
|
cd->features = CLOCK_EVT_FEAT_ONESHOT;
|
||||||
CLOCK_EVT_FEAT_KTIME;
|
|
||||||
cd->mult = 16777;
|
cd->mult = 16777;
|
||||||
cd->shift = 12;
|
cd->shift = 12;
|
||||||
cd->min_delta_ns = 1;
|
cd->min_delta_ns = 1;
|
||||||
cd->max_delta_ns = LONG_MAX;
|
cd->max_delta_ns = LONG_MAX;
|
||||||
cd->rating = 400;
|
cd->rating = 400;
|
||||||
cd->cpumask = cpumask_of(cpu);
|
cd->cpumask = cpumask_of(cpu);
|
||||||
cd->set_next_ktime = s390_next_ktime;
|
cd->set_next_event = s390_next_event;
|
||||||
cd->set_mode = s390_set_mode;
|
cd->set_mode = s390_set_mode;
|
||||||
|
|
||||||
clockevents_register_device(cd);
|
clockevents_register_device(cd);
|
||||||
|
@ -221,21 +210,30 @@ struct clocksource * __init clocksource_default_clock(void)
|
||||||
return &clocksource_tod;
|
return &clocksource_tod;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_vsyscall_old(struct timespec *wall_time, struct timespec *wtm,
|
void update_vsyscall(struct timekeeper *tk)
|
||||||
struct clocksource *clock, u32 mult)
|
|
||||||
{
|
{
|
||||||
if (clock != &clocksource_tod)
|
u64 nsecps;
|
||||||
|
|
||||||
|
if (tk->clock != &clocksource_tod)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Make userspace gettimeofday spin until we're done. */
|
/* Make userspace gettimeofday spin until we're done. */
|
||||||
++vdso_data->tb_update_count;
|
++vdso_data->tb_update_count;
|
||||||
smp_wmb();
|
smp_wmb();
|
||||||
vdso_data->xtime_tod_stamp = clock->cycle_last;
|
vdso_data->xtime_tod_stamp = tk->clock->cycle_last;
|
||||||
vdso_data->xtime_clock_sec = wall_time->tv_sec;
|
vdso_data->xtime_clock_sec = tk->xtime_sec;
|
||||||
vdso_data->xtime_clock_nsec = wall_time->tv_nsec;
|
vdso_data->xtime_clock_nsec = tk->xtime_nsec;
|
||||||
vdso_data->wtom_clock_sec = wtm->tv_sec;
|
vdso_data->wtom_clock_sec =
|
||||||
vdso_data->wtom_clock_nsec = wtm->tv_nsec;
|
tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
|
||||||
vdso_data->ntp_mult = mult;
|
vdso_data->wtom_clock_nsec = tk->xtime_nsec +
|
||||||
|
+ (tk->wall_to_monotonic.tv_nsec << tk->shift);
|
||||||
|
nsecps = (u64) NSEC_PER_SEC << tk->shift;
|
||||||
|
while (vdso_data->wtom_clock_nsec >= nsecps) {
|
||||||
|
vdso_data->wtom_clock_nsec -= nsecps;
|
||||||
|
vdso_data->wtom_clock_sec++;
|
||||||
|
}
|
||||||
|
vdso_data->tk_mult = tk->mult;
|
||||||
|
vdso_data->tk_shift = tk->shift;
|
||||||
smp_wmb();
|
smp_wmb();
|
||||||
++vdso_data->tb_update_count;
|
++vdso_data->tb_update_count;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,25 +38,26 @@ __kernel_clock_gettime:
|
||||||
sl %r1,__VDSO_XTIME_STAMP+4(%r5)
|
sl %r1,__VDSO_XTIME_STAMP+4(%r5)
|
||||||
brc 3,2f
|
brc 3,2f
|
||||||
ahi %r0,-1
|
ahi %r0,-1
|
||||||
2: ms %r0,__VDSO_NTP_MULT(%r5) /* cyc2ns(clock,cycle_delta) */
|
2: ms %r0,__VDSO_TK_MULT(%r5) /* * tk->mult */
|
||||||
lr %r2,%r0
|
lr %r2,%r0
|
||||||
l %r0,__VDSO_NTP_MULT(%r5)
|
l %r0,__VDSO_TK_MULT(%r5)
|
||||||
ltr %r1,%r1
|
ltr %r1,%r1
|
||||||
mr %r0,%r0
|
mr %r0,%r0
|
||||||
jnm 3f
|
jnm 3f
|
||||||
a %r0,__VDSO_NTP_MULT(%r5)
|
a %r0,__VDSO_TK_MULT(%r5)
|
||||||
3: alr %r0,%r2
|
3: alr %r0,%r2
|
||||||
srdl %r0,12
|
al %r0,__VDSO_XTIME_NSEC(%r5) /* + tk->xtime_nsec */
|
||||||
al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */
|
|
||||||
al %r1,__VDSO_XTIME_NSEC+4(%r5)
|
al %r1,__VDSO_XTIME_NSEC+4(%r5)
|
||||||
brc 12,4f
|
brc 12,4f
|
||||||
ahi %r0,1
|
ahi %r0,1
|
||||||
4: l %r2,__VDSO_XTIME_SEC+4(%r5)
|
4: al %r0,__VDSO_WTOM_NSEC(%r5) /* + wall_to_monotonic.nsec */
|
||||||
al %r0,__VDSO_WTOM_NSEC(%r5) /* + wall_to_monotonic */
|
|
||||||
al %r1,__VDSO_WTOM_NSEC+4(%r5)
|
al %r1,__VDSO_WTOM_NSEC+4(%r5)
|
||||||
brc 12,5f
|
brc 12,5f
|
||||||
ahi %r0,1
|
ahi %r0,1
|
||||||
5: al %r2,__VDSO_WTOM_SEC+4(%r5)
|
5: l %r2,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */
|
||||||
|
srdl %r0,0(%r2) /* >> tk->shift */
|
||||||
|
l %r2,__VDSO_XTIME_SEC+4(%r5)
|
||||||
|
al %r2,__VDSO_WTOM_SEC+4(%r5)
|
||||||
cl %r4,__VDSO_UPD_COUNT+4(%r5) /* check update counter */
|
cl %r4,__VDSO_UPD_COUNT+4(%r5) /* check update counter */
|
||||||
jne 1b
|
jne 1b
|
||||||
basr %r5,0
|
basr %r5,0
|
||||||
|
@ -86,20 +87,21 @@ __kernel_clock_gettime:
|
||||||
sl %r1,__VDSO_XTIME_STAMP+4(%r5)
|
sl %r1,__VDSO_XTIME_STAMP+4(%r5)
|
||||||
brc 3,12f
|
brc 3,12f
|
||||||
ahi %r0,-1
|
ahi %r0,-1
|
||||||
12: ms %r0,__VDSO_NTP_MULT(%r5) /* cyc2ns(clock,cycle_delta) */
|
12: ms %r0,__VDSO_TK_MULT(%r5) /* * tk->mult */
|
||||||
lr %r2,%r0
|
lr %r2,%r0
|
||||||
l %r0,__VDSO_NTP_MULT(%r5)
|
l %r0,__VDSO_TK_MULT(%r5)
|
||||||
ltr %r1,%r1
|
ltr %r1,%r1
|
||||||
mr %r0,%r0
|
mr %r0,%r0
|
||||||
jnm 13f
|
jnm 13f
|
||||||
a %r0,__VDSO_NTP_MULT(%r5)
|
a %r0,__VDSO_TK_MULT(%r5)
|
||||||
13: alr %r0,%r2
|
13: alr %r0,%r2
|
||||||
srdl %r0,12
|
al %r0,__VDSO_XTIME_NSEC(%r5) /* + tk->xtime_nsec */
|
||||||
al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */
|
|
||||||
al %r1,__VDSO_XTIME_NSEC+4(%r5)
|
al %r1,__VDSO_XTIME_NSEC+4(%r5)
|
||||||
brc 12,14f
|
brc 12,14f
|
||||||
ahi %r0,1
|
ahi %r0,1
|
||||||
14: l %r2,__VDSO_XTIME_SEC+4(%r5)
|
14: l %r2,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */
|
||||||
|
srdl %r0,0(%r2) /* >> tk->shift */
|
||||||
|
l %r2,__VDSO_XTIME_SEC+4(%r5)
|
||||||
cl %r4,__VDSO_UPD_COUNT+4(%r5) /* check update counter */
|
cl %r4,__VDSO_UPD_COUNT+4(%r5) /* check update counter */
|
||||||
jne 11b
|
jne 11b
|
||||||
basr %r5,0
|
basr %r5,0
|
||||||
|
|
|
@ -35,15 +35,14 @@ __kernel_gettimeofday:
|
||||||
sl %r1,__VDSO_XTIME_STAMP+4(%r5)
|
sl %r1,__VDSO_XTIME_STAMP+4(%r5)
|
||||||
brc 3,3f
|
brc 3,3f
|
||||||
ahi %r0,-1
|
ahi %r0,-1
|
||||||
3: ms %r0,__VDSO_NTP_MULT(%r5) /* cyc2ns(clock,cycle_delta) */
|
3: ms %r0,__VDSO_TK_MULT(%r5) /* * tk->mult */
|
||||||
st %r0,24(%r15)
|
st %r0,24(%r15)
|
||||||
l %r0,__VDSO_NTP_MULT(%r5)
|
l %r0,__VDSO_TK_MULT(%r5)
|
||||||
ltr %r1,%r1
|
ltr %r1,%r1
|
||||||
mr %r0,%r0
|
mr %r0,%r0
|
||||||
jnm 4f
|
jnm 4f
|
||||||
a %r0,__VDSO_NTP_MULT(%r5)
|
a %r0,__VDSO_TK_MULT(%r5)
|
||||||
4: al %r0,24(%r15)
|
4: al %r0,24(%r15)
|
||||||
srdl %r0,12
|
|
||||||
al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */
|
al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */
|
||||||
al %r1,__VDSO_XTIME_NSEC+4(%r5)
|
al %r1,__VDSO_XTIME_NSEC+4(%r5)
|
||||||
brc 12,5f
|
brc 12,5f
|
||||||
|
@ -51,6 +50,8 @@ __kernel_gettimeofday:
|
||||||
5: mvc 24(4,%r15),__VDSO_XTIME_SEC+4(%r5)
|
5: mvc 24(4,%r15),__VDSO_XTIME_SEC+4(%r5)
|
||||||
cl %r4,__VDSO_UPD_COUNT+4(%r5) /* check update counter */
|
cl %r4,__VDSO_UPD_COUNT+4(%r5) /* check update counter */
|
||||||
jne 1b
|
jne 1b
|
||||||
|
l %r4,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */
|
||||||
|
srdl %r0,0(%r4) /* >> tk->shift */
|
||||||
l %r4,24(%r15) /* get tv_sec from stack */
|
l %r4,24(%r15) /* get tv_sec from stack */
|
||||||
basr %r5,0
|
basr %r5,0
|
||||||
6: ltr %r0,%r0
|
6: ltr %r0,%r0
|
||||||
|
|
|
@ -34,14 +34,15 @@ __kernel_clock_gettime:
|
||||||
tmll %r4,0x0001 /* pending update ? loop */
|
tmll %r4,0x0001 /* pending update ? loop */
|
||||||
jnz 0b
|
jnz 0b
|
||||||
stck 48(%r15) /* Store TOD clock */
|
stck 48(%r15) /* Store TOD clock */
|
||||||
|
lgf %r2,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */
|
||||||
|
lg %r0,__VDSO_XTIME_SEC(%r5) /* tk->xtime_sec */
|
||||||
|
alg %r0,__VDSO_WTOM_SEC(%r5) /* + wall_to_monotonic.sec */
|
||||||
lg %r1,48(%r15)
|
lg %r1,48(%r15)
|
||||||
sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */
|
sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */
|
||||||
msgf %r1,__VDSO_NTP_MULT(%r5) /* * NTP adjustment */
|
msgf %r1,__VDSO_TK_MULT(%r5) /* * tk->mult */
|
||||||
srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */
|
alg %r1,__VDSO_XTIME_NSEC(%r5) /* + tk->xtime_nsec */
|
||||||
alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime */
|
alg %r1,__VDSO_WTOM_NSEC(%r5) /* + wall_to_monotonic.nsec */
|
||||||
lg %r0,__VDSO_XTIME_SEC(%r5)
|
srlg %r1,%r1,0(%r2) /* >> tk->shift */
|
||||||
alg %r1,__VDSO_WTOM_NSEC(%r5) /* + wall_to_monotonic */
|
|
||||||
alg %r0,__VDSO_WTOM_SEC(%r5)
|
|
||||||
clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */
|
clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */
|
||||||
jne 0b
|
jne 0b
|
||||||
larl %r5,13f
|
larl %r5,13f
|
||||||
|
@ -62,12 +63,13 @@ __kernel_clock_gettime:
|
||||||
tmll %r4,0x0001 /* pending update ? loop */
|
tmll %r4,0x0001 /* pending update ? loop */
|
||||||
jnz 5b
|
jnz 5b
|
||||||
stck 48(%r15) /* Store TOD clock */
|
stck 48(%r15) /* Store TOD clock */
|
||||||
|
lgf %r2,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */
|
||||||
lg %r1,48(%r15)
|
lg %r1,48(%r15)
|
||||||
sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */
|
sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */
|
||||||
msgf %r1,__VDSO_NTP_MULT(%r5) /* * NTP adjustment */
|
msgf %r1,__VDSO_TK_MULT(%r5) /* * tk->mult */
|
||||||
srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */
|
alg %r1,__VDSO_XTIME_NSEC(%r5) /* + tk->xtime_nsec */
|
||||||
alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime */
|
srlg %r1,%r1,0(%r2) /* >> tk->shift */
|
||||||
lg %r0,__VDSO_XTIME_SEC(%r5)
|
lg %r0,__VDSO_XTIME_SEC(%r5) /* tk->xtime_sec */
|
||||||
clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */
|
clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */
|
||||||
jne 5b
|
jne 5b
|
||||||
larl %r5,13f
|
larl %r5,13f
|
||||||
|
|
|
@ -31,12 +31,13 @@ __kernel_gettimeofday:
|
||||||
stck 48(%r15) /* Store TOD clock */
|
stck 48(%r15) /* Store TOD clock */
|
||||||
lg %r1,48(%r15)
|
lg %r1,48(%r15)
|
||||||
sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */
|
sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */
|
||||||
msgf %r1,__VDSO_NTP_MULT(%r5) /* * NTP adjustment */
|
msgf %r1,__VDSO_TK_MULT(%r5) /* * tk->mult */
|
||||||
srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */
|
alg %r1,__VDSO_XTIME_NSEC(%r5) /* + tk->xtime_nsec */
|
||||||
alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime.tv_nsec */
|
lg %r0,__VDSO_XTIME_SEC(%r5) /* tk->xtime_sec */
|
||||||
lg %r0,__VDSO_XTIME_SEC(%r5) /* xtime.tv_sec */
|
|
||||||
clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */
|
clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */
|
||||||
jne 0b
|
jne 0b
|
||||||
|
lgf %r5,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */
|
||||||
|
srlg %r1,%r1,0(%r5) /* >> tk->shift */
|
||||||
larl %r5,5f
|
larl %r5,5f
|
||||||
2: clg %r1,0(%r5)
|
2: clg %r1,0(%r5)
|
||||||
jl 3f
|
jl 3f
|
||||||
|
|
|
@ -78,11 +78,14 @@ static size_t copy_in_kernel(size_t count, void __user *to,
|
||||||
* contains the (negative) exception code.
|
* contains the (negative) exception code.
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
|
|
||||||
static unsigned long follow_table(struct mm_struct *mm,
|
static unsigned long follow_table(struct mm_struct *mm,
|
||||||
unsigned long address, int write)
|
unsigned long address, int write)
|
||||||
{
|
{
|
||||||
unsigned long *table = (unsigned long *)__pa(mm->pgd);
|
unsigned long *table = (unsigned long *)__pa(mm->pgd);
|
||||||
|
|
||||||
|
if (unlikely(address > mm->context.asce_limit - 1))
|
||||||
|
return -0x38UL;
|
||||||
switch (mm->context.asce_bits & _ASCE_TYPE_MASK) {
|
switch (mm->context.asce_bits & _ASCE_TYPE_MASK) {
|
||||||
case _ASCE_TYPE_REGION1:
|
case _ASCE_TYPE_REGION1:
|
||||||
table = table + ((address >> 53) & 0x7ff);
|
table = table + ((address >> 53) & 0x7ff);
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
avx_supported := $(call as-instr,vpxor %xmm0$(comma)%xmm0$(comma)%xmm0,yes,no)
|
avx_supported := $(call as-instr,vpxor %xmm0$(comma)%xmm0$(comma)%xmm0,yes,no)
|
||||||
|
avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\
|
||||||
|
$(comma)4)$(comma)%ymm2,yes,no)
|
||||||
|
|
||||||
obj-$(CONFIG_CRYPTO_ABLK_HELPER_X86) += ablk_helper.o
|
|
||||||
obj-$(CONFIG_CRYPTO_GLUE_HELPER_X86) += glue_helper.o
|
obj-$(CONFIG_CRYPTO_GLUE_HELPER_X86) += glue_helper.o
|
||||||
|
|
||||||
obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o
|
obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
#include <asm/cpu_device_id.h>
|
#include <asm/cpu_device_id.h>
|
||||||
#include <asm/i387.h>
|
#include <asm/i387.h>
|
||||||
#include <asm/crypto/aes.h>
|
#include <asm/crypto/aes.h>
|
||||||
#include <asm/crypto/ablk_helper.h>
|
#include <crypto/ablk_helper.h>
|
||||||
#include <crypto/scatterwalk.h>
|
#include <crypto/scatterwalk.h>
|
||||||
#include <crypto/internal/aead.h>
|
#include <crypto/internal/aead.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/crypto.h>
|
#include <linux/crypto.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <crypto/ablk_helper.h>
|
||||||
#include <crypto/algapi.h>
|
#include <crypto/algapi.h>
|
||||||
#include <crypto/ctr.h>
|
#include <crypto/ctr.h>
|
||||||
#include <crypto/lrw.h>
|
#include <crypto/lrw.h>
|
||||||
|
@ -21,7 +22,6 @@
|
||||||
#include <asm/xcr.h>
|
#include <asm/xcr.h>
|
||||||
#include <asm/xsave.h>
|
#include <asm/xsave.h>
|
||||||
#include <asm/crypto/camellia.h>
|
#include <asm/crypto/camellia.h>
|
||||||
#include <asm/crypto/ablk_helper.h>
|
|
||||||
#include <asm/crypto/glue_helper.h>
|
#include <asm/crypto/glue_helper.h>
|
||||||
|
|
||||||
#define CAMELLIA_AESNI_PARALLEL_BLOCKS 16
|
#define CAMELLIA_AESNI_PARALLEL_BLOCKS 16
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/crypto.h>
|
#include <linux/crypto.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <crypto/ablk_helper.h>
|
||||||
#include <crypto/algapi.h>
|
#include <crypto/algapi.h>
|
||||||
#include <crypto/ctr.h>
|
#include <crypto/ctr.h>
|
||||||
#include <crypto/lrw.h>
|
#include <crypto/lrw.h>
|
||||||
|
@ -21,7 +22,6 @@
|
||||||
#include <asm/xcr.h>
|
#include <asm/xcr.h>
|
||||||
#include <asm/xsave.h>
|
#include <asm/xsave.h>
|
||||||
#include <asm/crypto/camellia.h>
|
#include <asm/crypto/camellia.h>
|
||||||
#include <asm/crypto/ablk_helper.h>
|
|
||||||
#include <asm/crypto/glue_helper.h>
|
#include <asm/crypto/glue_helper.h>
|
||||||
|
|
||||||
#define CAMELLIA_AESNI_PARALLEL_BLOCKS 16
|
#define CAMELLIA_AESNI_PARALLEL_BLOCKS 16
|
||||||
|
|
|
@ -26,13 +26,13 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/crypto.h>
|
#include <linux/crypto.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <crypto/ablk_helper.h>
|
||||||
#include <crypto/algapi.h>
|
#include <crypto/algapi.h>
|
||||||
#include <crypto/cast5.h>
|
#include <crypto/cast5.h>
|
||||||
#include <crypto/cryptd.h>
|
#include <crypto/cryptd.h>
|
||||||
#include <crypto/ctr.h>
|
#include <crypto/ctr.h>
|
||||||
#include <asm/xcr.h>
|
#include <asm/xcr.h>
|
||||||
#include <asm/xsave.h>
|
#include <asm/xsave.h>
|
||||||
#include <asm/crypto/ablk_helper.h>
|
|
||||||
#include <asm/crypto/glue_helper.h>
|
#include <asm/crypto/glue_helper.h>
|
||||||
|
|
||||||
#define CAST5_PARALLEL_BLOCKS 16
|
#define CAST5_PARALLEL_BLOCKS 16
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/crypto.h>
|
#include <linux/crypto.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <crypto/ablk_helper.h>
|
||||||
#include <crypto/algapi.h>
|
#include <crypto/algapi.h>
|
||||||
#include <crypto/cast6.h>
|
#include <crypto/cast6.h>
|
||||||
#include <crypto/cryptd.h>
|
#include <crypto/cryptd.h>
|
||||||
|
@ -37,7 +38,6 @@
|
||||||
#include <crypto/xts.h>
|
#include <crypto/xts.h>
|
||||||
#include <asm/xcr.h>
|
#include <asm/xcr.h>
|
||||||
#include <asm/xsave.h>
|
#include <asm/xsave.h>
|
||||||
#include <asm/crypto/ablk_helper.h>
|
|
||||||
#include <asm/crypto/glue_helper.h>
|
#include <asm/crypto/glue_helper.h>
|
||||||
|
|
||||||
#define CAST6_PARALLEL_BLOCKS 8
|
#define CAST6_PARALLEL_BLOCKS 8
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/crypto.h>
|
#include <linux/crypto.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <crypto/ablk_helper.h>
|
||||||
#include <crypto/algapi.h>
|
#include <crypto/algapi.h>
|
||||||
#include <crypto/ctr.h>
|
#include <crypto/ctr.h>
|
||||||
#include <crypto/lrw.h>
|
#include <crypto/lrw.h>
|
||||||
|
@ -22,7 +23,6 @@
|
||||||
#include <asm/xcr.h>
|
#include <asm/xcr.h>
|
||||||
#include <asm/xsave.h>
|
#include <asm/xsave.h>
|
||||||
#include <asm/crypto/serpent-avx.h>
|
#include <asm/crypto/serpent-avx.h>
|
||||||
#include <asm/crypto/ablk_helper.h>
|
|
||||||
#include <asm/crypto/glue_helper.h>
|
#include <asm/crypto/glue_helper.h>
|
||||||
|
|
||||||
#define SERPENT_AVX2_PARALLEL_BLOCKS 16
|
#define SERPENT_AVX2_PARALLEL_BLOCKS 16
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/crypto.h>
|
#include <linux/crypto.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <crypto/ablk_helper.h>
|
||||||
#include <crypto/algapi.h>
|
#include <crypto/algapi.h>
|
||||||
#include <crypto/serpent.h>
|
#include <crypto/serpent.h>
|
||||||
#include <crypto/cryptd.h>
|
#include <crypto/cryptd.h>
|
||||||
|
@ -38,7 +39,6 @@
|
||||||
#include <asm/xcr.h>
|
#include <asm/xcr.h>
|
||||||
#include <asm/xsave.h>
|
#include <asm/xsave.h>
|
||||||
#include <asm/crypto/serpent-avx.h>
|
#include <asm/crypto/serpent-avx.h>
|
||||||
#include <asm/crypto/ablk_helper.h>
|
|
||||||
#include <asm/crypto/glue_helper.h>
|
#include <asm/crypto/glue_helper.h>
|
||||||
|
|
||||||
/* 8-way parallel cipher functions */
|
/* 8-way parallel cipher functions */
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/crypto.h>
|
#include <linux/crypto.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <crypto/ablk_helper.h>
|
||||||
#include <crypto/algapi.h>
|
#include <crypto/algapi.h>
|
||||||
#include <crypto/serpent.h>
|
#include <crypto/serpent.h>
|
||||||
#include <crypto/cryptd.h>
|
#include <crypto/cryptd.h>
|
||||||
|
@ -42,7 +43,6 @@
|
||||||
#include <crypto/lrw.h>
|
#include <crypto/lrw.h>
|
||||||
#include <crypto/xts.h>
|
#include <crypto/xts.h>
|
||||||
#include <asm/crypto/serpent-sse2.h>
|
#include <asm/crypto/serpent-sse2.h>
|
||||||
#include <asm/crypto/ablk_helper.h>
|
|
||||||
#include <asm/crypto/glue_helper.h>
|
#include <asm/crypto/glue_helper.h>
|
||||||
|
|
||||||
static void serpent_decrypt_cbc_xway(void *ctx, u128 *dst, const u128 *src)
|
static void serpent_decrypt_cbc_xway(void *ctx, u128 *dst, const u128 *src)
|
||||||
|
|
|
@ -281,7 +281,7 @@ static int __init sha256_ssse3_mod_init(void)
|
||||||
/* allow AVX to override SSSE3, it's a little faster */
|
/* allow AVX to override SSSE3, it's a little faster */
|
||||||
if (avx_usable()) {
|
if (avx_usable()) {
|
||||||
#ifdef CONFIG_AS_AVX2
|
#ifdef CONFIG_AS_AVX2
|
||||||
if (boot_cpu_has(X86_FEATURE_AVX2))
|
if (boot_cpu_has(X86_FEATURE_AVX2) && boot_cpu_has(X86_FEATURE_BMI2))
|
||||||
sha256_transform_asm = sha256_transform_rorx;
|
sha256_transform_asm = sha256_transform_rorx;
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
@ -319,4 +319,4 @@ MODULE_LICENSE("GPL");
|
||||||
MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm, Supplemental SSE3 accelerated");
|
MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm, Supplemental SSE3 accelerated");
|
||||||
|
|
||||||
MODULE_ALIAS("sha256");
|
MODULE_ALIAS("sha256");
|
||||||
MODULE_ALIAS("sha384");
|
MODULE_ALIAS("sha224");
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/crypto.h>
|
#include <linux/crypto.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <crypto/ablk_helper.h>
|
||||||
#include <crypto/algapi.h>
|
#include <crypto/algapi.h>
|
||||||
#include <crypto/twofish.h>
|
#include <crypto/twofish.h>
|
||||||
#include <crypto/cryptd.h>
|
#include <crypto/cryptd.h>
|
||||||
|
@ -39,7 +40,6 @@
|
||||||
#include <asm/xcr.h>
|
#include <asm/xcr.h>
|
||||||
#include <asm/xsave.h>
|
#include <asm/xsave.h>
|
||||||
#include <asm/crypto/twofish.h>
|
#include <asm/crypto/twofish.h>
|
||||||
#include <asm/crypto/ablk_helper.h>
|
|
||||||
#include <asm/crypto/glue_helper.h>
|
#include <asm/crypto/glue_helper.h>
|
||||||
#include <crypto/scatterwalk.h>
|
#include <crypto/scatterwalk.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
|
|
@ -216,6 +216,7 @@
|
||||||
#define X86_FEATURE_ERMS (9*32+ 9) /* Enhanced REP MOVSB/STOSB */
|
#define X86_FEATURE_ERMS (9*32+ 9) /* Enhanced REP MOVSB/STOSB */
|
||||||
#define X86_FEATURE_INVPCID (9*32+10) /* Invalidate Processor Context ID */
|
#define X86_FEATURE_INVPCID (9*32+10) /* Invalidate Processor Context ID */
|
||||||
#define X86_FEATURE_RTM (9*32+11) /* Restricted Transactional Memory */
|
#define X86_FEATURE_RTM (9*32+11) /* Restricted Transactional Memory */
|
||||||
|
#define X86_FEATURE_MPX (9*32+14) /* Memory Protection Extension */
|
||||||
#define X86_FEATURE_RDSEED (9*32+18) /* The RDSEED instruction */
|
#define X86_FEATURE_RDSEED (9*32+18) /* The RDSEED instruction */
|
||||||
#define X86_FEATURE_ADX (9*32+19) /* The ADCX and ADOX instructions */
|
#define X86_FEATURE_ADX (9*32+19) /* The ADCX and ADOX instructions */
|
||||||
#define X86_FEATURE_SMAP (9*32+20) /* Supervisor Mode Access Prevention */
|
#define X86_FEATURE_SMAP (9*32+20) /* Supervisor Mode Access Prevention */
|
||||||
|
|
|
@ -370,6 +370,26 @@ struct ymmh_struct {
|
||||||
u32 ymmh_space[64];
|
u32 ymmh_space[64];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct lwp_struct {
|
||||||
|
u64 lwpcb_addr;
|
||||||
|
u32 flags;
|
||||||
|
u32 buf_head_offset;
|
||||||
|
u64 buf_base;
|
||||||
|
u32 buf_size;
|
||||||
|
u32 filters;
|
||||||
|
u64 saved_event_record[4];
|
||||||
|
u32 event_counter[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bndregs_struct {
|
||||||
|
u64 bndregs[8];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct bndcsr_struct {
|
||||||
|
u64 cfg_reg_u;
|
||||||
|
u64 status_reg;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
struct xsave_hdr_struct {
|
struct xsave_hdr_struct {
|
||||||
u64 xstate_bv;
|
u64 xstate_bv;
|
||||||
u64 reserved1[2];
|
u64 reserved1[2];
|
||||||
|
@ -380,6 +400,9 @@ struct xsave_struct {
|
||||||
struct i387_fxsave_struct i387;
|
struct i387_fxsave_struct i387;
|
||||||
struct xsave_hdr_struct xsave_hdr;
|
struct xsave_hdr_struct xsave_hdr;
|
||||||
struct ymmh_struct ymmh;
|
struct ymmh_struct ymmh;
|
||||||
|
struct lwp_struct lwp;
|
||||||
|
struct bndregs_struct bndregs;
|
||||||
|
struct bndcsr_struct bndcsr;
|
||||||
/* new processor state extensions will go here */
|
/* new processor state extensions will go here */
|
||||||
} __attribute__ ((packed, aligned (64)));
|
} __attribute__ ((packed, aligned (64)));
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
#include <asm/i387.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* may_use_simd - whether it is allowable at this time to issue SIMD
|
||||||
|
* instructions or access the SIMD register file
|
||||||
|
*/
|
||||||
|
static __must_check inline bool may_use_simd(void)
|
||||||
|
{
|
||||||
|
return irq_fpu_usable();
|
||||||
|
}
|
|
@ -9,6 +9,8 @@
|
||||||
#define XSTATE_FP 0x1
|
#define XSTATE_FP 0x1
|
||||||
#define XSTATE_SSE 0x2
|
#define XSTATE_SSE 0x2
|
||||||
#define XSTATE_YMM 0x4
|
#define XSTATE_YMM 0x4
|
||||||
|
#define XSTATE_BNDREGS 0x8
|
||||||
|
#define XSTATE_BNDCSR 0x10
|
||||||
|
|
||||||
#define XSTATE_FPSSE (XSTATE_FP | XSTATE_SSE)
|
#define XSTATE_FPSSE (XSTATE_FP | XSTATE_SSE)
|
||||||
|
|
||||||
|
@ -20,10 +22,14 @@
|
||||||
#define XSAVE_YMM_SIZE 256
|
#define XSAVE_YMM_SIZE 256
|
||||||
#define XSAVE_YMM_OFFSET (XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET)
|
#define XSAVE_YMM_OFFSET (XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET)
|
||||||
|
|
||||||
/*
|
/* Supported features which support lazy state saving */
|
||||||
* These are the features that the OS can handle currently.
|
#define XSTATE_LAZY (XSTATE_FP | XSTATE_SSE | XSTATE_YMM)
|
||||||
*/
|
|
||||||
#define XCNTXT_MASK (XSTATE_FP | XSTATE_SSE | XSTATE_YMM)
|
/* Supported features which require eager state saving */
|
||||||
|
#define XSTATE_EAGER (XSTATE_BNDREGS | XSTATE_BNDCSR)
|
||||||
|
|
||||||
|
/* All currently supported features */
|
||||||
|
#define XCNTXT_MASK (XSTATE_LAZY | XSTATE_EAGER)
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
#define REX_PREFIX "0x48, "
|
#define REX_PREFIX "0x48, "
|
||||||
|
|
|
@ -562,6 +562,16 @@ static void __init xstate_enable_boot_cpu(void)
|
||||||
if (cpu_has_xsaveopt && eagerfpu != DISABLE)
|
if (cpu_has_xsaveopt && eagerfpu != DISABLE)
|
||||||
eagerfpu = ENABLE;
|
eagerfpu = ENABLE;
|
||||||
|
|
||||||
|
if (pcntxt_mask & XSTATE_EAGER) {
|
||||||
|
if (eagerfpu == DISABLE) {
|
||||||
|
pr_err("eagerfpu not present, disabling some xstate features: 0x%llx\n",
|
||||||
|
pcntxt_mask & XSTATE_EAGER);
|
||||||
|
pcntxt_mask &= ~XSTATE_EAGER;
|
||||||
|
} else {
|
||||||
|
eagerfpu = ENABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pr_info("enabled xstate_bv 0x%llx, cntxt size 0x%x\n",
|
pr_info("enabled xstate_bv 0x%llx, cntxt size 0x%x\n",
|
||||||
pcntxt_mask, xstate_size);
|
pcntxt_mask, xstate_size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,9 +174,8 @@ config CRYPTO_TEST
|
||||||
help
|
help
|
||||||
Quick & dirty crypto test module.
|
Quick & dirty crypto test module.
|
||||||
|
|
||||||
config CRYPTO_ABLK_HELPER_X86
|
config CRYPTO_ABLK_HELPER
|
||||||
tristate
|
tristate
|
||||||
depends on X86
|
|
||||||
select CRYPTO_CRYPTD
|
select CRYPTO_CRYPTD
|
||||||
|
|
||||||
config CRYPTO_GLUE_HELPER_X86
|
config CRYPTO_GLUE_HELPER_X86
|
||||||
|
@ -695,7 +694,7 @@ config CRYPTO_AES_NI_INTEL
|
||||||
select CRYPTO_AES_X86_64 if 64BIT
|
select CRYPTO_AES_X86_64 if 64BIT
|
||||||
select CRYPTO_AES_586 if !64BIT
|
select CRYPTO_AES_586 if !64BIT
|
||||||
select CRYPTO_CRYPTD
|
select CRYPTO_CRYPTD
|
||||||
select CRYPTO_ABLK_HELPER_X86
|
select CRYPTO_ABLK_HELPER
|
||||||
select CRYPTO_ALGAPI
|
select CRYPTO_ALGAPI
|
||||||
select CRYPTO_GLUE_HELPER_X86 if 64BIT
|
select CRYPTO_GLUE_HELPER_X86 if 64BIT
|
||||||
select CRYPTO_LRW
|
select CRYPTO_LRW
|
||||||
|
@ -895,7 +894,7 @@ config CRYPTO_CAMELLIA_AESNI_AVX_X86_64
|
||||||
depends on CRYPTO
|
depends on CRYPTO
|
||||||
select CRYPTO_ALGAPI
|
select CRYPTO_ALGAPI
|
||||||
select CRYPTO_CRYPTD
|
select CRYPTO_CRYPTD
|
||||||
select CRYPTO_ABLK_HELPER_X86
|
select CRYPTO_ABLK_HELPER
|
||||||
select CRYPTO_GLUE_HELPER_X86
|
select CRYPTO_GLUE_HELPER_X86
|
||||||
select CRYPTO_CAMELLIA_X86_64
|
select CRYPTO_CAMELLIA_X86_64
|
||||||
select CRYPTO_LRW
|
select CRYPTO_LRW
|
||||||
|
@ -917,7 +916,7 @@ config CRYPTO_CAMELLIA_AESNI_AVX2_X86_64
|
||||||
depends on CRYPTO
|
depends on CRYPTO
|
||||||
select CRYPTO_ALGAPI
|
select CRYPTO_ALGAPI
|
||||||
select CRYPTO_CRYPTD
|
select CRYPTO_CRYPTD
|
||||||
select CRYPTO_ABLK_HELPER_X86
|
select CRYPTO_ABLK_HELPER
|
||||||
select CRYPTO_GLUE_HELPER_X86
|
select CRYPTO_GLUE_HELPER_X86
|
||||||
select CRYPTO_CAMELLIA_X86_64
|
select CRYPTO_CAMELLIA_X86_64
|
||||||
select CRYPTO_CAMELLIA_AESNI_AVX_X86_64
|
select CRYPTO_CAMELLIA_AESNI_AVX_X86_64
|
||||||
|
@ -969,7 +968,7 @@ config CRYPTO_CAST5_AVX_X86_64
|
||||||
depends on X86 && 64BIT
|
depends on X86 && 64BIT
|
||||||
select CRYPTO_ALGAPI
|
select CRYPTO_ALGAPI
|
||||||
select CRYPTO_CRYPTD
|
select CRYPTO_CRYPTD
|
||||||
select CRYPTO_ABLK_HELPER_X86
|
select CRYPTO_ABLK_HELPER
|
||||||
select CRYPTO_CAST_COMMON
|
select CRYPTO_CAST_COMMON
|
||||||
select CRYPTO_CAST5
|
select CRYPTO_CAST5
|
||||||
help
|
help
|
||||||
|
@ -992,7 +991,7 @@ config CRYPTO_CAST6_AVX_X86_64
|
||||||
depends on X86 && 64BIT
|
depends on X86 && 64BIT
|
||||||
select CRYPTO_ALGAPI
|
select CRYPTO_ALGAPI
|
||||||
select CRYPTO_CRYPTD
|
select CRYPTO_CRYPTD
|
||||||
select CRYPTO_ABLK_HELPER_X86
|
select CRYPTO_ABLK_HELPER
|
||||||
select CRYPTO_GLUE_HELPER_X86
|
select CRYPTO_GLUE_HELPER_X86
|
||||||
select CRYPTO_CAST_COMMON
|
select CRYPTO_CAST_COMMON
|
||||||
select CRYPTO_CAST6
|
select CRYPTO_CAST6
|
||||||
|
@ -1110,7 +1109,7 @@ config CRYPTO_SERPENT_SSE2_X86_64
|
||||||
depends on X86 && 64BIT
|
depends on X86 && 64BIT
|
||||||
select CRYPTO_ALGAPI
|
select CRYPTO_ALGAPI
|
||||||
select CRYPTO_CRYPTD
|
select CRYPTO_CRYPTD
|
||||||
select CRYPTO_ABLK_HELPER_X86
|
select CRYPTO_ABLK_HELPER
|
||||||
select CRYPTO_GLUE_HELPER_X86
|
select CRYPTO_GLUE_HELPER_X86
|
||||||
select CRYPTO_SERPENT
|
select CRYPTO_SERPENT
|
||||||
select CRYPTO_LRW
|
select CRYPTO_LRW
|
||||||
|
@ -1132,7 +1131,7 @@ config CRYPTO_SERPENT_SSE2_586
|
||||||
depends on X86 && !64BIT
|
depends on X86 && !64BIT
|
||||||
select CRYPTO_ALGAPI
|
select CRYPTO_ALGAPI
|
||||||
select CRYPTO_CRYPTD
|
select CRYPTO_CRYPTD
|
||||||
select CRYPTO_ABLK_HELPER_X86
|
select CRYPTO_ABLK_HELPER
|
||||||
select CRYPTO_GLUE_HELPER_X86
|
select CRYPTO_GLUE_HELPER_X86
|
||||||
select CRYPTO_SERPENT
|
select CRYPTO_SERPENT
|
||||||
select CRYPTO_LRW
|
select CRYPTO_LRW
|
||||||
|
@ -1154,7 +1153,7 @@ config CRYPTO_SERPENT_AVX_X86_64
|
||||||
depends on X86 && 64BIT
|
depends on X86 && 64BIT
|
||||||
select CRYPTO_ALGAPI
|
select CRYPTO_ALGAPI
|
||||||
select CRYPTO_CRYPTD
|
select CRYPTO_CRYPTD
|
||||||
select CRYPTO_ABLK_HELPER_X86
|
select CRYPTO_ABLK_HELPER
|
||||||
select CRYPTO_GLUE_HELPER_X86
|
select CRYPTO_GLUE_HELPER_X86
|
||||||
select CRYPTO_SERPENT
|
select CRYPTO_SERPENT
|
||||||
select CRYPTO_LRW
|
select CRYPTO_LRW
|
||||||
|
@ -1176,7 +1175,7 @@ config CRYPTO_SERPENT_AVX2_X86_64
|
||||||
depends on X86 && 64BIT
|
depends on X86 && 64BIT
|
||||||
select CRYPTO_ALGAPI
|
select CRYPTO_ALGAPI
|
||||||
select CRYPTO_CRYPTD
|
select CRYPTO_CRYPTD
|
||||||
select CRYPTO_ABLK_HELPER_X86
|
select CRYPTO_ABLK_HELPER
|
||||||
select CRYPTO_GLUE_HELPER_X86
|
select CRYPTO_GLUE_HELPER_X86
|
||||||
select CRYPTO_SERPENT
|
select CRYPTO_SERPENT
|
||||||
select CRYPTO_SERPENT_AVX_X86_64
|
select CRYPTO_SERPENT_AVX_X86_64
|
||||||
|
@ -1292,7 +1291,7 @@ config CRYPTO_TWOFISH_AVX_X86_64
|
||||||
depends on X86 && 64BIT
|
depends on X86 && 64BIT
|
||||||
select CRYPTO_ALGAPI
|
select CRYPTO_ALGAPI
|
||||||
select CRYPTO_CRYPTD
|
select CRYPTO_CRYPTD
|
||||||
select CRYPTO_ABLK_HELPER_X86
|
select CRYPTO_ABLK_HELPER
|
||||||
select CRYPTO_GLUE_HELPER_X86
|
select CRYPTO_GLUE_HELPER_X86
|
||||||
select CRYPTO_TWOFISH_COMMON
|
select CRYPTO_TWOFISH_COMMON
|
||||||
select CRYPTO_TWOFISH_X86_64
|
select CRYPTO_TWOFISH_X86_64
|
||||||
|
|
|
@ -2,8 +2,13 @@
|
||||||
# Cryptographic API
|
# Cryptographic API
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# memneq MUST be built with -Os or -O0 to prevent early-return optimizations
|
||||||
|
# that will defeat memneq's actual purpose to prevent timing attacks.
|
||||||
|
CFLAGS_REMOVE_memneq.o := -O1 -O2 -O3
|
||||||
|
CFLAGS_memneq.o := -Os
|
||||||
|
|
||||||
obj-$(CONFIG_CRYPTO) += crypto.o
|
obj-$(CONFIG_CRYPTO) += crypto.o
|
||||||
crypto-y := api.o cipher.o compress.o
|
crypto-y := api.o cipher.o compress.o memneq.o
|
||||||
|
|
||||||
obj-$(CONFIG_CRYPTO_WORKQUEUE) += crypto_wq.o
|
obj-$(CONFIG_CRYPTO_WORKQUEUE) += crypto_wq.o
|
||||||
|
|
||||||
|
@ -105,3 +110,4 @@ obj-$(CONFIG_XOR_BLOCKS) += xor.o
|
||||||
obj-$(CONFIG_ASYNC_CORE) += async_tx/
|
obj-$(CONFIG_ASYNC_CORE) += async_tx/
|
||||||
obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/
|
obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/
|
||||||
obj-$(CONFIG_CRYPTO_HASH_INFO) += hash_info.o
|
obj-$(CONFIG_CRYPTO_HASH_INFO) += hash_info.o
|
||||||
|
obj-$(CONFIG_CRYPTO_ABLK_HELPER) += ablk_helper.o
|
||||||
|
|
|
@ -28,10 +28,11 @@
|
||||||
#include <linux/crypto.h>
|
#include <linux/crypto.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/hardirq.h>
|
||||||
#include <crypto/algapi.h>
|
#include <crypto/algapi.h>
|
||||||
#include <crypto/cryptd.h>
|
#include <crypto/cryptd.h>
|
||||||
#include <asm/i387.h>
|
#include <crypto/ablk_helper.h>
|
||||||
#include <asm/crypto/ablk_helper.h>
|
#include <asm/simd.h>
|
||||||
|
|
||||||
int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
|
int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
|
||||||
unsigned int key_len)
|
unsigned int key_len)
|
||||||
|
@ -70,11 +71,11 @@ int ablk_encrypt(struct ablkcipher_request *req)
|
||||||
struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
|
struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
|
||||||
struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm);
|
struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm);
|
||||||
|
|
||||||
if (!irq_fpu_usable()) {
|
if (!may_use_simd()) {
|
||||||
struct ablkcipher_request *cryptd_req =
|
struct ablkcipher_request *cryptd_req =
|
||||||
ablkcipher_request_ctx(req);
|
ablkcipher_request_ctx(req);
|
||||||
|
|
||||||
memcpy(cryptd_req, req, sizeof(*req));
|
*cryptd_req = *req;
|
||||||
ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
|
ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
|
||||||
|
|
||||||
return crypto_ablkcipher_encrypt(cryptd_req);
|
return crypto_ablkcipher_encrypt(cryptd_req);
|
||||||
|
@ -89,11 +90,11 @@ int ablk_decrypt(struct ablkcipher_request *req)
|
||||||
struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
|
struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
|
||||||
struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm);
|
struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm);
|
||||||
|
|
||||||
if (!irq_fpu_usable()) {
|
if (!may_use_simd()) {
|
||||||
struct ablkcipher_request *cryptd_req =
|
struct ablkcipher_request *cryptd_req =
|
||||||
ablkcipher_request_ctx(req);
|
ablkcipher_request_ctx(req);
|
||||||
|
|
||||||
memcpy(cryptd_req, req, sizeof(*req));
|
*cryptd_req = *req;
|
||||||
ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
|
ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
|
||||||
|
|
||||||
return crypto_ablkcipher_decrypt(cryptd_req);
|
return crypto_ablkcipher_decrypt(cryptd_req);
|
|
@ -16,9 +16,7 @@
|
||||||
#include <crypto/internal/skcipher.h>
|
#include <crypto/internal/skcipher.h>
|
||||||
#include <linux/cpumask.h>
|
#include <linux/cpumask.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/rtnetlink.h>
|
#include <linux/rtnetlink.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
@ -30,8 +28,6 @@
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
static const char *skcipher_default_geniv __read_mostly;
|
|
||||||
|
|
||||||
struct ablkcipher_buffer {
|
struct ablkcipher_buffer {
|
||||||
struct list_head entry;
|
struct list_head entry;
|
||||||
struct scatter_walk dst;
|
struct scatter_walk dst;
|
||||||
|
@ -527,8 +523,7 @@ const char *crypto_default_geniv(const struct crypto_alg *alg)
|
||||||
alg->cra_blocksize)
|
alg->cra_blocksize)
|
||||||
return "chainiv";
|
return "chainiv";
|
||||||
|
|
||||||
return alg->cra_flags & CRYPTO_ALG_ASYNC ?
|
return "eseqiv";
|
||||||
"eseqiv" : skcipher_default_geniv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int crypto_givcipher_default(struct crypto_alg *alg, u32 type, u32 mask)
|
static int crypto_givcipher_default(struct crypto_alg *alg, u32 type, u32 mask)
|
||||||
|
@ -709,17 +704,3 @@ err:
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(crypto_alloc_ablkcipher);
|
EXPORT_SYMBOL_GPL(crypto_alloc_ablkcipher);
|
||||||
|
|
||||||
static int __init skcipher_module_init(void)
|
|
||||||
{
|
|
||||||
skcipher_default_geniv = num_possible_cpus() > 1 ?
|
|
||||||
"eseqiv" : "chainiv";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void skcipher_module_exit(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(skcipher_module_init);
|
|
||||||
module_exit(skcipher_module_exit);
|
|
||||||
|
|
|
@ -230,11 +230,11 @@ remainder:
|
||||||
*/
|
*/
|
||||||
if (byte_count < DEFAULT_BLK_SZ) {
|
if (byte_count < DEFAULT_BLK_SZ) {
|
||||||
empty_rbuf:
|
empty_rbuf:
|
||||||
for (; ctx->rand_data_valid < DEFAULT_BLK_SZ;
|
while (ctx->rand_data_valid < DEFAULT_BLK_SZ) {
|
||||||
ctx->rand_data_valid++) {
|
|
||||||
*ptr = ctx->rand_data[ctx->rand_data_valid];
|
*ptr = ctx->rand_data[ctx->rand_data_valid];
|
||||||
ptr++;
|
ptr++;
|
||||||
byte_count--;
|
byte_count--;
|
||||||
|
ctx->rand_data_valid++;
|
||||||
if (byte_count == 0)
|
if (byte_count == 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <crypto/algapi.h>
|
||||||
#include "public_key.h"
|
#include "public_key.h"
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
@ -189,12 +190,12 @@ static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(asn1_template, EM + T_offset, asn1_size) != 0) {
|
if (crypto_memneq(asn1_template, EM + T_offset, asn1_size) != 0) {
|
||||||
kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]");
|
kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]");
|
||||||
return -EBADMSG;
|
return -EBADMSG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(H, EM + T_offset + asn1_size, hash_size) != 0) {
|
if (crypto_memneq(H, EM + T_offset + asn1_size, hash_size) != 0) {
|
||||||
kleave(" = -EKEYREJECTED [EM[T] hash mismatch]");
|
kleave(" = -EKEYREJECTED [EM[T] hash mismatch]");
|
||||||
return -EKEYREJECTED;
|
return -EKEYREJECTED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,59 +18,11 @@
|
||||||
#include <linux/asn1_decoder.h>
|
#include <linux/asn1_decoder.h>
|
||||||
#include <keys/asymmetric-subtype.h>
|
#include <keys/asymmetric-subtype.h>
|
||||||
#include <keys/asymmetric-parser.h>
|
#include <keys/asymmetric-parser.h>
|
||||||
#include <keys/system_keyring.h>
|
|
||||||
#include <crypto/hash.h>
|
#include <crypto/hash.h>
|
||||||
#include "asymmetric_keys.h"
|
#include "asymmetric_keys.h"
|
||||||
#include "public_key.h"
|
#include "public_key.h"
|
||||||
#include "x509_parser.h"
|
#include "x509_parser.h"
|
||||||
|
|
||||||
/*
|
|
||||||
* Find a key in the given keyring by issuer and authority.
|
|
||||||
*/
|
|
||||||
static struct key *x509_request_asymmetric_key(
|
|
||||||
struct key *keyring,
|
|
||||||
const char *signer, size_t signer_len,
|
|
||||||
const char *authority, size_t auth_len)
|
|
||||||
{
|
|
||||||
key_ref_t key;
|
|
||||||
char *id;
|
|
||||||
|
|
||||||
/* Construct an identifier. */
|
|
||||||
id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL);
|
|
||||||
if (!id)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
|
|
||||||
memcpy(id, signer, signer_len);
|
|
||||||
id[signer_len + 0] = ':';
|
|
||||||
id[signer_len + 1] = ' ';
|
|
||||||
memcpy(id + signer_len + 2, authority, auth_len);
|
|
||||||
id[signer_len + 2 + auth_len] = 0;
|
|
||||||
|
|
||||||
pr_debug("Look up: \"%s\"\n", id);
|
|
||||||
|
|
||||||
key = keyring_search(make_key_ref(keyring, 1),
|
|
||||||
&key_type_asymmetric, id);
|
|
||||||
if (IS_ERR(key))
|
|
||||||
pr_debug("Request for module key '%s' err %ld\n",
|
|
||||||
id, PTR_ERR(key));
|
|
||||||
kfree(id);
|
|
||||||
|
|
||||||
if (IS_ERR(key)) {
|
|
||||||
switch (PTR_ERR(key)) {
|
|
||||||
/* Hide some search errors */
|
|
||||||
case -EACCES:
|
|
||||||
case -ENOTDIR:
|
|
||||||
case -EAGAIN:
|
|
||||||
return ERR_PTR(-ENOKEY);
|
|
||||||
default:
|
|
||||||
return ERR_CAST(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key)));
|
|
||||||
return key_ref_to_ptr(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up the signature parameters in an X.509 certificate. This involves
|
* Set up the signature parameters in an X.509 certificate. This involves
|
||||||
* digesting the signed data and extracting the signature.
|
* digesting the signed data and extracting the signature.
|
||||||
|
@ -150,33 +102,6 @@ int x509_check_signature(const struct public_key *pub,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(x509_check_signature);
|
EXPORT_SYMBOL_GPL(x509_check_signature);
|
||||||
|
|
||||||
/*
|
|
||||||
* Check the new certificate against the ones in the trust keyring. If one of
|
|
||||||
* those is the signing key and validates the new certificate, then mark the
|
|
||||||
* new certificate as being trusted.
|
|
||||||
*
|
|
||||||
* Return 0 if the new certificate was successfully validated, 1 if we couldn't
|
|
||||||
* find a matching parent certificate in the trusted list and an error if there
|
|
||||||
* is a matching certificate but the signature check fails.
|
|
||||||
*/
|
|
||||||
static int x509_validate_trust(struct x509_certificate *cert,
|
|
||||||
struct key *trust_keyring)
|
|
||||||
{
|
|
||||||
const struct public_key *pk;
|
|
||||||
struct key *key;
|
|
||||||
int ret = 1;
|
|
||||||
|
|
||||||
key = x509_request_asymmetric_key(trust_keyring,
|
|
||||||
cert->issuer, strlen(cert->issuer),
|
|
||||||
cert->authority,
|
|
||||||
strlen(cert->authority));
|
|
||||||
if (!IS_ERR(key)) {
|
|
||||||
pk = key->payload.data;
|
|
||||||
ret = x509_check_signature(pk, cert);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Attempt to parse a data blob for a key as an X509 certificate.
|
* Attempt to parse a data blob for a key as an X509 certificate.
|
||||||
*/
|
*/
|
||||||
|
@ -230,13 +155,9 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
|
||||||
/* Check the signature on the key if it appears to be self-signed */
|
/* Check the signature on the key if it appears to be self-signed */
|
||||||
if (!cert->authority ||
|
if (!cert->authority ||
|
||||||
strcmp(cert->fingerprint, cert->authority) == 0) {
|
strcmp(cert->fingerprint, cert->authority) == 0) {
|
||||||
ret = x509_check_signature(cert->pub, cert); /* self-signed */
|
ret = x509_check_signature(cert->pub, cert);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error_free_cert;
|
goto error_free_cert;
|
||||||
} else {
|
|
||||||
ret = x509_validate_trust(cert, system_trusted_keyring);
|
|
||||||
if (!ret)
|
|
||||||
prep->trusted = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Propose a description */
|
/* Propose a description */
|
||||||
|
|
|
@ -52,40 +52,52 @@ static void authenc_request_complete(struct aead_request *req, int err)
|
||||||
aead_request_complete(req, err);
|
aead_request_complete(req, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key,
|
int crypto_authenc_extractkeys(struct crypto_authenc_keys *keys, const u8 *key,
|
||||||
unsigned int keylen)
|
unsigned int keylen)
|
||||||
{
|
{
|
||||||
unsigned int authkeylen;
|
struct rtattr *rta = (struct rtattr *)key;
|
||||||
unsigned int enckeylen;
|
|
||||||
struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
|
|
||||||
struct crypto_ahash *auth = ctx->auth;
|
|
||||||
struct crypto_ablkcipher *enc = ctx->enc;
|
|
||||||
struct rtattr *rta = (void *)key;
|
|
||||||
struct crypto_authenc_key_param *param;
|
struct crypto_authenc_key_param *param;
|
||||||
int err = -EINVAL;
|
|
||||||
|
|
||||||
if (!RTA_OK(rta, keylen))
|
if (!RTA_OK(rta, keylen))
|
||||||
goto badkey;
|
return -EINVAL;
|
||||||
if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
|
if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
|
||||||
goto badkey;
|
return -EINVAL;
|
||||||
if (RTA_PAYLOAD(rta) < sizeof(*param))
|
if (RTA_PAYLOAD(rta) < sizeof(*param))
|
||||||
goto badkey;
|
return -EINVAL;
|
||||||
|
|
||||||
param = RTA_DATA(rta);
|
param = RTA_DATA(rta);
|
||||||
enckeylen = be32_to_cpu(param->enckeylen);
|
keys->enckeylen = be32_to_cpu(param->enckeylen);
|
||||||
|
|
||||||
key += RTA_ALIGN(rta->rta_len);
|
key += RTA_ALIGN(rta->rta_len);
|
||||||
keylen -= RTA_ALIGN(rta->rta_len);
|
keylen -= RTA_ALIGN(rta->rta_len);
|
||||||
|
|
||||||
if (keylen < enckeylen)
|
if (keylen < keys->enckeylen)
|
||||||
goto badkey;
|
return -EINVAL;
|
||||||
|
|
||||||
authkeylen = keylen - enckeylen;
|
keys->authkeylen = keylen - keys->enckeylen;
|
||||||
|
keys->authkey = key;
|
||||||
|
keys->enckey = key + keys->authkeylen;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(crypto_authenc_extractkeys);
|
||||||
|
|
||||||
|
static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key,
|
||||||
|
unsigned int keylen)
|
||||||
|
{
|
||||||
|
struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
|
||||||
|
struct crypto_ahash *auth = ctx->auth;
|
||||||
|
struct crypto_ablkcipher *enc = ctx->enc;
|
||||||
|
struct crypto_authenc_keys keys;
|
||||||
|
int err = -EINVAL;
|
||||||
|
|
||||||
|
if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
|
||||||
|
goto badkey;
|
||||||
|
|
||||||
crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
|
crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
|
||||||
crypto_ahash_set_flags(auth, crypto_aead_get_flags(authenc) &
|
crypto_ahash_set_flags(auth, crypto_aead_get_flags(authenc) &
|
||||||
CRYPTO_TFM_REQ_MASK);
|
CRYPTO_TFM_REQ_MASK);
|
||||||
err = crypto_ahash_setkey(auth, key, authkeylen);
|
err = crypto_ahash_setkey(auth, keys.authkey, keys.authkeylen);
|
||||||
crypto_aead_set_flags(authenc, crypto_ahash_get_flags(auth) &
|
crypto_aead_set_flags(authenc, crypto_ahash_get_flags(auth) &
|
||||||
CRYPTO_TFM_RES_MASK);
|
CRYPTO_TFM_RES_MASK);
|
||||||
|
|
||||||
|
@ -95,7 +107,7 @@ static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key,
|
||||||
crypto_ablkcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK);
|
crypto_ablkcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK);
|
||||||
crypto_ablkcipher_set_flags(enc, crypto_aead_get_flags(authenc) &
|
crypto_ablkcipher_set_flags(enc, crypto_aead_get_flags(authenc) &
|
||||||
CRYPTO_TFM_REQ_MASK);
|
CRYPTO_TFM_REQ_MASK);
|
||||||
err = crypto_ablkcipher_setkey(enc, key + authkeylen, enckeylen);
|
err = crypto_ablkcipher_setkey(enc, keys.enckey, keys.enckeylen);
|
||||||
crypto_aead_set_flags(authenc, crypto_ablkcipher_get_flags(enc) &
|
crypto_aead_set_flags(authenc, crypto_ablkcipher_get_flags(enc) &
|
||||||
CRYPTO_TFM_RES_MASK);
|
CRYPTO_TFM_RES_MASK);
|
||||||
|
|
||||||
|
@ -188,7 +200,7 @@ static void authenc_verify_ahash_update_done(struct crypto_async_request *areq,
|
||||||
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
||||||
authsize, 0);
|
authsize, 0);
|
||||||
|
|
||||||
err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -227,7 +239,7 @@ static void authenc_verify_ahash_done(struct crypto_async_request *areq,
|
||||||
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
||||||
authsize, 0);
|
authsize, 0);
|
||||||
|
|
||||||
err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -462,7 +474,7 @@ static int crypto_authenc_verify(struct aead_request *req,
|
||||||
ihash = ohash + authsize;
|
ihash = ohash + authsize;
|
||||||
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
||||||
authsize, 0);
|
authsize, 0);
|
||||||
return memcmp(ihash, ohash, authsize) ? -EBADMSG : 0;
|
return crypto_memneq(ihash, ohash, authsize) ? -EBADMSG : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int crypto_authenc_iverify(struct aead_request *req, u8 *iv,
|
static int crypto_authenc_iverify(struct aead_request *req, u8 *iv,
|
||||||
|
|
|
@ -59,37 +59,19 @@ static void authenc_esn_request_complete(struct aead_request *req, int err)
|
||||||
static int crypto_authenc_esn_setkey(struct crypto_aead *authenc_esn, const u8 *key,
|
static int crypto_authenc_esn_setkey(struct crypto_aead *authenc_esn, const u8 *key,
|
||||||
unsigned int keylen)
|
unsigned int keylen)
|
||||||
{
|
{
|
||||||
unsigned int authkeylen;
|
|
||||||
unsigned int enckeylen;
|
|
||||||
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
|
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
|
||||||
struct crypto_ahash *auth = ctx->auth;
|
struct crypto_ahash *auth = ctx->auth;
|
||||||
struct crypto_ablkcipher *enc = ctx->enc;
|
struct crypto_ablkcipher *enc = ctx->enc;
|
||||||
struct rtattr *rta = (void *)key;
|
struct crypto_authenc_keys keys;
|
||||||
struct crypto_authenc_key_param *param;
|
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
|
|
||||||
if (!RTA_OK(rta, keylen))
|
if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
|
||||||
goto badkey;
|
goto badkey;
|
||||||
if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
|
|
||||||
goto badkey;
|
|
||||||
if (RTA_PAYLOAD(rta) < sizeof(*param))
|
|
||||||
goto badkey;
|
|
||||||
|
|
||||||
param = RTA_DATA(rta);
|
|
||||||
enckeylen = be32_to_cpu(param->enckeylen);
|
|
||||||
|
|
||||||
key += RTA_ALIGN(rta->rta_len);
|
|
||||||
keylen -= RTA_ALIGN(rta->rta_len);
|
|
||||||
|
|
||||||
if (keylen < enckeylen)
|
|
||||||
goto badkey;
|
|
||||||
|
|
||||||
authkeylen = keylen - enckeylen;
|
|
||||||
|
|
||||||
crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
|
crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
|
||||||
crypto_ahash_set_flags(auth, crypto_aead_get_flags(authenc_esn) &
|
crypto_ahash_set_flags(auth, crypto_aead_get_flags(authenc_esn) &
|
||||||
CRYPTO_TFM_REQ_MASK);
|
CRYPTO_TFM_REQ_MASK);
|
||||||
err = crypto_ahash_setkey(auth, key, authkeylen);
|
err = crypto_ahash_setkey(auth, keys.authkey, keys.authkeylen);
|
||||||
crypto_aead_set_flags(authenc_esn, crypto_ahash_get_flags(auth) &
|
crypto_aead_set_flags(authenc_esn, crypto_ahash_get_flags(auth) &
|
||||||
CRYPTO_TFM_RES_MASK);
|
CRYPTO_TFM_RES_MASK);
|
||||||
|
|
||||||
|
@ -99,7 +81,7 @@ static int crypto_authenc_esn_setkey(struct crypto_aead *authenc_esn, const u8 *
|
||||||
crypto_ablkcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK);
|
crypto_ablkcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK);
|
||||||
crypto_ablkcipher_set_flags(enc, crypto_aead_get_flags(authenc_esn) &
|
crypto_ablkcipher_set_flags(enc, crypto_aead_get_flags(authenc_esn) &
|
||||||
CRYPTO_TFM_REQ_MASK);
|
CRYPTO_TFM_REQ_MASK);
|
||||||
err = crypto_ablkcipher_setkey(enc, key + authkeylen, enckeylen);
|
err = crypto_ablkcipher_setkey(enc, keys.enckey, keys.enckeylen);
|
||||||
crypto_aead_set_flags(authenc_esn, crypto_ablkcipher_get_flags(enc) &
|
crypto_aead_set_flags(authenc_esn, crypto_ablkcipher_get_flags(enc) &
|
||||||
CRYPTO_TFM_RES_MASK);
|
CRYPTO_TFM_RES_MASK);
|
||||||
|
|
||||||
|
@ -247,7 +229,7 @@ static void authenc_esn_verify_ahash_update_done(struct crypto_async_request *ar
|
||||||
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
||||||
authsize, 0);
|
authsize, 0);
|
||||||
|
|
||||||
err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -296,7 +278,7 @@ static void authenc_esn_verify_ahash_update_done2(struct crypto_async_request *a
|
||||||
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
||||||
authsize, 0);
|
authsize, 0);
|
||||||
|
|
||||||
err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -336,7 +318,7 @@ static void authenc_esn_verify_ahash_done(struct crypto_async_request *areq,
|
||||||
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
||||||
authsize, 0);
|
authsize, 0);
|
||||||
|
|
||||||
err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -568,7 +550,7 @@ static int crypto_authenc_esn_verify(struct aead_request *req)
|
||||||
ihash = ohash + authsize;
|
ihash = ohash + authsize;
|
||||||
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
||||||
authsize, 0);
|
authsize, 0);
|
||||||
return memcmp(ihash, ohash, authsize) ? -EBADMSG : 0;
|
return crypto_memneq(ihash, ohash, authsize) ? -EBADMSG : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int crypto_authenc_esn_iverify(struct aead_request *req, u8 *iv,
|
static int crypto_authenc_esn_iverify(struct aead_request *req, u8 *iv,
|
||||||
|
|
|
@ -363,7 +363,7 @@ static void crypto_ccm_decrypt_done(struct crypto_async_request *areq,
|
||||||
|
|
||||||
if (!err) {
|
if (!err) {
|
||||||
err = crypto_ccm_auth(req, req->dst, cryptlen);
|
err = crypto_ccm_auth(req, req->dst, cryptlen);
|
||||||
if (!err && memcmp(pctx->auth_tag, pctx->odata, authsize))
|
if (!err && crypto_memneq(pctx->auth_tag, pctx->odata, authsize))
|
||||||
err = -EBADMSG;
|
err = -EBADMSG;
|
||||||
}
|
}
|
||||||
aead_request_complete(req, err);
|
aead_request_complete(req, err);
|
||||||
|
@ -422,7 +422,7 @@ static int crypto_ccm_decrypt(struct aead_request *req)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
/* verify */
|
/* verify */
|
||||||
if (memcmp(authtag, odata, authsize))
|
if (crypto_memneq(authtag, odata, authsize))
|
||||||
return -EBADMSG;
|
return -EBADMSG;
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -582,7 +582,7 @@ static int crypto_gcm_verify(struct aead_request *req,
|
||||||
|
|
||||||
crypto_xor(auth_tag, iauth_tag, 16);
|
crypto_xor(auth_tag, iauth_tag, 16);
|
||||||
scatterwalk_map_and_copy(iauth_tag, req->src, cryptlen, authsize, 0);
|
scatterwalk_map_and_copy(iauth_tag, req->src, cryptlen, authsize, 0);
|
||||||
return memcmp(iauth_tag, auth_tag, authsize) ? -EBADMSG : 0;
|
return crypto_memneq(iauth_tag, auth_tag, authsize) ? -EBADMSG : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gcm_decrypt_done(struct crypto_async_request *areq, int err)
|
static void gcm_decrypt_done(struct crypto_async_request *areq, int err)
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* Constant-time equality testing of memory regions.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
*
|
||||||
|
* James Yonan <james@openvpn.net>
|
||||||
|
* Daniel Borkmann <dborkman@redhat.com>
|
||||||
|
*
|
||||||
|
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||||
|
* redistributing this file, you may do so under either license.
|
||||||
|
*
|
||||||
|
* GPL LICENSE SUMMARY
|
||||||
|
*
|
||||||
|
* Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
* The full GNU General Public License is included in this distribution
|
||||||
|
* in the file called LICENSE.GPL.
|
||||||
|
*
|
||||||
|
* BSD LICENSE
|
||||||
|
*
|
||||||
|
* Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of OpenVPN Technologies nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <crypto/algapi.h>
|
||||||
|
|
||||||
|
#ifndef __HAVE_ARCH_CRYPTO_MEMNEQ
|
||||||
|
|
||||||
|
/* Generic path for arbitrary size */
|
||||||
|
static inline unsigned long
|
||||||
|
__crypto_memneq_generic(const void *a, const void *b, size_t size)
|
||||||
|
{
|
||||||
|
unsigned long neq = 0;
|
||||||
|
|
||||||
|
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
|
||||||
|
while (size >= sizeof(unsigned long)) {
|
||||||
|
neq |= *(unsigned long *)a ^ *(unsigned long *)b;
|
||||||
|
a += sizeof(unsigned long);
|
||||||
|
b += sizeof(unsigned long);
|
||||||
|
size -= sizeof(unsigned long);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */
|
||||||
|
while (size > 0) {
|
||||||
|
neq |= *(unsigned char *)a ^ *(unsigned char *)b;
|
||||||
|
a += 1;
|
||||||
|
b += 1;
|
||||||
|
size -= 1;
|
||||||
|
}
|
||||||
|
return neq;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop-free fast-path for frequently used 16-byte size */
|
||||||
|
static inline unsigned long __crypto_memneq_16(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
||||||
|
if (sizeof(unsigned long) == 8)
|
||||||
|
return ((*(unsigned long *)(a) ^ *(unsigned long *)(b))
|
||||||
|
| (*(unsigned long *)(a+8) ^ *(unsigned long *)(b+8)));
|
||||||
|
else if (sizeof(unsigned int) == 4)
|
||||||
|
return ((*(unsigned int *)(a) ^ *(unsigned int *)(b))
|
||||||
|
| (*(unsigned int *)(a+4) ^ *(unsigned int *)(b+4))
|
||||||
|
| (*(unsigned int *)(a+8) ^ *(unsigned int *)(b+8))
|
||||||
|
| (*(unsigned int *)(a+12) ^ *(unsigned int *)(b+12)));
|
||||||
|
else
|
||||||
|
#endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */
|
||||||
|
return ((*(unsigned char *)(a) ^ *(unsigned char *)(b))
|
||||||
|
| (*(unsigned char *)(a+1) ^ *(unsigned char *)(b+1))
|
||||||
|
| (*(unsigned char *)(a+2) ^ *(unsigned char *)(b+2))
|
||||||
|
| (*(unsigned char *)(a+3) ^ *(unsigned char *)(b+3))
|
||||||
|
| (*(unsigned char *)(a+4) ^ *(unsigned char *)(b+4))
|
||||||
|
| (*(unsigned char *)(a+5) ^ *(unsigned char *)(b+5))
|
||||||
|
| (*(unsigned char *)(a+6) ^ *(unsigned char *)(b+6))
|
||||||
|
| (*(unsigned char *)(a+7) ^ *(unsigned char *)(b+7))
|
||||||
|
| (*(unsigned char *)(a+8) ^ *(unsigned char *)(b+8))
|
||||||
|
| (*(unsigned char *)(a+9) ^ *(unsigned char *)(b+9))
|
||||||
|
| (*(unsigned char *)(a+10) ^ *(unsigned char *)(b+10))
|
||||||
|
| (*(unsigned char *)(a+11) ^ *(unsigned char *)(b+11))
|
||||||
|
| (*(unsigned char *)(a+12) ^ *(unsigned char *)(b+12))
|
||||||
|
| (*(unsigned char *)(a+13) ^ *(unsigned char *)(b+13))
|
||||||
|
| (*(unsigned char *)(a+14) ^ *(unsigned char *)(b+14))
|
||||||
|
| (*(unsigned char *)(a+15) ^ *(unsigned char *)(b+15)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compare two areas of memory without leaking timing information,
|
||||||
|
* and with special optimizations for common sizes. Users should
|
||||||
|
* not call this function directly, but should instead use
|
||||||
|
* crypto_memneq defined in crypto/algapi.h.
|
||||||
|
*/
|
||||||
|
noinline unsigned long __crypto_memneq(const void *a, const void *b,
|
||||||
|
size_t size)
|
||||||
|
{
|
||||||
|
switch (size) {
|
||||||
|
case 16:
|
||||||
|
return __crypto_memneq_16(a, b);
|
||||||
|
default:
|
||||||
|
return __crypto_memneq_generic(a, b, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(__crypto_memneq);
|
||||||
|
|
||||||
|
#endif /* __HAVE_ARCH_CRYPTO_MEMNEQ */
|
|
@ -184,7 +184,7 @@ acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer,
|
||||||
struct acpi_buffer *output_buffer);
|
struct acpi_buffer *output_buffer);
|
||||||
|
|
||||||
acpi_status
|
acpi_status
|
||||||
acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer,
|
acpi_rs_create_aml_resources(struct acpi_buffer *resource_list,
|
||||||
struct acpi_buffer *output_buffer);
|
struct acpi_buffer *output_buffer);
|
||||||
|
|
||||||
acpi_status
|
acpi_status
|
||||||
|
@ -227,8 +227,8 @@ acpi_rs_get_list_length(u8 * aml_buffer,
|
||||||
u32 aml_buffer_length, acpi_size * size_needed);
|
u32 aml_buffer_length, acpi_size * size_needed);
|
||||||
|
|
||||||
acpi_status
|
acpi_status
|
||||||
acpi_rs_get_aml_length(struct acpi_resource *linked_list_buffer,
|
acpi_rs_get_aml_length(struct acpi_resource *resource_list,
|
||||||
acpi_size * size_needed);
|
acpi_size resource_list_size, acpi_size * size_needed);
|
||||||
|
|
||||||
acpi_status
|
acpi_status
|
||||||
acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
|
acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
|
||||||
|
|
|
@ -106,6 +106,7 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name)
|
||||||
void acpi_ns_delete_node(struct acpi_namespace_node *node)
|
void acpi_ns_delete_node(struct acpi_namespace_node *node)
|
||||||
{
|
{
|
||||||
union acpi_operand_object *obj_desc;
|
union acpi_operand_object *obj_desc;
|
||||||
|
union acpi_operand_object *next_desc;
|
||||||
|
|
||||||
ACPI_FUNCTION_NAME(ns_delete_node);
|
ACPI_FUNCTION_NAME(ns_delete_node);
|
||||||
|
|
||||||
|
@ -114,12 +115,13 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node)
|
||||||
acpi_ns_detach_object(node);
|
acpi_ns_detach_object(node);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Delete an attached data object if present (an object that was created
|
* Delete an attached data object list if present (objects that were
|
||||||
* and attached via acpi_attach_data). Note: After any normal object is
|
* attached via acpi_attach_data). Note: After any normal object is
|
||||||
* detached above, the only possible remaining object is a data object.
|
* detached above, the only possible remaining object(s) are data
|
||||||
|
* objects, in a linked list.
|
||||||
*/
|
*/
|
||||||
obj_desc = node->object;
|
obj_desc = node->object;
|
||||||
if (obj_desc && (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) {
|
while (obj_desc && (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) {
|
||||||
|
|
||||||
/* Invoke the attached data deletion handler if present */
|
/* Invoke the attached data deletion handler if present */
|
||||||
|
|
||||||
|
@ -127,7 +129,15 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node)
|
||||||
obj_desc->data.handler(node, obj_desc->data.pointer);
|
obj_desc->data.handler(node, obj_desc->data.pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next_desc = obj_desc->common.next_object;
|
||||||
acpi_ut_remove_reference(obj_desc);
|
acpi_ut_remove_reference(obj_desc);
|
||||||
|
obj_desc = next_desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Special case for the statically allocated root node */
|
||||||
|
|
||||||
|
if (node == acpi_gbl_root_node) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now we can delete the node */
|
/* Now we can delete the node */
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue