summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/boards/imx.rst8
-rw-r--r--Documentation/boards/imx/amazon-kindle-3.rst6
-rw-r--r--Documentation/boards/imx/garz-fricke-vincell.rst4
-rw-r--r--Documentation/boards/imx/nxp-imx8mq-evk.rst4
-rw-r--r--Documentation/boards/imx/phytec-phycore-i.mx31.rst8
-rw-r--r--Documentation/boards/mips/dlink-dir-320.rst4
-rw-r--r--Documentation/boards/mips/qemu-malta.rst16
-rw-r--r--Documentation/boards/mvebu.rst4
-rw-r--r--Documentation/boards/mxs/Chumby-Falconwing.rst8
-rw-r--r--Documentation/boards/mxs/Freescale-i.MX23-evk.rst8
-rw-r--r--Documentation/boards/mxs/KaRo-TX28.rst8
-rw-r--r--Documentation/boards/mxs/Olimex-olinuxino.rst8
-rw-r--r--Documentation/boards/omap.rst4
-rw-r--r--Documentation/boards/openrisc.rst8
-rw-r--r--Documentation/boards/s3c/Digi-a9m2440.rst8
-rw-r--r--Documentation/boards/sandbox.rst6
-rw-r--r--Documentation/boards/socfpga.rst24
-rw-r--r--Documentation/boards/x86.rst3
-rw-r--r--Documentation/conf.py2
-rw-r--r--Documentation/filesystems/fat.rst4
-rw-r--r--Documentation/filesystems/nfs.rst8
-rw-r--r--Documentation/filesystems/pstore.rst2
-rw-r--r--Documentation/filesystems/ramfs.rst4
-rw-r--r--Documentation/filesystems/smhfs.rst4
-rw-r--r--Documentation/filesystems/squashfs.rst4
-rw-r--r--Documentation/filesystems/tftp.rst4
-rw-r--r--Documentation/user/automount.rst12
-rw-r--r--Documentation/user/barebox.rst4
-rw-r--r--Documentation/user/defaultenv-2.rst4
-rw-r--r--Documentation/user/driver-model.rst20
-rw-r--r--Documentation/user/hush.rst24
-rw-r--r--Documentation/user/memory-areas.rst8
-rw-r--r--Documentation/user/system-setup.rst12
-rw-r--r--Documentation/user/updating.rst8
-rw-r--r--Documentation/user/variables.rst14
-rw-r--r--Makefile2
-rw-r--r--arch/arm/Kconfig4
-rw-r--r--arch/arm/boards/freescale-mx6sx-sabresdb/board.c2
-rw-r--r--arch/arm/boards/gateworks-ventana/board.c29
-rw-r--r--arch/arm/boards/nxp-imx8mq-evk/ddr_init.c120
-rw-r--r--arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c219
-rw-r--r--arch/arm/boards/nxp-imx8mq-evk/lowlevel.c50
-rw-r--r--arch/arm/boards/phytec-som-am335x/board.c2
-rw-r--r--arch/arm/boards/zii-vf610-dev/lowlevel.c4
-rw-r--r--arch/arm/cpu/Makefile4
-rw-r--r--arch/arm/cpu/smccc-call_64.S52
-rw-r--r--arch/arm/include/asm/asm-offsets.h1
-rw-r--r--arch/arm/include/asm/common.h5
-rw-r--r--arch/arm/include/asm/errata.h9
-rw-r--r--arch/arm/lib/asm-offsets.c7
-rw-r--r--arch/arm/lib32/barebox.lds.S12
-rw-r--r--arch/arm/mach-imx/Kconfig2
-rw-r--r--arch/arm/mach-imx/Makefile2
-rw-r--r--arch/arm/mach-imx/atf.c41
-rw-r--r--arch/arm/mach-imx/boot.c99
-rw-r--r--arch/arm/mach-imx/cpu_init.c3
-rw-r--r--arch/arm/mach-imx/imx.c11
-rw-r--r--arch/arm/mach-imx/imx7.c11
-rw-r--r--arch/arm/mach-imx/imx8mq.c84
-rw-r--r--arch/arm/mach-imx/include/mach/atf.h13
-rw-r--r--arch/arm/mach-imx/include/mach/imx-header.h128
-rw-r--r--arch/arm/mach-imx/include/mach/imx8mq.h43
-rw-r--r--arch/arm/mach-imx/include/mach/ocotp.h1
-rw-r--r--arch/arm/mach-imx/include/mach/reset-reason.h1
-rw-r--r--arch/arm/mach-imx/xload-esdhc.c51
-rw-r--r--commands/memset.c2
-rw-r--r--commands/mm.c2
-rw-r--r--commands/mw.c2
-rw-r--r--commands/of_node.c7
-rw-r--r--common/block.c4
-rw-r--r--common/image-fit.c5
-rw-r--r--drivers/aiodev/Kconfig10
-rw-r--r--drivers/i2c/busses/i2c-imx.c4
-rw-r--r--drivers/mci/imx-esdhc.c5
-rw-r--r--drivers/mci/s3c.c2
-rw-r--r--drivers/net/e1000/eeprom.c56
-rw-r--r--drivers/pci/pci.c93
-rw-r--r--drivers/pinctrl/imx-iomux-v3.c3
-rw-r--r--drivers/reset/reset-socfpga.c1
-rw-r--r--drivers/serial/serial_lpuart.c13
-rw-r--r--drivers/spi/Kconfig2
-rw-r--r--drivers/usb/gadget/f_fastboot.c6
-rw-r--r--dts/Bindings/arm/samsung/samsung-boards.txt2
-rw-r--r--dts/Bindings/display/tilcdc/tilcdc.txt2
-rw-r--r--dts/Bindings/gpio/nintendo,hollywood-gpio.txt2
-rw-r--r--dts/Bindings/input/sprd,sc27xx-vibra.txt23
-rw-r--r--dts/Bindings/input/touchscreen/hideep.txt2
-rw-r--r--dts/Bindings/interrupt-controller/nvidia,tegra20-ictlr.txt2
-rw-r--r--dts/Bindings/interrupt-controller/st,stm32-exti.txt2
-rw-r--r--dts/Bindings/mips/brcm/soc.txt2
-rw-r--r--dts/Bindings/net/fsl-fman.txt2
-rw-r--r--dts/Bindings/power/power_domain.txt2
-rw-r--r--dts/Bindings/regulator/tps65090.txt2
-rw-r--r--dts/Bindings/reset/st,sti-softreset.txt2
-rw-r--r--dts/Bindings/soc/qcom/qcom,geni-se.txt2
-rw-r--r--dts/Bindings/sound/qcom,apq8016-sbc.txt2
-rw-r--r--dts/Bindings/sound/qcom,apq8096.txt2
-rw-r--r--dts/Bindings/usb/rockchip,dwc3.txt3
-rw-r--r--dts/Bindings/w1/w1-gpio.txt2
-rw-r--r--dts/include/dt-bindings/clock/imx6ul-clock.h40
-rw-r--r--dts/src/arm/am335x-bone-common.dtsi1
-rw-r--r--dts/src/arm/am3517.dtsi9
-rw-r--r--dts/src/arm/am437x-sk-evm.dts2
-rw-r--r--dts/src/arm/armada-385-synology-ds116.dts2
-rw-r--r--dts/src/arm/armada-38x.dtsi2
-rw-r--r--dts/src/arm/bcm-cygnus.dtsi24
-rw-r--r--dts/src/arm/bcm-hr2.dtsi24
-rw-r--r--dts/src/arm/bcm-nsp.dtsi32
-rw-r--r--dts/src/arm/bcm5301x.dtsi2
-rw-r--r--dts/src/arm/da850.dtsi6
-rw-r--r--dts/src/arm/dra7.dtsi2
-rw-r--r--dts/src/arm/imx51-zii-rdu1.dts2
-rw-r--r--dts/src/arm/imx6q.dtsi2
-rw-r--r--dts/src/arm/imx6qdl-zii-rdu2.dtsi2
-rw-r--r--dts/src/arm/imx6sx.dtsi2
-rw-r--r--dts/src/arm/omap4-droid4-xt894.dts9
-rw-r--r--dts/src/arm/socfpga.dtsi4
-rw-r--r--dts/src/arm/socfpga_arria10.dtsi5
-rw-r--r--dts/src/arm64/altera/socfpga_stratix10.dtsi6
-rw-r--r--dts/src/arm64/amlogic/meson-axg-s400.dts15
-rw-r--r--dts/src/arm64/amlogic/meson-axg.dtsi4
-rw-r--r--dts/src/arm64/amlogic/meson-gx.dtsi12
-rw-r--r--dts/src/arm64/amlogic/meson-gxl-mali.dtsi2
-rw-r--r--dts/src/arm64/amlogic/meson-gxl-s905x-libretech-cc.dts3
-rw-r--r--dts/src/arm64/amlogic/meson-gxl-s905x-p212.dtsi7
-rw-r--r--dts/src/arm64/amlogic/meson-gxl.dtsi8
-rw-r--r--dts/src/arm64/broadcom/northstar2/ns2.dtsi8
-rw-r--r--dts/src/arm64/broadcom/stingray/bcm958742k.dts4
-rw-r--r--dts/src/arm64/broadcom/stingray/bcm958742t.dts4
-rw-r--r--dts/src/arm64/broadcom/stingray/stingray.dtsi4
-rw-r--r--dts/src/arm64/hisilicon/hi3660-hikey960.dts2
-rw-r--r--dts/src/arm64/hisilicon/hi6220-hikey.dts2
-rw-r--r--dts/src/arm64/marvell/armada-cp110.dtsi2
-rw-r--r--dts/src/arm64/qcom/apq8096-db820c.dtsi2
-rw-r--r--dts/src/arm64/qcom/msm8916.dtsi4
-rw-r--r--dts/src/arm64/socionext/uniphier-ld11-global.dts2
-rw-r--r--dts/src/arm64/socionext/uniphier-ld20-global.dts2
-rw-r--r--firmware/Kconfig3
-rw-r--r--firmware/Makefile6
-rwxr-xr-xfirmware/imx/imx8m-bl31.binbin0 -> 46744 bytes
-rw-r--r--fs/Kconfig18
-rw-r--r--fs/Makefile3
-rw-r--r--fs/cramfs/cramfs.c523
-rw-r--r--fs/devfs.c150
-rw-r--r--fs/ext4/ext_barebox.c279
-rw-r--r--fs/ext4/ext_common.h3
-rw-r--r--fs/fat/Kconfig1
-rw-r--r--fs/fs.c3186
-rw-r--r--fs/legacy.c315
-rw-r--r--fs/libfs.c97
-rw-r--r--fs/nfs.c542
-rw-r--r--fs/pstore/Kconfig1
-rw-r--r--fs/ramfs.c403
-rw-r--r--fs/squashfs/Makefile2
-rw-r--r--fs/squashfs/dir.c232
-rw-r--r--fs/squashfs/inode.c9
-rw-r--r--fs/squashfs/namei.c17
-rw-r--r--fs/squashfs/squashfs.c186
-rw-r--r--fs/squashfs/squashfs.h9
-rw-r--r--fs/squashfs/super.c13
-rw-r--r--fs/squashfs/symlink.c82
-rw-r--r--fs/tftp.c97
-rw-r--r--fs/ubifs/Makefile2
-rw-r--r--fs/ubifs/dir.c291
-rw-r--r--fs/ubifs/super.c153
-rw-r--r--fs/ubifs/ubifs.c341
-rw-r--r--fs/ubifs/ubifs.h7
-rw-r--r--include/dirent.h3
-rw-r--r--include/fs.h38
-rw-r--r--include/gpio.h3
-rw-r--r--include/hab.h2
-rw-r--r--include/linux/arm-smccc.h135
-rw-r--r--include/linux/dcache.h109
-rw-r--r--include/linux/fs.h131
-rw-r--r--include/linux/mount.h3
-rw-r--r--include/linux/namei.h52
-rw-r--r--include/linux/pci.h54
-rw-r--r--include/linux/stat.h2
-rw-r--r--include/serial/lpuart.h2
-rw-r--r--lib/libfile.c20
-rw-r--r--net/eth.c14
-rw-r--r--scripts/dtc/Makefile5
-rw-r--r--scripts/dtc/fdtget.c119
-rw-r--r--scripts/imx/Makefile1
-rw-r--r--scripts/imx/imx.h114
185 files changed, 6006 insertions, 3599 deletions
diff --git a/Documentation/boards/imx.rst b/Documentation/boards/imx.rst
index db889ee702..56fd3ab41c 100644
--- a/Documentation/boards/imx.rst
+++ b/Documentation/boards/imx.rst
@@ -32,7 +32,9 @@ Normally it's not necessary to call this tool manually, it is executed
automatically at the end of the build process.
The images generated by the build process can be directly written to an
-SD card::
+SD card:
+
+.. code-block:: sh
# with Multi Image support:
cat images/barebox-freescale-imx51-babbage.img > /dev/sdd
@@ -152,7 +154,9 @@ contains a USB upload tool. As it depends on the libusb development headers,
it is not built by default. Enable it explicitly in ``make menuconfig``
and install the libusb development package. On Debian, this can be done
with ``apt-get install libusb-dev``. After compilation, the tool can be used
-with only the image name as argument::
+with only the image name as argument:
+
+.. code-block:: sh
scripts/imx/imx-usb-loader images/barebox-freescale-imx51-babbage.img
diff --git a/Documentation/boards/imx/amazon-kindle-3.rst b/Documentation/boards/imx/amazon-kindle-3.rst
index dffb7efb2d..6b5d9fe535 100644
--- a/Documentation/boards/imx/amazon-kindle-3.rst
+++ b/Documentation/boards/imx/amazon-kindle-3.rst
@@ -15,7 +15,7 @@ To upload and run a new bootloader the device can be put into USB-downloader
mode by the SOC microcode when Vol+ is pressed during startup. A new USB
device "SE Blank RINGO" should appear, barebox may be uploaded using
-::
+.. code-block:: console
$ scripts/imx/imx-usb-loader barebox.imximg
@@ -26,7 +26,9 @@ imx-usb-loader)
Barebox may be used as drop-in replacement for the shipped bootloader.
When installing the barebox imximg on the eMMC take care not to overwrite
the partition table and vendor supplied serial numbers stored on the eMMC.
-e.g. just write the imx-header and the application section::
+e.g. just write the imx-header and the application section:
+
+.. code-block:: sh
memcpy -b -s barebox.imximg -d /dev/disk0.imx_header 1024 0 1024
memcpy -b -s barebox.imximg -d /dev/disk0.self 4096 0 195584
diff --git a/Documentation/boards/imx/garz-fricke-vincell.rst b/Documentation/boards/imx/garz-fricke-vincell.rst
index 09d87d67c3..4127c8bc8c 100644
--- a/Documentation/boards/imx/garz-fricke-vincell.rst
+++ b/Documentation/boards/imx/garz-fricke-vincell.rst
@@ -38,6 +38,8 @@ If the network setup is working properly, barebox can be loaded into memory::
load -v -r -b 0x80100000 barebox-guf-vincell-lt.img
exec
-Once in barebox, the bootloader can now be persisted to NAND::
+Once in barebox, the bootloader can now be persisted to NAND:
+
+.. code-block:: sh
barebox_update -t nand /mnt/tftp/barebox-guf-vincell-lt.img``
diff --git a/Documentation/boards/imx/nxp-imx8mq-evk.rst b/Documentation/boards/imx/nxp-imx8mq-evk.rst
index 9dfa911bec..f0cdc34866 100644
--- a/Documentation/boards/imx/nxp-imx8mq-evk.rst
+++ b/Documentation/boards/imx/nxp-imx8mq-evk.rst
@@ -14,7 +14,7 @@ Downloading DDR PHY Firmware
As a part of DDR intialization routine NXP i.MX8MQ EVK requires and
uses several binary firmware blobs that are distributed under a
separate EULA and cannot be included in Barebox. In order to obtain
-the do the following::
+them do the following::
wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-7.2.bin
chmod +x firmware-imx-7.2.bin
@@ -113,4 +113,4 @@ Serial boot SW802 setting needed for i.MX8 DDR Tool is as follows::
| O | | <--- off = low level
| |
| 1 2 |
- +-----+ \ No newline at end of file
+ +-----+
diff --git a/Documentation/boards/imx/phytec-phycore-i.mx31.rst b/Documentation/boards/imx/phytec-phycore-i.mx31.rst
index d9a981b998..0feb22257a 100644
--- a/Documentation/boards/imx/phytec-phycore-i.mx31.rst
+++ b/Documentation/boards/imx/phytec-phycore-i.mx31.rst
@@ -26,11 +26,15 @@ Supported baseboards are:
How to get barebox for Phytec's phyCORE-i.MX31
----------------------------------------------
-Using the default configuration::
+Using the default configuration:
+
+.. code-block:: sh
make ARCH=arm pcm037_defconfig
-Build the binary image::
+Build the binary image:
+
+.. code-block:: sh
make ARCH=arm CROSS_COMPILE=armv5compiler
diff --git a/Documentation/boards/mips/dlink-dir-320.rst b/Documentation/boards/mips/dlink-dir-320.rst
index 74d11ffe59..7595381f55 100644
--- a/Documentation/boards/mips/dlink-dir-320.rst
+++ b/Documentation/boards/mips/dlink-dir-320.rst
@@ -26,7 +26,9 @@ Put your barebox.bin to tftp-server directory
Connect your DIR-320 to your tftp-server network via
one of four <LAN> sockets.
-Next, setup network on DIR-320 and run barebox.bin, e.g.::
+Next, setup network on DIR-320 and run barebox.bin, e.g.:
+
+.. code-block:: console
CFE> ifconfig eth0 -addr=192.168.0.99
CFE> boot -tftp -addr=a0800000 -raw 192.168.0.1:barebox.bin
diff --git a/Documentation/boards/mips/qemu-malta.rst b/Documentation/boards/mips/qemu-malta.rst
index 0c4d639194..2bb81350a1 100644
--- a/Documentation/boards/mips/qemu-malta.rst
+++ b/Documentation/boards/mips/qemu-malta.rst
@@ -4,7 +4,9 @@ QEMU Malta
Big-endian mode
---------------
-QEMU run string::
+QEMU run string:
+
+.. code-block:: sh
qemu-system-mips -nodefaults -M malta -m 256 \
-nographic -serial stdio -monitor null \
@@ -18,13 +20,17 @@ Running little-endian Malta is a bit tricky.
In little-endian mode the 32bit words in the boot flash image are swapped,
a neat trick which allows bi-endian firmware.
-You have to swap words of ``zbarebox.bin`` image, e.g.::
+You have to swap words of ``zbarebox.bin`` image, e.g.:
+
+.. code-block:: sh
echo arch/mips/pbl/zbarebox.bin \
| cpio --create \
| cpio --extract --swap --unconditional
-QEMU run string::
+QEMU run string:
+
+.. code-block:: sh
qemu-system-mipsel -nodefaults -M malta -m 256 \
-nographic -serial stdio -monitor null \
@@ -39,7 +45,9 @@ You can use GXemul to run little-endian barebox (use gxemul-malta_defconfig).
N.B. There is no need to swap words in ``zbarebox.bin`` for little-endian GXemul!
-GXemul run string::
+GXemul run string:
+
+.. code-block:: sh
gxemul -Q -e malta -M 256 0xbfc00000:barebox-flash-image
diff --git a/Documentation/boards/mvebu.rst b/Documentation/boards/mvebu.rst
index e27aa28306..9c99c815de 100644
--- a/Documentation/boards/mvebu.rst
+++ b/Documentation/boards/mvebu.rst
@@ -14,7 +14,9 @@ RAM initialisation
------------------
Traditionally the RAM initialisation happens with a binary blob that have to be
-extracted from the vendor U-Boot::
+extracted from the vendor U-Boot:
+
+.. code-block:: sh
scripts/kwbimage -x -i /dev/mtdblock0 -o .
diff --git a/Documentation/boards/mxs/Chumby-Falconwing.rst b/Documentation/boards/mxs/Chumby-Falconwing.rst
index 172d6840cf..690ccadf8c 100644
--- a/Documentation/boards/mxs/Chumby-Falconwing.rst
+++ b/Documentation/boards/mxs/Chumby-Falconwing.rst
@@ -20,11 +20,15 @@ Memory layout when barebox is running:
How to get the bootloader binary image
--------------------------------------
-Using the default configuration::
+Using the default configuration:
+
+.. code-block:: sh
make ARCH=arm chumbyone_defconfig
-Build the bootloader binary image::
+Build the bootloader binary image:
+
+.. code-block:: sh
make ARCH=arm CROSS_COMPILE=armv5compiler
diff --git a/Documentation/boards/mxs/Freescale-i.MX23-evk.rst b/Documentation/boards/mxs/Freescale-i.MX23-evk.rst
index cb73ec1279..077ab73bda 100644
--- a/Documentation/boards/mxs/Freescale-i.MX23-evk.rst
+++ b/Documentation/boards/mxs/Freescale-i.MX23-evk.rst
@@ -19,11 +19,15 @@ Memory layout when barebox is running:
How to get the bootloader binary image
--------------------------------------
-Using the default configuration::
+Using the default configuration:
+
+.. code-block:: sh
make ARCH=arm freescale-mx23-evk_defconfig
-Build the bootloader binary image::
+Build the bootloader binary image:
+
+.. code-block:: sh
make ARCH=arm CROSS_COMPILE=armv5compiler
diff --git a/Documentation/boards/mxs/KaRo-TX28.rst b/Documentation/boards/mxs/KaRo-TX28.rst
index 6cad5eb243..54b1ce71eb 100644
--- a/Documentation/boards/mxs/KaRo-TX28.rst
+++ b/Documentation/boards/mxs/KaRo-TX28.rst
@@ -24,11 +24,15 @@ Supported baseboards are:
How to get barebox for 'KARO's Starterkit 5'
--------------------------------------------
-Using the default configuration::
+Using the default configuration:
+
+.. code-block:: sh
make ARCH=arm tx28stk5_defconfig
-Build the binary image::
+Build the binary image:
+
+.. code-block:: sh
make ARCH=arm CROSS_COMPILE=armv5compiler
diff --git a/Documentation/boards/mxs/Olimex-olinuxino.rst b/Documentation/boards/mxs/Olimex-olinuxino.rst
index a06eb3309f..2080653887 100644
--- a/Documentation/boards/mxs/Olimex-olinuxino.rst
+++ b/Documentation/boards/mxs/Olimex-olinuxino.rst
@@ -9,11 +9,15 @@ This CPU module is based on a Freescale i.MX23 CPU.
How to get the bootloader binary image
--------------------------------------
-Using the default configuration::
+Using the default configuration:
+
+.. code-block:: sh
make ARCH=arm imx233-olinuxino_defconfig
-Build the binary image::
+Build the binary image:
+
+.. code-block:: sh
make ARCH=arm CROSS_COMPILE=armv5compiler
diff --git a/Documentation/boards/omap.rst b/Documentation/boards/omap.rst
index c2697510c5..717a38fe01 100644
--- a/Documentation/boards/omap.rst
+++ b/Documentation/boards/omap.rst
@@ -15,7 +15,9 @@ The PandaBoard boots from SD card. The OMAP Boot ROM code loads a file named
scripts on the net which describe how to prepare such a card (it needs
special partitioning). The same procedure can be used for barebox. With such a
card (assumed to be at /dev/sdc), the following can be used to build and install
-barebox::
+barebox:
+
+.. code-block:: console
# mount -t fat /dev/sdc1 /mnt
# make panda_xload_defconfig
diff --git a/Documentation/boards/openrisc.rst b/Documentation/boards/openrisc.rst
index fe6c48c958..f9d67f9650 100644
--- a/Documentation/boards/openrisc.rst
+++ b/Documentation/boards/openrisc.rst
@@ -4,7 +4,9 @@ OpenRISC
or1ksim
-------
-Compile or1ksim emulator::
+Compile or1ksim emulator:
+
+.. code-block:: console
$ cd ~/
$ git clone https://github.com/openrisc/or1ksim
@@ -48,6 +50,8 @@ Create minimal or1ksim.cfg file:
tap_dev = "tap0"
end
-Run or1ksim::
+Run or1ksim:
+
+.. code-block:: console
$ ~/or1ksim/sim -f or1ksim.cfg barebox
diff --git a/Documentation/boards/s3c/Digi-a9m2440.rst b/Documentation/boards/s3c/Digi-a9m2440.rst
index d01a001172..32d58b9a04 100644
--- a/Documentation/boards/s3c/Digi-a9m2440.rst
+++ b/Documentation/boards/s3c/Digi-a9m2440.rst
@@ -78,11 +78,15 @@ This CPU card is based on a Samsung S3C2440 CPU. The card is shipped with:
How to get the binary image
---------------------------
-Configure with the default configuration::
+Configure with the default configuration:
+
+.. code-block:: sh
make ARCH=arm a9m2440_defconfig
-Build the binary image::
+Build the binary image:
+
+.. code-block:: sh
make ARCH=arm CROSS_COMPILE=armv4compiler
diff --git a/Documentation/boards/sandbox.rst b/Documentation/boards/sandbox.rst
index 558f111697..85a54e6b04 100644
--- a/Documentation/boards/sandbox.rst
+++ b/Documentation/boards/sandbox.rst
@@ -7,7 +7,9 @@ hardware related features.
Building barebox for simulation
-------------------------------
-The barebox sandbox can be built with the host compiler::
+The barebox sandbox can be built with the host compiler:
+
+.. code-block:: sh
ARCH=sandbox make sandbox_defconfig
ARCH=sandbox make
@@ -17,6 +19,8 @@ Running the sandbox
Once you compile barebox for the sandbox, you can run it with::
+.. code-block:: console
+
$ barebox [<OPTIONS>]
Available sandbox invocation options include:
diff --git a/Documentation/boards/socfpga.rst b/Documentation/boards/socfpga.rst
index cd0fffa1ee..d73237491d 100644
--- a/Documentation/boards/socfpga.rst
+++ b/Documentation/boards/socfpga.rst
@@ -41,7 +41,9 @@ second partition of the SD card, which must be of type FAT32. On this partition
barebox searches for a file called barebox.bin.
To boot barebox on a Terasic SoCkit, the procedure is as follows (sdb1 is the A2 and
-sdb2 the FAT32 partition)::
+sdb2 the FAT32 partition):
+
+.. code-block:: sh
mount -t fat /dev/sdb2 /mnt
make socfpga-xload_defconfig
@@ -50,7 +52,9 @@ sdb2 the FAT32 partition)::
make
barebox has now generated multiple files in the images directory. So for the SoCkit
-proceed with::
+proceed with:
+
+.. code-block:: sh
cat images/barebox-socfpga-sockit-xload.img > /dev/sdb1
cp images/barebox-socfpga-sockit.img /mnt/barebox.bin
@@ -64,12 +68,16 @@ QSPI
The Boot ROM loads the preloader starting from address 0x0 on the QSPI flash.
barebox then searches for a barebox image at the 256K offset and loads it.
-The default bootsource is SD card, so to change that to QSPI, you have to::
+The default bootsource is SD card, so to change that to QSPI, you have to:
+
+.. code-block:: sh
make socfpga-xload_defconfig
make menuconfig
-And then select the options `MTD` and `SPI_CADENCE_QUADSPI`. Now::
+And then select the options `MTD` and `SPI_CADENCE_QUADSPI`. Now:
+
+.. code-block:: sh
make
cat images/barebox-socfpga-<board>-xload.img > /dev/mtd0
@@ -116,7 +124,9 @@ To update the handoff files, the following procedure is necessary:
preloader settings directory
7. Click ``Ok`` than ``Generate``
-Now run the command::
+Now run the command:
+
+.. code-block:: sh
scripts/socfpga_import_preloader <SPL_GENERATED_DIR> <ISW_HANDOFF> <BOARD_DIRECTORY>
@@ -141,7 +151,9 @@ tree:
* system.h
* tclrpt.h
-To add these files, run::
+To add these files, run:
+
+.. code-block:: sh
scripts/socfpga_get_sequencer <UBOOT-SRC> scripts/socfpga_sequencer_defines_defaults
diff --git a/Documentation/boards/x86.rst b/Documentation/boards/x86.rst
index d0528a3280..4514a766a2 100644
--- a/Documentation/boards/x86.rst
+++ b/Documentation/boards/x86.rst
@@ -50,7 +50,8 @@ sectors must be kept free after the MBR prior the first partition. Do this
simple calulation:
.. code-block:: none
- sectors = (\<size of barebox image\> + 511) / 512
+
+ sectors = (size of barebox image + 511) / 512
To be able to store the runtime configuration, further free sectors are
required. Its up to you and your requirements, how large this persistant
diff --git a/Documentation/conf.py b/Documentation/conf.py
index dbd4a80caa..ec6ec0470b 100644
--- a/Documentation/conf.py
+++ b/Documentation/conf.py
@@ -259,4 +259,4 @@ texinfo_documents = [
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False
-highlight_language = 'sh'
+highlight_language = 'none'
diff --git a/Documentation/filesystems/fat.rst b/Documentation/filesystems/fat.rst
index e39e34a0e9..138e69711f 100644
--- a/Documentation/filesystems/fat.rst
+++ b/Documentation/filesystems/fat.rst
@@ -5,7 +5,9 @@ FAT filesystem
barebox supports FAT filesystems in both read and write modes with optional
support for long filenames. A FAT filesystem can be mounted using the
-:ref:`command_mount` command::
+:ref:`command_mount` command:
+
+.. code-block:: console
barebox:/ mkdir /mnt
barebox:/ mount /dev/disk0.0 fat /mnt
diff --git a/Documentation/filesystems/nfs.rst b/Documentation/filesystems/nfs.rst
index ab51241549..3e40ae9767 100644
--- a/Documentation/filesystems/nfs.rst
+++ b/Documentation/filesystems/nfs.rst
@@ -7,7 +7,9 @@ NFS Support
barebox has readonly support for NFSv3 in UDP mode.
-Example::
+Example:
+
+.. code-block:: console
barebox:/ mount -t nfs 192.168.23.4:/home/user/nfsroot /mnt/nfs
@@ -15,7 +17,9 @@ The barebox NFS driver adds a ``linux.bootargs`` device parameter to the NFS dev
This parameter holds a Linux kernel commandline snippet containing a suitable root=
option for booting from exactly that NFS share.
-Example::
+Example:
+
+.. code-block:: console
barebox:/ devinfo nfs0
...
diff --git a/Documentation/filesystems/pstore.rst b/Documentation/filesystems/pstore.rst
index 8eee374bdd..22e89b3f1f 100644
--- a/Documentation/filesystems/pstore.rst
+++ b/Documentation/filesystems/pstore.rst
@@ -20,7 +20,7 @@ at boot:
none on /pstore type pstore
pstore may add additional warnings during boot due to wrong ECCs (no data
-written)::
+written):
.. code-block:: none
diff --git a/Documentation/filesystems/ramfs.rst b/Documentation/filesystems/ramfs.rst
index d27f88561f..e61505a5f9 100644
--- a/Documentation/filesystems/ramfs.rst
+++ b/Documentation/filesystems/ramfs.rst
@@ -7,6 +7,8 @@ ramfs is a simple malloc-based filesystem. An instance of ramfs is
mounted during startup on /. The filesystem type passed to ``mount``
is ``ramfs``.
-Example::
+Example:
+
+.. code-block:: console
barebox:/ mount none ramfs /somedir
diff --git a/Documentation/filesystems/smhfs.rst b/Documentation/filesystems/smhfs.rst
index 9e9993cb28..8f8a0ec6b7 100644
--- a/Documentation/filesystems/smhfs.rst
+++ b/Documentation/filesystems/smhfs.rst
@@ -18,7 +18,9 @@ not have support for listing directories. This means a
:ref:`command_ls` to a SMHFS-mounted path will show an empty
directory. Nevertheless, the files are there.
-Example::
+Example:
+
+.. code-block:: console
barebox:/ mount -t smhfs /dev/null /mnt/smhfs
diff --git a/Documentation/filesystems/squashfs.rst b/Documentation/filesystems/squashfs.rst
index 88c97ebbe8..a042f7b96b 100644
--- a/Documentation/filesystems/squashfs.rst
+++ b/Documentation/filesystems/squashfs.rst
@@ -6,7 +6,9 @@ SquashFS filesystem
SquashFS is a highly compressed read-only filesystem for Linux.
It uses zlib, lzo or xz compression to compress both files, inodes
and directories. A SquashFS filesystem can be mounted using the
-:ref:`command_mount` command::
+:ref:`command_mount` command:
+
+.. code-block:: console
barebox:/ mkdir /mnt
barebox:/ mount -t squashfs /dev/spiflash.FileSystem /mnt
diff --git a/Documentation/filesystems/tftp.rst b/Documentation/filesystems/tftp.rst
index eeb3fcb688..a292765e25 100644
--- a/Documentation/filesystems/tftp.rst
+++ b/Documentation/filesystems/tftp.rst
@@ -12,7 +12,9 @@ TFTP is not designed as a filesystem. It does not have support for listing
directories. This means a :ref:`ls <command_ls>` to a TFTP-mounted path will
show an empty directory. Nevertheless, the files are there.
-Example::
+Example:
+
+.. code-block:: console
barebox:/ mount -t tftp 192.168.23.4 /mnt/tftp
diff --git a/Documentation/user/automount.rst b/Documentation/user/automount.rst
index 7de8261354..1fdeffc663 100644
--- a/Documentation/user/automount.rst
+++ b/Documentation/user/automount.rst
@@ -10,7 +10,9 @@ filesystems. The filesystems (and the devices they are on) are only probed
when necessary, so barebox does not lose time probing unused devices.
Typical usage is for accessing the TFTP server. To set up an automount for a
-TFTP server, the following is required::
+TFTP server, the following is required:
+
+.. code-block:: sh
mkdir -p /mnt/tftp
automount /mnt/tftp 'ifup -a && mount -t tftp $global.net.server /mnt/tftp'
@@ -21,12 +23,16 @@ It will bring up the network device using :ref:`command_ifup` and mount a TFTP f
using :ref:`command_mount`.
Usually the above automount command is executed from an init script in ``/env/init/automount``.
-With the above, files on the TFTP server can be accessed without configuration::
+With the above, files on the TFTP server can be accessed without configuration:
+
+.. code-block:: sh
cp /mnt/tftp/linuximage /image
This automatically detects a USB mass storage device and mounts the first
-partition to ``/mnt/fat``::
+partition to ``/mnt/fat``:
+
+.. code-block:: sh
mkdir -p /mnt/fat
automount -d /mnt/fat 'usb && [ -e /dev/disk0.0 ] && mount /dev/disk0.0 /mnt/fat'
diff --git a/Documentation/user/barebox.rst b/Documentation/user/barebox.rst
index 82a33a3219..026ed1b9c0 100644
--- a/Documentation/user/barebox.rst
+++ b/Documentation/user/barebox.rst
@@ -181,9 +181,7 @@ simply with:
The resulting binary varies depending on the board barebox is compiled for.
Without :ref:`multi_image` support the ``barebox-flash-image`` link will point
to the binary for flashing/uploading to the board. With :ref:`multi_image` support
-the compilation process will finish with a list of images built under ``images/``:
-
-.. code-block:: sh
+the compilation process will finish with a list of images built under ``images/``::
images built:
barebox-freescale-imx51-babbage.img
diff --git a/Documentation/user/defaultenv-2.rst b/Documentation/user/defaultenv-2.rst
index 7502d3de10..a79ae83d56 100644
--- a/Documentation/user/defaultenv-2.rst
+++ b/Documentation/user/defaultenv-2.rst
@@ -44,7 +44,9 @@ and their respective included directories in ``defaultenv/Makefile``:
This script is executed by the barebox startup code after initialization.
In defaultenv-2, this script will define and set a number of global
-variables, followed by sourcing all of the scripts in ``/env/init/`` with::
+variables, followed by sourcing all of the scripts in ``/env/init/`` with:
+
+.. code-block:: sh
for i in /env/init/*; do
. $i
diff --git a/Documentation/user/driver-model.rst b/Documentation/user/driver-model.rst
index ce7083589c..a0fd3e99b5 100644
--- a/Documentation/user/driver-model.rst
+++ b/Documentation/user/driver-model.rst
@@ -32,7 +32,9 @@ Some devices like USB or MMC may take a longer time to probe. Probing USB
devices should not delay booting when USB may not even be used. This case is
handled with device detection. The user visible interface to device detection
is the :ref:`command_detect` command. ``detect -l`` shows a list of detectable
-devices::
+devices:
+
+.. code-block:: console
barebox:/ detect -l
70004000.esdhc
@@ -46,7 +48,9 @@ devices::
mmc1
miibus0
-A particular device can be detected with ``detect <devname>``::
+A particular device can be detected with ``detect <devname>``:
+
+.. code-block:: console
barebox:/ detect 73f80200.usb
Found SMSC USB331x ULPI transceiver (0x0424:0x0006).
@@ -67,7 +71,9 @@ Device parameters
Devices can have parameters which can be used to configure devices or to provide
additional information for a device. The parameters can be listed with the
:ref:`command_devinfo` command. A ``devinfo <devicename>`` will print the parameters
-of a device::
+of a device:
+
+.. code-block:: console
barebox:/ devinfo eth0
Parameters:
@@ -77,12 +83,16 @@ of a device::
netmask: 255.255.0.0
ethaddr: 00:1c:49:01:03:4b
-The parameters can be used as shell variables::
+The parameters can be used as shell variables:
+
+.. code-block:: sh
eth0.ipaddr=192.168.23.15
echo "my current ip is: $eth0.ipaddr"
-device variables may have a type, so assigning wrong values may fail::
+device variables may have a type, so assigning wrong values may fail:
+
+.. code-block:: console
barebox:/ eth0.ipaddr="This is not an IP"
set parameter: Invalid argument
diff --git a/Documentation/user/hush.rst b/Documentation/user/hush.rst
index 00d4e2983e..a4d8688142 100644
--- a/Documentation/user/hush.rst
+++ b/Documentation/user/hush.rst
@@ -13,13 +13,17 @@ more flexible and also more robust than a complicated shell script.
Hush features
-------------
-variables::
+variables:
+
+.. code-block:: sh
a="Hello user"
echo $a
Hello user
-conditional execution ``if`` / ``elif`` / ``else`` / ``fi``::
+conditional execution ``if`` / ``elif`` / ``else`` / ``fi``:
+
+.. code-block:: sh
if [ ${foo} = ${bar} ]; then
echo "foo equals bar"
@@ -27,19 +31,25 @@ conditional execution ``if`` / ``elif`` / ``else`` / ``fi``::
echo "foo and bar differ"
fi
-``for`` loops::
+``for`` loops:
+
+.. code-block:: sh
for i in a b c; do
echo $i
done
-``while`` loops::
+``while`` loops:
+
+.. code-block:: sh
while true; do
echo "endless loop"
done
-wildcard globbing::
+wildcard globbing:
+
+.. code-block:: sh
ls d*
echo ???
@@ -53,7 +63,9 @@ stored.
**NOTE:** hush feels like a normal Unix shell, but it cannot calculate by
itself, i.e. $(($A/2)) won't work. Calculation can however be done
-with :ref:`command_let`::
+with :ref:`command_let`:
+
+.. code-block:: sh
A=10
let B=$A/2
diff --git a/Documentation/user/memory-areas.rst b/Documentation/user/memory-areas.rst
index 9654a99167..d673f6e1b1 100644
--- a/Documentation/user/memory-areas.rst
+++ b/Documentation/user/memory-areas.rst
@@ -17,11 +17,15 @@ gigabyte.
Examples
--------
-Display a hexdump from 0x80000000 to 0x80001000 (inclusive)::
+Display a hexdump from 0x80000000 to 0x80001000 (inclusive):
+
+.. code-block:: sh
md 0x80000000-0x80001000
-Display 1 kilobyte of memory starting at 0x80000000::
+Display 1 kilobyte of memory starting at 0x80000000:
+
+.. code-block:: sh
md 0x80000000+1k
diff --git a/Documentation/user/system-setup.rst b/Documentation/user/system-setup.rst
index f0598bc2b5..5651569dc2 100644
--- a/Documentation/user/system-setup.rst
+++ b/Documentation/user/system-setup.rst
@@ -16,7 +16,9 @@ for root privileges.
Using the "screen" program
^^^^^^^^^^^^^^^^^^^^^^^^^^
-The terminal manager ``screen`` can also be used as a simple terminal emulator::
+The terminal manager ``screen`` can also be used as a simple terminal emulator:
+
+.. code-block:: sh
screen /dev/ttyUSB0 115200
@@ -31,7 +33,9 @@ from source:
https://git.pengutronix.de/cgit/tools/microcom
-Usage is simple::
+Usage is simple:
+
+.. code-block:: sh
microcom -p /dev/ttyUSB0
@@ -46,7 +50,9 @@ Configuration of dnsmasq for DHCP and TFTP
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``dnsmasq`` program can be configured as a DHCP and TFTP server in addition
-to its original DNS functionality::
+to its original DNS functionality:
+
+.. code-block:: sh
sudo ip addr add 192.168.23.1/24 dev <interface>
sudo ip link set <interface> up
diff --git a/Documentation/user/updating.rst b/Documentation/user/updating.rst
index 7aac0a99d6..0555909aa1 100644
--- a/Documentation/user/updating.rst
+++ b/Documentation/user/updating.rst
@@ -11,12 +11,16 @@ A board can register an update handler to the update command. The handler can
do additional checks before trying an update, e.g. it's possible
to check whether the new image actually is a barebox image.
-Updating barebox can be as easy as::
+Updating barebox can be as easy as:
+
+.. code-block:: sh
barebox_update /path/to/new/barebox.img
Multiple handlers can be registered to the update mechanism. Usually the device
-barebox has been started from is registered as default (marked with a ``*``)::
+barebox has been started from is registered as default (marked with a ``*``):
+
+.. code-block:: console
barebox:/ barebox_update -l
registered update handlers:
diff --git a/Documentation/user/variables.rst b/Documentation/user/variables.rst
index e0a79416c6..ddfd485740 100644
--- a/Documentation/user/variables.rst
+++ b/Documentation/user/variables.rst
@@ -12,12 +12,16 @@ The ``global`` device
The ``global`` device is a special purpose device. It only exists as a
storage for global variables. Some global variables are created internally
in barebox (see :ref:`magicvars`). Additional variables can be created with
-the :ref:`command_global` command::
+the :ref:`command_global` command:
+
+.. code-block:: sh
global myvar
This creates the ``global.myvar`` variable which now can be used like any
-other variable. You can also directly assign a value during creation::
+other variable. You can also directly assign a value during creation:
+
+.. code-block:: sh
global myvar1=foobar
@@ -48,7 +52,7 @@ actual values.
examples:
-.. code-block:: sh
+.. code-block:: console
barebox@Phytec phyCARD-i.MX27:/ devinfo nv
barebox@Phytec phyCARD-i.MX27:/ nv model=myboard
@@ -94,7 +98,9 @@ Some variables have special meanings and influence the behaviour
of barebox. Most but not all of them are consolidated in the :ref:`global_device`.
Since it's hard to remember which variables these are and if the current
barebox has support for them the :ref:`command_magicvar` command can print a list
-of all variables with special meaning along with a short description::
+of all variables with special meaning along with a short description:
+
+.. code-block:: console
barebox:/ magicvar
OPTARG optarg for hush builtin getopt
diff --git a/Makefile b/Makefile
index a49c1f7c63..973a8d1161 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
VERSION = 2018
-PATCHLEVEL = 07
+PATCHLEVEL = 08
SUBLEVEL = 0
EXTRAVERSION =
NAME = None
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 702b2fe6ef..3b486f7b8b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -384,7 +384,11 @@ config ARM_SEMIHOSTING
the data on the host computer connected to the target via
debugging channel (JTAG, SWD). If unsure say N
+config ARM_SMCCC
+ bool
+
config ARM_SECURE_MONITOR
+ select ARM_SMCCC
bool
config ARM_PSCI
diff --git a/arch/arm/boards/freescale-mx6sx-sabresdb/board.c b/arch/arm/boards/freescale-mx6sx-sabresdb/board.c
index 028b1dddbe..0fd9af80cb 100644
--- a/arch/arm/boards/freescale-mx6sx-sabresdb/board.c
+++ b/arch/arm/boards/freescale-mx6sx-sabresdb/board.c
@@ -161,7 +161,7 @@ err_out:
}
fs_initcall(imx6sx_sdb_setup_pmic_voltages);
-int ar8031_phy_fixup(struct phy_device *phydev)
+static int ar8031_phy_fixup(struct phy_device *phydev)
{
/*
* Enable 1.8V(SEL_1P5_1P8_POS_REG) on
diff --git a/arch/arm/boards/gateworks-ventana/board.c b/arch/arm/boards/gateworks-ventana/board.c
index 3ff142ee42..6f9e0343be 100644
--- a/arch/arm/boards/gateworks-ventana/board.c
+++ b/arch/arm/boards/gateworks-ventana/board.c
@@ -17,6 +17,7 @@
#include <i2c/i2c.h>
#include <init.h>
#include <linux/marvell_phy.h>
+#include <linux/pci.h>
#include <linux/phy.h>
#include <mach/bbu.h>
#include <mach/imx6.h>
@@ -111,3 +112,31 @@ static int gw54xx_coredevices_init(void)
return 0;
}
coredevice_initcall(gw54xx_coredevices_init);
+
+/*
+ * fixup for PLX PEX8909 bridge to configure GPIO1-7 as output High
+ * as they are used for slots1-7 PERST#
+ */
+static void ventana_pciesw_early_fixup(struct pci_dev *dev)
+{
+ u32 dw;
+
+ if (!of_machine_is_compatible("gw,ventana"))
+ return;
+
+ if (dev->devfn != 0)
+ return;
+
+ pci_read_config_dword(dev, 0x62c, &dw);
+ dw |= 0xaaa8; // GPIO1-7 outputs
+ pci_write_config_dword(dev, 0x62c, dw);
+
+ pci_read_config_dword(dev, 0x644, &dw);
+ dw |= 0xfe; // GPIO1-7 output high
+ pci_write_config_dword(dev, 0x644, dw);
+
+ mdelay(100);
+}
+DECLARE_PCI_FIXUP_EARLY(0x10b5, 0x8609, ventana_pciesw_early_fixup);
+DECLARE_PCI_FIXUP_EARLY(0x10b5, 0x8606, ventana_pciesw_early_fixup);
+DECLARE_PCI_FIXUP_EARLY(0x10b5, 0x8604, ventana_pciesw_early_fixup);
diff --git a/arch/arm/boards/nxp-imx8mq-evk/ddr_init.c b/arch/arm/boards/nxp-imx8mq-evk/ddr_init.c
index 81691b2fae..44103b5e26 100644
--- a/arch/arm/boards/nxp-imx8mq-evk/ddr_init.c
+++ b/arch/arm/boards/nxp-imx8mq-evk/ddr_init.c
@@ -2,7 +2,8 @@
* Copyright 2017 NXP
*
* SPDX-License-Identifier: GPL-2.0+
- * Generated code from MX8_DDR_tool
+ *
+ * Generated code from MX8M_DDR_tool
*/
#include "ddr.h"
@@ -21,7 +22,7 @@ void ddr_init(void)
reg32_write(0x303a00f8,tmp);
reg32_write(0x30391000,0x8f000000);
reg32_write(0x30391004,0x8f000000);
- reg32_write(0x30360068,0xbbe580);
+ reg32_write(0x30360068,0xece580);
tmp=reg32_read(0x30360060);
tmp &= ~0x80;
reg32_write(0x30360060,tmp);
@@ -41,18 +42,19 @@ void ddr_init(void)
reg32_write(0x30391000,0x8f000006);
reg32_write(0x3d400304,0x1);
reg32_write(0x3d400030,0x1);
- reg32_write(0x3d400000,0x83080020);
+ reg32_write(0x3d400000,0xa3080020);
+ reg32_write(0x3d400028,0x0);
+ reg32_write(0x3d400020,0x203);
+ reg32_write(0x3d400024,0x186a000);
reg32_write(0x3d400064,0x6100e0);
reg32_write(0x3d4000d0,0xc003061c);
reg32_write(0x3d4000d4,0x9e0000);
reg32_write(0x3d4000dc,0xd4002d);
reg32_write(0x3d4000e0,0x310008);
- reg32_write(0x3d4000e8,0x46004d);
- reg32_write(0x3d4000ec,0x15004d);
- reg32_write(0x3d4000f4,0x639);
+ reg32_write(0x3d4000e8,0x66004a);
+ reg32_write(0x3d4000ec,0x16004a);
reg32_write(0x3d400100,0x1a201b22);
reg32_write(0x3d400104,0x60633);
- reg32_write(0x3d400108,0x70e1214);
reg32_write(0x3d40010c,0xc0c000);
reg32_write(0x3d400110,0xf04080f);
reg32_write(0x3d400114,0x2040c0c);
@@ -64,78 +66,77 @@ void ddr_init(void)
reg32_write(0x3d400144,0xa00050);
reg32_write(0x3d400180,0x3200018);
reg32_write(0x3d400184,0x28061a8);
+ reg32_write(0x3d400188,0x0);
reg32_write(0x3d400190,0x497820a);
reg32_write(0x3d400194,0x80303);
- reg32_write(0x3d4001b4,0x170a);
- reg32_write(0x3d4001b0,0x11);
reg32_write(0x3d4001a0,0xe0400018);
reg32_write(0x3d4001a4,0xdf00e4);
- reg32_write(0x3d4001a8,0x0);
+ reg32_write(0x3d4001a8,0x80000000);
+ reg32_write(0x3d4001b0,0x11);
+ reg32_write(0x3d4001b4,0x170a);
reg32_write(0x3d4001c0,0x1);
reg32_write(0x3d4001c4,0x1);
+ reg32_write(0x3d4000f4,0x639);
+ reg32_write(0x3d400108,0x70e1214);
reg32_write(0x3d400200,0x15);
reg32_write(0x3d40020c,0x0);
reg32_write(0x3d400210,0x1f1f);
reg32_write(0x3d400204,0x80808);
reg32_write(0x3d400214,0x7070707);
reg32_write(0x3d400218,0x48080707);
+ reg32_write(0x3d402020,0x1);
+ reg32_write(0x3d402024,0x518b00);
+ reg32_write(0x3d402050,0x20d040);
+ reg32_write(0x3d402064,0x14002f);
+ reg32_write(0x3d4020dc,0x940009);
+ reg32_write(0x3d4020e0,0x310000);
+ reg32_write(0x3d4020e8,0x66004a);
+ reg32_write(0x3d4020ec,0x16004a);
+ reg32_write(0x3d402100,0xb070508);
+ reg32_write(0x3d402104,0x3040b);
+ reg32_write(0x3d402108,0x305090c);
+ reg32_write(0x3d40210c,0x505000);
+ reg32_write(0x3d402110,0x4040204);
+ reg32_write(0x3d402114,0x2030303);
+ reg32_write(0x3d402118,0x1010004);
+ reg32_write(0x3d40211c,0x301);
+ reg32_write(0x3d402130,0x20300);
+ reg32_write(0x3d402134,0xa100002);
+ reg32_write(0x3d402138,0x31);
+ reg32_write(0x3d402144,0x220011);
+ reg32_write(0x3d402180,0xa70006);
+ reg32_write(0x3d402190,0x3858202);
+ reg32_write(0x3d402194,0x80303);
+ reg32_write(0x3d4021b4,0x502);
reg32_write(0x3d400244,0x0);
- reg32_write(0x3d400490,0x1);
- reg32_write(0x3d400250,0x29001f01);
+ reg32_write(0x3d400250,0x29001505);
reg32_write(0x3d400254,0x2c);
- reg32_write(0x3d400264,0x900093e7);
+ reg32_write(0x3d40025c,0x5900575b);
+ reg32_write(0x3d400264,0x9);
reg32_write(0x3d40026c,0x2005574);
- reg32_write(0x3d400400,0x400);
+ reg32_write(0x3d400300,0x16);
+ reg32_write(0x3d400304,0x0);
+ reg32_write(0x3d40030c,0x0);
+ reg32_write(0x3d400320,0x1);
+ reg32_write(0x3d40036c,0x11);
+ reg32_write(0x3d400400,0x111);
+ reg32_write(0x3d400404,0x10f3);
reg32_write(0x3d400408,0x72ff);
- reg32_write(0x3d400494,0x10e00);
- reg32_write(0x3d400498,0x620096);
- reg32_write(0x3d40049c,0x10e00);
- reg32_write(0x3d4004a0,0x12c);
+ reg32_write(0x3d400490,0x1);
+ reg32_write(0x3d400494,0x1110d00);
+ reg32_write(0x3d400498,0x620790);
+ reg32_write(0x3d40049c,0x100001);
+ reg32_write(0x3d4004a0,0x41f);
reg32_write(0x30391000,0x8f000004);
reg32_write(0x30391000,0x8f000000);
- reg32_write(0x3d400304,0x0);
reg32_write(0x3d400030,0xa8);
+ do{
+ tmp=reg32_read(0x3d400004);
+ if(tmp&0x223) break;
+ }while(1);
reg32_write(0x3d400320,0x0);
reg32_write(0x3d000000,0x1);
reg32_write(0x3d4001b0,0x10);
- reg32_write(0x3d402100,0xa040305);
- reg32_write(0x3d402104,0x30407);
- reg32_write(0x3d402108,0x203060b);
- reg32_write(0x3d40210c,0x505000);
- reg32_write(0x3d402110,0x2040202);
- reg32_write(0x3d402114,0x2030202);
- reg32_write(0x3d402118,0x1010004);
- reg32_write(0x3d40211c,0x301);
- reg32_write(0x3d402138,0x1d);
- reg32_write(0x3d402144,0x14000a);
- reg32_write(0x3d403024,0x30d400);
- reg32_write(0x3d402050,0x20d040);
- reg32_write(0x3d402190,0x3818200);
- reg32_write(0x3d4021b4,0x100);
- reg32_write(0x3d402064,0xc001c);
- reg32_write(0x3d4020dc,0x840000);
- reg32_write(0x3d4020e8,0x46004d);
- reg32_write(0x3d4020ec,0x15004d);
- reg32_write(0x3d4020e0,0x310000);
- reg32_write(0x3d403100,0x6010102);
- reg32_write(0x3d403104,0x30404);
- reg32_write(0x3d403108,0x203060b);
- reg32_write(0x3d40310c,0x505000);
- reg32_write(0x3d403110,0x2040202);
- reg32_write(0x3d403114,0x2030202);
- reg32_write(0x3d403118,0x1010004);
- reg32_write(0x3d40311c,0x301);
- reg32_write(0x3d403138,0x8);
- reg32_write(0x3d403144,0x50003);
- reg32_write(0x3d403024,0xc3500);
- reg32_write(0x3d403050,0x20d040);
- reg32_write(0x3d403190,0x3818200);
- reg32_write(0x3d4031b4,0x100);
- reg32_write(0x3d403064,0x30007);
- reg32_write(0x3d4030dc,0x840000);
- reg32_write(0x3d4030e8,0x46004d);
- reg32_write(0x3d4030ec,0x15004d);
- reg32_write(0x3d4030e0,0x310000);
reg32_write(0x3c040280,0x0);
reg32_write(0x3c040284,0x1);
reg32_write(0x3c040288,0x2);
@@ -218,6 +219,7 @@ void ddr_init(void)
/* enable port 0 */
reg32_write(DDRC_PCTRL_0(0), 0x00000001);
- tmp = reg32_read(DDRC_CRCPARSTAT(0));
- reg32_write(DDRC_RFSHCTL3(0), 0x00000000);
+ /* enable DDR auto-refresh mode */
+ tmp = reg32_read(DDRC_RFSHCTL3(0)) & ~0x1;
+ reg32_write(DDRC_RFSHCTL3(0), tmp);
} \ No newline at end of file
diff --git a/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c b/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c
index 156d7cf87e..1b30ff7257 100644
--- a/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c
+++ b/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c
@@ -2,6 +2,8 @@
* Copyright 2017 NXP
*
* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Generated code from MX8M_DDR_tool
*/
#include "ddr.h"
@@ -32,14 +34,6 @@ void ddr_cfg_phy(void) {
reg32_write(0x3c44857c,0x1ff);
reg32_write(0x3c44c17c,0x1ff);
reg32_write(0x3c44c57c,0x1ff);
- reg32_write(0x3c84017c,0x1ff);
- reg32_write(0x3c84057c,0x1ff);
- reg32_write(0x3c84417c,0x1ff);
- reg32_write(0x3c84457c,0x1ff);
- reg32_write(0x3c84817c,0x1ff);
- reg32_write(0x3c84857c,0x1ff);
- reg32_write(0x3c84c17c,0x1ff);
- reg32_write(0x3c84c57c,0x1ff);
reg32_write(0x3c000154,0x1ff);
reg32_write(0x3c004154,0x1ff);
reg32_write(0x3c008154,0x1ff);
@@ -52,22 +46,16 @@ void ddr_cfg_phy(void) {
reg32_write(0x3c024154,0x1ff);
reg32_write(0x3c080314,0x19);
reg32_write(0x3c480314,0x7);
- reg32_write(0x3c880314,0x7);
reg32_write(0x3c0800b8,0x2);
- reg32_write(0x3c4800b8,0x2);
- reg32_write(0x3c8800b8,0x2);
+ reg32_write(0x3c4800b8,0x1);
reg32_write(0x3c240810,0x0);
reg32_write(0x3c640810,0x0);
- reg32_write(0x3ca40810,0x0);
reg32_write(0x3c080090,0xab);
reg32_write(0x3c0800e8,0x0);
reg32_write(0x3c480090,0xab);
reg32_write(0x3c0800e8,0x0);
- reg32_write(0x3c880090,0xab);
- reg32_write(0x3c0800e8,0x0);
- reg32_write(0x3c080158,0x7);
+ reg32_write(0x3c080158,0x3);
reg32_write(0x3c480158,0xa);
- reg32_write(0x3c880158,0xa);
reg32_write(0x3c040134,0xe00);
reg32_write(0x3c040534,0xe00);
reg32_write(0x3c044134,0xe00);
@@ -84,14 +72,6 @@ void ddr_cfg_phy(void) {
reg32_write(0x3c448534,0xe00);
reg32_write(0x3c44c134,0xe00);
reg32_write(0x3c44c534,0xe00);
- reg32_write(0x3c840134,0xe00);
- reg32_write(0x3c840534,0xe00);
- reg32_write(0x3c844134,0xe00);
- reg32_write(0x3c844534,0xe00);
- reg32_write(0x3c848134,0xe00);
- reg32_write(0x3c848534,0xe00);
- reg32_write(0x3c84c134,0xe00);
- reg32_write(0x3c84c534,0xe00);
reg32_write(0x3c040124,0xfbe);
reg32_write(0x3c040524,0xfbe);
reg32_write(0x3c044124,0xfbe);
@@ -108,14 +88,6 @@ void ddr_cfg_phy(void) {
reg32_write(0x3c448524,0xfbe);
reg32_write(0x3c44c124,0xfbe);
reg32_write(0x3c44c524,0xfbe);
- reg32_write(0x3c840124,0xfbe);
- reg32_write(0x3c840524,0xfbe);
- reg32_write(0x3c844124,0xfbe);
- reg32_write(0x3c844524,0xfbe);
- reg32_write(0x3c848124,0xfbe);
- reg32_write(0x3c848524,0xfbe);
- reg32_write(0x3c84c124,0xfbe);
- reg32_write(0x3c84c524,0xfbe);
reg32_write(0x3c00010c,0x63);
reg32_write(0x3c00410c,0x63);
reg32_write(0x3c00810c,0x63);
@@ -130,8 +102,7 @@ void ddr_cfg_phy(void) {
reg32_write(0x3c0801d4,0x4);
reg32_write(0x3c080140,0x0);
reg32_write(0x3c080020,0x320);
- reg32_write(0x3c480020,0x64);
- reg32_write(0x3c880020,0x19);
+ reg32_write(0x3c480020,0xa7);
reg32_write(0x3c080220,0x9);
reg32_write(0x3c0802c8,0xdc);
reg32_write(0x3c04010c,0x5a1);
@@ -151,33 +122,21 @@ void ddr_cfg_phy(void) {
reg32_write(0x3c44850c,0x5a1);
reg32_write(0x3c44c10c,0x5a1);
reg32_write(0x3c44c50c,0x5a1);
- reg32_write(0x3c8802c8,0xdc);
- reg32_write(0x3c84010c,0x5a1);
- reg32_write(0x3c84050c,0x5a1);
- reg32_write(0x3c84410c,0x5a1);
- reg32_write(0x3c84450c,0x5a1);
- reg32_write(0x3c84810c,0x5a1);
- reg32_write(0x3c84850c,0x5a1);
- reg32_write(0x3c84c10c,0x5a1);
- reg32_write(0x3c84c50c,0x5a1);
reg32_write(0x3c0803e8,0x1);
reg32_write(0x3c4803e8,0x1);
- reg32_write(0x3c8803e8,0x1);
reg32_write(0x3c080064,0x1);
reg32_write(0x3c480064,0x1);
- reg32_write(0x3c880064,0x1);
- reg32_write(0x3c0803c0,0x660);
+ reg32_write(0x3c0803c0,0x0);
reg32_write(0x3c0803c4,0x0);
reg32_write(0x3c0803c8,0x4444);
reg32_write(0x3c0803cc,0x8888);
- reg32_write(0x3c0803d0,0x5665);
+ reg32_write(0x3c0803d0,0x5555);
reg32_write(0x3c0803d4,0x0);
reg32_write(0x3c0803d8,0x0);
reg32_write(0x3c0803dc,0xf000);
reg32_write(0x3c080094,0x0);
reg32_write(0x3c0800b4,0x0);
reg32_write(0x3c4800b4,0x0);
- reg32_write(0x3c8800b4,0x0);
reg32_write(0x3c080180,0x2);
//enable APB bus to access DDRPHY RAM
@@ -195,31 +154,32 @@ void ddr_cfg_phy(void) {
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54008,0x131f);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54009,0xc8);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5400b,0x2);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5400d,0x100);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54012,0x310);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54019,0x2dd4);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401a,0x31);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401b,0x4d46);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401c,0x4d08);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401e,0x15);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401b,0x4a66);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401c,0x4a08);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401e,0x16);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401f,0x2dd4);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54020,0x31);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54021,0x4d46);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54022,0x4d08);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54024,0x15);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54021,0x4a66);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54022,0x4a08);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54024,0x16);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5402b,0x1000);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5402c,0x3);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54032,0xd400);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54033,0x312d);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54034,0x4600);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54035,0x84d);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54036,0x4d);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54037,0x1500);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54034,0x6600);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54035,0x84a);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54036,0x4a);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54037,0x1600);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54038,0xd400);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54039,0x312d);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403a,0x4600);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403b,0x84d);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403c,0x4d);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403d,0x1500);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403a,0x6600);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403b,0x84a);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403c,0x4a);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403d,0x1600);
//disable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x1);
@@ -233,96 +193,57 @@ void ddr_cfg_phy(void) {
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
//set the PHY input clock to the desired frequency for pstate 1
- reg32_write(0x3038a008,0x7070000);
- reg32_write(0x3038a004,0x5000000);
- reg32_write(0x3038a088,0x7070000);
- reg32_write(0x3038a084,0x2010000);
- reg32_write(0x303a00ec,0xffff);
- tmp=reg32_read(0x303a00f8);
- tmp |= 0x20;
- reg32_write(0x303a00f8,tmp);
- reg32_write(0x30389804,0x1000000);
-
- //enable APB bus to access DDRPHY RAM
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
-
- reg32_write(0x3c150008,0x101);
- reg32_write(0x3c15000c,0x190);
- reg32_write(0x3c150020,0x121f);
- reg32_write(0x3c150064,0x84);
- reg32_write(0x3c150068,0x31);
- reg32_write(0x3c15006c,0x4d46);
- reg32_write(0x3c150070,0x4d08);
- reg32_write(0x3c150074,0x0);
- reg32_write(0x3c150078,0x15);
- reg32_write(0x3c15007c,0x84);
- reg32_write(0x3c150080,0x31);
- reg32_write(0x3c150084,0x4d46);
- reg32_write(0x3c150088,0x4d08);
- reg32_write(0x3c15008c,0x0);
- reg32_write(0x3c150090,0x15);
- reg32_write(0x3c1500c8,0x8400);
- reg32_write(0x3c1500cc,0x3100);
- reg32_write(0x3c1500d0,0x4600);
- reg32_write(0x3c1500d4,0x84d);
- reg32_write(0x3c1500d8,0x4d);
- reg32_write(0x3c1500dc,0x1500);
- reg32_write(0x3c1500e0,0x8400);
- reg32_write(0x3c1500e4,0x3100);
- reg32_write(0x3c1500e8,0x4600);
- reg32_write(0x3c1500ec,0x84d);
- reg32_write(0x3c1500f0,0x4d);
- reg32_write(0x3c1500f4,0x1500);
- reg32_write(0x3c1500f8,0x0);
-
- //disable APB bus to access DDRPHY RAM
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x1);
- //Reset MPU and run
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0);
- wait_ddrphy_training_complete();
-
- //configure DDRPHY-FW DMEM structure @clock2...
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
-
- //set the PHY input clock to the desired frequency for pstate 2
- reg32_write(0x3038a008,0x7070000);
- reg32_write(0x3038a004,0x2000000);
reg32_write(0x3038a088,0x7070000);
- reg32_write(0x3038a084,0x2010000);
+ reg32_write(0x3038a084,0x4030000);
reg32_write(0x303a00ec,0xffff);
tmp=reg32_read(0x303a00f8);
tmp |= 0x20;
reg32_write(0x303a00f8,tmp);
- reg32_write(0x30389804,0x1000000);
+ reg32_write(0x30360068,0xf5a406);
+ tmp=reg32_read(0x30360060);
+ tmp &= ~0x80;
+ reg32_write(0x30360060,tmp);
+ tmp=reg32_read(0x30360060);
+ tmp |= 0x200;
+ reg32_write(0x30360060,tmp);
+ tmp=reg32_read(0x30360060);
+ tmp &= ~0x20;
+ reg32_write(0x30360060,tmp);
+ tmp=reg32_read(0x30360060);
+ tmp &= ~0x10;
+ reg32_write(0x30360060,tmp);
+ do{
+ tmp=reg32_read(0x30360060);
+ if(tmp&0x80000000) break;
+ }while(1);
+ reg32_write(0x30389808,0x1000000);
//enable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
- reg32_write(0x3c150008,0x102);
- reg32_write(0x3c15000c,0x64);
+ reg32_write(0x3c150008,0x1);
+ reg32_write(0x3c15000c,0x29c);
reg32_write(0x3c150020,0x121f);
- reg32_write(0x3c150064,0x84);
+ reg32_write(0x3c150064,0x994);
reg32_write(0x3c150068,0x31);
reg32_write(0x3c15006c,0x4d46);
reg32_write(0x3c150070,0x4d08);
reg32_write(0x3c150074,0x0);
reg32_write(0x3c150078,0x15);
- reg32_write(0x3c15007c,0x84);
+ reg32_write(0x3c15007c,0x994);
reg32_write(0x3c150080,0x31);
reg32_write(0x3c150084,0x4d46);
reg32_write(0x3c150088,0x4d08);
reg32_write(0x3c15008c,0x0);
reg32_write(0x3c150090,0x15);
- reg32_write(0x3c1500c8,0x8400);
- reg32_write(0x3c1500cc,0x3100);
+ reg32_write(0x3c1500c8,0x9400);
+ reg32_write(0x3c1500cc,0x3109);
reg32_write(0x3c1500d0,0x4600);
reg32_write(0x3c1500d4,0x84d);
reg32_write(0x3c1500d8,0x4d);
reg32_write(0x3c1500dc,0x1500);
- reg32_write(0x3c1500e0,0x8400);
- reg32_write(0x3c1500e4,0x3100);
+ reg32_write(0x3c1500e0,0x9400);
+ reg32_write(0x3c1500e4,0x3109);
reg32_write(0x3c1500e8,0x4600);
reg32_write(0x3c1500ec,0x84d);
reg32_write(0x3c1500f0,0x4d);
@@ -344,7 +265,7 @@ void ddr_cfg_phy(void) {
tmp=reg32_read(0x303a00f8);
tmp |= 0x20;
reg32_write(0x303a00f8,tmp);
- reg32_write(0x30360068,0xbbe580);
+ reg32_write(0x30360068,0xece580);
tmp=reg32_read(0x30360060);
tmp &= ~0x80;
reg32_write(0x30360060,tmp);
@@ -380,28 +301,28 @@ void ddr_cfg_phy(void) {
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54012,0x310);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54019,0x2dd4);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401a,0x31);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401b,0x4d46);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401c,0x4d08);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401e,0x15);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401b,0x4a66);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401c,0x4a08);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401e,0x16);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401f,0x2dd4);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54020,0x31);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54021,0x4d46);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54022,0x4d08);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54024,0x15);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54021,0x4a66);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54022,0x4a08);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54024,0x16);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5402b,0x1000);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5402c,0x3);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54032,0xd400);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54033,0x312d);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54034,0x4600);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54035,0x84d);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54036,0x4d);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54037,0x1500);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54034,0x6600);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54035,0x84a);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54036,0x4a);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54037,0x1600);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54038,0xd400);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54039,0x312d);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403a,0x4600);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403b,0x84d);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403c,0x4d);
- reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403d,0x1500);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403a,0x6600);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403b,0x84a);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403c,0x4a);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403d,0x1600);
//disable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x1);
@@ -912,10 +833,6 @@ void ddr_cfg_phy(void) {
reg32_write(0x3c480030,0xc9);
reg32_write(0x3c480034,0x7d1);
reg32_write(0x3c480038,0x2c);
- reg32_write(0x3c88002c,0x65);
- reg32_write(0x3c880030,0xc9);
- reg32_write(0x3c880034,0x7d1);
- reg32_write(0x3c880038,0x2c);
reg32_write(0x3c240030,0x0);
reg32_write(0x3c240034,0x173);
reg32_write(0x3c240038,0x60);
@@ -928,8 +845,6 @@ void ddr_cfg_phy(void) {
reg32_write(0x3c080044,0x3);
reg32_write(0x3c480040,0x5a);
reg32_write(0x3c480044,0x3);
- reg32_write(0x3c880040,0x5a);
- reg32_write(0x3c880044,0x3);
reg32_write(0x3c100200,0xe0);
reg32_write(0x3c100204,0x12);
reg32_write(0x3c100208,0xe0);
@@ -942,12 +857,6 @@ void ddr_cfg_phy(void) {
reg32_write(0x3c50020c,0x12);
reg32_write(0x3c500210,0xe0);
reg32_write(0x3c500214,0x12);
- reg32_write(0x3c900200,0xe0);
- reg32_write(0x3c900204,0x12);
- reg32_write(0x3c900208,0xe0);
- reg32_write(0x3c90020c,0x12);
- reg32_write(0x3c900210,0xe0);
- reg32_write(0x3c900214,0x12);
reg32_write(0x3c1003f4,0xf);
reg32_write(0x3c040044,0x1);
reg32_write(0x3c040048,0x1);
diff --git a/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c b/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c
index 1ed918ee0e..438c70c87e 100644
--- a/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c
+++ b/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c
@@ -23,6 +23,7 @@
#include <asm/cache.h>
#include <asm/sections.h>
#include <asm/mmu.h>
+#include <mach/atf.h>
#include "ddr.h"
@@ -65,6 +66,26 @@ static void nxp_imx8mq_evk_sram_setup(void)
BUG_ON(ret);
}
+/*
+ * Power-on execution flow of start_nxp_imx8mq_evk() might not be
+ * obvious for a very first read, so here's, hopefully helpful,
+ * summary:
+ *
+ * 1. MaskROM uploads PBL into OCRAM and that's where this function is
+ * executed for the first time
+ *
+ * 2. DDR is initialized and full i.MX image is loaded to the
+ * beginning of RAM
+ *
+ * 3. start_nxp_imx8mq_evk, now in RAM, is executed again
+ *
+ * 4. BL31 blob is uploaded to OCRAM and the control is transfer to it
+ *
+ * 5. BL31 exits EL3 into EL2 at address MX8MQ_ATF_BL33_BASE_ADDR,
+ * executing start_nxp_imx8mq_evk() the third time
+ *
+ * 6. Standard barebox boot flow continues
+ */
ENTRY_FUNCTION(start_nxp_imx8mq_evk, r0, r1, r2)
{
arm_cpu_lowlevel_init();
@@ -72,9 +93,34 @@ ENTRY_FUNCTION(start_nxp_imx8mq_evk, r0, r1, r2)
if (IS_ENABLED(CONFIG_DEBUG_LL))
setup_uart();
- if (get_pc() < MX8MQ_DDR_CSD1_BASE_ADDR)
+ if (get_pc() < MX8MQ_DDR_CSD1_BASE_ADDR) {
+ /*
+ * We assume that we were just loaded by MaskROM into
+ * SRAM if we are not running from DDR. We also assume
+ * that means DDR needs to be initialized for the
+ * first time.
+ */
nxp_imx8mq_evk_sram_setup();
-
+ }
+ /*
+ * Straight from the power-on we are at EL3, so the following
+ * code _will_ load and jump to ATF.
+ *
+ * However when we are re-executed upon exit from ATF's
+ * initialization routine, it is EL2 which means we'll skip
+ * loadting ATF blob again
+ */
+ if (current_el() == 3) {
+ const u8 *bl31;
+ size_t bl31_size;
+
+ get_builtin_firmware(imx_imx8m_bl31_bin, &bl31, &bl31_size);
+ imx8mq_atf_load_bl31(bl31, bl31_size);
+ }
+
+ /*
+ * Standard entry we hit once we initialized both DDR and ATF
+ */
barebox_arm_entry(MX8MQ_DDR_CSD1_BASE_ADDR,
SZ_2G + SZ_1G, __dtb_imx8mq_evk_start);
}
diff --git a/arch/arm/boards/phytec-som-am335x/board.c b/arch/arm/boards/phytec-som-am335x/board.c
index 0e9bf5fdef..8c24f2b332 100644
--- a/arch/arm/boards/phytec-som-am335x/board.c
+++ b/arch/arm/boards/phytec-som-am335x/board.c
@@ -135,7 +135,7 @@ static int physom_devices_init(void)
}
}
- if (IS_ENABLED(PHYTEC_SOM_AM335X_OF_AUTOENABLE)) {
+ if (IS_ENABLED(CONFIG_PHYTEC_SOM_AM335X_OF_AUTOENABLE)) {
/* Enable NAND */
of_autoenable_device_by_path("/ocp/gpmc@50000000");
/* Enable eMMC */
diff --git a/arch/arm/boards/zii-vf610-dev/lowlevel.c b/arch/arm/boards/zii-vf610-dev/lowlevel.c
index f3d67501ab..c771d81ccf 100644
--- a/arch/arm/boards/zii-vf610-dev/lowlevel.c
+++ b/arch/arm/boards/zii-vf610-dev/lowlevel.c
@@ -43,7 +43,7 @@ enum zii_platform_vf610_type {
ZII_PLATFORM_VF610_DEV_REV_C = 0x05,
};
-unsigned int get_system_type(void)
+static unsigned int get_system_type(void)
{
#define GPIO_PDIR 0x10
@@ -111,7 +111,7 @@ ENTRY_FUNCTION(start_zii_vf610_dev, r0, r1, r2)
if (IS_ENABLED(CONFIG_DEBUG_LL)) {
relocate_to_current_adr();
setup_c();
- puts_ll("*********************************\n");
+ puts_ll("\n*********************************\n");
puts_ll("* Unknown system type: ");
puthex_ll(system_type);
puts_ll("\n* Assuming devboard revision B\n");
diff --git a/arch/arm/cpu/Makefile b/arch/arm/cpu/Makefile
index 5b4b832e82..874d723e2c 100644
--- a/arch/arm/cpu/Makefile
+++ b/arch/arm/cpu/Makefile
@@ -21,8 +21,8 @@ obj-$(CONFIG_CPU_32v7) += no-mmu.o
endif
obj-$(CONFIG_ARM_PSCI) += psci.o
-obj-$(CONFIG_ARM_SECURE_MONITOR) += smccc-call.o
-AFLAGS_smccc-call.o :=-Wa,-march=armv7-a
+obj-pbl-$(CONFIG_ARM_SMCCC) += smccc-call$(S64).o
+AFLAGS_smccc-call$(S64).o :=-Wa,-march=armv$(if $(S64),8,7)-a
obj-$(CONFIG_ARM_SECURE_MONITOR) += sm.o sm_as.o
AFLAGS_sm_as.o :=-Wa,-march=armv7-a
diff --git a/arch/arm/cpu/smccc-call_64.S b/arch/arm/cpu/smccc-call_64.S
new file mode 100644
index 0000000000..44888fb594
--- /dev/null
+++ b/arch/arm/cpu/smccc-call_64.S
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/linkage.h>
+#include <linux/arm-smccc.h>
+#include <asm/asm-offsets.h>
+
+ .macro SMCCC instr
+ .cfi_startproc
+ \instr #0
+ ldr x4, [sp]
+ stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]
+ stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS]
+ ldr x4, [sp, #8]
+ cbz x4, 1f /* no quirk structure */
+ ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS]
+ cmp x9, #ARM_SMCCC_QUIRK_QCOM_A6
+ b.ne 1f
+ str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS]
+1: ret
+ .cfi_endproc
+ .endm
+
+/*
+ * void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,
+ * unsigned long a3, unsigned long a4, unsigned long a5,
+ * unsigned long a6, unsigned long a7, struct arm_smccc_res *res,
+ * struct arm_smccc_quirk *quirk)
+ */
+ENTRY(__arm_smccc_smc)
+ SMCCC smc
+ENDPROC(__arm_smccc_smc)
+
+/*
+ * void arm_smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2,
+ * unsigned long a3, unsigned long a4, unsigned long a5,
+ * unsigned long a6, unsigned long a7, struct arm_smccc_res *res,
+ * struct arm_smccc_quirk *quirk)
+ */
+ENTRY(__arm_smccc_hvc)
+ SMCCC hvc
+ENDPROC(__arm_smccc_hvc) \ No newline at end of file
diff --git a/arch/arm/include/asm/asm-offsets.h b/arch/arm/include/asm/asm-offsets.h
new file mode 100644
index 0000000000..2f84e83996
--- /dev/null
+++ b/arch/arm/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h> \ No newline at end of file
diff --git a/arch/arm/include/asm/common.h b/arch/arm/include/asm/common.h
index 97bfdc43f5..c32cdfe5ec 100644
--- a/arch/arm/include/asm/common.h
+++ b/arch/arm/include/asm/common.h
@@ -48,7 +48,10 @@ static inline unsigned long get_sp(void)
static inline void arm_setup_stack(unsigned long top)
{
- __asm__ __volatile__("mov sp, %0" : : "r"(top));
+ __asm__ __volatile__("mov sp, %0"
+ :
+ : "r"(top)
+ : "sp");
}
#endif /* __ASM_ARM_COMMON_H */
diff --git a/arch/arm/include/asm/errata.h b/arch/arm/include/asm/errata.h
index 98137b557f..f020369916 100644
--- a/arch/arm/include/asm/errata.h
+++ b/arch/arm/include/asm/errata.h
@@ -86,3 +86,12 @@ static inline void enable_arm_errata_845369_war(void)
"mcr p15, 0, r0, c15, c0, 1\n"
);
}
+
+static inline void enable_arm_errata_cortexa8_enable_ibe(void)
+{
+ __asm__ __volatile__ (
+ "mrc p15, 0, r0, c1, c0, 1\n"
+ "orr r0, r0, #1 << 6\n"
+ "mcr p15, 0, r0, c1, c0, 1\n"
+ );
+}
diff --git a/arch/arm/lib/asm-offsets.c b/arch/arm/lib/asm-offsets.c
index 7bf6d129cf..cdff6f7821 100644
--- a/arch/arm/lib/asm-offsets.c
+++ b/arch/arm/lib/asm-offsets.c
@@ -9,8 +9,13 @@
*/
#include <linux/kbuild.h>
+#include <linux/arm-smccc.h>
int main(void)
{
- return 0;
+ DEFINE(ARM_SMCCC_RES_X0_OFFS, offsetof(struct arm_smccc_res, a0));
+ DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2));
+ DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id));
+ DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state));
+ return 0;
}
diff --git a/arch/arm/lib32/barebox.lds.S b/arch/arm/lib32/barebox.lds.S
index 594bf56837..7230e5f31f 100644
--- a/arch/arm/lib32/barebox.lds.S
+++ b/arch/arm/lib32/barebox.lds.S
@@ -106,6 +106,18 @@ SECTIONS
__usymtab : { BAREBOX_SYMS }
__usymtab_end = .;
+#ifdef CONFIG_PCI
+ __start_pci_fixups_early = .;
+ .pci_fixup_early : { KEEP(*(.pci_fixup_early)) }
+ __end_pci_fixups_early = .;
+ __start_pci_fixups_header = .;
+ .pci_fixup_header : { KEEP(*(.pci_fixup_header)) }
+ __end_pci_fixups_header = .;
+ __start_pci_fixups_enable = .;
+ .pci_fixup_enable : { KEEP(*(.pci_fixup_enable)) }
+ __end_pci_fixups_enable = .;
+#endif
+
.oftables : { BAREBOX_CLK_TABLE() }
.dtb : { BAREBOX_DTB() }
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 73b7ea1b66..7cb9138d24 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -461,6 +461,8 @@ config MACH_NXP_IMX8MQ_EVK
bool "NXP i.MX8MQ EVK Board"
select ARCH_IMX8MQ
select FIRMWARE_IMX_LPDDR4_PMU_TRAIN
+ select FIRMWARE_IMX8MQ_ATF
+ select ARM_SMCCC
endif
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 28fe60dba2..595a7512ce 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -17,7 +17,7 @@ lwl-$(CONFIG_ARCH_IMX6) += imx6-mmdc.o
obj-$(CONFIG_ARCH_IMX7) += imx7.o
obj-$(CONFIG_ARCH_VF610) += vf610.o
obj-$(CONFIG_ARCH_IMX8MQ) += imx8mq.o
-lwl-$(CONFIG_ARCH_IMX8MQ) += imx8-ddrc.o
+lwl-$(CONFIG_ARCH_IMX8MQ) += imx8-ddrc.o atf.o
obj-$(CONFIG_ARCH_IMX_XLOAD) += xload.o
obj-$(CONFIG_IMX_IIM) += iim.o
obj-$(CONFIG_NAND_IMX) += nand.o
diff --git a/arch/arm/mach-imx/atf.c b/arch/arm/mach-imx/atf.c
new file mode 100644
index 0000000000..c1b358d125
--- /dev/null
+++ b/arch/arm/mach-imx/atf.c
@@ -0,0 +1,41 @@
+#include <common.h>
+#include <mach/atf.h>
+
+/**
+ * imx8mq_atf_load_bl31 - Load ATF BL31 blob and transfer control to it
+ *
+ * @fw: Pointer to the BL31 blob
+ * @fw_size: Size of the BL31 blob
+ *
+ * This function:
+
+ * 1. Copies built-in BL31 blob to an address i.MX8M's BL31
+ * expects to be placed
+ *
+ * 2. Sets up temporary stack pointer for EL2, which is execution
+ * level that BL31 will drop us off at after it completes its
+ * initialization routine
+ *
+ * 3. Transfers control to BL31
+ *
+ * NOTE: This function expects NXP's implementation of ATF that can be
+ * found at:
+ * https://source.codeaurora.org/external/imx/imx-atf
+ *
+ * any other implementation may or may not work
+ *
+ */
+void imx8mq_atf_load_bl31(const void *fw, size_t fw_size)
+{
+ void __noreturn (*bl31)(void) = (void *)MX8MQ_ATF_BL31_BASE_ADDR;
+
+ if (WARN_ON(fw_size > MX8MQ_ATF_BL31_SIZE_LIMIT))
+ return;
+
+ memcpy(bl31, fw, fw_size);
+
+ asm volatile("msr sp_el2, %0" : :
+ "r" (MX8MQ_ATF_BL33_BASE_ADDR - 16) :
+ "cc");
+ bl31();
+} \ No newline at end of file
diff --git a/arch/arm/mach-imx/boot.c b/arch/arm/mach-imx/boot.c
index ab25f75b2a..f1fc40479d 100644
--- a/arch/arm/mach-imx/boot.c
+++ b/arch/arm/mach-imx/boot.c
@@ -28,6 +28,7 @@
#include <mach/imx6-regs.h>
#include <mach/imx7-regs.h>
#include <mach/vf610-regs.h>
+#include <mach/imx8mq.h>
static void
@@ -424,32 +425,12 @@ void imx6_boot_save_loc(void)
imx_boot_save_loc(imx6_get_boot_source);
}
-#define IMX7_SRC_SBMR1 0x58
-#define IMX7_SRC_SBMR2 0x70
+#define IMX7_BOOT_SW_INFO_POINTER_ADDR 0x000001E8
+#define IMX8M_BOOT_SW_INFO_POINTER_ADDR_A0 0x000009e8
+#define IMX8M_BOOT_SW_INFO_POINTER_ADDR_B0 0x00000968
-/*
- * Re-defined to match the naming in reference manual
- */
-#define BOOT_CFG(m, l) BOOT_CFG1(m, l)
-
-#define IMX_BOOT_SW_INFO_POINTER_ADDR 0x000001E8
#define IMX_BOOT_SW_INFO_BDT_SD 0x1
-static unsigned int imx7_bootsource_internal(uint32_t r)
-{
- return FIELD_GET(BOOT_CFG(15, 12), r);
-}
-
-static int imx7_boot_instance_spi_nor(uint32_t r)
-{
- return FIELD_GET(BOOT_CFG(11, 9), r);
-}
-
-static int imx7_boot_instance_mmc(uint32_t r)
-{
- return FIELD_GET(BOOT_CFG(11, 10), r);
-}
-
struct imx_boot_sw_info {
uint8_t reserved_1;
uint8_t boot_device_instance;
@@ -460,60 +441,26 @@ struct imx_boot_sw_info {
uint32_t reserved_3[3];
} __packed;
-void imx7_get_boot_source(enum bootsource *src, int *instance)
+static void __imx7_get_boot_source(enum bootsource *src, int *instance,
+ unsigned long boot_sw_info_pointer_addr)
{
- void __iomem *src_base = IOMEM(MX7_SRC_BASE_ADDR);
- uint32_t sbmr1 = readl(src_base + IMX7_SRC_SBMR1);
- uint32_t sbmr2 = readl(src_base + IMX7_SRC_SBMR2);
+ const struct imx_boot_sw_info *info;
- if (imx6_bootsource_reserved(sbmr2))
- return;
+ info = (const void *)(unsigned long)
+ readl(boot_sw_info_pointer_addr);
- if (imx6_bootsource_serial(sbmr2)) {
- /*
- * On i.MX7 ROM code will try to bood from uSDHC1
- * before entering serial mode. It doesn't seem to be
- * reflected in the contents of SBMR1 in any way when
- * that happens, so we check "Boot_SW_Info" structure
- * (per 6.6.14 Boot information for software) to see
- * if that really happened.
- *
- * FIXME: This behaviour can be inhibited by
- * DISABLE_SDMMC_MFG, but location of that fuse
- * doesn't seem to be documented anywhere. Once that
- * is known it should be taken into account here.
- */
- const struct imx_boot_sw_info *info;
-
- info = (const void *)(unsigned long)
- readl(IMX_BOOT_SW_INFO_POINTER_ADDR);
-
- if (info->boot_device_type == IMX_BOOT_SW_INFO_BDT_SD) {
- *src = BOOTSOURCE_MMC;
- /*
- * We are expecting to only ever boot from
- * uSDHC1 here
- */
- WARN_ON(*instance = info->boot_device_instance);
- return;
- }
-
- *src = BOOTSOURCE_SERIAL;
- return;
- }
-
- switch (imx7_bootsource_internal(sbmr1)) {
+ switch (info->boot_device_type) {
case 1:
case 2:
*src = BOOTSOURCE_MMC;
- *instance = imx7_boot_instance_mmc(sbmr1);
+ *instance = info->boot_device_instance;
break;
case 3:
*src = BOOTSOURCE_NAND;
break;
case 6:
- *src = BOOTSOURCE_SPI_NOR,
- *instance = imx7_boot_instance_spi_nor(sbmr1);
+ *src = BOOTSOURCE_SPI_NOR;
+ *instance = info->boot_device_instance;
break;
case 4:
*src = BOOTSOURCE_SPI; /* Really: qspi */
@@ -526,6 +473,11 @@ void imx7_get_boot_source(enum bootsource *src, int *instance)
}
}
+void imx7_get_boot_source(enum bootsource *src, int *instance)
+{
+ __imx7_get_boot_source(src, instance, IMX7_BOOT_SW_INFO_POINTER_ADDR);
+}
+
void imx7_boot_save_loc(void)
{
imx_boot_save_loc(imx7_get_boot_source);
@@ -626,6 +578,17 @@ void vf610_boot_save_loc(void)
}
void imx8_get_boot_source(enum bootsource *src, int *instance)
- __alias(imx7_get_boot_source);
+{
+ unsigned long addr;
+
+ addr = (imx8mq_cpu_revision() == IMX_CHIP_REV_1_0) ?
+ IMX8M_BOOT_SW_INFO_POINTER_ADDR_A0 :
+ IMX8M_BOOT_SW_INFO_POINTER_ADDR_B0;
-void imx8_boot_save_loc(void) __alias(imx7_boot_save_loc);
+ __imx7_get_boot_source(src, instance, addr);
+}
+
+void imx8_boot_save_loc(void)
+{
+ imx_boot_save_loc(imx8_get_boot_source);
+}
diff --git a/arch/arm/mach-imx/cpu_init.c b/arch/arm/mach-imx/cpu_init.c
index 5b93d12da9..dfbd5ba6c1 100644
--- a/arch/arm/mach-imx/cpu_init.c
+++ b/arch/arm/mach-imx/cpu_init.c
@@ -22,6 +22,7 @@ void imx5_cpu_lowlevel_init(void)
arm_cpu_lowlevel_init();
enable_arm_errata_709718_war();
+ enable_arm_errata_cortexa8_enable_ibe();
}
void imx6_cpu_lowlevel_init(void)
@@ -51,4 +52,4 @@ void vf610_cpu_lowlevel_init(void)
{
arm_cpu_lowlevel_init();
}
-#endif \ No newline at end of file
+#endif
diff --git a/arch/arm/mach-imx/imx.c b/arch/arm/mach-imx/imx.c
index 6fe53f3140..ad227663dd 100644
--- a/arch/arm/mach-imx/imx.c
+++ b/arch/arm/mach-imx/imx.c
@@ -157,6 +157,17 @@ static int imx_init(void)
}
postcore_initcall(imx_init);
+const struct imx_reset_reason imx7_reset_reasons[] = {
+ { IMX_SRC_SRSR_IPP_RESET, RESET_POR, 0 },
+ { IMX_SRC_SRSR_WDOG1_RESET, RESET_WDG, 0 },
+ { IMX_SRC_SRSR_JTAG_RESET, RESET_JTAG, 0 },
+ { IMX_SRC_SRSR_JTAG_SW_RESET, RESET_JTAG, 0 },
+ { IMX_SRC_SRSR_WDOG3_RESET, RESET_WDG, 1 },
+ { IMX_SRC_SRSR_WDOG4_RESET, RESET_WDG, 2 },
+ { IMX_SRC_SRSR_TEMPSENSE_RESET, RESET_THERM, 0 },
+ { /* sentinel */ }
+};
+
const struct imx_reset_reason imx_reset_reasons[] = {
{ IMX_SRC_SRSR_IPP_RESET, RESET_POR, 0 },
{ IMX_SRC_SRSR_WDOG1_RESET, RESET_WDG, 0 },
diff --git a/arch/arm/mach-imx/imx7.c b/arch/arm/mach-imx/imx7.c
index e49baf6f77..ca11e83456 100644
--- a/arch/arm/mach-imx/imx7.c
+++ b/arch/arm/mach-imx/imx7.c
@@ -168,17 +168,6 @@ static struct psci_ops imx7_psci_ops = {
.cpu_off = imx7_cpu_off,
};
-static const struct imx_reset_reason imx7_reset_reasons[] = {
- { IMX_SRC_SRSR_IPP_RESET, RESET_POR, 0 },
- { IMX_SRC_SRSR_WDOG1_RESET, RESET_WDG, 0 },
- { IMX_SRC_SRSR_JTAG_RESET, RESET_JTAG, 0 },
- { IMX_SRC_SRSR_JTAG_SW_RESET, RESET_JTAG, 0 },
- { IMX_SRC_SRSR_WDOG3_RESET, RESET_WDG, 1 },
- { IMX_SRC_SRSR_WDOG4_RESET, RESET_WDG, 2 },
- { IMX_SRC_SRSR_TEMPSENSE_RESET, RESET_THERM, 0 },
- { /* sentinel */ }
-};
-
int imx7_init(void)
{
const char *cputypestr;
diff --git a/arch/arm/mach-imx/imx8mq.c b/arch/arm/mach-imx/imx8mq.c
index f3246e4373..4d00da5f0d 100644
--- a/arch/arm/mach-imx/imx8mq.c
+++ b/arch/arm/mach-imx/imx8mq.c
@@ -18,38 +18,46 @@
#include <asm/system.h>
#include <mach/generic.h>
#include <mach/revision.h>
-#include <mach/imx8mq-regs.h>
+#include <mach/imx8mq.h>
+#include <mach/reset-reason.h>
-#define IMX8MQ_ROM_VERSION_A0 0x800
-#define IMX8MQ_ROM_VERSION_B0 0x83C
+#include <linux/arm-smccc.h>
-#define MX8MQ_ANATOP_DIGPROG 0x6c
+#define FSL_SIP_BUILDINFO 0xC2000003
+#define FSL_SIP_BUILDINFO_GET_COMMITHASH 0x00
-static void imx8mq_silicon_revision(void)
+static int imx8mq_init_syscnt_frequency(void)
{
- void __iomem *anatop = IOMEM(MX8MQ_ANATOP_BASE_ADDR);
- uint32_t reg = readl(anatop + MX8MQ_ANATOP_DIGPROG);
- uint32_t type = (reg >> 16) & 0xff;
- uint32_t rom_version;
- const char *cputypestr;
-
- reg &= 0xff;
-
- if (reg == IMX_CHIP_REV_1_0) {
+ if (current_el() == 3) {
+ void __iomem *syscnt = IOMEM(MX8MQ_SYSCNT_CTRL_BASE_ADDR);
/*
- * For B0 chip, the DIGPROG is not updated, still TO1.0.
- * we have to check ROM version further
+ * Update with accurate clock frequency
*/
- rom_version = readl(IOMEM(IMX8MQ_ROM_VERSION_A0));
- if (rom_version != IMX_CHIP_REV_1_0) {
- rom_version = readl(IOMEM(IMX8MQ_ROM_VERSION_B0));
- if (rom_version >= IMX_CHIP_REV_2_0)
- reg = IMX_CHIP_REV_2_0;
- }
+ set_cntfrq(syscnt_get_cntfrq(syscnt));
+ syscnt_enable(syscnt);
}
+ return 0;
+}
+/*
+ * This call needs to happen before timer driver gets probed and
+ * requests its update frequency via cntfrq_el0
+ */
+core_initcall(imx8mq_init_syscnt_frequency);
+
+int imx8mq_init(void)
+{
+ void __iomem *anatop = IOMEM(MX8MQ_ANATOP_BASE_ADDR);
+ void __iomem *src = IOMEM(MX8MQ_SRC_BASE_ADDR);
+ uint32_t type = FIELD_GET(DIGPROG_MAJOR,
+ readl(anatop + MX8MQ_ANATOP_DIGPROG));
+ struct arm_smccc_res res;
+ const char *cputypestr;
+
+ imx8_boot_save_loc();
+
switch (type) {
- case 0x82:
+ case IMX8M_CPUTYPE_IMX8MQ:
cputypestr = "i.MX8MQ";
break;
default:
@@ -57,29 +65,19 @@ static void imx8mq_silicon_revision(void)
break;
};
- imx_set_silicon_revision(cputypestr, reg);
-}
-
-static int imx8mq_init_syscnt_frequency(void)
-{
- void __iomem *syscnt = IOMEM(MX8MQ_SYSCNT_CTRL_BASE_ADDR);
+ imx_set_silicon_revision(cputypestr, imx8mq_cpu_revision());
/*
- * Update with accurate clock frequency
+ * Reset reasons seem to be identical to that of i.MX7
*/
- set_cntfrq(syscnt_get_cntfrq(syscnt));
- syscnt_enable(syscnt);
+ imx_set_reset_reason(src + IMX7_SRC_SRSR, imx7_reset_reasons);
- return 0;
-}
-/*
- * This call needs to happen before timer driver gets probed and
- * requests its update frequency via cntfrq_el0
- */
-core_initcall(imx8mq_init_syscnt_frequency);
-
-int imx8mq_init(void)
-{
- imx8mq_silicon_revision();
+ if (IS_ENABLED(CONFIG_ARM_SMCCC) &&
+ IS_ENABLED(CONFIG_FIRMWARE_IMX8MQ_ATF)) {
+ arm_smccc_smc(FSL_SIP_BUILDINFO,
+ FSL_SIP_BUILDINFO_GET_COMMITHASH,
+ 0, 0, 0, 0, 0, 0, &res);
+ pr_info("i.MX ARM Trusted Firmware: %s\n", (char *)&res.a0);
+ }
return 0;
}
diff --git a/arch/arm/mach-imx/include/mach/atf.h b/arch/arm/mach-imx/include/mach/atf.h
new file mode 100644
index 0000000000..aeb24bad00
--- /dev/null
+++ b/arch/arm/mach-imx/include/mach/atf.h
@@ -0,0 +1,13 @@
+#ifndef __IMX_ATF_H__
+#define __IMX_ATF_H__
+
+#include <linux/sizes.h>
+#include <asm/system.h>
+
+#define MX8MQ_ATF_BL31_SIZE_LIMIT SZ_64K
+#define MX8MQ_ATF_BL31_BASE_ADDR 0x00910000
+#define MX8MQ_ATF_BL33_BASE_ADDR 0x40200000
+
+void imx8mq_atf_load_bl31(const void *fw, size_t fw_size);
+
+#endif \ No newline at end of file
diff --git a/arch/arm/mach-imx/include/mach/imx-header.h b/arch/arm/mach-imx/include/mach/imx-header.h
new file mode 100644
index 0000000000..c9b2a58819
--- /dev/null
+++ b/arch/arm/mach-imx/include/mach/imx-header.h
@@ -0,0 +1,128 @@
+#ifndef __IMX_HEADER_H__
+#define __IMX_HEADER_H__
+
+#include <linux/types.h>
+
+#define HEADER_LEN 0x1000 /* length of the blank area + IVT + DCD */
+
+/*
+ * ============================================================================
+ * i.MX flash header v1 handling. Found on i.MX35 and i.MX51
+ * ============================================================================
+ */
+#define DCD_BARKER 0xb17219e9
+
+struct imx_flash_header {
+ uint32_t app_code_jump_vector;
+ uint32_t app_code_barker;
+ uint32_t app_code_csf;
+ uint32_t dcd_ptr_ptr;
+ uint32_t super_root_key;
+ uint32_t dcd;
+ uint32_t app_dest;
+ uint32_t dcd_barker;
+ uint32_t dcd_block_len;
+} __attribute__((packed));
+
+struct imx_boot_data {
+ uint32_t start;
+ uint32_t size;
+ uint32_t plugin;
+} __attribute__((packed));
+
+struct imx_dcd_rec_v1 {
+ uint32_t type;
+ uint32_t addr;
+ uint32_t val;
+} __attribute__((packed));
+
+#define TAG_IVT_HEADER 0xd1
+#define IVT_VERSION 0x40
+#define TAG_DCD_HEADER 0xd2
+#define DCD_VERSION 0x40
+#define TAG_UNLOCK 0xb2
+#define TAG_NOP 0xc0
+#define TAG_WRITE 0xcc
+#define TAG_CHECK 0xcf
+#define PARAMETER_FLAG_MASK (1 << 3)
+#define PARAMETER_FLAG_SET (1 << 4)
+
+struct imx_ivt_header {
+ uint8_t tag;
+ uint16_t length;
+ uint8_t version;
+} __attribute__((packed));
+
+struct imx_flash_header_v2 {
+ struct imx_ivt_header header;
+
+ uint32_t entry;
+ uint32_t reserved1;
+ uint32_t dcd_ptr;
+ uint32_t boot_data_ptr;
+ uint32_t self;
+ uint32_t csf;
+ uint32_t reserved2;
+
+ struct imx_boot_data boot_data;
+ struct imx_ivt_header dcd_header;
+} __attribute__((packed));
+
+static inline bool is_imx_flash_header_v2(const void *blob)
+{
+ const struct imx_flash_header_v2 *hdr = blob;
+
+ return hdr->header.tag == TAG_IVT_HEADER &&
+ hdr->header.version >= IVT_VERSION;
+}
+
+struct config_data {
+ uint32_t image_load_addr;
+ uint32_t image_dcd_offset;
+ uint32_t image_size;
+ uint32_t load_size;
+ char *outfile;
+ char *srkfile;
+ int header_version;
+ off_t header_gap;
+ uint32_t first_opcode;
+ int cpu_type;
+ int (*check)(const struct config_data *data, uint32_t cmd,
+ uint32_t addr, uint32_t mask);
+ int (*write_mem)(const struct config_data *data, uint32_t addr,
+ uint32_t val, int width, int set_bits, int clear_bits);
+ int (*nop)(const struct config_data *data);
+ int csf_space;
+ char *csf;
+};
+
+#define MAX_RECORDS_DCD_V2 1024
+struct imx_dcd_v2_write_rec {
+ uint32_t addr;
+ uint32_t val;
+} __attribute__((packed));
+
+struct imx_dcd_v2_write {
+ uint8_t tag;
+ uint16_t length;
+ uint8_t param;
+ struct imx_dcd_v2_write_rec data[MAX_RECORDS_DCD_V2];
+} __attribute__((packed));
+
+struct imx_dcd_v2_check {
+ uint8_t tag;
+ uint16_t length;
+ uint8_t param;
+ uint32_t addr;
+ uint32_t mask;
+ uint32_t count;
+} __attribute__((packed));
+
+enum imx_dcd_v2_check_cond {
+ until_all_bits_clear = 0, /* until ((*address & mask) == 0) { ...} */
+ until_any_bit_clear = 1, /* until ((*address & mask) != mask) { ...} */
+ until_all_bits_set = 2, /* until ((*address & mask) == mask) { ...} */
+ until_any_bit_set = 3, /* until ((*address & mask) != 0) { ...} */
+} __attribute__((packed));
+
+#endif
diff --git a/arch/arm/mach-imx/include/mach/imx8mq.h b/arch/arm/mach-imx/include/mach/imx8mq.h
new file mode 100644
index 0000000000..f4a537d2b1
--- /dev/null
+++ b/arch/arm/mach-imx/include/mach/imx8mq.h
@@ -0,0 +1,43 @@
+#ifndef __MACH_IMX8MQ_H
+#define __MACH_IMX8MQ_H
+
+#include <io.h>
+#include <mach/generic.h>
+#include <mach/imx8mq-regs.h>
+#include <mach/revision.h>
+#include <linux/bitfield.h>
+
+#define IMX8MQ_ROM_VERSION_A0 0x800
+#define IMX8MQ_ROM_VERSION_B0 0x83C
+
+#define MX8MQ_ANATOP_DIGPROG 0x6c
+
+#define DIGPROG_MAJOR GENMASK(23, 8)
+#define DIGPROG_MINOR GENMASK(7, 0)
+
+#define IMX8M_CPUTYPE_IMX8MQ 0x8240
+
+static inline int imx8mq_cpu_revision(void)
+{
+ void __iomem *anatop = IOMEM(MX8MQ_ANATOP_BASE_ADDR);
+ uint32_t revision = FIELD_GET(DIGPROG_MINOR,
+ readl(anatop + MX8MQ_ANATOP_DIGPROG));
+
+ if (revision == IMX_CHIP_REV_1_0) {
+ uint32_t rom_version;
+ /*
+ * For B0 chip, the DIGPROG is not updated, still TO1.0.
+ * we have to check ROM version further
+ */
+ rom_version = readl(IOMEM(IMX8MQ_ROM_VERSION_A0));
+ if (rom_version != IMX_CHIP_REV_1_0) {
+ rom_version = readl(IOMEM(IMX8MQ_ROM_VERSION_B0));
+ if (rom_version >= IMX_CHIP_REV_2_0)
+ revision = IMX_CHIP_REV_2_0;
+ }
+ }
+
+ return revision;
+}
+
+#endif /* __MACH_IMX8_H */ \ No newline at end of file
diff --git a/arch/arm/mach-imx/include/mach/ocotp.h b/arch/arm/mach-imx/include/mach/ocotp.h
index 76a6da53de..e758238cb9 100644
--- a/arch/arm/mach-imx/include/mach/ocotp.h
+++ b/arch/arm/mach-imx/include/mach/ocotp.h
@@ -2,6 +2,7 @@
#define __MACH_IMX_OCOTP_H
#include <linux/bitfield.h>
+#include <linux/types.h>
#define OCOTP_SHADOW_OFFSET 0x400
#define OCOTP_SHADOW_SPACING 0x10
diff --git a/arch/arm/mach-imx/include/mach/reset-reason.h b/arch/arm/mach-imx/include/mach/reset-reason.h
index 0f644a8c1d..91a8171896 100644
--- a/arch/arm/mach-imx/include/mach/reset-reason.h
+++ b/arch/arm/mach-imx/include/mach/reset-reason.h
@@ -33,5 +33,6 @@ struct imx_reset_reason {
void imx_set_reset_reason(void __iomem *, const struct imx_reset_reason *);
extern const struct imx_reset_reason imx_reset_reasons[];
+extern const struct imx_reset_reason imx7_reset_reasons[];
#endif /* __MACH_RESET_REASON_H__ */
diff --git a/arch/arm/mach-imx/xload-esdhc.c b/arch/arm/mach-imx/xload-esdhc.c
index 08ba9b08dc..55d6c69299 100644
--- a/arch/arm/mach-imx/xload-esdhc.c
+++ b/arch/arm/mach-imx/xload-esdhc.c
@@ -14,10 +14,12 @@
#include <common.h>
#include <io.h>
#include <mci.h>
+#include <mach/atf.h>
#include <mach/imx6-regs.h>
#include <mach/imx8mq-regs.h>
#include <mach/xload.h>
#include <linux/sizes.h>
+#include <mach/imx-header.h>
#include "../../../drivers/mci/sdhci.h"
#include "../../../drivers/mci/imx-esdhc.h"
@@ -218,10 +220,11 @@ static int esdhc_read_blocks(struct esdhc *esdhc, void *dst, size_t len)
}
static int
-esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, u32 offset)
+esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, ptrdiff_t entry, u32 offset)
{
+
void *buf = (void *)address;
- u32 *ivt = buf + offset + SZ_1K;
+ struct imx_flash_header_v2 *hdr = buf + offset + SZ_1K;
int ret, len;
void __noreturn (*bb)(void);
unsigned int ofs;
@@ -233,14 +236,45 @@ esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, u32 offset)
if (ret)
return ret;
- if (*(u32 *)(ivt) != 0x402000d1) {
- pr_debug("IVT header not found on SD card. Found 0x%08x instead of 0x402000d1\n",
- *ivt);
+ if (!is_imx_flash_header_v2(hdr)) {
+ pr_debug("IVT header not found on SD card. "
+ "Found tag: 0x%02x length: 0x%04x version: %02x\n",
+ hdr->header.tag, hdr->header.length,
+ hdr->header.version);
return -EINVAL;
}
pr_debug("Check ok, loading image\n");
+ ofs = offset + hdr->entry - hdr->boot_data.start;
+
+ if (entry != address) {
+ /*
+ * Passing entry different from address is interpreted
+ * as a request to place the image such that its entry
+ * point would be exactly at 'entry', that is:
+ *
+ * buf + ofs = entry
+ *
+ * solving the above for 'buf' gvies us the
+ * adjustement that needs to be made:
+ *
+ * buf = entry - ofs
+ *
+ */
+ if (WARN_ON(entry - ofs < address)) {
+ /*
+ * We want to make sure we won't try to place
+ * the start of the image before the beginning
+ * of the memory buffer we were given in
+ * address.
+ */
+ return -EINVAL;
+ }
+
+ buf = (void *)(entry - ofs);
+ }
+
ret = esdhc_read_blocks(esdhc, buf, offset + len);
if (ret) {
pr_err("Loading image failed with %d\n", ret);
@@ -249,8 +283,6 @@ esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, u32 offset)
pr_debug("Image loaded successfully\n");
- ofs = offset + *(ivt + 1) - *(ivt + 8);
-
bb = buf + ofs;
bb();
@@ -291,7 +323,7 @@ int imx6_esdhc_start_image(int instance)
esdhc.is_mx6 = 1;
- return esdhc_start_image(&esdhc, 0x10000000, 0);
+ return esdhc_start_image(&esdhc, 0x10000000, 0x10000000, 0);
}
/**
@@ -323,5 +355,6 @@ int imx8_esdhc_start_image(int instance)
esdhc.is_mx6 = 1;
- return esdhc_start_image(&esdhc, MX8MQ_DDR_CSD1_BASE_ADDR, SZ_32K);
+ return esdhc_start_image(&esdhc, MX8MQ_DDR_CSD1_BASE_ADDR,
+ MX8MQ_ATF_BL33_BASE_ADDR, SZ_32K);
} \ No newline at end of file
diff --git a/commands/memset.c b/commands/memset.c
index f871e07c95..f99bf86c04 100644
--- a/commands/memset.c
+++ b/commands/memset.c
@@ -56,7 +56,7 @@ static int do_memset(int argc, char *argv[])
c = strtoull_suffix(argv[optind + 1], NULL, 0);
n = strtoull_suffix(argv[optind + 2], NULL, 0);
- fd = open_and_lseek(file, mode | O_WRONLY, s);
+ fd = open_and_lseek(file, mode | O_WRONLY | O_CREAT, s);
if (fd < 0)
return 1;
diff --git a/commands/mm.c b/commands/mm.c
index 6d2a887892..c7f62fca54 100644
--- a/commands/mm.c
+++ b/commands/mm.c
@@ -53,7 +53,7 @@ static int do_mem_mm(int argc, char *argv[])
value = simple_strtoull(argv[optind++], NULL, 0);
mask = simple_strtoull(argv[optind++], NULL, 0);
- fd = open_and_lseek(filename, mode | O_RDWR, adr);
+ fd = open_and_lseek(filename, mode | O_RDWR | O_CREAT, adr);
if (fd < 0)
return 1;
diff --git a/commands/mw.c b/commands/mw.c
index 7ff589abb1..2912997a31 100644
--- a/commands/mw.c
+++ b/commands/mw.c
@@ -52,7 +52,7 @@ static int do_mem_mw(int argc, char *argv[])
adr = strtoull_suffix(argv[optind++], NULL, 0);
- fd = open_and_lseek(filename, mode | O_WRONLY, adr);
+ fd = open_and_lseek(filename, mode | O_WRONLY | O_CREAT, adr);
if (fd < 0)
return 1;
diff --git a/commands/of_node.c b/commands/of_node.c
index 29cc371dd2..28c4357c5d 100644
--- a/commands/of_node.c
+++ b/commands/of_node.c
@@ -107,11 +107,10 @@ static int do_of_node(int argc, char *argv[])
}
}
- if (optind == argc)
+ if (optind + 1 != argc)
return COMMAND_ERROR_USAGE;
- if (optind < argc)
- path = argv[optind];
+ path = argv[optind];
if (!path)
return COMMAND_ERROR_USAGE;
@@ -147,7 +146,7 @@ BAREBOX_CMD_HELP_END
BAREBOX_CMD_START(of_node)
.cmd = do_of_node,
BAREBOX_CMD_DESC("create/delete nodes in the device tree")
- BAREBOX_CMD_OPTS("[-cd] [-f] NODE NAME")
+ BAREBOX_CMD_OPTS("[-cd] [-f] NODEPATH")
BAREBOX_CMD_GROUP(CMD_GRP_MISC)
BAREBOX_CMD_COMPLETE(devicetree_complete)
BAREBOX_CMD_HELP(cmd_of_node_help)
diff --git a/common/block.c b/common/block.c
index 55d8d1637e..219b943afc 100644
--- a/common/block.c
+++ b/common/block.c
@@ -36,7 +36,7 @@ struct chunk {
struct list_head list;
};
-#define BUFSIZE (PAGE_SIZE * 16)
+#define BUFSIZE (PAGE_SIZE * 4)
/*
* Write all dirty chunks back to the device
@@ -361,7 +361,7 @@ int blockdevice_register(struct block_device *blk)
debug("%s: rdbufsize: %d blockbits: %d blkmask: 0x%08x\n", __func__, blk->rdbufsize, blk->blockbits,
blk->blkmask);
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < 32; i++) {
struct chunk *chunk = xzalloc(sizeof(*chunk));
chunk->data = dma_alloc(BUFSIZE);
chunk->num = i;
diff --git a/common/image-fit.c b/common/image-fit.c
index 6cbf23250d..dfd1fa02c9 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -289,11 +289,12 @@ static int fit_check_rsa_signature(struct device_node *sig_node,
}
key_path = xasprintf("/signature/key-%s", key_name);
key_node = of_find_node_by_path(key_path);
- free(key_path);
if (!key_node) {
- pr_info("failed to find key node\n");
+ pr_info("failed to find key node %s\n", key_path);
+ free(key_path);
return -ENOENT;
}
+ free(key_path);
ret = rsa_of_read_key(key_node, &key);
if (ret) {
diff --git a/drivers/aiodev/Kconfig b/drivers/aiodev/Kconfig
index 8bad946920..3eabd3b3ff 100644
--- a/drivers/aiodev/Kconfig
+++ b/drivers/aiodev/Kconfig
@@ -7,10 +7,12 @@ menuconfig AIODEV
if AIODEV
config IMX_THERMAL
- tristate "Temperature sensor driver for Freescale i.MX SoCs"
- depends on ARCH_IMX6
- select MFD_SYSCON
- help
+ tristate "Temperature sensor driver for Freescale i.MX SoCs"
+ depends on ARCH_IMX6
+ select MFD_SYSCON
+ select NVMEM
+ select IMX_OCOTP
+ help
Support for Temperature Monitor (TEMPMON) found on Freescale
i.MX SoCs.
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 4ff4f5c2aa..67937da73a 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -200,13 +200,13 @@ static void i2c_fsl_dump_reg(struct i2c_adapter *adapter)
reg_cr = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR);
reg_sr = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2SR);
- dev_dbg(adapter->dev, "CONTROL:\t"
+ dev_dbg(&adapter->dev, "CONTROL:\t"
"IEN =%d, IIEN=%d, MSTA=%d, MTX =%d, TXAK=%d, RSTA=%d\n",
(reg_cr & I2CR_IEN ? 1 : 0), (reg_cr & I2CR_IIEN ? 1 : 0),
(reg_cr & I2CR_MSTA ? 1 : 0), (reg_cr & I2CR_MTX ? 1 : 0),
(reg_cr & I2CR_TXAK ? 1 : 0), (reg_cr & I2CR_RSTA ? 1 : 0));
- dev_dbg(adapter->dev, "STATUS:\t"
+ dev_dbg(&adapter->dev, "STATUS:\t"
"ICF =%d, IAAS=%d, IB =%d, IAL =%d, SRW =%d, IIF =%d, RXAK=%d\n",
(reg_sr & I2SR_ICF ? 1 : 0), (reg_sr & I2SR_IAAS ? 1 : 0),
(reg_sr & I2SR_IBB ? 1 : 0), (reg_sr & I2SR_IAL ? 1 : 0),
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index c4daa9d121..db96a81397 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -455,10 +455,13 @@ static void set_sysctl(struct mci_host *mci, u32 clock)
wait_on_timeout(10 * MSECOND,
esdhc_read32(regs + SDHCI_PRESENT_STATE) & PRSSTAT_SDSTB);
- clk = SYSCTL_PEREN | SYSCTL_CKEN;
+ clk = SYSCTL_PEREN | SYSCTL_CKEN | SYSCTL_INITA;
esdhc_setbits32(regs + SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET,
clk);
+
+ wait_on_timeout(1 * MSECOND,
+ !(esdhc_read32(regs + SDHCI_CLOCK_CONTROL) & SYSCTL_INITA));
}
static void esdhc_set_ios(struct mci_host *mci, struct mci_ios *ios)
diff --git a/drivers/mci/s3c.c b/drivers/mci/s3c.c
index 86a83b63fa..489609712c 100644
--- a/drivers/mci/s3c.c
+++ b/drivers/mci/s3c.c
@@ -755,7 +755,7 @@ static int s3c_mci_probe(struct device_d *hw_dev)
s3c_host->host.f_min = pd->f_min == 0 ? s3c_get_pclk() / 256 : pd->f_min;
s3c_host->host.f_max = pd->f_max == 0 ? s3c_get_pclk() / 2 : pd->f_max;
- if (IS_ENABLED(iCONFIG_MCI_INFO))
+ if (IS_ENABLED(CONFIG_MCI_INFO))
hw_dev->info = s3c_info;
/*
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index 3f39db7164..dda022e054 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -3,6 +3,8 @@
#include <malloc.h>
#include <linux/math64.h>
#include <linux/sizes.h>
+#include <of_device.h>
+#include <linux/pci.h>
#include <linux/mtd/spi-nor.h>
#include "e1000.h"
@@ -405,6 +407,45 @@ static void e1000_eeprom_uses_microwire(struct e1000_eeprom_info *eeprom,
eeprom->read = e1000_read_eeprom_microwire;
}
+size_t e1000_igb_get_flash_size(struct e1000_hw *hw)
+{
+ struct device_node *node =
+ hw->pdev->dev.device_node;
+ u32 flash_size;
+ uint32_t fla;
+ int ret = 0;
+
+ /*
+ * There are two potential places where the size of the flash can be
+ * specified. In the device tree, and in the flash itself. Use the
+ * first that looks valid.
+ */
+
+ ret = of_property_read_u32(node, "flash-size", &flash_size);
+ if (ret == 0) {
+ dev_info(hw->dev,
+ "Determined flash size from device tree (%u)\n",
+ flash_size);
+ return flash_size;
+ }
+
+ fla = e1000_read_reg(hw, E1000_FLA);
+ fla &= E1000_FLA_FL_SIZE_MASK;
+ fla >>= E1000_FLA_FL_SIZE_SHIFT;
+
+ if (fla) {
+ flash_size = SZ_64K << fla;
+ dev_info(hw->dev,
+ "Determined flash size from E1000_FLA.FL_SIZE (%u)\n",
+ flash_size);
+ return flash_size;
+ }
+
+ dev_info(hw->dev,
+ "Unprogrammed Flash detected and no flash-size found in device tree, limiting access to first 4 kiB\n");
+
+ return 4096;
+}
/******************************************************************************
* Sets up eeprom variables in the hw struct. Must be called after mac_type
@@ -480,20 +521,7 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
case e1000_igb:
if (eecd & E1000_EECD_I210_FLASH_DETECTED) {
- uint32_t fla;
-
- fla = e1000_read_reg(hw, E1000_FLA);
- fla &= E1000_FLA_FL_SIZE_MASK;
- fla >>= E1000_FLA_FL_SIZE_SHIFT;
-
- if (fla) {
- eeprom->word_size = (SZ_64K << fla) / 2;
- } else {
- eeprom->word_size = 2048;
- dev_info(hw->dev, "Unprogrammed Flash detected, "
- "limiting access to first 4KB\n");
- }
-
+ eeprom->word_size = e1000_igb_get_flash_size(hw) / 2;
eeprom->acquire = e1000_acquire_eeprom_flash;
eeprom->release = e1000_release_eeprom_flash;
}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index b2570eb151..d206c53848 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -253,6 +253,8 @@ static void setup_device(struct pci_dev *dev, int max_bar)
}
}
+ pci_fixup_device(pci_fixup_header, dev);
+
pci_write_config_byte(dev, PCI_COMMAND, cmd);
list_add_tail(&dev->bus_list, &dev->bus->devices);
}
@@ -331,6 +333,31 @@ static void postscan_setup_bridge(struct pci_dev *dev)
}
}
+static struct device_node *
+pci_of_match_device(struct device_d *parent, unsigned int devfn)
+{
+ struct device_node *np;
+ u32 reg;
+
+ if (!IS_ENABLED(CONFIG_OFTREE) || !parent->device_node)
+ return NULL;
+
+ for_each_child_of_node(parent->device_node, np) {
+ if (!of_property_read_u32_array(np, "reg", &reg, 1)) {
+ /*
+ * Only match device/function pair of the device
+ * address, other properties are defined by the
+ * PCI/OF node topology.
+ */
+ reg = (reg >> 8) & 0xffff;
+ if (reg == devfn)
+ return np;
+ }
+ }
+
+ return NULL;
+}
+
unsigned int pci_scan_bus(struct pci_bus *bus)
{
struct pci_dev *dev;
@@ -368,6 +395,11 @@ unsigned int pci_scan_bus(struct pci_bus *bus)
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;
dev->dev.parent = bus->parent;
+ dev->dev.device_node = pci_of_match_device(bus->parent, devfn);
+ if (dev->dev.device_node)
+ pr_debug("found DT node %s for device %04x:%04x\n",
+ dev->dev.device_node->full_name,
+ dev->vendor, dev->device);
/* non-destructively determine if device can be a master: */
pci_read_config_byte(dev, PCI_COMMAND, &cmd);
@@ -382,6 +414,10 @@ unsigned int pci_scan_bus(struct pci_bus *bus)
class >>= 8;
dev->hdr_type = hdr_type;
+ pci_fixup_device(pci_fixup_early, dev);
+ /* the fixup may have changed the device class */
+ class = dev->class >> 8;
+
pr_debug("class = %08x, hdr_type = %08x\n", class, hdr_type);
pr_debug("%02x:%02x [%04x:%04x]\n", bus->number, dev->devfn,
dev->vendor, dev->device);
@@ -489,12 +525,61 @@ EXPORT_SYMBOL(pci_clear_master);
*/
int pci_enable_device(struct pci_dev *dev)
{
+ int ret;
u32 t;
pci_read_config_dword(dev, PCI_COMMAND, &t);
- return pci_write_config_dword(dev, PCI_COMMAND, t
- | PCI_COMMAND_IO
- | PCI_COMMAND_MEMORY
- );
+ ret = pci_write_config_dword(dev, PCI_COMMAND,
+ t | PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+ if (ret)
+ return ret;
+
+ pci_fixup_device(pci_fixup_enable, dev);
+
+ return 0;
}
EXPORT_SYMBOL(pci_enable_device);
+
+static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
+ struct pci_fixup *end)
+{
+ for (; f < end; f++)
+ if ((f->class == (u32) (dev->class >> f->class_shift) ||
+ f->class == (u32) PCI_ANY_ID) &&
+ (f->vendor == dev->vendor ||
+ f->vendor == (u16) PCI_ANY_ID) &&
+ (f->device == dev->device ||
+ f->device == (u16) PCI_ANY_ID)) {
+ f->hook(dev);
+ }
+}
+
+extern struct pci_fixup __start_pci_fixups_early[];
+extern struct pci_fixup __end_pci_fixups_early[];
+extern struct pci_fixup __start_pci_fixups_header[];
+extern struct pci_fixup __end_pci_fixups_header[];
+extern struct pci_fixup __start_pci_fixups_enable[];
+extern struct pci_fixup __end_pci_fixups_enable[];
+
+void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
+{
+ struct pci_fixup *start, *end;
+
+ switch (pass) {
+ case pci_fixup_early:
+ start = __start_pci_fixups_early;
+ end = __end_pci_fixups_early;
+ break;
+ case pci_fixup_header:
+ start = __start_pci_fixups_header;
+ end = __end_pci_fixups_header;
+ break;
+ case pci_fixup_enable:
+ start = __start_pci_fixups_enable;
+ end = __end_pci_fixups_enable;
+ break;
+ default:
+ unreachable();
+ }
+ pci_do_fixups(dev, start, end);
+}
diff --git a/drivers/pinctrl/imx-iomux-v3.c b/drivers/pinctrl/imx-iomux-v3.c
index 38451875ea..d176199c52 100644
--- a/drivers/pinctrl/imx-iomux-v3.c
+++ b/drivers/pinctrl/imx-iomux-v3.c
@@ -117,6 +117,9 @@ static int imx_iomux_v3_set_state(struct pinctrl_device *pdev, struct device_nod
if (of_get_property(np, "input-schmitt-enable", NULL))
share_conf_val |= SHARE_CONF_PAD_CTL_HYS;
+ if (of_get_property(np, "input-enable", NULL))
+ share_conf_val |= IMX_PAD_SION;
+
if (of_get_property(np, "bias-pull-up", NULL))
share_conf_val |= SHARE_CONF_PAD_CTL_PUE;
} else {
diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c
index dd081ee84f..b6faa0217e 100644
--- a/drivers/reset/reset-socfpga.c
+++ b/drivers/reset/reset-socfpga.c
@@ -113,6 +113,7 @@ static const struct of_device_id socfpga_reset_dt_ids[] = {
};
static struct driver_d socfpga_reset_driver = {
+ .name = "socfpga_reset",
.probe = socfpga_reset_probe,
.of_compatible = DRV_OF_COMPAT(socfpga_reset_dt_ids),
};
diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c
index f28035a326..246fc3d3af 100644
--- a/drivers/serial/serial_lpuart.c
+++ b/drivers/serial/serial_lpuart.c
@@ -68,11 +68,14 @@ static int lpuart_serial_setbaudrate(struct console_device *cdev,
lpuart_enable(lpuart, false);
- lpuart_setbrg(lpuart->base,
- clk_get_rate(lpuart->clk),
- baudrate);
-
- lpuart_enable(lpuart, true);
+ /*
+ * We treat baudrate of 0 as a request to disable UART
+ */
+ if (baudrate) {
+ lpuart_setbrg(lpuart->base, clk_get_rate(lpuart->clk),
+ baudrate);
+ lpuart_enable(lpuart, true);
+ }
lpuart->baudrate = baudrate;
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 84945744ef..fed628c589 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -38,7 +38,7 @@ config DRIVER_SPI_IMX_0_7
config DRIVER_SPI_IMX_2_3
bool
- depends on ARCH_IMX50 || ARCH_IMX51 || ARCH_IMX53 || ARCH_IMX6 || ARCH_IMX7
+ depends on ARCH_IMX50 || ARCH_IMX51 || ARCH_IMX53 || ARCH_IMX6 || ARCH_IMX7 || ARCH_IMX8MQ
default y
config DRIVER_SPI_MXS
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index 7ccf227714..40a78987e4 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -337,7 +337,7 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
fb_setvar(var, "0.4");
var = fb_addvar(f_fb, "bootloader-version");
fb_setvar(var, release_string);
- if (IS_ENABLED(USB_GADGET_FASTBOOT_SPARSE)) {
+ if (IS_ENABLED(CONFIG_USB_GADGET_FASTBOOT_SPARSE)) {
var = fb_addvar(f_fb, "max-download-size");
fb_setvar(var, "%u", fastboot_max_download_size);
}
@@ -947,7 +947,7 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd)
filename = fentry->filename;
if (filetype == filetype_android_sparse) {
- if (!IS_ENABLED(USB_GADGET_FASTBOOT_SPARSE)) {
+ if (!IS_ENABLED(CONFIG_USB_GADGET_FASTBOOT_SPARSE)) {
fastboot_tx_print(f_fb, "FAILsparse image not supported");
ret = -EOPNOTSUPP;
goto out;
@@ -1233,7 +1233,7 @@ done:
static int fastboot_globalvars_init(void)
{
- if (IS_ENABLED(USB_GADGET_FASTBOOT_SPARSE))
+ if (IS_ENABLED(CONFIG_USB_GADGET_FASTBOOT_SPARSE))
globalvar_add_simple_int("usbgadget.fastboot_max_download_size",
&fastboot_max_download_size, "%u");
diff --git a/dts/Bindings/arm/samsung/samsung-boards.txt b/dts/Bindings/arm/samsung/samsung-boards.txt
index bdadc3da95..6970f30a37 100644
--- a/dts/Bindings/arm/samsung/samsung-boards.txt
+++ b/dts/Bindings/arm/samsung/samsung-boards.txt
@@ -66,7 +66,7 @@ Required root node properties:
- "insignal,arndale-octa" - for Exynos5420-based Insignal Arndale
Octa board.
- "insignal,origen" - for Exynos4210-based Insignal Origen board.
- - "insignal,origen4412 - for Exynos4412-based Insignal Origen board.
+ - "insignal,origen4412" - for Exynos4412-based Insignal Origen board.
Optional nodes:
diff --git a/dts/Bindings/display/tilcdc/tilcdc.txt b/dts/Bindings/display/tilcdc/tilcdc.txt
index 6fddb4f4f7..3055d5c2c0 100644
--- a/dts/Bindings/display/tilcdc/tilcdc.txt
+++ b/dts/Bindings/display/tilcdc/tilcdc.txt
@@ -36,7 +36,7 @@ Optional nodes:
- port/ports: to describe a connection to an external encoder. The
binding follows Documentation/devicetree/bindings/graph.txt and
- suppors a single port with a single endpoint.
+ supports a single port with a single endpoint.
- See also Documentation/devicetree/bindings/display/tilcdc/panel.txt and
Documentation/devicetree/bindings/display/tilcdc/tfp410.txt for connecting
diff --git a/dts/Bindings/gpio/nintendo,hollywood-gpio.txt b/dts/Bindings/gpio/nintendo,hollywood-gpio.txt
index 20fc72d9e6..45a61b4622 100644
--- a/dts/Bindings/gpio/nintendo,hollywood-gpio.txt
+++ b/dts/Bindings/gpio/nintendo,hollywood-gpio.txt
@@ -1,7 +1,7 @@
Nintendo Wii (Hollywood) GPIO controller
Required properties:
-- compatible: "nintendo,hollywood-gpio
+- compatible: "nintendo,hollywood-gpio"
- reg: Physical base address and length of the controller's registers.
- gpio-controller: Marks the device node as a GPIO controller.
- #gpio-cells: Should be <2>. The first cell is the pin number and the
diff --git a/dts/Bindings/input/sprd,sc27xx-vibra.txt b/dts/Bindings/input/sprd,sc27xx-vibra.txt
new file mode 100644
index 0000000000..f2ec0d4f2d
--- /dev/null
+++ b/dts/Bindings/input/sprd,sc27xx-vibra.txt
@@ -0,0 +1,23 @@
+Spreadtrum SC27xx PMIC Vibrator
+
+Required properties:
+- compatible: should be "sprd,sc2731-vibrator".
+- reg: address of vibrator control register.
+
+Example :
+
+ sc2731_pmic: pmic@0 {
+ compatible = "sprd,sc2731";
+ reg = <0>;
+ spi-max-frequency = <26000000>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ vibrator@eb4 {
+ compatible = "sprd,sc2731-vibrator";
+ reg = <0xeb4>;
+ };
+ };
diff --git a/dts/Bindings/input/touchscreen/hideep.txt b/dts/Bindings/input/touchscreen/hideep.txt
index 121d9b7c79..1063c30d53 100644
--- a/dts/Bindings/input/touchscreen/hideep.txt
+++ b/dts/Bindings/input/touchscreen/hideep.txt
@@ -32,7 +32,7 @@ i2c@00000000 {
reg = <0x6c>;
interrupt-parent = <&gpx1>;
interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
- vdd-supply = <&ldo15_reg>";
+ vdd-supply = <&ldo15_reg>;
vid-supply = <&ldo18_reg>;
reset-gpios = <&gpx1 5 0>;
touchscreen-size-x = <1080>;
diff --git a/dts/Bindings/interrupt-controller/nvidia,tegra20-ictlr.txt b/dts/Bindings/interrupt-controller/nvidia,tegra20-ictlr.txt
index 1099fe0788..f246ccbf88 100644
--- a/dts/Bindings/interrupt-controller/nvidia,tegra20-ictlr.txt
+++ b/dts/Bindings/interrupt-controller/nvidia,tegra20-ictlr.txt
@@ -15,7 +15,7 @@ Required properties:
include "nvidia,tegra30-ictlr".
- reg : Specifies base physical address and size of the registers.
Each controller must be described separately (Tegra20 has 4 of them,
- whereas Tegra30 and later have 5"
+ whereas Tegra30 and later have 5).
- interrupt-controller : Identifies the node as an interrupt controller.
- #interrupt-cells : Specifies the number of cells needed to encode an
interrupt source. The value must be 3.
diff --git a/dts/Bindings/interrupt-controller/st,stm32-exti.txt b/dts/Bindings/interrupt-controller/st,stm32-exti.txt
index 136bd612bd..6a36bf66d9 100644
--- a/dts/Bindings/interrupt-controller/st,stm32-exti.txt
+++ b/dts/Bindings/interrupt-controller/st,stm32-exti.txt
@@ -12,7 +12,7 @@ Required properties:
specifier, shall be 2
- interrupts: interrupts references to primary interrupt controller
(only needed for exti controller with multiple exti under
- same parent interrupt: st,stm32-exti and st,stm32h7-exti")
+ same parent interrupt: st,stm32-exti and st,stm32h7-exti)
Example:
diff --git a/dts/Bindings/mips/brcm/soc.txt b/dts/Bindings/mips/brcm/soc.txt
index 356c29789c..3a66d3c483 100644
--- a/dts/Bindings/mips/brcm/soc.txt
+++ b/dts/Bindings/mips/brcm/soc.txt
@@ -152,7 +152,7 @@ Required properties:
- compatible : should contain one of:
"brcm,bcm7425-timers"
"brcm,bcm7429-timers"
- "brcm,bcm7435-timers and
+ "brcm,bcm7435-timers" and
"brcm,brcmstb-timers"
- reg : the timers register range
- interrupts : the interrupt line for this timer block
diff --git a/dts/Bindings/net/fsl-fman.txt b/dts/Bindings/net/fsl-fman.txt
index df873d1f3b..f8c33890bc 100644
--- a/dts/Bindings/net/fsl-fman.txt
+++ b/dts/Bindings/net/fsl-fman.txt
@@ -238,7 +238,7 @@ PROPERTIES
Must include one of the following:
- "fsl,fman-dtsec" for dTSEC MAC
- "fsl,fman-xgec" for XGEC MAC
- - "fsl,fman-memac for mEMAC MAC
+ - "fsl,fman-memac" for mEMAC MAC
- cell-index
Usage: required
diff --git a/dts/Bindings/power/power_domain.txt b/dts/Bindings/power/power_domain.txt
index 9b387f861a..7dec508987 100644
--- a/dts/Bindings/power/power_domain.txt
+++ b/dts/Bindings/power/power_domain.txt
@@ -133,7 +133,7 @@ located inside a PM domain with index 0 of a power controller represented by a
node with the label "power".
In the second example the consumer device are partitioned across two PM domains,
the first with index 0 and the second with index 1, of a power controller that
-is represented by a node with the label "power.
+is represented by a node with the label "power".
Optional properties:
- required-opps: This contains phandle to an OPP node in another device's OPP
diff --git a/dts/Bindings/regulator/tps65090.txt b/dts/Bindings/regulator/tps65090.txt
index ca69f5e304..ae326f2635 100644
--- a/dts/Bindings/regulator/tps65090.txt
+++ b/dts/Bindings/regulator/tps65090.txt
@@ -16,7 +16,7 @@ Required properties:
Optional properties:
- ti,enable-ext-control: This is applicable for DCDC1, DCDC2 and DCDC3.
If DCDCs are externally controlled then this property should be there.
-- "dcdc-ext-control-gpios: This is applicable for DCDC1, DCDC2 and DCDC3.
+- dcdc-ext-control-gpios: This is applicable for DCDC1, DCDC2 and DCDC3.
If DCDCs are externally controlled and if it is from GPIO then GPIO
number should be provided. If it is externally controlled and no GPIO
entry then driver will just configure this rails as external control
diff --git a/dts/Bindings/reset/st,sti-softreset.txt b/dts/Bindings/reset/st,sti-softreset.txt
index a21658f18f..3661e6153a 100644
--- a/dts/Bindings/reset/st,sti-softreset.txt
+++ b/dts/Bindings/reset/st,sti-softreset.txt
@@ -15,7 +15,7 @@ Please refer to reset.txt in this directory for common reset
controller binding usage.
Required properties:
-- compatible: Should be st,stih407-softreset";
+- compatible: Should be "st,stih407-softreset";
- #reset-cells: 1, see below
example:
diff --git a/dts/Bindings/soc/qcom/qcom,geni-se.txt b/dts/Bindings/soc/qcom/qcom,geni-se.txt
index d330c73de9..68b7d6207e 100644
--- a/dts/Bindings/soc/qcom/qcom,geni-se.txt
+++ b/dts/Bindings/soc/qcom/qcom,geni-se.txt
@@ -39,7 +39,7 @@ Required properties:
Optional property:
- clock-frequency: Desired I2C bus clock frequency in Hz.
- When missing default to 400000Hz.
+ When missing default to 100000Hz.
Child nodes should conform to I2C bus binding as described in i2c.txt.
diff --git a/dts/Bindings/sound/qcom,apq8016-sbc.txt b/dts/Bindings/sound/qcom,apq8016-sbc.txt
index 6a4aadc4ce..84b28dbe9f 100644
--- a/dts/Bindings/sound/qcom,apq8016-sbc.txt
+++ b/dts/Bindings/sound/qcom,apq8016-sbc.txt
@@ -30,7 +30,7 @@ Required properties:
Board connectors:
* Headset Mic
- * Secondary Mic",
+ * Secondary Mic
* DMIC
* Ext Spk
diff --git a/dts/Bindings/sound/qcom,apq8096.txt b/dts/Bindings/sound/qcom,apq8096.txt
index aa54e49fc8..c7600a93ab 100644
--- a/dts/Bindings/sound/qcom,apq8096.txt
+++ b/dts/Bindings/sound/qcom,apq8096.txt
@@ -35,7 +35,7 @@ This binding describes the APQ8096 sound card, which uses qdsp for audio.
"Digital Mic3"
Audio pins and MicBias on WCD9335 Codec:
- "MIC_BIAS1
+ "MIC_BIAS1"
"MIC_BIAS2"
"MIC_BIAS3"
"MIC_BIAS4"
diff --git a/dts/Bindings/usb/rockchip,dwc3.txt b/dts/Bindings/usb/rockchip,dwc3.txt
index 252a05c5d9..c8c4b00ecb 100644
--- a/dts/Bindings/usb/rockchip,dwc3.txt
+++ b/dts/Bindings/usb/rockchip,dwc3.txt
@@ -16,7 +16,8 @@ A child node must exist to represent the core DWC3 IP block. The name of
the node is not important. The content of the node is defined in dwc3.txt.
Phy documentation is provided in the following places:
-Documentation/devicetree/bindings/phy/qcom-dwc3-usb-phy.txt
+Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt - USB2.0 PHY
+Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt - Type-C PHY
Example device nodes:
diff --git a/dts/Bindings/w1/w1-gpio.txt b/dts/Bindings/w1/w1-gpio.txt
index 6e09c35d9f..37091902a0 100644
--- a/dts/Bindings/w1/w1-gpio.txt
+++ b/dts/Bindings/w1/w1-gpio.txt
@@ -15,7 +15,7 @@ Optional properties:
Examples:
- onewire@0 {
+ onewire {
compatible = "w1-gpio";
gpios = <&gpio 126 0>, <&gpio 105 0>;
};
diff --git a/dts/include/dt-bindings/clock/imx6ul-clock.h b/dts/include/dt-bindings/clock/imx6ul-clock.h
index 9564597cbf..0aa1d9c3e0 100644
--- a/dts/include/dt-bindings/clock/imx6ul-clock.h
+++ b/dts/include/dt-bindings/clock/imx6ul-clock.h
@@ -235,27 +235,25 @@
#define IMX6UL_CLK_CSI_PODF 222
#define IMX6UL_CLK_PLL3_120M 223
#define IMX6UL_CLK_KPP 224
-#define IMX6UL_CLK_CKO1_SEL 225
-#define IMX6UL_CLK_CKO1_PODF 226
-#define IMX6UL_CLK_CKO1 227
-#define IMX6UL_CLK_CKO2_SEL 228
-#define IMX6UL_CLK_CKO2_PODF 229
-#define IMX6UL_CLK_CKO2 230
-#define IMX6UL_CLK_CKO 231
-
-/* For i.MX6ULL */
-#define IMX6ULL_CLK_ESAI_PRED 232
-#define IMX6ULL_CLK_ESAI_PODF 233
-#define IMX6ULL_CLK_ESAI_EXTAL 234
-#define IMX6ULL_CLK_ESAI_MEM 235
-#define IMX6ULL_CLK_ESAI_IPG 236
-#define IMX6ULL_CLK_DCP_CLK 237
-#define IMX6ULL_CLK_EPDC_PRE_SEL 238
-#define IMX6ULL_CLK_EPDC_SEL 239
-#define IMX6ULL_CLK_EPDC_PODF 240
-#define IMX6ULL_CLK_EPDC_ACLK 241
-#define IMX6ULL_CLK_EPDC_PIX 242
-#define IMX6ULL_CLK_ESAI_SEL 243
+#define IMX6ULL_CLK_ESAI_PRED 225
+#define IMX6ULL_CLK_ESAI_PODF 226
+#define IMX6ULL_CLK_ESAI_EXTAL 227
+#define IMX6ULL_CLK_ESAI_MEM 228
+#define IMX6ULL_CLK_ESAI_IPG 229
+#define IMX6ULL_CLK_DCP_CLK 230
+#define IMX6ULL_CLK_EPDC_PRE_SEL 231
+#define IMX6ULL_CLK_EPDC_SEL 232
+#define IMX6ULL_CLK_EPDC_PODF 233
+#define IMX6ULL_CLK_EPDC_ACLK 234
+#define IMX6ULL_CLK_EPDC_PIX 235
+#define IMX6ULL_CLK_ESAI_SEL 236
+#define IMX6UL_CLK_CKO1_SEL 237
+#define IMX6UL_CLK_CKO1_PODF 238
+#define IMX6UL_CLK_CKO1 239
+#define IMX6UL_CLK_CKO2_SEL 240
+#define IMX6UL_CLK_CKO2_PODF 241
+#define IMX6UL_CLK_CKO2 242
+#define IMX6UL_CLK_CKO 243
#define IMX6UL_CLK_END 244
#endif /* __DT_BINDINGS_CLOCK_IMX6UL_H */
diff --git a/dts/src/arm/am335x-bone-common.dtsi b/dts/src/arm/am335x-bone-common.dtsi
index f9e8667f58..73b514dddf 100644
--- a/dts/src/arm/am335x-bone-common.dtsi
+++ b/dts/src/arm/am335x-bone-common.dtsi
@@ -168,7 +168,6 @@
AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_clk.mmc0_clk */
- AM33XX_IOPAD(0x9a0, PIN_INPUT | MUX_MODE4) /* mcasp0_aclkr.mmc0_sdwp */
>;
};
diff --git a/dts/src/arm/am3517.dtsi b/dts/src/arm/am3517.dtsi
index ca294914bb..23ea381d36 100644
--- a/dts/src/arm/am3517.dtsi
+++ b/dts/src/arm/am3517.dtsi
@@ -39,6 +39,8 @@
ti,davinci-ctrl-ram-size = <0x2000>;
ti,davinci-rmii-en = /bits/ 8 <1>;
local-mac-address = [ 00 00 00 00 00 00 ];
+ clocks = <&emac_ick>;
+ clock-names = "ick";
};
davinci_mdio: ethernet@5c030000 {
@@ -49,6 +51,8 @@
bus_freq = <1000000>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&emac_fck>;
+ clock-names = "fck";
};
uart4: serial@4809e000 {
@@ -87,6 +91,11 @@
};
};
+/* Table Table 5-79 of the TRM shows 480ab000 is reserved */
+&usb_otg_hs {
+ status = "disabled";
+};
+
&iva {
status = "disabled";
};
diff --git a/dts/src/arm/am437x-sk-evm.dts b/dts/src/arm/am437x-sk-evm.dts
index 440351ad0b..d4be3fd0b6 100644
--- a/dts/src/arm/am437x-sk-evm.dts
+++ b/dts/src/arm/am437x-sk-evm.dts
@@ -610,6 +610,8 @@
touchscreen-size-x = <480>;
touchscreen-size-y = <272>;
+
+ wakeup-source;
};
tlv320aic3106: tlv320aic3106@1b {
diff --git a/dts/src/arm/armada-385-synology-ds116.dts b/dts/src/arm/armada-385-synology-ds116.dts
index 6782ce481a..d8769956cb 100644
--- a/dts/src/arm/armada-385-synology-ds116.dts
+++ b/dts/src/arm/armada-385-synology-ds116.dts
@@ -139,7 +139,7 @@
3700 5
3900 6
4000 7>;
- cooling-cells = <2>;
+ #cooling-cells = <2>;
};
gpio-leds {
diff --git a/dts/src/arm/armada-38x.dtsi b/dts/src/arm/armada-38x.dtsi
index 18edc9bc79..929459c427 100644
--- a/dts/src/arm/armada-38x.dtsi
+++ b/dts/src/arm/armada-38x.dtsi
@@ -547,7 +547,7 @@
thermal: thermal@e8078 {
compatible = "marvell,armada380-thermal";
- reg = <0xe4078 0x4>, <0xe4074 0x4>;
+ reg = <0xe4078 0x4>, <0xe4070 0x8>;
status = "okay";
};
diff --git a/dts/src/arm/bcm-cygnus.dtsi b/dts/src/arm/bcm-cygnus.dtsi
index 9fe4f5a637..2c4df2d2d4 100644
--- a/dts/src/arm/bcm-cygnus.dtsi
+++ b/dts/src/arm/bcm-cygnus.dtsi
@@ -216,7 +216,7 @@
reg = <0x18008000 0x100>;
#address-cells = <1>;
#size-cells = <0>;
- interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <100000>;
status = "disabled";
};
@@ -245,7 +245,7 @@
reg = <0x1800b000 0x100>;
#address-cells = <1>;
#size-cells = <0>;
- interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <100000>;
status = "disabled";
};
@@ -256,7 +256,7 @@
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
- interrupt-map = <0 0 0 0 &gic GIC_SPI 100 IRQ_TYPE_NONE>;
+ interrupt-map = <0 0 0 0 &gic GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
linux,pci-domain = <0>;
@@ -278,10 +278,10 @@
compatible = "brcm,iproc-msi";
msi-controller;
interrupt-parent = <&gic>;
- interrupts = <GIC_SPI 96 IRQ_TYPE_NONE>,
- <GIC_SPI 97 IRQ_TYPE_NONE>,
- <GIC_SPI 98 IRQ_TYPE_NONE>,
- <GIC_SPI 99 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>;
};
};
@@ -291,7 +291,7 @@
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
- interrupt-map = <0 0 0 0 &gic GIC_SPI 106 IRQ_TYPE_NONE>;
+ interrupt-map = <0 0 0 0 &gic GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
linux,pci-domain = <1>;
@@ -313,10 +313,10 @@
compatible = "brcm,iproc-msi";
msi-controller;
interrupt-parent = <&gic>;
- interrupts = <GIC_SPI 102 IRQ_TYPE_NONE>,
- <GIC_SPI 103 IRQ_TYPE_NONE>,
- <GIC_SPI 104 IRQ_TYPE_NONE>,
- <GIC_SPI 105 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
};
};
diff --git a/dts/src/arm/bcm-hr2.dtsi b/dts/src/arm/bcm-hr2.dtsi
index 3f9cedd801..3084a7c957 100644
--- a/dts/src/arm/bcm-hr2.dtsi
+++ b/dts/src/arm/bcm-hr2.dtsi
@@ -264,7 +264,7 @@
reg = <0x38000 0x50>;
#address-cells = <1>;
#size-cells = <0>;
- interrupts = <GIC_SPI 95 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <100000>;
};
@@ -279,7 +279,7 @@
reg = <0x3b000 0x50>;
#address-cells = <1>;
#size-cells = <0>;
- interrupts = <GIC_SPI 96 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <100000>;
};
};
@@ -300,7 +300,7 @@
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
- interrupt-map = <0 0 0 0 &gic GIC_SPI 186 IRQ_TYPE_NONE>;
+ interrupt-map = <0 0 0 0 &gic GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
linux,pci-domain = <0>;
@@ -322,10 +322,10 @@
compatible = "brcm,iproc-msi";
msi-controller;
interrupt-parent = <&gic>;
- interrupts = <GIC_SPI 182 IRQ_TYPE_NONE>,
- <GIC_SPI 183 IRQ_TYPE_NONE>,
- <GIC_SPI 184 IRQ_TYPE_NONE>,
- <GIC_SPI 185 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>;
brcm,pcie-msi-inten;
};
};
@@ -336,7 +336,7 @@
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
- interrupt-map = <0 0 0 0 &gic GIC_SPI 192 IRQ_TYPE_NONE>;
+ interrupt-map = <0 0 0 0 &gic GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
linux,pci-domain = <1>;
@@ -358,10 +358,10 @@
compatible = "brcm,iproc-msi";
msi-controller;
interrupt-parent = <&gic>;
- interrupts = <GIC_SPI 188 IRQ_TYPE_NONE>,
- <GIC_SPI 189 IRQ_TYPE_NONE>,
- <GIC_SPI 190 IRQ_TYPE_NONE>,
- <GIC_SPI 191 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>;
brcm,pcie-msi-inten;
};
};
diff --git a/dts/src/arm/bcm-nsp.dtsi b/dts/src/arm/bcm-nsp.dtsi
index dcc55aa845..09ba850463 100644
--- a/dts/src/arm/bcm-nsp.dtsi
+++ b/dts/src/arm/bcm-nsp.dtsi
@@ -391,7 +391,7 @@
reg = <0x38000 0x50>;
#address-cells = <1>;
#size-cells = <0>;
- interrupts = <GIC_SPI 89 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <100000>;
dma-coherent;
status = "disabled";
@@ -496,7 +496,7 @@
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
- interrupt-map = <0 0 0 0 &gic GIC_SPI 131 IRQ_TYPE_NONE>;
+ interrupt-map = <0 0 0 0 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
linux,pci-domain = <0>;
@@ -519,10 +519,10 @@
compatible = "brcm,iproc-msi";
msi-controller;
interrupt-parent = <&gic>;
- interrupts = <GIC_SPI 127 IRQ_TYPE_NONE>,
- <GIC_SPI 128 IRQ_TYPE_NONE>,
- <GIC_SPI 129 IRQ_TYPE_NONE>,
- <GIC_SPI 130 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
brcm,pcie-msi-inten;
};
};
@@ -533,7 +533,7 @@
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
- interrupt-map = <0 0 0 0 &gic GIC_SPI 137 IRQ_TYPE_NONE>;
+ interrupt-map = <0 0 0 0 &gic GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
linux,pci-domain = <1>;
@@ -556,10 +556,10 @@
compatible = "brcm,iproc-msi";
msi-controller;
interrupt-parent = <&gic>;
- interrupts = <GIC_SPI 133 IRQ_TYPE_NONE>,
- <GIC_SPI 134 IRQ_TYPE_NONE>,
- <GIC_SPI 135 IRQ_TYPE_NONE>,
- <GIC_SPI 136 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
brcm,pcie-msi-inten;
};
};
@@ -570,7 +570,7 @@
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
- interrupt-map = <0 0 0 0 &gic GIC_SPI 143 IRQ_TYPE_NONE>;
+ interrupt-map = <0 0 0 0 &gic GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
linux,pci-domain = <2>;
@@ -593,10 +593,10 @@
compatible = "brcm,iproc-msi";
msi-controller;
interrupt-parent = <&gic>;
- interrupts = <GIC_SPI 139 IRQ_TYPE_NONE>,
- <GIC_SPI 140 IRQ_TYPE_NONE>,
- <GIC_SPI 141 IRQ_TYPE_NONE>,
- <GIC_SPI 142 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
brcm,pcie-msi-inten;
};
};
diff --git a/dts/src/arm/bcm5301x.dtsi b/dts/src/arm/bcm5301x.dtsi
index 9a076c409f..ef995e50ee 100644
--- a/dts/src/arm/bcm5301x.dtsi
+++ b/dts/src/arm/bcm5301x.dtsi
@@ -365,7 +365,7 @@
i2c0: i2c@18009000 {
compatible = "brcm,iproc-i2c";
reg = <0x18009000 0x50>;
- interrupts = <GIC_SPI 121 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <100000>;
diff --git a/dts/src/arm/da850.dtsi b/dts/src/arm/da850.dtsi
index f6f1597b03..0f4f817a9e 100644
--- a/dts/src/arm/da850.dtsi
+++ b/dts/src/arm/da850.dtsi
@@ -549,11 +549,7 @@
gpio-controller;
#gpio-cells = <2>;
reg = <0x226000 0x1000>;
- interrupts = <42 IRQ_TYPE_EDGE_BOTH
- 43 IRQ_TYPE_EDGE_BOTH 44 IRQ_TYPE_EDGE_BOTH
- 45 IRQ_TYPE_EDGE_BOTH 46 IRQ_TYPE_EDGE_BOTH
- 47 IRQ_TYPE_EDGE_BOTH 48 IRQ_TYPE_EDGE_BOTH
- 49 IRQ_TYPE_EDGE_BOTH 50 IRQ_TYPE_EDGE_BOTH>;
+ interrupts = <42 43 44 45 46 47 48 49 50>;
ti,ngpio = <144>;
ti,davinci-gpio-unbanked = <0>;
status = "disabled";
diff --git a/dts/src/arm/dra7.dtsi b/dts/src/arm/dra7.dtsi
index 9dcd14edc2..e03495a799 100644
--- a/dts/src/arm/dra7.dtsi
+++ b/dts/src/arm/dra7.dtsi
@@ -1580,7 +1580,6 @@
dr_mode = "otg";
snps,dis_u3_susphy_quirk;
snps,dis_u2_susphy_quirk;
- snps,dis_metastability_quirk;
};
};
@@ -1608,6 +1607,7 @@
dr_mode = "otg";
snps,dis_u3_susphy_quirk;
snps,dis_u2_susphy_quirk;
+ snps,dis_metastability_quirk;
};
};
diff --git a/dts/src/arm/imx51-zii-rdu1.dts b/dts/src/arm/imx51-zii-rdu1.dts
index df9eca94d8..8a87868719 100644
--- a/dts/src/arm/imx51-zii-rdu1.dts
+++ b/dts/src/arm/imx51-zii-rdu1.dts
@@ -770,7 +770,7 @@
pinctrl_ts: tsgrp {
fsl,pins = <
- MX51_PAD_CSI1_D8__GPIO3_12 0x85
+ MX51_PAD_CSI1_D8__GPIO3_12 0x04
MX51_PAD_CSI1_D9__GPIO3_13 0x85
>;
};
diff --git a/dts/src/arm/imx6q.dtsi b/dts/src/arm/imx6q.dtsi
index 70483ce72b..77f8f030dd 100644
--- a/dts/src/arm/imx6q.dtsi
+++ b/dts/src/arm/imx6q.dtsi
@@ -90,7 +90,7 @@
clocks = <&clks IMX6Q_CLK_ECSPI5>,
<&clks IMX6Q_CLK_ECSPI5>;
clock-names = "ipg", "per";
- dmas = <&sdma 11 7 1>, <&sdma 12 7 2>;
+ dmas = <&sdma 11 8 1>, <&sdma 12 8 2>;
dma-names = "rx", "tx";
status = "disabled";
};
diff --git a/dts/src/arm/imx6qdl-zii-rdu2.dtsi b/dts/src/arm/imx6qdl-zii-rdu2.dtsi
index 19a075aee1..f14df0baf2 100644
--- a/dts/src/arm/imx6qdl-zii-rdu2.dtsi
+++ b/dts/src/arm/imx6qdl-zii-rdu2.dtsi
@@ -692,7 +692,7 @@
dsa,member = <0 0>;
eeprom-length = <512>;
interrupt-parent = <&gpio6>;
- interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
+ interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
interrupt-controller;
#interrupt-cells = <2>;
diff --git a/dts/src/arm/imx6sx.dtsi b/dts/src/arm/imx6sx.dtsi
index d8b94f4749..4e4a55aad5 100644
--- a/dts/src/arm/imx6sx.dtsi
+++ b/dts/src/arm/imx6sx.dtsi
@@ -1344,7 +1344,7 @@
ranges = <0x81000000 0 0 0x08f80000 0 0x00010000 /* downstream I/O */
0x82000000 0 0x08000000 0x08000000 0 0x00f00000>; /* non-prefetchable memory */
num-lanes = <1>;
- interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "msi";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
diff --git a/dts/src/arm/omap4-droid4-xt894.dts b/dts/src/arm/omap4-droid4-xt894.dts
index bdf73cbcec..e7c3c563ff 100644
--- a/dts/src/arm/omap4-droid4-xt894.dts
+++ b/dts/src/arm/omap4-droid4-xt894.dts
@@ -159,13 +159,7 @@
dais = <&mcbsp2_port>, <&mcbsp3_port>;
};
-};
-
-&dss {
- status = "okay";
-};
-&gpio6 {
pwm8: dmtimer-pwm-8 {
pinctrl-names = "default";
pinctrl-0 = <&vibrator_direction_pin>;
@@ -192,7 +186,10 @@
pwm-names = "enable", "direction";
direction-duty-cycle-ns = <10000000>;
};
+};
+&dss {
+ status = "okay";
};
&dsi1 {
diff --git a/dts/src/arm/socfpga.dtsi b/dts/src/arm/socfpga.dtsi
index 486d4e7433..b38f8c2405 100644
--- a/dts/src/arm/socfpga.dtsi
+++ b/dts/src/arm/socfpga.dtsi
@@ -748,13 +748,13 @@
nand0: nand@ff900000 {
#address-cells = <0x1>;
#size-cells = <0x1>;
- compatible = "denali,denali-nand-dt";
+ compatible = "altr,socfpga-denali-nand";
reg = <0xff900000 0x100000>,
<0xffb80000 0x10000>;
reg-names = "nand_data", "denali_reg";
interrupts = <0x0 0x90 0x4>;
dma-mask = <0xffffffff>;
- clocks = <&nand_clk>;
+ clocks = <&nand_x_clk>;
status = "disabled";
};
diff --git a/dts/src/arm/socfpga_arria10.dtsi b/dts/src/arm/socfpga_arria10.dtsi
index bead79e4b2..791ca15c79 100644
--- a/dts/src/arm/socfpga_arria10.dtsi
+++ b/dts/src/arm/socfpga_arria10.dtsi
@@ -593,8 +593,7 @@
#size-cells = <0>;
reg = <0xffda5000 0x100>;
interrupts = <0 102 4>;
- num-chipselect = <4>;
- bus-num = <0>;
+ num-cs = <4>;
/*32bit_access;*/
tx-dma-channel = <&pdma 16>;
rx-dma-channel = <&pdma 17>;
@@ -633,7 +632,7 @@
nand: nand@ffb90000 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "denali,denali-nand-dt", "altr,socfpga-denali-nand";
+ compatible = "altr,socfpga-denali-nand";
reg = <0xffb90000 0x72000>,
<0xffb80000 0x10000>;
reg-names = "nand_data", "denali_reg";
diff --git a/dts/src/arm64/altera/socfpga_stratix10.dtsi b/dts/src/arm64/altera/socfpga_stratix10.dtsi
index e6b059378d..67dac595dc 100644
--- a/dts/src/arm64/altera/socfpga_stratix10.dtsi
+++ b/dts/src/arm64/altera/socfpga_stratix10.dtsi
@@ -309,8 +309,7 @@
interrupts = <0 99 4>;
resets = <&rst SPIM0_RESET>;
reg-io-width = <4>;
- num-chipselect = <4>;
- bus-num = <0>;
+ num-cs = <4>;
status = "disabled";
};
@@ -322,8 +321,7 @@
interrupts = <0 100 4>;
resets = <&rst SPIM1_RESET>;
reg-io-width = <4>;
- num-chipselect = <4>;
- bus-num = <0>;
+ num-cs = <4>;
status = "disabled";
};
diff --git a/dts/src/arm64/amlogic/meson-axg-s400.dts b/dts/src/arm64/amlogic/meson-axg-s400.dts
index 4b3331fbfe..dff9b15eb3 100644
--- a/dts/src/arm64/amlogic/meson-axg-s400.dts
+++ b/dts/src/arm64/amlogic/meson-axg-s400.dts
@@ -66,9 +66,22 @@
&ethmac {
status = "okay";
- phy-mode = "rgmii";
pinctrl-0 = <&eth_rgmii_y_pins>;
pinctrl-names = "default";
+ phy-handle = <&eth_phy0>;
+ phy-mode = "rgmii";
+
+ mdio {
+ compatible = "snps,dwmac-mdio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ eth_phy0: ethernet-phy@0 {
+ /* Realtek RTL8211F (0x001cc916) */
+ reg = <0>;
+ eee-broken-1000t;
+ };
+ };
};
&uart_A {
diff --git a/dts/src/arm64/amlogic/meson-axg.dtsi b/dts/src/arm64/amlogic/meson-axg.dtsi
index fee87737a2..67d7115e4e 100644
--- a/dts/src/arm64/amlogic/meson-axg.dtsi
+++ b/dts/src/arm64/amlogic/meson-axg.dtsi
@@ -132,7 +132,7 @@
sd_emmc_b: sd@5000 {
compatible = "amlogic,meson-axg-mmc";
- reg = <0x0 0x5000 0x0 0x2000>;
+ reg = <0x0 0x5000 0x0 0x800>;
interrupts = <GIC_SPI 217 IRQ_TYPE_EDGE_RISING>;
status = "disabled";
clocks = <&clkc CLKID_SD_EMMC_B>,
@@ -144,7 +144,7 @@
sd_emmc_c: mmc@7000 {
compatible = "amlogic,meson-axg-mmc";
- reg = <0x0 0x7000 0x0 0x2000>;
+ reg = <0x0 0x7000 0x0 0x800>;
interrupts = <GIC_SPI 218 IRQ_TYPE_EDGE_RISING>;
status = "disabled";
clocks = <&clkc CLKID_SD_EMMC_C>,
diff --git a/dts/src/arm64/amlogic/meson-gx.dtsi b/dts/src/arm64/amlogic/meson-gx.dtsi
index 3c31e21cbe..b8dc4dbb39 100644
--- a/dts/src/arm64/amlogic/meson-gx.dtsi
+++ b/dts/src/arm64/amlogic/meson-gx.dtsi
@@ -35,6 +35,12 @@
no-map;
};
+ /* Alternate 3 MiB reserved for ARM Trusted Firmware (BL31) */
+ secmon_reserved_alt: secmon@5000000 {
+ reg = <0x0 0x05000000 0x0 0x300000>;
+ no-map;
+ };
+
linux,cma {
compatible = "shared-dma-pool";
reusable;
@@ -457,21 +463,21 @@
sd_emmc_a: mmc@70000 {
compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc";
- reg = <0x0 0x70000 0x0 0x2000>;
+ reg = <0x0 0x70000 0x0 0x800>;
interrupts = <GIC_SPI 216 IRQ_TYPE_EDGE_RISING>;
status = "disabled";
};
sd_emmc_b: mmc@72000 {
compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc";
- reg = <0x0 0x72000 0x0 0x2000>;
+ reg = <0x0 0x72000 0x0 0x800>;
interrupts = <GIC_SPI 217 IRQ_TYPE_EDGE_RISING>;
status = "disabled";
};
sd_emmc_c: mmc@74000 {
compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc";
- reg = <0x0 0x74000 0x0 0x2000>;
+ reg = <0x0 0x74000 0x0 0x800>;
interrupts = <GIC_SPI 218 IRQ_TYPE_EDGE_RISING>;
status = "disabled";
};
diff --git a/dts/src/arm64/amlogic/meson-gxl-mali.dtsi b/dts/src/arm64/amlogic/meson-gxl-mali.dtsi
index eb327664a4..6aaafff674 100644
--- a/dts/src/arm64/amlogic/meson-gxl-mali.dtsi
+++ b/dts/src/arm64/amlogic/meson-gxl-mali.dtsi
@@ -6,7 +6,7 @@
&apb {
mali: gpu@c0000 {
- compatible = "amlogic,meson-gxbb-mali", "arm,mali-450";
+ compatible = "amlogic,meson-gxl-mali", "arm,mali-450";
reg = <0x0 0xc0000 0x0 0x40000>;
interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>,
diff --git a/dts/src/arm64/amlogic/meson-gxl-s905x-libretech-cc.dts b/dts/src/arm64/amlogic/meson-gxl-s905x-libretech-cc.dts
index 3e3eb31748..f63bceb88c 100644
--- a/dts/src/arm64/amlogic/meson-gxl-s905x-libretech-cc.dts
+++ b/dts/src/arm64/amlogic/meson-gxl-s905x-libretech-cc.dts
@@ -234,9 +234,6 @@
bus-width = <4>;
cap-sd-highspeed;
- sd-uhs-sdr12;
- sd-uhs-sdr25;
- sd-uhs-sdr50;
max-frequency = <100000000>;
disable-wp;
diff --git a/dts/src/arm64/amlogic/meson-gxl-s905x-p212.dtsi b/dts/src/arm64/amlogic/meson-gxl-s905x-p212.dtsi
index 0cfd701809..a1b31013ab 100644
--- a/dts/src/arm64/amlogic/meson-gxl-s905x-p212.dtsi
+++ b/dts/src/arm64/amlogic/meson-gxl-s905x-p212.dtsi
@@ -189,3 +189,10 @@
&usb0 {
status = "okay";
};
+
+&usb2_phy0 {
+ /*
+ * HDMI_5V is also used as supply for the USB VBUS.
+ */
+ phy-supply = <&hdmi_5v>;
+};
diff --git a/dts/src/arm64/amlogic/meson-gxl.dtsi b/dts/src/arm64/amlogic/meson-gxl.dtsi
index 27538eea54..c87a80e9bc 100644
--- a/dts/src/arm64/amlogic/meson-gxl.dtsi
+++ b/dts/src/arm64/amlogic/meson-gxl.dtsi
@@ -13,14 +13,6 @@
/ {
compatible = "amlogic,meson-gxl";
- reserved-memory {
- /* Alternate 3 MiB reserved for ARM Trusted Firmware (BL31) */
- secmon_reserved_alt: secmon@5000000 {
- reg = <0x0 0x05000000 0x0 0x300000>;
- no-map;
- };
- };
-
soc {
usb0: usb@c9000000 {
status = "disabled";
diff --git a/dts/src/arm64/broadcom/northstar2/ns2.dtsi b/dts/src/arm64/broadcom/northstar2/ns2.dtsi
index 4a2a6af8e7..4057197048 100644
--- a/dts/src/arm64/broadcom/northstar2/ns2.dtsi
+++ b/dts/src/arm64/broadcom/northstar2/ns2.dtsi
@@ -118,7 +118,7 @@
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
- interrupt-map = <0 0 0 0 &gic 0 GIC_SPI 281 IRQ_TYPE_NONE>;
+ interrupt-map = <0 0 0 0 &gic 0 GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>;
linux,pci-domain = <0>;
@@ -149,7 +149,7 @@
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
- interrupt-map = <0 0 0 0 &gic 0 GIC_SPI 305 IRQ_TYPE_NONE>;
+ interrupt-map = <0 0 0 0 &gic 0 GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
linux,pci-domain = <4>;
@@ -566,7 +566,7 @@
reg = <0x66080000 0x100>;
#address-cells = <1>;
#size-cells = <0>;
- interrupts = <GIC_SPI 394 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 394 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <100000>;
status = "disabled";
};
@@ -594,7 +594,7 @@
reg = <0x660b0000 0x100>;
#address-cells = <1>;
#size-cells = <0>;
- interrupts = <GIC_SPI 395 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 395 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <100000>;
status = "disabled";
};
diff --git a/dts/src/arm64/broadcom/stingray/bcm958742k.dts b/dts/src/arm64/broadcom/stingray/bcm958742k.dts
index eb6f08cdbd..77efa28c4d 100644
--- a/dts/src/arm64/broadcom/stingray/bcm958742k.dts
+++ b/dts/src/arm64/broadcom/stingray/bcm958742k.dts
@@ -43,6 +43,10 @@
enet-phy-lane-swap;
};
+&sdio0 {
+ mmc-ddr-1_8v;
+};
+
&uart2 {
status = "okay";
};
diff --git a/dts/src/arm64/broadcom/stingray/bcm958742t.dts b/dts/src/arm64/broadcom/stingray/bcm958742t.dts
index 5084b03732..55ba495ef5 100644
--- a/dts/src/arm64/broadcom/stingray/bcm958742t.dts
+++ b/dts/src/arm64/broadcom/stingray/bcm958742t.dts
@@ -42,3 +42,7 @@
&gphy0 {
enet-phy-lane-swap;
};
+
+&sdio0 {
+ mmc-ddr-1_8v;
+};
diff --git a/dts/src/arm64/broadcom/stingray/stingray.dtsi b/dts/src/arm64/broadcom/stingray/stingray.dtsi
index 99aaff0b6d..b203152ad6 100644
--- a/dts/src/arm64/broadcom/stingray/stingray.dtsi
+++ b/dts/src/arm64/broadcom/stingray/stingray.dtsi
@@ -409,7 +409,7 @@
reg = <0x000b0000 0x100>;
#address-cells = <1>;
#size-cells = <0>;
- interrupts = <GIC_SPI 177 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <100000>;
status = "disabled";
};
@@ -453,7 +453,7 @@
reg = <0x000e0000 0x100>;
#address-cells = <1>;
#size-cells = <0>;
- interrupts = <GIC_SPI 178 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <100000>;
status = "disabled";
};
diff --git a/dts/src/arm64/hisilicon/hi3660-hikey960.dts b/dts/src/arm64/hisilicon/hi3660-hikey960.dts
index c6999624ed..68c5a6c819 100644
--- a/dts/src/arm64/hisilicon/hi3660-hikey960.dts
+++ b/dts/src/arm64/hisilicon/hi3660-hikey960.dts
@@ -585,6 +585,8 @@
vmmc-supply = <&wlan_en>;
ti,non-removable;
non-removable;
+ cap-power-off-card;
+ keep-power-in-suspend;
#address-cells = <0x1>;
#size-cells = <0x0>;
status = "ok";
diff --git a/dts/src/arm64/hisilicon/hi6220-hikey.dts b/dts/src/arm64/hisilicon/hi6220-hikey.dts
index edb4ee0b88..7f12624f6c 100644
--- a/dts/src/arm64/hisilicon/hi6220-hikey.dts
+++ b/dts/src/arm64/hisilicon/hi6220-hikey.dts
@@ -322,6 +322,8 @@
dwmmc_2: dwmmc2@f723f000 {
bus-width = <0x4>;
non-removable;
+ cap-power-off-card;
+ keep-power-in-suspend;
vmmc-supply = <&reg_vdd_3v3>;
mmc-pwrseq = <&wl1835_pwrseq>;
diff --git a/dts/src/arm64/marvell/armada-cp110.dtsi b/dts/src/arm64/marvell/armada-cp110.dtsi
index 7dabe25f67..1c6ff8197a 100644
--- a/dts/src/arm64/marvell/armada-cp110.dtsi
+++ b/dts/src/arm64/marvell/armada-cp110.dtsi
@@ -149,7 +149,7 @@
CP110_LABEL(icu): interrupt-controller@1e0000 {
compatible = "marvell,cp110-icu";
- reg = <0x1e0000 0x10>;
+ reg = <0x1e0000 0x440>;
#interrupt-cells = <3>;
interrupt-controller;
msi-parent = <&gicp>;
diff --git a/dts/src/arm64/qcom/apq8096-db820c.dtsi b/dts/src/arm64/qcom/apq8096-db820c.dtsi
index 0f829db33e..4d5ef01f43 100644
--- a/dts/src/arm64/qcom/apq8096-db820c.dtsi
+++ b/dts/src/arm64/qcom/apq8096-db820c.dtsi
@@ -75,7 +75,7 @@
serial@75b1000 {
label = "LS-UART0";
- status = "okay";
+ status = "disabled";
pinctrl-names = "default", "sleep";
pinctrl-0 = <&blsp2_uart2_4pins_default>;
pinctrl-1 = <&blsp2_uart2_4pins_sleep>;
diff --git a/dts/src/arm64/qcom/msm8916.dtsi b/dts/src/arm64/qcom/msm8916.dtsi
index 650f356f69..c2625d15a8 100644
--- a/dts/src/arm64/qcom/msm8916.dtsi
+++ b/dts/src/arm64/qcom/msm8916.dtsi
@@ -1191,14 +1191,14 @@
port@0 {
reg = <0>;
- etf_out: endpoint {
+ etf_in: endpoint {
slave-mode;
remote-endpoint = <&funnel0_out>;
};
};
port@1 {
reg = <0>;
- etf_in: endpoint {
+ etf_out: endpoint {
remote-endpoint = <&replicator_in>;
};
};
diff --git a/dts/src/arm64/socionext/uniphier-ld11-global.dts b/dts/src/arm64/socionext/uniphier-ld11-global.dts
index 9b4dc41703..ae3b5adf32 100644
--- a/dts/src/arm64/socionext/uniphier-ld11-global.dts
+++ b/dts/src/arm64/socionext/uniphier-ld11-global.dts
@@ -54,7 +54,7 @@
sound {
compatible = "audio-graph-card";
label = "UniPhier LD11";
- widgets = "Headphone", "Headphone Jack";
+ widgets = "Headphone", "Headphones";
dais = <&i2s_port2
&i2s_port3
&i2s_port4
diff --git a/dts/src/arm64/socionext/uniphier-ld20-global.dts b/dts/src/arm64/socionext/uniphier-ld20-global.dts
index fe6608ea32..7919233c9c 100644
--- a/dts/src/arm64/socionext/uniphier-ld20-global.dts
+++ b/dts/src/arm64/socionext/uniphier-ld20-global.dts
@@ -54,7 +54,7 @@
sound {
compatible = "audio-graph-card";
label = "UniPhier LD20";
- widgets = "Headphone", "Headphone Jack";
+ widgets = "Headphone", "Headphones";
dais = <&i2s_port2
&i2s_port3
&i2s_port4
diff --git a/firmware/Kconfig b/firmware/Kconfig
index b6449644be..a6f79e8a97 100644
--- a/firmware/Kconfig
+++ b/firmware/Kconfig
@@ -7,4 +7,7 @@ config EXTRA_FIRMWARE_DIR
config FIRMWARE_IMX_LPDDR4_PMU_TRAIN
bool
+config FIRMWARE_IMX8MQ_ATF
+ bool
+
endmenu
diff --git a/firmware/Makefile b/firmware/Makefile
index c82e81ae44..7f4dc49326 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -9,6 +9,8 @@ firmware-$(CONFIG_FIRMWARE_IMX_LPDDR4_PMU_TRAIN) += \
imx/lpddr4_pmu_train_2d_dmem.bin \
imx/lpddr4_pmu_train_2d_imem.bin
+firmware-$(CONFIG_FIRMWARE_IMX8MQ_ATF) += imx/imx8m-bl31.bin
+
# Create $(fwabs) from $(CONFIG_EXTRA_FIRMWARE_DIR) -- if it doesn't have a
# leading /, it's relative to $(srctree).
fwdir := $(subst $(quote),,$(CONFIG_EXTRA_FIRMWARE_DIR))
@@ -55,6 +57,6 @@ endif
targets := $(patsubst $(obj)/%,%, \
$(shell find $(obj) -name \*.gen.S 2>/dev/null))
-# just to build a built-in.o. Otherwise compilation fails when no devicetree is
-# created.
+# just to build a built-in.o. Otherwise compilation fails when no
+# firmware is built.
obj- += dummy.o
diff --git a/firmware/imx/imx8m-bl31.bin b/firmware/imx/imx8m-bl31.bin
new file mode 100755
index 0000000000..b2310e4334
--- /dev/null
+++ b/firmware/imx/imx8m-bl31.bin
Binary files differ
diff --git a/fs/Kconfig b/fs/Kconfig
index 3512000556..76a3846929 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -6,6 +6,17 @@ config FS
default y
select FILETYPE
+config FS_LEGACY
+ bool
+ help
+ invisible option selected by filesystem drivers which haven't
+ been ported to dentry cache.
+
+if FS_LEGACY
+comment "Some selected filesystems still use the legacy FS API."
+comment "Consider updating them."
+endif
+
config FS_AUTOMOUNT
bool
@@ -35,6 +46,7 @@ config FS_OMAP4_USBBOOT
bool
prompt "Filesystem over usb boot"
depends on OMAP4_USBBOOT
+ select FS_LEGACY
config FS_NFS
depends on NET
@@ -43,6 +55,7 @@ config FS_NFS
config FS_EFI
depends on EFI_BOOTUP
+ select FS_LEGACY
bool
prompt "EFI filesystem support"
help
@@ -51,6 +64,7 @@ config FS_EFI
config FS_EFIVARFS
depends on EFI_BOOTUP
+ select FS_LEGACY
bool
prompt "EFI variable filesystem support (efivarfs)"
help
@@ -62,6 +76,7 @@ source fs/ubifs/Kconfig
config FS_BPKFS
bool
select CRC32
+ select FS_LEGACY
prompt "BPKFS support"
help
Simple update file format developed for Somfy, tools and library are
@@ -78,10 +93,12 @@ config FS_BPKFS
config FS_UIMAGEFS
bool
select CRC32
+ select FS_LEGACY
prompt "uImage FS support"
config FS_SMHFS
depends on ARM_SEMIHOSTING
+ select FS_LEGACY
bool
prompt "Semihosting FS support"
help
@@ -95,6 +112,7 @@ source fs/squashfs/Kconfig
config FS_RATP
bool
depends on RATP
+ select FS_LEGACY
prompt "RATP filesystem support"
help
This enables support for transferring files over RATP. A host can
diff --git a/fs/Makefile b/fs/Makefile
index 8e3fd78e92..ac3e6a03aa 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -2,9 +2,10 @@ obj-$(CONFIG_FS_CRAMFS) += cramfs/
obj-$(CONFIG_FS_EXT4) += ext4/
obj-$(CONFIG_FS_RAMFS) += ramfs.o
obj-y += devfs-core.o
+obj-$(CONFIG_FS_LEGACY) += legacy.o
obj-$(CONFIG_FS_DEVFS) += devfs.o
obj-$(CONFIG_FS_FAT) += fat/
-obj-y += fs.o
+obj-y += fs.o libfs.o
obj-$(CONFIG_FS_UBIFS) += ubifs/
obj-$(CONFIG_FS_TFTP) += tftp.o
obj-$(CONFIG_FS_OMAP4_USBBOOT) += omap4_usbbootfs.o
diff --git a/fs/cramfs/cramfs.c b/fs/cramfs/cramfs.c
index a02c253841..a3ce354c92 100644
--- a/fs/cramfs/cramfs.c
+++ b/fs/cramfs/cramfs.c
@@ -51,10 +51,16 @@ struct cramfs_priv {
};
struct cramfs_inode_info {
+ struct inode i_inode;
struct cramfs_inode inode;
unsigned long *block_ptrs;
};
+static inline struct cramfs_inode_info* to_cramfs_inode_info(struct inode *inode)
+{
+ return container_of(inode, struct cramfs_inode_info, i_inode);
+}
+
static int cramfs_read_super(struct cramfs_priv *priv)
{
unsigned long root_offset;
@@ -107,233 +113,29 @@ static int cramfs_read_super(struct cramfs_priv *priv)
return 0;
}
-static struct cramfs_inode_info *cramfs_get_inode(struct cramfs_priv *priv, unsigned long offset)
-{
- struct cramfs_inode_info *inodei = xmalloc(sizeof(*inodei));
-
- if (cdev_read(priv->cdev, &inodei->inode, sizeof(struct cramfs_inode), offset, 0) < 0) {
- free(inodei);
- return NULL;
- }
-
- return inodei;
-}
-
-static struct cramfs_inode_info *cramfs_resolve (struct cramfs_priv *priv, unsigned long offset,
- unsigned long size, int raw,
- char *filename)
-{
- unsigned long inodeoffset = 0, nextoffset;
- struct cramfs_inode_info *inodei = NULL, *ret;
- char *name = xmalloc(256);
-
- while (inodeoffset < size) {
- int namelen;
- inodei = cramfs_get_inode(priv, offset + inodeoffset);
-
- /*
- * Namelengths on disk are shifted by two
- * and the name padded out to 4-byte boundaries
- * with zeroes.
- */
- namelen = CRAMFS_GET_NAMELEN (&inodei->inode) << 2;
- cdev_read(priv->cdev, name, namelen, offset + inodeoffset + sizeof (struct cramfs_inode), 0);
-
- nextoffset =
- inodeoffset + sizeof (struct cramfs_inode) + namelen;
-
- if (!strncmp (filename, name, namelen)) {
- char *p = strtok (NULL, "/");
-
- if (raw && (p == NULL || *p == '\0'))
- goto out1;
-
- if (S_ISDIR (CRAMFS_16 (inodei->inode.mode))) {
- ret = cramfs_resolve(priv,
- CRAMFS_GET_OFFSET(&inodei->inode) << 2,
- CRAMFS_24 (inodei->inode.size),
- raw, p);
- goto out;
- } else if (S_ISREG (CRAMFS_16 (inodei->inode.mode))) {
- goto out1;
- } else {
- printf ("%*.*s: unsupported file type (%x)\n",
- namelen, namelen, name,
- CRAMFS_16 (inodei->inode.mode));
- ret = NULL;
- goto out;
- }
- }
-
- free(inodei);
- inodeoffset = nextoffset;
- }
-
- free(name);
- return NULL;
-
-out1:
- ret = cramfs_get_inode(priv, offset + inodeoffset);
-out:
- free(inodei);
- free(name);
- return ret;
-}
-
-static int cramfs_fill_dirent (struct cramfs_priv *priv, unsigned long offset, struct dirent *d)
-{
- struct cramfs_inode_info *inodei = cramfs_get_inode(priv, offset);
- int namelen;
-
- if (!inodei)
- return -EINVAL;
-
- memset(d->d_name, 0, 256);
-
- /*
- * Namelengths on disk are shifted by two
- * and the name padded out to 4-byte boundaries
- * with zeroes.
- */
-
- namelen = CRAMFS_GET_NAMELEN (&inodei->inode) << 2;
- cdev_read(priv->cdev, d->d_name, namelen, offset + sizeof(struct cramfs_inode), 0);
- free(inodei);
- return namelen;
-}
-
-struct cramfs_dir {
- unsigned long offset, size;
- unsigned long inodeoffset;
- DIR dir;
-};
-
-static DIR* cramfs_opendir(struct device_d *_dev, const char *filename)
+static int cramfs_read_file(struct inode *inode, unsigned long offset,
+ void *buf, size_t size)
{
- struct cramfs_priv *priv = _dev->priv;
- char *f;
-
- struct cramfs_dir *dir = xzalloc(sizeof(struct cramfs_dir));
- dir->dir.priv = dir;
-
- if (strlen (filename) == 0 || !strcmp (filename, "/")) {
- /* Root directory. Use root inode in super block */
- dir->offset = CRAMFS_GET_OFFSET (&(priv->super.root)) << 2;
- dir->size = CRAMFS_24 (priv->super.root.size);
- } else {
- struct cramfs_inode_info *inodei;
-
- f = strdup(filename);
- /* Resolve the path */
- inodei = cramfs_resolve(priv,
- CRAMFS_GET_OFFSET (&(priv->super.root)) <<
- 2, CRAMFS_24 (priv->super.root.size), 1,
- strtok (f, "/"));
- free(f);
- if (!inodei)
- goto err_free;
-
- /* Resolving was successful. Examine the inode */
- if (!S_ISDIR (CRAMFS_16 (inodei->inode.mode))) {
- /* It's not a directory */
- free(inodei);
- goto err_free;
- }
-
- dir->offset = CRAMFS_GET_OFFSET (&inodei->inode) << 2;
- dir->size = CRAMFS_24 (inodei->inode.size);
- free(inodei);
- }
-
- return &dir->dir;
-
-err_free:
- free(dir);
- return NULL;
-}
-
-static struct dirent* cramfs_readdir(struct device_d *_dev, DIR *_dir)
-{
- struct cramfs_priv *priv = _dev->priv;
- struct cramfs_dir *dir = _dir->priv;
- unsigned long nextoffset;
-
- /* List the given directory */
- if (dir->inodeoffset < dir->size) {
- nextoffset = cramfs_fill_dirent (priv, dir->offset + dir->inodeoffset, &_dir->d);
-
- dir->inodeoffset += sizeof (struct cramfs_inode) + nextoffset;
- return &_dir->d;
- }
- return NULL;
-}
-
-static int cramfs_closedir(struct device_d *dev, DIR *_dir)
-{
- struct cramfs_dir *dir = _dir->priv;
- free(dir);
- return 0;
-}
-
-static int cramfs_open(struct device_d *_dev, FILE *file, const char *filename)
-{
- struct cramfs_priv *priv = _dev->priv;
- struct cramfs_inode_info *inodei;
- char *f;
-
- f = strdup(filename);
- inodei = cramfs_resolve (priv,
- CRAMFS_GET_OFFSET (&(priv->super.root)) << 2,
- CRAMFS_24 (priv->super.root.size), 0,
- strtok (f, "/"));
- free(f);
-
- if (!inodei)
- return -ENOENT;
-
- file->priv = inodei;
- file->size = inodei->inode.size;
-
- inodei->block_ptrs = xzalloc(4096);
- cdev_read(priv->cdev, inodei->block_ptrs, 4096, CRAMFS_GET_OFFSET(&inodei->inode) << 2, 0);
-
- return 0;
-}
-
-static int cramfs_close(struct device_d *dev, FILE *file)
-{
- struct cramfs_inode_info *inodei = file->priv;
-
- free(inodei->block_ptrs);
- free(inodei);
-
- return 0;
-}
-
-static int cramfs_read(struct device_d *_dev, FILE *f, void *buf, size_t size)
-{
- struct cramfs_priv *priv = _dev->priv;
- struct cramfs_inode_info *inodei = f->priv;
- struct cramfs_inode *inode = &inodei->inode;
+ struct cramfs_inode_info *info = to_cramfs_inode_info(inode);
+ struct cramfs_inode *cramfs_inode = &info->inode;
+ struct fs_device_d *fsdev = container_of(inode->i_sb, struct fs_device_d, sb);
+ struct cramfs_priv *priv = fsdev->dev.priv;
unsigned int blocknr;
int outsize = 0;
- unsigned long *block_ptrs = inodei->block_ptrs;
- int ofs = f->pos % 4096;
+ int ofs = offset % 4096;
static char cramfs_read_buf[4096];
- if (f->pos + size > inode->size)
- size = inode->size - f->pos;
-
while (size) {
- unsigned long base;
+ uint32_t base;
int copy;
- blocknr = (f->pos + outsize) >> 12;
-
+ blocknr = (offset + outsize) >> 12;
if (blocknr)
- base = CRAMFS_32 (block_ptrs[blocknr - 1]);
+ cdev_read(priv->cdev, &base, 4,
+ OFFSET(inode) + (blocknr - 1) * 4, 0);
else
- base = (CRAMFS_GET_OFFSET(inode) + (((CRAMFS_24 (inode->size)) + 4095) >> 12)) << 2;
+ base = (CRAMFS_GET_OFFSET(cramfs_inode) +
+ (((CRAMFS_24 (cramfs_inode->size)) + 4095) >> 12)) << 2;
if (priv->curr_base < 0 || priv->curr_base != base) {
@@ -359,38 +161,17 @@ static int cramfs_read(struct device_d *_dev, FILE *f, void *buf, size_t size)
return outsize;
}
+static int cramfs_read(struct device_d *_dev, FILE *f, void *buf, size_t size)
+{
+ return cramfs_read_file(f->f_inode, f->pos, buf, size);
+}
+
static loff_t cramfs_lseek(struct device_d *dev, FILE *f, loff_t pos)
{
f->pos = pos;
return f->pos;
}
-static int cramfs_stat(struct device_d *_dev, const char *filename, struct stat *stat)
-{
- struct cramfs_priv *priv = _dev->priv;
- struct cramfs_inode_info *inodei;
- struct cramfs_inode *inode;
- char *f;
-
- f = strdup(filename);
-
- inodei = cramfs_resolve (priv,
- CRAMFS_GET_OFFSET (&(priv->super.root)) << 2,
- CRAMFS_24 (priv->super.root.size), 1,
- strtok (f, "/"));
- free(f);
-
- if (!inodei)
- return -ENOENT;
-
- inode = &inodei->inode;
- stat->st_mode = CRAMFS_16 (inode->mode);
- stat->st_size = CRAMFS_24 (inode->size);
-
- free(inodei);
-
- return 0;
-}
#if 0
static int cramfs_info (struct device_d *dev)
{
@@ -419,20 +200,260 @@ static int cramfs_info (struct device_d *dev)
}
#endif
+static const struct file_operations cramfs_dir_operations;
+static const struct inode_operations cramfs_dir_inode_operations;
+static const struct inode_operations cramfs_symlink_inode_operations;
+
+static unsigned long cramino(const struct cramfs_inode *cino, unsigned int offset)
+{
+ if (!cino->offset)
+ return offset + 1;
+ if (!cino->size)
+ return offset + 1;
+
+ /*
+ * The file mode test fixes buggy mkcramfs implementations where
+ * cramfs_inode->offset is set to a non zero value for entries
+ * which did not contain data, like devices node and fifos.
+ */
+ switch (cino->mode & S_IFMT) {
+ case S_IFREG:
+ case S_IFDIR:
+ case S_IFLNK:
+ return cino->offset << 2;
+ default:
+ break;
+ }
+ return offset + 1;
+}
+
+static struct inode *get_cramfs_inode(struct super_block *sb,
+ const struct cramfs_inode *cramfs_inode, unsigned int offset)
+{
+ struct cramfs_inode_info *info;
+ static struct timespec zerotime;
+ struct inode *inode;
+
+ inode = new_inode(sb);
+
+ inode->i_ino = cramino(cramfs_inode, offset);
+
+ info = to_cramfs_inode_info(inode);
+
+ switch (cramfs_inode->mode & S_IFMT) {
+ case S_IFREG:
+ break;
+ case S_IFDIR:
+ inode->i_op = &cramfs_dir_inode_operations;
+ inode->i_fop = &cramfs_dir_operations;
+ break;
+ case S_IFLNK:
+ inode->i_op = &cramfs_symlink_inode_operations;
+ break;
+ default:
+ return NULL;
+ }
+
+ info->inode = *cramfs_inode;
+
+ inode->i_mode = cramfs_inode->mode;
+
+ /* if the lower 2 bits are zero, the inode contains data */
+ if (!(inode->i_ino & 3)) {
+ inode->i_size = cramfs_inode->size;
+ inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
+ }
+
+ /* Struct copy intentional */
+ inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
+ /* inode->i_nlink is left 1 - arguably wrong for directories,
+ but it's the best we can do without reading the directory
+ contents. 1 yields the right result in GNU find, even
+ without -noleaf option. */
+
+ return inode;
+}
+
+static struct dentry *cramfs_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
+{
+ struct cramfs_inode *de;
+ unsigned int offset = 0;
+ struct inode *inode = NULL;
+ struct fs_device_d *fsdev = container_of(dir->i_sb, struct fs_device_d, sb);
+ struct cramfs_priv *priv = fsdev->dev.priv;
+
+ de = xmalloc(sizeof(*de) + CRAMFS_MAXPATHLEN);
+
+ while (offset < dir->i_size) {
+ char *name;
+ int namelen, retval;
+ int dir_off = OFFSET(dir) + offset;
+
+ cdev_read(priv->cdev, de, sizeof(*de) + CRAMFS_MAXPATHLEN, dir_off, 0);
+
+ name = (char *)(de + 1);
+
+ namelen = de->namelen << 2;
+ offset += sizeof(*de) + namelen;
+
+ /* Quick check that the name is roughly the right length */
+ if (((dentry->d_name.len + 3) & ~3) != namelen)
+ continue;
+
+ for (;;) {
+ if (!namelen) {
+ inode = ERR_PTR(-EIO);
+ goto out;
+ }
+ if (name[namelen-1])
+ break;
+ namelen--;
+ }
+ if (namelen != dentry->d_name.len)
+ continue;
+ retval = memcmp(dentry->d_name.name, name, namelen);
+ if (retval > 0)
+ continue;
+ if (!retval) {
+ inode = get_cramfs_inode(dir->i_sb, de, dir_off);
+ break;
+ }
+ }
+out:
+ free(de);
+
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
+ d_add(dentry, inode);
+
+ return NULL;
+}
+
+static struct inode *cramfs_alloc_inode(struct super_block *sb)
+{
+ struct cramfs_inode_info *info;
+
+ info = xzalloc(sizeof(*info));
+
+ return &info->i_inode;
+}
+
+static int cramfs_iterate(struct file *file, struct dir_context *ctx)
+{
+ struct dentry *dentry = file->f_path.dentry;
+ struct inode *dir = d_inode(dentry);
+ struct fs_device_d *fsdev = container_of(dir->i_sb, struct fs_device_d, sb);
+ struct cramfs_priv *priv = fsdev->dev.priv;
+ char *buf;
+ unsigned int offset;
+ struct cramfs_inode *de;
+ int ret;
+
+ /* Offset within the thing. */
+ if (ctx->pos >= dir->i_size)
+ return 0;
+ offset = ctx->pos;
+ /* Directory entries are always 4-byte aligned */
+ if (offset & 3)
+ return -EINVAL;
+
+ buf = xmalloc(CRAMFS_MAXPATHLEN);
+ de = xmalloc(sizeof(*de) + CRAMFS_MAXPATHLEN);
+
+ while (offset < dir->i_size) {
+ unsigned long nextoffset;
+ char *name;
+ ino_t ino;
+ umode_t mode;
+ int namelen;
+
+ cdev_read(priv->cdev, de, sizeof(*de) + CRAMFS_MAXPATHLEN,
+ OFFSET(dir) + offset, 0);
+ name = (char *)(de + 1);
+
+ /*
+ * Namelengths on disk are shifted by two
+ * and the name padded out to 4-byte boundaries
+ * with zeroes.
+ */
+ namelen = de->namelen << 2;
+ memcpy(buf, name, namelen);
+ ino = cramino(de, OFFSET(dir) + offset);
+ mode = de->mode;
+
+ nextoffset = offset + sizeof(*de) + namelen;
+ for (;;) {
+ if (!namelen) {
+ ret = -EIO;
+ goto out;
+ }
+ if (buf[namelen - 1])
+ break;
+ namelen--;
+ }
+
+ dir_emit(ctx, buf, namelen, ino, mode >> 12);
+
+ ctx->pos = offset = nextoffset;
+ }
+ ret = 0;
+out:
+ kfree(buf);
+ free(de);
+ return ret;
+}
+
+static const struct file_operations cramfs_dir_operations = {
+ .iterate = cramfs_iterate,
+};
+
+static const struct inode_operations cramfs_dir_inode_operations =
+{
+ .lookup = cramfs_lookup,
+};
+
+static const char *cramfs_get_link(struct dentry *dentry, struct inode *inode)
+{
+ int ret;
+
+ inode->i_link = xzalloc(inode->i_size + 1);
+
+ ret = cramfs_read_file(inode, 0, inode->i_link, inode->i_size);
+ if (ret < 0)
+ return NULL;
+
+ return inode->i_link;
+}
+
+static const struct inode_operations cramfs_symlink_inode_operations =
+{
+ .get_link = cramfs_get_link,
+};
+
+static const struct super_operations cramfs_ops = {
+ .alloc_inode = cramfs_alloc_inode,
+};
+
static int cramfs_probe(struct device_d *dev)
{
struct fs_device_d *fsdev;
struct cramfs_priv *priv;
int ret;
+ struct super_block *sb;
+ struct inode *root;
fsdev = dev_to_fs_device(dev);
+ sb = &fsdev->sb;
priv = xmalloc(sizeof(struct cramfs_priv));
dev->priv = priv;
ret = fsdev_open_cdev(fsdev);
- if (ret)
+ if (ret) {
+ dev_err(dev, "open cdev failed: %d\n", ret);
goto err_out;
+ }
priv->cdev = fsdev->cdev;
@@ -444,6 +465,14 @@ static int cramfs_probe(struct device_d *dev)
priv->curr_base = -1;
cramfs_uncompress_init ();
+
+ sb->s_op = &cramfs_ops;
+
+ root = get_cramfs_inode(sb, &priv->super.root, 0);
+ if (IS_ERR(root))
+ return PTR_ERR(root);
+ sb->s_root = d_make_root(root);
+
return 0;
err_out:
@@ -461,14 +490,8 @@ static void cramfs_remove(struct device_d *dev)
}
static struct fs_driver_d cramfs_driver = {
- .open = cramfs_open,
- .close = cramfs_close,
.read = cramfs_read,
.lseek = cramfs_lseek,
- .opendir = cramfs_opendir,
- .readdir = cramfs_readdir,
- .closedir = cramfs_closedir,
- .stat = cramfs_stat,
.drv = {
.probe = cramfs_probe,
.remove = cramfs_remove,
diff --git a/fs/devfs.c b/fs/devfs.c
index 2a7b1b3466..5d0bb2c674 100644
--- a/fs/devfs.c
+++ b/fs/devfs.c
@@ -33,6 +33,11 @@
#include <linux/mtd/mtd-abi.h>
#include <partition.h>
+struct devfs_inode {
+ struct inode inode;
+ struct cdev *cdev;
+};
+
extern struct list_head cdev_list;
static int devfs_read(struct device_d *_dev, FILE *f, void *buf, size_t size)
@@ -110,14 +115,11 @@ static int devfs_memmap(struct device_d *_dev, FILE *f, void **map, int flags)
static int devfs_open(struct device_d *_dev, FILE *f, const char *filename)
{
- struct cdev *cdev;
+ struct inode *inode = f->f_inode;
+ struct devfs_inode *node = container_of(inode, struct devfs_inode, inode);
+ struct cdev *cdev = node->cdev;
int ret;
- cdev = cdev_by_name(filename + 1);
-
- if (!cdev)
- return -ENOENT;
-
f->size = cdev->flags & DEVFS_IS_CHARACTER_DEV ?
FILE_SIZE_STREAM : cdev->size;
f->priv = cdev;
@@ -180,71 +182,112 @@ static int devfs_truncate(struct device_d *dev, FILE *f, ulong size)
return 0;
}
-static DIR* devfs_opendir(struct device_d *dev, const char *pathname)
+static struct inode *devfs_alloc_inode(struct super_block *sb)
{
- DIR *dir;
-
- dir = xzalloc(sizeof(DIR));
+ struct devfs_inode *node;
- if (!list_empty(&cdev_list))
- dir->priv = list_first_entry(&cdev_list, struct cdev, list);
+ node = xzalloc(sizeof(*node));
+ if (!node)
+ return NULL;
- return dir;
+ return &node->inode;
}
-static struct dirent* devfs_readdir(struct device_d *_dev, DIR *dir)
+int devfs_iterate(struct file *file, struct dir_context *ctx)
{
- struct cdev *cdev = dir->priv;
+ struct cdev *cdev;
- if (!cdev)
- return NULL;
+ dir_emit_dots(file, ctx);
- list_for_each_entry_from(cdev, &cdev_list, list) {
- strcpy(dir->d.d_name, cdev->name);
- dir->priv = list_entry(cdev->list.next, struct cdev, list);
- return &dir->d;
+ list_for_each_entry(cdev, &cdev_list, list) {
+ dir_emit(ctx, cdev->name, strlen(cdev->name),
+ 1 /* FIXME */, DT_REG);
}
- return NULL;
+
+ return 0;
}
-static int devfs_closedir(struct device_d *dev, DIR *dir)
+static const struct inode_operations devfs_file_inode_operations;
+static const struct file_operations devfs_dir_operations;
+static const struct inode_operations devfs_dir_inode_operations;
+static const struct file_operations devfs_file_operations;
+
+static struct inode *devfs_get_inode(struct super_block *sb, const struct inode *dir,
+ umode_t mode)
{
- free(dir);
- return 0;
+ struct inode *inode = new_inode(sb);
+
+ if (!inode)
+ return NULL;
+
+ inode->i_ino = get_next_ino();
+ inode->i_mode = mode;
+
+ switch (mode & S_IFMT) {
+ default:
+ return NULL;
+ case S_IFREG:
+ inode->i_op = &devfs_file_inode_operations;
+ inode->i_fop = &devfs_file_operations;
+ break;
+ case S_IFDIR:
+ inode->i_op = &devfs_dir_inode_operations;
+ inode->i_fop = &devfs_dir_operations;
+ inc_nlink(inode);
+ break;
+ }
+
+ return inode;
}
-static int devfs_stat(struct device_d *_dev, const char *filename, struct stat *s)
+static struct dentry *devfs_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
{
+ struct devfs_inode *dinode;
+ struct inode *inode;
struct cdev *cdev;
- cdev = lcdev_by_name(filename + 1);
+ cdev = cdev_by_name(dentry->name);
if (!cdev)
- return -ENOENT;
+ return ERR_PTR(-ENOENT);
- s->st_mode = S_IFCHR;
- s->st_size = cdev->size;
+ inode = devfs_get_inode(dir->i_sb, dir, S_IFREG | S_IRWXUGO);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
- if (cdev->link)
- s->st_mode |= S_IFLNK;
+ dinode = container_of(inode, struct devfs_inode, inode);
- cdev = cdev_readlink(cdev);
+ inode->i_size = cdev->size;
+ dinode->cdev = cdev;
- if (cdev->ops->write)
- s->st_mode |= S_IWUSR;
- if (cdev->ops->read)
- s->st_mode |= S_IRUSR;
+ d_add(dentry, inode);
- return 0;
+ return NULL;
}
+static const struct file_operations devfs_dir_operations = {
+ .iterate = devfs_iterate,
+};
+
+static const struct inode_operations devfs_dir_inode_operations =
+{
+ .lookup = devfs_lookup,
+};
+
+static const struct super_operations devfs_ops = {
+ .alloc_inode = devfs_alloc_inode,
+};
+
static int devfs_probe(struct device_d *dev)
{
+ struct inode *inode;
struct fs_device_d *fsdev = dev_to_fs_device(dev);
+ struct super_block *sb = &fsdev->sb;
- if (strcmp(fsdev->path, "/dev")) {
- dev_err(dev, "devfs can only be mounted on /dev/\n");
- return -EINVAL;
- }
+ sb->s_op = &devfs_ops;
+
+ inode = devfs_get_inode(sb, NULL, S_IFDIR);
+ sb->s_root = d_make_root(inode);
return 0;
}
@@ -253,24 +296,6 @@ static void devfs_delete(struct device_d *dev)
{
}
-static int devfs_readlink(struct device_d *dev, const char *pathname,
- char *buf, size_t bufsz)
-{
- struct cdev *cdev;
-
- cdev = cdev_by_name(pathname + 1);
- if (!cdev)
- return -ENOENT;
-
- while (cdev->link)
- cdev = cdev->link;
-
- bufsz = min(bufsz, strlen(cdev->name));
- memcpy(buf, cdev->name, bufsz);
-
- return 0;
-}
-
static struct fs_driver_d devfs_driver = {
.read = devfs_read,
.write = devfs_write,
@@ -279,15 +304,10 @@ static struct fs_driver_d devfs_driver = {
.close = devfs_close,
.flush = devfs_flush,
.ioctl = devfs_ioctl,
- .opendir = devfs_opendir,
- .readdir = devfs_readdir,
.truncate = devfs_truncate,
- .closedir = devfs_closedir,
- .stat = devfs_stat,
.erase = devfs_erase,
.protect = devfs_protect,
.memmap = devfs_memmap,
- .readlink = devfs_readlink,
.flags = FS_DRIVER_NO_DEV,
.drv = {
.probe = devfs_probe,
diff --git a/fs/ext4/ext_barebox.c b/fs/ext4/ext_barebox.c
index e40278a5bd..1e7da2a4b4 100644
--- a/fs/ext4/ext_barebox.c
+++ b/fs/ext4/ext_barebox.c
@@ -46,34 +46,17 @@ int ext4fs_devread(struct ext_filesystem *fs, int __sector, int byte_offset,
return 0;
}
-static int ext_open(struct device_d *dev, FILE *file, const char *filename)
+static inline struct ext2fs_node *to_ext2_node(struct inode *inode)
{
- struct ext_filesystem *fs = dev->priv;
- struct ext2fs_node *inode;
- int ret;
-
- ret = ext4fs_open(fs->data, filename, &inode);
- if (ret)
- return ret;
-
- file->size = le32_to_cpu(inode->inode.size);
- file->priv = inode;
-
- return 0;
-}
-
-static int ext_close(struct device_d *dev, FILE *f)
-{
- struct ext_filesystem *fs = dev->priv;
-
- ext4fs_free_node(f->priv, &fs->data->diropen);
-
- return 0;
+ return container_of(inode, struct ext2fs_node, i);
}
static int ext_read(struct device_d *_dev, FILE *f, void *buf, size_t insize)
{
- return ext4fs_read_file(f->priv, f->pos, insize, buf);
+ struct inode *inode = f->f_inode;
+ struct ext2fs_node *node = to_ext2_node(inode);
+
+ return ext4fs_read_file(node, f->pos, insize, buf);
}
static loff_t ext_lseek(struct device_d *dev, FILE *f, loff_t pos)
@@ -83,143 +66,195 @@ static loff_t ext_lseek(struct device_d *dev, FILE *f, loff_t pos)
return f->pos;
}
-struct ext4fs_dir {
- struct ext2fs_node *dirnode;
- int fpos;
- DIR dir;
-};
-
-static DIR *ext_opendir(struct device_d *dev, const char *pathname)
+static struct inode *ext_alloc_inode(struct super_block *sb)
{
- struct ext_filesystem *fs = dev->priv;
- struct ext4fs_dir *ext4_dir;
- int type, ret;
-
- ext4_dir = xzalloc(sizeof(*ext4_dir));
-
- ret = ext4fs_find_file(pathname, &fs->data->diropen, &ext4_dir->dirnode,
- &type);
- if (ret) {
- free(ext4_dir);
- return NULL;
- }
+ struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb);
+ struct ext_filesystem *fs = fsdev->dev.priv;
+ struct ext2fs_node *node;
- if (type != FILETYPE_DIRECTORY)
+ node = xzalloc(sizeof(*node));
+ if (!node)
return NULL;
- ext4_dir->dir.priv = ext4_dir;
+ node->data = fs->data;
- ret = ext4fs_read_inode(ext4_dir->dirnode->data, ext4_dir->dirnode->ino,
- &ext4_dir->dirnode->inode);
- if (ret) {
- ext4fs_free_node(ext4_dir->dirnode, &fs->data->diropen);
- free(ext4_dir);
+ return &node->i;
+}
- return NULL;
- }
+static const struct super_operations ext_ops = {
+ .alloc_inode = ext_alloc_inode,
+};
- return &ext4_dir->dir;
-}
+struct inode *ext_get_inode(struct super_block *sb, int ino);
-static struct dirent *ext_readdir(struct device_d *dev, DIR *dir)
+static int ext4fs_get_ino(struct ext2fs_node *dir, struct qstr *name, int *inum)
{
- struct ext4fs_dir *ext4_dir = dir->priv;
- struct ext2_dirent dirent;
- struct ext2fs_node *diro = ext4_dir->dirnode;
+ unsigned int fpos = 0;
int ret;
- char *filename;
- if (ext4_dir->fpos >= le32_to_cpu(diro->inode.size))
- return NULL;
+ while (fpos < le32_to_cpu(dir->inode.size)) {
+ struct ext2_dirent dirent;
- ret = ext4fs_read_file(diro, ext4_dir->fpos, sizeof(struct ext2_dirent),
- (char *) &dirent);
- if (ret < 0)
- return NULL;
+ ret = ext4fs_read_file(dir, fpos, sizeof(dirent), (char *)&dirent);
+ if (ret < 1)
+ return -EINVAL;
- if (dirent.namelen == 0)
- return NULL;
+ if (dirent.namelen != 0) {
+ char filename[dirent.namelen];
+ int ino;
- filename = xzalloc(dirent.namelen + 1);
+ ret = ext4fs_read_file(dir, fpos + sizeof(dirent),
+ dirent.namelen, filename);
+ if (ret < 1)
+ return -EINVAL;
- ret = ext4fs_read_file(diro, ext4_dir->fpos + sizeof(struct ext2_dirent),
- dirent.namelen, filename);
- if (ret < 0) {
- free(filename);
- return NULL;
+ ino = le32_to_cpu(dirent.inode);
+
+ if (name->len == dirent.namelen &&
+ !strncmp(name->name, filename, name->len)) {
+ *inum = ino;
+ return 0;
+ }
+ }
+ fpos += le16_to_cpu(dirent.direntlen);
}
- filename[dirent.namelen] = '\0';
+ *inum = 0;
- ext4_dir->fpos += le16_to_cpu(dirent.direntlen);
+ return 0;
+}
- strcpy(dir->d.d_name, filename);
+static struct dentry *ext_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
+{
+ struct ext2fs_node *e2dir = to_ext2_node(dir);
+ int ret, ino;
+ struct inode *inode;
- free(filename);
+ ret = ext4fs_get_ino(e2dir, &dentry->d_name, &ino);
+ if (ret)
+ return ERR_PTR(ret);
- return &dir->d;
+ if (ino) {
+ inode = ext_get_inode(dir->i_sb, ino);
+
+ d_add(dentry, inode);
+ }
+
+ return NULL;
}
-static int ext_closedir(struct device_d *dev, DIR *dir)
+static const struct inode_operations ext_inode_operations = {
+ .lookup = ext_lookup,
+};
+
+static int ext_iterate(struct file *file, struct dir_context *ctx)
{
- struct ext_filesystem *fs = dev->priv;
- struct ext4fs_dir *ext4_dir = dir->priv;
+ struct dentry *dentry = file->f_path.dentry;
+ struct inode *dir = d_inode(dentry);
+ unsigned int fpos = 0;
+ int status, ret;
+ struct ext2fs_node *diro = to_ext2_node(dir);
+ void *buf;
- ext4fs_free_node(ext4_dir->dirnode, &fs->data->diropen);
+ buf = malloc(dir->i_size);
+ if (!buf)
+ return -ENOMEM;
- free(ext4_dir);
+ status = ext4fs_read_file(diro, 0, dir->i_size, buf);
+ if (status < 1) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ while (fpos < dir->i_size) {
+ const struct ext2_dirent *dirent = buf + fpos;
+ const char *filename = buf + fpos + sizeof(*dirent);
+
+ if (dirent->namelen != 0)
+ dir_emit(ctx, filename, dirent->namelen,
+ le32_to_cpu(dirent->inode), DT_UNKNOWN);
+
+ fpos += le16_to_cpu(dirent->direntlen);
+ }
+ ret = 0;
+out:
+ free(buf);
+
+ return ret;
- return 0;
}
-static int ext_stat(struct device_d *dev, const char *filename, struct stat *s)
+const struct file_operations ext_dir_operations = {
+ .iterate = ext_iterate,
+};
+
+static const char *ext_get_link(struct dentry *dentry, struct inode *inode)
{
- struct ext_filesystem *fs = dev->priv;
- struct ext2fs_node *node;
- int status, ret;
+ struct ext2fs_node *node = to_ext2_node(inode);
+ int ret;
- status = ext4fs_find_file(filename, &fs->data->diropen, &node, NULL);
- if (status)
- return -ENOENT;
+ if (inode->i_size < sizeof(node->inode.b.symlink))
+ return inode->i_link;
- ret = ext4fs_read_inode(node->data, node->ino, &node->inode);
- if (ret)
- return ret;
+ BUG_ON(inode->i_link);
- s->st_size = le32_to_cpu(node->inode.size);
- s->st_mode = le16_to_cpu(node->inode.mode);
+ inode->i_link = zalloc(inode->i_size + 1);
- ext4fs_free_node(node, &fs->data->diropen);
+ ret = ext4fs_read_file(node, 0, inode->i_size, inode->i_link);
+ if (ret == 0) {
+ free(inode->i_link);
+ inode->i_link = NULL;
+ }
- return 0;
+ return inode->i_link;
}
-static int ext_readlink(struct device_d *dev, const char *pathname,
- char *buf, size_t bufsiz)
+static const struct inode_operations ext_symlink_inode_operations =
{
- struct ext_filesystem *fs = dev->priv;
- struct ext2fs_node *node;
- char *symlink;
- int ret, len, type;
+ .get_link = ext_get_link,
+};
- ret = ext4fs_find_file(pathname, &fs->data->diropen, &node, &type);
- if (ret)
- return ret;
+struct inode *ext_get_inode(struct super_block *sb, int ino)
+{
+ struct inode *inode;
+ struct ext2fs_node *node;
+ struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb);
+ struct ext_filesystem *fs = fsdev->dev.priv;
+ int ret;
- if (type != FILETYPE_SYMLINK)
- return -EINVAL;
+ inode = new_inode(sb);
- symlink = ext4fs_read_symlink(node);
- if (!symlink)
- return -ENOENT;
+ node = container_of(inode, struct ext2fs_node, i);
- len = min(bufsiz, strlen(symlink));
+ ret = ext4fs_read_inode(fs->data, ino, &node->inode);
- memcpy(buf, symlink, len);
+ inode->i_ino = ino;
+ inode->i_mode = le16_to_cpu(node->inode.mode);
+ inode->i_size = le32_to_cpu(node->inode.size);
- free(symlink);
+ switch (inode->i_mode & S_IFMT) {
+ default:
+ return NULL;
+ case S_IFREG:
+ inode->i_op = &ext_inode_operations;
+ break;
+ case S_IFDIR:
+ inode->i_op = &ext_inode_operations;
+ inode->i_fop = &ext_dir_operations;
+ inc_nlink(inode);
+ break;
+ case S_IFLNK:
+ inode->i_op = &ext_symlink_inode_operations;
+ if (inode->i_size < sizeof(node->inode.b.symlink)) {
+ inode->i_link = zalloc(inode->i_size + 1);
+ strncpy(inode->i_link, node->inode.b.symlink,
+ inode->i_size);
+ }
+ break;
+ }
- return 0;
+ return inode;
}
static int ext_probe(struct device_d *dev)
@@ -227,6 +262,8 @@ static int ext_probe(struct device_d *dev)
struct fs_device_d *fsdev = dev_to_fs_device(dev);
int ret;
struct ext_filesystem *fs;
+ struct super_block *sb = &fsdev->sb;
+ struct inode *inode;
fs = xzalloc(sizeof(*fs));
@@ -243,6 +280,11 @@ static int ext_probe(struct device_d *dev)
if (ret)
goto err_mount;
+ sb->s_op = &ext_ops;
+
+ inode = ext_get_inode(sb, 2);
+ sb->s_root = d_make_root(inode);
+
return 0;
err_mount:
@@ -261,15 +303,8 @@ static void ext_remove(struct device_d *dev)
}
static struct fs_driver_d ext_driver = {
- .open = ext_open,
- .close = ext_close,
.read = ext_read,
.lseek = ext_lseek,
- .opendir = ext_opendir,
- .readdir = ext_readdir,
- .closedir = ext_closedir,
- .stat = ext_stat,
- .readlink = ext_readlink,
.type = filetype_ext,
.flags = 0,
.drv = {
diff --git a/fs/ext4/ext_common.h b/fs/ext4/ext_common.h
index e82b56b86a..c084cf9a32 100644
--- a/fs/ext4/ext_common.h
+++ b/fs/ext4/ext_common.h
@@ -30,6 +30,8 @@
#ifndef __EXT_COMMON__
#define __EXT_COMMON__
+#include <linux/fs.h>
+
#define SECTOR_SIZE 0x200
#define SECTOR_BITS 9
@@ -208,6 +210,7 @@ struct ext2_dirent {
};
struct ext2fs_node {
+ struct inode i;
struct ext2_data *data;
struct ext2_inode inode;
int ino;
diff --git a/fs/fat/Kconfig b/fs/fat/Kconfig
index 0699728494..b1def851cf 100644
--- a/fs/fat/Kconfig
+++ b/fs/fat/Kconfig
@@ -1,5 +1,6 @@
menuconfig FS_FAT
bool
+ select FS_LEGACY
prompt "FAT filesystem support"
if FS_FAT
diff --git a/fs/fs.c b/fs/fs.c
index 8a49e32b5c..41818ea811 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -36,6 +36,7 @@
#include <block.h>
#include <libfile.h>
#include <parseopt.h>
+#include <linux/namei.h>
char *mkmodestr(unsigned long mode, char *str)
{
@@ -69,8 +70,12 @@ char *mkmodestr(unsigned long mode, char *str)
EXPORT_SYMBOL(mkmodestr);
static char *cwd;
+static struct dentry *cwd_dentry;
+static struct vfsmount *cwd_mnt;
static FILE *files;
+static struct dentry *d_root;
+static struct vfsmount *mnt_root;
static int init_fs(void)
{
@@ -84,226 +89,40 @@ static int init_fs(void)
postcore_initcall(init_fs);
-char *normalise_path(const char *pathname)
-{
- char *path = xzalloc(strlen(pathname) + strlen(cwd) + 2);
- char *in, *out, *slashes[32];
- int sl = 0;
-
- debug("in: %s\n", pathname);
-
- if (*pathname != '/')
- strcpy(path, cwd);
- strcat(path, "/");
- strcat(path, pathname);
-
- slashes[0] = in = out = path;
-
- while (*in) {
- if(*in == '/') {
- slashes[sl++] = out;
- *out++ = *in++;
- while(*in == '/')
- in++;
- } else {
- if (*in == '.' && (*(in + 1) == '/' || !*(in + 1))) {
- sl--;
- if (sl < 0)
- sl = 0;
- out = slashes[sl];
- in++;
- continue;
- }
- if (*in == '.' && *(in + 1) == '.') {
- sl -= 2;
- if (sl < 0)
- sl = 0;
- out = slashes[sl];
- in += 2;
- continue;
- }
- *out++ = *in++;
- }
- }
-
- *out-- = 0;
-
- /*
- * Remove trailing slash
- */
- if (*out == '/')
- *out = 0;
-
- if (!*path) {
- *path = '/';
- *(path + 1) = 0;
- }
-
- return path;
-}
-EXPORT_SYMBOL(normalise_path);
-
-static int __lstat(const char *filename, struct stat *s);
static struct fs_device_d *get_fsdevice_by_path(const char *path);
-static char *__canonicalize_path(const char *_pathname, int level)
-{
- char *path, *freep;
- char *outpath;
- int ret;
- struct stat s;
-
- if (level > 10)
- return ERR_PTR(-ELOOP);
-
- path = freep = xstrdup(_pathname);
-
- if (*path == '/' || !strcmp(cwd, "/"))
- outpath = xstrdup("");
- else
- outpath = __canonicalize_path(cwd, level + 1);
-
- while (1) {
- char *p = strsep(&path, "/");
- char *tmp;
- char link[PATH_MAX] = {};
- struct fs_device_d *fsdev;
-
- if (!p)
- break;
- if (p[0] == '\0')
- continue;
- if (!strcmp(p, "."))
- continue;
- if (!strcmp(p, "..")) {
- tmp = xstrdup(dirname(outpath));
- free(outpath);
- outpath = tmp;
- continue;
- }
-
- tmp = basprintf("%s/%s", outpath, p);
- free(outpath);
- outpath = tmp;
-
- /*
- * Don't bother filesystems without link support
- * with an additional stat() call.
- */
- fsdev = get_fsdevice_by_path(outpath);
- if (!fsdev || !fsdev->driver->readlink)
- continue;
-
- ret = __lstat(outpath, &s);
- if (ret)
- goto out;
-
- if (!S_ISLNK(s.st_mode))
- continue;
-
- ret = readlink(outpath, link, PATH_MAX - 1);
- if (ret < 0)
- goto out;
-
- if (link[0] == '/') {
- free(outpath);
- outpath = __canonicalize_path(link, level + 1);
- } else {
- tmp = basprintf("%s/%s", dirname(outpath), link);
- free(outpath);
- outpath = __canonicalize_path(tmp, level + 1);
- free(tmp);
- }
-
- if (IS_ERR(outpath))
- goto out;
- }
-out:
- free(freep);
-
- if (!*outpath) {
- free(outpath);
- outpath = xstrdup("/");
- }
-
- return outpath;
-}
+LIST_HEAD(fs_device_list);
-/*
- * canonicalize_path - resolve links in path
- * @pathname: The input path
- *
- * This function resolves all links in @pathname and returns
- * a path without links in it.
- *
- * Return: Path with links resolved. Allocated, must be freed after use.
- */
-char *canonicalize_path(const char *pathname)
+struct vfsmount *mntget(struct vfsmount *mnt)
{
- char *r, *p = __canonicalize_path(pathname, 0);
-
- if (IS_ERR(p))
- return ERR_CAST(p);
+ if (!mnt)
+ return NULL;
- r = normalise_path(p);
- free(p);
+ mnt->ref++;
- return r;
+ return mnt;
}
-/*
- * canonicalize_dir - resolve links in path
- * @pathname: The input path
- *
- * This function resolves all links except the last one. Needed to give
- * access to the link itself.
- *
- * Return: Path with links resolved. Allocated, must be freed after use.
- */
-static char *canonicalize_dir(const char *pathname)
+void mntput(struct vfsmount *mnt)
{
- char *f, *d, *r, *ret, *p;
- char *freep1, *freep2;
-
- freep1 = xstrdup(pathname);
- freep2 = xstrdup(pathname);
- f = basename(freep1);
- d = dirname(freep2);
-
- p = __canonicalize_path(d, 0);
- if (IS_ERR(p)) {
- ret = ERR_CAST(p);
- goto out;
- }
-
- r = basprintf("%s/%s", p, f);
-
- ret = normalise_path(r);
-
- free(r);
- free(p);
-out:
- free(freep1);
- free(freep2);
+ if (!mnt)
+ return;
- return ret;
+ mnt->ref--;
}
-LIST_HEAD(fs_device_list);
-static struct fs_device_d *fs_dev_root;
-
-static struct fs_device_d *get_fsdevice_by_path(const char *path)
+struct vfsmount *lookup_mnt(struct path *path)
{
- struct fs_device_d *fsdev = NULL;
+ struct fs_device_d *fsdev;
for_each_fs_device(fsdev) {
- int len = strlen(fsdev->path);
- if (!strncmp(path, fsdev->path, len) &&
- (path[len] == '/' || path[len] == 0))
- return fsdev;
+ if (path->dentry == fsdev->vfsmount.mountpoint) {
+ mntget(&fsdev->vfsmount);
+ return &fsdev->vfsmount;
+ }
}
- return fs_dev_root;
+ return NULL;
}
/*
@@ -348,6 +167,8 @@ static void put_file(FILE *f)
free(f->path);
f->path = NULL;
f->in_use = 0;
+ iput(f->f_inode);
+ dput(f->dentry);
}
static int check_fd(int fd)
@@ -360,380 +181,20 @@ static int check_fd(int fd)
return 0;
}
-#ifdef CONFIG_FS_AUTOMOUNT
-
-#define AUTOMOUNT_IS_FILE (1 << 0)
-
-struct automount {
- char *path;
- char *cmd;
- struct list_head list;
- unsigned int flags;
-};
-
-static LIST_HEAD(automount_list);
-
-void automount_remove(const char *_path)
-{
- char *path = normalise_path(_path);
- struct automount *am;
-
- list_for_each_entry(am, &automount_list, list) {
- if (!strcmp(path, am->path))
- goto found;
- }
-
- return;
-found:
- list_del(&am->list);
- free(am->path);
- free(am->cmd);
- free(am);
-}
-EXPORT_SYMBOL(automount_remove);
-
-int automount_add(const char *path, const char *cmd)
-{
- struct automount *am = xzalloc(sizeof(*am));
- struct stat s;
- int ret;
-
- am->path = normalise_path(path);
- am->cmd = xstrdup(cmd);
-
- automount_remove(am->path);
-
- ret = stat(path, &s);
- if (!ret) {
- /*
- * If it exists it must be a directory
- */
- if (!S_ISDIR(s.st_mode))
- return -ENOTDIR;
- } else {
- am->flags |= AUTOMOUNT_IS_FILE;
- }
-
- list_add_tail(&am->list, &automount_list);
-
- return 0;
-}
-EXPORT_SYMBOL(automount_add);
-
-void cdev_create_default_automount(struct cdev *cdev)
-{
- char *path, *cmd;
-
- path = basprintf("/mnt/%s", cdev->name);
- cmd = basprintf("mount %s", cdev->name);
-
- make_directory(path);
- automount_add(path, cmd);
-
- free(cmd);
- free(path);
-}
-
-void automount_print(void)
-{
- struct automount *am;
-
- list_for_each_entry(am, &automount_list, list)
- printf("%-20s %s\n", am->path, am->cmd);
-}
-EXPORT_SYMBOL(automount_print);
-
-static void automount_mount(const char *path, int instat)
-{
- struct automount *am;
- int ret;
- static int in_automount;
-
- if (in_automount)
- return;
-
- in_automount++;
-
- if (fs_dev_root != get_fsdevice_by_path(path))
- goto out;
-
- list_for_each_entry(am, &automount_list, list) {
- int len_path = strlen(path);
- int len_am_path = strlen(am->path);
-
- /*
- * stat is a bit special. We do not want to trigger
- * automount when someone calls stat() on the automount
- * directory itself.
- */
- if (instat && !(am->flags & AUTOMOUNT_IS_FILE) &&
- len_path == len_am_path) {
- continue;
- }
-
- if (len_path < len_am_path)
- continue;
-
- if (strncmp(path, am->path, len_am_path))
- continue;
-
- if (*(path + len_am_path) != 0 && *(path + len_am_path) != '/')
- continue;
-
- setenv("automount_path", am->path);
- export("automount_path");
- ret = run_command(am->cmd);
- setenv("automount_path", NULL);
-
- if (ret)
- printf("running automount command '%s' failed\n",
- am->cmd);
-
- break;
- }
-out:
- in_automount--;
-}
-
-BAREBOX_MAGICVAR(automount_path, "mountpath passed to automount scripts");
-
-#else
-static void automount_mount(const char *path, int instat)
+int create(struct dentry *dir, struct dentry *dentry)
{
-}
-#endif /* CONFIG_FS_AUTOMOUNT */
+ struct inode *inode;
-static struct fs_device_d *get_fs_device_and_root_path(char **path)
-{
- struct fs_device_d *fsdev;
-
- automount_mount(*path, 0);
-
- fsdev = get_fsdevice_by_path(*path);
- if (!fsdev)
- return NULL;
- if (fsdev != fs_dev_root)
- *path += strlen(fsdev->path);
-
- return fsdev;
-}
-
-static int dir_is_empty(const char *pathname)
-{
- DIR *dir;
- struct dirent *d;
- int ret = 1;
-
- dir = opendir(pathname);
- if (!dir) {
- errno = ENOENT;
- return -ENOENT;
- }
-
- while ((d = readdir(dir))) {
- if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
- continue;
- ret = 0;
- break;
- }
-
- closedir(dir);
- return ret;
-}
-
-static int parent_check_directory(const char *path)
-{
- struct stat s;
- int ret;
- char *dir = dirname(xstrdup(path));
-
- ret = lstat(dir, &s);
-
- free(dir);
-
- if (ret)
+ if (d_is_negative(dir))
return -ENOENT;
- if (!S_ISDIR(s.st_mode))
- return -ENOTDIR;
-
- return 0;
-}
-
-const char *getcwd(void)
-{
- return cwd;
-}
-EXPORT_SYMBOL(getcwd);
-
-int chdir(const char *pathname)
-{
- char *p = normalise_path(pathname);
- int ret;
- struct stat s;
-
- ret = stat(p, &s);
- if (ret)
- goto out;
-
- if (!S_ISDIR(s.st_mode)) {
- ret = -ENOTDIR;
- goto out;
- }
-
- automount_mount(p, 0);
-
- strcpy(cwd, p);
-
-out:
- free(p);
-
- if (ret)
- errno = -ret;
-
- return ret;
-}
-EXPORT_SYMBOL(chdir);
-
-int unlink(const char *pathname)
-{
- struct fs_device_d *fsdev;
- struct fs_driver_d *fsdrv;
- char *p = canonicalize_dir(pathname);
- char *freep = p;
- int ret;
- struct stat s;
-
- ret = lstat(p, &s);
- if (ret)
- goto out;
-
- if (S_ISDIR(s.st_mode)) {
- ret = -EISDIR;
- goto out;
- }
-
- fsdev = get_fs_device_and_root_path(&p);
- if (!fsdev) {
- ret = -ENOENT;
- goto out;
- }
- fsdrv = fsdev->driver;
+ inode = d_inode(dir);
- if (!fsdrv->unlink) {
- ret = -ENOSYS;
- goto out;
- }
+ if (!inode->i_op->create)
+ return -EROFS;
- ret = fsdrv->unlink(&fsdev->dev, p);
- if (ret)
- errno = -ret;
-out:
- free(freep);
- if (ret)
- errno = -ret;
- return ret;
+ return inode->i_op->create(inode, dentry, S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO);
}
-EXPORT_SYMBOL(unlink);
-
-int open(const char *pathname, int flags, ...)
-{
- struct fs_device_d *fsdev;
- struct fs_driver_d *fsdrv;
- FILE *f;
- int exist_err = 0;
- struct stat s;
- char *path;
- char *freep;
- int ret;
-
- path = canonicalize_path(pathname);
- if (IS_ERR(path)) {
- ret = PTR_ERR(path);
- goto out2;
- }
-
- exist_err = stat(path, &s);
-
- freep = path;
-
- if (!exist_err && S_ISDIR(s.st_mode)) {
- ret = -EISDIR;
- goto out1;
- }
-
- if (exist_err && !(flags & O_CREAT)) {
- ret = exist_err;
- goto out1;
- }
-
- if (exist_err) {
- ret = parent_check_directory(path);
- if (ret)
- goto out1;
- }
-
- f = get_file();
- if (!f) {
- ret = -EMFILE;
- goto out1;
- }
-
- fsdev = get_fs_device_and_root_path(&path);
- if (!fsdev) {
- ret = -ENOENT;
- goto out;
- }
-
- fsdrv = fsdev->driver;
-
- f->fsdev = fsdev;
- f->flags = flags;
-
- if ((flags & O_ACCMODE) && !fsdrv->write) {
- ret = -EROFS;
- goto out;
- }
-
- if (exist_err) {
- if (NULL != fsdrv->create)
- ret = fsdrv->create(&fsdev->dev, path,
- S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO);
- else
- ret = -EROFS;
- if (ret)
- goto out;
- }
-
- f->path = xstrdup(path);
-
- ret = fsdrv->open(&fsdev->dev, f, path);
- if (ret)
- goto out;
-
- if (flags & O_TRUNC) {
- ret = fsdrv->truncate(&fsdev->dev, f, 0);
- f->size = 0;
- if (ret)
- goto out;
- }
-
- if (flags & O_APPEND)
- f->pos = f->size;
-
- free(freep);
- return f->no;
-
-out:
- put_file(f);
-out1:
- free(freep);
-out2:
- if (ret)
- errno = -ret;
- return ret;
-}
-EXPORT_SYMBOL(open);
int creat(const char *pathname, mode_t mode)
{
@@ -869,6 +330,7 @@ static ssize_t __write(FILE *f, const void *buf, size_t count)
goto out;
} else {
f->size = f->pos + count;
+ f->f_inode->i_size = f->size;
}
}
ret = fsdrv->write(&f->fsdev->dev, f, buf, count);
@@ -1097,7 +559,7 @@ int close(int fd)
{
struct fs_driver_d *fsdrv;
FILE *f;
- int ret;
+ int ret = 0;
if (check_fd(fd))
return -errno;
@@ -1105,7 +567,9 @@ int close(int fd)
f = &files[fd];
fsdrv = f->fsdev->driver;
- ret = fsdrv->close(&f->fsdev->dev, f);
+
+ if (fsdrv->close)
+ ret = fsdrv->close(&f->fsdev->dev, f);
put_file(f);
@@ -1116,91 +580,6 @@ int close(int fd)
}
EXPORT_SYMBOL(close);
-int readlink(const char *pathname, char *buf, size_t bufsiz)
-{
- struct fs_driver_d *fsdrv;
- struct fs_device_d *fsdev;
- char *p = canonicalize_dir(pathname);
- char *freep = p;
- int ret;
- struct stat s;
-
- ret = lstat(pathname, &s);
- if (ret)
- goto out;
-
- if (!S_ISLNK(s.st_mode)) {
- ret = -EINVAL;
- goto out;
- }
-
- fsdev = get_fs_device_and_root_path(&p);
- if (!fsdev) {
- ret = -ENODEV;
- goto out;
- }
- fsdrv = fsdev->driver;
-
- if (fsdrv->readlink)
- ret = fsdrv->readlink(&fsdev->dev, p, buf, bufsiz);
- else
- ret = -ENOSYS;
-
- if (ret)
- goto out;
-
-out:
- free(freep);
-
- if (ret)
- errno = -ret;
-
- return ret;
-}
-EXPORT_SYMBOL(readlink);
-
-int symlink(const char *pathname, const char *newpath)
-{
- struct fs_driver_d *fsdrv;
- struct fs_device_d *fsdev;
- char *p;
- int ret;
- struct stat s;
-
- p = canonicalize_path(newpath);
- if (IS_ERR(p)) {
- ret = PTR_ERR(p);
- goto out;
- }
-
- ret = lstat(p, &s);
- if (!ret) {
- ret = -EEXIST;
- goto out;
- }
-
- fsdev = get_fs_device_and_root_path(&p);
- if (!fsdev) {
- ret = -ENODEV;
- goto out;
- }
- fsdrv = fsdev->driver;
-
- if (fsdrv->symlink) {
- ret = fsdrv->symlink(&fsdev->dev, pathname, p);
- } else {
- ret = -EPERM;
- }
-
-out:
- free(p);
- if (ret)
- errno = -ret;
-
- return ret;
-}
-EXPORT_SYMBOL(symlink);
-
static int fs_match(struct device_d *dev, struct driver_d *drv)
{
return strcmp(dev->name, drv->name) ? -1 : 0;
@@ -1221,15 +600,56 @@ static int fs_probe(struct device_d *dev)
list_add_tail(&fsdev->list, &fs_device_list);
- if (!fs_dev_root)
- fs_dev_root = fsdev;
+ if (IS_ENABLED(CONFIG_FS_LEGACY) && !fsdev->sb.s_root) {
+ ret = fs_init_legacy(fsdev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+void dentry_kill(struct dentry *dentry)
+{
+ if (dentry->d_inode)
+ iput(dentry->d_inode);
+
+ if (!IS_ROOT(dentry))
+ dput(dentry->d_parent);
+
+ list_del(&dentry->d_child);
+ free(dentry->name);
+ free(dentry);
+}
+
+int dentry_delete_subtree(struct super_block *sb, struct dentry *parent)
+{
+ struct dentry *dentry, *tmp;
+
+ if (!parent)
+ return 0;
+
+ list_for_each_entry_safe(dentry, tmp, &parent->d_subdirs, d_child)
+ dentry_delete_subtree(sb, dentry);
+
+ dentry_kill(parent);
return 0;
}
+static void destroy_inode(struct inode *inode)
+{
+ if (inode->i_sb->s_op->destroy_inode)
+ inode->i_sb->s_op->destroy_inode(inode);
+ else
+ free(inode);
+}
+
static void fs_remove(struct device_d *dev)
{
struct fs_device_d *fsdev = dev_to_fs_device(dev);
+ struct super_block *sb = &fsdev->sb;
+ struct inode *inode, *tmp;
if (fsdev->dev.driver) {
dev->driver->remove(dev);
@@ -1239,15 +659,23 @@ static void fs_remove(struct device_d *dev)
free(fsdev->path);
free(fsdev->options);
- if (fsdev == fs_dev_root)
- fs_dev_root = NULL;
-
if (fsdev->cdev)
cdev_close(fsdev->cdev);
- if (fsdev->loop)
+ if (fsdev->loop && fsdev->cdev)
cdev_remove_loop(fsdev->cdev);
+ dput(sb->s_root);
+ dentry_delete_subtree(sb, sb->s_root);
+
+ list_for_each_entry_safe(inode, tmp, &sb->s_inodes, i_sb_list)
+ destroy_inode(inode);
+
+ if (fsdev->vfsmount.mountpoint)
+ fsdev->vfsmount.mountpoint->d_flags &= ~DCACHE_MOUNTED;
+
+ mntput(fsdev->vfsmount.parent);
+
free(fsdev->backingstore);
free(fsdev);
}
@@ -1322,551 +750,2319 @@ int fsdev_open_cdev(struct fs_device_d *fsdev)
return 0;
}
+static void init_super(struct super_block *sb)
+{
+ INIT_LIST_HEAD(&sb->s_inodes);
+}
+
+static int fsdev_umount(struct fs_device_d *fsdev)
+{
+ if (fsdev->vfsmount.ref)
+ return -EBUSY;
+
+ return unregister_device(&fsdev->dev);
+}
+
+/**
+ * umount_by_cdev Use a cdev struct to umount all mounted filesystems
+ * @param cdev cdev to the according device
+ * @return 0 on success or if cdev was not mounted, -errno otherwise
+ */
+int umount_by_cdev(struct cdev *cdev)
+{
+ struct fs_device_d *fs;
+ struct fs_device_d *fs_tmp;
+ int first_error = 0;
+
+ for_each_fs_device_safe(fs_tmp, fs) {
+ int ret;
+
+ if (fs->cdev == cdev) {
+ ret = fsdev_umount(fs);
+ if (ret) {
+ pr_err("Failed umounting %s, %d, continuing anyway\n",
+ fs->path, ret);
+ if (!first_error)
+ first_error = ret;
+ }
+ }
+ }
+
+ return first_error;
+}
+EXPORT_SYMBOL(umount_by_cdev);
+
+struct readdir_entry {
+ struct dirent d;
+ struct list_head list;
+};
+
+struct readdir_callback {
+ struct dir_context ctx;
+ DIR *dir;
+};
+
+static int fillonedir(struct dir_context *ctx, const char *name, int namlen,
+ loff_t offset, u64 ino, unsigned int d_type)
+{
+ struct readdir_callback *rd = container_of(ctx, struct readdir_callback, ctx);
+ struct readdir_entry *entry;
+
+ entry = xzalloc(sizeof(*entry));
+ if (!entry)
+ return -ENOMEM;
+
+ memcpy(entry->d.d_name, name, namlen);
+ list_add_tail(&entry->list, &rd->dir->entries);
+
+ return 0;
+}
+
+struct dirent *readdir(DIR *dir)
+{
+ struct readdir_entry *entry;
+
+ if (!dir)
+ return NULL;
+
+ if (list_empty(&dir->entries))
+ return NULL;
+
+ entry = list_first_entry(&dir->entries, struct readdir_entry, list);
+
+ list_del(&entry->list);
+ strcpy(dir->d.d_name, entry->d.d_name);
+ free(entry);
+
+ return &dir->d;
+}
+EXPORT_SYMBOL(readdir);
+
+static void stat_inode(struct inode *inode, struct stat *s)
+{
+ s->st_dev = 0;
+ s->st_ino = inode->i_ino;
+ s->st_mode = inode->i_mode;
+ s->st_uid = inode->i_uid;
+ s->st_gid = inode->i_gid;
+ s->st_size = inode->i_size;
+}
+
+int fstat(int fd, struct stat *s)
+{
+ FILE *f;
+ struct fs_device_d *fsdev;
+
+ if (check_fd(fd))
+ return -errno;
+
+ f = &files[fd];
+
+ fsdev = f->fsdev;
+
+ stat_inode(f->f_inode, s);
+
+ return 0;
+}
+EXPORT_SYMBOL(fstat);
+
/*
- * Mount a device to a directory.
- * We do this by registering a new device on which the filesystem
- * driver will match.
+ * cdev_get_mount_path - return the path a cdev is mounted on
+ *
+ * If a cdev is mounted return the path it's mounted on, NULL
+ * otherwise.
*/
-int mount(const char *device, const char *fsname, const char *_path,
- const char *fsoptions)
+const char *cdev_get_mount_path(struct cdev *cdev)
{
struct fs_device_d *fsdev;
+
+ for_each_fs_device(fsdev) {
+ if (fsdev->cdev && fsdev->cdev == cdev)
+ return fsdev->path;
+ }
+
+ return NULL;
+}
+
+/*
+ * cdev_mount_default - mount a cdev to the default path
+ *
+ * If a cdev is already mounted return the path it's mounted on, otherwise
+ * mount it to /mnt/<cdevname> and return the path. Returns an error pointer
+ * on failure.
+ */
+const char *cdev_mount_default(struct cdev *cdev, const char *fsoptions)
+{
+ const char *path;
+ char *newpath, *devpath;
int ret;
- char *path = normalise_path(_path);
- if (!fsoptions)
- fsoptions = "";
+ /*
+ * If this cdev is already mounted somewhere use this path
+ * instead of mounting it again to avoid corruption on the
+ * filesystem. Note this ignores eventual fsoptions though.
+ */
+ path = cdev_get_mount_path(cdev);
+ if (path)
+ return path;
- debug("mount: %s on %s type %s, options=%s\n",
- device, path, fsname, fsoptions);
+ newpath = basprintf("/mnt/%s", cdev->name);
+ make_directory(newpath);
- if (fs_dev_root) {
- struct stat s;
+ devpath = basprintf("/dev/%s", cdev->name);
- fsdev = get_fsdevice_by_path(path);
- if (fsdev != fs_dev_root) {
- printf("sorry, no nested mounts\n");
- ret = -EBUSY;
- goto err_free_path;
- }
- ret = lstat(path, &s);
- if (ret)
- goto err_free_path;
- if (!S_ISDIR(s.st_mode)) {
- ret = -ENOTDIR;
- goto err_free_path;
+ ret = mount(devpath, NULL, newpath, fsoptions);
+
+ free(devpath);
+
+ if (ret) {
+ free(newpath);
+ return ERR_PTR(ret);
+ }
+
+ return cdev_get_mount_path(cdev);
+}
+
+/*
+ * mount_all - iterate over block devices and mount all devices we are able to
+ */
+void mount_all(void)
+{
+ struct device_d *dev;
+ struct block_device *bdev;
+
+ if (!IS_ENABLED(CONFIG_BLOCK))
+ return;
+
+ for_each_device(dev)
+ device_detect(dev);
+
+ for_each_block_device(bdev) {
+ struct cdev *cdev = &bdev->cdev;
+
+ list_for_each_entry(cdev, &bdev->dev->cdevs, devices_list)
+ cdev_mount_default(cdev, NULL);
+ }
+}
+
+void fsdev_set_linux_rootarg(struct fs_device_d *fsdev, const char *str)
+{
+ fsdev->linux_rootarg = xstrdup(str);
+
+ dev_add_param_fixed(&fsdev->dev, "linux.bootargs", fsdev->linux_rootarg);
+}
+
+/**
+ * path_get_linux_rootarg() - Given a path return a suitable root= option for
+ * Linux
+ * @path: The path
+ *
+ * Return: A string containing the root= option or an ERR_PTR. the returned
+ * string must be freed by the caller.
+ */
+char *path_get_linux_rootarg(const char *path)
+{
+ struct fs_device_d *fsdev;
+ const char *str;
+
+ fsdev = get_fsdevice_by_path(path);
+ if (!fsdev)
+ return ERR_PTR(-EINVAL);
+
+ str = dev_get_param(&fsdev->dev, "linux.bootargs");
+ if (!str)
+ return ERR_PTR(-ENOSYS);
+
+ return xstrdup(str);
+}
+
+/**
+ * __is_tftp_fs() - return true when path is mounted on TFTP
+ * @path: The path
+ *
+ * Do not use directly, use is_tftp_fs instead.
+ *
+ * Return: true when @path is on TFTP, false otherwise
+ */
+bool __is_tftp_fs(const char *path)
+{
+ struct fs_device_d *fsdev;
+
+ fsdev = get_fsdevice_by_path(path);
+ if (!fsdev)
+ return false;
+
+ if (strcmp(fsdev->driver->drv.name, "tftp"))
+ return false;
+
+ return true;
+}
+
+/* inode.c */
+unsigned int get_next_ino(void)
+{
+ static unsigned int ino;
+
+ return ++ino;
+}
+
+void drop_nlink(struct inode *inode)
+{
+ WARN_ON(inode->i_nlink == 0);
+ inode->__i_nlink--;
+}
+
+void inc_nlink(struct inode *inode)
+{
+ inode->__i_nlink++;
+}
+
+static struct inode *alloc_inode(struct super_block *sb)
+{
+ static const struct inode_operations empty_iops;
+ static const struct file_operations no_open_fops;
+ struct inode *inode;
+
+ if (sb->s_op->alloc_inode)
+ inode = sb->s_op->alloc_inode(sb);
+ else
+ inode = xzalloc(sizeof(*inode));
+
+ inode->i_op = &empty_iops;
+ inode->i_fop = &no_open_fops;
+ inode->__i_nlink = 1;
+ inode->i_count = 1;
+
+ return inode;
+}
+
+struct inode *new_inode(struct super_block *sb)
+{
+ struct inode *inode;
+
+ inode = alloc_inode(sb);
+ if (!inode)
+ return NULL;
+
+ inode->i_sb = sb;
+
+ list_add(&inode->i_sb_list, &sb->s_inodes);
+
+ return inode;
+}
+
+void iput(struct inode *inode)
+{
+ if (!inode->i_count)
+ return;
+
+ inode->i_count--;
+}
+
+struct inode *iget(struct inode *inode)
+{
+ inode->i_count++;
+
+ return inode;
+}
+
+/* dcache.c */
+
+/*
+ * refcounting is implemented but right now we do not do anything with
+ * the refcounting information. Dentries are never freed unless the
+ * filesystem they are on is unmounted. In this case we do not care
+ * about the refcounts so we may free up a dentry that is actually used
+ * (file is opened). This leaves room for improvements.
+ */
+void dput(struct dentry *dentry)
+{
+ if (!dentry)
+ return;
+
+ if (!dentry->d_count)
+ return;
+
+ dentry->d_count--;
+}
+
+struct dentry *dget(struct dentry *dentry)
+{
+ if (!dentry)
+ return NULL;
+
+ dentry->d_count++;
+
+ return dentry;
+}
+
+const struct qstr slash_name = QSTR_INIT("/", 1);
+
+void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
+{
+ dentry->d_op = op;
+}
+
+/**
+ * __d_alloc - allocate a dcache entry
+ * @sb: filesystem it will belong to
+ * @name: qstr of the name
+ *
+ * Allocates a dentry. It returns %NULL if there is insufficient memory
+ * available. On a success the dentry is returned. The name passed in is
+ * copied and the copy passed in may be reused after this call.
+ */
+struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
+{
+ struct dentry *dentry;
+
+ dentry = xzalloc(sizeof(*dentry));
+ if (!dentry)
+ return NULL;
+
+ if (!name)
+ name = &slash_name;
+
+ dentry->name = malloc(name->len + 1);
+ if (!dentry->name)
+ return NULL;
+
+ memcpy(dentry->name, name->name, name->len);
+ dentry->name[name->len] = 0;
+
+ dentry->d_name.len = name->len;
+ dentry->d_name.name = dentry->name;
+
+ dentry->d_count = 1;
+ dentry->d_parent = dentry;
+ dentry->d_sb = sb;
+ INIT_LIST_HEAD(&dentry->d_subdirs);
+ INIT_LIST_HEAD(&dentry->d_child);
+ d_set_d_op(dentry, dentry->d_sb->s_d_op);
+
+ return dentry;
+}
+
+/**
+ * d_alloc - allocate a dcache entry
+ * @parent: parent of entry to allocate
+ * @name: qstr of the name
+ *
+ * Allocates a dentry. It returns %NULL if there is insufficient memory
+ * available. On a success the dentry is returned. The name passed in is
+ * copied and the copy passed in may be reused after this call.
+ */
+struct dentry *d_alloc(struct dentry *parent, const struct qstr *name)
+{
+ struct dentry *dentry = __d_alloc(parent->d_sb, name);
+ if (!dentry)
+ return NULL;
+
+ dget(parent);
+
+ dentry->d_parent = parent;
+ list_add(&dentry->d_child, &parent->d_subdirs);
+
+ return dentry;
+}
+
+struct dentry *d_alloc_anon(struct super_block *sb)
+{
+ return __d_alloc(sb, NULL);
+}
+
+static unsigned d_flags_for_inode(struct inode *inode)
+{
+ if (!inode)
+ return DCACHE_MISS_TYPE;
+
+ if (S_ISDIR(inode->i_mode))
+ return DCACHE_DIRECTORY_TYPE;
+
+ if (inode->i_op->get_link)
+ return DCACHE_SYMLINK_TYPE;
+
+ return DCACHE_REGULAR_TYPE;
+}
+
+void d_instantiate(struct dentry *dentry, struct inode *inode)
+{
+ dentry->d_inode = inode;
+ dentry->d_flags &= ~DCACHE_ENTRY_TYPE;
+ dentry->d_flags |= d_flags_for_inode(inode);
+}
+
+struct dentry *d_make_root(struct inode *inode)
+{
+ struct dentry *res;
+
+ if (!inode)
+ return NULL;
+
+ res = d_alloc_anon(inode->i_sb);
+ if (!res)
+ return NULL;
+
+ d_instantiate(res, inode);
+
+ return res;
+}
+
+void d_add(struct dentry *dentry, struct inode *inode)
+{
+ dentry->d_inode = inode;
+ dentry->d_flags &= ~DCACHE_ENTRY_TYPE;
+ dentry->d_flags |= d_flags_for_inode(inode);
+}
+
+static bool d_same_name(const struct dentry *dentry,
+ const struct dentry *parent,
+ const struct qstr *name)
+{
+ if (dentry->d_name.len != name->len)
+ return false;
+
+ return strncmp(dentry->d_name.name, name->name, name->len) == 0;
+}
+
+struct dentry *d_lookup(const struct dentry *parent, const struct qstr *name)
+{
+ struct dentry *dentry;
+
+ list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
+ if (!d_same_name(dentry, parent, name))
+ continue;
+
+ dget(dentry);
+
+ return dentry;
+ }
+
+ return NULL;
+}
+
+void d_invalidate(struct dentry *dentry)
+{
+}
+
+static inline void __d_clear_type_and_inode(struct dentry *dentry)
+{
+ dentry->d_flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU);
+
+ dentry->d_inode = NULL;
+}
+
+/*
+ * Release the dentry's inode, using the filesystem
+ * d_iput() operation if defined.
+ */
+static void dentry_unlink_inode(struct dentry * dentry)
+{
+ struct inode *inode = dentry->d_inode;
+
+ __d_clear_type_and_inode(dentry);
+ iput(inode);
+}
+
+void d_delete(struct dentry * dentry)
+{
+ dentry_unlink_inode(dentry);
+}
+
+/*
+ * These are the Linux name resolve functions from fs/namei.c
+ *
+ * The implementation is more or less directly ported from the
+ * Linux Kernel (as of Linux-4.16) minus the RCU and locking code.
+ */
+
+enum {WALK_FOLLOW = 1, WALK_MORE = 2};
+
+/*
+ * Define EMBEDDED_LEVELS to MAXSYMLINKS so we do not have to
+ * dynamically allocate a path stack.
+ */
+#define EMBEDDED_LEVELS MAXSYMLINKS
+
+struct nameidata {
+ struct path path;
+ struct qstr last;
+ struct inode *inode; /* path.dentry.d_inode */
+ unsigned int flags;
+ unsigned seq, m_seq;
+ int last_type;
+ unsigned depth;
+ int total_link_count;
+ struct saved {
+ struct path link;
+ const char *name;
+ unsigned seq;
+ } *stack, internal[EMBEDDED_LEVELS];
+ struct filename *name;
+ struct nameidata *saved;
+ struct inode *link_inode;
+ unsigned root_seq;
+ int dfd;
+};
+
+struct filename {
+ char *name;
+ int refcnt;
+};
+
+static void set_nameidata(struct nameidata *p, int dfd, struct filename *name)
+{
+ p->stack = p->internal;
+ p->dfd = dfd;
+ p->name = name;
+ p->total_link_count = 0;
+}
+
+void path_get(const struct path *path)
+{
+ mntget(path->mnt);
+ dget(path->dentry);
+}
+
+void path_put(const struct path *path)
+{
+ dput(path->dentry);
+ mntput(path->mnt);
+}
+
+static inline void get_root(struct path *root)
+{
+ root->dentry = d_root;
+ root->mnt = mnt_root;
+
+ path_get(root);
+}
+
+static inline void get_pwd(struct path *pwd)
+{
+ if (!cwd_dentry) {
+ cwd_dentry = d_root;
+ cwd_mnt = mnt_root;
+ }
+
+ pwd->dentry = cwd_dentry;
+ pwd->mnt = cwd_mnt;
+
+ path_get(pwd);
+}
+
+static inline void put_link(struct nameidata *nd)
+{
+ struct saved *last = nd->stack + --nd->depth;
+ path_put(&last->link);
+}
+
+static int automount_mount(struct dentry *dentry);
+
+static void path_put_conditional(struct path *path, struct nameidata *nd)
+{
+ dput(path->dentry);
+ if (path->mnt != nd->path.mnt)
+ mntput(path->mnt);
+}
+
+static int follow_automount(struct path *path, struct nameidata *nd,
+ bool *need_mntput)
+{
+ /* We don't want to mount if someone's just doing a stat -
+ * unless they're stat'ing a directory and appended a '/' to
+ * the name.
+ *
+ * We do, however, want to mount if someone wants to open or
+ * create a file of any type under the mountpoint, wants to
+ * traverse through the mountpoint or wants to open the
+ * mounted directory. Also, autofs may mark negative dentries
+ * as being automount points. These will need the attentions
+ * of the daemon to instantiate them before they can be used.
+ */
+ if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY |
+ LOOKUP_OPEN | LOOKUP_CREATE | LOOKUP_AUTOMOUNT)) &&
+ path->dentry->d_inode)
+ return -EISDIR;
+
+ return automount_mount(path->dentry);
+}
+
+/*
+ * Handle a dentry that is managed in some way.
+ * - Flagged for transit management (autofs)
+ * - Flagged as mountpoint
+ * - Flagged as automount point
+ *
+ * This may only be called in refwalk mode.
+ *
+ * Serialization is taken care of in namespace.c
+ */
+static int follow_managed(struct path *path, struct nameidata *nd)
+{
+ struct vfsmount *mnt = path->mnt;
+ unsigned managed = path->dentry->d_flags;
+ bool need_mntput = false;
+ int ret = 0;
+
+ while (managed = path->dentry->d_flags,
+ managed &= DCACHE_MANAGED_DENTRY,
+ managed != 0) {
+
+ if (managed & DCACHE_MOUNTED) {
+ struct vfsmount *mounted = lookup_mnt(path);
+
+ if (mounted) {
+ dput(path->dentry);
+ if (need_mntput)
+ mntput(path->mnt);
+ path->mnt = mounted;
+ path->dentry = dget(mounted->mnt_root);
+ need_mntput = true;
+ continue;
+ }
}
- } else {
- /* no mtab, so we only allow to mount on '/' */
- if (*path != '/' || *(path + 1)) {
- ret = -ENOTDIR;
- goto err_free_path;
+
+ /* Handle an automount point */
+ if (managed & DCACHE_NEED_AUTOMOUNT) {
+ ret = follow_automount(path, nd, &need_mntput);
+ if (ret < 0)
+ break;
+ continue;
}
+
+ /* We didn't change the current path point */
+ break;
}
- if (!fsname)
- fsname = detect_fs(device, fsoptions);
+ if (need_mntput && path->mnt == mnt)
+ mntput(path->mnt);
+ if (ret == -EISDIR || !ret)
+ ret = 1;
+ if (need_mntput)
+ nd->flags |= LOOKUP_JUMPED;
+ if (ret < 0)
+ path_put_conditional(path, nd);
+ return ret;
+}
- if (!fsname)
+static struct dentry *__lookup_hash(const struct qstr *name,
+ struct dentry *base, unsigned int flags)
+{
+ struct dentry *dentry;
+ struct dentry *old;
+ struct inode *dir = base->d_inode;
+
+ if (!base)
+ return ERR_PTR(-ENOENT);
+
+ dentry = d_lookup(base, name);
+ if (dentry)
+ return dentry;
+
+ dentry = d_alloc(base, name);
+ if (unlikely(!dentry))
+ return ERR_PTR(-ENOMEM);
+
+ old = dir->i_op->lookup(dir, dentry, flags);
+ if (IS_ERR(old)) {
+ dput(dentry);
+ return old;
+ }
+
+ if (unlikely(old)) {
+ dput(dentry);
+ dentry = old;
+ }
+
+ return dentry;
+}
+
+static int lookup_fast(struct nameidata *nd, struct path *path)
+{
+ struct dentry *dentry, *parent = nd->path.dentry;
+
+ dentry = __lookup_hash(&nd->last, parent, 0);
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+
+ if (d_is_negative(dentry)) {
+ dput(dentry);
return -ENOENT;
+ }
- fsdev = xzalloc(sizeof(struct fs_device_d));
- fsdev->backingstore = xstrdup(device);
- safe_strncpy(fsdev->dev.name, fsname, MAX_DRIVER_NAME);
- fsdev->dev.id = get_free_deviceid(fsdev->dev.name);
- fsdev->path = xstrdup(path);
- fsdev->dev.bus = &fs_bus;
- fsdev->options = xstrdup(fsoptions);
+ path->dentry = dentry;
+ path->mnt = nd->path.mnt;
- ret = register_device(&fsdev->dev);
- if (ret)
- goto err_register;
+ return follow_managed(path, nd);
+}
- if (!fsdev->dev.driver) {
- /*
- * Driver didn't accept the device or no driver for this
- * device. Bail out
- */
- ret = -EINVAL;
- goto err_no_driver;
+/*
+ * follow_up - Find the mountpoint of path's vfsmount
+ *
+ * Given a path, find the mountpoint of its source file system.
+ * Replace @path with the path of the mountpoint in the parent mount.
+ * Up is towards /.
+ *
+ * Return 1 if we went up a level and 0 if we were already at the
+ * root.
+ */
+int follow_up(struct path *path)
+{
+ struct vfsmount *parent, *mnt = path->mnt;
+ struct dentry *mountpoint;
+
+ parent = mnt->parent;
+ if (parent == mnt)
+ return 0;
+
+ mntget(parent);
+ mountpoint = dget(mnt->mountpoint);
+ dput(path->dentry);
+ path->dentry = mountpoint;
+ mntput(path->mnt);
+ path->mnt = mnt->parent;
+
+ return 1;
+}
+
+static void follow_mount(struct path *path)
+{
+ while (d_mountpoint(path->dentry)) {
+ struct vfsmount *mounted = lookup_mnt(path);
+ if (!mounted)
+ break;
+ dput(path->dentry);
+ path->mnt = mounted;
+ path->dentry = dget(mounted->mnt_root);
}
+}
- if (!fsdev->linux_rootarg && fsdev->cdev && fsdev->cdev->partuuid[0] != 0) {
- char *str = basprintf("root=PARTUUID=%s",
- fsdev->cdev->partuuid);
+static int path_parent_directory(struct path *path)
+{
+ struct dentry *old = path->dentry;
- fsdev_set_linux_rootarg(fsdev, str);
+ path->dentry = dget(path->dentry->d_parent);
+ dput(old);
+
+ return 0;
+}
+
+static int follow_dotdot(struct nameidata *nd)
+{
+ while (1) {
+ if (nd->path.dentry != nd->path.mnt->mnt_root) {
+ int ret = path_parent_directory(&nd->path);
+ if (ret)
+ return ret;
+ break;
+ }
+
+ if (!follow_up(&nd->path))
+ break;
}
- free(path);
+ follow_mount(&nd->path);
+
+ nd->inode = nd->path.dentry->d_inode;
return 0;
+}
-err_no_driver:
- unregister_device(&fsdev->dev);
-err_register:
- fs_remove(&fsdev->dev);
-err_free_path:
- free(path);
+static inline int handle_dots(struct nameidata *nd, int type)
+{
+ if (type == LAST_DOTDOT) {
+ return follow_dotdot(nd);
+ }
+ return 0;
+}
- errno = -ret;
+static inline void path_to_nameidata(const struct path *path,
+ struct nameidata *nd)
+{
+ dput(nd->path.dentry);
+ if (nd->path.mnt != path->mnt)
+ mntput(nd->path.mnt);
+ nd->path.mnt = path->mnt;
+ nd->path.dentry = path->dentry;
+}
- return ret;
+static const char *get_link(struct nameidata *nd)
+{
+ struct saved *last = nd->stack + nd->depth - 1;
+ struct dentry *dentry = last->link.dentry;
+ struct inode *inode = nd->link_inode;
+ const char *res;
+
+ nd->last_type = LAST_BIND;
+ res = inode->i_link;
+ if (!res) {
+ res = inode->i_op->get_link(dentry, inode);
+ if (IS_ERR_OR_NULL(res))
+ return res;
+ }
+ if (*res == '/') {
+ while (unlikely(*++res == '/'))
+ ;
+ }
+ if (!*res)
+ res = NULL;
+ return res;
}
-EXPORT_SYMBOL(mount);
-static int fsdev_umount(struct fs_device_d *fsdev)
+static int pick_link(struct nameidata *nd, struct path *link,
+ struct inode *inode)
{
- return unregister_device(&fsdev->dev);
+ struct saved *last;
+
+ if (unlikely(nd->total_link_count++ >= MAXSYMLINKS)) {
+ path_to_nameidata(link, nd);
+ return -ELOOP;
+ }
+
+ if (link->mnt == nd->path.mnt)
+ mntget(link->mnt);
+
+ last = nd->stack + nd->depth++;
+ last->link = *link;
+ nd->link_inode = inode;
+
+ return 1;
}
-/**
- * umount_by_cdev Use a cdev struct to umount all mounted filesystems
- * @param cdev cdev to the according device
- * @return 0 on success or if cdev was not mounted, -errno otherwise
+/*
+ * Do we need to follow links? We _really_ want to be able
+ * to do this check without having to look at inode->i_op,
+ * so we keep a cache of "no, this doesn't need follow_link"
+ * for the common case.
*/
-int umount_by_cdev(struct cdev *cdev)
+static inline int step_into(struct nameidata *nd, struct path *path,
+ int flags, struct inode *inode)
{
- struct fs_device_d *fs;
- struct fs_device_d *fs_tmp;
- int first_error = 0;
+ if (!(flags & WALK_MORE) && nd->depth)
+ put_link(nd);
- for_each_fs_device_safe(fs_tmp, fs) {
- int ret;
+ if (likely(!d_is_symlink(path->dentry)) ||
+ !(flags & WALK_FOLLOW || nd->flags & LOOKUP_FOLLOW)) {
+ /* not a symlink or should not follow */
+ path_to_nameidata(path, nd);
+ nd->inode = inode;
+ return 0;
+ }
- if (fs->cdev == cdev) {
- ret = fsdev_umount(fs);
- if (ret) {
- pr_err("Failed umounting %s, %d, continuing anyway\n",
- fs->path, ret);
- if (!first_error)
- first_error = ret;
- }
+ return pick_link(nd, path, inode);
+}
+
+static int walk_component(struct nameidata *nd, int flags)
+{
+ struct path path;
+ int err;
+
+ /*
+ * "." and ".." are special - ".." especially so because it has
+ * to be able to know about the current root directory and
+ * parent relationships.
+ */
+ if (nd->last_type != LAST_NORM) {
+ err = handle_dots(nd, nd->last_type);
+ if (!(flags & WALK_MORE) && nd->depth)
+ put_link(nd);
+ return err;
+ }
+
+ err = lookup_fast(nd, &path);
+ if (err < 0)
+ return err;
+
+ if (err == 0) {
+ path.mnt = nd->path.mnt;
+ err = follow_managed(&path, nd);
+ if (err < 0)
+ return err;
+
+ if (d_is_negative(path.dentry)) {
+ path_to_nameidata(&path, nd);
+ return -ENOENT;
}
}
- return first_error;
+ return step_into(nd, &path, flags, d_inode(path.dentry));
}
-EXPORT_SYMBOL(umount_by_cdev);
-int umount(const char *pathname)
+static int component_len(const char *name, char separator)
{
- struct fs_device_d *fsdev = NULL, *f;
- char *p = normalise_path(pathname);
+ int len = 0;
- for_each_fs_device(f) {
- if (!strcmp(p, f->path)) {
- fsdev = f;
- break;
- }
+ while (name[len] && name[len] != separator)
+ len++;
+
+ return len;
+}
+
+struct filename *getname(const char *filename)
+{
+ struct filename *result;
+
+ result = malloc(sizeof(*result));
+ if (!result)
+ return NULL;
+
+ result->name = strdup(filename);
+ if (!result->name) {
+ free(result);
+ return NULL;
}
- if (!fsdev) {
- struct cdev *cdev = cdev_open(p, O_RDWR);
+ result->refcnt = 1;
- if (cdev) {
- free(p);
- cdev_close(cdev);
- return umount_by_cdev(cdev);
+ return result;
+}
+
+void putname(struct filename *name)
+{
+ BUG_ON(name->refcnt <= 0);
+
+ if (--name->refcnt > 0)
+ return;
+
+ free(name->name);
+ free(name);
+}
+
+static struct fs_device_d *get_fsdevice_by_dentry(struct dentry *dentry)
+{
+ struct super_block *sb;
+
+ sb = dentry->d_sb;
+
+ return container_of(sb, struct fs_device_d, sb);
+}
+
+static bool dentry_is_tftp(struct dentry *dentry)
+{
+ struct fs_device_d *fsdev;
+
+ fsdev = get_fsdevice_by_dentry(dentry);
+ if (!fsdev)
+ return false;
+
+ if (strcmp(fsdev->driver->drv.name, "tftp"))
+ return false;
+
+ return true;
+}
+
+/*
+ * Name resolution.
+ * This is the basic name resolution function, turning a pathname into
+ * the final dentry. We expect 'base' to be positive and a directory.
+ *
+ * Returns 0 and nd will have valid dentry and mnt on success.
+ * Returns error and drops reference to input namei data on failure.
+ */
+static int link_path_walk(const char *name, struct nameidata *nd)
+{
+ int err;
+ char separator = '/';
+
+ while (*name=='/')
+ name++;
+ if (!*name)
+ return 0;
+
+ /* At this point we know we have a real path component. */
+ for(;;) {
+ int len;
+ int type;
+
+ len = component_len(name, separator);
+
+ type = LAST_NORM;
+ if (name[0] == '.') switch (len) {
+ case 2:
+ if (name[1] == '.') {
+ type = LAST_DOTDOT;
+ nd->flags |= LOOKUP_JUMPED;
+ }
+ break;
+ case 1:
+ type = LAST_DOT;
+ }
+ if (likely(type == LAST_NORM))
+ nd->flags &= ~LOOKUP_JUMPED;
+
+ nd->last.len = len;
+ nd->last.name = name;
+ nd->last_type = type;
+
+ name += len;
+ if (!*name)
+ goto OK;
+
+ /*
+ * If it wasn't NUL, we know it was '/'. Skip that
+ * slash, and continue until no more slashes.
+ */
+ do {
+ name++;
+ } while (unlikely(*name == separator));
+
+ if (unlikely(!*name)) {
+OK:
+ /* pathname body, done */
+ if (!nd->depth)
+ return 0;
+ name = nd->stack[nd->depth - 1].name;
+ /* trailing symlink, done */
+ if (!name)
+ return 0;
+ /* last component of nested symlink */
+ err = walk_component(nd, WALK_FOLLOW);
+ } else {
+ /* not the last component */
+ err = walk_component(nd, WALK_FOLLOW | WALK_MORE);
+ }
+
+ if (err < 0)
+ return err;
+
+ /*
+ * barebox specific hack for TFTP. TFTP does not support
+ * looking up directories, only the files in directories.
+ * Since the filename is not known at this point we replace
+ * the path separator with an invalid char so that TFTP will
+ * get the full remaining path including slashes.
+ */
+ if (dentry_is_tftp(nd->path.dentry))
+ separator = 0x1;
+
+ if (err) {
+ const char *s = get_link(nd);
+
+ if (IS_ERR(s))
+ return PTR_ERR(s);
+ err = 0;
+ if (unlikely(!s)) {
+ /* jumped */
+ put_link(nd);
+ } else {
+ nd->stack[nd->depth - 1].name = name;
+ name = s;
+ continue;
+ }
}
+ if (unlikely(!d_can_lookup(nd->path.dentry)))
+ return -ENOTDIR;
}
+}
- free(p);
+static const char *path_init(struct nameidata *nd, unsigned flags)
+{
+ const char *s = nd->name->name;
- if (f == fs_dev_root && !list_is_singular(&fs_device_list)) {
- errno = EBUSY;
- return -EBUSY;
+ nd->last_type = LAST_ROOT; /* if there are only slashes... */
+ nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT;
+ nd->depth = 0;
+
+ nd->path.mnt = NULL;
+ nd->path.dentry = NULL;
+
+ if (*s == '/') {
+ get_root(&nd->path);
+ return s;
+ } else if (nd->dfd == AT_FDCWD) {
+ get_pwd(&nd->path);
+ nd->inode = nd->path.dentry->d_inode;
+ return s;
}
- if (!fsdev) {
- errno = EFAULT;
- return -EFAULT;
+ return s;
+}
+
+static const char *trailing_symlink(struct nameidata *nd)
+{
+ const char *s;
+
+ nd->flags |= LOOKUP_PARENT;
+ nd->stack[0].name = NULL;
+ s = get_link(nd);
+
+ return s ? s : "";
+}
+
+static inline int lookup_last(struct nameidata *nd)
+{
+ if (nd->last_type == LAST_NORM && nd->last.name[nd->last.len])
+ nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
+
+ nd->flags &= ~LOOKUP_PARENT;
+ return walk_component(nd, 0);
+}
+
+static void terminate_walk(struct nameidata *nd)
+{
+ int i;
+
+ path_put(&nd->path);
+ for (i = 0; i < nd->depth; i++)
+ path_put(&nd->stack[i].link);
+
+ nd->depth = 0;
+}
+
+/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
+static int path_parentat(struct nameidata *nd, unsigned flags,
+ struct path *parent)
+{
+ const char *s = path_init(nd, flags);
+ int err;
+
+ if (IS_ERR(s))
+ return PTR_ERR(s);
+
+ err = link_path_walk(s, nd);
+ if (!err) {
+ *parent = nd->path;
+ nd->path.mnt = NULL;
+ nd->path.dentry = NULL;
}
+ terminate_walk(nd);
+ return err;
+}
- return fsdev_umount(fsdev);
+static struct filename *filename_parentat(int dfd, struct filename *name,
+ unsigned int flags, struct path *parent,
+ struct qstr *last, int *type)
+{
+ int retval;
+ struct nameidata nd;
+
+ if (IS_ERR(name))
+ return name;
+
+ set_nameidata(&nd, dfd, name);
+
+ retval = path_parentat(&nd, flags, parent);
+ if (likely(!retval)) {
+ *last = nd.last;
+ *type = nd.last_type;
+ } else {
+ putname(name);
+ name = ERR_PTR(retval);
+ }
+
+ return name;
}
-EXPORT_SYMBOL(umount);
-DIR *opendir(const char *pathname)
+static struct dentry *filename_create(int dfd, struct filename *name,
+ struct path *path, unsigned int lookup_flags)
+{
+ struct dentry *dentry = ERR_PTR(-EEXIST);
+ struct qstr last;
+ int type;
+ int error;
+ bool is_dir = (lookup_flags & LOOKUP_DIRECTORY);
+
+ /*
+ * Note that only LOOKUP_REVAL and LOOKUP_DIRECTORY matter here. Any
+ * other flags passed in are ignored!
+ */
+ lookup_flags &= LOOKUP_REVAL;
+
+ name = filename_parentat(dfd, name, 0, path, &last, &type);
+ if (IS_ERR(name))
+ return ERR_CAST(name);
+
+ /*
+ * Yucky last component or no last component at all?
+ * (foo/., foo/.., /////)
+ */
+ if (unlikely(type != LAST_NORM))
+ goto out;
+
+ /*
+ * Do the final lookup.
+ */
+ lookup_flags |= LOOKUP_CREATE | LOOKUP_EXCL;
+ dentry = __lookup_hash(&last, path->dentry, lookup_flags);
+ if (IS_ERR(dentry))
+ goto unlock;
+
+ error = -EEXIST;
+ if (d_is_positive(dentry))
+ goto fail;
+
+ /*
+ * Special case - lookup gave negative, but... we had foo/bar/
+ * From the vfs_mknod() POV we just have a negative dentry -
+ * all is fine. Let's be bastards - you had / on the end, you've
+ * been asking for (non-existent) directory. -ENOENT for you.
+ */
+ if (unlikely(!is_dir && last.name[last.len])) {
+ error = -ENOENT;
+ goto fail;
+ }
+ putname(name);
+ return dentry;
+fail:
+ dput(dentry);
+ dentry = ERR_PTR(error);
+unlock:
+out:
+ path_put(path);
+ putname(name);
+ return dentry;
+}
+
+static int filename_lookup(int dfd, struct filename *name, unsigned flags,
+ struct path *path)
+{
+ int err;
+ struct nameidata nd;
+ const char *s;
+
+ set_nameidata(&nd, dfd, name);
+
+ s = path_init(&nd, flags);
+
+ while (!(err = link_path_walk(s, &nd)) && ((err = lookup_last(&nd)) > 0)) {
+ s = trailing_symlink(&nd);
+ if (IS_ERR(s)) {
+ err = PTR_ERR(s);
+ break;
+ }
+ }
+
+ if (!err && nd.flags & LOOKUP_DIRECTORY)
+ if (!d_can_lookup(nd.path.dentry))
+ err = -ENOTDIR;
+ if (!err) {
+ *path = nd.path;
+ nd.path.mnt = NULL;
+ nd.path.dentry = NULL;
+ }
+
+ terminate_walk(&nd);
+ putname(name);
+
+ return err;
+}
+
+static struct fs_device_d *get_fsdevice_by_path(const char *pathname)
{
- DIR *dir = NULL;
struct fs_device_d *fsdev;
- struct fs_driver_d *fsdrv;
- char *p = canonicalize_path(pathname);
- char *freep = p;
+ struct path path;
int ret;
- struct stat s;
- ret = stat(pathname, &s);
+ ret = filename_lookup(AT_FDCWD, getname(pathname), 0, &path);
if (ret)
+ return NULL;
+
+ fsdev = get_fsdevice_by_dentry(path.dentry);
+
+ path_put(&path);
+
+ return fsdev;
+}
+
+int vfs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+ int error;
+
+ if (!dir->i_op->rmdir)
+ return -EPERM;
+
+ dget(dentry);
+
+ error = dir->i_op->rmdir(dir, dentry);
+ if (error)
goto out;
- if (!S_ISDIR(s.st_mode)) {
- ret = -ENOTDIR;
+ dentry->d_inode->i_flags |= S_DEAD;
+
+out:
+ dput(dentry);
+
+ if (!error)
+ d_delete(dentry);
+
+ return error;
+}
+
+int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+ int error;
+
+ if (!dir->i_op->mkdir)
+ return -EPERM;
+
+ mode &= (S_IRWXUGO|S_ISVTX);
+
+ error = dir->i_op->mkdir(dir, dentry, mode);
+
+ return error;
+}
+
+/* libfs.c */
+
+/* ---------------------------------------------------------------- */
+int mkdir (const char *pathname, mode_t mode)
+{
+ struct dentry *dentry;
+ struct path path;
+ int error;
+ unsigned int lookup_flags = LOOKUP_DIRECTORY;
+
+ dentry = filename_create(AT_FDCWD, getname(pathname), &path, lookup_flags);
+ if (IS_ERR(dentry)) {
+ error = PTR_ERR(dentry);
goto out;
}
- fsdev = get_fs_device_and_root_path(&p);
- if (!fsdev) {
- ret = -ENOENT;
+ error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
+
+ dput(dentry);
+ path_put(&path);
+out:
+ if (error)
+ errno = -error;
+
+ return error;
+}
+EXPORT_SYMBOL(mkdir);
+
+int rmdir (const char *pathname)
+{
+ int error = 0;
+ struct filename *name;
+ struct dentry *dentry;
+ struct path path;
+ struct qstr last;
+ int type;
+
+ name = filename_parentat(AT_FDCWD, getname(pathname), 0,
+ &path, &last, &type);
+ if (IS_ERR(name))
+ return PTR_ERR(name);
+
+ switch (type) {
+ case LAST_DOTDOT:
+ error = -ENOTEMPTY;
+ goto out;
+ case LAST_DOT:
+ error = -EINVAL;
+ goto out;
+ case LAST_ROOT:
+ error = -EBUSY;
goto out;
}
- fsdrv = fsdev->driver;
- debug("opendir: fsdrv: %p\n",fsdrv);
+ dentry = __lookup_hash(&last, path.dentry, 0);
+ if (d_is_negative(dentry)) {
+ error = -ENOENT;
+ goto out;
+ }
+ if (d_mountpoint(dentry)) {
+ error = -EBUSY;
+ goto out;
+ }
+
+ if (!d_is_dir(dentry)) {
+ error = -ENOTDIR;
+ goto out;
+ }
- dir = fsdrv->opendir(&fsdev->dev, p);
- if (dir) {
- dir->dev = &fsdev->dev;
- dir->fsdrv = fsdrv;
+ error = vfs_rmdir(path.dentry->d_inode, dentry);
+
+ dput(dentry);
+out:
+ path_put(&path);
+ putname(name);
+
+ if (error)
+ errno = -error;
+
+ return error;
+}
+EXPORT_SYMBOL(rmdir);
+
+int open(const char *pathname, int flags, ...)
+{
+ struct fs_device_d *fsdev;
+ struct fs_driver_d *fsdrv;
+ struct super_block *sb;
+ FILE *f;
+ int error = 0;
+ struct inode *inode = NULL;
+ struct dentry *dentry = NULL;
+ struct nameidata nd;
+ const char *s;
+
+ set_nameidata(&nd, AT_FDCWD, getname(pathname));
+ s = path_init(&nd, LOOKUP_FOLLOW);
+
+ while (1) {
+ error = link_path_walk(s, &nd);
+ if (error)
+ break;
+
+ if (!d_is_dir(nd.path.dentry)) {
+ error = -ENOTDIR;
+ break;
+ }
+
+ dentry = __lookup_hash(&nd.last, nd.path.dentry, 0);
+ if (IS_ERR(dentry)) {
+ error = PTR_ERR(dentry);
+ break;
+ }
+
+ if (!d_is_symlink(dentry))
+ break;
+
+ dput(dentry);
+
+ error = lookup_last(&nd);
+ if (error <= 0)
+ break;
+
+ s = trailing_symlink(&nd);
+ if (IS_ERR(s)) {
+ error = PTR_ERR(s);
+ break;
+ }
+ }
+
+ terminate_walk(&nd);
+ putname(nd.name);
+
+ if (error)
+ return error;
+
+ if (d_is_negative(dentry)) {
+ if (flags & O_CREAT) {
+ error = create(nd.path.dentry, dentry);
+ if (error)
+ goto out1;
+ } else {
+ dput(dentry);
+ error = -ENOENT;
+ goto out1;
+ }
} else {
- /*
- * FIXME: The fs drivers should return ERR_PTR here so that
- * we are able to forward the error
- */
- ret = -EINVAL;
+ if (d_is_dir(dentry) && !dentry_is_tftp(dentry)) {
+ error = -EISDIR;
+ goto out1;
+ }
+ }
+
+ inode = d_inode(dentry);
+
+ f = get_file();
+ if (!f) {
+ error = -EMFILE;
+ goto out1;
}
+ f->path = xstrdup(pathname);
+ f->dentry = dentry;
+ f->f_inode = iget(inode);
+ f->flags = flags;
+ f->size = inode->i_size;
+
+ sb = inode->i_sb;
+ fsdev = container_of(sb, struct fs_device_d, sb);
+ fsdrv = fsdev->driver;
+
+ f->fsdev = fsdev;
+
+ if (fsdrv->open) {
+ char *pathname = dpath(dentry, fsdev->vfsmount.mnt_root);
+
+ error = fsdrv->open(&fsdev->dev, f, pathname);
+ free(pathname);
+ if (error)
+ goto out;
+ }
+
+ if (flags & O_TRUNC) {
+ error = fsdrv->truncate(&fsdev->dev, f, 0);
+ f->size = 0;
+ inode->i_size = 0;
+ if (error)
+ goto out;
+ }
+
+ if (flags & O_APPEND)
+ f->pos = f->size;
+
+ return f->no;
+
out:
- free(freep);
+ put_file(f);
+out1:
+
+ if (error)
+ errno = -error;
+ return error;
+}
+EXPORT_SYMBOL(open);
+int unlink(const char *pathname)
+{
+ int ret;
+ struct dentry *dentry;
+ struct inode *inode;
+ struct path path;
+
+ ret = filename_lookup(AT_FDCWD, getname(pathname), 0, &path);
+ if (ret)
+ goto out;
+
+ dentry = path.dentry;
+
+ if (d_is_dir(dentry)) {
+ ret = -EISDIR;
+ goto out_put;
+ }
+
+ inode = d_inode(dentry->d_parent);
+
+ if (!inode->i_op->unlink) {
+ ret = -EPERM;
+ goto out_put;
+ }
+
+ ret = inode->i_op->unlink(inode, dentry);
+ if (ret)
+ goto out_put;
+
+ d_delete(dentry);
+
+out_put:
+ path_put(&path);
+out:
if (ret)
errno = -ret;
+ return ret;
+}
+EXPORT_SYMBOL(unlink);
- return dir;
+int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
+{
+ if (!dir->i_op->symlink)
+ return -EPERM;
+
+ return dir->i_op->symlink(dir, dentry, oldname);
}
-EXPORT_SYMBOL(opendir);
-struct dirent *readdir(DIR *dir)
+int symlink(const char *pathname, const char *newpath)
{
- struct dirent *ent;
+ struct dentry *dentry;
+ struct path path;
+ int error;
+ unsigned int lookup_flags = LOOKUP_DIRECTORY;
- if (!dir)
- return NULL;
+ dentry = filename_create(AT_FDCWD, getname(newpath), &path, lookup_flags);
+ if (IS_ERR(dentry)) {
+ error = PTR_ERR(dentry);
+ goto out;
+ }
- ent = dir->fsdrv->readdir(dir->dev, dir);
+ error = vfs_symlink(path.dentry->d_inode, dentry, pathname);
+out:
+ if (error)
+ errno = -error;
- if (!ent)
- errno = EBADF;
+ return error;
+}
+EXPORT_SYMBOL(symlink);
+
+static void release_dir(DIR *d)
+{
+ struct readdir_entry *entry, *tmp;
+
+ list_for_each_entry_safe(entry, tmp, &d->entries, list) {
+ free(entry);
+ }
- return ent;
+ free(d);
}
-EXPORT_SYMBOL(readdir);
-int closedir(DIR *dir)
+DIR *opendir(const char *pathname)
{
int ret;
+ struct dentry *dir;
+ struct inode *inode;
+ struct file file = {};
+ DIR *d;
+ struct path path = {};
+ struct readdir_callback rd = {
+ .ctx = {
+ .actor = fillonedir,
+ },
+ };
+
+ ret = filename_lookup(AT_FDCWD, getname(pathname),
+ LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
+ if (ret)
+ goto out;
- if (!dir) {
- errno = EBADF;
- return -EBADF;
+ dir = path.dentry;
+
+ if (d_is_negative(dir)) {
+ ret = -ENOENT;
+ goto out_put;
}
- ret = dir->fsdrv->closedir(dir->dev, dir);
+ inode = d_inode(dir);
+
+ if (!S_ISDIR(inode->i_mode)) {
+ ret = -ENOTDIR;
+ goto out_put;
+ }
+
+ file.f_path.dentry = dir;
+ file.f_op = dir->d_inode->i_fop;
+
+ d = xzalloc(sizeof(*d));
+
+ INIT_LIST_HEAD(&d->entries);
+ rd.dir = d;
+
+ ret = file.f_op->iterate(&file, &rd.ctx);
if (ret)
- errno = -ret;
+ goto out_release;
- return ret;
+ path_put(&path);
+
+ return d;
+
+out_release:
+ release_dir(d);
+out_put:
+ path_put(&path);
+out:
+ errno = -ret;
+
+ return NULL;
}
-EXPORT_SYMBOL(closedir);
+EXPORT_SYMBOL(opendir);
-int stat(const char *filename, struct stat *s)
+int closedir(DIR *dir)
{
- char *path = canonicalize_path(filename);
int ret;
- if (IS_ERR(path))
- return PTR_ERR(path);
-
- ret = lstat(path, s);
+ if (!dir) {
+ errno = EBADF;
+ return -EBADF;
+ }
- free(path);
+ release_dir(dir);
return ret;
}
-EXPORT_SYMBOL(stat);
+EXPORT_SYMBOL(closedir);
-static int __lstat(const char *filename, struct stat *s)
+int readlink(const char *pathname, char *buf, size_t bufsiz)
{
- struct fs_driver_d *fsdrv;
- struct fs_device_d *fsdev;
- char *f = normalise_path(filename);
- char *freep = f;
int ret;
+ struct dentry *dentry;
+ struct inode *inode;
+ const char *link;
+ struct path path = {};
- automount_mount(f, 1);
+ ret = filename_lookup(AT_FDCWD, getname(pathname), 0, &path);
+ if (ret)
+ goto out;
- memset(s, 0, sizeof(struct stat));
+ dentry = path.dentry;
- fsdev = get_fsdevice_by_path(f);
- if (!fsdev) {
- ret = -ENOENT;
- goto out;
+ if (!d_is_symlink(dentry)) {
+ ret = -EINVAL;
+ goto out_put;
}
- if (fsdev != fs_dev_root && strcmp(f, fsdev->path))
- f += strlen(fsdev->path);
- else
- fsdev = fs_dev_root;
+ inode = d_inode(dentry);
- fsdrv = fsdev->driver;
+ if (!inode->i_op->get_link) {
+ ret = -EPERM;
+ goto out_put;
+ }
- if (*f == 0)
- f = "/";
+ link = inode->i_op->get_link(dentry, inode);
+ if (IS_ERR(link)) {
+ ret = PTR_ERR(link);
+ goto out_put;
+ }
- ret = fsdrv->stat(&fsdev->dev, f, s);
-out:
- free(freep);
+ strncpy(buf, link, bufsiz);
+ ret = 0;
+out_put:
+ path_put(&path);
+out:
if (ret)
errno = -ret;
return ret;
}
+EXPORT_SYMBOL(readlink);
-int lstat(const char *filename, struct stat *s)
+static int stat_filename(const char *filename, struct stat *s, unsigned int flags)
{
- char *f = canonicalize_dir(filename);
int ret;
+ struct dentry *dentry;
+ struct inode *inode;
+ struct path path = {};
+
+ ret = filename_lookup(AT_FDCWD, getname(filename), flags, &path);
+ if (ret)
+ goto out;
+
+ dentry = path.dentry;
- if (IS_ERR(f))
- return PTR_ERR(f);
+ if (d_is_negative(dentry)) {
+ ret = -ENOENT;
+ goto out_put;
+ }
- ret = __lstat(f, s);
+ inode = d_inode(dentry);
- free(f);
+ stat_inode(inode, s);
+ ret = 0;
+out_put:
+ path_put(&path);
+out:
return ret;
}
+
+int stat(const char *filename, struct stat *s)
+{
+ return stat_filename(filename, s, LOOKUP_FOLLOW);
+}
+EXPORT_SYMBOL(stat);
+
+int lstat(const char *filename, struct stat *s)
+{
+ return stat_filename(filename, s, 0);
+}
EXPORT_SYMBOL(lstat);
-int fstat(int fd, struct stat *s)
+static char *__dpath(struct dentry *dentry, struct dentry *root)
{
- FILE *f;
- struct fs_device_d *fsdev;
+ char *res, *ppath;
- if (check_fd(fd))
- return -errno;
+ if (dentry == root)
+ return NULL;
+ if (dentry == d_root)
+ return NULL;
- f = &files[fd];
+ while (IS_ROOT(dentry)) {
+ struct fs_device_d *fsdev;
- fsdev = f->fsdev;
+ for_each_fs_device(fsdev) {
+ if (dentry == fsdev->vfsmount.mnt_root) {
+ dentry = fsdev->vfsmount.mountpoint;
+ break;
+ }
+ }
+ }
+
+ ppath = __dpath(dentry->d_parent, root);
+ if (ppath)
+ res = basprintf("%s/%s", ppath, dentry->name);
+ else
+ res = basprintf("/%s", dentry->name);
+ free(ppath);
- return fsdev->driver->stat(&fsdev->dev, f->path, s);
+ return res;
}
-EXPORT_SYMBOL(fstat);
-int mkdir (const char *pathname, mode_t mode)
+/**
+ * dpath - return path of a dentry
+ * @dentry: The dentry to return the path from
+ * @root: The dentry up to which the path is followed
+ *
+ * Get the path of a dentry. The path is followed up to
+ * @root or the root ("/") dentry, whatever is found first.
+ *
+ * Return: Dynamically allocated string containing the path
+ */
+char *dpath(struct dentry *dentry, struct dentry *root)
{
- struct fs_driver_d *fsdrv;
- struct fs_device_d *fsdev;
- char *p = canonicalize_path(pathname);
- char *freep = p;
- int ret;
- struct stat s;
+ char *res;
- ret = parent_check_directory(p);
- if (ret)
- goto out;
+ if (dentry == root)
+ return strdup("/");
- ret = stat(pathname, &s);
- if (!ret) {
- ret = -EEXIST;
- goto out;
- }
+ res = __dpath(dentry, root);
- fsdev = get_fs_device_and_root_path(&p);
- if (!fsdev) {
- ret = -ENOENT;
+ return res;
+}
+
+/**
+ * canonicalize_path - resolve links in path
+ * @pathname: The input path
+ *
+ * This function resolves all links in @pathname and returns
+ * a path without links in it.
+ *
+ * Return: Path with links resolved. Allocated, must be freed after use.
+ */
+char *canonicalize_path(const char *pathname)
+{
+ char *res = NULL;
+ struct path path;
+ int ret;
+
+ ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW, &path);
+ if (ret)
goto out;
- }
- fsdrv = fsdev->driver;
- if (fsdrv->mkdir)
- ret = fsdrv->mkdir(&fsdev->dev, p);
- else
- ret = -EROFS;
+ res = dpath(path.dentry, d_root);
out:
- free(freep);
-
if (ret)
errno = -ret;
- return ret;
+ return res;
}
-EXPORT_SYMBOL(mkdir);
-int rmdir (const char *pathname)
+const char *getcwd(void)
{
- struct fs_driver_d *fsdrv;
- struct fs_device_d *fsdev;
- char *p = canonicalize_path(pathname);
- char *freep = p;
+ return cwd;
+}
+EXPORT_SYMBOL(getcwd);
+
+int chdir(const char *pathname)
+{
+ char *realpath;
+ struct path path;
int ret;
- struct stat s;
- ret = lstat(pathname, &s);
+ ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW, &path);
if (ret)
goto out;
- if (!S_ISDIR(s.st_mode)) {
+
+ if (!d_is_dir(path.dentry)) {
ret = -ENOTDIR;
goto out;
}
- if (!dir_is_empty(pathname)) {
- ret = -ENOTEMPTY;
- goto out;
- }
+ realpath = dpath(path.dentry, d_root);
+ strcpy(cwd, realpath);
+ free(realpath);
+ cwd_dentry = path.dentry;
+ cwd_mnt = path.mnt;
- fsdev = get_fs_device_and_root_path(&p);
- if (!fsdev) {
- ret = -ENODEV;
- goto out;
- }
- fsdrv = fsdev->driver;
+ ret = 0;
- if (fsdrv->rmdir)
- ret = fsdrv->rmdir(&fsdev->dev, p);
- else
- ret = -EROFS;
out:
- free(freep);
-
if (ret)
errno = -ret;
return ret;
}
-EXPORT_SYMBOL(rmdir);
+EXPORT_SYMBOL(chdir);
/*
- * cdev_get_mount_path - return the path a cdev is mounted on
- *
- * If a cdev is mounted return the path it's mounted on, NULL
- * otherwise.
+ * Mount a device to a directory.
+ * We do this by registering a new device on which the filesystem
+ * driver will match.
*/
-const char *cdev_get_mount_path(struct cdev *cdev)
+int mount(const char *device, const char *fsname, const char *pathname,
+ const char *fsoptions)
{
struct fs_device_d *fsdev;
+ int ret;
+ struct path path = {};
- for_each_fs_device(fsdev) {
- if (fsdev->cdev && fsdev->cdev == cdev)
- return fsdev->path;
+ if (d_root) {
+ ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW, &path);
+ if (ret)
+ goto out;
+
+ if (!d_is_dir(path.dentry)) {
+ ret = -ENOTDIR;
+ goto out;
+ }
+
+ if (IS_ROOT(path.dentry) || d_mountpoint(path.dentry)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ } else {
+ if (pathname[0] != '/' || pathname[1])
+ return -EINVAL;
}
- return NULL;
+ if (!fsoptions)
+ fsoptions = "";
+
+ debug("mount: %s on %s type %s, options=%s\n",
+ device, pathname, fsname, fsoptions);
+
+ if (!fsname)
+ fsname = detect_fs(device, fsoptions);
+
+ if (!fsname) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ fsdev = xzalloc(sizeof(struct fs_device_d));
+ fsdev->backingstore = xstrdup(device);
+ safe_strncpy(fsdev->dev.name, fsname, MAX_DRIVER_NAME);
+ fsdev->dev.id = get_free_deviceid(fsdev->dev.name);
+ fsdev->dev.bus = &fs_bus;
+ fsdev->options = xstrdup(fsoptions);
+
+ init_super(&fsdev->sb);
+
+ if (path.mnt)
+ mntget(path.mnt);
+
+ if (d_root)
+ fsdev->path = dpath(path.dentry, d_root);
+
+ ret = register_device(&fsdev->dev);
+ if (ret)
+ goto err_register;
+
+ if (!fsdev->dev.driver) {
+ /*
+ * Driver didn't accept the device or no driver for this
+ * device. Bail out
+ */
+ ret = -EINVAL;
+ goto err_no_driver;
+ }
+
+ if (d_root) {
+ fsdev->vfsmount.mountpoint = path.dentry;
+ fsdev->vfsmount.parent = path.mnt;
+ fsdev->vfsmount.mountpoint->d_flags |= DCACHE_MOUNTED;
+ } else {
+ d_root = fsdev->sb.s_root;
+ path.dentry = d_root;
+ mnt_root = &fsdev->vfsmount;
+ fsdev->vfsmount.mountpoint = d_root;
+ fsdev->vfsmount.parent = &fsdev->vfsmount;
+ fsdev->path = xstrdup("/");
+ }
+
+ fsdev->vfsmount.mnt_root = fsdev->sb.s_root;
+
+ if (!fsdev->linux_rootarg && fsdev->cdev && fsdev->cdev->partuuid[0] != 0) {
+ char *str = basprintf("root=PARTUUID=%s",
+ fsdev->cdev->partuuid);
+
+ fsdev_set_linux_rootarg(fsdev, str);
+ }
+
+ path_put(&path);
+
+ return 0;
+
+err_no_driver:
+ unregister_device(&fsdev->dev);
+err_register:
+ fs_remove(&fsdev->dev);
+out:
+ path_put(&path);
+
+ errno = -ret;
+
+ return ret;
}
+EXPORT_SYMBOL(mount);
-/*
- * cdev_mount_default - mount a cdev to the default path
- *
- * If a cdev is already mounted return the path it's mounted on, otherwise
- * mount it to /mnt/<cdevname> and return the path. Returns an error pointer
- * on failure.
- */
-const char *cdev_mount_default(struct cdev *cdev, const char *fsoptions)
+int umount(const char *pathname)
{
- const char *path;
- char *newpath, *devpath;
+ struct fs_device_d *fsdev = NULL, *f;
+ struct path path = {};
int ret;
- /*
- * If this cdev is already mounted somewhere use this path
- * instead of mounting it again to avoid corruption on the
- * filesystem. Note this ignores eventual fsoptions though.
- */
- path = cdev_get_mount_path(cdev);
- if (path)
- return path;
+ ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW, &path);
+ if (ret)
+ return ret;
- newpath = basprintf("/mnt/%s", cdev->name);
- make_directory(newpath);
+ if (path.dentry == d_root) {
+ path_put(&path);
+ return -EBUSY;
+ }
- devpath = basprintf("/dev/%s", cdev->name);
+ for_each_fs_device(f) {
+ if (path.dentry == f->vfsmount.mnt_root) {
+ fsdev = f;
+ break;
+ }
+ }
- ret = mount(devpath, NULL, newpath, fsoptions);
+ path_put(&path);
- free(devpath);
+ if (!fsdev) {
+ struct cdev *cdev = cdev_open(pathname, O_RDWR);
- if (ret) {
- free(newpath);
- return ERR_PTR(ret);
+ if (cdev) {
+ cdev_close(cdev);
+ return umount_by_cdev(cdev);
+ }
}
- return cdev_get_mount_path(cdev);
+ if (!fsdev) {
+ errno = EFAULT;
+ return -EFAULT;
+ }
+
+ return fsdev_umount(fsdev);
}
+EXPORT_SYMBOL(umount);
-/*
- * mount_all - iterate over block devices and mount all devices we are able to
- */
-void mount_all(void)
+#ifdef CONFIG_FS_AUTOMOUNT
+
+#define AUTOMOUNT_IS_FILE (1 << 0)
+
+struct automount {
+ char *path;
+ struct dentry *dentry;
+ char *cmd;
+ struct list_head list;
+ unsigned int flags;
+};
+
+static LIST_HEAD(automount_list);
+
+static void automount_remove_dentry(struct dentry *dentry)
{
- struct device_d *dev;
- struct block_device *bdev;
+ struct automount *am;
- if (!IS_ENABLED(CONFIG_BLOCK))
+ list_for_each_entry(am, &automount_list, list) {
+ if (dentry == am->dentry)
+ goto found;
+ }
+
+ return;
+found:
+ list_del(&am->list);
+ dput(am->dentry);
+ free(am->path);
+ free(am->cmd);
+ free(am);
+}
+
+void automount_remove(const char *pathname)
+{
+ struct path path;
+ int ret;
+
+ ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW, &path);
+ if (ret)
return;
- for_each_device(dev)
- device_detect(dev);
+ automount_remove_dentry(path.dentry);
- for_each_block_device(bdev) {
- struct cdev *cdev = &bdev->cdev;
+ path_put(&path);
+}
+EXPORT_SYMBOL(automount_remove);
- list_for_each_entry(cdev, &bdev->dev->cdevs, devices_list)
- cdev_mount_default(cdev, NULL);
+int automount_add(const char *pathname, const char *cmd)
+{
+ struct automount *am = xzalloc(sizeof(*am));
+ struct path path;
+ int ret;
+
+ ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW, &path);
+ if (ret)
+ return ret;
+
+ if (!d_is_dir(path.dentry)) {
+ ret = -ENOTDIR;
+ goto out;
}
+
+ am->path = dpath(path.dentry, d_root);
+ am->dentry = dget(path.dentry);
+ am->dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
+ am->cmd = xstrdup(cmd);
+
+ automount_remove_dentry(am->dentry);
+
+ list_add_tail(&am->list, &automount_list);
+
+ ret = 0;
+out:
+ path_put(&path);
+
+ return ret;
}
+EXPORT_SYMBOL(automount_add);
-void fsdev_set_linux_rootarg(struct fs_device_d *fsdev, const char *str)
+void cdev_create_default_automount(struct cdev *cdev)
{
- fsdev->linux_rootarg = xstrdup(str);
+ char *path, *cmd;
- dev_add_param_fixed(&fsdev->dev, "linux.bootargs", fsdev->linux_rootarg);
+ path = basprintf("/mnt/%s", cdev->name);
+ cmd = basprintf("mount %s", cdev->name);
+
+ make_directory(path);
+ automount_add(path, cmd);
+
+ free(cmd);
+ free(path);
}
-/**
- * path_get_linux_rootarg() - Given a path return a suitable root= option for
- * Linux
- * @path: The path
- *
- * Return: A string containing the root= option or an ERR_PTR. the returned
- * string must be freed by the caller.
- */
-char *path_get_linux_rootarg(const char *path)
+void automount_print(void)
{
- struct fs_device_d *fsdev;
- const char *str;
+ struct automount *am;
- fsdev = get_fsdevice_by_path(path);
- if (!fsdev)
- return ERR_PTR(-EINVAL);
+ list_for_each_entry(am, &automount_list, list)
+ printf("%-20s %s\n", am->path, am->cmd);
+}
+EXPORT_SYMBOL(automount_print);
- str = dev_get_param(&fsdev->dev, "linux.bootargs");
- if (!str)
- return ERR_PTR(-ENOSYS);
+static int automount_mount(struct dentry *dentry)
+{
+ struct automount *am;
+ int ret = -ENOENT;
+ static int in_automount;
- return xstrdup(str);
+ if (in_automount)
+ return -EINVAL;
+
+ in_automount++;
+
+ list_for_each_entry(am, &automount_list, list) {
+ if (am->dentry != dentry)
+ continue;
+
+ setenv("automount_path", am->path);
+ export("automount_path");
+ ret = run_command(am->cmd);
+ setenv("automount_path", NULL);
+
+ if (ret) {
+ printf("running automount command '%s' failed\n",
+ am->cmd);
+ ret = -ENODEV;
+ }
+
+ break;
+ }
+
+ in_automount--;
+
+ return ret;
}
-/**
- * __is_tftp_fs() - return true when path is mounted on TFTP
- * @path: The path
- *
- * Do not use directly, use is_tftp_fs instead.
- *
- * Return: true when @path is on TFTP, false otherwise
+BAREBOX_MAGICVAR(automount_path, "mountpath passed to automount scripts");
+
+#else
+static int automount_mount(struct dentry *dentry)
+{
+ return 0;
+}
+#endif /* CONFIG_FS_AUTOMOUNT */
+
+#ifdef DEBUG
+
+/*
+ * Some debug commands, helpful to debug the dcache implementation
*/
-bool __is_tftp_fs(const char *path)
+#include <command.h>
+
+static int do_lookup_dentry(int argc, char *argv[])
+{
+ struct path path;
+ int ret;
+ char *canon;
+ char mode[16];
+
+ if (argc < 2)
+ return COMMAND_ERROR_USAGE;
+
+ ret = filename_lookup(AT_FDCWD, getname(argv[1]), 0, &path);
+ if (ret) {
+ printf("Cannot lookup path \"%s\": %s\n",
+ argv[1], strerror(-ret));
+ return 1;
+ }
+
+ canon = canonicalize_path(argv[1]);
+
+ printf("path \"%s\":\n", argv[1]);
+ printf("dentry: 0x%p\n", path.dentry);
+ printf("dentry refcnt: %d\n", path.dentry->d_count);
+ if (path.dentry->d_inode) {
+ struct inode *inode = path.dentry->d_inode;
+ printf("inode: 0x%p\n", inode);
+ printf("inode refcnt: %d\n", inode->i_count);
+ printf("Type: %s\n", mkmodestr(inode->i_mode, mode));
+ }
+ printf("canonical path: \"%s\"\n", canon);
+
+ path_put(&path);
+ free(canon);
+
+ return 0;
+}
+
+BAREBOX_CMD_START(lookup_dentry)
+ .cmd = do_lookup_dentry,
+BAREBOX_CMD_END
+
+static struct dentry *debug_follow_mount(struct dentry *dentry)
{
struct fs_device_d *fsdev;
+ unsigned managed = dentry->d_flags;
- fsdev = get_fsdevice_by_path(path);
- if (!fsdev)
- return false;
+ if (managed & DCACHE_MOUNTED) {
+ for_each_fs_device(fsdev) {
+ if (dentry == fsdev->vfsmount.mountpoint)
+ return fsdev->vfsmount.mnt_root;
+ }
+ return NULL;
+ } else {
+ return dentry;
+ }
+}
- if (strcmp(fsdev->driver->drv.name, "tftp"))
- return false;
+static void debug_dump_dentries(struct dentry *parent, int indent)
+{
+ int i;
+ struct dentry *dentry, *mp;
- return true;
+ for (i = 0; i < indent; i++)
+ printf("\t");
+again:
+ printf("%s d: %p refcnt: %d, inode %p refcnt %d\n",
+ parent->name, parent, parent->d_count, parent->d_inode,
+ parent->d_inode ? parent->d_inode->i_count : -1);
+
+ mp = debug_follow_mount(parent);
+ if (mp != parent) {
+ for (i = 0; i < indent; i++)
+ printf("\t");
+ printf("MOUNT: ");
+
+ parent = mp;
+
+ goto again;
+ }
+
+ list_for_each_entry(dentry, &parent->d_subdirs, d_child)
+ debug_dump_dentries(dentry, indent + 1);
+}
+
+static int do_debug_fs_dump(int argc, char *argv[])
+{
+ debug_dump_dentries(d_root, 0);
+
+ return 0;
}
+
+BAREBOX_CMD_START(debug_fs_dump)
+ .cmd = do_debug_fs_dump,
+BAREBOX_CMD_END
+#endif
diff --git a/fs/legacy.c b/fs/legacy.c
new file mode 100644
index 0000000000..fc6a18f408
--- /dev/null
+++ b/fs/legacy.c
@@ -0,0 +1,315 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include <common.h>
+#include <fs.h>
+
+static struct inode *legacy_get_inode(struct super_block *sb, const struct inode *dir,
+ umode_t mode);
+
+static int legacy_iterate(struct file *file, struct dir_context *ctx)
+{
+ struct dentry *dentry = file->f_path.dentry;
+ struct inode *dir = d_inode(dentry);
+ struct super_block *sb = dir->i_sb;
+ struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb);
+ struct dir *d;
+ struct dirent *dirent;
+ char *pathname;
+
+ dir_emit_dots(file, ctx);
+
+ pathname = dpath(dentry, fsdev->vfsmount.mnt_root);
+
+ d = fsdev->driver->opendir(&fsdev->dev, pathname);
+ while (1) {
+ dirent = fsdev->driver->readdir(&fsdev->dev, d);
+ if (!dirent)
+ break;
+
+ dir_emit(ctx, dirent->d_name, strlen(dirent->d_name), 0, DT_UNKNOWN);
+ }
+
+ fsdev->driver->closedir(&fsdev->dev, d);
+
+ free(pathname);
+
+ return 0;
+}
+
+static struct dentry *legacy_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
+{
+ struct super_block *sb = dir->i_sb;
+ struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb);
+ struct inode *inode;
+ char *pathname;
+ struct stat s;
+ int ret;
+
+ pathname = dpath(dentry, fsdev->vfsmount.mnt_root);
+
+ ret = fsdev->driver->stat(&fsdev->dev, pathname, &s);
+ if (!ret) {
+ inode = legacy_get_inode(sb, dir, s.st_mode);
+
+ inode->i_size = s.st_size;
+ inode->i_mode = s.st_mode;
+
+ d_add(dentry, inode);
+ }
+
+ return NULL;
+}
+
+static int legacy_create(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+ struct super_block *sb = dir->i_sb;
+ struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb);
+ struct inode *inode;
+ char *pathname;
+ int ret;
+
+ if (!fsdev->driver->create)
+ return -EROFS;
+
+ pathname = dpath(dentry, fsdev->vfsmount.mnt_root);
+
+ ret = fsdev->driver->create(&fsdev->dev, pathname, mode | S_IFREG);
+
+ free(pathname);
+
+ if (ret)
+ return ret;
+
+ inode = legacy_get_inode(sb, dir, mode | S_IFREG);
+
+ d_instantiate(dentry, inode);
+
+ return 0;
+}
+
+static int legacy_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+ struct super_block *sb = dir->i_sb;
+ struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb);
+ struct inode *inode;
+ char *pathname;
+ int ret;
+
+ if (!fsdev->driver->mkdir)
+ return -EROFS;
+
+ pathname = dpath(dentry, fsdev->vfsmount.mnt_root);
+
+ ret = fsdev->driver->mkdir(&fsdev->dev, pathname);
+
+ free(pathname);
+
+ if (ret)
+ return ret;
+
+ inode = legacy_get_inode(sb, dir, mode | S_IFDIR);
+
+ d_instantiate(dentry, inode);
+
+ return 0;
+}
+
+static int legacy_dir_is_empty(struct dentry *dentry)
+{
+ struct inode *dir = d_inode(dentry);
+ struct super_block *sb = dir->i_sb;
+ struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb);
+ struct dir *d;
+ struct dirent *dirent;
+ char *pathname;
+
+ pathname = dpath(dentry, fsdev->vfsmount.mnt_root);
+
+ d = fsdev->driver->opendir(&fsdev->dev, pathname);
+ dirent = fsdev->driver->readdir(&fsdev->dev, d);
+
+ fsdev->driver->closedir(&fsdev->dev, d);
+
+ free(pathname);
+
+ return dirent ? 0 : 1;
+}
+
+static int legacy_rmdir(struct inode *dir, struct dentry *dentry)
+{
+ struct super_block *sb = dir->i_sb;
+ struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb);
+ char *pathname;
+ int ret;
+
+ if (!fsdev->driver->rmdir)
+ return -EROFS;
+
+ if (!legacy_dir_is_empty(dentry))
+ return -ENOTEMPTY;
+
+ pathname = dpath(dentry, fsdev->vfsmount.mnt_root);
+
+ ret = fsdev->driver->rmdir(&fsdev->dev, pathname);
+
+ free(pathname);
+
+ if (ret)
+ return ret;
+
+ drop_nlink(d_inode(dentry));
+ dput(dentry);
+ drop_nlink(dir);
+
+ return 0;
+}
+
+static int legacy_unlink(struct inode *dir, struct dentry *dentry)
+{
+ struct super_block *sb = dir->i_sb;
+ struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb);
+ char *pathname;
+ int ret;
+
+ if (!fsdev->driver->unlink)
+ return -EROFS;
+
+ pathname = dpath(dentry, fsdev->vfsmount.mnt_root);
+
+ ret = fsdev->driver->unlink(&fsdev->dev, pathname);
+
+ free(pathname);
+
+ if (ret)
+ return ret;
+
+ drop_nlink(d_inode(dentry));
+ dput(dentry);
+
+ return 0;
+}
+
+static int legacy_symlink(struct inode *dir, struct dentry *dentry,
+ const char *dest)
+{
+ struct super_block *sb = dir->i_sb;
+ struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb);
+ struct inode *inode;
+ char *pathname;
+ int ret;
+
+ if (!fsdev->driver->symlink)
+ return -ENOSYS;
+
+ pathname = dpath(dentry, fsdev->vfsmount.mnt_root);
+
+ ret = fsdev->driver->symlink(&fsdev->dev, dest, pathname);
+
+ free(pathname);
+
+ if (ret)
+ return ret;
+
+ inode = legacy_get_inode(sb, dir, S_IFLNK);
+ inode->i_link = xstrdup(dest);
+
+ d_instantiate(dentry, inode);
+
+ return 0;
+}
+
+static const char *legacy_get_link(struct dentry *dentry, struct inode *inode)
+{
+ struct super_block *sb = inode->i_sb;
+ struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb);
+ char *pathname;
+ int ret;
+ char link[PATH_MAX] = {};
+
+ if (!fsdev->driver->readlink)
+ return ERR_PTR(-ENOSYS);
+
+ pathname = dpath(dentry, fsdev->vfsmount.mnt_root);
+
+ ret = fsdev->driver->readlink(&fsdev->dev, pathname, link, PATH_MAX - 1);
+
+ free(pathname);
+
+ if (ret)
+ return NULL;
+
+ inode->i_link = xstrdup(link);
+
+ return inode->i_link;
+}
+
+static const struct super_operations legacy_s_ops;
+static const struct inode_operations legacy_file_inode_operations;
+
+static const struct inode_operations legacy_dir_inode_operations = {
+ .lookup = legacy_lookup,
+ .create = legacy_create,
+ .mkdir = legacy_mkdir,
+ .rmdir = legacy_rmdir,
+ .unlink = legacy_unlink,
+ .symlink = legacy_symlink,
+};
+
+static const struct file_operations legacy_dir_operations = {
+ .iterate = legacy_iterate,
+};
+
+static const struct inode_operations legacy_symlink_inode_operations = {
+ .get_link = legacy_get_link,
+};
+
+static struct inode *legacy_get_inode(struct super_block *sb, const struct inode *dir,
+ umode_t mode)
+{
+ struct inode *inode = new_inode(sb);
+
+ if (!inode)
+ return NULL;
+
+ inode->i_ino = get_next_ino();
+ inode->i_mode = mode;
+
+ switch (mode & S_IFMT) {
+ default:
+ return NULL;
+ case S_IFREG:
+ case S_IFCHR:
+ inode->i_op = &legacy_file_inode_operations;
+ break;
+ case S_IFDIR:
+ inode->i_op = &legacy_dir_inode_operations;
+ inode->i_fop = &legacy_dir_operations;
+ inc_nlink(inode);
+ break;
+ case S_IFLNK:
+ inode->i_op = &legacy_symlink_inode_operations;
+ break;
+ }
+
+ return inode;
+}
+
+int fs_init_legacy(struct fs_device_d *fsdev)
+{
+ struct inode *inode;
+
+ fsdev->sb.s_op = &legacy_s_ops;
+ inode = legacy_get_inode(&fsdev->sb, NULL, S_IFDIR);
+ fsdev->sb.s_root = d_make_root(inode);
+
+ return 0;
+}
diff --git a/fs/libfs.c b/fs/libfs.c
new file mode 100644
index 0000000000..af8f0f7462
--- /dev/null
+++ b/fs/libfs.c
@@ -0,0 +1,97 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include <common.h>
+#include <fs.h>
+#include <linux/fs.h>
+
+/*
+ * Lookup the data. This is trivial - if the dentry didn't already
+ * exist, we know it is negative. Set d_op to delete negative dentries.
+ */
+struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
+{
+ return NULL;
+}
+
+/* Relationship between i_mode and the DT_xxx types */
+static inline unsigned char dt_type(struct inode *inode)
+{
+ return (inode->i_mode >> 12) & 15;
+}
+
+int dcache_readdir(struct file *file, struct dir_context *ctx)
+{
+ struct dentry *dentry = file->f_path.dentry;
+ struct dentry *d;
+
+ dir_emit_dots(file, ctx);
+
+ list_for_each_entry(d, &dentry->d_subdirs, d_child) {
+ if (d_is_negative(d))
+ continue;
+ dir_emit(ctx, d->d_name.name, d->d_name.len,
+ d_inode(d)->i_ino, dt_type(d_inode(d)));
+ }
+
+ return 0;
+}
+
+const struct file_operations simple_dir_operations = {
+ .iterate = dcache_readdir,
+};
+
+int simple_empty(struct dentry *dentry)
+{
+ struct dentry *child;
+ int ret = 0;
+
+ list_for_each_entry(child, &dentry->d_subdirs, d_child) {
+ if (d_is_positive(child))
+ goto out;
+ }
+ ret = 1;
+out:
+ return ret;
+}
+
+int simple_unlink(struct inode *dir, struct dentry *dentry)
+{
+ struct inode *inode = d_inode(dentry);
+
+ drop_nlink(inode);
+ dput(dentry);
+
+ return 0;
+}
+
+int simple_rmdir(struct inode *dir, struct dentry *dentry)
+{
+ if (IS_ROOT(dentry))
+ return -EBUSY;
+
+ if (!simple_empty(dentry))
+ return -ENOTEMPTY;
+
+ drop_nlink(d_inode(dentry));
+ simple_unlink(dir, dentry);
+ drop_nlink(dir);
+
+ return 0;
+}
+
+const char *simple_get_link(struct dentry *dentry, struct inode *inode)
+{
+ return inode->i_link;
+}
+
+const struct inode_operations simple_symlink_inode_operations = {
+ .get_link = simple_get_link,
+};
diff --git a/fs/nfs.c b/fs/nfs.c
index 75cd127eeb..eb5db344db 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -20,6 +20,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+#define pr_fmt(fmt) "NFS: " fmt
#include <common.h>
#include <net.h>
@@ -127,6 +128,11 @@ struct rpc_reply {
#define NFS_TIMEOUT (2 * SECOND)
#define NFS_MAX_RESEND 5
+struct nfs_fh {
+ unsigned short size;
+ unsigned char data[NFS3_FHSIZE];
+};
+
struct nfs_priv {
struct net_connection *con;
IPaddr_t server;
@@ -136,18 +142,34 @@ struct nfs_priv {
uint16_t nfs_port;
unsigned manual_nfs_port:1;
uint32_t rpc_id;
- uint32_t rootfh_len;
- char rootfh[NFS3_FHSIZE];
+ struct nfs_fh rootfh;
};
struct file_priv {
struct kfifo *fifo;
void *buf;
- uint32_t filefh_len;
- char filefh[NFS3_FHSIZE];
+ struct nfs_priv *npriv;
+ struct nfs_fh fh;
+};
+
+struct nfs_inode {
+ struct inode inode;
+ struct nfs_fh fh;
struct nfs_priv *npriv;
};
+static inline struct nfs_inode *nfsi(struct inode *inode)
+{
+ return container_of(inode, struct nfs_inode, inode);
+}
+
+static void nfs_set_fh(struct inode *inode, struct nfs_fh *fh)
+{
+ struct nfs_inode *ninode = nfsi(inode);
+
+ ninode->fh = *fh;
+}
+
static uint64_t nfs_timer_start;
static int nfs_state;
@@ -234,17 +256,14 @@ struct xdr_stream {
#define XDR_QUADLEN(l) (((l) + 3) >> 2)
struct nfs_dir {
- DIR dir;
-
/*
* stream points to the next entry3 in the reply member of READDIR3res
* (if any, to the end indicator otherwise).
*/
struct xdr_stream stream;
- struct dirent ent;
- struct file_priv *priv;
uint64_t cookie;
char cookieverf[NFS3_COOKIEVERFSIZE];
+ struct nfs_fh fh;
};
static void xdr_init(struct xdr_stream *stream, void *buf, int len)
@@ -300,11 +319,11 @@ static int decode_filename(struct xdr_stream *xdr, char *name, u32 *length)
return 0;
out_nametoolong:
- printf("%s: returned a too long filename: %u\n", __func__, count);
+ pr_err("%s: returned a too long filename: %u\n", __func__, count);
return -ENAMETOOLONG;
out_overflow:
- printf("%s: premature end of packet\n", __func__);
+ pr_err("%s: premature end of packet\n", __func__);
return -EIO;
}
@@ -486,16 +505,16 @@ static uint32_t *nfs_add_uint64(uint32_t *p, uint64_t val)
return p + 2;
}
-static uint32_t *nfs_add_fh3(uint32_t *p, unsigned fh_len, const char *fh)
+static uint32_t *nfs_add_fh3(uint32_t *p, struct nfs_fh *fh)
{
- *p++ = hton32(fh_len);
+ *p++ = hton32(fh->size);
/* zero padding */
- if (fh_len & 3)
- p[fh_len / 4] = 0;
+ if (fh->size & 3)
+ p[fh->size / 4] = 0;
- memcpy(p, fh, fh_len);
- p += DIV_ROUND_UP(fh_len, 4);
+ memcpy(p, fh->data, fh->size);
+ p += DIV_ROUND_UP(fh->size, 4);
return p;
}
@@ -532,33 +551,36 @@ static const struct {
{ 0x00800, S_ISUID },
};
-static int nfs_fattr3_to_stat(uint32_t *p, struct stat *s)
+static int nfs_fattr3_to_stat(uint32_t *p, struct inode *inode)
{
uint32_t mode;
size_t i;
+ if (!inode)
+ return 0;
+
/* offsetof(struct fattr3, type) = 0 */
switch (ntoh32(net_read_uint32(p + 0))) {
case NF3REG:
- s->st_mode = S_IFREG;
+ inode->i_mode = S_IFREG;
break;
case NF3DIR:
- s->st_mode = S_IFDIR;
+ inode->i_mode = S_IFDIR;
break;
case NF3BLK:
- s->st_mode = S_IFBLK;
+ inode->i_mode = S_IFBLK;
break;
case NF3CHR:
- s->st_mode = S_IFCHR;
+ inode->i_mode = S_IFCHR;
break;
case NF3LNK:
- s->st_mode = S_IFLNK;
+ inode->i_mode = S_IFLNK;
break;
case NF3SOCK:
- s->st_mode = S_IFSOCK;
+ inode->i_mode = S_IFSOCK;
break;
case NF3FIFO:
- s->st_mode = S_IFIFO;
+ inode->i_mode = S_IFIFO;
break;
default:
printf("%s: invalid mode %x\n",
@@ -570,18 +592,17 @@ static int nfs_fattr3_to_stat(uint32_t *p, struct stat *s)
mode = ntoh32(net_read_uint32(p + 1));
for (i = 0; i < ARRAY_SIZE(nfs3_mode_bits); ++i) {
if (mode & nfs3_mode_bits[i].nfsmode)
- s->st_mode |= nfs3_mode_bits[i].statmode;
+ inode->i_mode |= nfs3_mode_bits[i].statmode;
}
/* offsetof(struct fattr3, size) = 20 */
- s->st_size = ntoh64(net_read_uint64(p + 5));
+ inode->i_size = ntoh64(net_read_uint64(p + 5));
return 0;
}
-static uint32_t *nfs_read_post_op_attr(uint32_t *p, struct stat **s)
+static uint32_t *nfs_read_post_op_attr(uint32_t *p, struct inode *inode)
{
- struct stat dummy;
/*
* union post_op_attr switch (bool attributes_follow) {
* case TRUE:
@@ -592,11 +613,8 @@ static uint32_t *nfs_read_post_op_attr(uint32_t *p, struct stat **s)
*/
if (ntoh32(net_read_uint32(p++))) {
- nfs_fattr3_to_stat(p, s ? *s : &dummy);
+ nfs_fattr3_to_stat(p, inode);
p += 21;
- } else if (s) {
- /* no attributes available */
- *s = NULL;
}
return p;
@@ -635,14 +653,14 @@ static int nfs_mount_req(struct nfs_priv *npriv)
p = nfs_packet + sizeof(struct rpc_reply) + 4;
- npriv->rootfh_len = ntoh32(net_read_uint32(p++));
- if (npriv->rootfh_len > NFS3_FHSIZE) {
+ npriv->rootfh.size = ntoh32(net_read_uint32(p++));
+ if (npriv->rootfh.size > NFS3_FHSIZE) {
printf("%s: file handle too big: %lu\n", __func__,
- (unsigned long)npriv->rootfh_len);
+ (unsigned long)npriv->rootfh.size);
return -EIO;
}
- memcpy(npriv->rootfh, p, npriv->rootfh_len);
- p += DIV_ROUND_UP(npriv->rootfh_len, 4);
+ memcpy(npriv->rootfh.data, p, npriv->rootfh.size);
+ p += DIV_ROUND_UP(npriv->rootfh.size, 4);
return 0;
}
@@ -674,9 +692,10 @@ static void nfs_umount_req(struct nfs_priv *npriv)
*
* *s is set to NULL if LOOKUP3resok doesn't contain obj_attributes.
*/
-static int nfs_lookup_req(struct file_priv *priv,
- uint32_t filename_len, const char *filename, struct stat **s)
+static int nfs_lookup_req(struct nfs_priv *npriv, struct nfs_fh *fh,
+ const char *filename, struct inode *inode)
{
+ struct nfs_inode *ninode = nfsi(inode);
uint32_t data[1024];
uint32_t *p;
int len;
@@ -709,73 +728,29 @@ static int nfs_lookup_req(struct file_priv *priv,
p = rpc_add_credentials(p);
/* what.dir */
- p = nfs_add_fh3(p, priv->filefh_len, priv->filefh);
+ p = nfs_add_fh3(p, fh);
/* what.name */
- p = nfs_add_filename(p, filename_len, filename);
+ p = nfs_add_filename(p, strlen(filename), filename);
len = p - &(data[0]);
- ret = rpc_req(priv->npriv, PROG_NFS, NFSPROC3_LOOKUP, data, len);
+ ret = rpc_req(npriv, PROG_NFS, NFSPROC3_LOOKUP, data, len);
if (ret)
return ret;
p = nfs_packet + sizeof(struct rpc_reply) + 4;
- priv->filefh_len = ntoh32(net_read_uint32(p++));
- if (priv->filefh_len > NFS3_FHSIZE) {
- debug("%s: file handle too big: %lu\n", __func__,
- (unsigned long)priv->filefh_len);
+ ninode->fh.size = ntoh32(net_read_uint32(p++));
+ if (ninode->fh.size > NFS3_FHSIZE) {
+ debug("%s: file handle too big: %u\n", __func__,
+ ninode->fh.size);
return -EIO;
}
- memcpy(priv->filefh, p, priv->filefh_len);
- p += DIV_ROUND_UP(priv->filefh_len, 4);
-
- if (s)
- nfs_read_post_op_attr(p, s);
-
- return 0;
-}
-
-static int nfs_attr_req(struct file_priv *priv, struct stat *s)
-{
- uint32_t data[1024];
- uint32_t *p;
- int len;
- int ret;
-
- /*
- * struct GETATTR3args {
- * nfs_fh3 object;
- * }
- *
- * struct GETATTR3resok {
- * fattr3 obj_attributes;
- * };
- *
- * union GETATTR3res switch (nfsstat3 status) {
- * case NFS3_OK:
- * GETATTR3resok resok;
- * default:
- * void;
- * }
- */
-
- p = &(data[0]);
- p = rpc_add_credentials(p);
-
- /* object */
- p = nfs_add_fh3(p, priv->filefh_len, priv->filefh);
-
- len = p - &(data[0]);
-
- ret = rpc_req(priv->npriv, PROG_NFS, NFSPROC3_GETATTR, data, len);
- if (ret)
- return ret;
+ memcpy(ninode->fh.data, p, ninode->fh.size);
+ p += DIV_ROUND_UP(ninode->fh.size, 4);
- p = nfs_packet + sizeof(struct rpc_reply) + 4;
-
- nfs_fattr3_to_stat(p, s);
+ nfs_read_post_op_attr(p, inode);
return 0;
}
@@ -784,7 +759,7 @@ static int nfs_attr_req(struct file_priv *priv, struct stat *s)
* returns with dir->stream pointing to the first entry
* of dirlist3 res.resok.reply
*/
-static void *nfs_readdirattr_req(struct file_priv *priv, struct nfs_dir *dir)
+static void *nfs_readdirattr_req(struct nfs_priv *npriv, struct nfs_dir *dir)
{
uint32_t data[1024];
uint32_t *p;
@@ -833,7 +808,7 @@ static void *nfs_readdirattr_req(struct file_priv *priv, struct nfs_dir *dir)
p = &(data[0]);
p = rpc_add_credentials(p);
- p = nfs_add_fh3(p, priv->filefh_len, priv->filefh);
+ p = nfs_add_fh3(p, &dir->fh);
p = nfs_add_uint64(p, dir->cookie);
memcpy(p, dir->cookieverf, NFS3_COOKIEVERFSIZE);
@@ -841,7 +816,7 @@ static void *nfs_readdirattr_req(struct file_priv *priv, struct nfs_dir *dir)
p = nfs_add_uint32(p, 1024); /* count */
- ret = rpc_req(priv->npriv, PROG_NFS, NFSPROC3_READDIR, data, p - data);
+ ret = rpc_req(npriv, PROG_NFS, NFSPROC3_READDIR, data, p - data);
if (ret)
return NULL;
@@ -909,7 +884,7 @@ static int nfs_read_req(struct file_priv *priv, uint64_t offset,
p = &(data[0]);
p = rpc_add_credentials(p);
- p = nfs_add_fh3(p, priv->filefh_len, priv->filefh);
+ p = nfs_add_fh3(p, &priv->fh);
p = nfs_add_uint64(p, offset);
p = nfs_add_uint32(p, readlen);
@@ -953,82 +928,11 @@ static void nfs_handler(void *ctx, char *packet, unsigned len)
nfs_len = len;
}
-static int nfs_create(struct device_d *dev, const char *pathname, mode_t mode)
-{
- return -ENOSYS;
-}
-
-static int nfs_unlink(struct device_d *dev, const char *pathname)
-{
- return -ENOSYS;
-}
-
-static int nfs_mkdir(struct device_d *dev, const char *pathname)
-{
- return -ENOSYS;
-}
-
-static int nfs_rmdir(struct device_d *dev, const char *pathname)
-{
- return -ENOSYS;
-}
-
static int nfs_truncate(struct device_d *dev, FILE *f, ulong size)
{
return -ENOSYS;
}
-static struct file_priv *nfs_do_open(struct device_d *dev,
- const char *filename, struct stat **s)
-{
- struct file_priv *priv;
- struct nfs_priv *npriv = dev->priv;
- int ret;
- const char *tok;
-
- debug("%s: filename = %s\n", __func__, filename);
- priv = xzalloc(sizeof(*priv));
-
- priv->npriv = npriv;
-
- if (!*filename) {
- priv->filefh_len = npriv->rootfh_len;
- memcpy(priv->filefh, npriv->rootfh, npriv->rootfh_len);
- return priv;
- }
-
- filename++;
-
- priv->filefh_len = npriv->rootfh_len;
- memcpy(priv->filefh, npriv->rootfh, NFS3_FHSIZE);
-
- while (*filename) {
- size_t flen;
-
- tok = strchr(filename, '/');
- if (tok)
- flen = tok - filename;
- else
- flen = strlen(filename);
-
- ret = nfs_lookup_req(priv, flen, filename, s);
- if (ret)
- goto out;
-
- if (tok)
- filename += flen + 1;
- else
- break;
- }
-
- return priv;
-
-out:
- free(priv);
-
- return ERR_PTR(ret);
-}
-
static void nfs_do_close(struct file_priv *priv)
{
if (priv->fifo)
@@ -1037,34 +941,8 @@ static void nfs_do_close(struct file_priv *priv)
free(priv);
}
-static struct file_priv *nfs_do_stat(struct device_d *dev,
- const char *filename, struct stat *s)
-{
- struct file_priv *priv;
- int ret;
- struct stat **sptr = &s;
-
- debug("%s: filename = %s\n", __func__, filename);
- priv = nfs_do_open(dev, filename, sptr);
- if (IS_ERR(priv))
- return priv;
-
- if (!*sptr) {
- /*
- * The nfs server didn't provide obj_attributes in the lookup
- * reply, so ask for them explicitly.
- */
- ret = nfs_attr_req(priv, s);
- if (ret) {
- nfs_do_close(priv);
- return ERR_PTR(ret);
- }
- }
-
- return priv;
-}
-
-static int nfs_readlink_req(struct file_priv *priv, char* buf, size_t size)
+static int nfs_readlink_req(struct nfs_priv *npriv, struct nfs_fh *fh,
+ char **target)
{
uint32_t data[1024];
uint32_t *p;
@@ -1095,11 +973,11 @@ static int nfs_readlink_req(struct file_priv *priv, char* buf, size_t size)
p = &(data[0]);
p = rpc_add_credentials(p);
- p = nfs_add_fh3(p, priv->filefh_len, priv->filefh);
+ p = nfs_add_fh3(p, fh);
len = p - &(data[0]);
- ret = rpc_req(priv->npriv, PROG_NFS, NFSPROC3_READLINK, data, len);
+ ret = rpc_req(npriv, PROG_NFS, NFSPROC3_READLINK, data, len);
if (ret)
return ret;
@@ -1110,44 +988,37 @@ static int nfs_readlink_req(struct file_priv *priv, char* buf, size_t size)
len = ntoh32(net_read_uint32(p)); /* new path length */
p++;
- if (len > size)
- return -ENOMEM;
-
- memcpy(buf, p, len);
+ *target = xzalloc(len + 1);
+ memcpy(*target, p, len);
return 0;
}
-static int nfs_readlink(struct device_d *dev, const char *filename,
- char *realname, size_t size)
+static const char *nfs_get_link(struct dentry *dentry, struct inode *inode)
{
- struct file_priv *priv;
+ struct nfs_inode *ninode = nfsi(inode);
+ struct nfs_priv *npriv = ninode->npriv;
int ret;
- priv = nfs_do_open(dev, filename, NULL);
- if (IS_ERR(priv))
- return PTR_ERR(priv);
-
- ret = nfs_readlink_req(priv, realname, size);
- if (ret) {
- nfs_do_close(priv);
- return ret;
- }
+ ret = nfs_readlink_req(npriv, &ninode->fh, &inode->i_link);
+ if (ret)
+ return ERR_PTR(ret);
- return 0;
+ return inode->i_link;
}
static int nfs_open(struct device_d *dev, FILE *file, const char *filename)
{
+ struct inode *inode = file->f_inode;
+ struct nfs_inode *ninode = nfsi(inode);
+ struct nfs_priv *npriv = ninode->npriv;
struct file_priv *priv;
- struct stat s;
-
- priv = nfs_do_stat(dev, filename, &s);
- if (IS_ERR(priv))
- return PTR_ERR(priv);
+ priv = xzalloc(sizeof(*priv));
+ priv->fh = ninode->fh;
+ priv->npriv = npriv;
file->priv = priv;
- file->size = s.st_size;
+ file->size = inode->i_size;
priv->fifo = kfifo_alloc(1024);
if (!priv->fifo) {
@@ -1199,115 +1070,170 @@ static loff_t nfs_lseek(struct device_d *dev, FILE *file, loff_t pos)
return file->pos;
}
-static DIR *nfs_opendir(struct device_d *dev, const char *pathname)
+static int nfs_iterate(struct file *file, struct dir_context *ctx)
{
- struct file_priv *priv;
+ struct dentry *dentry = file->f_path.dentry;
+ struct inode *dir = d_inode(dentry);
+ struct nfs_priv *npriv = nfsi(dir)->npriv;
void *buf = NULL;
- struct nfs_dir *dir;
+ struct nfs_dir *ndir;
+ struct xdr_stream *xdr;
+ int ret;
+ uint32_t *p, len;
- priv = nfs_do_open(dev, pathname, NULL);
- if (IS_ERR(priv))
- return NULL;
+ ndir = xzalloc(sizeof(*ndir));
+ ndir->fh = nfsi(dir)->fh;
- dir = xzalloc(sizeof(*dir));
- dir->priv = priv;
+ while (1) {
+ /* cookie == 0 and cookieverf == 0 means start of dir */
+ buf = nfs_readdirattr_req(npriv, ndir);
+ if (!buf) {
+ pr_err("%s: nfs_readdirattr_req failed\n", __func__);
+ ret = -EINVAL;
+ goto out;
+ }
- /* cookie == 0 and cookieverf == 0 means start of dir */
- buf = nfs_readdirattr_req(priv, dir);
- if (!buf) {
- debug("%s: nfs_readdirattr_req failed\n", __func__);
- goto err;
- }
+ xdr = &ndir->stream;
- return &dir->dir;
+ while (1) {
+ char name[256];
-err:
- free(buf);
- free(dir);
- nfs_do_close(priv);
- return NULL;
-}
+ p = xdr_inline_decode(xdr, 4);
+ if (!p)
+ goto err_eop;
-static struct dirent *nfs_readdir(struct device_d *dev, DIR *dir)
-{
- struct nfs_dir *ndir = container_of(dir, struct nfs_dir, dir);
- uint32_t *p;
- int ret;
- int len;
- struct xdr_stream *xdr = &ndir->stream;
+ if (!net_read_uint32(p)) {
+ /* eof? */
+ p = xdr_inline_decode(xdr, 4);
+ if (!p)
+ goto err_eop;
-again:
- p = xdr_inline_decode(xdr, 4);
- if (!p) {
- printf("%s: premature end of packet\n", __func__);
- return NULL;
- }
+ if (net_read_uint32(p)) {
+ ret = 0;
+ goto out;
+ }
- if (!net_read_uint32(p)) {
- /* eof? */
- p = xdr_inline_decode(xdr, 4);
- if (!p) {
- printf("%s: premature end of packet\n", __func__);
- return NULL;
- }
- if (net_read_uint32(p))
- return NULL;
+ break;
+ }
- if (!nfs_readdirattr_req(ndir->priv, ndir)) {
- printf("%s: nfs_readdirattr_req failed\n", __func__);
- return NULL;
- }
+ /* skip over fileid */
+ p = xdr_inline_decode(xdr, 8);
+ if (!p)
+ goto err_eop;
- goto again;
- }
+ ret = decode_filename(xdr, name, &len);
+ if (ret)
+ goto out;
- /* there is another entry available in the last reply */
+ dir_emit(ctx, name, len, 0, DT_UNKNOWN);
- /* skip over fileid */
- p = xdr_inline_decode(xdr, 8);
- if (!p) {
- printf("%s: premature end of packet\n", __func__);
- return NULL;
+ p = xdr_inline_decode(xdr, 8);
+ if (!p)
+ goto err_eop;
+
+ ndir->cookie = ntoh64(net_read_uint64(p));
+ }
+ free(buf);
}
- ret = decode_filename(xdr, ndir->ent.d_name, &len);
- if (ret)
- return NULL;
+ ret = 0;
- p = xdr_inline_decode(xdr, 8);
- if (!p) {
- printf("%s: premature end of packet\n", __func__);
+out:
+ free(ndir->stream.buf);
+ free(ndir);
+
+ return ret;
+
+err_eop:
+ pr_err("Unexpected end of packet\n");
+
+ return -EIO;
+}
+
+static struct inode *nfs_alloc_inode(struct super_block *sb)
+{
+ struct nfs_inode *node;
+
+ node = xzalloc(sizeof(*node));
+ if (!node)
return NULL;
- }
- ndir->cookie = ntoh64(net_read_uint64(p));
- return &ndir->ent;
+ return &node->inode;
}
-static int nfs_closedir(struct device_d *dev, DIR *dir)
+static const struct inode_operations nfs_file_inode_operations;
+static const struct file_operations nfs_dir_operations;
+static const struct inode_operations nfs_dir_inode_operations;
+static const struct file_operations nfs_file_operations;
+static const struct inode_operations nfs_symlink_inode_operations = {
+ .get_link = nfs_get_link,
+};
+
+static int nfs_init_inode(struct nfs_priv *npriv, struct inode *inode,
+ unsigned int mode)
{
- struct nfs_dir *ndir = (void *)dir;
+ struct nfs_inode *ninode = nfsi(inode);
- nfs_do_close(ndir->priv);
- free(ndir->stream.buf);
- free(ndir);
+ ninode->npriv = npriv;
+
+ inode->i_ino = get_next_ino();
+ inode->i_mode = mode;
+
+ switch (inode->i_mode & S_IFMT) {
+ default:
+ return -EINVAL;
+ case S_IFREG:
+ inode->i_op = &nfs_file_inode_operations;
+ inode->i_fop = &nfs_file_operations;
+ break;
+ case S_IFDIR:
+ inode->i_op = &nfs_dir_inode_operations;
+ inode->i_fop = &nfs_dir_operations;
+ inc_nlink(inode);
+ break;
+ case S_IFLNK:
+ inode->i_op = &nfs_symlink_inode_operations;
+ break;
+ }
return 0;
}
-static int nfs_stat(struct device_d *dev, const char *filename, struct stat *s)
+static struct dentry *nfs_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
{
- struct file_priv *priv;
+ struct nfs_inode *ndir = nfsi(dir);
+ struct inode *inode = new_inode(dir->i_sb);
+ struct nfs_priv *npriv = ndir->npriv;
+ int ret;
- priv = nfs_do_stat(dev, filename, s);
- if (IS_ERR(priv)) {
- return PTR_ERR(priv);
- } else {
- nfs_do_close(priv);
- return 0;
- }
+ if (!inode)
+ return NULL;
+
+ ret = nfs_lookup_req(npriv, &ndir->fh, dentry->name, inode);
+ if (ret)
+ return NULL;
+
+ nfs_init_inode(npriv, inode, inode->i_mode);
+
+ d_add(dentry, inode);
+
+ return NULL;
}
+static const struct file_operations nfs_dir_operations = {
+ .iterate = nfs_iterate,
+};
+
+static const struct inode_operations nfs_dir_inode_operations =
+{
+ .lookup = nfs_lookup,
+};
+
+static const struct super_operations nfs_ops = {
+ .alloc_inode = nfs_alloc_inode,
+};
+
static char *rootnfsopts;
static void nfs_set_rootarg(struct nfs_priv *npriv, struct fs_device_d *fsdev)
@@ -1347,8 +1273,10 @@ static int nfs_probe(struct device_d *dev)
{
struct fs_device_d *fsdev = dev_to_fs_device(dev);
struct nfs_priv *npriv = xzalloc(sizeof(struct nfs_priv));
+ struct super_block *sb = &fsdev->sb;
char *tmp = xstrdup(fsdev->backingstore);
char *path;
+ struct inode *inode;
int ret;
dev->priv = npriv;
@@ -1414,6 +1342,13 @@ static int nfs_probe(struct device_d *dev)
free(tmp);
+ sb->s_op = &nfs_ops;
+
+ inode = new_inode(sb);
+ nfs_set_fh(inode, &npriv->rootfh);
+ nfs_init_inode(npriv, inode, S_IFDIR);
+ sb->s_root = d_make_root(inode);
+
return 0;
err2:
@@ -1443,17 +1378,8 @@ static struct fs_driver_d nfs_driver = {
.close = nfs_close,
.read = nfs_read,
.lseek = nfs_lseek,
- .opendir = nfs_opendir,
- .readdir = nfs_readdir,
- .closedir = nfs_closedir,
- .stat = nfs_stat,
- .create = nfs_create,
- .unlink = nfs_unlink,
- .mkdir = nfs_mkdir,
- .rmdir = nfs_rmdir,
.write = nfs_write,
.truncate = nfs_truncate,
- .readlink = nfs_readlink,
.flags = 0,
.drv = {
.probe = nfs_probe,
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index 0c6f136920..0e042cb162 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -1,4 +1,5 @@
menuconfig FS_PSTORE
+ select FS_LEGACY
bool
prompt "pstore fs support"
help
diff --git a/fs/ramfs.c b/fs/ramfs.c
index a97f0a6ebf..7548bdac9f 100644
--- a/fs/ramfs.c
+++ b/fs/ramfs.c
@@ -35,6 +35,7 @@ struct ramfs_chunk {
};
struct ramfs_inode {
+ struct inode inode;
char *name;
struct ramfs_inode *parent;
struct ramfs_inode *next;
@@ -52,84 +53,52 @@ struct ramfs_inode {
struct ramfs_chunk *recent_chunkp;
};
+static inline struct ramfs_inode *to_ramfs_inode(struct inode *inode)
+{
+ return container_of(inode, struct ramfs_inode, inode);
+}
+
struct ramfs_priv {
struct ramfs_inode root;
};
/* ---------------------------------------------------------------*/
-static struct ramfs_inode * lookup(struct ramfs_inode *node, const char *name)
-{
- debug("lookup: %s in %p\n",name, node);
- if(!S_ISDIR(node->mode))
- return NULL;
-
- node = node->child;
- if (!node)
- return NULL;
-
- while (node) {
- debug("lookup: %s\n", node->name);
- if (!strcmp(node->name, name)) {
- debug("lookup: found: 0x%p\n",node);
- return node;
- }
- node = node->next;
- }
- return NULL;
-}
-static struct ramfs_inode* rlookup(struct ramfs_priv *priv, const char *path)
-{
- struct ramfs_inode *node = &priv->root;
- static char *buf;
- char *part;
-
- debug("rlookup %s in %p\n",path, node);
- buf = strdup(path);
-
- part = strtok(buf, "/");
- if (!part)
- goto out;
-
- do {
- node = lookup(node, part);
- if (!node)
- goto out;
- part = strtok(NULL, "/");
- } while(part);
-
-out:
- free(buf);
- return node;
-}
+static const struct super_operations ramfs_ops;
+static const struct inode_operations ramfs_dir_inode_operations;
+static const struct inode_operations ramfs_file_inode_operations;
+static const struct inode_operations ramfs_symlink_inode_operations;
+static const struct file_operations ramfs_file_operations;
-static struct ramfs_inode* rlookup_parent(struct ramfs_priv *priv, const char *pathname, char **file)
+static struct inode *ramfs_get_inode(struct super_block *sb, const struct inode *dir,
+ umode_t mode)
{
- char *path;
- struct ramfs_inode *node;
+ struct inode *inode = new_inode(sb);
- pathname++;
- path = strdup(pathname);
+ if (!inode)
+ return NULL;
- if ((*file = strrchr((char *) pathname, '/'))) {
- char *tmp;
- (*file)++;
+ inode->i_ino = get_next_ino();
+ inode->i_mode = mode;
- tmp = strrchr(path, '/');
- *tmp = 0;
- node = rlookup(priv, path);
- if (!node) {
- errno = -ENOENT;
- goto out;
- }
- } else {
- *file = (char *)pathname;
- node = &priv->root;
+ switch (mode & S_IFMT) {
+ default:
+ return NULL;
+ case S_IFREG:
+ inode->i_op = &ramfs_file_inode_operations;
+ inode->i_fop = &ramfs_file_operations;
+ break;
+ case S_IFDIR:
+ inode->i_op = &ramfs_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+ inc_nlink(inode);
+ break;
+ case S_IFLNK:
+ inode->i_op = &ramfs_symlink_inode_operations;
+ break;
}
-out:
- free(path);
- return node;
+ return inode;
}
static int chunks = 0;
@@ -140,7 +109,7 @@ static struct ramfs_chunk *ramfs_get_chunk(void)
if (!data)
return NULL;
- data->data = malloc(CHUNK_SIZE);
+ data->data = calloc(CHUNK_SIZE, 1);
if (!data->data) {
free(data);
return NULL;
@@ -158,168 +127,75 @@ static void ramfs_put_chunk(struct ramfs_chunk *data)
chunks--;
}
-static struct ramfs_inode* ramfs_get_inode(void)
-{
- struct ramfs_inode *node = xzalloc(sizeof(struct ramfs_inode));
- return node;
-}
-
-static void ramfs_put_inode(struct ramfs_inode *node)
-{
- struct ramfs_chunk *data = node->data;
-
- while (data) {
- struct ramfs_chunk *tmp = data->next;
- ramfs_put_chunk(data);
- data = tmp;
- }
-
- free(node->symlink);
- free(node->name);
- free(node);
-}
-
-static struct ramfs_inode* node_insert(struct ramfs_inode *parent_node, const char *filename, ulong mode)
-{
- struct ramfs_inode *node, *new_node = ramfs_get_inode();
- new_node->name = strdup(filename);
- new_node->mode = mode;
-
- node = parent_node->child;
-
- if (S_ISDIR(mode)) {
- struct ramfs_inode *n = ramfs_get_inode();
- n->name = strdup(".");
- n->mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
- n->child = n;
- n->parent = new_node;
- new_node->child = n;
- n = ramfs_get_inode();
- n->name = strdup("..");
- n->mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
- n->parent = new_node;
- n->child = parent_node->child;
- new_node->child->next = n;
- }
-
- while (node->next)
- node = node->next;
-
- node->next = new_node;
- return new_node;
-}
-
/* ---------------------------------------------------------------*/
-static int __ramfs_create(struct device_d *dev, const char *pathname,
- mode_t mode, const char *symlink)
+static int
+ramfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode)
{
- struct ramfs_priv *priv = dev->priv;
- struct ramfs_inode *node;
- char *file;
- char *__symlink = NULL;
+ struct inode *inode = ramfs_get_inode(dir->i_sb, dir, mode);
- node = rlookup_parent(priv, pathname, &file);
- if (!node)
- return -ENOENT;
-
- if (symlink) {
- __symlink = strdup(symlink);
- if (!__symlink)
- return -ENOMEM;
- }
+ if (!inode)
+ return -ENOSPC;
- node = node_insert(node, file, mode);
- if (!node) {
- free(__symlink);
- return -ENOMEM;
+ if (inode) {
+ d_instantiate(dentry, inode);
+ dget(dentry); /* Extra count - pin the dentry in core */
}
- node->symlink = __symlink;
-
return 0;
}
-static int ramfs_create(struct device_d *dev, const char *pathname, mode_t mode)
+static int ramfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
- return __ramfs_create(dev, pathname, mode, NULL);
-}
+ int ret;
-static int ramfs_unlink(struct device_d *dev, const char *pathname)
-{
- struct ramfs_priv *priv = dev->priv;
- struct ramfs_inode *node, *lastnode;
- char *file;
-
- node = rlookup_parent(priv, pathname, &file);
-
- lastnode = node->child->next;
- node = lastnode->next;
-
- while (node) {
- if (!strcmp(node->name, file)) {
- struct ramfs_inode *tmp;
- tmp = node;
- lastnode->next = node->next;
- ramfs_put_inode(tmp);
- return 0;
- }
- lastnode = node;
- node = node->next;
- };
- return -ENOENT;
-}
+ ret = ramfs_mknod(dir, dentry, mode | S_IFDIR);
+ if (!ret)
+ inc_nlink(dir);
-static int ramfs_mkdir(struct device_d *dev, const char *pathname)
-{
- return ramfs_create(dev, pathname, S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
+ return ret;
}
-static int ramfs_rmdir(struct device_d *dev, const char *pathname)
+static int ramfs_create(struct inode *dir, struct dentry *dentry, umode_t mode)
{
- struct ramfs_priv *priv = dev->priv;
- struct ramfs_inode *node, *lastnode;
- char *file;
-
- node = rlookup_parent(priv, pathname, &file);
-
- lastnode = node->child->next;
- node = lastnode->next;
-
- while (node) {
- if (!strcmp(node->name, file)) {
- struct ramfs_inode *tmp;
- tmp = node;
- lastnode->next = node->next;
- ramfs_put_inode(tmp->child->next);
- ramfs_put_inode(tmp->child);
- ramfs_put_inode(tmp);
- return 0;
- }
- lastnode = node;
- node = node->next;
- };
- return -ENOENT;
+ return ramfs_mknod(dir, dentry, mode | S_IFREG);
}
-static int ramfs_open(struct device_d *dev, FILE *file, const char *filename)
+static int ramfs_symlink(struct inode *dir, struct dentry *dentry,
+ const char *symname)
{
- struct ramfs_priv *priv = dev->priv;
- struct ramfs_inode *node = rlookup(priv, filename);
+ struct inode *inode;
- if (!node)
- return -ENOENT;
+ inode = ramfs_get_inode(dir->i_sb, dir, S_IFLNK | S_IRWXG);
+ if (!inode)
+ return -ENOSPC;
+
+ inode->i_link = xstrdup(symname);
+ d_instantiate(dentry, inode);
- file->size = node->size;
- file->priv = node;
return 0;
}
-static int ramfs_close(struct device_d *dev, FILE *f)
+static const char *ramfs_get_link(struct dentry *dentry, struct inode *inode)
{
- return 0;
+ return inode->i_link;
}
+static const struct inode_operations ramfs_symlink_inode_operations =
+{
+ .get_link = ramfs_get_link,
+};
+
+static const struct inode_operations ramfs_dir_inode_operations =
+{
+ .lookup = simple_lookup,
+ .symlink = ramfs_symlink,
+ .mkdir = ramfs_mkdir,
+ .rmdir = simple_rmdir,
+ .unlink = simple_unlink,
+ .create = ramfs_create,
+};
+
static struct ramfs_chunk *ramfs_find_chunk(struct ramfs_inode *node, int chunk)
{
struct ramfs_chunk *data;
@@ -351,7 +227,8 @@ static struct ramfs_chunk *ramfs_find_chunk(struct ramfs_inode *node, int chunk)
static int ramfs_read(struct device_d *_dev, FILE *f, void *buf, size_t insize)
{
- struct ramfs_inode *node = f->priv;
+ struct inode *inode = f->f_inode;
+ struct ramfs_inode *node = to_ramfs_inode(inode);
int chunk;
struct ramfs_chunk *data;
int ofs;
@@ -359,12 +236,12 @@ static int ramfs_read(struct device_d *_dev, FILE *f, void *buf, size_t insize)
int pos = f->pos;
int size = insize;
- chunk = f->pos / CHUNK_SIZE;
+ chunk = pos / CHUNK_SIZE;
debug("%s: reading from chunk %d\n", __FUNCTION__, chunk);
/* Position ourself in stream */
data = ramfs_find_chunk(node, chunk);
- ofs = f->pos % CHUNK_SIZE;
+ ofs = pos % CHUNK_SIZE;
/* Read till end of current chunk */
if (ofs) {
@@ -400,7 +277,8 @@ static int ramfs_read(struct device_d *_dev, FILE *f, void *buf, size_t insize)
static int ramfs_write(struct device_d *_dev, FILE *f, const void *buf, size_t insize)
{
- struct ramfs_inode *node = f->priv;
+ struct inode *inode = f->f_inode;
+ struct ramfs_inode *node = to_ramfs_inode(inode);
int chunk;
struct ramfs_chunk *data;
int ofs;
@@ -455,7 +333,8 @@ static loff_t ramfs_lseek(struct device_d *dev, FILE *f, loff_t pos)
static int ramfs_truncate(struct device_d *dev, FILE *f, ulong size)
{
- struct ramfs_inode *node = f->priv;
+ struct inode *inode = f->f_inode;
+ struct ramfs_inode *node = to_ramfs_inode(inode);
int oldchunks, newchunks;
struct ramfs_chunk *data = node->data;
@@ -502,108 +381,38 @@ static int ramfs_truncate(struct device_d *dev, FILE *f, ulong size)
return 0;
}
-static DIR* ramfs_opendir(struct device_d *dev, const char *pathname)
+static struct inode *ramfs_alloc_inode(struct super_block *sb)
{
- DIR *dir;
- struct ramfs_priv *priv = dev->priv;
struct ramfs_inode *node;
- debug("opendir: %s\n", pathname);
-
- node = rlookup(priv, pathname);
-
+ node = xzalloc(sizeof(*node));
if (!node)
return NULL;
- if (!S_ISDIR(node->mode))
- return NULL;
-
- dir = xmalloc(sizeof(DIR));
-
- dir->priv = node->child;
-
- return dir;
-}
-
-static struct dirent* ramfs_readdir(struct device_d *dev, DIR *dir)
-{
- struct ramfs_inode *node = dir->priv;
-
- if (node) {
- strcpy(dir->d.d_name, node->name);
- dir->priv = node->next;
- return &dir->d;
- }
- return NULL;
-}
-
-static int ramfs_closedir(struct device_d *dev, DIR *dir)
-{
- free(dir);
- return 0;
-}
-
-static int ramfs_stat(struct device_d *dev, const char *filename, struct stat *s)
-{
- struct ramfs_priv *priv = dev->priv;
- struct ramfs_inode *node = rlookup(priv, filename);
-
- if (!node)
- return -ENOENT;
-
- s->st_size = node->symlink ? strlen(node->symlink) : node->size;
- s->st_mode = node->mode;
-
- return 0;
-}
-
-static int ramfs_symlink(struct device_d *dev, const char *pathname,
- const char *newpath)
-{
- mode_t mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
-
- return __ramfs_create(dev, newpath, mode, pathname);
+ return &node->inode;
}
-static int ramfs_readlink(struct device_d *dev, const char *pathname,
- char *buf, size_t bufsiz)
-{
- struct ramfs_priv *priv = dev->priv;
- struct ramfs_inode *node = rlookup(priv, pathname);
- int len;
-
- if (!node || !node->symlink)
- return -ENOENT;
-
- len = min(bufsiz, strlen(node->symlink));
-
- memcpy(buf, node->symlink, len);
-
- return 0;
-}
+static const struct super_operations ramfs_ops = {
+ .alloc_inode = ramfs_alloc_inode,
+};
static int ramfs_probe(struct device_d *dev)
{
- struct ramfs_inode *n;
+ struct inode *inode;
struct ramfs_priv *priv = xzalloc(sizeof(struct ramfs_priv));
+ struct fs_device_d *fsdev = dev_to_fs_device(dev);
+ struct super_block *sb = &fsdev->sb;
dev->priv = priv;
priv->root.name = "/";
priv->root.mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
priv->root.parent = &priv->root;
- n = ramfs_get_inode();
- n->name = strdup(".");
- n->mode = S_IFDIR;
- n->parent = &priv->root;
- n->child = n;
- priv->root.child = n;
- n = ramfs_get_inode();
- n->name = strdup("..");
- n->mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
- n->parent = &priv->root;
- n->child = priv->root.child;
- priv->root.child->next = n;
+
+ sb->s_op = &ramfs_ops;
+
+ inode = ramfs_get_inode(sb, NULL, S_IFDIR);
+ sb->s_root = d_make_root(inode);
return 0;
}
@@ -614,22 +423,10 @@ static void ramfs_remove(struct device_d *dev)
}
static struct fs_driver_d ramfs_driver = {
- .create = ramfs_create,
- .unlink = ramfs_unlink,
- .open = ramfs_open,
- .close = ramfs_close,
- .truncate = ramfs_truncate,
.read = ramfs_read,
.write = ramfs_write,
.lseek = ramfs_lseek,
- .mkdir = ramfs_mkdir,
- .rmdir = ramfs_rmdir,
- .opendir = ramfs_opendir,
- .readdir = ramfs_readdir,
- .closedir = ramfs_closedir,
- .stat = ramfs_stat,
- .symlink = ramfs_symlink,
- .readlink = ramfs_readlink,
+ .truncate = ramfs_truncate,
.flags = FS_DRIVER_NO_DEV,
.drv = {
.probe = ramfs_probe,
diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile
index 077114c49c..81fc7e570d 100644
--- a/fs/squashfs/Makefile
+++ b/fs/squashfs/Makefile
@@ -10,6 +10,8 @@ obj-y += id.o
obj-y += inode.o
obj-y += namei.o
obj-y += super.o
+obj-y += symlink.o
+obj-y += dir.o
obj-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o
obj-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o
obj-$(CONFIG_SQUASHFS_LZ4) += lz4_wrapper.o
diff --git a/fs/squashfs/dir.c b/fs/squashfs/dir.c
new file mode 100644
index 0000000000..6275857136
--- /dev/null
+++ b/fs/squashfs/dir.c
@@ -0,0 +1,232 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ * Phillip Lougher <phillip@squashfs.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * dir.c
+ */
+
+/*
+ * This file implements code to read directories from disk.
+ *
+ * See namei.c for a description of directory organisation on disk.
+ */
+
+#include <linux/fs.h>
+
+#include "squashfs_fs.h"
+#include "squashfs_fs_sb.h"
+#include "squashfs_fs_i.h"
+#include "squashfs.h"
+
+static const unsigned char squashfs_filetype_table[] = {
+ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
+};
+
+/*
+ * Lookup offset (f_pos) in the directory index, returning the
+ * metadata block containing it.
+ *
+ * If we get an error reading the index then return the part of the index
+ * (if any) we have managed to read - the index isn't essential, just
+ * quicker.
+ */
+static int get_dir_index_using_offset(struct super_block *sb,
+ u64 *next_block, int *next_offset, u64 index_start, int index_offset,
+ int i_count, u64 f_pos)
+{
+ struct squashfs_sb_info *msblk = sb->s_fs_info;
+ int err, i, index, length = 0;
+ unsigned int size;
+ struct squashfs_dir_index dir_index;
+
+ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %lld\n",
+ i_count, f_pos);
+
+ /*
+ * Translate from external f_pos to the internal f_pos. This
+ * is offset by 3 because we invent "." and ".." entries which are
+ * not actually stored in the directory.
+ */
+ if (f_pos <= 3)
+ return f_pos;
+ f_pos -= 3;
+
+ for (i = 0; i < i_count; i++) {
+ err = squashfs_read_metadata(sb, &dir_index, &index_start,
+ &index_offset, sizeof(dir_index));
+ if (err < 0)
+ break;
+
+ index = le32_to_cpu(dir_index.index);
+ if (index > f_pos)
+ /*
+ * Found the index we're looking for.
+ */
+ break;
+
+ size = le32_to_cpu(dir_index.size) + 1;
+
+ /* size should never be larger than SQUASHFS_NAME_LEN */
+ if (size > SQUASHFS_NAME_LEN)
+ break;
+
+ err = squashfs_read_metadata(sb, NULL, &index_start,
+ &index_offset, size);
+ if (err < 0)
+ break;
+
+ length = index;
+ *next_block = le32_to_cpu(dir_index.start_block) +
+ msblk->directory_table;
+ }
+
+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
+
+ /*
+ * Translate back from internal f_pos to external f_pos.
+ */
+ return length + 3;
+}
+
+
+static int squashfs_readdir(struct file *file, struct dir_context *ctx)
+{
+ struct dentry *dentry = file->f_path.dentry;
+ struct inode *inode = d_inode(dentry);
+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
+ u64 block = squashfs_i(inode)->start + msblk->directory_table;
+ int offset = squashfs_i(inode)->offset, length, err;
+ unsigned int inode_number, dir_count, size, type;
+ struct squashfs_dir_header dirh;
+ struct squashfs_dir_entry *dire;
+
+ TRACE("Entered squashfs_readdir [%llx:%x]\n", block, offset);
+
+ dire = kmalloc(sizeof(*dire) + SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
+ if (dire == NULL) {
+ ERROR("Failed to allocate squashfs_dir_entry\n");
+ goto finish;
+ }
+
+ /*
+ * Return "." and ".." entries as the first two filenames in the
+ * directory. To maximise compression these two entries are not
+ * stored in the directory, and so we invent them here.
+ *
+ * It also means that the external f_pos is offset by 3 from the
+ * on-disk directory f_pos.
+ */
+ while (ctx->pos < 3) {
+ char *name;
+ int i_ino;
+
+ if (ctx->pos == 0) {
+ name = ".";
+ size = 1;
+ i_ino = inode->i_ino;
+ } else {
+ name = "..";
+ size = 2;
+ i_ino = squashfs_i(inode)->parent;
+ }
+
+ if (!dir_emit(ctx, name, size, i_ino,
+ squashfs_filetype_table[1]))
+ goto finish;
+
+ ctx->pos += size;
+ }
+
+ length = get_dir_index_using_offset(inode->i_sb, &block, &offset,
+ squashfs_i(inode)->dir_idx_start,
+ squashfs_i(inode)->dir_idx_offset,
+ squashfs_i(inode)->dir_idx_cnt,
+ ctx->pos);
+
+ while (length < i_size_read(inode)) {
+ /*
+ * Read directory header
+ */
+ err = squashfs_read_metadata(inode->i_sb, &dirh, &block,
+ &offset, sizeof(dirh));
+ if (err < 0)
+ goto failed_read;
+
+ length += sizeof(dirh);
+
+ dir_count = le32_to_cpu(dirh.count) + 1;
+
+ if (dir_count > SQUASHFS_DIR_COUNT)
+ goto failed_read;
+
+ while (dir_count--) {
+ /*
+ * Read directory entry.
+ */
+ err = squashfs_read_metadata(inode->i_sb, dire, &block,
+ &offset, sizeof(*dire));
+ if (err < 0)
+ goto failed_read;
+
+ size = le16_to_cpu(dire->size) + 1;
+
+ /* size should never be larger than SQUASHFS_NAME_LEN */
+ if (size > SQUASHFS_NAME_LEN)
+ goto failed_read;
+
+ err = squashfs_read_metadata(inode->i_sb, dire->name,
+ &block, &offset, size);
+ if (err < 0)
+ goto failed_read;
+
+ length += sizeof(*dire) + size;
+
+ if (ctx->pos >= length)
+ continue;
+
+ dire->name[size] = '\0';
+ inode_number = le32_to_cpu(dirh.inode_number) +
+ ((short) le16_to_cpu(dire->inode_number));
+ type = le16_to_cpu(dire->type);
+
+ if (type > SQUASHFS_MAX_DIR_TYPE)
+ goto failed_read;
+
+ if (!dir_emit(ctx, dire->name, size,
+ inode_number,
+ squashfs_filetype_table[type]))
+ goto finish;
+
+ ctx->pos = length;
+ }
+ }
+
+finish:
+ kfree(dire);
+ return 0;
+
+failed_read:
+ ERROR("Unable to read directory block [%llx:%x]\n", block, offset);
+ kfree(dire);
+ return 0;
+}
+
+const struct file_operations squashfs_dir_ops = {
+ .iterate = squashfs_readdir,
+};
diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c
index 923c397fa8..470536e589 100644
--- a/fs/squashfs/inode.c
+++ b/fs/squashfs/inode.c
@@ -172,6 +172,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
}
inode->i_size = le32_to_cpu(sqsh_ino->file_size);
+ inode->i_op = &squashfs_inode_ops;
inode->i_mode |= S_IFREG;
inode->i_blocks = ((inode->i_size - 1) >> 9) + 1;
squashfs_i(inode)->fragment_block = frag_blk;
@@ -214,6 +215,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
xattr_id = le32_to_cpu(sqsh_ino->xattr);
inode->i_size = le64_to_cpu(sqsh_ino->file_size);
+ inode->i_op = &squashfs_inode_ops;
inode->i_mode |= S_IFREG;
inode->i_blocks = (inode->i_size -
le64_to_cpu(sqsh_ino->sparse) + 511) >> 9;
@@ -240,6 +242,8 @@ int squashfs_read_inode(struct inode *inode, long long ino)
goto failed_read;
inode->i_size = le16_to_cpu(sqsh_ino->file_size);
+ inode->i_op = &squashfs_dir_inode_ops;
+ inode->i_fop = &squashfs_dir_ops;
inode->i_mode |= S_IFDIR;
squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset);
@@ -263,6 +267,8 @@ int squashfs_read_inode(struct inode *inode, long long ino)
xattr_id = le32_to_cpu(sqsh_ino->xattr);
inode->i_size = le32_to_cpu(sqsh_ino->file_size);
+ inode->i_op = &squashfs_dir_inode_ops;
+ inode->i_fop = &squashfs_dir_ops;
inode->i_mode |= S_IFDIR;
squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset);
@@ -288,6 +294,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
goto failed_read;
inode->i_size = le32_to_cpu(sqsh_ino->symlink_size);
+ inode->i_op = &squashfs_symlink_inode_ops;
inode->i_mode |= S_IFLNK;
squashfs_i(inode)->start = block;
squashfs_i(inode)->offset = offset;
@@ -400,3 +407,5 @@ failed_read:
ERROR("Unable to read inode 0x%llx\n", ino);
return err;
}
+
+const struct inode_operations squashfs_inode_ops;
diff --git a/fs/squashfs/namei.c b/fs/squashfs/namei.c
index 482fda5a11..baf1e8b646 100644
--- a/fs/squashfs/namei.c
+++ b/fs/squashfs/namei.c
@@ -48,11 +48,11 @@
* and doesn't require much extra storage on disk.
*/
+#include <common.h>
#include <linux/fs.h>
#include <malloc.h>
#include <linux/string.h>
#include <linux/dcache.h>
-#include <common.h>
#include "squashfs_fs.h"
#include "squashfs_fs_sb.h"
@@ -130,11 +130,11 @@ out:
}
-struct inode *squashfs_lookup(struct inode *dir, const char *cur_name,
- unsigned int flags)
+static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
{
- const unsigned char *name = cur_name;
- int len = strlen(cur_name);
+ const unsigned char *name = dentry->d_name.name;
+ int len = dentry->d_name.len;
struct inode *inode = NULL;
struct squashfs_sb_info *msblk = dir->i_sb->s_fs_info;
struct squashfs_dir_header dirh;
@@ -223,7 +223,8 @@ struct inode *squashfs_lookup(struct inode *dir, const char *cur_name,
exit_lookup:
kfree(dire);
- return inode;
+ d_add(dentry, inode);
+ return NULL;
data_error:
err = -EIO;
@@ -344,3 +345,7 @@ failed:
kfree(dire);
return 1;
}
+
+const struct inode_operations squashfs_dir_inode_ops = {
+ .lookup = squashfs_lookup,
+};
diff --git a/fs/squashfs/squashfs.c b/fs/squashfs/squashfs.c
index cf7431ee04..d9049b7523 100644
--- a/fs/squashfs/squashfs.c
+++ b/fs/squashfs/squashfs.c
@@ -39,81 +39,7 @@ char *squashfs_devread(struct squashfs_sb_info *fs, int byte_offset,
return buf;
}
-static struct inode *duplicate_inode(struct inode *inode)
-{
- struct squashfs_inode_info *ei;
- ei = malloc(sizeof(struct squashfs_inode_info));
- if (ei == NULL) {
- ERROR("Error allocating memory for inode\n");
- return NULL;
- }
- memcpy(ei, squashfs_i(inode),
- sizeof(struct squashfs_inode_info));
-
- return &ei->vfs_inode;
-}
-
-static struct inode *squashfs_findfile(struct super_block *sb,
- const char *filename, char *buf)
-{
- char *next;
- char fpath[128];
- char *name = fpath;
- struct inode *inode;
- struct inode *t_inode = NULL;
-
- strcpy(fpath, filename);
-
- /* Remove all leading slashes */
- while (*name == '/')
- name++;
-
- inode = duplicate_inode(sb->s_root->d_inode);
-
- /*
- * Handle root-directory ('/')
- */
- if (!name || *name == '\0')
- return inode;
-
- for (;;) {
- /* Extract the actual part from the pathname. */
- next = strchr(name, '/');
- if (next) {
- /* Remove all leading slashes. */
- while (*next == '/')
- *(next++) = '\0';
- }
-
- t_inode = squashfs_lookup(inode, name, 0);
- if (t_inode == NULL)
- break;
-
- /*
- * Check if directory with this name exists
- */
-
- /* Found the node! */
- if (!next || *next == '\0') {
- if (buf != NULL)
- sprintf(buf, "%s", name);
-
- free(squashfs_i(inode));
- return t_inode;
- }
-
- name = next;
-
- free(squashfs_i(inode));
- inode = t_inode;
- }
-
- free(squashfs_i(inode));
- return NULL;
-}
-
-static void squashfs_set_rootarg(struct squashfs_priv *priv,
- struct fs_device_d *fsdev)
+static void squashfs_set_rootarg(struct fs_device_d *fsdev)
{
struct ubi_volume_desc *ubi_vol;
struct ubi_volume_info vi = {};
@@ -141,16 +67,27 @@ static void squashfs_set_rootarg(struct squashfs_priv *priv,
free(str);
}
+static struct inode *squashfs_alloc_inode(struct super_block *sb)
+{
+ struct squashfs_inode_info *node;
+
+ node = xzalloc(sizeof(*node));
+
+ return &node->vfs_inode;
+}
+
+static const struct super_operations squashfs_super_ops = {
+ .alloc_inode = squashfs_alloc_inode,
+};
+
static int squashfs_probe(struct device_d *dev)
{
struct fs_device_d *fsdev;
- struct squashfs_priv *priv;
int ret;
+ struct super_block *sb;
fsdev = dev_to_fs_device(dev);
-
- priv = xzalloc(sizeof(struct squashfs_priv));
- dev->priv = priv;
+ sb = &fsdev->sb;
ret = fsdev_open_cdev(fsdev);
if (ret)
@@ -163,35 +100,34 @@ static int squashfs_probe(struct device_d *dev)
goto err_out;
}
- squashfs_set_rootarg(priv, fsdev);
+ squashfs_set_rootarg(fsdev);
+
+ sb->s_op = &squashfs_super_ops;
return 0;
err_out:
- free(priv);
return ret;
}
static void squashfs_remove(struct device_d *dev)
{
- struct squashfs_priv *priv = dev->priv;
+ struct fs_device_d *fsdev;
+ struct super_block *sb;
+
+ fsdev = dev_to_fs_device(dev);
+ sb = &fsdev->sb;
- squashfs_put_super(&priv->sb);
- free(priv);
+ squashfs_put_super(sb);
}
static int squashfs_open(struct device_d *dev, FILE *file, const char *filename)
{
- struct squashfs_priv *priv = dev->priv;
- struct inode *inode;
+ struct inode *inode = file->f_inode;
struct squashfs_page *page;
int i;
- inode = squashfs_findfile(&priv->sb, filename, NULL);
- if (!inode)
- return -ENOENT;
-
page = malloc(sizeof(struct squashfs_page));
page->buf = calloc(32, sizeof(*page->buf));
for (i = 0; i < 32; i++) {
@@ -229,7 +165,6 @@ static int squashfs_close(struct device_d *dev, FILE *f)
free(page->buf[i]);
free(page->buf);
- free(squashfs_i(page->real_page.inode));
free(page);
return 0;
@@ -314,80 +249,11 @@ struct squashfs_dir {
char root_d_name[256];
};
-static DIR *squashfs_opendir(struct device_d *dev, const char *pathname)
-{
- struct squashfs_priv *priv = dev->priv;
- struct inode *inode;
- struct squashfs_dir *dir;
- char buf[256];
-
- inode = squashfs_findfile(&priv->sb, pathname, buf);
- if (!inode)
- return NULL;
-
- dir = xzalloc(sizeof(struct squashfs_dir));
- dir->dir.priv = dir;
-
- dir->root_dentry.d_inode = inode;
-
- sprintf(dir->d_name, "%s", buf);
- sprintf(dir->root_d_name, "%s", buf);
-
- return &dir->dir;
-}
-
-static struct dirent *squashfs_readdir(struct device_d *dev, DIR *_dir)
-{
- struct squashfs_dir *dir = _dir->priv;
- struct dentry *root_dentry = &dir->root_dentry;
-
- if (squashfs_lookup_next(root_dentry->d_inode,
- dir->root_d_name,
- dir->d_name))
- return NULL;
-
- strcpy(_dir->d.d_name, dir->d_name);
-
- return &_dir->d;
-}
-
-static int squashfs_closedir(struct device_d *dev, DIR *_dir)
-{
- struct squashfs_dir *dir = _dir->priv;
-
- free(squashfs_i(dir->root_dentry.d_inode));
- free(dir);
-
- return 0;
-}
-
-static int squashfs_stat(struct device_d *dev, const char *filename,
- struct stat *s)
-{
- struct squashfs_priv *priv = dev->priv;
- struct inode *inode;
-
- inode = squashfs_findfile(&priv->sb, filename, NULL);
- if (!inode)
- return -ENOENT;
-
- s->st_size = inode->i_size;
- s->st_mode = inode->i_mode;
-
- free(squashfs_i(inode));
-
- return 0;
-}
-
static struct fs_driver_d squashfs_driver = {
.open = squashfs_open,
.close = squashfs_close,
.read = squashfs_read,
.lseek = squashfs_lseek,
- .opendir = squashfs_opendir,
- .readdir = squashfs_readdir,
- .closedir = squashfs_closedir,
- .stat = squashfs_stat,
.type = filetype_squashfs,
.drv = {
.probe = squashfs_probe,
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h
index 9ad6534e46..31c9bc454e 100644
--- a/fs/squashfs/squashfs.h
+++ b/fs/squashfs/squashfs.h
@@ -25,10 +25,6 @@
#define DEBUG
#define pgoff_t unsigned long
-struct squashfs_priv {
- struct super_block sb;
-};
-
/*
* We "simulate" the Linux page struct much simpler here
*/
@@ -132,10 +128,7 @@ extern const struct address_space_operations squashfs_aops;
extern const struct inode_operations squashfs_inode_ops;
/* namei.c */
-extern struct inode *squashfs_lookup(struct inode *dir, const char *cur_name,
- unsigned int flags);
-extern int squashfs_lookup_next(struct inode *dir,
- char *root_name, char *cur_name);
+extern const struct inode_operations squashfs_dir_inode_ops;
/* symlink.c */
extern const struct address_space_operations squashfs_symlink_aops;
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c
index 4c730e09e4..e2b7b8d5a1 100644
--- a/fs/squashfs/super.c
+++ b/fs/squashfs/super.c
@@ -39,15 +39,6 @@
#include "squashfs.h"
#include "decompressor.h"
-static struct dentry *d_make_root(struct inode *inode)
-{
- struct dentry *de = malloc(sizeof(struct dentry));
- de->d_name.name = "/";
- de->d_name.len = strlen("/");
- de->d_inode = inode;
- return de;
-}
-
static const struct squashfs_decompressor *supported_squashfs_filesystem(short
major, short minor, short id)
{
@@ -333,11 +324,11 @@ failed_mount:
int squashfs_mount(struct fs_device_d *fsdev, int silent)
{
- struct squashfs_priv *priv = fsdev->dev.priv;
+ struct super_block *sb = &fsdev->sb;
dev_dbg(&fsdev->dev, "squashfs_mount\n");
- if (squashfs_fill_super(&priv->sb, fsdev, silent))
+ if (squashfs_fill_super(sb, fsdev, silent))
return -EINVAL;
return 0;
diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c
new file mode 100644
index 0000000000..40b9bdcc8b
--- /dev/null
+++ b/fs/squashfs/symlink.c
@@ -0,0 +1,82 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ * Phillip Lougher <phillip@squashfs.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * symlink.c
+ */
+
+/*
+ * This file implements code to handle symbolic links.
+ *
+ * The data contents of symbolic links are stored inside the symbolic
+ * link inode within the inode table. This allows the normally small symbolic
+ * link to be compressed as part of the inode table, achieving much greater
+ * compression than if the symbolic link was compressed individually.
+ */
+
+#include <malloc.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/pagemap.h>
+
+#include "squashfs_fs.h"
+#include "squashfs_fs_sb.h"
+#include "squashfs_fs_i.h"
+#include "squashfs.h"
+
+static const char *squashfs_get_link(struct dentry *dentry, struct inode *inode)
+{
+ struct super_block *sb = inode->i_sb;
+ int index = 0;
+ u64 block = squashfs_i(inode)->start;
+ int offset = squashfs_i(inode)->offset;
+ int length = min_t(int, i_size_read(inode) - index, PAGE_SIZE);
+ int bytes;
+ unsigned char *symlink;
+
+ TRACE("Entered squashfs_symlink_readpage, start block "
+ "%llx, offset %x\n", block, offset);
+
+ symlink = malloc(length + 1);
+ if (!symlink)
+ return NULL;
+
+ symlink[length] = 0;
+
+ bytes = squashfs_read_metadata(sb, symlink, &block, &offset, length);
+ if (bytes < 0) {
+ ERROR("Unable to read symlink [%llx:%x]\n",
+ squashfs_i(inode)->start,
+ squashfs_i(inode)->offset);
+ goto error_out;
+ }
+
+ inode->i_link = symlink;
+
+ return inode->i_link;
+
+error_out:
+ free(symlink);
+
+ return NULL;
+}
+
+const struct inode_operations squashfs_symlink_inode_ops = {
+ .get_link = squashfs_get_link,
+};
diff --git a/fs/tftp.c b/fs/tftp.c
index 847921aa56..cc30c5eb8f 100644
--- a/fs/tftp.c
+++ b/fs/tftp.c
@@ -89,26 +89,6 @@ struct tftp_priv {
IPaddr_t server;
};
-static int tftp_create(struct device_d *dev, const char *pathname, mode_t mode)
-{
- return 0;
-}
-
-static int tftp_unlink(struct device_d *dev, const char *pathname)
-{
- return -ENOSYS;
-}
-
-static int tftp_mkdir(struct device_d *dev, const char *pathname)
-{
- return -ENOSYS;
-}
-
-static int tftp_rmdir(struct device_d *dev, const char *pathname)
-{
- return -ENOSYS;
-}
-
static int tftp_truncate(struct device_d *dev, FILE *f, ulong size)
{
return 0;
@@ -466,6 +446,9 @@ out:
static int tftp_open(struct device_d *dev, FILE *file, const char *filename)
{
struct file_priv *priv;
+ struct fs_device_d *fsdev = dev_to_fs_device(dev);
+
+ filename = dpath(file->dentry, fsdev->vfsmount.mnt_root);
priv = tftp_do_open(dev, file->flags, filename);
if (IS_ERR(priv))
@@ -618,40 +601,76 @@ out_free:
return -ENOSYS;
}
-static DIR* tftp_opendir(struct device_d *dev, const char *pathname)
+static const struct inode_operations tftp_file_inode_operations;
+static const struct inode_operations tftp_dir_inode_operations;
+static const struct file_operations tftp_file_operations;
+
+static struct inode *tftp_get_inode(struct super_block *sb, const struct inode *dir,
+ umode_t mode)
{
- /* not implemented in tftp protocol */
- return NULL;
+ struct inode *inode = new_inode(sb);
+
+ if (!inode)
+ return NULL;
+
+ inode->i_ino = get_next_ino();
+ inode->i_mode = mode;
+ inode->i_size = FILE_SIZE_STREAM;
+
+ switch (mode & S_IFMT) {
+ default:
+ return NULL;
+ case S_IFREG:
+ inode->i_op = &tftp_file_inode_operations;
+ inode->i_fop = &tftp_file_operations;
+ break;
+ case S_IFDIR:
+ inode->i_op = &tftp_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+ inc_nlink(inode);
+ break;
+ }
+
+ return inode;
}
-static int tftp_stat(struct device_d *dev, const char *filename, struct stat *s)
+static struct dentry *tftp_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
{
- struct file_priv *priv;
-
- priv = tftp_do_open(dev, O_RDONLY, filename);
- if (IS_ERR(priv))
- return PTR_ERR(priv);
+ struct inode *inode;
- s->st_mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;
- if (priv->filesize)
- s->st_size = priv->filesize;
- else
- s->st_size = FILESIZE_MAX;
+ inode = tftp_get_inode(dir->i_sb, dir, S_IFREG | S_IRWXUGO);
+ if (!inode)
+ return ERR_PTR(-ENOSPC);
- tftp_do_close(priv);
+ d_add(dentry, inode);
- return 0;
+ return NULL;
}
+static const struct inode_operations tftp_dir_inode_operations =
+{
+ .lookup = tftp_lookup,
+};
+
+static const struct super_operations tftp_ops;
+
static int tftp_probe(struct device_d *dev)
{
struct fs_device_d *fsdev = dev_to_fs_device(dev);
struct tftp_priv *priv = xzalloc(sizeof(struct tftp_priv));
+ struct super_block *sb = &fsdev->sb;
+ struct inode *inode;
dev->priv = priv;
priv->server = resolv(fsdev->backingstore);
+ sb->s_op = &tftp_ops;
+
+ inode = tftp_get_inode(sb, NULL, S_IFDIR);
+ sb->s_root = d_make_root(inode);
+
return 0;
}
@@ -667,12 +686,6 @@ static struct fs_driver_d tftp_driver = {
.close = tftp_close,
.read = tftp_read,
.lseek = tftp_lseek,
- .opendir = tftp_opendir,
- .stat = tftp_stat,
- .create = tftp_create,
- .unlink = tftp_unlink,
- .mkdir = tftp_mkdir,
- .rmdir = tftp_rmdir,
.write = tftp_write,
.truncate = tftp_truncate,
.flags = 0,
diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile
index e39ae3b0fd..44ef1b561c 100644
--- a/fs/ubifs/Makefile
+++ b/fs/ubifs/Makefile
@@ -1,4 +1,4 @@
obj-y += ubifs.o io.o super.o sb.o master.o lpt.o
-obj-y += lpt_commit.o scan.o lprops.o
+obj-y += lpt_commit.o scan.o lprops.o dir.o
obj-y += tnc.o tnc_misc.o debug.o crc16.o budget.o
obj-y += log.o orphan.o recovery.o replay.o gc.o
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
new file mode 100644
index 0000000000..8c230da8f3
--- /dev/null
+++ b/fs/ubifs/dir.c
@@ -0,0 +1,291 @@
+/* * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ * Copyright (C) 2006, 2007 University of Szeged, Hungary
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ * Adrian Hunter
+ * Zoltan Sogor
+ */
+
+/*
+ * This file implements directory operations.
+ *
+ * All FS operations in this file allocate budget before writing anything to the
+ * media. If they fail to allocate it, the error is returned. The only
+ * exceptions are 'ubifs_unlink()' and 'ubifs_rmdir()' which keep working even
+ * if they unable to allocate the budget, because deletion %-ENOSPC failure is
+ * not what users are usually ready to get. UBIFS budgeting subsystem has some
+ * space reserved for these purposes.
+ *
+ * All operations in this file write all inodes which they change straight
+ * away, instead of marking them dirty. For example, 'ubifs_link()' changes
+ * @i_size of the parent inode and writes the parent inode together with the
+ * target inode. This was done to simplify file-system recovery which would
+ * otherwise be very difficult to do. The only exception is rename which marks
+ * the re-named inode dirty (because its @i_ctime is updated) but does not
+ * write it, but just marks it as dirty.
+ */
+
+#include "ubifs.h"
+
+static int dbg_check_name(const struct ubifs_info *c,
+ const struct ubifs_dent_node *dent,
+ const struct qstr *nm)
+{
+ if (!dbg_is_chk_gen(c))
+ return 0;
+ if (le16_to_cpu(dent->nlen) != nm->len)
+ return -EINVAL;
+ if (memcmp(dent->name, nm->name, nm->len))
+ return -EINVAL;
+ return 0;
+}
+
+static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
+{
+ int err;
+ union ubifs_key key;
+ struct inode *inode = NULL;
+ struct ubifs_dent_node *dent;
+ struct ubifs_info *c = dir->i_sb->s_fs_info;
+
+ dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino);
+
+ if (dentry->d_name.len > UBIFS_MAX_NLEN)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
+ if (!dent)
+ return ERR_PTR(-ENOMEM);
+
+ dent_key_init(c, &key, dir->i_ino, &dentry->d_name);
+
+ err = ubifs_tnc_lookup_nm(c, &key, dent, &dentry->d_name);
+ if (err) {
+ if (err == -ENOENT) {
+ dbg_gen("not found");
+ goto done;
+ }
+ goto out;
+ }
+
+ if (dbg_check_name(c, dent, &dentry->d_name)) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum));
+ if (IS_ERR(inode)) {
+ /*
+ * This should not happen. Probably the file-system needs
+ * checking.
+ */
+ err = PTR_ERR(inode);
+ ubifs_err(c, "dead directory entry '%pd', error %d",
+ dentry, err);
+ ubifs_ro_mode(c, err);
+ goto out;
+ }
+
+done:
+ kfree(dent);
+ /*
+ * Note, d_splice_alias() would be required instead if we supported
+ * NFS.
+ */
+ d_add(dentry, inode);
+ return NULL;
+
+out:
+ kfree(dent);
+ return ERR_PTR(err);
+}
+
+/**
+ * vfs_dent_type - get VFS directory entry type.
+ * @type: UBIFS directory entry type
+ *
+ * This function converts UBIFS directory entry type into VFS directory entry
+ * type.
+ */
+static unsigned int vfs_dent_type(uint8_t type)
+{
+ switch (type) {
+ case UBIFS_ITYPE_REG:
+ return DT_REG;
+ case UBIFS_ITYPE_DIR:
+ return DT_DIR;
+ case UBIFS_ITYPE_LNK:
+ return DT_LNK;
+ case UBIFS_ITYPE_BLK:
+ return DT_BLK;
+ case UBIFS_ITYPE_CHR:
+ return DT_CHR;
+ case UBIFS_ITYPE_FIFO:
+ return DT_FIFO;
+ case UBIFS_ITYPE_SOCK:
+ return DT_SOCK;
+ default:
+ BUG();
+ }
+ return 0;
+}
+
+/*
+ * The classical Unix view for directory is that it is a linear array of
+ * (name, inode number) entries. Linux/VFS assumes this model as well.
+ * Particularly, 'readdir()' call wants us to return a directory entry offset
+ * which later may be used to continue 'readdir()'ing the directory or to
+ * 'seek()' to that specific direntry. Obviously UBIFS does not really fit this
+ * model because directory entries are identified by keys, which may collide.
+ *
+ * UBIFS uses directory entry hash value for directory offsets, so
+ * 'seekdir()'/'telldir()' may not always work because of possible key
+ * collisions. But UBIFS guarantees that consecutive 'readdir()' calls work
+ * properly by means of saving full directory entry name in the private field
+ * of the file description object.
+ *
+ * This means that UBIFS cannot support NFS which requires full
+ * 'seekdir()'/'telldir()' support.
+ */
+static int ubifs_readdir(struct file *file, struct dir_context *ctx)
+{
+ int err = 0;
+ struct qstr nm;
+ union ubifs_key key;
+ struct ubifs_dent_node *dent;
+ struct dentry *dentry = file->f_path.dentry;
+ struct inode *dir = d_inode(dentry);
+ struct ubifs_info *c = dir->i_sb->s_fs_info;
+
+ dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, ctx->pos);
+
+ if (ctx->pos > UBIFS_S_KEY_HASH_MASK || ctx->pos == 2)
+ /*
+ * The directory was seek'ed to a senseless position or there
+ * are no more entries.
+ */
+ return 0;
+
+ if (file->f_version == 0) {
+ /*
+ * The file was seek'ed, which means that @file->private_data
+ * is now invalid. This may also be just the first
+ * 'ubifs_readdir()' invocation, in which case
+ * @file->private_data is NULL, and the below code is
+ * basically a no-op.
+ */
+ kfree(file->private_data);
+ file->private_data = NULL;
+ }
+
+ /*
+ * 'generic_file_llseek()' unconditionally sets @file->f_version to
+ * zero, and we use this for detecting whether the file was seek'ed.
+ */
+ file->f_version = 1;
+
+ /* File positions 0 and 1 correspond to "." and ".." */
+ if (ctx->pos < 2) {
+ ubifs_assert(!file->private_data);
+ dir_emit_dots(file, ctx);
+
+ /* Find the first entry in TNC and save it */
+ lowest_dent_key(c, &key, dir->i_ino);
+ nm.name = NULL;
+ dent = ubifs_tnc_next_ent(c, &key, &nm);
+ if (IS_ERR(dent)) {
+ err = PTR_ERR(dent);
+ goto out;
+ }
+
+ ctx->pos = key_hash_flash(c, &dent->key);
+ file->private_data = dent;
+ }
+
+ dent = file->private_data;
+ if (!dent) {
+ /*
+ * The directory was seek'ed to and is now readdir'ed.
+ * Find the entry corresponding to @ctx->pos or the closest one.
+ */
+ dent_key_init_hash(c, &key, dir->i_ino, ctx->pos);
+ nm.name = NULL;
+ dent = ubifs_tnc_next_ent(c, &key, &nm);
+ if (IS_ERR(dent)) {
+ err = PTR_ERR(dent);
+ goto out;
+ }
+ ctx->pos = key_hash_flash(c, &dent->key);
+ file->private_data = dent;
+ }
+
+ while (1) {
+ dbg_gen("feed '%s', ino %llu, new f_pos %#x",
+ dent->name, (unsigned long long)le64_to_cpu(dent->inum),
+ key_hash_flash(c, &dent->key));
+ ubifs_assert(le64_to_cpu(dent->ch.sqnum) >
+ ubifs_inode(dir)->creat_sqnum);
+
+ nm.len = le16_to_cpu(dent->nlen);
+ dir_emit(ctx, dent->name, nm.len,
+ le64_to_cpu(dent->inum),
+ vfs_dent_type(dent->type));
+
+ /* Switch to the next entry */
+ key_read(c, &dent->key, &key);
+ nm.name = dent->name;
+ dent = ubifs_tnc_next_ent(c, &key, &nm);
+ if (IS_ERR(dent)) {
+ err = PTR_ERR(dent);
+ goto out;
+ }
+
+ kfree(file->private_data);
+ ctx->pos = key_hash_flash(c, &dent->key);
+ file->private_data = dent;
+ cond_resched();
+ }
+
+out:
+ kfree(file->private_data);
+ file->private_data = NULL;
+
+ if (err != -ENOENT)
+ ubifs_err(c, "cannot find next direntry, error %d", err);
+ else
+ /*
+ * -ENOENT is a non-fatal error in this context, the TNC uses
+ * it to indicate that the cursor moved past the current directory
+ * and readdir() has to stop.
+ */
+ err = 0;
+
+
+ /* 2 is a special value indicating that there are no more direntries */
+ ctx->pos = 2;
+ return err;
+}
+
+const struct inode_operations ubifs_dir_inode_operations = {
+ .lookup = ubifs_lookup,
+};
+
+const struct file_operations ubifs_dir_operations = {
+ .iterate = ubifs_readdir,
+};
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index b4eb76202b..abf8ef63c9 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -30,6 +30,7 @@
#include <common.h>
#include <init.h>
+#include <fs.h>
#include <malloc.h>
#include <linux/bug.h>
#include <linux/log2.h>
@@ -49,8 +50,6 @@ struct vfsmount;
struct super_block *ubifs_sb;
LIST_HEAD(super_blocks);
-static struct inode *inodes_locked_down[INODE_LOCKED_MAX];
-
int set_anon_super(struct super_block *s, void *data)
{
return 0;
@@ -84,39 +83,6 @@ int ubifs_iput(struct inode *inode)
return 0;
}
-/*
- * Lock (save) inode in inode array for readback after recovery
- */
-void iput(struct inode *inode)
-{
- int i;
- struct inode *ino;
-
- /*
- * Search end of list
- */
- for (i = 0; i < INODE_LOCKED_MAX; i++) {
- if (inodes_locked_down[i] == NULL)
- break;
- }
-
- if (i >= INODE_LOCKED_MAX) {
- dbg_gen("Error, can't lock (save) more inodes while recovery!!!");
- return;
- }
-
- /*
- * Allocate and use new inode
- */
- ino = (struct inode *)kzalloc(sizeof(struct ubifs_inode), 0);
- memcpy(ino, inode, sizeof(struct ubifs_inode));
-
- /*
- * Finally save inode in array
- */
- inodes_locked_down[i] = ino;
-}
-
/* from fs/inode.c */
/**
* clear_nlink - directly zero an inode's link count
@@ -231,6 +197,9 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
return err;
}
+const struct inode_operations ubifs_file_inode_operations;
+const struct file_operations ubifs_file_operations;
+
struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
{
int err;
@@ -239,35 +208,9 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
struct ubifs_info *c = sb->s_fs_info;
struct inode *inode;
struct ubifs_inode *ui;
-#ifdef __BAREBOX__
- int i;
-#endif
dbg_gen("inode %lu", inum);
-#ifdef __BAREBOX__
- /*
- * U-Boot special handling of locked down inodes via recovery
- * e.g. ubifs_recover_size()
- */
- for (i = 0; i < INODE_LOCKED_MAX; i++) {
- /*
- * Exit on last entry (NULL), inode not found in list
- */
- if (inodes_locked_down[i] == NULL)
- break;
-
- if (inodes_locked_down[i]->i_ino == inum) {
- /*
- * We found the locked down inode in our array,
- * so just return this pointer instead of creating
- * a new one.
- */
- return inodes_locked_down[i];
- }
- }
-#endif
-
inode = iget_locked(sb, inum);
if (!inode)
return ERR_PTR(-ENOMEM);
@@ -315,10 +258,8 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
if (err)
goto out_invalid;
-#ifndef __BAREBOX__
switch (inode->i_mode & S_IFMT) {
case S_IFREG:
- inode->i_mapping->a_ops = &ubifs_file_address_operations;
inode->i_op = &ubifs_file_inode_operations;
inode->i_fop = &ubifs_file_operations;
if (ui->xattr) {
@@ -343,7 +284,7 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
}
break;
case S_IFLNK:
- inode->i_op = &ubifs_symlink_inode_operations;
+ inode->i_op = &simple_symlink_inode_operations;
if (ui->data_len <= 0 || ui->data_len > UBIFS_MAX_INO_DATA) {
err = 12;
goto out_invalid;
@@ -357,60 +298,10 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
((char *)ui->data)[ui->data_len] = '\0';
inode->i_link = ui->data;
break;
- case S_IFBLK:
- case S_IFCHR:
- {
- dev_t rdev;
- union ubifs_dev_desc *dev;
-
- ui->data = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS);
- if (!ui->data) {
- err = -ENOMEM;
- goto out_ino;
- }
-
- dev = (union ubifs_dev_desc *)ino->data;
- if (ui->data_len == sizeof(dev->new))
- rdev = new_decode_dev(le32_to_cpu(dev->new));
- else if (ui->data_len == sizeof(dev->huge))
- rdev = huge_decode_dev(le64_to_cpu(dev->huge));
- else {
- err = 13;
- goto out_invalid;
- }
- memcpy(ui->data, ino->data, ui->data_len);
- inode->i_op = &ubifs_file_inode_operations;
- init_special_inode(inode, inode->i_mode, rdev);
- break;
- }
- case S_IFSOCK:
- case S_IFIFO:
- inode->i_op = &ubifs_file_inode_operations;
- init_special_inode(inode, inode->i_mode, 0);
- if (ui->data_len != 0) {
- err = 14;
- goto out_invalid;
- }
- break;
default:
err = 15;
goto out_invalid;
}
-#else
- if ((inode->i_mode & S_IFMT) == S_IFLNK) {
- if (ui->data_len <= 0 || ui->data_len > UBIFS_MAX_INO_DATA) {
- err = 12;
- goto out_invalid;
- }
- ui->data = kmalloc(ui->data_len + 1, GFP_NOFS);
- if (!ui->data) {
- err = -ENOMEM;
- goto out_ino;
- }
- memcpy(ui->data, ino->data, ui->data_len);
- ((char *)ui->data)[ui->data_len] = '\0';
- }
-#endif
kfree(ino);
#ifndef __BAREBOX__
@@ -447,22 +338,15 @@ static struct inode *ubifs_alloc_inode(struct super_block *sb)
return &ui->vfs_inode;
};
-#ifndef __BAREBOX__
-static void ubifs_i_callback(struct rcu_head *head)
-{
- struct inode *inode = container_of(head, struct inode, i_rcu);
- struct ubifs_inode *ui = ubifs_inode(inode);
- kmem_cache_free(ubifs_inode_slab, ui);
-}
-
static void ubifs_destroy_inode(struct inode *inode)
{
struct ubifs_inode *ui = ubifs_inode(inode);
kfree(ui->data);
- call_rcu(&inode->i_rcu, ubifs_i_callback);
+ kfree(ui);
}
+#ifndef __BAREBOX__
/*
* Note, Linux write-back code calls this without 'i_mutex'.
*/
@@ -1330,15 +1214,9 @@ static int mount_ubifs(struct ubifs_info *c)
long long x, y;
size_t sz;
- c->ro_mount = !!(c->vfs_sb->s_flags & MS_RDONLY);
+ c->ro_mount = true;
/* Suppress error messages while probing if MS_SILENT is set */
c->probing = !!(c->vfs_sb->s_flags & MS_SILENT);
-#ifdef __BAREBOX__
- if (!c->ro_mount) {
- printf("UBIFS: only ro mode in Barebox allowed.\n");
- return -EACCES;
- }
-#endif
err = init_constants_early(c);
if (err)
@@ -2099,8 +1977,8 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
const struct super_operations ubifs_super_operations = {
.alloc_inode = ubifs_alloc_inode,
-#ifndef __BAREBOX__
.destroy_inode = ubifs_destroy_inode,
+#ifndef __BAREBOX__
.put_super = ubifs_put_super,
.write_inode = ubifs_write_inode,
.evict_inode = ubifs_evict_inode,
@@ -2298,15 +2176,11 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
goto out_umount;
}
-#ifndef __BAREBOX__
sb->s_root = d_make_root(root);
if (!sb->s_root) {
err = -ENOMEM;
goto out_umount;
}
-#else
- sb->s_root = NULL;
-#endif
mutex_unlock(&c->umount_mutex);
return 0;
@@ -2680,13 +2554,14 @@ MODULE_AUTHOR("Artem Bityutskiy, Adrian Hunter");
MODULE_DESCRIPTION("UBIFS - UBI File System");
#endif
-struct super_block *ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent)
+int ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent)
{
+ struct fs_device_d *fsdev = dev_to_fs_device(dev);
struct super_block *sb;
struct ubifs_info *c;
int err;
- sb = alloc_super(NULL, MS_RDONLY | MS_ACTIVE | MS_NOATIME);
+ sb = &fsdev->sb;
c = alloc_ubifs_info(ubi);
c->dev = dev;
@@ -2712,9 +2587,9 @@ struct super_block *ubifs_get_super(struct device_d *dev, struct ubi_volume_desc
goto out;
}
- return sb;
+ return 0;
out:
kfree(c);
kfree(sb);
- return ERR_PTR(err);
+ return err;
}
diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c
index a525b044b8..f9b4f4babc 100644
--- a/fs/ubifs/ubifs.c
+++ b/fs/ubifs/ubifs.c
@@ -269,161 +269,6 @@ int __init ubifs_compressors_init(void)
return 0;
}
-/*
- * ubifsls...
- */
-
-static int ubifs_finddir(struct super_block *sb, char *dirname,
- unsigned long root_inum, unsigned long *inum)
-{
- int err;
- struct qstr nm;
- union ubifs_key key;
- struct ubifs_dent_node *dent;
- struct ubifs_info *c;
- struct file *file;
- struct dentry *dentry;
- struct inode *dir;
- int ret = 0;
-
- file = kzalloc(sizeof(struct file), 0);
- dentry = kzalloc(sizeof(struct dentry), 0);
- dir = kzalloc(sizeof(struct inode), 0);
- if (!file || !dentry || !dir) {
- printf("%s: Error, no memory for malloc!\n", __func__);
- err = -ENOMEM;
- goto out;
- }
-
- dir->i_sb = sb;
- file->f_path.dentry = dentry;
- file->f_path.dentry->d_parent = dentry;
- file->f_path.dentry->d_inode = dir;
- file->f_path.dentry->d_inode->i_ino = root_inum;
- c = sb->s_fs_info;
-
- dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
-
- /* Find the first entry in TNC and save it */
- lowest_dent_key(c, &key, dir->i_ino);
- nm.name = NULL;
- dent = ubifs_tnc_next_ent(c, &key, &nm);
- if (IS_ERR(dent)) {
- err = PTR_ERR(dent);
- goto out;
- }
-
- file->f_pos = key_hash_flash(c, &dent->key);
- file->private_data = dent;
-
- while (1) {
- dbg_gen("feed '%s', ino %llu, new f_pos %#x",
- dent->name, (unsigned long long)le64_to_cpu(dent->inum),
- key_hash_flash(c, &dent->key));
- ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum);
-
- nm.len = le16_to_cpu(dent->nlen);
- if ((strncmp(dirname, (char *)dent->name, nm.len) == 0) &&
- (strlen(dirname) == nm.len)) {
- *inum = le64_to_cpu(dent->inum);
- ret = 1;
- goto out_free;
- }
-
- /* Switch to the next entry */
- key_read(c, &dent->key, &key);
- nm.name = (char *)dent->name;
- dent = ubifs_tnc_next_ent(c, &key, &nm);
- if (IS_ERR(dent)) {
- err = PTR_ERR(dent);
- goto out;
- }
-
- kfree(file->private_data);
- file->f_pos = key_hash_flash(c, &dent->key);
- file->private_data = dent;
- cond_resched();
- }
-
-out:
- if (err != -ENOENT)
- dbg_gen("cannot find next direntry, error %d", err);
-
-out_free:
- if (file->private_data)
- kfree(file->private_data);
- if (file)
- free(file);
- if (dentry)
- free(dentry);
- if (dir)
- free(dir);
-
- return ret;
-}
-
-static unsigned long ubifs_findfile(struct super_block *sb, const char *filename)
-{
- int ret;
- char *next;
- char fpath[128];
- char *name = fpath;
- unsigned long root_inum = 1;
- unsigned long inum;
-
- strcpy(fpath, filename);
-
- /* Remove all leading slashes */
- while (*name == '/')
- name++;
-
- /*
- * Handle root-direcoty ('/')
- */
- inum = root_inum;
- if (!name || *name == '\0')
- return inum;
-
- for (;;) {
- struct inode *inode;
- struct ubifs_inode *ui;
-
- /* Extract the actual part from the pathname. */
- next = strchr(name, '/');
- if (next) {
- /* Remove all leading slashes. */
- while (*next == '/')
- *(next++) = '\0';
- }
-
- ret = ubifs_finddir(sb, name, root_inum, &inum);
- if (!ret)
- return 0;
- inode = ubifs_iget(sb, inum);
-
- if (IS_ERR(inode))
- return 0;
- ui = ubifs_inode(inode);
-
- /*
- * Check if directory with this name exists
- */
-
- /* Found the node! */
- if (!next || *next == '\0')
- return inum;
-
- root_inum = inum;
- name = next;
- }
-
- return 0;
-}
-
-/*
- * ubifsload...
- */
-
/* file.c */
static inline void *kmap(struct page *page)
@@ -487,18 +332,8 @@ struct ubifs_file {
static int ubifs_open(struct device_d *dev, FILE *file, const char *filename)
{
- struct ubifs_priv *priv = dev->priv;
- struct inode *inode;
+ struct inode *inode = file->f_inode;
struct ubifs_file *uf;
- unsigned long inum;
-
- inum = ubifs_findfile(priv->sb, filename);
- if (!inum)
- return -ENOENT;
-
- inode = ubifs_iget(priv->sb, inum);
- if (IS_ERR(inode))
- return -ENOENT;
uf = xzalloc(sizeof(*uf));
@@ -516,9 +351,6 @@ static int ubifs_open(struct device_d *dev, FILE *file, const char *filename)
static int ubifs_close(struct device_d *dev, FILE *f)
{
struct ubifs_file *uf = f->priv;
- struct inode *inode = uf->inode;
-
- ubifs_iput(inode);
free(uf->buf);
free(uf->dn);
@@ -596,163 +428,6 @@ static loff_t ubifs_lseek(struct device_d *dev, FILE *f, loff_t pos)
return pos;
}
-struct ubifs_dir {
- struct file file;
- struct dentry dentry;
- struct inode inode;
- DIR dir;
- union ubifs_key key;
- struct ubifs_dent_node *dent;
- struct ubifs_priv *priv;
- struct qstr nm;
-};
-
-static DIR *ubifs_opendir(struct device_d *dev, const char *pathname)
-{
- struct ubifs_priv *priv = dev->priv;
- struct ubifs_dir *dir;
- struct file *file;
- struct dentry *dentry;
- struct inode *inode;
- unsigned long inum;
- struct ubifs_info *c = priv->sb->s_fs_info;
-
- inum = ubifs_findfile(priv->sb, pathname);
- if (!inum)
- return NULL;
-
- inode = ubifs_iget(priv->sb, inum);
- if (IS_ERR(inode))
- return NULL;
-
- ubifs_iput(inode);
-
- dir = xzalloc(sizeof(*dir));
-
- dir->priv = priv;
-
- file = &dir->file;
- dentry = &dir->dentry;
- inode = &dir->inode;
-
- inode->i_sb = priv->sb;
- file->f_path.dentry = dentry;
- file->f_path.dentry->d_parent = dentry;
- file->f_path.dentry->d_inode = inode;
- file->f_path.dentry->d_inode->i_ino = inum;
- file->f_pos = 1;
-
- /* Find the first entry in TNC and save it */
- lowest_dent_key(c, &dir->key, inode->i_ino);
-
- return &dir->dir;
-}
-
-static struct dirent *ubifs_readdir(struct device_d *dev, DIR *_dir)
-{
- struct ubifs_dir *dir = container_of(_dir, struct ubifs_dir, dir);
- struct ubifs_info *c = dir->priv->sb->s_fs_info;
- struct ubifs_dent_node *dent;
- struct qstr *nm = &dir->nm;
- struct file *file = &dir->file;
-
- dent = ubifs_tnc_next_ent(c, &dir->key, nm);
- if (IS_ERR(dent))
- return NULL;
-
- debug("feed '%s', ino %llu, new f_pos %#x\n",
- dent->name, (unsigned long long)le64_to_cpu(dent->inum),
- key_hash_flash(c, &dent->key));
-
- ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(&dir->inode)->creat_sqnum);
-
- key_read(c, &dent->key, &dir->key);
- file->f_pos = key_hash_flash(c, &dent->key);
- file->private_data = dent;
-
- nm->len = le16_to_cpu(dent->nlen);
- nm->name = dent->name;
-
- strcpy(_dir->d.d_name, dent->name);
-
- free(dir->dent);
- dir->dent = dent;
-
- return &_dir->d;
-}
-
-static int ubifs_closedir(struct device_d *dev, DIR *_dir)
-{
- struct ubifs_dir *dir = container_of(_dir, struct ubifs_dir, dir);
-
- free(dir->dent);
- free(dir);
-
- return 0;
-}
-
-static int ubifs_stat(struct device_d *dev, const char *filename, struct stat *s)
-{
- struct ubifs_priv *priv = dev->priv;
- struct inode *inode;
- unsigned long inum;
-
- inum = ubifs_findfile(priv->sb, filename);
- if (!inum)
- return -ENOENT;
-
- inode = ubifs_iget(priv->sb, inum);
- if (IS_ERR(inode))
- return -ENOENT;
-
- s->st_size = inode->i_size;
- s->st_mode = inode->i_mode;
-
- ubifs_iput(inode);
-
- return 0;
-}
-
-static char *ubifs_symlink(struct inode *inode)
-{
- struct ubifs_inode *ui;
- char *symlink;
-
- ui = ubifs_inode(inode);
- symlink = malloc(ui->data_len + 1);
-
- memcpy(symlink, ui->data, ui->data_len);
- symlink[ui->data_len] = '\0';
-
- return symlink;
-}
-
-static int ubifs_readlink(struct device_d *dev, const char *pathname, char *buf,
- size_t bufsz)
-{
- struct ubifs_priv *priv = dev->priv;
- struct inode *inode;
- char *symlink;
- int len;
- unsigned long inum;
-
- inum = ubifs_findfile(priv->sb, pathname);
- if (!inum)
- return -ENOENT;
-
- inode = ubifs_iget(priv->sb, inum);
- if (!inode)
- return -ENOENT;
-
- symlink = ubifs_symlink(inode);
-
- len = min(bufsz, strlen(symlink));
- memcpy(buf, symlink, len);
- free(symlink);
-
- return 0;
-}
-
void ubifs_set_rootarg(struct ubifs_priv *priv, struct fs_device_d *fsdev)
{
struct ubi_volume_info vi = {};
@@ -795,11 +470,11 @@ static int ubifs_probe(struct device_d *dev)
goto err_free;
}
- priv->sb = ubifs_get_super(dev, priv->ubi, 0);
- if (IS_ERR(priv->sb)) {
- ret = PTR_ERR(priv->sb);
+ ret = ubifs_get_super(dev, priv->ubi, 0);
+ if (ret)
goto err;
- }
+
+ priv->sb = &fsdev->sb;
ubifs_set_rootarg(priv, fsdev);
@@ -821,7 +496,6 @@ static void ubifs_remove(struct device_d *dev)
ubi_close_volume(priv->ubi);
free(c);
- free(sb);
free(priv);
}
@@ -831,11 +505,6 @@ static struct fs_driver_d ubifs_driver = {
.close = ubifs_close,
.read = ubifs_read,
.lseek = ubifs_lseek,
- .opendir = ubifs_opendir,
- .readdir = ubifs_readdir,
- .closedir = ubifs_closedir,
- .stat = ubifs_stat,
- .readlink = ubifs_readlink,
.type = filetype_ubifs,
.flags = 0,
.drv = {
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 22b24a1161..4c4c927de9 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -36,6 +36,7 @@
#include <lzo.h>
#include <crc.h>
#include <linux/fs.h>
+#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/ctype.h>
#include <linux/time.h>
@@ -49,11 +50,9 @@
#define crc32(seed, data, length) crc32_no_comp(seed, (unsigned char const *)data, length)
-struct dentry;
struct file;
struct iattr;
struct kstat;
-struct vfsmount;
extern struct super_block *ubifs_sb;
@@ -72,8 +71,6 @@ struct page {
struct inode *inode;
};
-void iput(struct inode *inode);
-
struct kmem_cache { int sz; };
struct kmem_cache *get_mem(int element_sz);
@@ -1901,7 +1898,7 @@ int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len,
#ifdef __BAREBOX__
void ubifs_umount(struct ubifs_info *c);
-struct super_block *ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent);
+int ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent);
#endif
#endif /* !__UBIFS_H__ */
diff --git a/include/dirent.h b/include/dirent.h
index 5ee4c2063e..1df5d90452 100644
--- a/include/dirent.h
+++ b/include/dirent.h
@@ -1,6 +1,8 @@
#ifndef __DIRENT_H
#define __DIRENT_H
+#include <linux/list.h>
+
struct dirent {
char d_name[256];
};
@@ -11,6 +13,7 @@ typedef struct dir {
struct node_d *node;
struct dirent d;
void *priv; /* private data for the fs driver */
+ struct list_head entries;
} DIR;
DIR *opendir(const char *pathname);
diff --git a/include/fs.h b/include/fs.h
index e6fcd044dd..181318f404 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -31,14 +31,15 @@ typedef struct filep {
/* private fields. Mapping between FILE and filedescriptor number */
int no;
char in_use;
+
+ struct inode *f_inode;
+ struct dentry *dentry;
} FILE;
#define FS_DRIVER_NO_DEV 1
struct fs_driver_d {
int (*probe) (struct device_d *dev);
- int (*mkdir)(struct device_d *dev, const char *pathname);
- int (*rmdir)(struct device_d *dev, const char *pathname);
/* create a file. The file is guaranteed to not exist */
int (*create)(struct device_d *dev, const char *pathname, mode_t mode);
@@ -47,11 +48,6 @@ struct fs_driver_d {
/* Truncate a file to given size */
int (*truncate)(struct device_d *dev, FILE *f, ulong size);
- int (*symlink)(struct device_d *dev, const char *pathname,
- const char *newpath);
- int (*readlink)(struct device_d *dev, const char *pathname, char *name,
- size_t size);
-
int (*open)(struct device_d *dev, FILE *f, const char *pathname);
int (*close)(struct device_d *dev, FILE *f);
int (*read)(struct device_d *dev, FILE *f, void *buf, size_t size);
@@ -59,11 +55,6 @@ struct fs_driver_d {
int (*flush)(struct device_d *dev, FILE *f);
loff_t (*lseek)(struct device_d *dev, FILE *f, loff_t pos);
- struct dir* (*opendir)(struct device_d *dev, const char *pathname);
- struct dirent* (*readdir)(struct device_d *dev, struct dir *dir);
- int (*closedir)(struct device_d *dev, DIR *dir);
- int (*stat)(struct device_d *dev, const char *file, struct stat *stat);
-
int (*ioctl)(struct device_d *dev, FILE *f, int request, void *buf);
int (*erase)(struct device_d *dev, FILE *f, loff_t count,
loff_t offset);
@@ -72,6 +63,18 @@ struct fs_driver_d {
int (*memmap)(struct device_d *dev, FILE *f, void **map, int flags);
+ /* legacy */
+ int (*mkdir)(struct device_d *dev, const char *pathname);
+ int (*rmdir)(struct device_d *dev, const char *pathname);
+ int (*symlink)(struct device_d *dev, const char *pathname,
+ const char *newpath);
+ int (*readlink)(struct device_d *dev, const char *pathname, char *name,
+ size_t size);
+ struct dir* (*opendir)(struct device_d *dev, const char *pathname);
+ struct dirent* (*readdir)(struct device_d *dev, struct dir *dir);
+ int (*closedir)(struct device_d *dev, DIR *dir);
+ int (*stat)(struct device_d *dev, const char *file, struct stat *stat);
+
struct driver_d drv;
enum filetype type;
@@ -99,6 +102,10 @@ struct fs_device_d {
struct list_head list;
char *options;
char *linux_rootarg;
+
+ struct super_block sb;
+
+ struct vfsmount vfsmount;
};
bool __is_tftp_fs(const char *path);
@@ -135,12 +142,6 @@ int ls(const char *path, ulong flags);
char *mkmodestr(unsigned long mode, char *str);
-/*
- * This function turns 'path' into an absolute path and removes all occurrences
- * of "..", "." and double slashes. The returned string must be freed wit free().
- */
-char *normalise_path(const char *path);
-
char *canonicalize_path(const char *pathname);
char *get_mounted_path(const char *path);
@@ -154,6 +155,7 @@ void automount_remove(const char *_path);
int automount_add(const char *path, const char *cmd);
void automount_print(void);
+int fs_init_legacy(struct fs_device_d *fsdev);
int fsdev_open_cdev(struct fs_device_d *fsdev);
const char *cdev_get_mount_path(struct cdev *cdev);
const char *cdev_mount_default(struct cdev *cdev, const char *fsoptions);
diff --git a/include/gpio.h b/include/gpio.h
index f5262aac42..e42fa23383 100644
--- a/include/gpio.h
+++ b/include/gpio.h
@@ -1,6 +1,9 @@
#ifndef __GPIO_H
#define __GPIO_H
+#include <linux/types.h>
+#include <linux/list.h>
+
#ifdef CONFIG_GENERIC_GPIO
void gpio_set_value(unsigned gpio, int value);
int gpio_get_value(unsigned gpio);
diff --git a/include/hab.h b/include/hab.h
index fb7149ef53..78c2b865ba 100644
--- a/include/hab.h
+++ b/include/hab.h
@@ -18,6 +18,8 @@
#ifndef __HABV4_H
#define __HABV4_H
+#include <errno.h>
+
#ifdef CONFIG_HABV4
int imx28_hab_get_status(void);
int imx6_hab_get_status(void);
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
new file mode 100644
index 0000000000..1b38b7b372
--- /dev/null
+++ b/include/linux/arm-smccc.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+#ifndef __LINUX_ARM_SMCCC_H
+#define __LINUX_ARM_SMCCC_H
+
+/*
+ * This file provides common defines for ARM SMC Calling Convention as
+ * specified in
+ * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
+ */
+
+/* This constant is shifted by 31, make sure it's of an unsigned type */
+#define ARM_SMCCC_STD_CALL 0UL
+#define ARM_SMCCC_FAST_CALL 1UL
+#define ARM_SMCCC_TYPE_SHIFT 31
+
+#define ARM_SMCCC_SMC_32 0
+#define ARM_SMCCC_SMC_64 1
+#define ARM_SMCCC_CALL_CONV_SHIFT 30
+
+#define ARM_SMCCC_OWNER_MASK 0x3F
+#define ARM_SMCCC_OWNER_SHIFT 24
+
+#define ARM_SMCCC_FUNC_MASK 0xFFFF
+
+#define ARM_SMCCC_IS_FAST_CALL(smc_val) \
+ ((smc_val) & (ARM_SMCCC_FAST_CALL << ARM_SMCCC_TYPE_SHIFT))
+#define ARM_SMCCC_IS_64(smc_val) \
+ ((smc_val) & (ARM_SMCCC_SMC_64 << ARM_SMCCC_CALL_CONV_SHIFT))
+#define ARM_SMCCC_FUNC_NUM(smc_val) ((smc_val) & ARM_SMCCC_FUNC_MASK)
+#define ARM_SMCCC_OWNER_NUM(smc_val) \
+ (((smc_val) >> ARM_SMCCC_OWNER_SHIFT) & ARM_SMCCC_OWNER_MASK)
+
+#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \
+ (((type) << ARM_SMCCC_TYPE_SHIFT) | \
+ ((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \
+ (((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \
+ ((func_num) & ARM_SMCCC_FUNC_MASK))
+
+#define ARM_SMCCC_OWNER_ARCH 0
+#define ARM_SMCCC_OWNER_CPU 1
+#define ARM_SMCCC_OWNER_SIP 2
+#define ARM_SMCCC_OWNER_OEM 3
+#define ARM_SMCCC_OWNER_STANDARD 4
+#define ARM_SMCCC_OWNER_TRUSTED_APP 48
+#define ARM_SMCCC_OWNER_TRUSTED_APP_END 49
+#define ARM_SMCCC_OWNER_TRUSTED_OS 50
+#define ARM_SMCCC_OWNER_TRUSTED_OS_END 63
+
+#define ARM_SMCCC_QUIRK_NONE 0
+#define ARM_SMCCC_QUIRK_QCOM_A6 1 /* Save/restore register a6 */
+
+#ifndef __ASSEMBLY__
+
+#include <linux/linkage.h>
+#include <linux/types.h>
+/**
+ * struct arm_smccc_res - Result from SMC/HVC call
+ * @a0-a3 result values from registers 0 to 3
+ */
+struct arm_smccc_res {
+ unsigned long a0;
+ unsigned long a1;
+ unsigned long a2;
+ unsigned long a3;
+};
+
+/**
+ * struct arm_smccc_quirk - Contains quirk information
+ * @id: quirk identification
+ * @state: quirk specific information
+ * @a6: Qualcomm quirk entry for returning post-smc call contents of a6
+ */
+struct arm_smccc_quirk {
+ int id;
+ union {
+ unsigned long a6;
+ } state;
+};
+
+/**
+ * __arm_smccc_smc() - make SMC calls
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from registers 0 to 3
+ * @quirk: points to an arm_smccc_quirk, or NULL when no quirks are required.
+ *
+ * This function is used to make SMC calls following SMC Calling Convention.
+ * The content of the supplied param are copied to registers 0 to 7 prior
+ * to the SMC instruction. The return values are updated with the content
+ * from register 0 to 3 on return from the SMC instruction. An optional
+ * quirk structure provides vendor specific behavior.
+ */
+asmlinkage void __arm_smccc_smc(unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3, unsigned long a4,
+ unsigned long a5, unsigned long a6, unsigned long a7,
+ struct arm_smccc_res *res, struct arm_smccc_quirk *quirk);
+
+/**
+ * __arm_smccc_hvc() - make HVC calls
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from registers 0 to 3
+ * @quirk: points to an arm_smccc_quirk, or NULL when no quirks are required.
+ *
+ * This function is used to make HVC calls following SMC Calling
+ * Convention. The content of the supplied param are copied to registers 0
+ * to 7 prior to the HVC instruction. The return values are updated with
+ * the content from register 0 to 3 on return from the HVC instruction. An
+ * optional quirk structure provides vendor specific behavior.
+ */
+asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3, unsigned long a4,
+ unsigned long a5, unsigned long a6, unsigned long a7,
+ struct arm_smccc_res *res, struct arm_smccc_quirk *quirk);
+
+#define arm_smccc_smc(...) __arm_smccc_smc(__VA_ARGS__, NULL)
+
+#define arm_smccc_smc_quirk(...) __arm_smccc_smc(__VA_ARGS__)
+
+#define arm_smccc_hvc(...) __arm_smccc_hvc(__VA_ARGS__, NULL)
+
+#define arm_smccc_hvc_quirk(...) __arm_smccc_hvc(__VA_ARGS__)
+
+#endif /*__ASSEMBLY__*/
+#endif /*__LINUX_ARM_SMCCC_H*/
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index dfb466722c..16244129bf 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -53,6 +53,10 @@ struct dentry {
spinlock_t d_lock; /* per dentry lock */
struct inode *d_inode; /* Where the name belongs to - NULL is
* negative */
+
+ unsigned int d_count;
+ const struct dentry_operations *d_op;
+
/*
* The next three fields are touched by __d_lookup. Place them here
* so they all fit in a cache line.
@@ -65,8 +69,8 @@ struct dentry {
/*
* d_child and d_rcu can share memory
*/
+ struct list_head d_child; /* child of parent list */
struct list_head d_subdirs; /* our children */
- struct list_head d_alias; /* inode alias list */
unsigned long d_time; /* used by d_revalidate */
struct super_block *d_sb; /* The root of the dentry tree */
void *d_fsdata; /* fs-specific data */
@@ -74,7 +78,108 @@ struct dentry {
struct dcookie_struct *d_cookie; /* cookie, if any */
#endif
int d_mounted;
- unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
+ unsigned char *name; /* all names */
+};
+
+struct dentry_operations {
};
+struct dentry * d_make_root(struct inode *);
+void d_add(struct dentry *, struct inode *);
+struct dentry * d_alloc_anon(struct super_block *);
+void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op);
+void d_instantiate(struct dentry *dentry, struct inode *inode);
+void d_delete(struct dentry *);
+struct dentry *dget(struct dentry *);
+void dput(struct dentry *);
+
+#define DCACHE_ENTRY_TYPE 0x00700000
+#define DCACHE_MISS_TYPE 0x00000000 /* Negative dentry (maybe fallthru to nowhere) */
+#define DCACHE_WHITEOUT_TYPE 0x00100000 /* Whiteout dentry (stop pathwalk) */
+#define DCACHE_DIRECTORY_TYPE 0x00200000 /* Normal directory */
+#define DCACHE_AUTODIR_TYPE 0x00300000 /* Lookupless directory (presumed automount) */
+#define DCACHE_REGULAR_TYPE 0x00400000 /* Regular file type (or fallthru to such) */
+#define DCACHE_SPECIAL_TYPE 0x00500000 /* Other file type (or fallthru to such) */
+#define DCACHE_SYMLINK_TYPE 0x00600000 /* Symlink (or fallthru to such) */
+
+#define DCACHE_FALLTHRU 0x01000000 /* Fall through to lower layer */
+#define DCACHE_CANT_MOUNT 0x00000100
+#define DCACHE_MOUNTED 0x00010000 /* is a mountpoint */
+#define DCACHE_NEED_AUTOMOUNT 0x00020000 /* handle automount on this dir */
+#define DCACHE_MANAGED_DENTRY \
+ (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT)
+
+static inline bool d_mountpoint(const struct dentry *dentry)
+{
+ return dentry->d_flags & DCACHE_MOUNTED;
+}
+
+/*
+ * Directory cache entry type accessor functions.
+ */
+static inline unsigned __d_entry_type(const struct dentry *dentry)
+{
+ return dentry->d_flags & DCACHE_ENTRY_TYPE;
+}
+
+static inline bool d_is_miss(const struct dentry *dentry)
+{
+ return __d_entry_type(dentry) == DCACHE_MISS_TYPE;
+}
+
+static inline bool d_can_lookup(const struct dentry *dentry)
+{
+ return __d_entry_type(dentry) == DCACHE_DIRECTORY_TYPE;
+}
+
+static inline bool d_is_autodir(const struct dentry *dentry)
+{
+ return __d_entry_type(dentry) == DCACHE_AUTODIR_TYPE;
+}
+
+static inline bool d_is_dir(const struct dentry *dentry)
+{
+ return d_can_lookup(dentry) || d_is_autodir(dentry);
+}
+
+static inline bool d_is_symlink(const struct dentry *dentry)
+{
+ return __d_entry_type(dentry) == DCACHE_SYMLINK_TYPE;
+}
+
+static inline bool d_is_reg(const struct dentry *dentry)
+{
+ return __d_entry_type(dentry) == DCACHE_REGULAR_TYPE;
+}
+
+static inline bool d_is_special(const struct dentry *dentry)
+{
+ return __d_entry_type(dentry) == DCACHE_SPECIAL_TYPE;
+}
+
+static inline bool d_is_file(const struct dentry *dentry)
+{
+ return d_is_reg(dentry) || d_is_special(dentry);
+}
+
+static inline bool d_is_negative(const struct dentry *dentry)
+{
+ // TODO: check d_is_whiteout(dentry) also.
+ return d_is_miss(dentry);
+}
+
+static inline bool d_is_positive(const struct dentry *dentry)
+{
+ return !d_is_negative(dentry);
+}
+
+static inline struct inode *d_inode(const struct dentry *dentry)
+{
+ return dentry->d_inode;
+}
+
+#define IS_ROOT(x) ((x) == (x)->d_parent)
+
+char *dpath(struct dentry *dentry, struct dentry *root);
+
#endif /* __LINUX_DCACHE_H */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 153c464470..4550e8feeb 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -34,7 +34,18 @@
#define DT_SOCK 12
#define DT_WHT 14
+/*
+ * This is the "filldir" function type, used by readdir() to let
+ * the kernel specify what kind of dirent layout it wants to have.
+ * This allows the kernel to read directories into kernel space or
+ * to have different dirent layouts depending on the binary type.
+ */
+struct dir_context;
+typedef int (*filldir_t)(struct dir_context *, const char *, int, loff_t, u64,
+ unsigned);
+
struct dir_context {
+ const filldir_t actor;
loff_t pos;
};
@@ -94,12 +105,8 @@ struct inode {
};
uid_t i_uid;
gid_t i_gid;
- dev_t i_rdev;
u64 i_version;
loff_t i_size;
-#ifdef __NEED_I_SIZE_ORDERED
- seqcount_t i_size_seqcount;
-#endif
struct timespec i_atime;
struct timespec i_mtime;
struct timespec i_ctime;
@@ -107,39 +114,19 @@ struct inode {
blkcnt_t i_blocks;
unsigned short i_bytes;
umode_t i_mode;
- spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
- struct mutex i_mutex;
- struct rw_semaphore i_alloc_sem;
const struct inode_operations *i_op;
const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
struct super_block *i_sb;
- struct file_lock *i_flock;
-#ifdef CONFIG_QUOTA
- struct dquot *i_dquot[MAXQUOTAS];
-#endif
- struct list_head i_devices;
- int i_cindex;
__u32 i_generation;
-#ifdef CONFIG_DNOTIFY
- unsigned long i_dnotify_mask; /* Directory notify events */
- struct dnotify_struct *i_dnotify; /* for directory notifications */
-#endif
-
-#ifdef CONFIG_INOTIFY
- struct list_head inotify_watches; /* watches on this inode */
- struct mutex inotify_mutex; /* protects the watches list */
-#endif
-
unsigned long i_state;
- unsigned long dirtied_when; /* jiffies of first dirtying */
unsigned int i_flags;
+ unsigned int i_count;
+
+ char *i_link;
-#ifdef CONFIG_SECURITY
- void *i_security;
-#endif
void *i_private; /* fs or device private pointer */
};
@@ -199,19 +186,9 @@ struct super_block {
Cannot be worse than a second */
u32 s_time_gran;
- /*
- * Filesystem subtype. If non-empty the filesystem type field
- * in /proc/mounts will be "type.subtype"
- */
- char *s_subtype;
-
- /*
- * Saved mount options for lazy filesystems using
- * generic_show_options()
- */
- char *s_options;
-
/* Number of inodes with nlink == 0 but still referenced */
+
+ const struct dentry_operations *s_d_op; /* default d_op for dentries */
};
struct file_system_type {
@@ -405,4 +382,80 @@ static inline loff_t i_size_read(const struct inode *inode)
return inode->i_size;
}
+struct inode *new_inode(struct super_block *sb);
+unsigned int get_next_ino(void);
+void iput(struct inode *);
+struct inode *iget(struct inode *);
+void inc_nlink(struct inode *inode);
+
+struct inode_operations {
+ struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
+
+ const char *(*get_link) (struct dentry *dentry, struct inode *inode);
+
+ int (*create) (struct inode *,struct dentry *, umode_t);
+ int (*link) (struct dentry *,struct inode *,struct dentry *);
+ int (*unlink) (struct inode *,struct dentry *);
+ int (*symlink) (struct inode *,struct dentry *,const char *);
+ int (*mkdir) (struct inode *,struct dentry *,umode_t);
+ int (*rmdir) (struct inode *,struct dentry *);
+ int (*rename) (struct inode *, struct dentry *,
+ struct inode *, struct dentry *, unsigned int);
+};
+
+static inline ino_t parent_ino(struct dentry *dentry)
+{
+ return dentry->d_parent->d_inode->i_ino;
+}
+
+static inline bool dir_emit(struct dir_context *ctx,
+ const char *name, int namelen,
+ u64 ino, unsigned type)
+{
+ return ctx->actor(ctx, name, namelen, ctx->pos, ino, type) == 0;
+}
+
+static inline bool dir_emit_dot(struct file *file, struct dir_context *ctx)
+{
+ return ctx->actor(ctx, ".", 1, ctx->pos,
+ file->f_path.dentry->d_inode->i_ino, DT_DIR) == 0;
+}
+static inline bool dir_emit_dotdot(struct file *file, struct dir_context *ctx)
+{
+ return ctx->actor(ctx, "..", 2, ctx->pos,
+ parent_ino(file->f_path.dentry), DT_DIR) == 0;
+}
+
+static inline void dir_emit_dots(struct file *file, struct dir_context *ctx)
+{
+ if (ctx->pos == 0) {
+ dir_emit_dot(file, ctx);
+ ctx->pos = 1;
+ }
+ if (ctx->pos == 1) {
+ dir_emit_dotdot(file, ctx);
+ ctx->pos = 2;
+ }
+}
+
+struct file_operations {
+ int (*iterate) (struct file *, struct dir_context *);
+ ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
+ ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
+ int (*ioctl) (struct file *, int request, void *buf);
+ int (*truncate) (struct file *, loff_t);
+};
+
+void drop_nlink(struct inode *inode);
+
+extern const struct file_operations simple_dir_operations;
+extern const struct inode_operations simple_symlink_inode_operations;
+
+int simple_empty(struct dentry *dentry);
+int simple_unlink(struct inode *dir, struct dentry *dentry);
+int simple_rmdir(struct inode *dir, struct dentry *dentry);
+struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned int flags);
+int dcache_readdir(struct file *, struct dir_context *);
+const char *simple_get_link(struct dentry *dentry, struct inode *inode);
+
#endif /* _LINUX_FS_H */
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 57d5ba9523..9557365fb5 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -14,8 +14,11 @@
struct vfsmount {
struct dentry *mnt_root; /* root of the mounted tree */
+ struct dentry *mountpoint; /* where it's mounted (barebox specific, no support */
+ struct vfsmount *parent; /* for bind mounts and the like) */
struct super_block *mnt_sb; /* pointer to superblock */
int mnt_flags;
+ int ref;
};
#endif /* _LINUX_MOUNT_H */
diff --git a/include/linux/namei.h b/include/linux/namei.h
new file mode 100644
index 0000000000..8ed7f8a1cd
--- /dev/null
+++ b/include/linux/namei.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_NAMEI_H
+#define _LINUX_NAMEI_H
+
+#include <linux/kernel.h>
+#include <linux/path.h>
+
+enum { MAX_NESTED_LINKS = 8 };
+
+#define MAXSYMLINKS 40
+
+/*
+ * Type of the last component on LOOKUP_PARENT
+ */
+enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
+
+/*
+ * The bitmask for a lookup event:
+ * - follow links at the end
+ * - require a directory
+ * - ending slashes ok even for nonexistent files
+ * - internal "there are more path components" flag
+ * - dentry cache is untrusted; force a real lookup
+ * - suppress terminal automount
+ */
+#define LOOKUP_FOLLOW 0x0001
+#define LOOKUP_DIRECTORY 0x0002
+#define LOOKUP_AUTOMOUNT 0x0004
+
+#define LOOKUP_PARENT 0x0010
+#define LOOKUP_REVAL 0x0020
+#define LOOKUP_RCU 0x0040
+#define LOOKUP_NO_REVAL 0x0080
+
+/*
+ * Intent data
+ */
+#define LOOKUP_OPEN 0x0100
+#define LOOKUP_CREATE 0x0200
+#define LOOKUP_EXCL 0x0400
+#define LOOKUP_RENAME_TARGET 0x0800
+
+#define LOOKUP_JUMPED 0x1000
+#define LOOKUP_ROOT 0x2000
+#define LOOKUP_EMPTY 0x4000
+#define LOOKUP_DOWN 0x8000
+
+#define AT_FDCWD -100 /* Special value used to indicate
+ openat should use the current
+ working directory. */
+
+#endif /* _LINUX_NAMEI_H */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 152ba10a04..82f27f21b2 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -29,6 +29,7 @@
#include <linux/pci_ids.h>
+#define PCI_ANY_ID (~0)
/*
* The PCI interface treats multi-function devices as independent
@@ -299,4 +300,57 @@ int pci_enable_device(struct pci_dev *dev);
extern void __iomem *pci_iomap(struct pci_dev *dev, int bar);
+/*
+ * The world is not perfect and supplies us with broken PCI devices.
+ * For at least a part of these bugs we need a work-around, so both
+ * generic (drivers/pci/quirks.c) and per-architecture code can define
+ * fixup hooks to be called for particular buggy devices.
+ */
+
+struct pci_fixup {
+ u16 vendor; /* Or PCI_ANY_ID */
+ u16 device; /* Or PCI_ANY_ID */
+ u32 class; /* Or PCI_ANY_ID */
+ unsigned int class_shift; /* should be 0, 8, 16 */
+ void (*hook)(struct pci_dev *dev);
+};
+
+enum pci_fixup_pass {
+ pci_fixup_early, /* Before probing BARs */
+ pci_fixup_header, /* After reading configuration header */
+ pci_fixup_enable, /* pci_enable_device() time */
+};
+
+/* Anonymous variables would be nice... */
+#define DECLARE_PCI_FIXUP_SECTION(section, name, vendor, device, class, \
+ class_shift, hook) \
+ static const struct pci_fixup __PASTE(__pci_fixup_##name,__LINE__) __used \
+ __attribute__((__section__(#section), aligned((sizeof(void *))))) \
+ = { vendor, device, class, class_shift, hook };
+
+#define DECLARE_PCI_FIXUP_CLASS_EARLY(vendor, device, class, \
+ class_shift, hook) \
+ DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early, \
+ hook, vendor, device, class, class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_HEADER(vendor, device, class, \
+ class_shift, hook) \
+ DECLARE_PCI_FIXUP_SECTION(.pci_fixup_header, \
+ hook, vendor, device, class, class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_ENABLE(vendor, device, class, \
+ class_shift, hook) \
+ DECLARE_PCI_FIXUP_SECTION(.pci_fixup_enable, \
+ hook, vendor, device, class, class_shift, hook)
+
+#define DECLARE_PCI_FIXUP_EARLY(vendor, device, hook) \
+ DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early, \
+ hook, vendor, device, PCI_ANY_ID, 0, hook)
+#define DECLARE_PCI_FIXUP_HEADER(vendor, device, hook) \
+ DECLARE_PCI_FIXUP_SECTION(.pci_fixup_header, \
+ hook, vendor, device, PCI_ANY_ID, 0, hook)
+#define DECLARE_PCI_FIXUP_ENABLE(vendor, device, hook) \
+ DECLARE_PCI_FIXUP_SECTION(.pci_fixup_enable, \
+ hook, vendor, device, PCI_ANY_ID, 0, hook)
+
+void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
+
#endif /* LINUX_PCI_H */
diff --git a/include/linux/stat.h b/include/linux/stat.h
index af022c5c79..87fe068396 100644
--- a/include/linux/stat.h
+++ b/include/linux/stat.h
@@ -42,6 +42,8 @@ extern "C" {
#define S_IWOTH 00002 /* read permission for other */
#define S_IXOTH 00001 /* execute/search permission for other */
+#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
+
struct stat {
unsigned short st_dev;
unsigned short __pad1;
diff --git a/include/serial/lpuart.h b/include/serial/lpuart.h
index a920291dec..9c6e271ebf 100644
--- a/include/serial/lpuart.h
+++ b/include/serial/lpuart.h
@@ -228,6 +228,8 @@ static inline void lpuart_setbrg(void __iomem *base,
unsigned int bfra;
u16 sbr;
+ BUG_ON(!baudrate);
+
sbr = (u16) (refclock / (16 * baudrate));
writeb(sbr >> 8, base + UARTBDH);
diff --git a/lib/libfile.c b/lib/libfile.c
index d22519b8f4..0052e789fc 100644
--- a/lib/libfile.c
+++ b/lib/libfile.c
@@ -501,7 +501,7 @@ int open_and_lseek(const char *filename, int mode, loff_t pos)
{
int fd, ret;
- fd = open(filename, mode | O_RDONLY);
+ fd = open(filename, mode);
if (fd < 0) {
perror("open");
return fd;
@@ -510,6 +510,24 @@ int open_and_lseek(const char *filename, int mode, loff_t pos)
if (!pos)
return fd;
+ if (mode & (O_WRONLY | O_RDWR)) {
+ struct stat s;
+
+ ret = fstat(fd, &s);
+ if (ret) {
+ perror("fstat");
+ return ret;
+ }
+
+ if (s.st_size < pos) {
+ ret = ftruncate(fd, pos);
+ if (ret) {
+ perror("ftruncate");
+ return ret;
+ }
+ }
+ }
+
ret = lseek(fd, pos, SEEK_SET);
if (ret == -1) {
perror("lseek");
diff --git a/net/eth.c b/net/eth.c
index 5d45a04612..9dc4411952 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -40,7 +40,7 @@ LIST_HEAD(netdev_list);
struct eth_ethaddr {
struct list_head list;
- u8 ethaddr[6];
+ u8 ethaddr[ETH_ALEN];
int ethid;
struct device_node *node;
};
@@ -82,7 +82,7 @@ static int eth_get_registered_ethaddr(struct eth_device *edev, void *buf)
list_for_each_entry(addr, &ethaddr_list, list) {
if ((node && node == addr->node) ||
addr->ethid == edev->dev.id) {
- memcpy(buf, addr->ethaddr, 6);
+ memcpy(buf, addr->ethaddr, ETH_ALEN);
return 0;
}
}
@@ -118,7 +118,7 @@ void eth_register_ethaddr(int ethid, const char *ethaddr)
addr = xzalloc(sizeof(*addr));
addr->ethid = ethid;
- memcpy(addr->ethaddr, ethaddr, 6);
+ memcpy(addr->ethaddr, ethaddr, ETH_ALEN);
list_add_tail(&addr->list, &ethaddr_list);
}
@@ -150,7 +150,7 @@ void of_eth_register_ethaddr(struct device_node *node, const char *ethaddr)
addr = xzalloc(sizeof(*addr));
addr->node = node;
- memcpy(addr->ethaddr, ethaddr, 6);
+ memcpy(addr->ethaddr, ethaddr, ETH_ALEN);
list_add_tail(&addr->list, &ethaddr_list);
}
@@ -284,7 +284,7 @@ static int eth_param_set_ethaddr(struct param_d *param, void *priv)
#ifdef CONFIG_OFTREE
static void eth_of_fixup_node(struct device_node *root,
const char *node_path, int ethid,
- const u8 ethaddr[6])
+ const u8 ethaddr[ETH_ALEN])
{
struct device_node *node;
int ret;
@@ -308,7 +308,7 @@ static void eth_of_fixup_node(struct device_node *root,
return;
}
- ret = of_set_property(node, "mac-address", ethaddr, 6, 1);
+ ret = of_set_property(node, "mac-address", ethaddr, ETH_ALEN, 1);
if (ret)
pr_err("Setting mac-address property of %s failed with: %s\n",
node->full_name, strerror(-ret));
@@ -355,7 +355,7 @@ static const char * const eth_mode_names[] = {
int eth_register(struct eth_device *edev)
{
struct device_d *dev = &edev->dev;
- unsigned char ethaddr[6];
+ unsigned char ethaddr[ETH_ALEN];
int ret, found = 0;
if (!edev->get_ethaddr) {
diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile
index 06aaa8c550..cc4ebefcb6 100644
--- a/scripts/dtc/Makefile
+++ b/scripts/dtc/Makefile
@@ -1,6 +1,6 @@
# scripts/dtc makefile
-hostprogs-y := dtc
+hostprogs-y := dtc fdtget
always := $(hostprogs-y)
dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \
@@ -10,6 +10,8 @@ dtc-objs += dtc-lexer.lex.o dtc-parser.tab.o
libfdt-objs = fdt.o fdt_ro.o fdt_strerror.o fdt_wip.o fdt_overlay.o
libfdt-objs += fdt_empty_tree.o fdt_rw.o fdt_sw.o
+fdtget-objs += fdtget.o $(libfdt-objs) util.o
+
# Source files need to get at the userspace version of libfdt_env.h to compile
HOSTCFLAGS_DTC := -I$(src)
@@ -23,6 +25,7 @@ HOSTCFLAGS_livetree.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_srcpos.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_treesource.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_util.o := $(HOSTCFLAGS_DTC)
+HOSTCFLAGS_fdtget.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_fdt.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_fdt_ro.o := $(HOSTCFLAGS_DTC)
diff --git a/scripts/dtc/fdtget.c b/scripts/dtc/fdtget.c
index c2fbab2a54..6cc5242f10 100644
--- a/scripts/dtc/fdtget.c
+++ b/scripts/dtc/fdtget.c
@@ -54,6 +54,37 @@ static void report_error(const char *where, int err)
}
/**
+ * Shows a list of cells in the requested format
+ *
+ * @param disp Display information / options
+ * @param data Data to display
+ * @param len Maximum length of buffer
+ * @param size Data size to use for display (e.g. 4 for 32-bit)
+ * @return 0 if ok, -1 on error
+ */
+static int show_cell_list(struct display_info *disp, const char *data, int len,
+ int size)
+{
+ const uint8_t *p = (const uint8_t *)data;
+ char fmt[3];
+ int value;
+ int i;
+
+ fmt[0] = '%';
+ fmt[1] = disp->type ? disp->type : 'd';
+ fmt[2] = '\0';
+ for (i = 0; i < len; i += size, p += size) {
+ if (i)
+ printf(" ");
+ value = size == 4 ? fdt32_to_cpu(*(const fdt32_t *)p) :
+ size == 2 ? (*p << 8) | p[1] : *p;
+ printf(fmt, value);
+ }
+
+ return 0;
+}
+
+/**
* Displays data of a given length according to selected options
*
* If a specific data type is provided in disp, then this is used. Otherwise
@@ -66,12 +97,9 @@ static void report_error(const char *where, int err)
*/
static int show_data(struct display_info *disp, const char *data, int len)
{
- int i, size;
- const uint8_t *p = (const uint8_t *)data;
+ int size;
const char *s;
- int value;
int is_string;
- char fmt[3];
/* no data, don't print */
if (len == 0)
@@ -99,17 +127,8 @@ static int show_data(struct display_info *disp, const char *data, int len)
"selected data size\n");
return -1;
}
- fmt[0] = '%';
- fmt[1] = disp->type ? disp->type : 'd';
- fmt[2] = '\0';
- for (i = 0; i < len; i += size, p += size) {
- if (i)
- printf(" ");
- value = size == 4 ? fdt32_to_cpu(*(const uint32_t *)p) :
- size == 2 ? (*p << 8) | p[1] : *p;
- printf(fmt, value);
- }
- return 0;
+
+ return show_cell_list(disp, data, len, size);
}
/**
@@ -245,7 +264,7 @@ static int show_data_for_item(const void *blob, struct display_info *disp,
* @param filename Filename of blob file
* @param arg List of arguments to process
* @param arg_count Number of arguments
- * @param return 0 if ok, -ve on error
+ * @return 0 if ok, -ve on error
*/
static int do_fdtget(struct display_info *disp, const char *filename,
char **arg, int arg_count, int args_per_step)
@@ -266,44 +285,50 @@ static int do_fdtget(struct display_info *disp, const char *filename,
continue;
} else {
report_error(arg[i], node);
+ free(blob);
return -1;
}
}
prop = args_per_step == 1 ? NULL : arg[i + 1];
- if (show_data_for_item(blob, disp, node, prop))
+ if (show_data_for_item(blob, disp, node, prop)) {
+ free(blob);
return -1;
+ }
}
+
+ free(blob);
+
return 0;
}
-static const char *usage_msg =
- "fdtget - read values from device tree\n"
- "\n"
- "Each value is printed on a new line.\n\n"
- "Usage:\n"
+/* Usage related data. */
+static const char usage_synopsis[] =
+ "read values from device tree\n"
" fdtget <options> <dt file> [<node> <property>]...\n"
" fdtget -p <options> <dt file> [<node> ]...\n"
- "Options:\n"
- "\t-t <type>\tType of data\n"
- "\t-p\t\tList properties for each node\n"
- "\t-l\t\tList subnodes for each node\n"
- "\t-d\t\tDefault value to display when the property is "
- "missing\n"
- "\t-h\t\tPrint this help\n\n"
+ "\n"
+ "Each value is printed on a new line.\n"
USAGE_TYPE_MSG;
-
-static void usage(const char *msg)
-{
- if (msg)
- fprintf(stderr, "Error: %s\n\n", msg);
-
- fprintf(stderr, "%s", usage_msg);
- exit(2);
-}
+static const char usage_short_opts[] = "t:pld:" USAGE_COMMON_SHORT_OPTS;
+static struct option const usage_long_opts[] = {
+ {"type", a_argument, NULL, 't'},
+ {"properties", no_argument, NULL, 'p'},
+ {"list", no_argument, NULL, 'l'},
+ {"default", a_argument, NULL, 'd'},
+ USAGE_COMMON_LONG_OPTS,
+};
+static const char * const usage_opts_help[] = {
+ "Type of data",
+ "List properties for each node",
+ "List subnodes for each node",
+ "Default value to display when the property is missing",
+ USAGE_COMMON_OPTS_HELP
+};
int main(int argc, char *argv[])
{
+ int opt;
char *filename = NULL;
struct display_info disp;
int args_per_step = 2;
@@ -312,20 +337,14 @@ int main(int argc, char *argv[])
memset(&disp, '\0', sizeof(disp));
disp.size = -1;
disp.mode = MODE_SHOW_VALUE;
- for (;;) {
- int c = getopt(argc, argv, "d:hlpt:");
- if (c == -1)
- break;
-
- switch (c) {
- case 'h':
- case '?':
- usage(NULL);
+ while ((opt = util_getopt_long()) != EOF) {
+ switch (opt) {
+ case_USAGE_COMMON_FLAGS
case 't':
if (utilfdt_decode_type(optarg, &disp.type,
&disp.size))
- usage("Invalid type string");
+ usage("invalid type string");
break;
case 'p':
@@ -347,7 +366,7 @@ int main(int argc, char *argv[])
if (optind < argc)
filename = argv[optind++];
if (!filename)
- usage("Missing filename");
+ usage("missing filename");
argv += optind;
argc -= optind;
@@ -358,7 +377,7 @@ int main(int argc, char *argv[])
/* Check for node, property arguments */
if (args_per_step == 2 && (argc % 2))
- usage("Must have an even number of arguments");
+ usage("must have an even number of arguments");
if (do_fdtget(&disp, filename, argv, argc, args_per_step))
return 1;
diff --git a/scripts/imx/Makefile b/scripts/imx/Makefile
index 335e3e65ae..4fb62a60f8 100644
--- a/scripts/imx/Makefile
+++ b/scripts/imx/Makefile
@@ -8,6 +8,7 @@ HOSTLOADLIBES_imx-usb-loader = `pkg-config --libs libusb-1.0`
HOSTCFLAGS_imx.o = -I$(srctree)/arch/arm/mach-imx/include
HOSTCFLAGS_imx-image.o = -I$(srctree) -I$(srctree)/arch/arm/mach-imx/include
+HOSTCFLAGS_imx-usb-loader.o += -I$(srctree) -I$(srctree)/arch/arm/mach-imx/include
ifdef CONFIG_ARCH_IMX_IMXIMAGE_SSL_SUPPORT
HOSTCFLAGS_imx-image.o += -DIMXIMAGE_SSL_SUPPORT
HOSTLOADLIBES_imx-image = `pkg-config --libs openssl`
diff --git a/scripts/imx/imx.h b/scripts/imx/imx.h
index 92a3fd316d..20fb1e876e 100644
--- a/scripts/imx/imx.h
+++ b/scripts/imx/imx.h
@@ -1,116 +1,4 @@
-#define HEADER_LEN 0x1000 /* length of the blank area + IVT + DCD */
-
-/*
- * ============================================================================
- * i.MX flash header v1 handling. Found on i.MX35 and i.MX51
- * ============================================================================
- */
-#define DCD_BARKER 0xb17219e9
-
-struct imx_flash_header {
- uint32_t app_code_jump_vector;
- uint32_t app_code_barker;
- uint32_t app_code_csf;
- uint32_t dcd_ptr_ptr;
- uint32_t super_root_key;
- uint32_t dcd;
- uint32_t app_dest;
- uint32_t dcd_barker;
- uint32_t dcd_block_len;
-} __attribute__((packed));
-
-struct imx_boot_data {
- uint32_t start;
- uint32_t size;
- uint32_t plugin;
-} __attribute__((packed));
-
-struct imx_dcd_rec_v1 {
- uint32_t type;
- uint32_t addr;
- uint32_t val;
-} __attribute__((packed));
-
-#define TAG_IVT_HEADER 0xd1
-#define IVT_VERSION 0x40
-#define TAG_DCD_HEADER 0xd2
-#define DCD_VERSION 0x40
-#define TAG_UNLOCK 0xb2
-#define TAG_NOP 0xc0
-#define TAG_WRITE 0xcc
-#define TAG_CHECK 0xcf
-#define PARAMETER_FLAG_MASK (1 << 3)
-#define PARAMETER_FLAG_SET (1 << 4)
-
-struct imx_ivt_header {
- uint8_t tag;
- uint16_t length;
- uint8_t version;
-} __attribute__((packed));
-
-struct imx_flash_header_v2 {
- struct imx_ivt_header header;
-
- uint32_t entry;
- uint32_t reserved1;
- uint32_t dcd_ptr;
- uint32_t boot_data_ptr;
- uint32_t self;
- uint32_t csf;
- uint32_t reserved2;
-
- struct imx_boot_data boot_data;
- struct imx_ivt_header dcd_header;
-} __attribute__((packed));
-
-struct config_data {
- uint32_t image_load_addr;
- uint32_t image_dcd_offset;
- uint32_t image_size;
- uint32_t load_size;
- char *outfile;
- char *srkfile;
- int header_version;
- off_t header_gap;
- uint32_t first_opcode;
- int cpu_type;
- int (*check)(const struct config_data *data, uint32_t cmd,
- uint32_t addr, uint32_t mask);
- int (*write_mem)(const struct config_data *data, uint32_t addr,
- uint32_t val, int width, int set_bits, int clear_bits);
- int (*nop)(const struct config_data *data);
- int csf_space;
- char *csf;
-};
-
-#define MAX_RECORDS_DCD_V2 1024
-struct imx_dcd_v2_write_rec {
- uint32_t addr;
- uint32_t val;
-} __attribute__((packed));
-
-struct imx_dcd_v2_write {
- uint8_t tag;
- uint16_t length;
- uint8_t param;
- struct imx_dcd_v2_write_rec data[MAX_RECORDS_DCD_V2];
-} __attribute__((packed));
-
-struct imx_dcd_v2_check {
- uint8_t tag;
- uint16_t length;
- uint8_t param;
- uint32_t addr;
- uint32_t mask;
- uint32_t count;
-} __attribute__((packed));
-
-enum imx_dcd_v2_check_cond {
- until_all_bits_clear = 0, /* until ((*address & mask) == 0) { ...} */
- until_any_bit_clear = 1, /* until ((*address & mask) != mask) { ...} */
- until_all_bits_set = 2, /* until ((*address & mask) == mask) { ...} */
- until_any_bit_set = 3, /* until ((*address & mask) != 0) { ...} */
-} __attribute__((packed));
+#include <mach/imx-header.h>
int parse_config(struct config_data *data, const char *filename);