diff --git a/.gitignore b/.gitignore index 7e9932e55475ce..42fa0d5626a956 100644 --- a/.gitignore +++ b/.gitignore @@ -92,3 +92,6 @@ extra_certificates signing_key.priv signing_key.x509 x509.genkey + +# Kconfig presets +all.config diff --git a/CREDITS b/CREDITS index 4c7738f493570e..e371c5504a5053 100644 --- a/CREDITS +++ b/CREDITS @@ -823,8 +823,8 @@ S: D-69231 Rauenberg S: Germany N: Jean Delvare -E: khali@linux-fr.org -W: http://khali.linux-fr.org/ +E: jdelvare@suse.de +W: http://jdelvare.nerim.net/ D: Several hardware monitoring drivers S: France diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 38f8444bdd0e2b..07de7e19b4ce4b 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -29,6 +29,8 @@ DMA-ISA-LPC.txt - How to do DMA with ISA (and LPC) devices. DMA-attributes.txt - listing of the various possible attributes a DMA region can have +dmatest.txt + - how to compile, configure and use the dmatest system. DocBook/ - directory with DocBook templates etc. for kernel documentation. EDID/ @@ -77,6 +79,8 @@ arm/ - directory with info about Linux on the ARM architecture. arm64/ - directory with info about Linux on the 64 bit ARM architecture. +assoc_array.txt + - generic associative array intro. atomic_ops.txt - semantics and behavior of atomic and bitmask operations. auxdisplay/ @@ -87,6 +91,8 @@ bad_memory.txt - how to use kernel parameters to exclude bad RAM regions. basic_profiling.txt - basic instructions for those who wants to profile Linux kernel. +bcache.txt + - Block-layer cache on fast SSDs to improve slow (raid) I/O performance. binfmt_misc.txt - info on the kernel support for extra binary formats. blackfin/ @@ -171,6 +177,8 @@ early-userspace/ - info about initramfs, klibc, and userspace early during boot. edac.txt - information on EDAC - Error Detection And Correction +efi-stub.txt + - How to use the EFI boot stub to bypass GRUB or elilo on EFI systems. eisa.txt - info on EISA bus support. email-clients.txt @@ -195,8 +203,8 @@ futex-requeue-pi.txt - info on requeueing of tasks from a non-PI futex to a PI futex gcov.txt - use of GCC's coverage testing tool "gcov" with the Linux kernel -gpio.txt - - overview of GPIO (General Purpose Input/Output) access conventions. +gpio/ + - gpio related documentation hid/ - directory with information on human interface devices highuid.txt @@ -255,6 +263,8 @@ kernel-docs.txt - listing of various WWW + books that document kernel internals. kernel-parameters.txt - summary listing of command line / boot prompt args for the kernel. +kernel-per-CPU-kthreads.txt + - List of all per-CPU kthreads and how they introduce jitter. kmemcheck.txt - info on dynamic checker that detects uses of uninitialized memory. kmemleak.txt @@ -299,8 +309,6 @@ memory-devices/ - directory with info on parts like the Texas Instruments EMIF driver memory-hotplug.txt - Hotpluggable memory support, how to use and current status. -memory.txt - - info on typical Linux memory problems. metag/ - directory with info about Linux on Meta architecture. mips/ @@ -311,6 +319,8 @@ mmc/ - directory with info about the MMC subsystem mn10300/ - directory with info about the mn10300 architecture port +module-signing.txt + - Kernel module signing for increased security when loading modules. mtd/ - directory with info about memory technology devices (flash) mono.txt @@ -343,6 +353,8 @@ pcmcia/ - info on the Linux PCMCIA driver. percpu-rw-semaphore.txt - RCU based read-write semaphore optimized for locking for reading +phy.txt + - Description of the generic PHY framework. pi-futex.txt - documentation on lightweight priority inheritance futexes. pinctrl.txt @@ -431,6 +443,8 @@ sysrq.txt - info on the magic SysRq key. target/ - directory with info on generating TCM v4 fabric .ko modules +this_cpu_ops.txt + - List rationale behind and the way to use this_cpu operations. thermal/ - directory with information on managing thermal issues (CPU/temp) trace/ @@ -469,6 +483,8 @@ wimax/ - directory with info about Intel Wireless Wimax Connections workqueue.txt - information on the Concurrency Managed Workqueue implementation +ww-mutex-design.txt + - Intro to Mutex wait/would deadlock handling.s x86/x86_64/ - directory with info on Linux support for AMD x86-64 (Hammer) machines. xtensa/ diff --git a/Documentation/ABI/testing/configfs-usb-gadget b/Documentation/ABI/testing/configfs-usb-gadget index 01e769d6984d57..37559a06393b56 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget +++ b/Documentation/ABI/testing/configfs-usb-gadget @@ -1,13 +1,13 @@ What: /config/usb-gadget Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: This group contains sub-groups corresponding to created USB gadgets. What: /config/usb-gadget/gadget Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: The attributes of a gadget: @@ -27,7 +27,7 @@ Description: What: /config/usb-gadget/gadget/configs Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: This group contains a USB gadget's configurations @@ -58,20 +58,20 @@ Description: What: /config/usb-gadget/gadget/functions Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: This group contains functions available to this USB gadget. What: /config/usb-gadget/gadget/strings Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: This group contains subdirectories for language-specific strings for this gadget. What: /config/usb-gadget/gadget/strings/language Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: The attributes: diff --git a/Documentation/ABI/testing/configfs-usb-gadget-acm b/Documentation/ABI/testing/configfs-usb-gadget-acm index 5708a568b5f6fb..d21092d75a0587 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-acm +++ b/Documentation/ABI/testing/configfs-usb-gadget-acm @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/acm.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: This item contains just one readonly attribute: port_num. diff --git a/Documentation/ABI/testing/configfs-usb-gadget-ecm b/Documentation/ABI/testing/configfs-usb-gadget-ecm index 6b9a582ce0b55a..0addf7704b4c0e 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-ecm +++ b/Documentation/ABI/testing/configfs-usb-gadget-ecm @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/ecm.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: The attributes: diff --git a/Documentation/ABI/testing/configfs-usb-gadget-eem b/Documentation/ABI/testing/configfs-usb-gadget-eem index dbddf36b48b3c0..a4c57158fcdef2 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-eem +++ b/Documentation/ABI/testing/configfs-usb-gadget-eem @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/eem.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: The attributes: diff --git a/Documentation/ABI/testing/configfs-usb-gadget-ffs b/Documentation/ABI/testing/configfs-usb-gadget-ffs index 14343e237e8391..e39b27653c65c1 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-ffs +++ b/Documentation/ABI/testing/configfs-usb-gadget-ffs @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/ffs.name Date: Nov 2013 -KenelVersion: 3.13 +KernelVersion: 3.13 Description: The purpose of this directory is to create and remove it. A corresponding USB function instance is created/removed. diff --git a/Documentation/ABI/testing/configfs-usb-gadget-loopback b/Documentation/ABI/testing/configfs-usb-gadget-loopback index 852b2365a5b57a..9aae5bfb990887 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-loopback +++ b/Documentation/ABI/testing/configfs-usb-gadget-loopback @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/Loopback.name Date: Nov 2013 -KenelVersion: 3.13 +KernelVersion: 3.13 Description: The attributes: diff --git a/Documentation/ABI/testing/configfs-usb-gadget-mass-storage b/Documentation/ABI/testing/configfs-usb-gadget-mass-storage index ad72a37ee9ff24..9931fb0d63ba44 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-mass-storage +++ b/Documentation/ABI/testing/configfs-usb-gadget-mass-storage @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/mass_storage.name Date: Oct 2013 -KenelVersion: 3.13 +KernelVersion: 3.13 Description: The attributes: @@ -13,7 +13,7 @@ Description: What: /config/usb-gadget/gadget/functions/mass_storage.name/lun.name Date: Oct 2013 -KenelVersion: 3.13 +KernelVersion: 3.13 Description: The attributes: diff --git a/Documentation/ABI/testing/configfs-usb-gadget-ncm b/Documentation/ABI/testing/configfs-usb-gadget-ncm index bc309f42357d60..6fe723effc7894 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-ncm +++ b/Documentation/ABI/testing/configfs-usb-gadget-ncm @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/ncm.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: The attributes: diff --git a/Documentation/ABI/testing/configfs-usb-gadget-obex b/Documentation/ABI/testing/configfs-usb-gadget-obex index aaa5c96fb7c609..a6a9327ed9ba51 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-obex +++ b/Documentation/ABI/testing/configfs-usb-gadget-obex @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/obex.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: This item contains just one readonly attribute: port_num. diff --git a/Documentation/ABI/testing/configfs-usb-gadget-phonet b/Documentation/ABI/testing/configfs-usb-gadget-phonet index 3e3b742cdfd73a..7037a358e6c48f 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-phonet +++ b/Documentation/ABI/testing/configfs-usb-gadget-phonet @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/phonet.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: This item contains just one readonly attribute: ifname. diff --git a/Documentation/ABI/testing/configfs-usb-gadget-rndis b/Documentation/ABI/testing/configfs-usb-gadget-rndis index 822e6dad8fc08e..e32879b84b4d09 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-rndis +++ b/Documentation/ABI/testing/configfs-usb-gadget-rndis @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/rndis.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: The attributes: diff --git a/Documentation/ABI/testing/configfs-usb-gadget-serial b/Documentation/ABI/testing/configfs-usb-gadget-serial index 16f130c1501f00..474d249f760be0 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-serial +++ b/Documentation/ABI/testing/configfs-usb-gadget-serial @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/gser.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: This item contains just one readonly attribute: port_num. diff --git a/Documentation/ABI/testing/configfs-usb-gadget-sourcesink b/Documentation/ABI/testing/configfs-usb-gadget-sourcesink index a30f3093ef6cae..29477c319f61bf 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-sourcesink +++ b/Documentation/ABI/testing/configfs-usb-gadget-sourcesink @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/SourceSink.name Date: Nov 2013 -KenelVersion: 3.13 +KernelVersion: 3.13 Description: The attributes: diff --git a/Documentation/ABI/testing/configfs-usb-gadget-subset b/Documentation/ABI/testing/configfs-usb-gadget-subset index 154ae597cd99a8..9373e2c51ea454 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-subset +++ b/Documentation/ABI/testing/configfs-usb-gadget-subset @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/geth.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: The attributes: diff --git a/Documentation/ABI/testing/sysfs-bus-rbd b/Documentation/ABI/testing/sysfs-bus-rbd index 0a306476424ef0..501adc2a9ec723 100644 --- a/Documentation/ABI/testing/sysfs-bus-rbd +++ b/Documentation/ABI/testing/sysfs-bus-rbd @@ -18,6 +18,28 @@ Removal of a device: $ echo > /sys/bus/rbd/remove +What: /sys/bus/rbd/add_single_major +Date: December 2013 +KernelVersion: 3.14 +Contact: Sage Weil +Description: Available only if rbd module is inserted with single_major + parameter set to true. + Usage is the same as for /sys/bus/rbd/add. If present, + should be used instead of the latter: any attempts to use + /sys/bus/rbd/add if /sys/bus/rbd/add_single_major is + available will fail for backwards compatibility reasons. + +What: /sys/bus/rbd/remove_single_major +Date: December 2013 +KernelVersion: 3.14 +Contact: Sage Weil +Description: Available only if rbd module is inserted with single_major + parameter set to true. + Usage is the same as for /sys/bus/rbd/remove. If present, + should be used instead of the latter: any attempts to use + /sys/bus/rbd/remove if /sys/bus/rbd/remove_single_major is + available will fail for backwards compatibility reasons. + Entries under /sys/bus/rbd/devices// -------------------------------------------- @@ -33,6 +55,10 @@ major The block device major number. +minor + + The block device minor number. (December 2013, since 3.14.) + name The name of the rbd image. diff --git a/Documentation/ABI/testing/sysfs-tty b/Documentation/ABI/testing/sysfs-tty index ad22fb0ee765b7..a2ccec35ffce2c 100644 --- a/Documentation/ABI/testing/sysfs-tty +++ b/Documentation/ABI/testing/sysfs-tty @@ -3,7 +3,8 @@ Date: Nov 2010 Contact: Kay Sievers Description: Shows the list of currently configured - console devices, like 'tty1 ttyS0'. + tty devices used for the console, + like 'tty1 ttyS0'. The last entry in the file is the active device connected to /dev/console. The file supports poll() to detect virtual diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index 0c7195e3e0937b..c4cac6dbf9af04 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2523,6 +2523,18 @@ that used it. It was originally scheduled for removal in 2.6.35. +
+ Codestin Search App + + + In struct v4l2_rect, the type +of width and height +fields changed from _s32 to _u32. + + + +
+
Codestin Search App diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 7a3b49b3cc3baf..a5a3188e5af796 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -3161,6 +3161,47 @@ V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD as a golden frame. + + + V4L2_CID_MPEG_VIDEO_VPX_MIN_QP + integer + + Minimum quantization parameter for VP8. + + + + + V4L2_CID_MPEG_VIDEO_VPX_MAX_QP + integer + + Maximum quantization parameter for VP8. + + + + + V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP  + integer + + Quantization parameter for an I frame for VP8. + + + + + V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP  + integer + + Quantization parameter for a P frame for VP8. + + + + + V4L2_CID_MPEG_VIDEO_VPX_PROFILE  + integer + + Select the desired profile for VPx encoder. +Acceptable values are 0, 1, 2 and 3 corresponding to encoder profiles 0, 1, 2 and 3. + + diff --git a/Documentation/DocBook/media/v4l/dev-overlay.xml b/Documentation/DocBook/media/v4l/dev-overlay.xml index 40d1d768143948..cc6e0c5c960ceb 100644 --- a/Documentation/DocBook/media/v4l/dev-overlay.xml +++ b/Documentation/DocBook/media/v4l/dev-overlay.xml @@ -346,17 +346,14 @@ rectangle, in pixels. rectangle, in pixels. Offsets increase to the right and down. - __s32 + __u32 width Width of the rectangle, in pixels. - __s32 + __u32 height - Height of the rectangle, in pixels. Width and -height cannot be negative, the fields are signed for hysterical -reasons. + Height of the rectangle, in pixels. diff --git a/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml b/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml index 355df43badc5d7..cf8548556c7dcb 100644 --- a/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml +++ b/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml @@ -134,6 +134,15 @@ Output pad, relative to the entity. Output pads source data and are origins of links. + + MEDIA_PAD_FL_MUST_CONNECT + If this flag is set and the pad is linked to any other + pad, then at least one of those links must be enabled for the + entity to be able to stream. There could be temporary reasons + (e.g. device configuration dependent) for the pad to need + enabled links even when this flag isn't set; the absence of the + flag doesn't imply there is none. + diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index f72c1cc93a9b0d..7331ce116f4cc1 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -89,7 +89,7 @@ V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE. - The following tables list existing packet RGB formats. + The following tables list existing packed RGB formats. Codestin Search App @@ -615,7 +615,7 @@ - The following table lists existing packet Bayer formats. The data + The following table lists existing packed Bayer formats. The data organization is given as an example for the first pixel only.
@@ -1178,7 +1178,7 @@ U, Y, V, Y order will be named V4L2_MBUS_FMT_UYVY8_2X8. - list existing packet YUV + lists existing packed YUV formats and describes the organization of each pixel data in each sample. When a format pattern is split across multiple samples each of the samples in the pattern is described. @@ -2491,6 +2491,163 @@
+
+ Codestin Search App + + Those formats transfer pixel data as RGB values in a cylindrical-coordinate + system using Hue-Saturation-Value or Hue-Saturation-Lightness components. The + format code is made of the following information. + + The hue, saturation, value or lightness and optional alpha + components order code, as encoded in a pixel sample. The only currently + supported value is AHSV. + + The number of bits per component, for each component. The values + can be different for all components. The only currently supported value is 8888. + + The number of bus samples per pixel. Pixels that are wider than + the bus width must be transferred in multiple samples. The only currently + supported value is 1. + The bus width. + For formats where the total number of bits per pixel is smaller + than the number of bus samples per pixel times the bus width, a padding + value stating if the bytes are padded in their most high order bits + (PADHI) or low order bits (PADLO). + For formats where the number of bus samples per pixel is larger + than 1, an endianness value stating if the pixel is transferred MSB first + (BE) or LSB first (LE). + + + + The following table lists existing HSV/HSL formats. + + + Codestin Search App + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Identifier + Code + + Data organization + + + + + Bit + 31 + 30 + 29 + 28 + 27 + 26 + 25 + 24 + 23 + 22 + 21 + 20 + 19 + 18 + 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0 + + + + + V4L2_MBUS_FMT_AHSV8888_1X32 + 0x6001 + + a7 + a6 + a5 + a4 + a3 + a2 + a1 + a0 + h7 + h6 + h5 + h4 + h3 + h2 + h1 + h0 + s7 + s6 + s5 + s4 + s3 + s2 + s1 + s0 + v7 + v6 + v5 + v4 + v3 + v2 + v1 + v0 + + + +
+
+
Codestin Search App diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index 8469fe13945c52..74b7f27af71a71 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -140,6 +140,14 @@ structs, ioctls) must be noted in more detail in the history chapter (compat.xml), along with the possible impact on existing drivers and applications. --> + + 3.14 + 2013-11-25 + rr + Set width and height as unsigned on v4l2_rect. + + + 3.11 2013-05-26 @@ -501,7 +509,7 @@ and discussions on the V4L mailing list. Codestin Search App - Revision 3.11 + Revision 3.14 &sub-common; diff --git a/Documentation/DocBook/media/v4l/vidioc-cropcap.xml b/Documentation/DocBook/media/v4l/vidioc-cropcap.xml index bf7cc979fdfa6b..1f5ed64cd75a0e 100644 --- a/Documentation/DocBook/media/v4l/vidioc-cropcap.xml +++ b/Documentation/DocBook/media/v4l/vidioc-cropcap.xml @@ -133,18 +133,14 @@ rectangle, in pixels. rectangle, in pixels. - __s32 + __u32 width Width of the rectangle, in pixels. - __s32 + __u32 height - Height of the rectangle, in pixels. Width -and height cannot be negative, the fields are signed for -hysterical reasons. - + Height of the rectangle, in pixels. diff --git a/Documentation/DocBook/media/v4l/vidioc-streamon.xml b/Documentation/DocBook/media/v4l/vidioc-streamon.xml index 716ea15e54a174..65dff55079d717 100644 --- a/Documentation/DocBook/media/v4l/vidioc-streamon.xml +++ b/Documentation/DocBook/media/v4l/vidioc-streamon.xml @@ -59,7 +59,7 @@ buffers are filled (if there are any empty buffers in the incoming queue) until VIDIOC_STREAMON has been called. Accordingly the output hardware is disabled, no video signal is produced until VIDIOC_STREAMON has been called. -The ioctl will succeed only when at least one output buffer is in the +The ioctl will succeed when at least one output buffer is in the incoming queue. The VIDIOC_STREAMOFF ioctl, apart of diff --git a/Documentation/PCI/MSI-HOWTO.txt b/Documentation/PCI/MSI-HOWTO.txt index a8d01005f480ad..10a93696e55ad3 100644 --- a/Documentation/PCI/MSI-HOWTO.txt +++ b/Documentation/PCI/MSI-HOWTO.txt @@ -82,7 +82,19 @@ Most of the hard work is done for the driver in the PCI layer. It simply has to request that the PCI layer set up the MSI capability for this device. -4.2.1 pci_enable_msi_range +4.2.1 pci_enable_msi + +int pci_enable_msi(struct pci_dev *dev) + +A successful call allocates ONE interrupt to the device, regardless +of how many MSIs the device supports. The device is switched from +pin-based interrupt mode to MSI mode. The dev->irq number is changed +to a new number which represents the message signaled interrupt; +consequently, this function should be called before the driver calls +request_irq(), because an MSI is delivered via a vector that is +different from the vector of a pin-based interrupt. + +4.2.2 pci_enable_msi_range int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec) @@ -147,6 +159,11 @@ static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec) return pci_enable_msi_range(pdev, nvec, nvec); } +Note, unlike pci_enable_msi_exact() function, which could be also used to +enable a particular number of MSI-X interrupts, pci_enable_msi_range() +returns either a negative errno or 'nvec' (not negative errno or 0 - as +pci_enable_msi_exact() does). + 4.2.1.3 Single MSI mode The most notorious example of the request type described above is @@ -158,7 +175,27 @@ static int foo_driver_enable_single_msi(struct pci_dev *pdev) return pci_enable_msi_range(pdev, 1, 1); } -4.2.2 pci_disable_msi +Note, unlike pci_enable_msi() function, which could be also used to +enable the single MSI mode, pci_enable_msi_range() returns either a +negative errno or 1 (not negative errno or 0 - as pci_enable_msi() +does). + +4.2.3 pci_enable_msi_exact + +int pci_enable_msi_exact(struct pci_dev *dev, int nvec) + +This variation on pci_enable_msi_range() call allows a device driver to +request exactly 'nvec' MSIs. + +If this function returns a negative number, it indicates an error and +the driver should not attempt to request any more MSI interrupts for +this device. + +By contrast with pci_enable_msi_range() function, pci_enable_msi_exact() +returns zero in case of success, which indicates MSI interrupts have been +successfully allocated. + +4.2.4 pci_disable_msi void pci_disable_msi(struct pci_dev *dev) @@ -172,7 +209,7 @@ on any interrupt for which it previously called request_irq(). Failure to do so results in a BUG_ON(), leaving the device with MSI enabled and thus leaking its vector. -4.2.3 pci_msi_vec_count +4.2.4 pci_msi_vec_count int pci_msi_vec_count(struct pci_dev *dev) @@ -257,8 +294,8 @@ possible, likely up to the limit returned by pci_msix_vec_count() function: static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec) { - return pci_enable_msi_range(adapter->pdev, adapter->msix_entries, - 1, nvec); + return pci_enable_msix_range(adapter->pdev, adapter->msix_entries, + 1, nvec); } Note the value of 'minvec' parameter is 1. As 'minvec' is inclusive, @@ -269,8 +306,8 @@ In this case the function could look like this: static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec) { - return pci_enable_msi_range(adapter->pdev, adapter->msix_entries, - FOO_DRIVER_MINIMUM_NVEC, nvec); + return pci_enable_msix_range(adapter->pdev, adapter->msix_entries, + FOO_DRIVER_MINIMUM_NVEC, nvec); } 4.3.1.2 Exact number of MSI-X interrupts @@ -282,10 +319,15 @@ parameters: static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec) { - return pci_enable_msi_range(adapter->pdev, adapter->msix_entries, - nvec, nvec); + return pci_enable_msix_range(adapter->pdev, adapter->msix_entries, + nvec, nvec); } +Note, unlike pci_enable_msix_exact() function, which could be also used to +enable a particular number of MSI-X interrupts, pci_enable_msix_range() +returns either a negative errno or 'nvec' (not negative errno or 0 - as +pci_enable_msix_exact() does). + 4.3.1.3 Specific requirements to the number of MSI-X interrupts As noted above, there could be devices that can not operate with just any @@ -332,7 +374,64 @@ Note how pci_enable_msix_range() return value is analized for a fallback - any error code other than -ENOSPC indicates a fatal error and should not be retried. -4.3.2 pci_disable_msix +4.3.2 pci_enable_msix_exact + +int pci_enable_msix_exact(struct pci_dev *dev, + struct msix_entry *entries, int nvec) + +This variation on pci_enable_msix_range() call allows a device driver to +request exactly 'nvec' MSI-Xs. + +If this function returns a negative number, it indicates an error and +the driver should not attempt to allocate any more MSI-X interrupts for +this device. + +By contrast with pci_enable_msix_range() function, pci_enable_msix_exact() +returns zero in case of success, which indicates MSI-X interrupts have been +successfully allocated. + +Another version of a routine that enables MSI-X mode for a device with +specific requirements described in chapter 4.3.1.3 might look like this: + +/* + * Assume 'minvec' and 'maxvec' are non-zero + */ +static int foo_driver_enable_msix(struct foo_adapter *adapter, + int minvec, int maxvec) +{ + int rc; + + minvec = roundup_pow_of_two(minvec); + maxvec = rounddown_pow_of_two(maxvec); + + if (minvec > maxvec) + return -ERANGE; + +retry: + rc = pci_enable_msix_exact(adapter->pdev, + adapter->msix_entries, maxvec); + + /* + * -ENOSPC is the only error code allowed to be analyzed + */ + if (rc == -ENOSPC) { + if (maxvec == 1) + return -ENOSPC; + + maxvec /= 2; + + if (minvec > maxvec) + return -ENOSPC; + + goto retry; + } else if (rc < 0) { + return rc; + } + + return maxvec; +} + +4.3.3 pci_disable_msix void pci_disable_msix(struct pci_dev *dev) diff --git a/Documentation/RCU/00-INDEX b/Documentation/RCU/00-INDEX index 1d7a885761f51f..fa57139f50bf77 100644 --- a/Documentation/RCU/00-INDEX +++ b/Documentation/RCU/00-INDEX @@ -8,6 +8,8 @@ listRCU.txt - Using RCU to Protect Read-Mostly Linked Lists lockdep.txt - RCU and lockdep checking +lockdep-splat.txt + - RCU Lockdep splats explained. NMI-RCU.txt - Using RCU to Protect Dynamic NMI Handlers rcubarrier.txt diff --git a/Documentation/arm/00-INDEX b/Documentation/arm/00-INDEX index 36420e116c908b..a94090cc785d06 100644 --- a/Documentation/arm/00-INDEX +++ b/Documentation/arm/00-INDEX @@ -4,6 +4,8 @@ Booting - requirements for booting Interrupts - ARM Interrupt subsystem documentation +IXP4xx + - Intel IXP4xx Network processor. msm - MSM specific documentation Netwinder @@ -24,8 +26,16 @@ SPEAr - ST SPEAr platform Linux Overview VFP/ - Release notes for Linux Kernel Vector Floating Point support code +cluster-pm-race-avoidance.txt + - Algorithm for CPU and Cluster setup/teardown empeg/ - Ltd's Empeg MP3 Car Audio Player +firmware.txt + - Secure firmware registration and calling. +kernel_mode_neon.txt + - How to use NEON instructions in kernel mode +kernel_user_helpers.txt + - Helper functions in kernel space made available for userspace. mem_alignment - alignment abort handler documentation memory.txt @@ -34,3 +44,7 @@ nwfpe/ - NWFPE floating point emulator documentation swp_emulation - SWP/SWPB emulation handler/logging description +tcm.txt + - ARM Tightly Coupled Memory +vlocks.txt + - Voting locks, low-level mechanism relying on memory system atomic writes. diff --git a/Documentation/blackfin/00-INDEX b/Documentation/blackfin/00-INDEX index 2df0365f2dff0e..c54fcdd4ae9f68 100644 --- a/Documentation/blackfin/00-INDEX +++ b/Documentation/blackfin/00-INDEX @@ -1,8 +1,10 @@ 00-INDEX - This file - +Makefile + - Makefile for gptimers example file. bfin-gpio-notes.txt - Notes in developing/using bfin-gpio driver. - bfin-spi-notes.txt - Notes for using bfin spi bus driver. +gptimers-example.c + - gptimers example diff --git a/Documentation/block/00-INDEX b/Documentation/block/00-INDEX index 929d9904f74b7e..e840b47613f78f 100644 --- a/Documentation/block/00-INDEX +++ b/Documentation/block/00-INDEX @@ -14,6 +14,8 @@ deadline-iosched.txt - Deadline IO scheduler tunables ioprio.txt - Block io priorities (in CFQ scheduler) +null_blk.txt + - Null block for block-layer benchmarking. queue-sysfs.txt - Queue's sysfs entries request.txt diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt index 8df5e8e6dceba0..2101e718670d02 100644 --- a/Documentation/block/biodoc.txt +++ b/Documentation/block/biodoc.txt @@ -447,14 +447,13 @@ struct bio_vec { * main unit of I/O for the block layer and lower layers (ie drivers) */ struct bio { - sector_t bi_sector; struct bio *bi_next; /* request queue link */ struct block_device *bi_bdev; /* target device */ unsigned long bi_flags; /* status, command, etc */ unsigned long bi_rw; /* low bits: r/w, high: priority */ unsigned int bi_vcnt; /* how may bio_vec's */ - unsigned int bi_idx; /* current index into bio_vec array */ + struct bvec_iter bi_iter; /* current index into bio_vec array */ unsigned int bi_size; /* total size in bytes */ unsigned short bi_phys_segments; /* segments after physaddr coalesce*/ @@ -480,7 +479,7 @@ With this multipage bio design: - Code that traverses the req list can find all the segments of a bio by using rq_for_each_segment. This handles the fact that a request has multiple bios, each of which can have multiple segments. -- Drivers which can't process a large bio in one shot can use the bi_idx +- Drivers which can't process a large bio in one shot can use the bi_iter field to keep track of the next bio_vec entry to process. (e.g a 1MB bio_vec needs to be handled in max 128kB chunks for IDE) [TBD: Should preferably also have a bi_voffset and bi_vlen to avoid modifying @@ -589,7 +588,7 @@ driver should not modify these values. The block layer sets up the nr_sectors and current_nr_sectors fields (based on the corresponding hard_xxx values and the number of bytes transferred) and updates it on every transfer that invokes end_that_request_first. It does the same for the -buffer, bio, bio->bi_idx fields too. +buffer, bio, bio->bi_iter fields too. The buffer field is just a virtual address mapping of the current segment of the i/o buffer in cases where the buffer resides in low-memory. For high diff --git a/Documentation/block/biovecs.txt b/Documentation/block/biovecs.txt new file mode 100644 index 00000000000000..74a32ad52f5300 --- /dev/null +++ b/Documentation/block/biovecs.txt @@ -0,0 +1,111 @@ + +Immutable biovecs and biovec iterators: +======================================= + +Kent Overstreet + +As of 3.13, biovecs should never be modified after a bio has been submitted. +Instead, we have a new struct bvec_iter which represents a range of a biovec - +the iterator will be modified as the bio is completed, not the biovec. + +More specifically, old code that needed to partially complete a bio would +update bi_sector and bi_size, and advance bi_idx to the next biovec. If it +ended up partway through a biovec, it would increment bv_offset and decrement +bv_len by the number of bytes completed in that biovec. + +In the new scheme of things, everything that must be mutated in order to +partially complete a bio is segregated into struct bvec_iter: bi_sector, +bi_size and bi_idx have been moved there; and instead of modifying bv_offset +and bv_len, struct bvec_iter has bi_bvec_done, which represents the number of +bytes completed in the current bvec. + +There are a bunch of new helper macros for hiding the gory details - in +particular, presenting the illusion of partially completed biovecs so that +normal code doesn't have to deal with bi_bvec_done. + + * Driver code should no longer refer to biovecs directly; we now have + bio_iovec() and bio_iovec_iter() macros that return literal struct biovecs, + constructed from the raw biovecs but taking into account bi_bvec_done and + bi_size. + + bio_for_each_segment() has been updated to take a bvec_iter argument + instead of an integer (that corresponded to bi_idx); for a lot of code the + conversion just required changing the types of the arguments to + bio_for_each_segment(). + + * Advancing a bvec_iter is done with bio_advance_iter(); bio_advance() is a + wrapper around bio_advance_iter() that operates on bio->bi_iter, and also + advances the bio integrity's iter if present. + + There is a lower level advance function - bvec_iter_advance() - which takes + a pointer to a biovec, not a bio; this is used by the bio integrity code. + +What's all this get us? +======================= + +Having a real iterator, and making biovecs immutable, has a number of +advantages: + + * Before, iterating over bios was very awkward when you weren't processing + exactly one bvec at a time - for example, bio_copy_data() in fs/bio.c, + which copies the contents of one bio into another. Because the biovecs + wouldn't necessarily be the same size, the old code was tricky convoluted - + it had to walk two different bios at the same time, keeping both bi_idx and + and offset into the current biovec for each. + + The new code is much more straightforward - have a look. This sort of + pattern comes up in a lot of places; a lot of drivers were essentially open + coding bvec iterators before, and having common implementation considerably + simplifies a lot of code. + + * Before, any code that might need to use the biovec after the bio had been + completed (perhaps to copy the data somewhere else, or perhaps to resubmit + it somewhere else if there was an error) had to save the entire bvec array + - again, this was being done in a fair number of places. + + * Biovecs can be shared between multiple bios - a bvec iter can represent an + arbitrary range of an existing biovec, both starting and ending midway + through biovecs. This is what enables efficient splitting of arbitrary + bios. Note that this means we _only_ use bi_size to determine when we've + reached the end of a bio, not bi_vcnt - and the bio_iovec() macro takes + bi_size into account when constructing biovecs. + + * Splitting bios is now much simpler. The old bio_split() didn't even work on + bios with more than a single bvec! Now, we can efficiently split arbitrary + size bios - because the new bio can share the old bio's biovec. + + Care must be taken to ensure the biovec isn't freed while the split bio is + still using it, in case the original bio completes first, though. Using + bio_chain() when splitting bios helps with this. + + * Submitting partially completed bios is now perfectly fine - this comes up + occasionally in stacking block drivers and various code (e.g. md and + bcache) had some ugly workarounds for this. + + It used to be the case that submitting a partially completed bio would work + fine to _most_ devices, but since accessing the raw bvec array was the + norm, not all drivers would respect bi_idx and those would break. Now, + since all drivers _must_ go through the bvec iterator - and have been + audited to make sure they are - submitting partially completed bios is + perfectly fine. + +Other implications: +=================== + + * Almost all usage of bi_idx is now incorrect and has been removed; instead, + where previously you would have used bi_idx you'd now use a bvec_iter, + probably passing it to one of the helper macros. + + I.e. instead of using bio_iovec_idx() (or bio->bi_iovec[bio->bi_idx]), you + now use bio_iter_iovec(), which takes a bvec_iter and returns a + literal struct bio_vec - constructed on the fly from the raw biovec but + taking into account bi_bvec_done (and bi_size). + + * bi_vcnt can't be trusted or relied upon by driver code - i.e. anything that + doesn't actually own the bio. The reason is twofold: firstly, it's not + actually needed for iterating over the bio anymore - we only use bi_size. + Secondly, when cloning a bio and reusing (a portion of) the original bio's + biovec, in order to calculate bi_vcnt for the new bio we'd have to iterate + over all the biovecs in the new bio - which is silly as it's not needed. + + So, don't use bi_vcnt anymore. diff --git a/drivers/staging/zram/zram.txt b/Documentation/blockdev/zram.txt similarity index 90% rename from drivers/staging/zram/zram.txt rename to Documentation/blockdev/zram.txt index 765d790ae83102..2eccddffa6c8fd 100644 --- a/drivers/staging/zram/zram.txt +++ b/Documentation/blockdev/zram.txt @@ -1,8 +1,6 @@ zram: Compressed RAM based block devices ---------------------------------------- -Project home: http://compcache.googlecode.com/ - * Introduction The zram module creates RAM based block devices named /dev/zram @@ -69,9 +67,5 @@ Following shows a typical sequence of steps for using zram. resets the disksize to zero. You must set the disksize again before reusing the device. -Please report any problems at: - - Mailing list: linux-mm-cc at laptop dot org - - Issue tracker: http://code.google.com/p/compcache/issues/list - Nitin Gupta ngupta@vflare.org diff --git a/Documentation/cgroups/resource_counter.txt b/Documentation/cgroups/resource_counter.txt index 52e1da16a30942..5108afb3645c49 100644 --- a/Documentation/cgroups/resource_counter.txt +++ b/Documentation/cgroups/resource_counter.txt @@ -95,7 +95,7 @@ to work with it. f. u64 res_counter_uncharge_until (struct res_counter *rc, struct res_counter *top, - unsinged long val) + unsigned long val) Almost same as res_counter_uncharge() but propagation of uncharge stops when rc == top. This is useful when kill a res_counter in diff --git a/Documentation/debugging-via-ohci1394.txt b/Documentation/debugging-via-ohci1394.txt index 611f5a5499b153..fa0151a712f9c5 100644 --- a/Documentation/debugging-via-ohci1394.txt +++ b/Documentation/debugging-via-ohci1394.txt @@ -22,10 +22,12 @@ locations such as buffers like the printk buffer or the process table. Retrieving a full system memory dump is also possible over the FireWire, using data transfer rates in the order of 10MB/s or more. -Memory access is currently limited to the low 4G of physical address -space which can be a problem on IA64 machines where memory is located -mostly above that limit, but it is rarely a problem on more common -hardware such as hardware based on x86, x86-64 and PowerPC. +With most FireWire controllers, memory access is limited to the low 4 GB +of physical address space. This can be a problem on IA64 machines where +memory is located mostly above that limit, but it is rarely a problem on +more common hardware such as x86, x86-64 and PowerPC. However, at least +Agere/LSI FW643e and FW643e2 controllers are known to support access to +physical addresses above 4 GB. Together with a early initialization of the OHCI-1394 controller for debugging, this facility proved most useful for examining long debugs logs in the printk @@ -36,17 +38,11 @@ available (notebooks) or too slow for extensive debug information (like ACPI). Drivers ------- -The ohci1394 driver in drivers/ieee1394 initializes the OHCI-1394 controllers -to a working state and enables physical DMA by default for all remote nodes. -This can be turned off by ohci1394's module parameter phys_dma=0. - -The alternative firewire-ohci driver in drivers/firewire uses filtered physical +The firewire-ohci driver in drivers/firewire uses filtered physical DMA by default, which is more secure but not suitable for remote debugging. -Compile the driver with CONFIG_FIREWIRE_OHCI_REMOTE_DMA (Kernel hacking menu: -Remote debugging over FireWire with firewire-ohci) to get unfiltered physical -DMA. +Pass the remote_dma=1 parameter to the driver to get unfiltered physical DMA. -Because ohci1394 and firewire-ohci depend on the PCI enumeration to be +Because the firewire-ohci driver depends on the PCI enumeration to be completed, an initialization routine which runs pretty early has been implemented for x86. This routine runs long before console_init() can be called, i.e. before the printk buffer appears on the console. @@ -64,7 +60,7 @@ be used to view the printk buffer of a remote machine, even with live update. Bernhard Kaindl enhanced firescope to support accessing 64-bit machines from 32-bit firescope and vice versa: -- http://halobates.de/firewire/firescope-0.2.2.tar.bz2 +- http://v3.sk/~lkundrak/firescope/ and he implemented fast system dump (alpha version - read README.txt): - http://halobates.de/firewire/firedump-0.1.tar.bz2 @@ -92,11 +88,11 @@ Step-by-step instructions for using firescope with early OHCI initialization: 1) Verify that your hardware is supported: - Load the ohci1394 or the fw-ohci module and check your kernel logs. + Load the firewire-ohci module and check your kernel logs. You should see a line similar to - ohci1394: fw-host0: OHCI-1394 1.1 (PCI): IRQ=[18] MMIO=[fe9ff800-fe9fffff] - ... Max Packet=[2048] IR/IT contexts=[4/8] + firewire_ohci 0000:15:00.1: added OHCI v1.0 device as card 2, 4 IR + 4 IT + ... contexts, quirks 0x11 when loading the driver. If you have no supported controller, many PCI, CardBus and even some Express cards which are fully compliant to OHCI-1394 @@ -105,6 +101,9 @@ Step-by-step instructions for using firescope with early OHCI initialization: compliant, they are based on TI PCILynx chips and require drivers for Win- dows operating systems. + The mentioned kernel log message contains ">4 GB phys DMA" in case of + OHCI-1394 controllers which support accesses above this limit. + 2) Establish a working FireWire cable connection: Any FireWire cable, as long at it provides electrically and mechanically @@ -113,20 +112,18 @@ Step-by-step instructions for using firescope with early OHCI initialization: If an driver is running on both machines you should see a line like - ieee1394: Node added: ID:BUS[0-01:1023] GUID[0090270001b84bba] + firewire_core 0000:15:00.1: created device fw1: GUID 00061b0020105917, S400 on both machines in the kernel log when the cable is plugged in and connects the two machines. 3) Test physical DMA using firescope: - On the debug host, - - load the raw1394 module, - - make sure that /dev/raw1394 is accessible, + On the debug host, make sure that /dev/fw* is accessible, then start firescope: $ firescope - Port 0 (ohci1394) opened, 2 nodes detected + Port 0 (/dev/fw1) opened, 2 nodes detected FireScope --------- diff --git a/Documentation/devicetree/00-INDEX b/Documentation/devicetree/00-INDEX index b78f691fd84705..8c4102c6a5e77b 100644 --- a/Documentation/devicetree/00-INDEX +++ b/Documentation/devicetree/00-INDEX @@ -8,3 +8,5 @@ https://lists.ozlabs.org/listinfo/devicetree-discuss - this file booting-without-of.txt - Booting Linux without Open Firmware, describes history and format of device trees. +usage-model.txt + - How Linux uses DT and what DT aims to solve. \ No newline at end of file diff --git a/Documentation/devicetree/bindings/arm/bcm/kona-timer.txt b/Documentation/devicetree/bindings/arm/bcm/kona-timer.txt index 17d88b233d1bce..39adf54b4388b9 100644 --- a/Documentation/devicetree/bindings/arm/bcm/kona-timer.txt +++ b/Documentation/devicetree/bindings/arm/bcm/kona-timer.txt @@ -8,13 +8,18 @@ Required properties: - DEPRECATED: compatible : "bcm,kona-timer" - reg : Register range for the timer - interrupts : interrupt for the timer +- clocks: phandle + clock specifier pair of the external clock - clock-frequency: frequency that the clock operates +Only one of clocks or clock-frequency should be specified. + +Refer to clocks/clock-bindings.txt for generic clock consumer properties. + Example: timer@35006000 { compatible = "brcm,kona-timer"; reg = <0x35006000 0x1000>; interrupts = <0x0 7 0x4>; - clock-frequency = <32768>; + clocks = <&hub_timer_clk>; }; diff --git a/Documentation/devicetree/bindings/arm/davinci/nand.txt b/Documentation/devicetree/bindings/arm/davinci/nand.txt deleted file mode 100644 index 3545ea704b50cb..00000000000000 --- a/Documentation/devicetree/bindings/arm/davinci/nand.txt +++ /dev/null @@ -1,46 +0,0 @@ -* Texas Instruments Davinci NAND - -This file provides information, what the device node for the -davinci nand interface contain. - -Required properties: -- compatible: "ti,davinci-nand"; -- reg : contain 2 offset/length values: - - offset and length for the access window - - offset and length for accessing the aemif control registers -- ti,davinci-chipselect: Indicates on the davinci_nand driver which - chipselect is used for accessing the nand. - -Recommended properties : -- ti,davinci-mask-ale: mask for ale -- ti,davinci-mask-cle: mask for cle -- ti,davinci-mask-chipsel: mask for chipselect -- ti,davinci-ecc-mode: ECC mode valid values for davinci driver: - - "none" - - "soft" - - "hw" -- ti,davinci-ecc-bits: used ECC bits, currently supported 1 or 4. -- ti,davinci-nand-buswidth: buswidth 8 or 16 -- ti,davinci-nand-use-bbt: use flash based bad block table support. - -nand device bindings may contain additional sub-nodes describing -partitions of the address space. See partition.txt for more detail. - -Example(da850 EVM ): -nand_cs3@62000000 { - compatible = "ti,davinci-nand"; - reg = <0x62000000 0x807ff - 0x68000000 0x8000>; - ti,davinci-chipselect = <1>; - ti,davinci-mask-ale = <0>; - ti,davinci-mask-cle = <0>; - ti,davinci-mask-chipsel = <0>; - ti,davinci-ecc-mode = "hw"; - ti,davinci-ecc-bits = <4>; - ti,davinci-nand-use-bbt; - - partition@180000 { - label = "ubifs"; - reg = <0x180000 0x7e80000>; - }; -}; diff --git a/Documentation/devicetree/bindings/clock/bcm-kona-clock.txt b/Documentation/devicetree/bindings/clock/bcm-kona-clock.txt new file mode 100644 index 00000000000000..56d1f4961075a5 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/bcm-kona-clock.txt @@ -0,0 +1,93 @@ +Broadcom Kona Family Clocks + +This binding is associated with Broadcom SoCs having "Kona" style +clock control units (CCUs). A CCU is a clock provider that manages +a set of clock signals. Each CCU is represented by a node in the +device tree. + +This binding uses the common clock binding: + Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible + Shall have one of the following values: + - "brcm,bcm11351-root-ccu" + - "brcm,bcm11351-aon-ccu" + - "brcm,bcm11351-hub-ccu" + - "brcm,bcm11351-master-ccu" + - "brcm,bcm11351-slave-ccu" +- reg + Shall define the base and range of the address space + containing clock control registers +- #clock-cells + Shall have value <1>. The permitted clock-specifier values + are defined below. +- clock-output-names + Shall be an ordered list of strings defining the names of + the clocks provided by the CCU. + + +BCM281XX family SoCs use Kona CCUs. The following table defines +the set of CCUs and clock specifiers for BCM281XX clocks. When +a clock consumer references a clocks, its symbolic specifier +(rather than its numeric index value) should be used. These +specifiers are defined in "include/dt-bindings/clock/bcm281xx.h". + + CCU Clock Type Index Specifier + --- ----- ---- ----- --------- + root frac_1m peri 0 BCM281XX_ROOT_CCU_FRAC_1M + + aon hub_timer peri 0 BCM281XX_AON_CCU_HUB_TIMER + aon pmu_bsc peri 1 BCM281XX_AON_CCU_PMU_BSC + aon pmu_bsc_var peri 2 BCM281XX_AON_CCU_PMU_BSC_VAR + + hub tmon_1m peri 0 BCM281XX_HUB_CCU_TMON_1M + + master sdio1 peri 0 BCM281XX_MASTER_CCU_SDIO1 + master sdio2 peri 1 BCM281XX_MASTER_CCU_SDIO2 + master sdio3 peri 2 BCM281XX_MASTER_CCU_SDIO3 + master sdio4 peri 3 BCM281XX_MASTER_CCU_SDIO4 + master dmac peri 4 BCM281XX_MASTER_CCU_DMAC + master usb_ic peri 5 BCM281XX_MASTER_CCU_USB_IC + master hsic2_48m peri 6 BCM281XX_MASTER_CCU_HSIC_48M + master hsic2_12m peri 7 BCM281XX_MASTER_CCU_HSIC_12M + + slave uartb peri 0 BCM281XX_SLAVE_CCU_UARTB + slave uartb2 peri 1 BCM281XX_SLAVE_CCU_UARTB2 + slave uartb3 peri 2 BCM281XX_SLAVE_CCU_UARTB3 + slave uartb4 peri 3 BCM281XX_SLAVE_CCU_UARTB4 + slave ssp0 peri 4 BCM281XX_SLAVE_CCU_SSP0 + slave ssp2 peri 5 BCM281XX_SLAVE_CCU_SSP2 + slave bsc1 peri 6 BCM281XX_SLAVE_CCU_BSC1 + slave bsc2 peri 7 BCM281XX_SLAVE_CCU_BSC2 + slave bsc3 peri 8 BCM281XX_SLAVE_CCU_BSC3 + slave pwm peri 9 BCM281XX_SLAVE_CCU_PWM + + +Device tree example: + + slave_ccu: slave_ccu { + compatible = "brcm,bcm11351-slave-ccu"; + reg = <0x3e011000 0x0f00>; + #clock-cells = <1>; + clock-output-names = "uartb", + "uartb2", + "uartb3", + "uartb4"; + }; + + ref_crystal_clk: ref_crystal { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <26000000>; + }; + + uart@3e002000 { + compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart"; + status = "disabled"; + reg = <0x3e002000 0x1000>; + clocks = <&slave_ccu BCM281XX_SLAVE_CCU_UARTB3>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + }; diff --git a/Documentation/devicetree/bindings/clock/corenet-clock.txt b/Documentation/devicetree/bindings/clock/corenet-clock.txt new file mode 100644 index 00000000000000..24711af48e30c7 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/corenet-clock.txt @@ -0,0 +1,134 @@ +* Clock Block on Freescale CoreNet Platforms + +Freescale CoreNet chips take primary clocking input from the external +SYSCLK signal. The SYSCLK input (frequency) is multiplied using +multiple phase locked loops (PLL) to create a variety of frequencies +which can then be passed to a variety of internal logic, including +cores and peripheral IP blocks. +Please refer to the Reference Manual for details. + +1. Clock Block Binding + +Required properties: +- compatible: Should contain a specific clock block compatible string + and a single chassis clock compatible string. + Clock block strings include, but not limited to, one of the: + * "fsl,p2041-clockgen" + * "fsl,p3041-clockgen" + * "fsl,p4080-clockgen" + * "fsl,p5020-clockgen" + * "fsl,p5040-clockgen" + * "fsl,t4240-clockgen" + * "fsl,b4420-clockgen" + * "fsl,b4860-clockgen" + Chassis clock strings include: + * "fsl,qoriq-clockgen-1.0": for chassis 1.0 clocks + * "fsl,qoriq-clockgen-2.0": for chassis 2.0 clocks +- reg: Describes the address of the device's resources within the + address space defined by its parent bus, and resource zero + represents the clock register set +- clock-frequency: Input system clock frequency + +Recommended properties: +- ranges: Allows valid translation between child's address space and + parent's. Must be present if the device has sub-nodes. +- #address-cells: Specifies the number of cells used to represent + physical base addresses. Must be present if the device has + sub-nodes and set to 1 if present +- #size-cells: Specifies the number of cells used to represent + the size of an address. Must be present if the device has + sub-nodes and set to 1 if present + +2. Clock Provider/Consumer Binding + +Most of the bindings are from the common clock binding[1]. + [1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : Should include one of the following: + * "fsl,qoriq-core-pll-1.0" for core PLL clocks (v1.0) + * "fsl,qoriq-core-pll-2.0" for core PLL clocks (v2.0) + * "fsl,qoriq-core-mux-1.0" for core mux clocks (v1.0) + * "fsl,qoriq-core-mux-2.0" for core mux clocks (v2.0) + * "fsl,qoriq-sysclk-1.0": for input system clock (v1.0). + It takes parent's clock-frequency as its clock. + * "fsl,qoriq-sysclk-2.0": for input system clock (v2.0). + It takes parent's clock-frequency as its clock. +- #clock-cells: From common clock binding. The number of cells in a + clock-specifier. Should be <0> for "fsl,qoriq-sysclk-[1,2].0" + clocks, or <1> for "fsl,qoriq-core-pll-[1,2].0" clocks. + For "fsl,qoriq-core-pll-[1,2].0" clocks, the single + clock-specifier cell may take the following values: + * 0 - equal to the PLL frequency + * 1 - equal to the PLL frequency divided by 2 + * 2 - equal to the PLL frequency divided by 4 + +Recommended properties: +- clocks: Should be the phandle of input parent clock +- clock-names: From common clock binding, indicates the clock name +- clock-output-names: From common clock binding, indicates the names of + output clocks +- reg: Should be the offset and length of clock block base address. + The length should be 4. + +Example for clock block and clock provider: +/ { + clockgen: global-utilities@e1000 { + compatible = "fsl,p5020-clockgen", "fsl,qoriq-clockgen-1.0"; + ranges = <0x0 0xe1000 0x1000>; + clock-frequency = <133333333>; + reg = <0xe1000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + sysclk: sysclk { + #clock-cells = <0>; + compatible = "fsl,qoriq-sysclk-1.0"; + clock-output-names = "sysclk"; + } + + pll0: pll0@800 { + #clock-cells = <1>; + reg = <0x800 0x4>; + compatible = "fsl,qoriq-core-pll-1.0"; + clocks = <&sysclk>; + clock-output-names = "pll0", "pll0-div2"; + }; + + pll1: pll1@820 { + #clock-cells = <1>; + reg = <0x820 0x4>; + compatible = "fsl,qoriq-core-pll-1.0"; + clocks = <&sysclk>; + clock-output-names = "pll1", "pll1-div2"; + }; + + mux0: mux0@0 { + #clock-cells = <0>; + reg = <0x0 0x4>; + compatible = "fsl,qoriq-core-mux-1.0"; + clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>; + clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2"; + clock-output-names = "cmux0"; + }; + + mux1: mux1@20 { + #clock-cells = <0>; + reg = <0x20 0x4>; + compatible = "fsl,qoriq-core-mux-1.0"; + clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>; + clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2"; + clock-output-names = "cmux1"; + }; + }; + } + +Example for clock consumer: + +/ { + cpu0: PowerPC,e5500@0 { + ... + clocks = <&mux0>; + ... + }; + } diff --git a/Documentation/devicetree/bindings/clock/ti/apll.txt b/Documentation/devicetree/bindings/clock/ti/apll.txt new file mode 100644 index 00000000000000..7faf5a68b3beeb --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/apll.txt @@ -0,0 +1,31 @@ +Binding for Texas Instruments APLL clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a +register-mapped APLL with usually two selectable input clocks +(reference clock and bypass clock), with analog phase locked +loop logic for multiplying the input clock to a desired output +clock. This clock also typically supports different operation +modes (locked, low power stop etc.) APLL mostly behaves like +a subtype of a DPLL [2], although a simplified one at that. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/ti/dpll.txt + +Required properties: +- compatible : shall be "ti,dra7-apll-clock" +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link phandles of parent clocks (clk-ref and clk-bypass) +- reg : address and length of the register set for controlling the APLL. + It contains the information of registers in the following order: + "control" - contains the control register base address + "idlest" - contains the idlest register base address + +Examples: + apll_pcie_ck: apll_pcie_ck@4a008200 { + #clock-cells = <0>; + clocks = <&apll_pcie_in_clk_mux>, <&dpll_pcie_ref_ck>; + reg = <0x4a00821c 0x4>, <0x4a008220 0x4>; + compatible = "ti,dra7-apll-clock"; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/autoidle.txt b/Documentation/devicetree/bindings/clock/ti/autoidle.txt new file mode 100644 index 00000000000000..7c735dde9fe971 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/autoidle.txt @@ -0,0 +1,39 @@ +Binding for Texas Instruments autoidle clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a register mapped +clock which can be put to idle automatically by hardware based on the usage +and a configuration bit setting. Autoidle clock is never an individual +clock, it is always a derivative of some basic clock like a gate, divider, +or fixed-factor. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- reg : offset for the register controlling the autoidle +- ti,autoidle-shift : bit shift of the autoidle enable bit +- ti,invert-autoidle-bit : autoidle is enabled by setting the bit to 0 + +Examples: + dpll_core_m4_ck: dpll_core_m4_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x2d38>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_usb_clkdcoldo_ck: dpll_usb_clkdcoldo_ck { + #clock-cells = <0>; + compatible = "ti,fixed-factor-clock"; + clocks = <&dpll_usb_ck>; + ti,clock-div = <1>; + ti,autoidle-shift = <8>; + reg = <0x01b4>; + ti,clock-mult = <1>; + ti,invert-autoidle-bit; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/clockdomain.txt b/Documentation/devicetree/bindings/clock/ti/clockdomain.txt new file mode 100644 index 00000000000000..cb76b3f2b3415a --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/clockdomain.txt @@ -0,0 +1,24 @@ +Binding for Texas Instruments clockdomain. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1] in consumer role. +Every clock on TI SoC belongs to one clockdomain, but software +only needs this information for specific clocks which require +their parent clockdomain to be controlled when the clock is +enabled/disabled. This binding doesn't define a new clock +binding type, it is used to group existing clock nodes under +hardware hierarchy. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "ti,clockdomain" +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link phandles of clocks within this domain + +Examples: + dss_clkdm: dss_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dss1_alwon_fck_3430es2>, <&dss_ick_3430es2>; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/composite.txt b/Documentation/devicetree/bindings/clock/ti/composite.txt new file mode 100644 index 00000000000000..5f43c4706b0944 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/composite.txt @@ -0,0 +1,54 @@ +Binding for TI composite clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a +register-mapped composite clock with multiple different sub-types; + +a multiplexer clock with multiple input clock signals or parents, one +of which can be selected as output, this behaves exactly as [2] + +an adjustable clock rate divider, this behaves exactly as [3] + +a gating function which can be used to enable and disable the output +clock, this behaves exactly as [4] + +The binding must provide a list of the component clocks that shall be +merged to this clock. The component clocks shall be of one of the +"ti,*composite*-clock" types. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/ti/mux.txt +[3] Documentation/devicetree/bindings/clock/ti/divider.txt +[4] Documentation/devicetree/bindings/clock/ti/gate.txt + +Required properties: +- compatible : shall be: "ti,composite-clock" +- clocks : link phandles of component clocks +- #clock-cells : from common clock binding; shall be set to 0. + +Examples: + +usb_l4_gate_ick: usb_l4_gate_ick { + #clock-cells = <0>; + compatible = "ti,composite-interface-clock"; + clocks = <&l4_ick>; + ti,bit-shift = <5>; + reg = <0x0a10>; +}; + +usb_l4_div_ick: usb_l4_div_ick { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&l4_ick>; + ti,bit-shift = <4>; + ti,max-div = <1>; + reg = <0x0a40>; + ti,index-starts-at-one; +}; + +usb_l4_ick: usb_l4_ick { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&usb_l4_gate_ick>, <&usb_l4_div_ick>; +}; diff --git a/Documentation/devicetree/bindings/clock/ti/divider.txt b/Documentation/devicetree/bindings/clock/ti/divider.txt new file mode 100644 index 00000000000000..35a6f5c7e5c26f --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/divider.txt @@ -0,0 +1,114 @@ +Binding for TI divider clock + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a +register-mapped adjustable clock rate divider that does not gate and has +only one input clock or parent. By default the value programmed into +the register is one less than the actual divisor value. E.g: + +register value actual divisor value +0 1 +1 2 +2 3 + +This assumption may be modified by the following optional properties: + +ti,index-starts-at-one - valid divisor values start at 1, not the default +of 0. E.g: +register value actual divisor value +1 1 +2 2 +3 3 + +ti,index-power-of-two - valid divisor values are powers of two. E.g: +register value actual divisor value +0 1 +1 2 +2 4 + +Additionally an array of valid dividers may be supplied like so: + + ti,dividers = <4>, <8>, <0>, <16>; + +Which will map the resulting values to a divisor table by their index: +register value actual divisor value +0 4 +1 8 +2 +3 16 + +Any zero value in this array means the corresponding bit-value is invalid +and must not be used. + +The binding must also provide the register to control the divider and +unless the divider array is provided, min and max dividers. Optionally +the number of bits to shift that mask, if necessary. If the shift value +is missing it is the same as supplying a zero shift. + +This binding can also optionally provide support to the hardware autoidle +feature, see [2]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/ti/autoidle.txt + +Required properties: +- compatible : shall be "ti,divider-clock" or "ti,composite-divider-clock". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link to phandle of parent clock +- reg : offset for register controlling adjustable divider + +Optional properties: +- clock-output-names : from common clock binding. +- ti,dividers : array of integers defining divisors +- ti,bit-shift : number of bits to shift the divider value, defaults to 0 +- ti,min-div : min divisor for dividing the input clock rate, only + needed if the first divisor is offset from the default value (1) +- ti,max-div : max divisor for dividing the input clock rate, only needed + if ti,dividers is not defined. +- ti,index-starts-at-one : valid divisor programming starts at 1, not zero, + only valid if ti,dividers is not defined. +- ti,index-power-of-two : valid divisor programming must be a power of two, + only valid if ti,dividers is not defined. +- ti,autoidle-shift : bit shift of the autoidle enable bit for the clock, + see [2] +- ti,invert-autoidle-bit : autoidle is enabled by setting the bit to 0, + see [2] +- ti,set-rate-parent : clk_set_rate is propagated to parent + +Examples: +dpll_usb_m2_ck: dpll_usb_m2_ck@4a008190 { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_ck>; + ti,max-div = <127>; + reg = <0x190>; + ti,index-starts-at-one; +}; + +aess_fclk: aess_fclk@4a004528 { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&abe_clk>; + ti,bit-shift = <24>; + reg = <0x528>; + ti,max-div = <2>; +}; + +dpll_core_m3x2_div_ck: dpll_core_m3x2_div_ck { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + reg = <0x0134>; + ti,index-starts-at-one; +}; + +ssi_ssr_div_fck_3430es2: ssi_ssr_div_fck_3430es2 { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&corex2_fck>; + ti,bit-shift = <8>; + reg = <0x0a40>; + ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>; +}; diff --git a/Documentation/devicetree/bindings/clock/ti/dpll.txt b/Documentation/devicetree/bindings/clock/ti/dpll.txt new file mode 100644 index 00000000000000..30bfdb7c9f18a7 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/dpll.txt @@ -0,0 +1,75 @@ +Binding for Texas Instruments DPLL clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a +register-mapped DPLL with usually two selectable input clocks +(reference clock and bypass clock), with digital phase locked +loop logic for multiplying the input clock to a desired output +clock. This clock also typically supports different operation +modes (locked, low power stop etc.) This binding has several +sub-types, which effectively result in slightly different setup +for the actual DPLL clock. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of: + "ti,omap3-dpll-clock", + "ti,omap3-dpll-core-clock", + "ti,omap3-dpll-per-clock", + "ti,omap3-dpll-per-j-type-clock", + "ti,omap4-dpll-clock", + "ti,omap4-dpll-x2-clock", + "ti,omap4-dpll-core-clock", + "ti,omap4-dpll-m4xen-clock", + "ti,omap4-dpll-j-type-clock", + "ti,am3-dpll-no-gate-clock", + "ti,am3-dpll-j-type-clock", + "ti,am3-dpll-no-gate-j-type-clock", + "ti,am3-dpll-clock", + "ti,am3-dpll-core-clock", + "ti,am3-dpll-x2-clock", + +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link phandles of parent clocks, first entry lists reference clock + and second entry bypass clock +- reg : offsets for the register set for controlling the DPLL. + Registers are listed in following order: + "control" - contains the control register base address + "idlest" - contains the idle status register base address + "mult-div1" - contains the multiplier / divider register base address + "autoidle" - contains the autoidle register base address (optional) + ti,am3-* dpll types do not have autoidle register + +Optional properties: +- DPLL mode setting - defining any one or more of the following overrides + default setting. + - ti,low-power-stop : DPLL supports low power stop mode, gating output + - ti,low-power-bypass : DPLL output matches rate of parent bypass clock + - ti,lock : DPLL locks in programmed rate + +Examples: + dpll_core_ck: dpll_core_ck@44e00490 { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-core-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x490>, <0x45c>, <0x488>, <0x468>; + }; + + dpll2_ck: dpll2_ck@48004004 { + #clock-cells = <0>; + compatible = "ti,omap3-dpll-clock"; + clocks = <&sys_ck>, <&dpll2_fck>; + ti,low-power-stop; + ti,low-power-bypass; + ti,lock; + reg = <0x4>, <0x24>, <0x34>, <0x40>; + }; + + dpll_core_ck: dpll_core_ck@44e00490 { + #clock-cells = <0>; + compatible = "ti,am3-dpll-core-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x90>, <0x5c>, <0x68>; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/fixed-factor-clock.txt b/Documentation/devicetree/bindings/clock/ti/fixed-factor-clock.txt new file mode 100644 index 00000000000000..662b36d53bf0b6 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/fixed-factor-clock.txt @@ -0,0 +1,43 @@ +Binding for TI fixed factor rate clock sources. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1], and also uses the autoidle +support from TI autoidle clock [2]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/ti/autoidle.txt + +Required properties: +- compatible : shall be "ti,fixed-factor-clock". +- #clock-cells : from common clock binding; shall be set to 0. +- ti,clock-div: fixed divider. +- ti,clock-mult: fixed multiplier. +- clocks: parent clock. + +Optional properties: +- ti,autoidle-shift: bit shift of the autoidle enable bit for the clock, + see [2] +- reg: offset for the autoidle register of this clock, see [2] +- ti,invert-autoidle-bit: autoidle is enabled by setting the bit to 0, see [2] +- ti,set-rate-parent: clk_set_rate is propagated to parent + +Example: + clock { + compatible = "ti,fixed-factor-clock"; + clocks = <&parentclk>; + #clock-cells = <0>; + ti,clock-div = <2>; + ti,clock-mult = <1>; + }; + + dpll_usb_clkdcoldo_ck: dpll_usb_clkdcoldo_ck { + #clock-cells = <0>; + compatible = "ti,fixed-factor-clock"; + clocks = <&dpll_usb_ck>; + ti,clock-div = <1>; + ti,autoidle-shift = <8>; + reg = <0x01b4>; + ti,clock-mult = <1>; + ti,invert-autoidle-bit; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/gate.txt b/Documentation/devicetree/bindings/clock/ti/gate.txt new file mode 100644 index 00000000000000..125281aaa4ca03 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/gate.txt @@ -0,0 +1,85 @@ +Binding for Texas Instruments gate clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. This clock is +quite much similar to the basic gate-clock [2], however, +it supports a number of additional features. If no register +is provided for this clock, the code assumes that a clockdomain +will be controlled instead and the corresponding hw-ops for +that is used. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/gate-clock.txt +[3] Documentation/devicetree/bindings/clock/ti/clockdomain.txt + +Required properties: +- compatible : shall be one of: + "ti,gate-clock" - basic gate clock + "ti,wait-gate-clock" - gate clock which waits until clock is active before + returning from clk_enable() + "ti,dss-gate-clock" - gate clock with DSS specific hardware handling + "ti,am35xx-gate-clock" - gate clock with AM35xx specific hardware handling + "ti,clkdm-gate-clock" - clockdomain gate clock, which derives its functional + clock directly from a clockdomain, see [3] how + to map clockdomains properly + "ti,hsdiv-gate-clock" - gate clock with OMAP36xx specific hardware handling, + required for a hardware errata +- #clock-cells : from common clock binding; shall be set to 0 +- clocks : link to phandle of parent clock +- reg : offset for register controlling adjustable gate, not needed for + ti,clkdm-gate-clock type + +Optional properties: +- ti,bit-shift : bit shift for programming the clock gate, invalid for + ti,clkdm-gate-clock type +- ti,set-bit-to-disable : inverts default gate programming. Setting the bit + gates the clock and clearing the bit ungates the clock. + +Examples: + mmchs2_fck: mmchs2_fck@48004a00 { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x48004a00 0x4>; + ti,bit-shift = <25>; + }; + + uart4_fck_am35xx: uart4_fck_am35xx { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <23>; + }; + + dss1_alwon_fck_3430es2: dss1_alwon_fck_3430es2@48004e00 { + #clock-cells = <0>; + compatible = "ti,dss-gate-clock"; + clocks = <&dpll4_m4x2_ck>; + reg = <0x48004e00 0x4>; + ti,bit-shift = <0>; + }; + + emac_ick: emac_ick@4800259c { + #clock-cells = <0>; + compatible = "ti,am35xx-gate-clock"; + clocks = <&ipss_ick>; + reg = <0x4800259c 0x4>; + ti,bit-shift = <1>; + }; + + emu_src_ck: emu_src_ck { + #clock-cells = <0>; + compatible = "ti,clkdm-gate-clock"; + clocks = <&emu_src_mux_ck>; + }; + + dpll4_m2x2_ck: dpll4_m2x2_ck@48004d00 { + #clock-cells = <0>; + compatible = "ti,hsdiv-gate-clock"; + clocks = <&dpll4_m2x2_mul_ck>; + ti,bit-shift = <0x1b>; + reg = <0x48004d00 0x4>; + ti,set-bit-to-disable; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/interface.txt b/Documentation/devicetree/bindings/clock/ti/interface.txt new file mode 100644 index 00000000000000..064e8caccac371 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/interface.txt @@ -0,0 +1,54 @@ +Binding for Texas Instruments interface clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. This clock is +quite much similar to the basic gate-clock [2], however, +it supports a number of additional features, including +companion clock finding (match corresponding functional gate +clock) and hardware autoidle enable / disable. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/gate-clock.txt + +Required properties: +- compatible : shall be one of: + "ti,omap3-interface-clock" - basic OMAP3 interface clock + "ti,omap3-no-wait-interface-clock" - interface clock which has no hardware + capability for waiting clock to be ready + "ti,omap3-hsotgusb-interface-clock" - interface clock with USB specific HW + handling + "ti,omap3-dss-interface-clock" - interface clock with DSS specific HW handling + "ti,omap3-ssi-interface-clock" - interface clock with SSI specific HW handling + "ti,am35xx-interface-clock" - interface clock with AM35xx specific HW handling +- #clock-cells : from common clock binding; shall be set to 0 +- clocks : link to phandle of parent clock +- reg : base address for the control register + +Optional properties: +- ti,bit-shift : bit shift for the bit enabling/disabling the clock (default 0) + +Examples: + aes1_ick: aes1_ick@48004a14 { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&security_l4_ick2>; + reg = <0x48004a14 0x4>; + ti,bit-shift = <3>; + }; + + cam_ick: cam_ick@48004f10 { + #clock-cells = <0>; + compatible = "ti,omap3-no-wait-interface-clock"; + clocks = <&l4_ick>; + reg = <0x48004f10 0x4>; + ti,bit-shift = <0>; + }; + + ssi_ick_3430es2: ssi_ick_3430es2@48004a10 { + #clock-cells = <0>; + compatible = "ti,omap3-ssi-interface-clock"; + clocks = <&ssi_l4_ick>; + reg = <0x48004a10 0x4>; + ti,bit-shift = <0>; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/mux.txt b/Documentation/devicetree/bindings/clock/ti/mux.txt new file mode 100644 index 00000000000000..2d0d170f80013d --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/mux.txt @@ -0,0 +1,76 @@ +Binding for TI mux clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a +register-mapped multiplexer with multiple input clock signals or +parents, one of which can be selected as output. This clock does not +gate or adjust the parent rate via a divider or multiplier. + +By default the "clocks" property lists the parents in the same order +as they are programmed into the regster. E.g: + + clocks = <&foo_clock>, <&bar_clock>, <&baz_clock>; + +results in programming the register as follows: + +register value selected parent clock +0 foo_clock +1 bar_clock +2 baz_clock + +Some clock controller IPs do not allow a value of zero to be programmed +into the register, instead indexing begins at 1. The optional property +"index-starts-at-one" modified the scheme as follows: + +register value selected clock parent +1 foo_clock +2 bar_clock +3 baz_clock + +The binding must provide the register to control the mux. Optionally +the number of bits to shift the control field in the register can be +supplied. If the shift value is missing it is the same as supplying +a zero shift. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "ti,mux-clock" or "ti,composite-mux-clock". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link phandles of parent clocks +- reg : register offset for register controlling adjustable mux + +Optional properties: +- ti,bit-shift : number of bits to shift the bit-mask, defaults to + 0 if not present +- ti,index-starts-at-one : valid input select programming starts at 1, not + zero +- ti,set-rate-parent : clk_set_rate is propagated to parent clock, + not supported by the composite-mux-clock subtype + +Examples: + +sys_clkin_ck: sys_clkin_ck@4a306110 { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>; + reg = <0x0110>; + ti,index-starts-at-one; +}; + +abe_dpll_bypass_clk_mux_ck: abe_dpll_bypass_clk_mux_ck@4a306108 { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0108>; +}; + +mcbsp5_mux_fck: mcbsp5_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&core_96m_fck>, <&mcbsp_clks>; + ti,bit-shift = <4>; + reg = <0x02d8>; +}; diff --git a/Documentation/devicetree/bindings/dma/bcm2835-dma.txt b/Documentation/devicetree/bindings/dma/bcm2835-dma.txt new file mode 100644 index 00000000000000..1396078d15ac62 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/bcm2835-dma.txt @@ -0,0 +1,57 @@ +* BCM2835 DMA controller + +The BCM2835 DMA controller has 16 channels in total. +Only the lower 13 channels have an associated IRQ. +Some arbitrary channels are used by the firmware +(1,3,6,7 in the current firmware version). +The channels 0,2 and 3 have special functionality +and should not be used by the driver. + +Required properties: +- compatible: Should be "brcm,bcm2835-dma". +- reg: Should contain DMA registers location and length. +- interrupts: Should contain the DMA interrupts associated + to the DMA channels in ascending order. +- #dma-cells: Must be <1>, the cell in the dmas property of the + client device represents the DREQ number. +- brcm,dma-channel-mask: Bit mask representing the channels + not used by the firmware in ascending order, + i.e. first channel corresponds to LSB. + +Example: + +dma: dma@7e007000 { + compatible = "brcm,bcm2835-dma"; + reg = <0x7e007000 0xf00>; + interrupts = <1 16>, + <1 17>, + <1 18>, + <1 19>, + <1 20>, + <1 21>, + <1 22>, + <1 23>, + <1 24>, + <1 25>, + <1 26>, + <1 27>, + <1 28>; + + #dma-cells = <1>; + brcm,dma-channel-mask = <0x7f35>; +}; + +DMA clients connected to the BCM2835 DMA controller must use the format +described in the dma.txt file, using a two-cell specifier for each channel. + +Example: + +bcm2835_i2s: i2s@7e203000 { + compatible = "brcm,bcm2835-i2s"; + reg = < 0x7e203000 0x20>, + < 0x7e101098 0x02>; + + dmas = <&dma 2>, + <&dma 3>; + dma-names = "tx", "rx"; +}; diff --git a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt index 4fa814d3832124..68b83ecc385007 100644 --- a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt +++ b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt @@ -42,6 +42,7 @@ The full ID of peripheral types can be found below. 19 IPU Memory 20 ASRC 21 ESAI + 22 SSI Dual FIFO (needs firmware ver >= 2) The third cell specifies the transfer priority as below. diff --git a/Documentation/devicetree/bindings/dma/moxa,moxart-dma.txt b/Documentation/devicetree/bindings/dma/moxa,moxart-dma.txt new file mode 100644 index 00000000000000..8a9f3559335b50 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/moxa,moxart-dma.txt @@ -0,0 +1,45 @@ +MOXA ART DMA Controller + +See dma.txt first + +Required properties: + +- compatible : Must be "moxa,moxart-dma" +- reg : Should contain registers location and length +- interrupts : Should contain an interrupt-specifier for the sole + interrupt generated by the device +- #dma-cells : Should be 1, a single cell holding a line request number + +Example: + + dma: dma@90500000 { + compatible = "moxa,moxart-dma"; + reg = <0x90500080 0x40>; + interrupts = <24 0>; + #dma-cells = <1>; + }; + + +Clients: + +DMA clients connected to the MOXA ART DMA controller must use the format +described in the dma.txt file, using a two-cell specifier for each channel: +a phandle plus one integer cells. +The two cells in order are: + +1. A phandle pointing to the DMA controller. +2. Peripheral identifier for the hardware handshaking interface. + +Example: +Use specific request line passing from dma +For example, MMC request line is 5 + + sdhci: sdhci@98e00000 { + compatible = "moxa,moxart-sdhci"; + reg = <0x98e00000 0x5C>; + interrupts = <5 0>; + clocks = <&clk_apb>; + dmas = <&dma 5>, + <&dma 5>; + dma-names = "tx", "rx"; + }; diff --git a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt index ab45c02aa658f6..efaeec8961b64b 100644 --- a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt @@ -118,6 +118,9 @@ of the following host1x client modules: See ../reset/reset.txt for details. - reset-names: Must include the following entries: - dc + - nvidia,head: The number of the display controller head. This is used to + setup the various types of output to receive video data from the given + head. Each display controller node has a child node, named "rgb", that represents the RGB output associated with the controller. It can take the following @@ -125,6 +128,7 @@ of the following host1x client modules: - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection - nvidia,edid: supplies a binary EDID blob + - nvidia,panel: phandle of a display panel - hdmi: High Definition Multimedia Interface @@ -149,6 +153,7 @@ of the following host1x client modules: - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection - nvidia,edid: supplies a binary EDID blob + - nvidia,panel: phandle of a display panel - tvo: TV encoder output @@ -169,11 +174,21 @@ of the following host1x client modules: - clock-names: Must include the following entries: - dsi This MUST be the first entry. + - lp - parent - resets: Must contain an entry for each entry in reset-names. See ../reset/reset.txt for details. - reset-names: Must include the following entries: - dsi + - nvidia,mipi-calibrate: Should contain a phandle and a specifier specifying + which pads are used by this DSI output and need to be calibrated. See also + ../mipi/nvidia,tegra114-mipi.txt. + + Optional properties: + - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing + - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection + - nvidia,edid: supplies a binary EDID blob + - nvidia,panel: phandle of a display panel Example: @@ -253,7 +268,7 @@ Example: interrupts = <0 73 0x04>; clocks = <&tegra_car TEGRA20_CLK_DISP1>, <&tegra_car TEGRA20_CLK_PLL_P>; - clock-names = "disp1", "parent"; + clock-names = "dc", "parent"; resets = <&tegra_car 27>; reset-names = "dc"; @@ -268,7 +283,7 @@ Example: interrupts = <0 74 0x04>; clocks = <&tegra_car TEGRA20_CLK_DISP2>, <&tegra_car TEGRA20_CLK_PLL_P>; - clock-names = "disp2", "parent"; + clock-names = "dc", "parent"; resets = <&tegra_car 26>; reset-names = "dc"; diff --git a/Documentation/devicetree/bindings/interrupt-controller/lsi,zevio-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/lsi,zevio-intc.txt new file mode 100644 index 00000000000000..aee38e7c13e7d1 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/lsi,zevio-intc.txt @@ -0,0 +1,18 @@ +TI-NSPIRE interrupt controller + +Required properties: +- compatible: Compatible property value should be "lsi,zevio-intc". + +- reg: Physical base address of the controller and length of memory mapped + region. + +- interrupt-controller : Identifies the node as an interrupt controller + +Example: + +interrupt-controller { + compatible = "lsi,zevio-intc"; + interrupt-controller; + reg = <0xDC000000 0x1000>; + #interrupt-cells = <1>; +}; diff --git a/Documentation/devicetree/bindings/leds/tca6507.txt b/Documentation/devicetree/bindings/leds/tca6507.txt index 80ff3dfb1f325e..d7221b84987cd6 100644 --- a/Documentation/devicetree/bindings/leds/tca6507.txt +++ b/Documentation/devicetree/bindings/leds/tca6507.txt @@ -2,6 +2,13 @@ LEDs connected to tca6507 Required properties: - compatible : should be : "ti,tca6507". +- #address-cells: must be 1 +- #size-cells: must be 0 +- reg: typically 0x45. + +Optional properties: +- gpio-controller: allows lines to be used as output-only GPIOs. +- #gpio-cells: if present, must be 0. Each led is represented as a sub-node of the ti,tca6507 device. @@ -10,6 +17,7 @@ LED sub-node properties: - reg : number of LED line (could be from 0 to 6) - linux,default-trigger : (optional) see Documentation/devicetree/bindings/leds/common.txt +- compatible: either "led" (the default) or "gpio". Examples: @@ -19,6 +27,9 @@ tca6507@45 { #size-cells = <0>; reg = <0x45>; + gpio-controller; + #gpio-cells = <2>; + led0: red-aux@0 { label = "red:aux"; reg = <0x0>; @@ -29,5 +40,10 @@ tca6507@45 { reg = <0x5>; linux,default-trigger = "default-on"; }; + + wifi-reset@6 { + reg = <0x6>; + compatible = "gpio"; + }; }; diff --git a/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt b/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt new file mode 100644 index 00000000000000..937b755baf8fd8 --- /dev/null +++ b/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt @@ -0,0 +1,11 @@ +Samsung S5P/EXYNOS SoC series JPEG codec + +Required properties: + +- compatible : should be one of: + "samsung,s5pv210-jpeg", "samsung,exynos4210-jpeg"; +- reg : address and length of the JPEG codec IP register set; +- interrupts : specifies the JPEG codec IP interrupt; +- clocks : should contain the JPEG codec IP gate clock specifier, from the + common clock bindings; +- clock-names : should contain "jpeg" entry. diff --git a/Documentation/devicetree/bindings/media/samsung-s5k5baf.txt b/Documentation/devicetree/bindings/media/samsung-s5k5baf.txt new file mode 100644 index 00000000000000..1f51e0439c962d --- /dev/null +++ b/Documentation/devicetree/bindings/media/samsung-s5k5baf.txt @@ -0,0 +1,58 @@ +Samsung S5K5BAF UXGA 1/5" 2M CMOS Image Sensor with embedded SoC ISP +-------------------------------------------------------------------- + +Required properties: + +- compatible : "samsung,s5k5baf"; +- reg : I2C slave address of the sensor; +- vdda-supply : analog power supply 2.8V (2.6V to 3.0V); +- vddreg-supply : regulator input power supply 1.8V (1.7V to 1.9V) + or 2.8V (2.6V to 3.0); +- vddio-supply : I/O power supply 1.8V (1.65V to 1.95V) + or 2.8V (2.5V to 3.1V); +- stbyn-gpios : GPIO connected to STDBYN pin; +- rstn-gpios : GPIO connected to RSTN pin; +- clocks : list of phandle and clock specifier pairs + according to common clock bindings for the + clocks described in clock-names; +- clock-names : should include "mclk" for the sensor's master clock; + +Optional properties: + +- clock-frequency : the frequency at which the "mclk" clock should be + configured to operate, in Hz; if this property is not + specified default 24 MHz value will be used. + +The device node should contain one 'port' child node with one child 'endpoint' +node, according to the bindings defined in Documentation/devicetree/bindings/ +media/video-interfaces.txt. The following are properties specific to those +nodes. + +endpoint node +------------- + +- data-lanes : (optional) specifies MIPI CSI-2 data lanes as covered in + video-interfaces.txt. If present it should be <1> - the device + supports only one data lane without re-mapping. + +Example: + +s5k5bafx@2d { + compatible = "samsung,s5k5baf"; + reg = <0x2d>; + vdda-supply = <&cam_io_en_reg>; + vddreg-supply = <&vt_core_15v_reg>; + vddio-supply = <&vtcam_reg>; + stbyn-gpios = <&gpl2 0 1>; + rstn-gpios = <&gpl2 1 1>; + clock-names = "mclk"; + clocks = <&clock_cam 0>; + clock-frequency = <24000000>; + + port { + s5k5bafx_ep: endpoint { + remote-endpoint = <&csis1_ep>; + data-lanes = <1>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt b/Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt new file mode 100644 index 00000000000000..973c27273772b5 --- /dev/null +++ b/Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt @@ -0,0 +1,98 @@ +MIPI DSI (Display Serial Interface) busses +========================================== + +The MIPI Display Serial Interface specifies a serial bus and a protocol for +communication between a host and up to four peripherals. This document will +define the syntax used to represent a DSI bus in a device tree. + +This document describes DSI bus-specific properties only or defines existing +standard properties in the context of the DSI bus. + +Each DSI host provides a DSI bus. The DSI host controller's node contains a +set of properties that characterize the bus. Child nodes describe individual +peripherals on that bus. + +The following assumes that only a single peripheral is connected to a DSI +host. Experience shows that this is true for the large majority of setups. + +DSI host +-------- + +In addition to the standard properties and those defined by the parent bus of +a DSI host, the following properties apply to a node representing a DSI host. + +Required properties: +- #address-cells: The number of cells required to represent an address on the + bus. DSI peripherals are addressed using a 2-bit virtual channel number, so + a maximum of 4 devices can be addressed on a single bus. Hence the value of + this property should be 1. +- #size-cells: Should be 0. There are cases where it makes sense to use a + different value here. See below. + +DSI peripheral +-------------- + +Peripherals are represented as child nodes of the DSI host's node. Properties +described here apply to all DSI peripherals, but individual bindings may want +to define additional, device-specific properties. + +Required properties: +- reg: The virtual channel number of a DSI peripheral. Must be in the range + from 0 to 3. + +Some DSI peripherals respond to more than a single virtual channel. In that +case two alternative representations can be chosen: +- The reg property can take multiple entries, one for each virtual channel + that the peripheral responds to. +- If the virtual channels that a peripheral responds to are consecutive, the + #size-cells can be set to 1. The first cell of each entry in the reg + property is the number of the first virtual channel and the second cell is + the number of consecutive virtual channels. + +Example +------- + + dsi-host { + ... + + #address-cells = <1>; + #size-cells = <0>; + + /* peripheral responds to virtual channel 0 */ + peripheral@0 { + compatible = "..."; + reg = <0>; + }; + + ... + }; + + dsi-host { + ... + + #address-cells = <1>; + #size-cells = <0>; + + /* peripheral responds to virtual channels 0 and 2 */ + peripheral@0 { + compatible = "..."; + reg = <0, 2>; + }; + + ... + }; + + dsi-host { + ... + + #address-cells = <1>; + #size-cells = <1>; + + /* peripheral responds to virtual channels 1, 2 and 3 */ + peripheral@1 { + compatible = "..."; + reg = <1 3>; + }; + + ... + }; diff --git a/Documentation/devicetree/bindings/mipi/nvidia,tegra114-mipi.txt b/Documentation/devicetree/bindings/mipi/nvidia,tegra114-mipi.txt new file mode 100644 index 00000000000000..e4a25cedc5cf4a --- /dev/null +++ b/Documentation/devicetree/bindings/mipi/nvidia,tegra114-mipi.txt @@ -0,0 +1,41 @@ +NVIDIA Tegra MIPI pad calibration controller + +Required properties: +- compatible: "nvidia,tegra-mipi" +- reg: Physical base address and length of the controller's registers. +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - mipi-cal +- #nvidia,mipi-calibrate-cells: Should be 1. The cell is a bitmask of the pads + that need to be calibrated for a given device. + +User nodes need to contain an nvidia,mipi-calibrate property that has a +phandle to refer to the calibration controller node and a bitmask of the pads +that need to be calibrated. + +Example: + + mipi: mipi@700e3000 { + compatible = "nvidia,tegra114-mipi"; + reg = <0x700e3000 0x100>; + clocks = <&tegra_car TEGRA114_CLK_MIPI_CAL>; + clock-names = "mipi-cal"; + #nvidia,mipi-calibrate-cells = <1>; + }; + + ... + + host1x@50000000 { + ... + + dsi@54300000 { + ... + + nvidia,mipi-calibrate = <&mipi 0x060>; + + ... + }; + + ... + }; diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt new file mode 100644 index 00000000000000..98ee2abbe1387b --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt @@ -0,0 +1,27 @@ +Device Tree Bindings for the Arasan SDHCI Controller + + The bindings follow the mmc[1], clock[2] and interrupt[3] bindings. Only + deviations are documented here. + + [1] Documentation/devicetree/bindings/mmc/mmc.txt + [2] Documentation/devicetree/bindings/clock/clock-bindings.txt + [3] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + +Required Properties: + - compatible: Compatibility string. Must be 'arasan,sdhci-8.9a' + - reg: From mmc bindings: Register location and length. + - clocks: From clock bindings: Handles to clock inputs. + - clock-names: From clock bindings: Tuple including "clk_xin" and "clk_ahb" + - interrupts: Interrupt specifier + - interrupt-parent: Phandle for the interrupt controller that services + interrupts for this device. + +Example: + sdhci@e0100000 { + compatible = "arasan,sdhci-8.9a"; + reg = <0xe0100000 0x1000>; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&clkc 21>, <&clkc 32>; + interrupt-parent = <&gic>; + interrupts = <0 24 4>; + } ; diff --git a/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt index 0a85c70cd30a6e..07ad02075a9354 100644 --- a/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt +++ b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt @@ -13,6 +13,9 @@ Required properties: - #address-cells: should be one. The cell is the slot id. - #size-cells: should be zero. - at least one slot node +- clock-names: tuple listing input clock names. + Required elements: "mci_clk" +- clocks: phandles to input clocks. The node contains child nodes for each slot that the platform uses @@ -24,6 +27,8 @@ mmc0: mmc@f0008000 { interrupts = <12 4>; #address-cells = <1>; #size-cells = <0>; + clock-names = "mci_clk"; + clocks = <&mci0_clk>; [ child node definitions...] }; diff --git a/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt new file mode 100644 index 00000000000000..b8653ea97957d0 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt @@ -0,0 +1,46 @@ +* Hisilicon specific extensions to the Synopsys Designware Mobile + Storage Host Controller + +Read synopsys-dw-mshc.txt for more details + +The Synopsys designware mobile storage host controller is used to interface +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents +differences between the core Synopsys dw mshc controller properties described +by synopsys-dw-mshc.txt and the properties used by the Hisilicon specific +extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: + +* compatible: should be one of the following. + - "hisilicon,hi4511-dw-mshc": for controllers with hi4511 specific extentions. + +Example: + + /* for Hi3620 */ + + /* SoC portion */ + dwmmc_0: dwmmc0@fcd03000 { + compatible = "hisilicon,hi4511-dw-mshc"; + reg = <0xfcd03000 0x1000>; + interrupts = <0 16 4>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&mmc_clock HI3620_SD_CIUCLK>, <&clock HI3620_DDRC_PER_CLK>; + clock-names = "ciu", "biu"; + }; + + /* Board portion */ + dwmmc0@fcd03000 { + num-slots = <1>; + vmmc-supply = <&ldo12>; + fifo-depth = <0x100>; + supports-highspeed; + pinctrl-names = "default"; + pinctrl-0 = <&sd_pmx_pins &sd_cfg_func1 &sd_cfg_func2>; + slot@0 { + reg = <0>; + bus-width = <4>; + disable-wp; + cd-gpios = <&gpio10 3 0>; + }; + }; diff --git a/Documentation/devicetree/bindings/mmc/kona-sdhci.txt b/Documentation/devicetree/bindings/mmc/kona-sdhci.txt index 789fb07a426da6..aaba2483b4ff8c 100644 --- a/Documentation/devicetree/bindings/mmc/kona-sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/kona-sdhci.txt @@ -6,12 +6,16 @@ and the properties present in the bcm281xx SDHCI Required properties: - compatible : Should be "brcm,kona-sdhci" - DEPRECATED: compatible : Should be "bcm,kona-sdhci" +- clocks: phandle + clock specifier pair of the external clock + +Refer to clocks/clock-bindings.txt for generic clock consumer properties. Example: sdio2: sdio@0x3f1a0000 { compatible = "brcm,kona-sdhci"; reg = <0x3f1a0000 0x10000>; + clocks = <&sdio3_clk>; interrupts = <0x0 74 0x4>; }; diff --git a/Documentation/devicetree/bindings/mtd/davinci-nand.txt b/Documentation/devicetree/bindings/mtd/davinci-nand.txt new file mode 100644 index 00000000000000..cfb18abe600167 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/davinci-nand.txt @@ -0,0 +1,94 @@ +Device tree bindings for Texas instruments Davinci/Keystone NAND controller + +This file provides information, what the device node for the davinci/keystone +NAND interface contains. + +Documentation: +Davinci DM646x - http://www.ti.com/lit/ug/sprueq7c/sprueq7c.pdf +Kestone - http://www.ti.com/lit/ug/sprugz3a/sprugz3a.pdf + +Required properties: + +- compatible: "ti,davinci-nand" + "ti,keystone-nand" + +- reg: Contains 2 offset/length values: + - offset and length for the access window. + - offset and length for accessing the AEMIF + control registers. + +- ti,davinci-chipselect: number of chipselect. Indicates on the + davinci_nand driver which chipselect is used + for accessing the nand. + Can be in the range [0-3]. + +Recommended properties : + +- ti,davinci-mask-ale: mask for ALE. Needed for executing address + phase. These offset will be added to the base + address for the chip select space the NAND Flash + device is connected to. + If not set equal to 0x08. + +- ti,davinci-mask-cle: mask for CLE. Needed for executing command + phase. These offset will be added to the base + address for the chip select space the NAND Flash + device is connected to. + If not set equal to 0x10. + +- ti,davinci-mask-chipsel: mask for chipselect address. Needed to mask + addresses for given chipselect. + +- nand-ecc-mode: operation mode of the NAND ecc mode. ECC mode + valid values for davinci driver: + - "none" + - "soft" + - "hw" + +- ti,davinci-ecc-bits: used ECC bits, currently supported 1 or 4. + +- nand-bus-width: buswidth 8 or 16. If not present 8. + +- nand-on-flash-bbt: use flash based bad block table support. OOB + identifier is saved in OOB area. If not present + false. + +Deprecated properties: + +- ti,davinci-ecc-mode: operation mode of the NAND ecc mode. ECC mode + valid values for davinci driver: + - "none" + - "soft" + - "hw" + +- ti,davinci-nand-buswidth: buswidth 8 or 16. If not present 8. + +- ti,davinci-nand-use-bbt: use flash based bad block table support. OOB + identifier is saved in OOB area. If not present + false. + +Nand device bindings may contain additional sub-nodes describing partitions of +the address space. See partition.txt for more detail. The NAND Flash timing +values must be programmed in the chip select’s node of AEMIF +memory-controller (see Documentation/devicetree/bindings/memory-controllers/ +davinci-aemif.txt). + +Example(da850 EVM ): + +nand_cs3@62000000 { + compatible = "ti,davinci-nand"; + reg = <0x62000000 0x807ff + 0x68000000 0x8000>; + ti,davinci-chipselect = <1>; + ti,davinci-mask-ale = <0>; + ti,davinci-mask-cle = <0>; + ti,davinci-mask-chipsel = <0>; + nand-ecc-mode = "hw"; + ti,davinci-ecc-bits = <4>; + nand-on-flash-bbt; + + partition@180000 { + label = "ubifs"; + reg = <0x180000 0x7e80000>; + }; +}; diff --git a/Documentation/devicetree/bindings/mtd/gpmi-nand.txt b/Documentation/devicetree/bindings/mtd/gpmi-nand.txt index 551b2a179d016d..458d5963468826 100644 --- a/Documentation/devicetree/bindings/mtd/gpmi-nand.txt +++ b/Documentation/devicetree/bindings/mtd/gpmi-nand.txt @@ -17,6 +17,14 @@ Required properties: Optional properties: - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false + - fsl,use-minimum-ecc: Protect this NAND flash with the minimum ECC + strength required. The required ECC strength is + automatically discoverable for some flash + (e.g., according to the ONFI standard). + However, note that if this strength is not + discoverable or this property is not enabled, + the software may chooses an implementation-defined + ECC scheme. The device tree may optionally contain sub-nodes describing partitions of the address space. See partition.txt for more detail. diff --git a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt index f1421e2bbab738..86e0a5601ff5df 100644 --- a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt +++ b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt @@ -2,7 +2,9 @@ PXA3xx NAND DT bindings Required properties: - - compatible: Should be "marvell,pxa3xx-nand" + - compatible: Should be set to one of the following: + marvell,pxa3xx-nand + marvell,armada370-nand - reg: The register base for the controller - interrupts: The interrupt to map - #address-cells: Set to <1> if the node includes partitions @@ -13,6 +15,8 @@ Optional properties: - marvell,nand-keep-config: Set to keep the NAND controller config as set by the bootloader - num-cs: Number of chipselect lines to usw + - nand-on-flash-bbt: boolean to enable on flash bbt option if + not present false Example: diff --git a/Documentation/devicetree/bindings/net/allwinner,sun4i-emac.txt b/Documentation/devicetree/bindings/net/allwinner,sun4i-emac.txt index b90bfcd138fff1..863d5b8155c70d 100644 --- a/Documentation/devicetree/bindings/net/allwinner,sun4i-emac.txt +++ b/Documentation/devicetree/bindings/net/allwinner,sun4i-emac.txt @@ -1,7 +1,8 @@ * Allwinner EMAC ethernet controller Required properties: -- compatible: should be "allwinner,sun4i-emac". +- compatible: should be "allwinner,sun4i-a10-emac" (Deprecated: + "allwinner,sun4i-emac") - reg: address and length of the register set for the device. - interrupts: interrupt for the device - phy: A phandle to a phy node defining the PHY address (as the reg @@ -14,7 +15,7 @@ Optional properties: Example: emac: ethernet@01c0b000 { - compatible = "allwinner,sun4i-emac"; + compatible = "allwinner,sun4i-a10-emac"; reg = <0x01c0b000 0x1000>; interrupts = <55>; clocks = <&ahb_gates 17>; diff --git a/Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt b/Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt index 00b9f9a3ec1d8b..4ec56413779d3a 100644 --- a/Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt +++ b/Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt @@ -1,7 +1,8 @@ * Allwinner A10 MDIO Ethernet Controller interface Required properties: -- compatible: should be "allwinner,sun4i-mdio". +- compatible: should be "allwinner,sun4i-a10-mdio" + (Deprecated: "allwinner,sun4i-mdio"). - reg: address and length of the register set for the device. Optional properties: @@ -9,7 +10,7 @@ Optional properties: Example at the SoC level: mdio@01c0b080 { - compatible = "allwinner,sun4i-mdio"; + compatible = "allwinner,sun4i-a10-mdio"; reg = <0x01c0b080 0x14>; #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/net/davinci_emac.txt b/Documentation/devicetree/bindings/net/davinci_emac.txt index ca0911a20e8b21..6e356d15154a96 100644 --- a/Documentation/devicetree/bindings/net/davinci_emac.txt +++ b/Documentation/devicetree/bindings/net/davinci_emac.txt @@ -10,8 +10,6 @@ Required properties: - ti,davinci-ctrl-mod-reg-offset: offset to control module register - ti,davinci-ctrl-ram-offset: offset to control module ram - ti,davinci-ctrl-ram-size: size of control module ram -- ti,davinci-rmii-en: use RMII -- ti,davinci-no-bd-ram: has the emac controller BD RAM - interrupts: interrupt mapping for the davinci emac interrupts sources: 4 sources: , <0x8bc 0x4>; + reg-names = "stmmaceth", "sti-ethconf"; + interrupts = <0 133 0>, <0 134 0>, <0 135 0>; + interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; + phy-mode = "mii"; + + st,syscon = <&syscfg_rear>; + + snps,pbl = <32>; + snps,mixed-burst; + + resets = <&softreset STIH416_ETH0_SOFTRESET>; + reset-names = "stmmaceth"; + pinctrl-0 = <&pinctrl_mii0>; + pinctrl-names = "default"; + clocks = <&CLK_S_GMAC0_PHY>; + clock-names = "stmmaceth"; +}; diff --git a/Documentation/devicetree/bindings/panel/auo,b101aw03.txt b/Documentation/devicetree/bindings/panel/auo,b101aw03.txt new file mode 100644 index 00000000000000..72e088a4fb3a95 --- /dev/null +++ b/Documentation/devicetree/bindings/panel/auo,b101aw03.txt @@ -0,0 +1,7 @@ +AU Optronics Corporation 10.1" WSVGA TFT LCD panel + +Required properties: +- compatible: should be "auo,b101aw03" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/panel/chunghwa,claa101wa01a.txt b/Documentation/devicetree/bindings/panel/chunghwa,claa101wa01a.txt new file mode 100644 index 00000000000000..f24614e4d5ecb8 --- /dev/null +++ b/Documentation/devicetree/bindings/panel/chunghwa,claa101wa01a.txt @@ -0,0 +1,7 @@ +Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel + +Required properties: +- compatible: should be "chunghwa,claa101wa01a" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt b/Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt new file mode 100644 index 00000000000000..0ab2c05a4c22a6 --- /dev/null +++ b/Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt @@ -0,0 +1,7 @@ +Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel + +Required properties: +- compatible: should be "chunghwa,claa101wb03" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt b/Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt new file mode 100644 index 00000000000000..d328b0341bf441 --- /dev/null +++ b/Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt @@ -0,0 +1,7 @@ +Panasonic Corporation 10.1" WUXGA TFT LCD panel + +Required properties: +- compatible: should be "panasonic,vvx10f004b00" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/panel/samsung,ltn101nt05.txt b/Documentation/devicetree/bindings/panel/samsung,ltn101nt05.txt new file mode 100644 index 00000000000000..ef522c6bb85f8b --- /dev/null +++ b/Documentation/devicetree/bindings/panel/samsung,ltn101nt05.txt @@ -0,0 +1,7 @@ +Samsung Electronics 10.1" WSVGA TFT LCD panel + +Required properties: +- compatible: should be "samsung,ltn101nt05" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/panel/simple-panel.txt b/Documentation/devicetree/bindings/panel/simple-panel.txt new file mode 100644 index 00000000000000..1341bbf4aa3d13 --- /dev/null +++ b/Documentation/devicetree/bindings/panel/simple-panel.txt @@ -0,0 +1,21 @@ +Simple display panel + +Required properties: +- power-supply: regulator to provide the supply voltage + +Optional properties: +- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing +- enable-gpios: GPIO pin to enable or disable the panel +- backlight: phandle of the backlight device attached to the panel + +Example: + + panel: panel { + compatible = "cptt,claa101wb01"; + ddc-i2c-bus = <&panelddc>; + + power-supply = <&vdd_pnl_reg>; + enable-gpios = <&gpio 90 0>; + + backlight = <&backlight>; + }; diff --git a/Documentation/devicetree/bindings/power/bq2415x.txt b/Documentation/devicetree/bindings/power/bq2415x.txt new file mode 100644 index 00000000000000..d0327f0b59addf --- /dev/null +++ b/Documentation/devicetree/bindings/power/bq2415x.txt @@ -0,0 +1,47 @@ +Binding for TI bq2415x Li-Ion Charger + +Required properties: +- compatible: Should contain one of the following: + * "ti,bq24150" + * "ti,bq24150" + * "ti,bq24150a" + * "ti,bq24151" + * "ti,bq24151a" + * "ti,bq24152" + * "ti,bq24153" + * "ti,bq24153a" + * "ti,bq24155" + * "ti,bq24156" + * "ti,bq24156a" + * "ti,bq24158" +- reg: integer, i2c address of the device. +- ti,current-limit: integer, initial maximum current charger can pull + from power supply in mA. +- ti,weak-battery-voltage: integer, weak battery voltage threshold in mV. + The chip will use slow precharge if battery voltage + is below this value. +- ti,battery-regulation-voltage: integer, maximum charging voltage in mV. +- ti,charge-current: integer, maximum charging current in mA. +- ti,termination-current: integer, charge will be terminated when current in + constant-voltage phase drops below this value (in mA). +- ti,resistor-sense: integer, value of sensing resistor in milliohm. + +Optional properties: +- ti,usb-charger-detection: phandle to usb charger detection device. + (required for auto mode) + +Example from Nokia N900: + +bq24150a { + compatible = "ti,bq24150a"; + reg = <0x6b>; + + ti,current-limit = <100>; + ti,weak-battery-voltage = <3400>; + ti,battery-regulation-voltage = <4200>; + ti,charge-current = <650>; + ti,termination-current = <100>; + ti,resistor-sense = <68>; + + ti,usb-charger-detection = <&isp1704>; +}; diff --git a/Documentation/devicetree/bindings/pwm/atmel-pwm.txt b/Documentation/devicetree/bindings/pwm/atmel-pwm.txt new file mode 100644 index 00000000000000..02331b904d4e73 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/atmel-pwm.txt @@ -0,0 +1,33 @@ +Atmel PWM controller + +Required properties: + - compatible: should be one of: + - "atmel,at91sam9rl-pwm" + - "atmel,sama5d3-pwm" + - reg: physical base address and length of the controller's registers + - #pwm-cells: Should be 3. See pwm.txt in this directory for a + description of the cells format. + +Example: + + pwm0: pwm@f8034000 { + compatible = "atmel,at91sam9rl-pwm"; + reg = <0xf8034000 0x400>; + #pwm-cells = <3>; + }; + + pwmleds { + compatible = "pwm-leds"; + + d1 { + label = "d1"; + pwms = <&pwm0 3 5000 0> + max-brightness = <255>; + }; + + d2 { + label = "d2"; + pwms = <&pwm0 1 5000 1> + max-brightness = <255>; + }; + }; diff --git a/Documentation/devicetree/bindings/pwm/pxa-pwm.txt b/Documentation/devicetree/bindings/pwm/pxa-pwm.txt new file mode 100644 index 00000000000000..5ae9f1e3c33896 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pxa-pwm.txt @@ -0,0 +1,30 @@ +Marvell PWM controller + +Required properties: +- compatible: should be one or more of: + - "marvell,pxa250-pwm" + - "marvell,pxa270-pwm" + - "marvell,pxa168-pwm" + - "marvell,pxa910-pwm" +- reg: Physical base address and length of the registers used by the PWM channel + Note that one device instance must be created for each PWM that is used, so the + length covers only the register window for one PWM output, not that of the + entire PWM controller. Currently length is 0x10 for all supported devices. +- #pwm-cells: Should be 1. This cell is used to specify the period in + nanoseconds. + +Example PWM device node: + +pwm0: pwm@40b00000 { + compatible = "marvell,pxa250-pwm"; + reg = <0x40b00000 0x10>; + #pwm-cells = <1>; +}; + +Example PWM client node: + +backlight { + compatible = "pwm-backlight"; + pwms = <&pwm0 5000000>; + ... +} diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt index e9e20ec67d62b3..19c84df5fffa35 100644 --- a/Documentation/devicetree/bindings/sound/simple-card.txt +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -43,7 +43,7 @@ Example: sound { compatible = "simple-audio-card"; simple-audio-card,format = "left_j"; - simple-audio-routing = + simple-audio-card,routing = "MIC_IN", "Mic Jack", "Headphone Jack", "HP_OUT", "Ext Spk", "LINE_OUT"; diff --git a/Documentation/devicetree/bindings/spi/spi_atmel.txt b/Documentation/devicetree/bindings/spi/spi_atmel.txt index 07e04cdc0c9e0c..4f8184d069cb5a 100644 --- a/Documentation/devicetree/bindings/spi/spi_atmel.txt +++ b/Documentation/devicetree/bindings/spi/spi_atmel.txt @@ -5,6 +5,9 @@ Required properties: - reg: Address and length of the register set for the device - interrupts: Should contain spi interrupt - cs-gpios: chipselects +- clock-names: tuple listing input clock names. + Required elements: "spi_clk" +- clocks: phandles to input clocks. Example: @@ -14,6 +17,8 @@ spi1: spi@fffcc000 { interrupts = <13 4 5>; #address-cells = <1>; #size-cells = <0>; + clocks = <&spi1_clk>; + clock-names = "spi_clk"; cs-gpios = <&pioB 3 0>; status = "okay"; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 3f900cd51bf00e..40ce2df0e0e95a 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -8,6 +8,7 @@ ad Avionic Design GmbH adi Analog Devices, Inc. aeroflexgaisler Aeroflex Gaisler AB ak Asahi Kasei Corp. +allwinner Allwinner Technology Co., Ltd. altr Altera Corp. amcc Applied Micro Circuits Corporation (APM, formally AMCC) amstaos AMS-Taos Inc. @@ -40,6 +41,7 @@ gmt Global Mixed-mode Technology, Inc. gumstix Gumstix, Inc. haoyu Haoyu Microelectronic Co. Ltd. hisilicon Hisilicon Limited. +honeywell Honeywell hp Hewlett Packard ibm International Business Machines (IBM) idt Integrated Device Technologies, Inc. @@ -55,6 +57,7 @@ maxim Maxim Integrated Products microchip Microchip Technology Inc. mosaixtech Mosaix Technologies, Inc. national National Semiconductor +neonode Neonode Inc. nintendo Nintendo nvidia NVIDIA nxp NXP Semiconductors @@ -64,7 +67,7 @@ phytec PHYTEC Messtechnik GmbH picochip Picochip Ltd powervr PowerVR (deprecated, use img) qca Qualcomm Atheros, Inc. -qcom Qualcomm, Inc. +qcom Qualcomm Technologies, Inc ralink Mediatek/Ralink Technology Corp. ramtron Ramtron International realtek Realtek Semiconductor Corp. @@ -78,6 +81,7 @@ silabs Silicon Laboratories simtek sirf SiRF Technology, Inc. snps Synopsys, Inc. +spansion Spansion Inc. st STMicroelectronics ste ST-Ericsson stericsson ST-Ericsson diff --git a/Documentation/devicetree/bindings/video/ssd1289fb.txt b/Documentation/devicetree/bindings/video/ssd1289fb.txt new file mode 100644 index 00000000000000..4fcd5e68cb6e00 --- /dev/null +++ b/Documentation/devicetree/bindings/video/ssd1289fb.txt @@ -0,0 +1,13 @@ +* Solomon SSD1289 Framebuffer Driver + +Required properties: + - compatible: Should be "solomon,ssd1289fb". The only supported bus for + now is lbc. + - reg: Should contain address of the controller on the LBC bus. The detail + was described in Documentation/devicetree/bindings/powerpc/fsl/lbc.txt + +Examples: +display@2,0 { + compatible = "solomon,ssd1289fb"; + reg = <0x2 0x0000 0x0004>; +}; diff --git a/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt b/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt index fcdd48f7dcffc0..f90e294d7631f9 100644 --- a/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt @@ -9,11 +9,37 @@ Required properties: Optional properties: - timeout-sec: contains the watchdog timeout in seconds. +- interrupts : Should contain WDT interrupt. +- atmel,max-heartbeat-sec : Should contain the maximum heartbeat value in + seconds. This value should be less or equal to 16. It is used to + compute the WDV field. +- atmel,min-heartbeat-sec : Should contain the minimum heartbeat value in + seconds. This value must be smaller than the max-heartbeat-sec value. + It is used to compute the WDD field. +- atmel,watchdog-type : Should be "hardware" or "software". Hardware watchdog + use the at91 watchdog reset. Software watchdog use the watchdog + interrupt to trigger a software reset. +- atmel,reset-type : Should be "proc" or "all". + "all" : assert peripherals and processor reset signals + "proc" : assert the processor reset signal + This is valid only when using "hardware" watchdog. +- atmel,disable : Should be present if you want to disable the watchdog. +- atmel,idle-halt : Should be present if you want to stop the watchdog when + entering idle state. +- atmel,dbg-halt : Should be present if you want to stop the watchdog when + entering debug state. Example: - watchdog@fffffd40 { compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffd40 0x10>; - timeout-sec = <10>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + timeout-sec = <15>; + atmel,watchdog-type = "hardware"; + atmel,reset-type = "all"; + atmel,dbg-halt; + atmel,idle-halt; + atmel,max-heartbeat-sec = <16>; + atmel,min-heartbeat-sec = <0>; + status = "okay"; }; diff --git a/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt b/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt index 75558ccd9a051e..e60b9a13bdcbd5 100644 --- a/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt @@ -1,12 +1,24 @@ -DaVinci Watchdog Timer (WDT) Controller +Texas Instruments DaVinci/Keystone Watchdog Timer (WDT) Controller Required properties: -- compatible : Should be "ti,davinci-wdt" +- compatible : Should be "ti,davinci-wdt", "ti,keystone-wdt" - reg : Should contain WDT registers location and length +Optional properties: +- timeout-sec : Contains the watchdog timeout in seconds +- clocks : the clock feeding the watchdog timer. + Needed if platform uses clocks. + See clock-bindings.txt + +Documentation: +Davinci DM646x - http://www.ti.com/lit/ug/spruer5b/spruer5b.pdf +Keystone - http://www.ti.com/lit/ug/sprugv5a/sprugv5a.pdf + Examples: wdt: wdt@2320000 { compatible = "ti,davinci-wdt"; reg = <0x02320000 0x80>; + timeout-sec = <30>; + clocks = <&clkwdtimer0>; }; diff --git a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt new file mode 100644 index 00000000000000..37afec194949a3 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt @@ -0,0 +1,23 @@ +* GPIO-controlled Watchdog + +Required Properties: +- compatible: Should contain "linux,wdt-gpio". +- gpios: From common gpio binding; gpio connection to WDT reset pin. +- hw_algo: The algorithm used by the driver. Should be one of the + following values: + - toggle: Either a high-to-low or a low-to-high transition clears + the WDT counter. The watchdog timer is disabled when GPIO is + left floating or connected to a three-state buffer. + - level: Low or high level starts counting WDT timeout, + the opposite level disables the WDT. Active level is determined + by the GPIO flags. +- hw_margin_ms: Maximum time to reset watchdog circuit (milliseconds). + +Example: + watchdog: watchdog { + /* ADM706 */ + compatible = "linux,wdt-gpio"; + gpios = <&gpio3 9 GPIO_ACTIVE_LOW>; + hw_algo = "toggle"; + hw_margin_ms = <1600>; + }; diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt index 2aa486cc1ff6a1..cfff37511aac0e 100644 --- a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt @@ -5,10 +5,29 @@ after a preset amount of time during which the WDT reset event has not occurred. Required properties: -- compatible : should be "samsung,s3c2410-wdt" +- compatible : should be one among the following + (a) "samsung,s3c2410-wdt" for Exynos4 and previous SoCs + (b) "samsung,exynos5250-wdt" for Exynos5250 + (c) "samsung,exynos5420-wdt" for Exynos5420 + - reg : base physical address of the controller and length of memory mapped region. - interrupts : interrupt number to the cpu. +- samsung,syscon-phandle : reference to syscon node (This property required only + in case of compatible being "samsung,exynos5250-wdt" or "samsung,exynos5420-wdt". + In case of Exynos5250 and 5420 this property points to syscon node holding the PMU + base address) Optional properties: - timeout-sec : contains the watchdog timeout in seconds. + +Example: + +watchdog@101D0000 { + compatible = "samsung,exynos5250-wdt"; + reg = <0x101D0000 0x100>; + interrupts = <0 42 0>; + clocks = <&clock 336>; + clock-names = "watchdog"; + samsung,syscon-phandle = <&pmu_syscon>; +}; diff --git a/Documentation/dvb/contributors.txt b/Documentation/dvb/contributors.txt index 47c30098dab65e..731a009723c7cd 100644 --- a/Documentation/dvb/contributors.txt +++ b/Documentation/dvb/contributors.txt @@ -78,7 +78,7 @@ Peter Beutner Wilson Michaels for the lgdt330x frontend driver, and various bugfixes -Michael Krufky +Michael Krufky for maintaining v4l/dvb inter-tree dependencies Taylor Jacob diff --git a/Documentation/fb/00-INDEX b/Documentation/fb/00-INDEX index 30a70542e8235d..fe85e7c5907a54 100644 --- a/Documentation/fb/00-INDEX +++ b/Documentation/fb/00-INDEX @@ -5,6 +5,8 @@ please mail me. 00-INDEX - this file. +api.txt + - The frame buffer API between applications and buffer devices. arkfb.txt - info on the fbdev driver for ARK Logic chips. aty128fb.txt @@ -51,12 +53,16 @@ sh7760fb.txt - info on the SH7760/SH7763 integrated LCDC Framebuffer driver. sisfb.txt - info on the framebuffer device driver for various SiS chips. +sm501.txt + - info on the framebuffer device driver for sm501 videoframebuffer. sstfb.txt - info on the frame buffer driver for 3dfx' Voodoo Graphics boards. tgafb.txt - info on the TGA (DECChip 21030) frame buffer driver. tridentfb.txt info on the framebuffer driver for some Trident chip based cards. +udlfb.txt + - Driver for DisplayLink USB 2.0 chips. uvesafb.txt - info on the userspace VESA (VBE2+ compliant) frame buffer device. vesafb.txt diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX index 632211cbdd5692..ac28149aede4c1 100644 --- a/Documentation/filesystems/00-INDEX +++ b/Documentation/filesystems/00-INDEX @@ -2,6 +2,8 @@ - this file (info on some of the filesystems supported by linux). Locking - info on locking rules as they pertain to Linux VFS. +Makefile + - Makefile for building the filsystems-part of DocBook. 9p.txt - 9p (v9fs) is an implementation of the Plan 9 remote fs protocol. adfs.txt diff --git a/Documentation/filesystems/9p.txt b/Documentation/filesystems/9p.txt index 2c032144284552..fec7144e817c41 100644 --- a/Documentation/filesystems/9p.txt +++ b/Documentation/filesystems/9p.txt @@ -69,10 +69,14 @@ OPTIONS offering several exported file systems. cache=mode specifies a caching policy. By default, no caches are used. + none = default no cache policy, metadata and data + alike are synchronous. loose = no attempts are made at consistency, intended for exclusive, read-only mounts - fscache = use FS-Cache for a persistent, read-only + fscache = use FS-Cache for a persistent, read-only cache backend. + mmap = minimal cache that is only used for read-write + mmap. Northing else is cached, like cache=none debug=n specifies debug level. The debug level is a bitmask. 0x01 = display verbose error messages @@ -147,8 +151,7 @@ on sourceforge (http://sourceforge.net/projects/v9fs). News and other information is maintained on a Wiki. (http://sf.net/apps/mediawiki/v9fs/index.php). -Bug reports may be issued through the kernel.org bugzilla -(http://bugzilla.kernel.org) +Bug reports are best issued via the mailing list. For more information on the Plan 9 Operating System check out http://plan9.bell-labs.com/plan9 @@ -156,11 +159,3 @@ http://plan9.bell-labs.com/plan9 For information on Plan 9 from User Space (Plan 9 applications and libraries ported to Linux/BSD/OSX/etc) check out http://swtch.com/plan9 - -STATUS -====== - -The 2.6 kernel support is working on PPC and x86. - -PLEASE USE THE KERNEL BUGZILLA TO REPORT PROBLEMS. (http://bugzilla.kernel.org) - diff --git a/Documentation/filesystems/btrfs.txt b/Documentation/filesystems/btrfs.txt index 5dd282dda55c5e..d11cc2f8077b9e 100644 --- a/Documentation/filesystems/btrfs.txt +++ b/Documentation/filesystems/btrfs.txt @@ -38,7 +38,7 @@ Mount Options ============= When mounting a btrfs filesystem, the following option are accepted. -Unless otherwise specified, all options default to off. +Options with (*) are default options and will not show in the mount options. alloc_start= Debugging option to force all block allocations above a certain @@ -46,10 +46,12 @@ Unless otherwise specified, all options default to off. bytes, optionally with a K, M, or G suffix, case insensitive. Default is 1MB. + noautodefrag(*) autodefrag - Detect small random writes into files and queue them up for the - defrag process. Works best for small files; Not well suited for - large database workloads. + Disable/enable auto defragmentation. + Auto defragmentation detects small random writes into files and queue + them up for the defrag process. Works best for small files; + Not well suited for large database workloads. check_int check_int_data @@ -96,21 +98,26 @@ Unless otherwise specified, all options default to off. can be avoided. Especially useful when trying to mount a multi-device setup as root. May be specified multiple times for multiple devices. + nodiscard(*) discard - Issue frequent commands to let the block device reclaim space freed by - the filesystem. This is useful for SSD devices, thinly provisioned + Disable/enable discard mount option. + Discard issues frequent commands to let the block device reclaim space + freed by the filesystem. + This is useful for SSD devices, thinly provisioned LUNs and virtual machine images, but may have a significant performance impact. (The fstrim command is also available to initiate batch trims from userspace). + noenospc_debug(*) enospc_debug - Debugging option to be more verbose in some ENOSPC conditions. + Disable/enable debugging option to be more verbose in some ENOSPC conditions. fatal_errors= Action to take when encountering a fatal error: "bug" - BUG() on a fatal error. This is the default. "panic" - panic() on a fatal error. + noflushoncommit(*) flushoncommit The 'flushoncommit' mount option forces any data dirtied by a write in a prior transaction to commit as part of the current commit. This makes @@ -134,26 +141,32 @@ Unless otherwise specified, all options default to off. Specify that 1 metadata chunk should be allocated after every data chunks. Off by default. + acl(*) noacl - Disable support for Posix Access Control Lists (ACLs). See the + Enable/disable support for Posix Access Control Lists (ACLs). See the acl(5) manual page for more information about ACLs. + barrier(*) nobarrier - Disables the use of block layer write barriers. Write barriers ensure - that certain IOs make it through the device cache and are on persistent - storage. If used on a device with a volatile (non-battery-backed) - write-back cache, this option will lead to filesystem corruption on a - system crash or power loss. + Enable/disable the use of block layer write barriers. Write barriers + ensure that certain IOs make it through the device cache and are on + persistent storage. If disabled on a device with a volatile + (non-battery-backed) write-back cache, nobarrier option will lead to + filesystem corruption on a system crash or power loss. + datacow(*) nodatacow - Disable data copy-on-write for newly created files. Implies nodatasum, - and disables all compression. + Enable/disable data copy-on-write for newly created files. + Nodatacow implies nodatasum, and disables all compression. + datasum(*) nodatasum - Disable data checksumming for newly created files. + Enable/disable data checksumming for newly created files. + Datasum implies datacow. + treelog(*) notreelog - Disable the tree logging used for fsync and O_SYNC writes. + Enable/disable the tree logging used for fsync and O_SYNC writes. recovery Enable autorecovery attempts if a bad tree root is found at mount time. diff --git a/Documentation/filesystems/nfs/00-INDEX b/Documentation/filesystems/nfs/00-INDEX index 66eb6c8c533451..53f3b596ac0dd9 100644 --- a/Documentation/filesystems/nfs/00-INDEX +++ b/Documentation/filesystems/nfs/00-INDEX @@ -12,6 +12,8 @@ nfs41-server.txt - info on the Linux server implementation of NFSv4 minor version 1. nfs-rdma.txt - how to install and setup the Linux NFS/RDMA client and server software +nfsd-admin-interfaces.txt + - Administrative interfaces for nfsd. nfsroot.txt - short guide on setting up a diskless box with NFS root filesystem. pnfs.txt @@ -20,5 +22,5 @@ rpc-cache.txt - introduction to the caching mechanisms in the sunrpc layer. idmapper.txt - information for configuring request-keys to be used by idmapper -knfsd-rpcgss.txt +rpc-server-gss.txt - Information on GSS authentication support in the NFS Server diff --git a/Documentation/filesystems/nfs/nfs41-server.txt b/Documentation/filesystems/nfs/nfs41-server.txt index 01c2db76979183..b930ad08778000 100644 --- a/Documentation/filesystems/nfs/nfs41-server.txt +++ b/Documentation/filesystems/nfs/nfs41-server.txt @@ -5,11 +5,11 @@ Server support for minorversion 1 can be controlled using the by reading this file will contain either "+4.1" or "-4.1" correspondingly. -Currently, server support for minorversion 1 is disabled by default. -It can be enabled at run time by writing the string "+4.1" to +Currently, server support for minorversion 1 is enabled by default. +It can be disabled at run time by writing the string "-4.1" to the /proc/fs/nfsd/versions control file. Note that to write this -control file, the nfsd service must be taken down. Use your user-mode -nfs-utils to set this up; see rpc.nfsd(8) +control file, the nfsd service must be taken down. You can use rpc.nfsd +for this; see rpc.nfsd(8). (Warning: older servers will interpret "+4.1" and "-4.1" as "+4" and "-4", respectively. Therefore, code meant to work on both new and old @@ -29,29 +29,6 @@ are still under development out of tree. See http://wiki.linux-nfs.org/wiki/index.php/PNFS_prototype_design for more information. -The current implementation is intended for developers only: while it -does support ordinary file operations on clients we have tested against -(including the linux client), it is incomplete in ways which may limit -features unexpectedly, cause known bugs in rare cases, or cause -interoperability problems with future clients. Known issues: - - - gss support is questionable: currently mounts with kerberos - from a linux client are possible, but we aren't really - conformant with the spec (for example, we don't use kerberos - on the backchannel correctly). - - We do not support SSV, which provides security for shared - client-server state (thus preventing unauthorized tampering - with locks and opens, for example). It is mandatory for - servers to support this, though no clients use it yet. - -In addition, some limitations are inherited from the current NFSv4 -implementation: - - - Incomplete delegation enforcement: if a file is renamed or - unlinked by a local process, a client holding a delegation may - continue to indefinitely allow opens of the file under the old - name. - The table below, taken from the NFSv4.1 document, lists the operations that are mandatory to implement (REQ), optional (OPT), and NFSv4.0 operations that are required not to implement (MNI) @@ -169,6 +146,16 @@ NS*| CB_WANTS_CANCELLED | OPT | FDELG, | Section 20.10 | Implementation notes: +SSV: +* The spec claims this is mandatory, but we don't actually know of any + implementations, so we're ignoring it for now. The server returns + NFS4ERR_ENCR_ALG_UNSUPP on EXCHANGE_ID, which should be future-proof. + +GSS on the backchannel: +* Again, theoretically required but not widely implemented (in + particular, the current Linux client doesn't request it). We return + NFS4ERR_ENCR_ALG_UNSUPP on CREATE_SESSION. + DELEGPURGE: * mandatory only for servers that support CLAIM_DELEGATE_PREV and/or CLAIM_DELEG_PREV_FH (which allows clients to keep delegations that @@ -176,7 +163,6 @@ DELEGPURGE: now. EXCHANGE_ID: -* only SP4_NONE state protection supported * implementation ids are ignored CREATE_SESSION: diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 31f76178c987f1..f00bee144addc5 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -1386,8 +1386,8 @@ may allocate from based on an estimation of its current memory and swap use. For example, if a task is using all allowed memory, its badness score will be 1000. If it is using half of its allowed memory, its score will be 500. -There is an additional factor included in the badness score: root -processes are given 3% extra memory over other tasks. +There is an additional factor included in the badness score: the current memory +and swap usage is discounted by 3% for root processes. The amount of "allowed" memory depends on the context in which the oom killer was called. If it is due to the memory assigned to the allocating task's cpuset diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index deb48b5fd88327..c53784c119c8ea 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -782,7 +782,7 @@ struct file_operations ---------------------- This describes how the VFS can manipulate an open file. As of kernel -3.5, the following members are defined: +3.12, the following members are defined: struct file_operations { struct module *owner; @@ -803,9 +803,6 @@ struct file_operations { int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); - ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); - ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); - ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int (*check_flags)(int); @@ -814,6 +811,7 @@ struct file_operations { ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int); int (*setlease)(struct file *, long arg, struct file_lock **); long (*fallocate)(struct file *, int mode, loff_t offset, loff_t len); + int (*show_fdinfo)(struct seq_file *m, struct file *f); }; Again, all methods are called without any locks being held, unless @@ -864,12 +862,6 @@ otherwise noted. lock: called by the fcntl(2) system call for F_GETLK, F_SETLK, and F_SETLKW commands - readv: called by the readv(2) system call - - writev: called by the writev(2) system call - - sendfile: called by the sendfile(2) system call - get_unmapped_area: called by the mmap(2) system call check_flags: called by the fcntl(2) system call for F_SETFL command diff --git a/Documentation/hwmon/adm1025 b/Documentation/hwmon/adm1025 index 39d2b781b5d614..99f05049c68a89 100644 --- a/Documentation/hwmon/adm1025 +++ b/Documentation/hwmon/adm1025 @@ -18,7 +18,7 @@ The NE1619 presents some differences with the original ADM1025: Authors: Chen-Yuan Wu , - Jean Delvare + Jean Delvare Description ----------- diff --git a/Documentation/hwmon/adm1031 b/Documentation/hwmon/adm1031 index be92a77da1d511..a143117c99cb3d 100644 --- a/Documentation/hwmon/adm1031 +++ b/Documentation/hwmon/adm1031 @@ -16,7 +16,7 @@ Supported chips: Authors: Alexandre d'Alton - Jean Delvare + Jean Delvare Description ----------- diff --git a/Documentation/hwmon/adm9240 b/Documentation/hwmon/adm9240 index 36e8ec6aa868c1..9b174fc700cce8 100644 --- a/Documentation/hwmon/adm9240 +++ b/Documentation/hwmon/adm9240 @@ -25,7 +25,7 @@ Authors: Philip Edelbrock , Michiel Rook , Grant Coady with guidance - from Jean Delvare + from Jean Delvare Interface --------- diff --git a/Documentation/hwmon/ds1621 b/Documentation/hwmon/ds1621 index 896cdc972ca8ed..f775e612f5820a 100644 --- a/Documentation/hwmon/ds1621 +++ b/Documentation/hwmon/ds1621 @@ -31,7 +31,7 @@ Authors: Christian W. Zuckschwerdt valuable contributions by Jan M. Sendler ported to 2.6 by Aurelien Jarno - with the help of Jean Delvare + with the help of Jean Delvare Module Parameters ------------------ diff --git a/Documentation/hwmon/emc6w201 b/Documentation/hwmon/emc6w201 index 32f355aaf56b6b..757629b128978d 100644 --- a/Documentation/hwmon/emc6w201 +++ b/Documentation/hwmon/emc6w201 @@ -7,7 +7,7 @@ Supported chips: Addresses scanned: I2C 0x2c, 0x2d, 0x2e Datasheet: Not public -Author: Jean Delvare +Author: Jean Delvare Description diff --git a/Documentation/hwmon/f71805f b/Documentation/hwmon/f71805f index f0d55976740adf..48a356084bc671 100644 --- a/Documentation/hwmon/f71805f +++ b/Documentation/hwmon/f71805f @@ -15,7 +15,7 @@ Supported chips: Addresses scanned: none, address read from Super I/O config space Datasheet: Available from the Fintek website -Author: Jean Delvare +Author: Jean Delvare Thanks to Denis Kieft from Barracuda Networks for the donation of a test system (custom Jetway K8M8MS motherboard, with CPU and RAM) and diff --git a/Documentation/hwmon/gl518sm b/Documentation/hwmon/gl518sm index 26f9f3c02dc7e6..494bb55b6e7261 100644 --- a/Documentation/hwmon/gl518sm +++ b/Documentation/hwmon/gl518sm @@ -14,7 +14,7 @@ Authors: Frodo Looijaard , Kyösti Mälkki Hong-Gunn Chew - Jean Delvare + Jean Delvare Description ----------- diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index c263740f0cba83..0c1635082c9951 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 @@ -2,6 +2,10 @@ Kernel driver it87 ================== Supported chips: + * IT8603E + Prefix: 'it8603' + Addresses scanned: from Super I/O config space (8 I/O ports) + Datasheet: Not publicly available * IT8705F Prefix: 'it87' Addresses scanned: from Super I/O config space (8 I/O ports) @@ -53,7 +57,7 @@ Supported chips: Authors: Christophe Gauthron - Jean Delvare + Jean Delvare Module Parameters @@ -90,7 +94,7 @@ motherboard models. Description ----------- -This driver implements support for the IT8705F, IT8712F, IT8716F, +This driver implements support for the IT8603E, IT8705F, IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8771E, IT8772E, IT8782F, IT8783E/F, and SiS950 chips. @@ -129,6 +133,10 @@ to userspace applications. The IT8728F, IT8771E, and IT8772E are considered compatible with the IT8721F, until a datasheet becomes available (hopefully.) +The IT8603E is a custom design, hardware monitoring part is similar to +IT8728F. It only supports 16-bit fan mode, the full speed mode of the +fan is not supported (value 0 of pwmX_enable). + Temperatures are measured in degrees Celsius. An alarm is triggered once when the Overtemperature Shutdown limit is crossed. @@ -145,13 +153,16 @@ alarm is triggered if the voltage has crossed a programmable minimum or maximum limit. Note that minimum in this case always means 'closest to zero'; this is important for negative voltage measurements. All voltage inputs can measure voltages between 0 and 4.08 volts, with a resolution of -0.016 volt (except IT8721F/IT8758E and IT8728F: 0.012 volt.) The battery -voltage in8 does not have limit registers. - -On the IT8721F/IT8758E, IT8782F, and IT8783E/F, some voltage inputs are -internal and scaled inside the chip (in7 (optional for IT8782F and IT8783E/F), -in8 and optionally in3). The driver handles this transparently so user-space -doesn't have to care. +0.016 volt (except IT8603E, IT8721F/IT8758E and IT8728F: 0.012 volt.) The +battery voltage in8 does not have limit registers. + +On the IT8603E, IT8721F/IT8758E, IT8782F, and IT8783E/F, some voltage inputs +are internal and scaled inside the chip: +* in3 (optional) +* in7 (optional for IT8782F and IT8783E/F) +* in8 (always) +* in9 (relevant for IT8603E only) +The driver handles this transparently so user-space doesn't have to care. The VID lines (IT8712F/IT8716F/IT8718F/IT8720F) encode the core voltage value: the voltage level your processor should work with. This is hardcoded by diff --git a/Documentation/hwmon/lm63 b/Documentation/hwmon/lm63 index 4d30d209881a28..4a00461512a61e 100644 --- a/Documentation/hwmon/lm63 +++ b/Documentation/hwmon/lm63 @@ -18,7 +18,7 @@ Supported chips: Datasheet: Publicly available at the National Semiconductor website http://www.national.com/pf/LM/LM96163.html -Author: Jean Delvare +Author: Jean Delvare Thanks go to Tyan and especially Alex Buckingham for setting up a remote access to their S4882 test platform for this driver. diff --git a/Documentation/hwmon/lm70 b/Documentation/hwmon/lm70 index 86d182942c5149..1bb2db4406717e 100644 --- a/Documentation/hwmon/lm70 +++ b/Documentation/hwmon/lm70 @@ -43,5 +43,5 @@ data (0.03125 degrees celsius resolution). Thanks to --------- -Jean Delvare for mentoring the hwmon-side driver +Jean Delvare for mentoring the hwmon-side driver development. diff --git a/Documentation/hwmon/lm78 b/Documentation/hwmon/lm78 index 2bdc881a0c1238..4dd47731789f1b 100644 --- a/Documentation/hwmon/lm78 +++ b/Documentation/hwmon/lm78 @@ -14,7 +14,7 @@ Supported chips: http://www.national.com/ Authors: Frodo Looijaard - Jean Delvare + Jean Delvare Description ----------- diff --git a/Documentation/hwmon/lm83 b/Documentation/hwmon/lm83 index a04d1fe9269cc9..50be5cb26de930 100644 --- a/Documentation/hwmon/lm83 +++ b/Documentation/hwmon/lm83 @@ -13,7 +13,7 @@ Supported chips: http://www.national.com/pf/LM/LM82.html -Author: Jean Delvare +Author: Jean Delvare Description ----------- diff --git a/Documentation/hwmon/lm87 b/Documentation/hwmon/lm87 index 6b47b67fd968e8..a2339fd9acb970 100644 --- a/Documentation/hwmon/lm87 +++ b/Documentation/hwmon/lm87 @@ -17,7 +17,7 @@ Authors: Mark Studebaker , Stephen Rousset , Dan Eaton , - Jean Delvare , + Jean Delvare , Original 2.6 port Jeff Oliver Description diff --git a/Documentation/hwmon/lm90 b/Documentation/hwmon/lm90 index ab81013cc3907a..8122675d30f627 100644 --- a/Documentation/hwmon/lm90 +++ b/Documentation/hwmon/lm90 @@ -129,7 +129,7 @@ Supported chips: http://www.ti.com/litv/pdf/sbos686 -Author: Jean Delvare +Author: Jean Delvare Description diff --git a/Documentation/hwmon/lm92 b/Documentation/hwmon/lm92 index 7705bfaa070856..22f68ad032cf98 100644 --- a/Documentation/hwmon/lm92 +++ b/Documentation/hwmon/lm92 @@ -19,7 +19,7 @@ Supported chips: Authors: Abraham van der Merwe - Jean Delvare + Jean Delvare Description diff --git a/Documentation/hwmon/max1619 b/Documentation/hwmon/max1619 index e6d87398cc8f01..518bae3a80c472 100644 --- a/Documentation/hwmon/max1619 +++ b/Documentation/hwmon/max1619 @@ -10,7 +10,7 @@ Supported chips: Authors: Oleksij Rempel , - Jean Delvare + Jean Delvare Description ----------- diff --git a/Documentation/hwmon/pc87360 b/Documentation/hwmon/pc87360 index cbac32b59c8c96..d5f5cf16ce5987 100644 --- a/Documentation/hwmon/pc87360 +++ b/Documentation/hwmon/pc87360 @@ -7,7 +7,7 @@ Supported chips: Addresses scanned: none, address read from Super I/O config space Datasheets: No longer available -Authors: Jean Delvare +Authors: Jean Delvare Thanks to Sandeep Mehta, Tonko de Rooy and Daniel Ceregatti for testing. Thanks to Rudolf Marek for helping me investigate conversion issues. diff --git a/Documentation/hwmon/pc87427 b/Documentation/hwmon/pc87427 index 8fdd08c9e48b5c..c313eb66e08adb 100644 --- a/Documentation/hwmon/pc87427 +++ b/Documentation/hwmon/pc87427 @@ -7,7 +7,7 @@ Supported chips: Addresses scanned: none, address read from Super I/O config space Datasheet: No longer available -Author: Jean Delvare +Author: Jean Delvare Thanks to Amir Habibi at Candelis for setting up a test system, and to Michael Kress for testing several iterations of this driver. diff --git a/Documentation/hwmon/pcf8591 b/Documentation/hwmon/pcf8591 index ac020b3bb7b376..447c0702c0ecbf 100644 --- a/Documentation/hwmon/pcf8591 +++ b/Documentation/hwmon/pcf8591 @@ -11,7 +11,7 @@ Supported chips: Authors: Aurelien Jarno valuable contributions by Jan M. Sendler , - Jean Delvare + Jean Delvare Description diff --git a/Documentation/hwmon/smsc47m1 b/Documentation/hwmon/smsc47m1 index 2a13378dcf2213..10a24b42068636 100644 --- a/Documentation/hwmon/smsc47m1 +++ b/Documentation/hwmon/smsc47m1 @@ -25,7 +25,7 @@ Authors: With assistance from Bruce Allen , and his fan.c program: http://www.lsc-group.phys.uwm.edu/%7Eballen/driver/ Gabriele Gorla , - Jean Delvare + Jean Delvare Description ----------- diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf index ceaf6f652b0066..735c42a85eadca 100644 --- a/Documentation/hwmon/w83627ehf +++ b/Documentation/hwmon/w83627ehf @@ -36,7 +36,7 @@ Supported chips: Datasheet: Available from Nuvoton upon request Authors: - Jean Delvare + Jean Delvare Yuan Mu (Winbond) Rudolf Marek David Hubbard diff --git a/Documentation/hwmon/w83795 b/Documentation/hwmon/w83795 index 9f160371f463db..d3e678216b9adb 100644 --- a/Documentation/hwmon/w83795 +++ b/Documentation/hwmon/w83795 @@ -13,7 +13,7 @@ Supported chips: Authors: Wei Song (Nuvoton) - Jean Delvare + Jean Delvare Pin mapping diff --git a/Documentation/hwmon/w83l785ts b/Documentation/hwmon/w83l785ts index bd1fa9d4468d9b..c8978478871f27 100644 --- a/Documentation/hwmon/w83l785ts +++ b/Documentation/hwmon/w83l785ts @@ -9,7 +9,7 @@ Supported chips: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf Authors: - Jean Delvare + Jean Delvare Description ----------- diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 index 7b0dcdb57173ce..aaaf069306a3ec 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -33,7 +33,7 @@ and the additional 'Integrated Device Function' controllers are supported. Authors: Mark Studebaker - Jean Delvare + Jean Delvare Module Parameters diff --git a/Documentation/i2c/busses/i2c-parport b/Documentation/i2c/busses/i2c-parport index 2461c7b53b2c1e..0e2d17b460fddc 100644 --- a/Documentation/i2c/busses/i2c-parport +++ b/Documentation/i2c/busses/i2c-parport @@ -1,6 +1,6 @@ Kernel driver i2c-parport -Author: Jean Delvare +Author: Jean Delvare This is a unified driver for several i2c-over-parallel-port adapters, such as the ones made by Philips, Velleman or ELV. This driver is diff --git a/Documentation/i2c/busses/i2c-parport-light b/Documentation/i2c/busses/i2c-parport-light index c22ee063e1e52e..7071b8ba0af4c8 100644 --- a/Documentation/i2c/busses/i2c-parport-light +++ b/Documentation/i2c/busses/i2c-parport-light @@ -1,6 +1,6 @@ Kernel driver i2c-parport-light -Author: Jean Delvare +Author: Jean Delvare This driver is a light version of i2c-parport. It doesn't depend on the parport driver, and uses direct I/O access instead. This might be diff --git a/Documentation/i2c/busses/i2c-piix4 b/Documentation/i2c/busses/i2c-piix4 index c097e0f020fe1d..aa959fd22450de 100644 --- a/Documentation/i2c/busses/i2c-piix4 +++ b/Documentation/i2c/busses/i2c-piix4 @@ -13,7 +13,7 @@ Supported adapters: * AMD SP5100 (SB700 derivative found on some server mainboards) Datasheet: Publicly available at the AMD website http://support.amd.com/us/Embedded_TechDocs/44413.pdf - * AMD Hudson-2, CZ + * AMD Hudson-2, ML, CZ Datasheet: Not publicly available * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge Datasheet: Publicly available at the SMSC website http://www.smsc.com diff --git a/Documentation/i2c/busses/i2c-taos-evm b/Documentation/i2c/busses/i2c-taos-evm index 63f62bcbf59200..60299555dcf01f 100644 --- a/Documentation/i2c/busses/i2c-taos-evm +++ b/Documentation/i2c/busses/i2c-taos-evm @@ -1,6 +1,6 @@ Kernel driver i2c-taos-evm -Author: Jean Delvare +Author: Jean Delvare This is a driver for the evaluation modules for TAOS I2C/SMBus chips. The modules include an SMBus master with limited capabilities, which can diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro index b88f91ae580ef5..ab64ce21c25442 100644 --- a/Documentation/i2c/busses/i2c-viapro +++ b/Documentation/i2c/busses/i2c-viapro @@ -28,7 +28,7 @@ Supported adapters: Authors: Kyösti Mälkki , Mark D. Studebaker , - Jean Delvare + Jean Delvare Module Parameters ----------------- diff --git a/Documentation/i2c/instantiating-devices b/Documentation/i2c/instantiating-devices index c70e7a7638d1e6..0d85ac1935b73a 100644 --- a/Documentation/i2c/instantiating-devices +++ b/Documentation/i2c/instantiating-devices @@ -8,8 +8,8 @@ reason, the kernel code must instantiate I2C devices explicitly. There are several ways to achieve this, depending on the context and requirements. -Method 1: Declare the I2C devices by bus number ------------------------------------------------ +Method 1a: Declare the I2C devices by bus number +------------------------------------------------ This method is appropriate when the I2C bus is a system bus as is the case for many embedded systems. On such systems, each I2C bus has a number @@ -51,6 +51,43 @@ The devices will be automatically unbound and destroyed when the I2C bus they sit on goes away (if ever.) +Method 1b: Declare the I2C devices via devicetree +------------------------------------------------- + +This method has the same implications as method 1a. The declaration of I2C +devices is here done via devicetree as subnodes of the master controller. + +Example: + + i2c1: i2c@400a0000 { + /* ... master properties skipped ... */ + clock-frequency = <100000>; + + flash@50 { + compatible = "atmel,24c256"; + reg = <0x50>; + }; + + pca9532: gpio@60 { + compatible = "nxp,pca9532"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x60>; + }; + }; + +Here, two devices are attached to the bus using a speed of 100kHz. For +additional properties which might be needed to set up the device, please refer +to its devicetree documentation in Documentation/devicetree/bindings/. + + +Method 1c: Declare the I2C devices via ACPI +------------------------------------------- + +ACPI can also describe I2C devices. There is special documentation for this +which is currently located at Documentation/acpi/enumeration.txt. + + Method 2: Instantiate the devices explicitly -------------------------------------------- diff --git a/Documentation/ide/00-INDEX b/Documentation/ide/00-INDEX index d6b778842b754c..22f98ca79539d5 100644 --- a/Documentation/ide/00-INDEX +++ b/Documentation/ide/00-INDEX @@ -10,3 +10,5 @@ ide-tape.txt - info on the IDE ATAPI streaming tape driver ide.txt - important info for users of ATA devices (IDE/EIDE disks and CD-ROMS). +warm-plug-howto.txt + - using sysfs to remove and add IDE devices. \ No newline at end of file diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 7cbfa3c4fc3d32..d7e43fa88575b1 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -73,6 +73,7 @@ Code Seq#(hex) Include File Comments 0x09 all linux/raid/md_u.h 0x10 00-0F drivers/char/s390/vmcp.h 0x10 10-1F arch/s390/include/uapi/sclp_ctl.h +0x10 20-2F arch/s390/include/uapi/asm/hypfs.h 0x12 all linux/fs.h linux/blkpg.h 0x1b all InfiniBand Subsystem diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index be6ba33d4ff1ae..7116fda7077ffc 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1726,16 +1726,16 @@ bytes respectively. Such letter suffixes can also be entirely omitted. option description. memmap=nn[KMG]@ss[KMG] - [KNL] Force usage of a specific region of memory - Region of memory to be used, from ss to ss+nn. + [KNL] Force usage of a specific region of memory. + Region of memory to be used is from ss to ss+nn. memmap=nn[KMG]#ss[KMG] [KNL,ACPI] Mark specific memory as ACPI data. - Region of memory to be used, from ss to ss+nn. + Region of memory to be marked is from ss to ss+nn. memmap=nn[KMG]$ss[KMG] [KNL,ACPI] Mark specific memory as reserved. - Region of memory to be used, from ss to ss+nn. + Region of memory to be reserved is from ss to ss+nn. Example: Exclude memory from 0x18690000-0x1869ffff memmap=64K$0x18690000 or @@ -3124,7 +3124,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. controller if no parameter or 1 is given or disable it if 0 is given (See Documentation/cgroups/memory.txt) - swiotlb= [IA-64] Number of I/O TLB slabs + swiotlb= [ARM,IA-64,PPC,MIPS,X86] + Format: { | force } + -- Number of I/O TLB slabs + force -- force using of bounce buffers even if they + wouldn't be automatically used by the kernel switches= [HW,M68k] diff --git a/Documentation/kmsg/s390/zcrypt b/Documentation/kmsg/s390/zcrypt deleted file mode 100644 index 7fb2087409d6d1..00000000000000 --- a/Documentation/kmsg/s390/zcrypt +++ /dev/null @@ -1,20 +0,0 @@ -/*? - * Text: "Cryptographic device %x failed and was set offline\n" - * Severity: Error - * Parameter: - * @1: device index - * Description: - * A cryptographic device failed to process a cryptographic request. - * The cryptographic device driver could not correct the error and - * set the device offline. The application that issued the - * request received an indication that the request has failed. - * User action: - * Use the lszcrypt command to confirm that the cryptographic - * hardware is still configured to your LPAR or z/VM guest virtual - * machine. If the device is available to your Linux instance the - * command output contains a line that begins with 'card', - * where is the two-digit decimal number in the message text. - * After ensuring that the device is available, use the chzcrypt command to - * set it online again. - * If the error persists, contact your support organization. - */ diff --git a/Documentation/laptops/00-INDEX b/Documentation/laptops/00-INDEX index fa688538e757e9..d13b9a9a9e0029 100644 --- a/Documentation/laptops/00-INDEX +++ b/Documentation/laptops/00-INDEX @@ -1,13 +1,15 @@ 00-INDEX - This file -acer-wmi.txt - - information on the Acer Laptop WMI Extras driver. +Makefile + - Makefile for building dslm example program. asus-laptop.txt - information on the Asus Laptop Extras driver. disk-shock-protection.txt - information on hard disk shock protection. dslm.c - Simple Disk Sleep Monitor program +hpfall.c + - (HP) laptop accelerometer program for disk protection. laptop-mode.txt - how to conserve battery power using laptop-mode. sony-laptop.txt diff --git a/Documentation/leds/00-INDEX b/Documentation/leds/00-INDEX index 1ecd1596633e58..b4ef1f34e25faa 100644 --- a/Documentation/leds/00-INDEX +++ b/Documentation/leds/00-INDEX @@ -1,3 +1,7 @@ +00-INDEX + - This file +leds-blinkm.txt + - Driver for BlinkM LED-devices. leds-class.txt - documents LED handling under Linux. leds-lp3944.txt @@ -12,3 +16,7 @@ leds-lp55xx.txt - description about lp55xx common driver. leds-lm3556.txt - notes on how to use the leds-lm3556 driver. +ledtrig-oneshot.txt + - One-shot LED trigger for both sporadic and dense events. +ledtrig-transient.txt + - LED Transient Trigger, one shot timer activation. diff --git a/Documentation/leds/leds-lp55xx.txt b/Documentation/leds/leds-lp55xx.txt index 82713ff92eb3e5..bcea12a0c5847e 100644 --- a/Documentation/leds/leds-lp55xx.txt +++ b/Documentation/leds/leds-lp55xx.txt @@ -73,6 +73,10 @@ select_engine : Select which engine is used for running program run_engine : Start program which is loaded via the firmware interface firmware : Load program data +In case of LP5523, one more command is required, 'enginex_leds'. +It is used for selecting LED output(s) at each engine number. +In more details, please refer to 'leds-lp5523.txt'. + For example, run blinking pattern in engine #1 of LP5521 echo 1 > /sys/bus/i2c/devices/xxxx/select_engine echo 1 > /sys/class/firmware/lp5521/loading @@ -81,10 +85,12 @@ echo 0 > /sys/class/firmware/lp5521/loading echo 1 > /sys/bus/i2c/devices/xxxx/run_engine For example, run blinking pattern in engine #3 of LP55231 +Two LEDs are configured as pattern output channels. echo 3 > /sys/bus/i2c/devices/xxxx/select_engine echo 1 > /sys/class/firmware/lp55231/loading echo "9d0740ff7e0040007e00a0010000" > /sys/class/firmware/lp55231/data echo 0 > /sys/class/firmware/lp55231/loading +echo "000001100" > /sys/bus/i2c/devices/xxxx/engine3_leds echo 1 > /sys/bus/i2c/devices/xxxx/run_engine To start blinking patterns in engine #2 and #3 simultaneously, @@ -99,17 +105,19 @@ done echo 1 > /sys/class/leds/red/device/run_engine Here is another example for LP5523. +Full LED strings are selected by 'engine2_leds'. echo 2 > /sys/bus/i2c/devices/xxxx/select_engine echo 1 > /sys/class/firmware/lp5523/loading echo "9d80400004ff05ff437f0000" > /sys/class/firmware/lp5523/data echo 0 > /sys/class/firmware/lp5523/loading +echo "111111111" > /sys/bus/i2c/devices/xxxx/engine2_leds echo 1 > /sys/bus/i2c/devices/xxxx/run_engine As soon as 'loading' is set to 0, registered callback is called. Inside the callback, the selected engine is loaded and memory is updated. To run programmed pattern, 'run_engine' attribute should be enabled. -The pattern sqeuence of LP8501 is same as LP5523. +The pattern sqeuence of LP8501 is similar to LP5523. However pattern data is specific. Ex 1) Engine 1 is used echo 1 > /sys/bus/i2c/devices/xxxx/select_engine diff --git a/Documentation/m68k/00-INDEX b/Documentation/m68k/00-INDEX index a014e9f0076511..2be8c6b00e7464 100644 --- a/Documentation/m68k/00-INDEX +++ b/Documentation/m68k/00-INDEX @@ -1,5 +1,7 @@ 00-INDEX - this file +README.buddha + - Amiga Buddha and Catweasel IDE Driver kernel-options.txt - command line options for Linux/m68k diff --git a/Documentation/misc-devices/eeprom b/Documentation/misc-devices/eeprom index f7e8104b5764fa..ba692011f22133 100644 --- a/Documentation/misc-devices/eeprom +++ b/Documentation/misc-devices/eeprom @@ -38,7 +38,7 @@ Supported chips: Authors: Frodo Looijaard , Philip Edelbrock , - Jean Delvare , + Jean Delvare , Greg Kroah-Hartman , IBM Corp. diff --git a/Documentation/mtd/nand/pxa3xx-nand.txt b/Documentation/mtd/nand/pxa3xx-nand.txt new file mode 100644 index 00000000000000..840fd41c181b98 --- /dev/null +++ b/Documentation/mtd/nand/pxa3xx-nand.txt @@ -0,0 +1,113 @@ + +About this document +=================== + +Some notes about Marvell's NAND controller available in PXA and Armada 370/XP +SoC (aka NFCv1 and NFCv2), with an emphasis on the latter. + +NFCv2 controller background +=========================== + +The controller has a 2176 bytes FIFO buffer. Therefore, in order to support +larger pages, I/O operations on 4 KiB and 8 KiB pages is done with a set of +chunked transfers. + +For instance, if we choose a 2048 data chunk and set "BCH" ECC (see below) +we'll have this layout in the pages: + + ------------------------------------------------------------------------------ + | 2048B data | 32B spare | 30B ECC || 2048B data | 32B spare | 30B ECC | ... | + ------------------------------------------------------------------------------ + +The driver reads the data and spare portions independently and builds an internal +buffer with this layout (in the 4 KiB page case): + + ------------------------------------------ + | 4096B data | 64B spare | + ------------------------------------------ + +Also, for the READOOB command the driver disables the ECC and reads a 'spare + ECC' +OOB, one per chunk read. + + ------------------------------------------------------------------- + | 4096B data | 32B spare | 30B ECC | 32B spare | 30B ECC | + ------------------------------------------------------------------- + +So, in order to achieve reading (for instance), we issue several READ0 commands +(with some additional controller-specific magic) and read two chunks of 2080B +(2048 data + 32 spare) each. +The driver accommodates this data to expose the NAND core a contiguous buffer +(4096 data + spare) or (4096 + spare + ECC + spare + ECC). + +ECC +=== + +The controller has built-in hardware ECC capabilities. In addition it is +configurable between two modes: 1) Hamming, 2) BCH. + +Note that the actual BCH mode: BCH-4 or BCH-8 will depend on the way +the controller is configured to transfer the data. + +In the BCH mode the ECC code will be calculated for each transfered chunk +and expected to be located (when reading/programming) right after the spare +bytes as the figure above shows. + +So, repeating the above scheme, a 2048B data chunk will be followed by 32B +spare, and then the ECC controller will read/write the ECC code (30B in +this case): + + ------------------------------------ + | 2048B data | 32B spare | 30B ECC | + ------------------------------------ + +If the ECC mode is 'BCH' then the ECC is *always* 30 bytes long. +If the ECC mode is 'Hamming' the ECC is 6 bytes long, for each 512B block. +So in Hamming mode, a 2048B page will have a 24B ECC. + +Despite all of the above, the controller requires the driver to only read or +write in multiples of 8-bytes, because the data buffer is 64-bits. + +OOB +=== + +Because of the above scheme, and because the "spare" OOB is really located in +the middle of a page, spare OOB cannot be read or write independently of the +data area. In other words, in order to read the OOB (aka READOOB), the entire +page (aka READ0) has to be read. + +In the same sense, in order to write to the spare OOB the driver has to write +an *entire* page. + +Factory bad blocks handling +=========================== + +Given the ECC BCH requires to layout the device's pages in a split +data/OOB/data/OOB way, the controller has a view of the flash page that's +different from the specified (aka the manufacturer's) view. In other words, + +Factory view: + + ----------------------------------------------- + | Data |x OOB | + ----------------------------------------------- + +Driver's view: + + ----------------------------------------------- + | Data | OOB | Data x | OOB | + ----------------------------------------------- + +It can be seen from the above, that the factory bad block marker must be +searched within the 'data' region, and not in the usual OOB region. + +In addition, this means under regular usage the driver will write such +position (since it belongs to the data region) and every used block is +likely to be marked as bad. + +For this reason, marking the block as bad in the OOB is explicitly +disabled by using the NAND_BBT_NO_OOB_BBM option in the driver. The rationale +for this is that there's no point in marking a block as bad, because good +blocks are also 'marked as bad' (in the OOB BBM sense) under normal usage. + +Instead, the driver relies on the bad block table alone, and should only perform +the bad block scan on the very first time (when the device hasn't been used). diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX index f11580f8719a0c..557b6ef70c265d 100644 --- a/Documentation/networking/00-INDEX +++ b/Documentation/networking/00-INDEX @@ -6,8 +6,14 @@ - information on the 3Com Etherlink III Series Ethernet cards. 6pack.txt - info on the 6pack protocol, an alternative to KISS for AX.25 -DLINK.txt - - info on the D-Link DE-600/DE-620 parallel port pocket adapters +LICENSE.qla3xxx + - GPLv2 for QLogic Linux Networking HBA Driver +LICENSE.qlge + - GPLv2 for QLogic Linux qlge NIC Driver +LICENSE.qlcnic + - GPLv2 for QLogic Linux qlcnic NIC Driver +Makefile + - Makefile for docsrc. PLIP.txt - PLIP: The Parallel Line Internet Protocol device driver README.ipw2100 @@ -17,7 +23,7 @@ README.ipw2200 README.sb1000 - info on General Instrument/NextLevel SURFboard1000 cable modem. alias.txt - - info on using alias network devices + - info on using alias network devices. arcnet-hardware.txt - tons of info on ARCnet, hubs, jumper settings for ARCnet cards, etc. arcnet.txt @@ -80,7 +86,7 @@ framerelay.txt - info on using Frame Relay/Data Link Connection Identifier (DLCI). gen_stats.txt - Generic networking statistics for netlink users. -generic_hdlc.txt +generic-hdlc.txt - The generic High Level Data Link Control (HDLC) layer. generic_netlink.txt - info on Generic Netlink @@ -88,6 +94,8 @@ gianfar.txt - Gianfar Ethernet Driver. i40e.txt - README for the Intel Ethernet Controller XL710 Driver (i40e). +i40evf.txt + - Short note on the Driver for the Intel(R) XL710 X710 Virtual Function ieee802154.txt - Linux IEEE 802.15.4 implementation, API and drivers igb.txt @@ -102,6 +110,8 @@ ipddp.txt - AppleTalk-IP Decapsulation and AppleTalk-IP Encapsulation iphase.txt - Interphase PCI ATM (i)Chip IA Linux driver info. +ipsec.txt + - Note on not compressing IPSec payload and resulting failed policy check. ipv6.txt - Options to the ipv6 kernel module. ipvs-sysctl.txt @@ -120,6 +130,8 @@ lapb-module.txt - programming information of the LAPB module. ltpc.txt - the Apple or Farallon LocalTalk PC card driver +mac80211-auth-assoc-deauth.txt + - authentication and association / deauth-disassoc with max80211 mac80211-injection.txt - HOWTO use packet injection with mac80211 multiqueue.txt @@ -134,6 +146,10 @@ netdevices.txt - info on network device driver functions exported to the kernel. netif-msg.txt - Design of the network interface message level setting (NETIF_MSG_*). +netlink_mmap.txt + - memory mapped I/O with netlink +nf_conntrack-sysctl.txt + - list of netfilter-sysctl knobs. nfc.txt - The Linux Near Field Communication (NFS) subsystem. openvswitch.txt @@ -176,7 +192,7 @@ skfp.txt - SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info. smc9.txt - the driver for SMC's 9000 series of Ethernet cards -spider-net.txt +spider_net.txt - README for the Spidernet Driver (as found in PS3 / Cell BE). stmmac.txt - README for the STMicro Synopsys Ethernet driver. @@ -188,6 +204,8 @@ tcp.txt - short blurb on how TCP output takes place. tcp-thin.txt - kernel tuning options for low rate 'thin' TCP streams. +team.txt + - pointer to information for ethernet teaming devices. tlan.txt - ThunderLAN (Compaq Netelligent 10/100, Olicom OC-2xxx) driver info. tproxy.txt @@ -200,6 +218,8 @@ vortex.txt - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards. vxge.txt - README for the Neterion X3100 PCIe Server Adapter. +vxlan.txt + - Virtual extensible LAN overview x25.txt - general info on X.25 development. x25-iface.txt diff --git a/Documentation/networking/3c505.txt b/Documentation/networking/3c505.txt deleted file mode 100644 index 72f38b13101d74..00000000000000 --- a/Documentation/networking/3c505.txt +++ /dev/null @@ -1,45 +0,0 @@ -The 3Com Etherlink Plus (3c505) driver. - -This driver now uses DMA. There is currently no support for PIO operation. -The default DMA channel is 6; this is _not_ autoprobed, so you must -make sure you configure it correctly. If loading the driver as a -module, you can do this with "modprobe 3c505 dma=n". If the driver is -linked statically into the kernel, you must either use an "ether=" -statement on the command line, or change the definition of ELP_DMA in 3c505.h. - -The driver will warn you if it has to fall back on the compiled in -default DMA channel. - -If no base address is given at boot time, the driver will autoprobe -ports 0x300, 0x280 and 0x310 (in that order). If no IRQ is given, the driver -will try to probe for it. - -The driver can be used as a loadable module. - -Theoretically, one instance of the driver can now run multiple cards, -in the standard way (when loading a module, say "modprobe 3c505 -io=0x300,0x340 irq=10,11 dma=6,7" or whatever). I have not tested -this, though. - -The driver may now support revision 2 hardware; the dependency on -being able to read the host control register has been removed. This -is also untested, since I don't have a suitable card. - -Known problems: - I still see "DMA upload timed out" messages from time to time. These -seem to be fairly non-fatal though. - The card is old and slow. - -To do: - Improve probe/setup code - Test multicast and promiscuous operation - -Authors: - The driver is mainly written by Craig Southeren, email - . - Parts of the driver (adapting the driver to 1.1.4+ kernels, - IRQ/address detection, some changes) and this README by - Juha Laiho . - DMA mode, more fixes, etc, by Philip Blundell - Multicard support, Software configurable DMA, etc., by - Christopher Collins diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 5de03740cdd50c..ab42c95f9985c0 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1088,6 +1088,12 @@ igmpv3_unsolicited_report_interval - INTEGER IGMPv3 report retransmit will take place. Default: 1000 (1 seconds) +promote_secondaries - BOOLEAN + When a primary IP address is removed from this interface + promote a corresponding secondary IP address instead of + removing all the corresponding secondary IP addresses. + + tag - INTEGER Allows you to write a number, which can be used as required. Default value is 0. diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt index 91ffe1d9e8cab8..1404674c0a0282 100644 --- a/Documentation/networking/packet_mmap.txt +++ b/Documentation/networking/packet_mmap.txt @@ -583,6 +583,7 @@ Currently implemented fanout policies are: - PACKET_FANOUT_CPU: schedule to socket by CPU packet arrives on - PACKET_FANOUT_RND: schedule to socket by random selection - PACKET_FANOUT_ROLLOVER: if one socket is full, rollover to another + - PACKET_FANOUT_QM: schedule to socket by skbs recorded queue_mapping Minimal example code by David S. Miller (try things like "./test eth0 hash", "./test eth0 lb", etc.): diff --git a/Documentation/phy.txt b/Documentation/phy.txt index 0103e4b15b0ead..ebff6ee52441ed 100644 --- a/Documentation/phy.txt +++ b/Documentation/phy.txt @@ -75,14 +75,26 @@ Before the controller can make use of the PHY, it has to get a reference to it. This framework provides the following APIs to get a reference to the PHY. struct phy *phy_get(struct device *dev, const char *string); +struct phy *phy_optional_get(struct device *dev, const char *string); struct phy *devm_phy_get(struct device *dev, const char *string); - -phy_get and devm_phy_get can be used to get the PHY. In the case of dt boot, -the string arguments should contain the phy name as given in the dt data and -in the case of non-dt boot, it should contain the label of the PHY. -The only difference between the two APIs is that devm_phy_get associates the -device with the PHY using devres on successful PHY get. On driver detach, -release function is invoked on the the devres data and devres data is freed. +struct phy *devm_phy_optional_get(struct device *dev, const char *string); + +phy_get, phy_optional_get, devm_phy_get and devm_phy_optional_get can +be used to get the PHY. In the case of dt boot, the string arguments +should contain the phy name as given in the dt data and in the case of +non-dt boot, it should contain the label of the PHY. The two +devm_phy_get associates the device with the PHY using devres on +successful PHY get. On driver detach, release function is invoked on +the the devres data and devres data is freed. phy_optional_get and +devm_phy_optional_get should be used when the phy is optional. These +two functions will never return -ENODEV, but instead returns NULL when +the phy cannot be found. + +It should be noted that NULL is a valid phy reference. All phy +consumer calls on the NULL phy become NOPs. That is the release calls, +the phy_init() and phy_exit() calls, and phy_power_on() and +phy_power_off() calls are all NOP when applied to a NULL phy. The NULL +phy is useful in devices for handling optional phy devices. 5. Releasing a reference to the PHY diff --git a/Documentation/power/00-INDEX b/Documentation/power/00-INDEX index a4d682f54231d0..ad04cc8097ed97 100644 --- a/Documentation/power/00-INDEX +++ b/Documentation/power/00-INDEX @@ -4,6 +4,8 @@ apm-acpi.txt - basic info about the APM and ACPI support. basic-pm-debugging.txt - Debugging suspend and resume +charger-manager.txt + - Battery charger management. devices.txt - How drivers interact with system-wide power management drivers-testing.txt @@ -22,6 +24,8 @@ pm_qos_interface.txt - info on Linux PM Quality of Service interface power_supply_class.txt - Tells userspace about battery, UPS, AC or DC power supply properties +runtime_pm.txt + - Power management framework for I/O devices. s2ram.txt - How to get suspend to ram working (and debug it when it isn't) states.txt @@ -38,7 +42,5 @@ tricks.txt - How to trick software suspend (to disk) into working when it isn't userland-swsusp.txt - Experimental implementation of software suspend in userspace -video_extension.txt - - ACPI video extensions video.txt - Video issues during resume from suspend diff --git a/Documentation/power/basic-pm-debugging.txt b/Documentation/power/basic-pm-debugging.txt index e9b54de8fdf750..edeecd447d23dc 100644 --- a/Documentation/power/basic-pm-debugging.txt +++ b/Documentation/power/basic-pm-debugging.txt @@ -172,7 +172,7 @@ you can boot the kernel with the 'no_console_suspend' parameter and try to log kernel messages using the serial console. This may provide you with some information about the reasons of the suspend (resume) failure. Alternatively, it may be possible to use a FireWire port for debugging with firescope -(ftp://ftp.firstfloor.org/pub/ak/firescope/). On x86 it is also possible to +(http://v3.sk/~lkundrak/firescope/). On x86 it is also possible to use the PM_TRACE mechanism documented in Documentation/power/s2ram.txt . 2. Testing suspend to RAM (STR) diff --git a/Documentation/ptp/testptp.c b/Documentation/ptp/testptp.c index a74d0a84d329a2..4aba0436da65c3 100644 --- a/Documentation/ptp/testptp.c +++ b/Documentation/ptp/testptp.c @@ -117,6 +117,7 @@ static void usage(char *progname) " -f val adjust the ptp clock frequency by 'val' ppb\n" " -g get the ptp clock time\n" " -h prints this message\n" + " -i val index for event/trigger\n" " -k val measure the time offset between system and phc clock\n" " for 'val' times (Maximum 25)\n" " -p val enable output with a period of 'val' nanoseconds\n" @@ -154,6 +155,7 @@ int main(int argc, char *argv[]) int capabilities = 0; int extts = 0; int gettime = 0; + int index = 0; int oneshot = 0; int pct_offset = 0; int n_samples = 0; @@ -167,7 +169,7 @@ int main(int argc, char *argv[]) progname = strrchr(argv[0], '/'); progname = progname ? 1+progname : argv[0]; - while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghk:p:P:sSt:v"))) { + while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghi:k:p:P:sSt:v"))) { switch (c) { case 'a': oneshot = atoi(optarg); @@ -190,6 +192,9 @@ int main(int argc, char *argv[]) case 'g': gettime = 1; break; + case 'i': + index = atoi(optarg); + break; case 'k': pct_offset = 1; n_samples = atoi(optarg); @@ -301,7 +306,7 @@ int main(int argc, char *argv[]) if (extts) { memset(&extts_request, 0, sizeof(extts_request)); - extts_request.index = 0; + extts_request.index = index; extts_request.flags = PTP_ENABLE_FEATURE; if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) { perror("PTP_EXTTS_REQUEST"); @@ -375,7 +380,7 @@ int main(int argc, char *argv[]) return -1; } memset(&perout_request, 0, sizeof(perout_request)); - perout_request.index = 0; + perout_request.index = index; perout_request.start.sec = ts.tv_sec + 2; perout_request.start.nsec = 0; perout_request.period.sec = 0; diff --git a/Documentation/s390/00-INDEX b/Documentation/s390/00-INDEX index 3a2b96302eccc5..10c874ebdfe529 100644 --- a/Documentation/s390/00-INDEX +++ b/Documentation/s390/00-INDEX @@ -16,11 +16,13 @@ Debugging390.txt - hints for debugging on s390 systems. driver-model.txt - information on s390 devices and the driver model. +kvm.txt + - ioctl calls to /dev/kvm on s390. monreader.txt - information on accessing the z/VM monitor stream from Linux. +qeth.txt + - HiperSockets Bridge Port Support. s390dbf.txt - information on using the s390 debug feature. -TAPE - - information on the driver for channel-attached tapes. -zfcpdump +zfcpdump.txt - information on the s390 SCSI dump tool. diff --git a/Documentation/scheduler/00-INDEX b/Documentation/scheduler/00-INDEX index d2651c47ae27fd..eccf7ad2e7f96b 100644 --- a/Documentation/scheduler/00-INDEX +++ b/Documentation/scheduler/00-INDEX @@ -2,6 +2,8 @@ - this file. sched-arch.txt - CPU Scheduler implementation hints for architecture specific code. +sched-bwc.txt + - CFS bandwidth control overview. sched-design-CFS.txt - goals, design and implementation of the Completely Fair Scheduler. sched-domains.txt @@ -10,5 +12,7 @@ sched-nice-design.txt - How and why the scheduler's nice levels are implemented. sched-rt-group.txt - real-time group scheduling. +sched-deadline.txt + - deadline scheduling. sched-stats.txt - information on schedstats (Linux Scheduler Statistics). diff --git a/Documentation/scheduler/sched-deadline.txt b/Documentation/scheduler/sched-deadline.txt new file mode 100644 index 00000000000000..18adc92a6b3b9e --- /dev/null +++ b/Documentation/scheduler/sched-deadline.txt @@ -0,0 +1,281 @@ + Deadline Task Scheduling + ------------------------ + +CONTENTS +======== + + 0. WARNING + 1. Overview + 2. Scheduling algorithm + 3. Scheduling Real-Time Tasks + 4. Bandwidth management + 4.1 System-wide settings + 4.2 Task interface + 4.3 Default behavior + 5. Tasks CPU affinity + 5.1 SCHED_DEADLINE and cpusets HOWTO + 6. Future plans + + +0. WARNING +========== + + Fiddling with these settings can result in an unpredictable or even unstable + system behavior. As for -rt (group) scheduling, it is assumed that root users + know what they're doing. + + +1. Overview +=========== + + The SCHED_DEADLINE policy contained inside the sched_dl scheduling class is + basically an implementation of the Earliest Deadline First (EDF) scheduling + algorithm, augmented with a mechanism (called Constant Bandwidth Server, CBS) + that makes it possible to isolate the behavior of tasks between each other. + + +2. Scheduling algorithm +================== + + SCHED_DEADLINE uses three parameters, named "runtime", "period", and + "deadline" to schedule tasks. A SCHED_DEADLINE task is guaranteed to receive + "runtime" microseconds of execution time every "period" microseconds, and + these "runtime" microseconds are available within "deadline" microseconds + from the beginning of the period. In order to implement this behaviour, + every time the task wakes up, the scheduler computes a "scheduling deadline" + consistent with the guarantee (using the CBS[2,3] algorithm). Tasks are then + scheduled using EDF[1] on these scheduling deadlines (the task with the + smallest scheduling deadline is selected for execution). Notice that this + guaranteed is respected if a proper "admission control" strategy (see Section + "4. Bandwidth management") is used. + + Summing up, the CBS[2,3] algorithms assigns scheduling deadlines to tasks so + that each task runs for at most its runtime every period, avoiding any + interference between different tasks (bandwidth isolation), while the EDF[1] + algorithm selects the task with the smallest scheduling deadline as the one + to be executed first. Thanks to this feature, also tasks that do not + strictly comply with the "traditional" real-time task model (see Section 3) + can effectively use the new policy. + + In more details, the CBS algorithm assigns scheduling deadlines to + tasks in the following way: + + - Each SCHED_DEADLINE task is characterised by the "runtime", + "deadline", and "period" parameters; + + - The state of the task is described by a "scheduling deadline", and + a "current runtime". These two parameters are initially set to 0; + + - When a SCHED_DEADLINE task wakes up (becomes ready for execution), + the scheduler checks if + + current runtime runtime + ---------------------------------- > ---------------- + scheduling deadline - current time period + + then, if the scheduling deadline is smaller than the current time, or + this condition is verified, the scheduling deadline and the + current budget are re-initialised as + + scheduling deadline = current time + deadline + current runtime = runtime + + otherwise, the scheduling deadline and the current runtime are + left unchanged; + + - When a SCHED_DEADLINE task executes for an amount of time t, its + current runtime is decreased as + + current runtime = current runtime - t + + (technically, the runtime is decreased at every tick, or when the + task is descheduled / preempted); + + - When the current runtime becomes less or equal than 0, the task is + said to be "throttled" (also known as "depleted" in real-time literature) + and cannot be scheduled until its scheduling deadline. The "replenishment + time" for this task (see next item) is set to be equal to the current + value of the scheduling deadline; + + - When the current time is equal to the replenishment time of a + throttled task, the scheduling deadline and the current runtime are + updated as + + scheduling deadline = scheduling deadline + period + current runtime = current runtime + runtime + + +3. Scheduling Real-Time Tasks +============================= + + * BIG FAT WARNING ****************************************************** + * + * This section contains a (not-thorough) summary on classical deadline + * scheduling theory, and how it applies to SCHED_DEADLINE. + * The reader can "safely" skip to Section 4 if only interested in seeing + * how the scheduling policy can be used. Anyway, we strongly recommend + * to come back here and continue reading (once the urge for testing is + * satisfied :P) to be sure of fully understanding all technical details. + ************************************************************************ + + There are no limitations on what kind of task can exploit this new + scheduling discipline, even if it must be said that it is particularly + suited for periodic or sporadic real-time tasks that need guarantees on their + timing behavior, e.g., multimedia, streaming, control applications, etc. + + A typical real-time task is composed of a repetition of computation phases + (task instances, or jobs) which are activated on a periodic or sporadic + fashion. + Each job J_j (where J_j is the j^th job of the task) is characterised by an + arrival time r_j (the time when the job starts), an amount of computation + time c_j needed to finish the job, and a job absolute deadline d_j, which + is the time within which the job should be finished. The maximum execution + time max_j{c_j} is called "Worst Case Execution Time" (WCET) for the task. + A real-time task can be periodic with period P if r_{j+1} = r_j + P, or + sporadic with minimum inter-arrival time P is r_{j+1} >= r_j + P. Finally, + d_j = r_j + D, where D is the task's relative deadline. + + SCHED_DEADLINE can be used to schedule real-time tasks guaranteeing that + the jobs' deadlines of a task are respected. In order to do this, a task + must be scheduled by setting: + + - runtime >= WCET + - deadline = D + - period <= P + + IOW, if runtime >= WCET and if period is >= P, then the scheduling deadlines + and the absolute deadlines (d_j) coincide, so a proper admission control + allows to respect the jobs' absolute deadlines for this task (this is what is + called "hard schedulability property" and is an extension of Lemma 1 of [2]). + + References: + 1 - C. L. Liu and J. W. Layland. Scheduling algorithms for multiprogram- + ming in a hard-real-time environment. Journal of the Association for + Computing Machinery, 20(1), 1973. + 2 - L. Abeni , G. Buttazzo. Integrating Multimedia Applications in Hard + Real-Time Systems. Proceedings of the 19th IEEE Real-time Systems + Symposium, 1998. http://retis.sssup.it/~giorgio/paps/1998/rtss98-cbs.pdf + 3 - L. Abeni. Server Mechanisms for Multimedia Applications. ReTiS Lab + Technical Report. http://xoomer.virgilio.it/lucabe72/pubs/tr-98-01.ps + +4. Bandwidth management +======================= + + In order for the -deadline scheduling to be effective and useful, it is + important to have some method to keep the allocation of the available CPU + bandwidth to the tasks under control. + This is usually called "admission control" and if it is not performed at all, + no guarantee can be given on the actual scheduling of the -deadline tasks. + + Since when RT-throttling has been introduced each task group has a bandwidth + associated, calculated as a certain amount of runtime over a period. + Moreover, to make it possible to manipulate such bandwidth, readable/writable + controls have been added to both procfs (for system wide settings) and cgroupfs + (for per-group settings). + Therefore, the same interface is being used for controlling the bandwidth + distrubution to -deadline tasks. + + However, more discussion is needed in order to figure out how we want to manage + SCHED_DEADLINE bandwidth at the task group level. Therefore, SCHED_DEADLINE + uses (for now) a less sophisticated, but actually very sensible, mechanism to + ensure that a certain utilization cap is not overcome per each root_domain. + + Another main difference between deadline bandwidth management and RT-throttling + is that -deadline tasks have bandwidth on their own (while -rt ones don't!), + and thus we don't need an higher level throttling mechanism to enforce the + desired bandwidth. + +4.1 System wide settings +------------------------ + + The system wide settings are configured under the /proc virtual file system. + + For now the -rt knobs are used for dl admission control and the -deadline + runtime is accounted against the -rt runtime. We realise that this isn't + entirely desirable; however, it is better to have a small interface for now, + and be able to change it easily later. The ideal situation (see 5.) is to run + -rt tasks from a -deadline server; in which case the -rt bandwidth is a direct + subset of dl_bw. + + This means that, for a root_domain comprising M CPUs, -deadline tasks + can be created while the sum of their bandwidths stays below: + + M * (sched_rt_runtime_us / sched_rt_period_us) + + It is also possible to disable this bandwidth management logic, and + be thus free of oversubscribing the system up to any arbitrary level. + This is done by writing -1 in /proc/sys/kernel/sched_rt_runtime_us. + + +4.2 Task interface +------------------ + + Specifying a periodic/sporadic task that executes for a given amount of + runtime at each instance, and that is scheduled according to the urgency of + its own timing constraints needs, in general, a way of declaring: + - a (maximum/typical) instance execution time, + - a minimum interval between consecutive instances, + - a time constraint by which each instance must be completed. + + Therefore: + * a new struct sched_attr, containing all the necessary fields is + provided; + * the new scheduling related syscalls that manipulate it, i.e., + sched_setattr() and sched_getattr() are implemented. + + +4.3 Default behavior +--------------------- + + The default value for SCHED_DEADLINE bandwidth is to have rt_runtime equal to + 950000. With rt_period equal to 1000000, by default, it means that -deadline + tasks can use at most 95%, multiplied by the number of CPUs that compose the + root_domain, for each root_domain. + + A -deadline task cannot fork. + +5. Tasks CPU affinity +===================== + + -deadline tasks cannot have an affinity mask smaller that the entire + root_domain they are created on. However, affinities can be specified + through the cpuset facility (Documentation/cgroups/cpusets.txt). + +5.1 SCHED_DEADLINE and cpusets HOWTO +------------------------------------ + + An example of a simple configuration (pin a -deadline task to CPU0) + follows (rt-app is used to create a -deadline task). + + mkdir /dev/cpuset + mount -t cgroup -o cpuset cpuset /dev/cpuset + cd /dev/cpuset + mkdir cpu0 + echo 0 > cpu0/cpuset.cpus + echo 0 > cpu0/cpuset.mems + echo 1 > cpuset.cpu_exclusive + echo 0 > cpuset.sched_load_balance + echo 1 > cpu0/cpuset.cpu_exclusive + echo 1 > cpu0/cpuset.mem_exclusive + echo $$ > cpu0/tasks + rt-app -t 100000:10000:d:0 -D5 (it is now actually superfluous to specify + task affinity) + +6. Future plans +=============== + + Still missing: + + - refinements to deadline inheritance, especially regarding the possibility + of retaining bandwidth isolation among non-interacting tasks. This is + being studied from both theoretical and practical points of view, and + hopefully we should be able to produce some demonstrative code soon; + - (c)group based bandwidth management, and maybe scheduling; + - access control for non-root users (and related security concerns to + address), which is the best way to allow unprivileged use of the mechanisms + and how to prevent non-root users "cheat" the system? + + As already discussed, we are planning also to merge this work with the EDF + throttling patches [https://lkml.org/lkml/2010/2/23/239] but we still are in + the preliminary phases of the merge and we really seek feedback that would + help us decide on the direction it should take. diff --git a/Documentation/scsi/00-INDEX b/Documentation/scsi/00-INDEX index 2044be565d93b9..c4b978a72f78d4 100644 --- a/Documentation/scsi/00-INDEX +++ b/Documentation/scsi/00-INDEX @@ -36,6 +36,8 @@ NinjaSCSI.txt - info on WorkBiT NinjaSCSI-32/32Bi driver aacraid.txt - Driver supporting Adaptec RAID controllers +advansys.txt + - List of Advansys Host Adapters aha152x.txt - info on driver for Adaptec AHA152x based adapters aic79xx.txt @@ -44,6 +46,12 @@ aic7xxx.txt - info on driver for Adaptec controllers arcmsr_spec.txt - ARECA FIRMWARE SPEC (for IOP331 adapter) +bfa.txt + - Brocade FC/FCOE adapter driver. +bnx2fc.txt + - FCoE hardware offload for Broadcom network interfaces. +cxgb3i.txt + - Chelsio iSCSI Linux Driver dc395x.txt - README file for the dc395x SCSI driver dpti.txt @@ -52,18 +60,24 @@ dtc3x80.txt - info on driver for DTC 2x80 based adapters g_NCR5380.txt - info on driver for NCR5380 and NCR53c400 based adapters +hpsa.txt + - HP Smart Array Controller SCSI driver. hptiop.txt - HIGHPOINT ROCKETRAID 3xxx RAID DRIVER in2000.txt - info on in2000 driver libsas.txt - Serial Attached SCSI management layer. +link_power_management_policy.txt + - Link power management options. lpfc.txt - LPFC driver release notes megaraid.txt - Common Management Module, shared code handling ioctls for LSI drivers ncr53c8xx.txt - info on driver for NCR53c8xx based adapters +osd.txt + Object-Based Storage Device, command set introduction. osst.txt - info on driver for OnStream SC-x0 SCSI tape ppa.txt @@ -74,6 +88,8 @@ scsi-changer.txt - README for the SCSI media changer driver scsi-generic.txt - info on the sg driver for generic (non-disk/CD/tape) SCSI devices. +scsi-parameters.txt + - List of SCSI-parameters to pass to the kernel at module load-time. scsi.txt - short blurb on using SCSI support as a module. scsi_mid_low_api.txt diff --git a/Documentation/serial/00-INDEX b/Documentation/serial/00-INDEX index 1f1b22fbd73935..f9c6b5ed03e7f0 100644 --- a/Documentation/serial/00-INDEX +++ b/Documentation/serial/00-INDEX @@ -4,10 +4,12 @@ README.cycladesZ - info on Cyclades-Z firmware loading. digiepca.txt - info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards. -hayes-esp.txt - - info on using the Hayes ESP serial driver. +driver + - intro to the low level serial driver. moxa-smartio - file with info on installing/using Moxa multiport serial driver. +n_gsm.txt + - GSM 0710 tty multiplexer howto. riscom8.txt - notes on using the RISCom/8 multi-port serial driver. rocket.txt diff --git a/Documentation/spi/00-INDEX b/Documentation/spi/00-INDEX new file mode 100644 index 00000000000000..a128fa83551297 --- /dev/null +++ b/Documentation/spi/00-INDEX @@ -0,0 +1,22 @@ +00-INDEX + - this file. +Makefile + - Makefile for the example sourcefiles. +butterfly + - AVR Butterfly SPI driver overview and pin configuration. +ep93xx_spi + - Basic EP93xx SPI driver configuration. +pxa2xx + - PXA2xx SPI master controller build by spi_message fifo wq +spidev + - Intro to the userspace API for spi devices +spidev_fdx.c + - spidev example file +spi-lm70llp + - Connecting an LM70-LLP sensor to the kernel via the SPI subsys. +spi-sc18is602 + - NXP SC18IS602/603 I2C-bus to SPI bridge +spi-summary + - (Linux) SPI overview. If unsure about SPI or SPI in Linux, start here. +spidev_test.c + - SPI testing utility. diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary index f72e0d1e0da852..7982bcc4d151ad 100644 --- a/Documentation/spi/spi-summary +++ b/Documentation/spi/spi-summary @@ -543,7 +543,22 @@ SPI MASTER METHODS queuing transfers that arrive in the meantime. When the driver is finished with this message, it must call spi_finalize_current_message() so the subsystem can issue the next - transfer. This may sleep. + message. This may sleep. + + master->transfer_one(struct spi_master *master, struct spi_device *spi, + struct spi_transfer *transfer) + The subsystem calls the driver to transfer a single transfer while + queuing transfers that arrive in the meantime. When the driver is + finished with this transfer, it must call + spi_finalize_current_transfer() so the subsystem can issue the next + transfer. This may sleep. Note: transfer_one and transfer_one_message + are mutually exclusive; when both are set, the generic subsystem does + not call your transfer_one callback. + + Return values: + negative errno: error + 0: transfer is finished + 1: transfer is still in progress DEPRECATED METHODS diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index ee9a2f983b9901..e55124e7c40cd0 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -33,6 +33,10 @@ show up in /proc/sys/kernel: - domainname - hostname - hotplug +- hung_task_panic +- hung_task_check_count +- hung_task_timeout_secs +- hung_task_warnings - kexec_load_disabled - kptr_restrict - kstack_depth_to_print [ X86 only ] @@ -288,6 +292,44 @@ Default value is "/sbin/hotplug". ============================================================== +hung_task_panic: + +Controls the kernel's behavior when a hung task is detected. +This file shows up if CONFIG_DETECT_HUNG_TASK is enabled. + +0: continue operation. This is the default behavior. + +1: panic immediately. + +============================================================== + +hung_task_check_count: + +The upper bound on the number of tasks that are checked. +This file shows up if CONFIG_DETECT_HUNG_TASK is enabled. + +============================================================== + +hung_task_timeout_secs: + +Check interval. When a task in D state did not get scheduled +for more than this value report a warning. +This file shows up if CONFIG_DETECT_HUNG_TASK is enabled. + +0: means infinite timeout - no checking done. + +============================================================== + +hung_task_warning: + +The maximum number of warnings to report. During a check interval +When this value is reached, no more the warnings will be reported. +This file shows up if CONFIG_DETECT_HUNG_TASK is enabled. + +-1: report an infinite number of warnings. + +============================================================== + kexec_load_disabled: A toggle indicating if the kexec_load syscall has been disabled. This diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index 9f5481bdc5a43f..d614a9b6a28048 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -696,7 +696,9 @@ swappiness This control is used to define how aggressive the kernel will swap memory pages. Higher values will increase agressiveness, lower values -decrease the amount of swap. +decrease the amount of swap. A value of 0 instructs the kernel not to +initiate swap until the amount of free and file-backed pages is less +than the high water mark in a zone. The default value is 60. diff --git a/Documentation/timers/00-INDEX b/Documentation/timers/00-INDEX index ef2ccbf77fa2d4..6d042dc1cce0db 100644 --- a/Documentation/timers/00-INDEX +++ b/Documentation/timers/00-INDEX @@ -8,6 +8,8 @@ hpet_example.c - sample hpet timer test program hrtimers.txt - subsystem for high-resolution kernel timers +Makefile + - Build and link hpet_example NO_HZ.txt - Summary of the different methods for the scheduler clock-interrupts management. timers-howto.txt diff --git a/Documentation/video4linux/omap4_camera.txt b/Documentation/video4linux/omap4_camera.txt new file mode 100644 index 00000000000000..25d9b40a4651f0 --- /dev/null +++ b/Documentation/video4linux/omap4_camera.txt @@ -0,0 +1,60 @@ + OMAP4 ISS Driver + ================ + +Introduction +------------ + +The OMAP44XX family of chips contains the Imaging SubSystem (a.k.a. ISS), +Which contains several components that can be categorized in 3 big groups: + +- Interfaces (2 Interfaces: CSI2-A & CSI2-B/CCP2) +- ISP (Image Signal Processor) +- SIMCOP (Still Image Coprocessor) + +For more information, please look in [1] for latest version of: + "OMAP4430 Multimedia Device Silicon Revision 2.x" + +As of Revision AB, the ISS is described in detail in section 8. + +This driver is supporting _only_ the CSI2-A/B interfaces for now. + +It makes use of the Media Controller framework [2], and inherited most of the +code from OMAP3 ISP driver (found under drivers/media/platform/omap3isp/*), +except that it doesn't need an IOMMU now for ISS buffers memory mapping. + +Supports usage of MMAP buffers only (for now). + +Tested platforms +---------------- + +- OMAP4430SDP, w/ ES2.1 GP & SEVM4430-CAM-V1-0 (Contains IMX060 & OV5640, in + which only the last one is supported, outputting YUV422 frames). + +- TI Blaze MDP, w/ OMAP4430 ES2.2 EMU (Contains 1 IMX060 & 2 OV5650 sensors, in + which only the OV5650 are supported, outputting RAW10 frames). + +- PandaBoard, Rev. A2, w/ OMAP4430 ES2.1 GP & OV adapter board, tested with + following sensors: + * OV5640 + * OV5650 + +- Tested on mainline kernel: + + http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=summary + + Tag: v3.3 (commit c16fa4f2ad19908a47c63d8fa436a1178438c7e7) + +File list +--------- +drivers/staging/media/omap4iss/ +include/media/omap4iss.h + +References +---------- + +[1] http://focus.ti.com/general/docs/wtbu/wtbudocumentcenter.tsp?navigationId=12037&templateId=6123#62 +[2] http://lwn.net/Articles/420485/ +[3] http://www.spinics.net/lists/linux-media/msg44370.html +-- +Author: Sergio Aguirre +Copyright (C) 2012, Texas Instruments diff --git a/Documentation/video4linux/si476x.txt b/Documentation/video4linux/si476x.txt index 2f9b4875ab8a33..616607955aafc4 100644 --- a/Documentation/video4linux/si476x.txt +++ b/Documentation/video4linux/si476x.txt @@ -147,7 +147,7 @@ The drivers exposes following files: -------------------------------------------------------------------- 0x12 | readfreq | Current tuned frequency -------------------------------------------------------------------- - 0x14 | freqoff | Singed frequency offset in units of + 0x14 | freqoff | Signed frequency offset in units of | | 2ppm -------------------------------------------------------------------- 0x15 | rssi | Signed value of RSSI in dBuV diff --git a/Documentation/virtual/kvm/00-INDEX b/Documentation/virtual/kvm/00-INDEX index 641ec922017993..fee9f2bf9c64a8 100644 --- a/Documentation/virtual/kvm/00-INDEX +++ b/Documentation/virtual/kvm/00-INDEX @@ -20,5 +20,7 @@ ppc-pv.txt - the paravirtualization interface on PowerPC. review-checklist.txt - review checklist for KVM patches. +s390-diag.txt + - Diagnose hypercall description (for IBM S/390) timekeeping.txt - timekeeping virtualization for x86-based architectures. diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 366bf4b47ef48b..6cd63a9010fbbf 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -1838,6 +1838,7 @@ registers, find a list below: PPC | KVM_REG_PPC_LPCR | 64 PPC | KVM_REG_PPC_PPR | 64 PPC | KVM_REG_PPC_ARCH_COMPAT 32 + PPC | KVM_REG_PPC_DABRX | 32 PPC | KVM_REG_PPC_TM_GPR0 | 64 ... PPC | KVM_REG_PPC_TM_GPR31 | 64 diff --git a/Documentation/vm/00-INDEX b/Documentation/vm/00-INDEX index a39d06680e1c1a..081c49777abb81 100644 --- a/Documentation/vm/00-INDEX +++ b/Documentation/vm/00-INDEX @@ -16,8 +16,6 @@ hwpoison.txt - explains what hwpoison is ksm.txt - how to use the Kernel Samepage Merging feature. -locking - - info on how locking and synchronization is done in the Linux vm code. numa - information about NUMA specific code in the Linux vm. numa_memory_policy.txt @@ -32,6 +30,8 @@ slub.txt - a short users guide for SLUB. soft-dirty.txt - short explanation for soft-dirty PTEs +split_page_table_lock + - Separate per-table lock to improve scalability of the old page_table_lock. transhuge.txt - Transparent Hugepage Support, alternative way of using hugepages. unevictable-lru.txt diff --git a/Documentation/w1/masters/00-INDEX b/Documentation/w1/masters/00-INDEX index d63fa024ac0590..8330cf9325f0ad 100644 --- a/Documentation/w1/masters/00-INDEX +++ b/Documentation/w1/masters/00-INDEX @@ -4,7 +4,9 @@ ds2482 - The Maxim/Dallas Semiconductor DS2482 provides 1-wire busses. ds2490 - The Maxim/Dallas Semiconductor DS2490 builds USB <-> W1 bridges. -mxc_w1 +mxc-w1 - W1 master controller driver found on Freescale MX2/MX3 SoCs +omap-hdq + - HDQ/1-wire module of TI OMAP 2430/3430. w1-gpio - GPIO 1-wire bus master driver. diff --git a/Documentation/w1/slaves/00-INDEX b/Documentation/w1/slaves/00-INDEX index 75613c9ac4dbe2..6e18c70c347488 100644 --- a/Documentation/w1/slaves/00-INDEX +++ b/Documentation/w1/slaves/00-INDEX @@ -4,3 +4,5 @@ w1_therm - The Maxim/Dallas Semiconductor ds18*20 temperature sensor. w1_ds2423 - The Maxim/Dallas Semiconductor ds2423 counter device. +w1_ds28e04 + - The Maxim/Dallas Semiconductor ds28e04 eeprom. diff --git a/Documentation/x86/00-INDEX b/Documentation/x86/00-INDEX index f37b46d348614b..692264456f0f6c 100644 --- a/Documentation/x86/00-INDEX +++ b/Documentation/x86/00-INDEX @@ -1,6 +1,20 @@ 00-INDEX - this file -mtrr.txt - - how to use x86 Memory Type Range Registers to increase performance +boot.txt + - List of boot protocol versions +early-microcode.txt + - How to load microcode from an initrd-CPIO archive early to fix CPU issues. +earlyprintk.txt + - Using earlyprintk with a USB2 debug port key. +entry_64.txt + - Describe (some of the) kernel entry points for x86. exception-tables.txt - why and how Linux kernel uses exception tables on x86 +mtrr.txt + - how to use x86 Memory Type Range Registers to increase performance +pat.txt + - Page Attribute Table intro and API +usb-legacy-support.txt + - how to fix/avoid quirks when using emulated PS/2 mouse/keyboard. +zero-page.txt + - layout of the first page of memory. diff --git a/Documentation/zh_CN/arm64/booting.txt b/Documentation/zh_CN/arm64/booting.txt index 28fa325b74617f..6f6d956ac1c972 100644 --- a/Documentation/zh_CN/arm64/booting.txt +++ b/Documentation/zh_CN/arm64/booting.txt @@ -7,7 +7,7 @@ help. Contact the Chinese maintainer if this translation is outdated or if there is a problem with the translation. Maintainer: Will Deacon -Chinese maintainer: Fu Wei +Chinese maintainer: Fu Wei --------------------------------------------------------------------- Documentation/arm64/booting.txt 的中文翻译 @@ -16,9 +16,9 @@ Documentation/arm64/booting.txt 的中文翻译 译存在问题,请è”系中文版维护者。 英文版维护者: Will Deacon -中文版维护者: 傅炜 Fu Wei -中文版翻译者: 傅炜 Fu Wei -中文版校译者: 傅炜 Fu Wei +中文版维护者: 傅炜 Fu Wei +中文版翻译者: 傅炜 Fu Wei +中文版校译者: 傅炜 Fu Wei 以下为正文 --------------------------------------------------------------------- @@ -64,8 +64,8 @@ RAM,或å¯èƒ½ä½¿ç”¨å¯¹è¿™ä¸ªè®¾å¤‡å·²çŸ¥çš„ RAM ä¿¡æ¯ï¼Œè¿˜å¯èƒ½ä½¿ç”¨ä»»ä½• å¿…è¦æ€§: 强制 -设备树数æ®å—(dtb)大å°å¿…é¡»ä¸å¤§äºŽ 2 MB,且ä½äºŽä»Žå†…核映åƒèµ·å§‹ç®—起第一个 -512MB 内的 2MB 边界上。这使得内核å¯ä»¥é€šè¿‡åˆå§‹é¡µè¡¨ä¸­çš„å•个节æè¿°ç¬¦æ¥ +设备树数æ®å—(dtb)必须 8 字节对é½ï¼Œå¹¶ä½äºŽä»Žå†…核映åƒèµ·å§‹ç®—起第一个 512MB +内,且ä¸å¾—跨越 2MB 对é½è¾¹ç•Œã€‚这使得内核å¯ä»¥é€šè¿‡åˆå§‹é¡µè¡¨ä¸­çš„å•个节æè¿°ç¬¦æ¥ 映射此数æ®å—。 @@ -84,13 +84,23 @@ AArch64 å†…æ ¸å½“å‰æ²¡æœ‰æä¾›è‡ªè§£åދ代ç ï¼Œå› æ­¤å¦‚果使用了压缩内 å¿…è¦æ€§: 强制 -已解压的内核映åƒåŒ…å«ä¸€ä¸ª 32 字节的头,内容如下: +已解压的内核映åƒåŒ…å«ä¸€ä¸ª 64 字节的头,内容如下: - u32 magic = 0x14000008; /* 跳转到 stext, å°ç«¯ */ - u32 res0 = 0; /* ä¿ç•™ */ + u32 code0; /* 坿‰§è¡Œä»£ç  */ + u32 code1; /* 坿‰§è¡Œä»£ç  */ u64 text_offset; /* 映åƒè£…è½½åç§» */ + u64 res0 = 0; /* ä¿ç•™ */ u64 res1 = 0; /* ä¿ç•™ */ u64 res2 = 0; /* ä¿ç•™ */ + u64 res3 = 0; /* ä¿ç•™ */ + u64 res4 = 0; /* ä¿ç•™ */ + u32 magic = 0x644d5241; /* 魔数, å°ç«¯, "ARM\x64" */ + u32 res5 = 0; /* ä¿ç•™ */ + + +映åƒå¤´æ³¨é‡Šï¼š + +- code0/code1 负责跳转到 stext. 映åƒå¿…é¡»ä½äºŽç³»ç»Ÿ RAM 起始处的特定åç§»ï¼ˆå½“å‰æ˜¯ 0x80000)。系统 RAM 的起始地å€å¿…须是以 2MB 对é½çš„。 @@ -118,9 +128,9 @@ AArch64 å†…æ ¸å½“å‰æ²¡æœ‰æä¾›è‡ªè§£åދ代ç ï¼Œå› æ­¤å¦‚果使用了压缩内 外部高速缓存(如果存在)必须é…置并ç¦ç”¨ã€‚ - 架构计时器 - CNTFRQ 必须设定为计时器的频率。 - 如果在 EL1 模å¼ä¸‹è¿›å…¥å†…核,则 CNTHCTL_EL2 中的 EL1PCTEN (bit 0) - 必须置ä½ã€‚ + CNTFRQ 必须设定为计时器的频率,且 CNTVOFF 必须设定为对所有 CPU + 都一致的值。如果在 EL1 模å¼ä¸‹è¿›å…¥å†…核,则 CNTHCTL_EL2 中的 + EL1PCTEN (bit 0) 必须置ä½ã€‚ - 一致性 通过内核å¯åŠ¨çš„æ‰€æœ‰ CPU 在内核入å£åœ°å€ä¸Šå¿…须处于相åŒçš„一致性域中。 @@ -131,23 +141,40 @@ AArch64 å†…æ ¸å½“å‰æ²¡æœ‰æä¾›è‡ªè§£åދ代ç ï¼Œå› æ­¤å¦‚果使用了压缩内 在进入内核映åƒçš„异常级中,所有构架中å¯å†™çš„系统寄存器必须通过软件 在一个更高的异常级别下åˆå§‹åŒ–,以防止在 未知 状æ€ä¸‹è¿è¡Œã€‚ +以上对于 CPU 模å¼ã€é«˜é€Ÿç¼“å­˜ã€MMUã€æž¶æž„计时器ã€ä¸€è‡´æ€§ã€ç³»ç»Ÿå¯„存器的 +å¿…è¦æ¡ä»¶æè¿°é€‚用于所有 CPU。所有 CPU 必须在åŒä¸€å¼‚常级别跳入内核。 + 引导装载程åºå¿…须在æ¯ä¸ª CPU å¤„äºŽä»¥ä¸‹çŠ¶æ€æ—¶è·³å…¥å†…核入å£ï¼š - 主 CPU 必须直接跳入内核映åƒçš„ç¬¬ä¸€æ¡æŒ‡ä»¤ã€‚通过此 CPU 传递的设备树 - æ•°æ®å—必须在æ¯ä¸ª CPU 节点中包å«ä»¥ä¸‹å†…容: - - 1ã€â€˜enable-method’属性。目å‰ï¼Œæ­¤å­—段支æŒçš„值仅为字符串“spin-tableâ€ã€‚ - - 2ã€â€˜cpu-release-addr’标识一个 64-bitã€åˆå§‹åŒ–为零的内存ä½ç½®ã€‚ + æ•°æ®å—必须在æ¯ä¸ª CPU 节点中包å«ä¸€ä¸ª ‘enable-method’ 属性,所 + 支æŒçš„ enable-method 请è§ä¸‹æ–‡ã€‚ 引导装载程åºå¿…须生æˆè¿™äº›è®¾å¤‡æ ‘属性,并在跳入内核入å£ä¹‹å‰å°†å…¶æ’å…¥ æ•°æ®å—。 -- 任何辅助 CPU 必须在内存ä¿ç•™åŒºï¼ˆé€šè¿‡è®¾å¤‡æ ‘中的 /memreserve/ 域传递 +- enable-method 为 “spin-table†的 CPU 必须在它们的 CPU + 节点中包å«ä¸€ä¸ª ‘cpu-release-addr’ 属性。这个属性标识了一个 + 64 ä½è‡ªç„¶å¯¹é½ä¸”åˆå§‹åŒ–为零的内存ä½ç½®ã€‚ + + 这些 CPU 必须在内存ä¿ç•™åŒºï¼ˆé€šè¿‡è®¾å¤‡æ ‘中的 /memreserve/ 域传递 给内核)中自旋于内核之外,轮询它们的 cpu-release-addr ä½ç½®ï¼ˆå¿…é¡» 包å«åœ¨ä¿ç•™åŒºä¸­ï¼‰ã€‚å¯é€šè¿‡æ’å…¥ wfe 指令æ¥é™ä½Žå¿™å¾ªçŽ¯å¼€é”€ï¼Œè€Œä¸» CPU å°† å‘出 sev 指令。当对 cpu-release-addr 所指ä½ç½®çš„è¯»å–æ“作返回éžé›¶å€¼ - 时,CPU 必须直接跳入此值所指å‘的地å€ã€‚ + 时,CPU 必须跳入此值所指å‘的地å€ã€‚此值为一个å•独的 64 ä½å°ç«¯å€¼ï¼Œ + å› æ­¤ CPU 须在跳转å‰å°†æ‰€è¯»å–的值转æ¢ä¸ºå…¶æœ¬èº«çš„端模å¼ã€‚ + +- enable-method 为 “psci†的 CPU ä¿æŒåœ¨å†…核外(比如,在 + memory 节点中æè¿°ä¸ºå†…核空间的内存区外,或在通过设备树 /memreserve/ + 域中æè¿°ä¸ºå†…æ ¸ä¿ç•™åŒºçš„空间中)。内核将会å‘起在 ARM æ–‡æ¡£ï¼ˆç¼–å· + ARM DEN 0022A:用于 ARM 上的电æºçжæ€å调接å£ç³»ç»Ÿè½¯ä»¶ï¼‰ä¸­æè¿°çš„ + CPU_ON 调用æ¥å°† CPU 带入内核。 + + *译者注:到文档翻译时,此文档已更新为 ARM DEN 0022B。 + + 设备树必须包å«ä¸€ä¸ª ‘psci’ 节点,请å‚考以下文档: + Documentation/devicetree/bindings/arm/psci.txt + - 辅助 CPU 通用寄存器设置 x0 = 0 (ä¿ç•™ï¼Œå°†æ¥å¯èƒ½ä½¿ç”¨) diff --git a/Documentation/zh_CN/arm64/memory.txt b/Documentation/zh_CN/arm64/memory.txt index a5f6283829f9c9..a782704c1cb59a 100644 --- a/Documentation/zh_CN/arm64/memory.txt +++ b/Documentation/zh_CN/arm64/memory.txt @@ -7,7 +7,7 @@ help. Contact the Chinese maintainer if this translation is outdated or if there is a problem with the translation. Maintainer: Catalin Marinas -Chinese maintainer: Fu Wei +Chinese maintainer: Fu Wei --------------------------------------------------------------------- Documentation/arm64/memory.txt 的中文翻译 @@ -16,9 +16,9 @@ Documentation/arm64/memory.txt 的中文翻译 译存在问题,请è”系中文版维护者。 英文版维护者: Catalin Marinas -中文版维护者: 傅炜 Fu Wei -中文版翻译者: 傅炜 Fu Wei -中文版校译者: 傅炜 Fu Wei +中文版维护者: 傅炜 Fu Wei +中文版翻译者: 傅炜 Fu Wei +中文版校译者: 傅炜 Fu Wei 以下为正文 --------------------------------------------------------------------- @@ -41,7 +41,7 @@ AArch64 Linux 使用页大å°ä¸º 4KB çš„ 3 级转æ¢è¡¨é…置,对于用户和 TTBR1 中,且从ä¸å†™å…¥ TTBR0。 -AArch64 Linux 内存布局: +AArch64 Linux 在页大å°ä¸º 4KB 时的内存布局: èµ·å§‹åœ°å€ ç»“æŸåœ°å€ å¤§å° ç”¨é€” ----------------------------------------------------------------------- @@ -55,15 +55,42 @@ ffffffbc00000000 ffffffbdffffffff 8GB vmemmap ffffffbe00000000 ffffffbffbbfffff ~8GB [防护页,未æ¥ç”¨äºŽ vmmemap] +ffffffbffbc00000 ffffffbffbdfffff 2MB earlyprintk 设备 + ffffffbffbe00000 ffffffbffbe0ffff 64KB PCI I/O 空间 -ffffffbbffff0000 ffffffbcffffffff ~2MB [防护页] +ffffffbffbe10000 ffffffbcffffffff ~2MB [防护页] ffffffbffc000000 ffffffbfffffffff 64MB æ¨¡å— ffffffc000000000 ffffffffffffffff 256GB 内核逻辑内存映射 +AArch64 Linux 在页大å°ä¸º 64KB 时的内存布局: + +èµ·å§‹åœ°å€ ç»“æŸåœ°å€ å¤§å° ç”¨é€” +----------------------------------------------------------------------- +0000000000000000 000003ffffffffff 4TB 用户空间 + +fffffc0000000000 fffffdfbfffeffff ~2TB vmalloc + +fffffdfbffff0000 fffffdfbffffffff 64KB [防护页] + +fffffdfc00000000 fffffdfdffffffff 8GB vmemmap + +fffffdfe00000000 fffffdfffbbfffff ~8GB [防护页,未æ¥ç”¨äºŽ vmmemap] + +fffffdfffbc00000 fffffdfffbdfffff 2MB earlyprintk 设备 + +fffffdfffbe00000 fffffdfffbe0ffff 64KB PCI I/O 空间 + +fffffdfffbe10000 fffffdfffbffffff ~2MB [防护页] + +fffffdfffc000000 fffffdffffffffff 64MB æ¨¡å— + +fffffe0000000000 ffffffffffffffff 2TB 内核逻辑内存映射 + + 4KB 页大å°çš„转æ¢è¡¨æŸ¥æ‰¾ï¼š +--------+--------+--------+--------+--------+--------+--------+--------+ @@ -91,3 +118,10 @@ ffffffc000000000 ffffffffffffffff 256GB 内核逻辑内存映射 | | +--------------------------> [41:29] L2 索引 (仅使用 38:29 ) | +-------------------------------> [47:42] L1 索引 (未使用) +-------------------------------------------------> [63] TTBR0/1 + +当使用 KVM æ—¶, 管ç†ç¨‹åºï¼ˆhypervisor)在 EL2 中通过相对内核虚拟地å€çš„ +一个固定åç§»æ¥æ˜ å°„内核页(内核虚拟地å€çš„高 24 ä½è®¾ä¸ºé›¶ï¼‰: + +èµ·å§‹åœ°å€ ç»“æŸåœ°å€ å¤§å° ç”¨é€” +----------------------------------------------------------------------- +0000004000000000 0000007fffffffff 256GB 在 HYP 中映射的内核对象 diff --git a/Documentation/zh_CN/arm64/tagged-pointers.txt b/Documentation/zh_CN/arm64/tagged-pointers.txt new file mode 100644 index 00000000000000..2664d1bd5a1cc8 --- /dev/null +++ b/Documentation/zh_CN/arm64/tagged-pointers.txt @@ -0,0 +1,52 @@ +Chinese translated version of Documentation/arm64/tagged-pointers.txt + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Maintainer: Will Deacon +Chinese maintainer: Fu Wei +--------------------------------------------------------------------- +Documentation/arm64/tagged-pointers.txt 的中文翻译 + +如果想评论或更新本文的内容,请直接è”系原文档的维护者。如果你使用英文 +äº¤æµæœ‰å›°éš¾çš„è¯ï¼Œä¹Ÿå¯ä»¥å‘中文版维护者求助。如果本翻译更新ä¸åŠæ—¶æˆ–者翻 +译存在问题,请è”系中文版维护者。 + +英文版维护者: Will Deacon +中文版维护者: 傅炜 Fu Wei +中文版翻译者: 傅炜 Fu Wei +中文版校译者: 傅炜 Fu Wei + +以下为正文 +--------------------------------------------------------------------- + Linux 在 AArch64 ä¸­å¸¦æ ‡è®°çš„è™šæ‹Ÿåœ°å€ + ================================= + +作者: Will Deacon +日期: 2013 å¹´ 06 月 12 æ—¥ + +本文档简述了在 AArch64 地å€è½¬æ¢ç³»ç»Ÿä¸­æä¾›çš„带标记的虚拟地å€åŠå…¶åœ¨ +AArch64 Linux 中的潜在用途。 + +内核æä¾›çš„地å€è½¬æ¢è¡¨é…置使通过 TTBR0 完æˆçš„虚拟地å€è½¬æ¢ï¼ˆå³ç”¨æˆ·ç©ºé—´ +映射),其虚拟地å€çš„æœ€é«˜ 8 ä½ï¼ˆ63:56)会被转æ¢ç¡¬ä»¶æ‰€å¿½ç•¥ã€‚è¿™ç§æœºåˆ¶ +让这些ä½å¯ä¾›åº”用程åºè‡ªç”±ä½¿ç”¨ï¼Œå…¶æ³¨æ„事项如下: + + (1) å†…æ ¸è¦æ±‚所有传递到 EL1 的用户空间地å€å¸¦æœ‰ 0x00 标记。 + è¿™æ„味ç€ä»»ä½•æºå¸¦ç”¨æˆ·ç©ºé—´è™šæ‹Ÿåœ°å€çš„系统调用(syscall) + 傿•° *å¿…é¡»* 在陷入内核å‰ä½¿å®ƒä»¬çš„æœ€é«˜å­—节被清零。 + + (2) éžé›¶æ ‡è®°åœ¨ä¼ é€’ä¿¡å·æ—¶ä¸è¢«ä¿å­˜ã€‚è¿™æ„味ç€åœ¨åº”用程åºä¸­åˆ©ç”¨äº† + 标记的信å·å¤„ç†å‡½æ•°æ— æ³•ä¾èµ– siginfo_t 的用户空间虚拟 + åœ°å€æ‰€æºå¸¦çš„包å«å…¶å†…部域信æ¯çš„æ ‡è®°ã€‚此规则的一个例外是 + å½“ä¿¡å·æ˜¯åœ¨è°ƒè¯•观察点的异常处ç†ç¨‹åºä¸­äº§ç”Ÿçš„,此时标记的 + ä¿¡æ¯å°†è¢«ä¿å­˜ã€‚ + + (3) å½“ä½¿ç”¨å¸¦æ ‡è®°çš„æŒ‡é’ˆæ—¶éœ€ç‰¹åˆ«ç•™å¿ƒï¼Œå› ä¸ºä»…å¯¹ä¸¤ä¸ªè™šæ‹Ÿåœ°å€ + 的高字节,C 编译器很å¯èƒ½æ— æ³•判断它们是ä¸åŒçš„。 + +此构架会阻止对带标记的 PC 指针的利用,因此在异常返回时,其高字节 +将被设置æˆä¸€ä¸ªä¸º “55†的扩展符。 diff --git a/MAINTAINERS b/MAINTAINERS index 1912139a59a1f7..5aa1c500fe6dd8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -309,36 +309,36 @@ F: sound/pci/ad1889.* AD525X ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER M: Michael Hennerich -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/AD5254 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/misc/ad525x_dpot.c AD5398 CURRENT REGULATOR DRIVER (AD5398/AD5821) M: Michael Hennerich -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/AD5398 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/regulator/ad5398.c AD714X CAPACITANCE TOUCH SENSOR DRIVER (AD7142/3/7/8/7A) M: Michael Hennerich -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/AD7142 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/input/misc/ad714x.c AD7877 TOUCHSCREEN DRIVER M: Michael Hennerich -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/AD7877 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/input/touchscreen/ad7877.c AD7879 TOUCHSCREEN DRIVER (AD7879/AD7889) M: Michael Hennerich -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/AD7879 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/input/touchscreen/ad7879.c @@ -347,7 +347,7 @@ M: Jiri Kosina S: Maintained ADM1025 HARDWARE MONITOR DRIVER -M: Jean Delvare +M: Jean Delvare L: lm-sensors@lm-sensors.org S: Maintained F: Documentation/hwmon/adm1025 @@ -374,8 +374,8 @@ F: include/media/adp1653.h ADP5520 BACKLIGHT DRIVER WITH IO EXPANDER (ADP5520/ADP5501) M: Michael Hennerich -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/ADP5520 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/mfd/adp5520.c F: drivers/video/backlight/adp5520_bl.c @@ -385,16 +385,16 @@ F: drivers/input/keyboard/adp5520-keys.c ADP5588 QWERTY KEYPAD AND IO EXPANDER DRIVER (ADP5588/ADP5587) M: Michael Hennerich -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/ADP5588 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/input/keyboard/adp5588-keys.c F: drivers/gpio/gpio-adp5588.c ADP8860 BACKLIGHT DRIVER (ADP8860/ADP8861/ADP8863) M: Michael Hennerich -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/ADP8860 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/video/backlight/adp8860_bl.c @@ -412,7 +412,7 @@ S: Maintained F: drivers/macintosh/therm_adt746x.c ADT7475 HARDWARE MONITOR DRIVER -M: Jean Delvare +M: Jean Delvare L: lm-sensors@lm-sensors.org S: Maintained F: Documentation/hwmon/adt7475 @@ -420,8 +420,8 @@ F: drivers/hwmon/adt7475.c ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346) M: Michael Hennerich -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/ADXL345 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/input/misc/adxl34x.c @@ -627,9 +627,9 @@ F: drivers/media/i2c/adv7842* ANALOG DEVICES INC ASOC CODEC DRIVERS M: Lars-Peter Clausen -L: device-drivers-devel@blackfin.uclinux.org L: alsa-devel@alsa-project.org (moderated for non-subscribers) W: http://wiki.analog.com/ +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: sound/soc/codecs/adau* F: sound/soc/codecs/adav* @@ -639,7 +639,7 @@ F: sound/soc/codecs/ssm* F: sound/soc/codecs/sigmadsp.* ANALOG DEVICES INC ASOC DRIVERS -L: uclinux-dist-devel@blackfin.uclinux.org +L: adi-buildroot-devel@lists.sourceforge.net L: alsa-devel@alsa-project.org (moderated for non-subscribers) W: http://blackfin.uclinux.org/ S: Supported @@ -868,14 +868,7 @@ F: arch/arm/mach-prima2/ F: drivers/clk/clk-prima2.c F: drivers/clocksource/timer-prima2.c F: drivers/clocksource/timer-marco.c -F: drivers/dma/sirf-dma.c -F: drivers/i2c/busses/i2c-sirf.c -F: drivers/input/misc/sirfsoc-onkey.c -F: drivers/irqchip/irq-sirfsoc.c -F: drivers/mmc/host/sdhci-sirf.c -F: drivers/pinctrl/sirf/ -F: drivers/rtc/rtc-sirfsoc.c -F: drivers/spi/spi-sirf.c +N: [^a-z]sirf ARM/EBSA110 MACHINE SUPPORT M: Russell King @@ -1409,6 +1402,7 @@ F: drivers/cpuidle/cpuidle-zynq.c N: zynq N: xilinx F: drivers/clocksource/cadence_ttc_timer.c +F: drivers/mmc/host/sdhci-of-arasan.c ARM SMMU DRIVER M: Will Deacon @@ -1741,56 +1735,54 @@ F: fs/bfs/ F: include/uapi/linux/bfs_fs.h BLACKFIN ARCHITECTURE -M: Mike Frysinger -L: uclinux-dist-devel@blackfin.uclinux.org +M: Steven Miao +L: adi-buildroot-devel@lists.sourceforge.net W: http://blackfin.uclinux.org S: Supported F: arch/blackfin/ BLACKFIN EMAC DRIVER -L: uclinux-dist-devel@blackfin.uclinux.org +L: adi-buildroot-devel@lists.sourceforge.net W: http://blackfin.uclinux.org S: Supported F: drivers/net/ethernet/adi/ BLACKFIN RTC DRIVER -M: Mike Frysinger -L: uclinux-dist-devel@blackfin.uclinux.org +L: adi-buildroot-devel@lists.sourceforge.net W: http://blackfin.uclinux.org S: Supported F: drivers/rtc/rtc-bfin.c BLACKFIN SDH DRIVER M: Sonic Zhang -L: uclinux-dist-devel@blackfin.uclinux.org +L: adi-buildroot-devel@lists.sourceforge.net W: http://blackfin.uclinux.org S: Supported F: drivers/mmc/host/bfin_sdh.c BLACKFIN SERIAL DRIVER M: Sonic Zhang -L: uclinux-dist-devel@blackfin.uclinux.org +L: adi-buildroot-devel@lists.sourceforge.net W: http://blackfin.uclinux.org S: Supported F: drivers/tty/serial/bfin_uart.c BLACKFIN WATCHDOG DRIVER -M: Mike Frysinger -L: uclinux-dist-devel@blackfin.uclinux.org +L: adi-buildroot-devel@lists.sourceforge.net W: http://blackfin.uclinux.org S: Supported F: drivers/watchdog/bfin_wdt.c BLACKFIN I2C TWI DRIVER M: Sonic Zhang -L: uclinux-dist-devel@blackfin.uclinux.org +L: adi-buildroot-devel@lists.sourceforge.net W: http://blackfin.uclinux.org/ S: Supported F: drivers/i2c/busses/i2c-bfin-twi.c BLACKFIN MEDIA DRIVER M: Scott Jiang -L: uclinux-dist-devel@blackfin.uclinux.org +L: adi-buildroot-devel@lists.sourceforge.net W: http://blackfin.uclinux.org/ S: Supported F: drivers/media/platform/blackfin/ @@ -2223,6 +2215,7 @@ F: include/linux/clk.h CLOCKSOURCE, CLOCKEVENT DRIVERS M: Daniel Lezcano M: Thomas Gleixner +L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core S: Supported F: drivers/clocksource @@ -2374,7 +2367,7 @@ F: include/linux/cpufreq.h CPU FREQUENCY DRIVERS - ARM BIG LITTLE M: Viresh Kumar -M: Sudeep KarkadaNagesha +M: Sudeep Holla L: cpufreq@vger.kernel.org L: linux-pm@vger.kernel.org W: http://www.arm.com/products/processors/technologies/biglittleprocessing.php @@ -2415,8 +2408,10 @@ F: tools/power/cpupower/ CPUSETS M: Li Zefan +L: cgroups@vger.kernel.org W: http://www.bullopensource.org/cpuset/ W: http://oss.sgi.com/projects/cpusets/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git S: Maintained F: Documentation/cgroups/cpusets.txt F: include/linux/cpuset.h @@ -2864,7 +2859,7 @@ M: Jani Nikula L: intel-gfx@lists.freedesktop.org L: dri-devel@lists.freedesktop.org Q: http://patchwork.freedesktop.org/project/intel-gfx/ -T: git git://people.freedesktop.org/~danvet/drm-intel +T: git git://anongit.freedesktop.org/drm-intel S: Supported F: drivers/gpu/drm/i915/ F: include/drm/i915* @@ -3331,6 +3326,17 @@ S: Maintained F: include/linux/netfilter_bridge/ F: net/bridge/ +ETHERNET PHY LIBRARY +M: Florian Fainelli +L: netdev@vger.kernel.org +S: Maintained +F: include/linux/phy.h +F: include/linux/phy_fixed.h +F: drivers/net/phy/ +F: Documentation/networking/phy.txt +F: drivers/of/of_mdio.c +F: drivers/of/of_net.c + EXT2 FILE SYSTEM M: Jan Kara L: linux-ext4@vger.kernel.org @@ -3388,7 +3394,7 @@ F: drivers/video/exynos/exynos_mipi* F: include/video/exynos_mipi* F71805F HARDWARE MONITORING DRIVER -M: Jean Delvare +M: Jean Delvare L: lm-sensors@lm-sensors.org S: Maintained F: Documentation/hwmon/f71805f @@ -3915,7 +3921,7 @@ S: Odd Fixes F: drivers/tty/hvc/ HARDWARE MONITORING -M: Jean Delvare +M: Jean Delvare M: Guenter Roeck L: lm-sensors@lm-sensors.org W: http://www.lm-sensors.org/ @@ -4024,6 +4030,7 @@ F: include/uapi/linux/hid* HIGH-RESOLUTION TIMERS, CLOCKEVENTS, DYNTICKS M: Thomas Gleixner +L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core S: Maintained F: Documentation/timers/ @@ -4143,7 +4150,7 @@ F: include/linux/hyperv.h F: tools/hv/ I2C OVER PARALLEL PORT -M: Jean Delvare +M: Jean Delvare L: linux-i2c@vger.kernel.org S: Maintained F: Documentation/i2c/busses/i2c-parport @@ -4152,7 +4159,7 @@ F: drivers/i2c/busses/i2c-parport.c F: drivers/i2c/busses/i2c-parport-light.c I2C/SMBUS CONTROLLER DRIVERS FOR PC -M: Jean Delvare +M: Jean Delvare L: linux-i2c@vger.kernel.org S: Maintained F: Documentation/i2c/busses/i2c-ali1535 @@ -4193,7 +4200,7 @@ F: drivers/i2c/busses/i2c-ismt.c F: Documentation/i2c/busses/i2c-ismt I2C/SMBUS STUB DRIVER -M: Jean Delvare +M: Jean Delvare L: linux-i2c@vger.kernel.org S: Maintained F: drivers/i2c/i2c-stub.c @@ -4212,7 +4219,7 @@ F: include/uapi/linux/i2c.h F: include/uapi/linux/i2c-*.h I2C-TAOS-EVM DRIVER -M: Jean Delvare +M: Jean Delvare L: linux-i2c@vger.kernel.org S: Maintained F: Documentation/i2c/busses/i2c-taos-evm @@ -4695,6 +4702,7 @@ F: net/irda/ IRQ SUBSYSTEM M: Thomas Gleixner +L: linux-kernel@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core F: kernel/irq/ @@ -4769,7 +4777,7 @@ S: Maintained F: drivers/isdn/hardware/eicon/ IT87 HARDWARE MONITORING DRIVER -M: Jean Delvare +M: Jean Delvare L: lm-sensors@lm-sensors.org S: Maintained F: Documentation/hwmon/it87 @@ -5139,7 +5147,7 @@ F: drivers/leds/ F: include/linux/leds.h LEGACY EEPROM DRIVER -M: Jean Delvare +M: Jean Delvare S: Maintained F: Documentation/misc-devices/eeprom F: drivers/misc/eeprom/eeprom.c @@ -5287,21 +5295,21 @@ S: Maintained F: drivers/hwmon/lm73.c LM78 HARDWARE MONITOR DRIVER -M: Jean Delvare +M: Jean Delvare L: lm-sensors@lm-sensors.org S: Maintained F: Documentation/hwmon/lm78 F: drivers/hwmon/lm78.c LM83 HARDWARE MONITOR DRIVER -M: Jean Delvare +M: Jean Delvare L: lm-sensors@lm-sensors.org S: Maintained F: Documentation/hwmon/lm83 F: drivers/hwmon/lm83.c LM90 HARDWARE MONITOR DRIVER -M: Jean Delvare +M: Jean Delvare L: lm-sensors@lm-sensors.org S: Maintained F: Documentation/hwmon/lm90 @@ -5326,6 +5334,7 @@ F: drivers/media/usb/dvb-usb-v2/lmedm04* LOCKDEP AND LOCKSTAT M: Peter Zijlstra M: Ingo Molnar +L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git core/locking S: Maintained F: Documentation/lockdep*.txt @@ -5422,6 +5431,16 @@ W: http://www.tazenda.demon.co.uk/phil/linux-hp S: Maintained F: arch/m68k/hp300/ +M88DS3103 MEDIA DRIVER +M: Antti Palosaari +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +W: http://palosaari.fi/linux/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +T: git git://linuxtv.org/anttip/media_tree.git +S: Maintained +F: drivers/media/dvb-frontends/m88ds3103* + M88RS2000 MEDIA DRIVER M: Malcolm Priestley L: linux-media@vger.kernel.org @@ -5430,6 +5449,16 @@ Q: http://patchwork.linuxtv.org/project/linux-media/list/ S: Maintained F: drivers/media/dvb-frontends/m88rs2000* +M88TS2022 MEDIA DRIVER +M: Antti Palosaari +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +W: http://palosaari.fi/linux/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +T: git git://linuxtv.org/anttip/media_tree.git +S: Maintained +F: drivers/media/tuners/m88ts2022* + MA901 MASTERKIT USB FM RADIO DRIVER M: Alexey Klimov L: linux-media@vger.kernel.org @@ -5621,10 +5650,11 @@ F: mm/page_cgroup.c MEMORY TECHNOLOGY DEVICES (MTD) M: David Woodhouse +M: Brian Norris L: linux-mtd@lists.infradead.org W: http://www.linux-mtd.infradead.org/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ -T: git git://git.infradead.org/mtd-2.6.git +T: git git://git.infradead.org/linux-mtd.git S: Maintained F: drivers/mtd/ F: include/linux/mtd/ @@ -5782,7 +5812,7 @@ F: drivers/mfd/ F: include/linux/mfd/ MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM -M: Chris Ball +M: Chris Ball L: linux-mmc@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git S: Maintained @@ -6493,7 +6523,7 @@ S: Maintained F: drivers/char/pc8736x_gpio.c PC87427 HARDWARE MONITORING DRIVER -M: Jean Delvare +M: Jean Delvare L: lm-sensors@lm-sensors.org S: Maintained F: Documentation/hwmon/pc87427 @@ -6622,6 +6652,7 @@ M: Peter Zijlstra M: Paul Mackerras M: Ingo Molnar M: Arnaldo Carvalho de Melo +L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core S: Supported F: kernel/events/* @@ -6745,6 +6776,7 @@ F: drivers/scsi/pm8001/ POSIX CLOCKS and TIMERS M: Thomas Gleixner +L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core S: Supported F: fs/timerfd.c @@ -6941,6 +6973,12 @@ F: include/sound/pxa2xx-lib.h F: sound/arm/pxa* F: sound/soc/pxa/ +PXA3xx NAND FLASH DRIVER +M: Ezequiel Garcia +L: linux-mtd@lists.infradead.org +S: Maintained +F: drivers/mtd/nand/pxa3xx-nand.c + MMP SUPPORT M: Eric Miao M: Haojian Zhuang @@ -7074,7 +7112,7 @@ F: drivers/media/parport/*-qcam* RADOS BLOCK DEVICE (RBD) M: Yehuda Sadeh M: Sage Weil -M: Alex Elder +M: Alex Elder M: ceph-devel@vger.kernel.org W: http://ceph.com/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git @@ -7147,6 +7185,7 @@ F: drivers/net/wireless/ray* RCUTORTURE MODULE M: Josh Triplett M: "Paul E. McKenney" +L: linux-kernel@vger.kernel.org S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git F: Documentation/RCU/torture.txt @@ -7154,6 +7193,7 @@ F: kernel/rcu/torture.c RCUTORTURE TEST FRAMEWORK M: "Paul E. McKenney" +L: linux-kernel@vger.kernel.org S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git F: tools/testing/selftests/rcutorture @@ -7169,7 +7209,7 @@ S: Maintained F: drivers/net/ethernet/rdc/r6040.c RDS - RELIABLE DATAGRAM SOCKETS -M: Venkat Venkatsubra +M: Chien Yen L: rds-devel@oss.oracle.com (moderated for non-subscribers) S: Supported F: net/rds/ @@ -7177,6 +7217,7 @@ F: net/rds/ READ-COPY UPDATE (RCU) M: Dipankar Sarma M: "Paul E. McKenney" +L: linux-kernel@vger.kernel.org W: http://www.rdrop.com/users/paulmck/RCU/ S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git @@ -7456,6 +7497,13 @@ L: linux-media@vger.kernel.org S: Supported F: drivers/media/i2c/s5c73m3/* +SAMSUNG S5K5BAF CAMERA DRIVER +M: Kyungmin Park +M: Andrzej Hajda +L: linux-media@vger.kernel.org +S: Supported +F: drivers/media/i2c/s5k5baf.c + SAMSUNG SOC CLOCK DRIVERS M: Tomasz Figa S: Supported @@ -7486,6 +7534,7 @@ F: drivers/mmc/host/dw_mmc* TIMEKEEPING, CLOCKSOURCE CORE, NTP M: John Stultz M: Thomas Gleixner +L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core S: Supported F: include/linux/clocksource.h @@ -7511,6 +7560,7 @@ F: drivers/watchdog/sc1200wdt.c SCHEDULER M: Ingo Molnar M: Peter Zijlstra +L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git sched/core S: Maintained F: kernel/sched/ @@ -7609,7 +7659,7 @@ S: Maintained F: drivers/mmc/host/sdricoh_cs.c SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER -M: Chris Ball +M: Chris Ball L: linux-mmc@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git S: Maintained @@ -7757,7 +7807,7 @@ L: linux-media@vger.kernel.org T: git git://linuxtv.org/media_tree.git W: http://linuxtv.org S: Odd Fixes -F: drivers/media/radio/si4713-i2c.? +F: drivers/media/radio/si4713/si4713.? SI4713 FM RADIO TRANSMITTER PLATFORM DRIVER M: Eduardo Valentin @@ -7765,7 +7815,15 @@ L: linux-media@vger.kernel.org T: git git://linuxtv.org/media_tree.git W: http://linuxtv.org S: Odd Fixes -F: drivers/media/radio/radio-si4713.c +F: drivers/media/radio/si4713/radio-platform-si4713.c + +SI4713 FM RADIO TRANSMITTER USB DRIVER +M: Hans Verkuil +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +W: http://linuxtv.org +S: Maintained +F: drivers/media/radio/si4713/radio-usb-si4713.c SIANO DVB DRIVER M: Mauro Carvalho Chehab @@ -7878,6 +7936,7 @@ F: mm/sl?b.c SLEEPABLE READ-COPY UPDATE (SRCU) M: Lai Jiangshan M: "Paul E. McKenney" +L: linux-kernel@vger.kernel.org W: http://www.rdrop.com/users/paulmck/RCU/ S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git @@ -7937,7 +7996,7 @@ F: Documentation/hwmon/sch5627 F: drivers/hwmon/sch5627.c SMSC47B397 HARDWARE MONITOR DRIVER -M: Jean Delvare +M: Jean Delvare L: lm-sensors@lm-sensors.org S: Maintained F: Documentation/hwmon/smsc47b397 @@ -8616,6 +8675,14 @@ L: linux-xtensa@linux-xtensa.org S: Maintained F: arch/xtensa/ +THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER +M: Hans Verkuil +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +W: http://linuxtv.org +S: Maintained +F: drivers/media/radio/radio-raremono.c + THERMAL M: Zhang Rui M: Eduardo Valentin @@ -8768,7 +8835,6 @@ F: include/linux/toshiba.h F: include/uapi/linux/toshiba.h TMIO MMC DRIVER -M: Guennadi Liakhovetski M: Ian Molton L: linux-mmc@vger.kernel.org S: Maintained @@ -8955,7 +9021,7 @@ UNSORTED BLOCK IMAGES (UBI) M: Artem Bityutskiy W: http://www.linux-mtd.infradead.org/ L: linux-mtd@lists.infradead.org -T: git git://git.infradead.org/ubi-2.6.git +T: git git://git.infradead.org/ubifs-2.6.git S: Maintained F: drivers/mtd/ubi/ F: include/linux/mtd/ubi.h @@ -9149,8 +9215,7 @@ L: linux-media@vger.kernel.org T: git git://linuxtv.org/media_tree.git W: http://www.linux-projects.org S: Maintained -F: Documentation/video4linux/sn9c102.txt -F: drivers/media/usb/sn9c102/ +F: drivers/staging/media/sn9c102/ USB SUBSYSTEM M: Greg Kroah-Hartman @@ -9456,7 +9521,7 @@ F: Documentation/hwmon/w83793 F: drivers/hwmon/w83793.c W83795 HARDWARE MONITORING DRIVER -M: Jean Delvare +M: Jean Delvare L: lm-sensors@lm-sensors.org S: Maintained F: drivers/hwmon/w83795.c @@ -9582,6 +9647,7 @@ M: Thomas Gleixner M: Ingo Molnar M: "H. Peter Anvin" M: x86@kernel.org +L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/core S: Maintained F: Documentation/x86/ @@ -9662,7 +9728,6 @@ F: drivers/xen/*swiotlb* XFS FILESYSTEM P: Silicon Graphics Inc M: Dave Chinner -M: Ben Myers M: xfs@oss.sgi.com L: xfs@oss.sgi.com W: http://oss.sgi.com/projects/xfs @@ -9735,11 +9800,27 @@ T: Mercurial http://linuxtv.org/hg/v4l-dvb S: Odd Fixes F: drivers/media/pci/zoran/ +ZRAM COMPRESSED RAM BLOCK DEVICE DRVIER +M: Minchan Kim +M: Nitin Gupta +L: linux-kernel@vger.kernel.org +S: Maintained +F: drivers/block/zram/ +F: Documentation/blockdev/zram.txt + ZS DECSTATION Z85C30 SERIAL DRIVER M: "Maciej W. Rozycki" S: Maintained F: drivers/tty/serial/zs.* +ZSMALLOC COMPRESSED SLAB MEMORY ALLOCATOR +M: Minchan Kim +M: Nitin Gupta +L: linux-mm@kvack.org +S: Maintained +F: mm/zsmalloc.c +F: include/linux/zsmalloc.h + ZSWAP COMPRESSED SWAP CACHING M: Seth Jennings L: linux-mm@kvack.org diff --git a/Makefile b/Makefile index 455fd484b20edb..893d6f0e875bf7 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ VERSION = 3 -PATCHLEVEL = 13 +PATCHLEVEL = 14 SUBLEVEL = 0 -EXTRAVERSION = -NAME = One Giant Leap for Frogkind +EXTRAVERSION = -rc3 +NAME = Shuffling Zombie Juror # *DOCUMENTATION* # To see a list of typical targets execute "make help" @@ -311,9 +311,15 @@ endif # If the user is running make -s (silent mode), suppress echoing of # commands +ifneq ($(filter 4.%,$(MAKE_VERSION)),) # make-4 +ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),) + quiet=silent_ +endif +else # make-3.8x ifneq ($(filter s% -s%,$(MAKEFLAGS)),) quiet=silent_ endif +endif export quiet Q KBUILD_VERBOSE @@ -633,7 +639,7 @@ endif ifdef CONFIG_DEBUG_INFO KBUILD_CFLAGS += -g -KBUILD_AFLAGS += -gdwarf-2 +KBUILD_AFLAGS += -Wa,--gdwarf-2 endif ifdef CONFIG_DEBUG_INFO_REDUCED @@ -682,6 +688,9 @@ KBUILD_CFLAGS += $(call cc-option,-Werror=implicit-int) # require functions to have arguments in prototypes, not empty 'int foo()' KBUILD_CFLAGS += $(call cc-option,-Werror=strict-prototypes) +# Prohibit date/time macros, which would make the build non-deterministic +KBUILD_CFLAGS += $(call cc-option,-Werror=date-time) + # use the deterministic mode of AR if available KBUILD_ARFLAGS := $(call ar-option,D) diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 97a2d9a096b948..f6c6b345388c85 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -17,6 +17,7 @@ config ALPHA select ARCH_WANT_IPC_PARSE_VERSION select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE + select AUDIT_ARCH select GENERIC_CLOCKEVENTS select GENERIC_SMP_IDLE_THREAD select GENERIC_STRNCPY_FROM_USER @@ -77,6 +78,8 @@ config GENERIC_ISA_DMA source "init/Kconfig" source "kernel/Kconfig.freezer" +config AUDIT_ARCH + bool menu "System setup" diff --git a/arch/alpha/include/asm/ptrace.h b/arch/alpha/include/asm/ptrace.h index 21128505ddbe31..9047c2fe8f23f4 100644 --- a/arch/alpha/include/asm/ptrace.h +++ b/arch/alpha/include/asm/ptrace.h @@ -19,4 +19,9 @@ #define force_successful_syscall_return() (current_pt_regs()->r0 = 0) +static inline unsigned long regs_return_value(struct pt_regs *regs) +{ + return regs->r0; +} + #endif diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h index 453597b91f3a65..3d6ce6d56fc9ee 100644 --- a/arch/alpha/include/asm/thread_info.h +++ b/arch/alpha/include/asm/thread_info.h @@ -70,6 +70,7 @@ register struct thread_info *__current_thread_info __asm__("$8"); #define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ #define TIF_SIGPENDING 2 /* signal pending */ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ +#define TIF_SYSCALL_AUDIT 4 /* syscall audit active */ #define TIF_DIE_IF_KERNEL 9 /* dik recursion lock */ #define TIF_MEMDIE 13 /* is terminating due to OOM killer */ @@ -77,6 +78,7 @@ register struct thread_info *__current_thread_info __asm__("$8"); #define _TIF_SIGPENDING (1< +#include +#include +#include + +static unsigned dir_class[] = { +#include +~0U +}; + +static unsigned read_class[] = { +#include +~0U +}; + +static unsigned write_class[] = { +#include +~0U +}; + +static unsigned chattr_class[] = { +#include +~0U +}; + +static unsigned signal_class[] = { +#include +~0U +}; + +int audit_classify_arch(int arch) +{ + return 0; +} + +int audit_classify_syscall(int abi, unsigned syscall) +{ + switch(syscall) { + case __NR_open: + return 2; + case __NR_openat: + return 3; + case __NR_execve: + return 5; + default: + return 0; + } +} + +static int __init audit_classes_init(void) +{ + audit_register_class(AUDIT_CLASS_WRITE, write_class); + audit_register_class(AUDIT_CLASS_READ, read_class); + audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class); + audit_register_class(AUDIT_CLASS_CHATTR, chattr_class); + audit_register_class(AUDIT_CLASS_SIGNAL, signal_class); + return 0; +} + +__initcall(audit_classes_init); diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index a969b95ee5ac78..98703d99b565af 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -465,7 +465,11 @@ entSys: .cfi_rel_offset $16, SP_OFF+24 .cfi_rel_offset $17, SP_OFF+32 .cfi_rel_offset $18, SP_OFF+40 - blbs $3, strace +#ifdef CONFIG_AUDITSYSCALL + lda $6, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT + and $3, $6, $3 +#endif + bne $3, strace beq $4, 1f ldq $27, 0($5) 1: jsr $26, ($27), alpha_ni_syscall diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index 2a4a80ff4a2064..86d835157b546f 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -316,15 +317,18 @@ long arch_ptrace(struct task_struct *child, long request, asmlinkage unsigned long syscall_trace_enter(void) { unsigned long ret = 0; + struct pt_regs *regs = current_pt_regs(); if (test_thread_flag(TIF_SYSCALL_TRACE) && tracehook_report_syscall_entry(current_pt_regs())) ret = -1UL; + audit_syscall_entry(AUDIT_ARCH_ALPHA, regs->r0, regs->r16, regs->r17, regs->r18, regs->r19); return ret ?: current_pt_regs()->r0; } asmlinkage void syscall_trace_leave(void) { + audit_syscall_exit(current_pt_regs()); if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall_exit(current_pt_regs(), 0); } diff --git a/arch/alpha/lib/csum_partial_copy.c b/arch/alpha/lib/csum_partial_copy.c index ff3c10721caf67..5675dca8dbb141 100644 --- a/arch/alpha/lib/csum_partial_copy.c +++ b/arch/alpha/lib/csum_partial_copy.c @@ -378,6 +378,11 @@ csum_partial_copy_from_user(const void __user *src, void *dst, int len, __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum) { - return csum_partial_copy_from_user((__force const void __user *)src, - dst, len, sum, NULL); + __wsum checksum; + mm_segment_t oldfs = get_fs(); + set_fs(KERNEL_DS); + checksum = csum_partial_copy_from_user((__force const void __user *)src, + dst, len, sum, NULL); + set_fs(oldfs); + return checksum; } diff --git a/arch/arc/include/asm/linkage.h b/arch/arc/include/asm/linkage.h index 0283e9e44e0d8c..66ee5527aefc08 100644 --- a/arch/arc/include/asm/linkage.h +++ b/arch/arc/include/asm/linkage.h @@ -11,6 +11,8 @@ #ifdef __ASSEMBLY__ +#define ASM_NL ` /* use '`' to mark new line in macro */ + /* Can't use the ENTRY macro in linux/linkage.h * gas considers ';' as comment vs. newline */ diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index dc6ef9a2c649df..e254198177914c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1905,6 +1905,7 @@ config XEN depends on !GENERIC_ATOMIC64 select ARM_PSCI select SWIOTLB_XEN + select ARCH_DMA_ADDR_T_64BIT help Say Y if you want to run Linux in a Virtual Machine on Xen on ARM. diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 23d5e3946589a6..08a9ef58d9c356 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -96,7 +96,7 @@ tune-$(CONFIG_CPU_V6K) =$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm) tune-y := $(tune-y) ifeq ($(CONFIG_AEABI),y) -CFLAGS_ABI :=-mabi=aapcs-linux -mno-thumb-interwork +CFLAGS_ABI :=-mabi=aapcs-linux -mno-thumb-interwork -mfpu=vfp else CFLAGS_ABI :=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) $(call cc-option,-mno-thumb-interwork,) endif diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index ede21c16fdc03f..6d1e43d461871a 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -38,6 +38,7 @@ dtb-$(CONFIG_ARCH_AT91) += at91sam9g35ek.dtb dtb-$(CONFIG_ARCH_AT91) += at91sam9x25ek.dtb dtb-$(CONFIG_ARCH_AT91) += at91sam9x35ek.dtb # sama5d3 +dtb-$(CONFIG_ARCH_AT91) += at91-sama5d3_xplained.dtb dtb-$(CONFIG_ARCH_AT91) += sama5d31ek.dtb dtb-$(CONFIG_ARCH_AT91) += sama5d33ek.dtb dtb-$(CONFIG_ARCH_AT91) += sama5d34ek.dtb @@ -152,10 +153,13 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx53-mba53.dtb \ imx53-qsb.dtb \ imx53-smd.dtb \ + imx6dl-cubox-i.dtb \ + imx6dl-hummingboard.dtb \ imx6dl-sabreauto.dtb \ imx6dl-sabresd.dtb \ imx6dl-wandboard.dtb \ imx6q-arm2.dtb \ + imx6q-cubox-i.dtb \ imx6q-phytec-pbab01.dtb \ imx6q-sabreauto.dtb \ imx6q-sabrelite.dtb \ diff --git a/arch/arm/boot/dts/am33xx-clocks.dtsi b/arch/arm/boot/dts/am33xx-clocks.dtsi new file mode 100644 index 00000000000000..9ccfe508dea22f --- /dev/null +++ b/arch/arm/boot/dts/am33xx-clocks.dtsi @@ -0,0 +1,664 @@ +/* + * Device Tree Source for AM33xx clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * 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. + */ +&scrm_clocks { + sys_clkin_ck: sys_clkin_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&virt_19200000_ck>, <&virt_24000000_ck>, <&virt_25000000_ck>, <&virt_26000000_ck>; + ti,bit-shift = <22>; + reg = <0x0040>; + }; + + adc_tsc_fck: adc_tsc_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dcan0_fck: dcan0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dcan1_fck: dcan1_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + mcasp0_fck: mcasp0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + mcasp1_fck: mcasp1_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + smartreflex0_fck: smartreflex0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + smartreflex1_fck: smartreflex1_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + sha0_fck: sha0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + aes0_fck: aes0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + rng_fck: rng_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + ehrpwm0_gate_tbclk: ehrpwm0_gate_tbclk { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_per_m2_ck>; + ti,bit-shift = <0>; + reg = <0x0664>; + }; + + ehrpwm0_tbclk: ehrpwm0_tbclk { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&ehrpwm0_gate_tbclk>; + }; + + ehrpwm1_gate_tbclk: ehrpwm1_gate_tbclk { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_per_m2_ck>; + ti,bit-shift = <1>; + reg = <0x0664>; + }; + + ehrpwm1_tbclk: ehrpwm1_tbclk { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&ehrpwm1_gate_tbclk>; + }; + + ehrpwm2_gate_tbclk: ehrpwm2_gate_tbclk { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_per_m2_ck>; + ti,bit-shift = <2>; + reg = <0x0664>; + }; + + ehrpwm2_tbclk: ehrpwm2_tbclk { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&ehrpwm2_gate_tbclk>; + }; +}; +&prcm_clocks { + clk_32768_ck: clk_32768_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + clk_rc32k_ck: clk_rc32k_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32000>; + }; + + virt_19200000_ck: virt_19200000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <19200000>; + }; + + virt_24000000_ck: virt_24000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + }; + + virt_25000000_ck: virt_25000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + virt_26000000_ck: virt_26000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <26000000>; + }; + + tclkin_ck: tclkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + dpll_core_ck: dpll_core_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-core-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x0490>, <0x045c>, <0x0468>; + }; + + dpll_core_x2_ck: dpll_core_x2_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-x2-clock"; + clocks = <&dpll_core_ck>; + }; + + dpll_core_m4_ck: dpll_core_m4_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + reg = <0x0480>; + ti,index-starts-at-one; + }; + + dpll_core_m5_ck: dpll_core_m5_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + reg = <0x0484>; + ti,index-starts-at-one; + }; + + dpll_core_m6_ck: dpll_core_m6_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + reg = <0x04d8>; + ti,index-starts-at-one; + }; + + dpll_mpu_ck: dpll_mpu_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x0488>, <0x0420>, <0x042c>; + }; + + dpll_mpu_m2_ck: dpll_mpu_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_mpu_ck>; + ti,max-div = <31>; + reg = <0x04a8>; + ti,index-starts-at-one; + }; + + dpll_ddr_ck: dpll_ddr_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-no-gate-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x0494>, <0x0434>, <0x0440>; + }; + + dpll_ddr_m2_ck: dpll_ddr_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_ddr_ck>; + ti,max-div = <31>; + reg = <0x04a0>; + ti,index-starts-at-one; + }; + + dpll_ddr_m2_div2_ck: dpll_ddr_m2_div2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_ddr_m2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + dpll_disp_ck: dpll_disp_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-no-gate-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x0498>, <0x0448>, <0x0454>; + }; + + dpll_disp_m2_ck: dpll_disp_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_disp_ck>; + ti,max-div = <31>; + reg = <0x04a4>; + ti,index-starts-at-one; + ti,set-rate-parent; + }; + + dpll_per_ck: dpll_per_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-no-gate-j-type-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x048c>, <0x0470>, <0x049c>; + }; + + dpll_per_m2_ck: dpll_per_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_ck>; + ti,max-div = <31>; + reg = <0x04ac>; + ti,index-starts-at-one; + }; + + dpll_per_m2_div4_wkupdm_ck: dpll_per_m2_div4_wkupdm_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + dpll_per_m2_div4_ck: dpll_per_m2_div4_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + cefuse_fck: cefuse_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_clkin_ck>; + ti,bit-shift = <1>; + reg = <0x0a20>; + }; + + clk_24mhz: clk_24mhz { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <8>; + }; + + clkdiv32k_ck: clkdiv32k_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&clk_24mhz>; + clock-mult = <1>; + clock-div = <732>; + }; + + clkdiv32k_ick: clkdiv32k_ick { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ck>; + ti,bit-shift = <1>; + reg = <0x014c>; + }; + + l3_gclk: l3_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + pruss_ocp_gclk: pruss_ocp_gclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&l3_gclk>, <&dpll_disp_m2_ck>; + reg = <0x0530>; + }; + + mmu_fck: mmu_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_core_m4_ck>; + ti,bit-shift = <1>; + reg = <0x0914>; + }; + + timer1_fck: timer1_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&clkdiv32k_ick>, <&tclkin_ck>, <&clk_rc32k_ck>, <&clk_32768_ck>; + reg = <0x0528>; + }; + + timer2_fck: timer2_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x0508>; + }; + + timer3_fck: timer3_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x050c>; + }; + + timer4_fck: timer4_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x0510>; + }; + + timer5_fck: timer5_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x0518>; + }; + + timer6_fck: timer6_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x051c>; + }; + + timer7_fck: timer7_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x0504>; + }; + + usbotg_fck: usbotg_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_per_ck>; + ti,bit-shift = <8>; + reg = <0x047c>; + }; + + dpll_core_m4_div2_ck: dpll_core_m4_div2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + ieee5000_fck: ieee5000_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_core_m4_div2_ck>; + ti,bit-shift = <1>; + reg = <0x00e4>; + }; + + wdt1_fck: wdt1_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&clk_rc32k_ck>, <&clkdiv32k_ick>; + reg = <0x0538>; + }; + + l4_rtc_gclk: l4_rtc_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + l4hs_gclk: l4hs_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l3s_gclk: l3s_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_div2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l4fw_gclk: l4fw_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_div2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l4ls_gclk: l4ls_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_div2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + sysclk_div_ck: sysclk_div_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + cpsw_125mhz_gclk: cpsw_125mhz_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m5_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + cpsw_cpts_rft_clk: cpsw_cpts_rft_clk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_core_m5_ck>, <&dpll_core_m4_ck>; + reg = <0x0520>; + }; + + gpio0_dbclk_mux_ck: gpio0_dbclk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&clk_rc32k_ck>, <&clk_32768_ck>, <&clkdiv32k_ick>; + reg = <0x053c>; + }; + + gpio0_dbclk: gpio0_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&gpio0_dbclk_mux_ck>; + ti,bit-shift = <18>; + reg = <0x0408>; + }; + + gpio1_dbclk: gpio1_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ick>; + ti,bit-shift = <18>; + reg = <0x00ac>; + }; + + gpio2_dbclk: gpio2_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ick>; + ti,bit-shift = <18>; + reg = <0x00b0>; + }; + + gpio3_dbclk: gpio3_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ick>; + ti,bit-shift = <18>; + reg = <0x00b4>; + }; + + lcd_gclk: lcd_gclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_disp_m2_ck>, <&dpll_core_m5_ck>, <&dpll_per_m2_ck>; + reg = <0x0534>; + ti,set-rate-parent; + }; + + mmc_clk: mmc_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + gfx_fclk_clksel_ck: gfx_fclk_clksel_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_core_m4_ck>, <&dpll_per_m2_ck>; + ti,bit-shift = <1>; + reg = <0x052c>; + }; + + gfx_fck_div_ck: gfx_fck_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&gfx_fclk_clksel_ck>; + reg = <0x052c>; + ti,max-div = <2>; + }; + + sysclkout_pre_ck: sysclkout_pre_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&clk_32768_ck>, <&l3_gclk>, <&dpll_ddr_m2_ck>, <&dpll_per_m2_ck>, <&lcd_gclk>; + reg = <0x0700>; + }; + + clkout2_div_ck: clkout2_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sysclkout_pre_ck>; + ti,bit-shift = <3>; + ti,max-div = <8>; + reg = <0x0700>; + }; + + dbg_sysclk_ck: dbg_sysclk_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_clkin_ck>; + ti,bit-shift = <19>; + reg = <0x0414>; + }; + + dbg_clka_ck: dbg_clka_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_core_m4_ck>; + ti,bit-shift = <30>; + reg = <0x0414>; + }; + + stm_pmd_clock_mux_ck: stm_pmd_clock_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dbg_sysclk_ck>, <&dbg_clka_ck>; + ti,bit-shift = <22>; + reg = <0x0414>; + }; + + trace_pmd_clk_mux_ck: trace_pmd_clk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dbg_sysclk_ck>, <&dbg_clka_ck>; + ti,bit-shift = <20>; + reg = <0x0414>; + }; + + stm_clk_div_ck: stm_clk_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&stm_pmd_clock_mux_ck>; + ti,bit-shift = <27>; + ti,max-div = <64>; + reg = <0x0414>; + ti,index-power-of-two; + }; + + trace_clk_div_ck: trace_clk_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&trace_pmd_clk_mux_ck>; + ti,bit-shift = <24>; + ti,max-div = <64>; + reg = <0x0414>; + ti,index-power-of-two; + }; + + clkout2_ck: clkout2_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkout2_div_ck>; + ti,bit-shift = <7>; + reg = <0x0700>; + }; +}; + +&prcm_clockdomains { + clk_24mhz_clkdm: clk_24mhz_clkdm { + compatible = "ti,clockdomain"; + clocks = <&clkdiv32k_ick>; + }; +}; diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index f6d8ffe98d0bfa..6d95d3df33c791 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -102,6 +102,32 @@ ranges; ti,hwmods = "l3_main"; + prcm: prcm@44e00000 { + compatible = "ti,am3-prcm"; + reg = <0x44e00000 0x4000>; + + prcm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + prcm_clockdomains: clockdomains { + }; + }; + + scrm: scrm@44e10000 { + compatible = "ti,am3-scrm"; + reg = <0x44e10000 0x2000>; + + scrm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + scrm_clockdomains: clockdomains { + }; + }; + intc: interrupt-controller@48200000 { compatible = "ti,omap2-intc"; interrupt-controller; @@ -794,3 +820,5 @@ }; }; }; + +/include/ "am33xx-clocks.dtsi" diff --git a/arch/arm/boot/dts/am3517.dtsi b/arch/arm/boot/dts/am3517.dtsi index 2fbe02faa8b18f..788391f9168441 100644 --- a/arch/arm/boot/dts/am3517.dtsi +++ b/arch/arm/boot/dts/am3517.dtsi @@ -61,3 +61,6 @@ }; }; }; + +/include/ "am35xx-clocks.dtsi" +/include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi" diff --git a/arch/arm/boot/dts/am35xx-clocks.dtsi b/arch/arm/boot/dts/am35xx-clocks.dtsi new file mode 100644 index 00000000000000..df489d310b50aa --- /dev/null +++ b/arch/arm/boot/dts/am35xx-clocks.dtsi @@ -0,0 +1,128 @@ +/* + * Device Tree Source for OMAP3 clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * 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. + */ +&scrm_clocks { + emac_ick: emac_ick { + #clock-cells = <0>; + compatible = "ti,am35xx-gate-clock"; + clocks = <&ipss_ick>; + reg = <0x059c>; + ti,bit-shift = <1>; + }; + + emac_fck: emac_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&rmii_ck>; + reg = <0x059c>; + ti,bit-shift = <9>; + }; + + vpfe_ick: vpfe_ick { + #clock-cells = <0>; + compatible = "ti,am35xx-gate-clock"; + clocks = <&ipss_ick>; + reg = <0x059c>; + ti,bit-shift = <2>; + }; + + vpfe_fck: vpfe_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&pclk_ck>; + reg = <0x059c>; + ti,bit-shift = <10>; + }; + + hsotgusb_ick_am35xx: hsotgusb_ick_am35xx { + #clock-cells = <0>; + compatible = "ti,am35xx-gate-clock"; + clocks = <&ipss_ick>; + reg = <0x059c>; + ti,bit-shift = <0>; + }; + + hsotgusb_fck_am35xx: hsotgusb_fck_am35xx { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_ck>; + reg = <0x059c>; + ti,bit-shift = <8>; + }; + + hecc_ck: hecc_ck { + #clock-cells = <0>; + compatible = "ti,am35xx-gate-clock"; + clocks = <&sys_ck>; + reg = <0x059c>; + ti,bit-shift = <3>; + }; +}; +&cm_clocks { + ipss_ick: ipss_ick { + #clock-cells = <0>; + compatible = "ti,am35xx-interface-clock"; + clocks = <&core_l3_ick>; + reg = <0x0a10>; + ti,bit-shift = <4>; + }; + + rmii_ck: rmii_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <50000000>; + }; + + pclk_ck: pclk_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <27000000>; + }; + + uart4_ick_am35xx: uart4_ick_am35xx { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <23>; + }; + + uart4_fck_am35xx: uart4_fck_am35xx { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <23>; + }; +}; + +&cm_clockdomains { + core_l3_clkdm: core_l3_clkdm { + compatible = "ti,clockdomain"; + clocks = <&sdrc_ick>, <&ipss_ick>, <&emac_ick>, <&vpfe_ick>, + <&hsotgusb_ick_am35xx>, <&hsotgusb_fck_am35xx>, + <&hecc_ck>; + }; + + core_l4_clkdm: core_l4_clkdm { + compatible = "ti,clockdomain"; + clocks = <&cpefuse_fck>, <&ts_fck>, <&usbtll_fck>, + <&usbtll_ick>, <&mmchs3_ick>, <&mmchs3_fck>, + <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>, + <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>, + <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>, + <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>, + <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>, + <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>, + <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>, + <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>, + <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>, + <&uart4_ick_am35xx>, <&uart4_fck_am35xx>; + }; +}; diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index 974d103ab3b1e6..c6bd4d986c290a 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -67,6 +67,32 @@ ranges; ti,hwmods = "l3_main"; + prcm: prcm@44df0000 { + compatible = "ti,am4-prcm"; + reg = <0x44df0000 0x11000>; + + prcm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + prcm_clockdomains: clockdomains { + }; + }; + + scrm: scrm@44e10000 { + compatible = "ti,am4-scrm"; + reg = <0x44e10000 0x2000>; + + scrm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + scrm_clockdomains: clockdomains { + }; + }; + edma: edma@49000000 { compatible = "ti,edma3"; ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2"; @@ -665,3 +691,5 @@ }; }; }; + +/include/ "am43xx-clocks.dtsi" diff --git a/arch/arm/boot/dts/am43xx-clocks.dtsi b/arch/arm/boot/dts/am43xx-clocks.dtsi new file mode 100644 index 00000000000000..142009cc93325d --- /dev/null +++ b/arch/arm/boot/dts/am43xx-clocks.dtsi @@ -0,0 +1,656 @@ +/* + * Device Tree Source for AM43xx clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * 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. + */ +&scrm_clocks { + sys_clkin_ck: sys_clkin_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&virt_19200000_ck>, <&virt_24000000_ck>, <&virt_25000000_ck>, <&virt_26000000_ck>; + ti,bit-shift = <22>; + reg = <0x0040>; + }; + + adc_tsc_fck: adc_tsc_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dcan0_fck: dcan0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dcan1_fck: dcan1_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + mcasp0_fck: mcasp0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + mcasp1_fck: mcasp1_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + smartreflex0_fck: smartreflex0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + smartreflex1_fck: smartreflex1_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + sha0_fck: sha0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + aes0_fck: aes0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; +}; +&prcm_clocks { + clk_32768_ck: clk_32768_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + clk_rc32k_ck: clk_rc32k_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + virt_19200000_ck: virt_19200000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <19200000>; + }; + + virt_24000000_ck: virt_24000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + }; + + virt_25000000_ck: virt_25000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + virt_26000000_ck: virt_26000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <26000000>; + }; + + tclkin_ck: tclkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <26000000>; + }; + + dpll_core_ck: dpll_core_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-core-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x2d20>, <0x2d24>, <0x2d2c>; + }; + + dpll_core_x2_ck: dpll_core_x2_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-x2-clock"; + clocks = <&dpll_core_ck>; + }; + + dpll_core_m4_ck: dpll_core_m4_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x2d38>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_m5_ck: dpll_core_m5_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x2d3c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_m6_ck: dpll_core_m6_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x2d40>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_mpu_ck: dpll_mpu_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x2d60>, <0x2d64>, <0x2d6c>; + }; + + dpll_mpu_m2_ck: dpll_mpu_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_mpu_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x2d70>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_ddr_ck: dpll_ddr_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x2da0>, <0x2da4>, <0x2dac>; + }; + + dpll_ddr_m2_ck: dpll_ddr_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_ddr_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x2db0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_disp_ck: dpll_disp_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x2e20>, <0x2e24>, <0x2e2c>; + }; + + dpll_disp_m2_ck: dpll_disp_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_disp_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x2e30>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_ck: dpll_per_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-j-type-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x2de0>, <0x2de4>, <0x2dec>; + }; + + dpll_per_m2_ck: dpll_per_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_ck>; + ti,max-div = <127>; + ti,autoidle-shift = <8>; + reg = <0x2df0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m2_div4_wkupdm_ck: dpll_per_m2_div4_wkupdm_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + dpll_per_m2_div4_ck: dpll_per_m2_div4_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + clk_24mhz: clk_24mhz { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <8>; + }; + + clkdiv32k_ck: clkdiv32k_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&clk_24mhz>; + clock-mult = <1>; + clock-div = <732>; + }; + + clkdiv32k_ick: clkdiv32k_ick { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ck>; + ti,bit-shift = <8>; + reg = <0x2a38>; + }; + + sysclk_div: sysclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + pruss_ocp_gclk: pruss_ocp_gclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sysclk_div>, <&dpll_disp_m2_ck>; + reg = <0x4248>; + }; + + clk_32k_tpm_ck: clk_32k_tpm_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + timer1_fck: timer1_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&clkdiv32k_ick>, <&tclkin_ck>, <&clk_rc32k_ck>, <&clk_32768_ck>, <&clk_32k_tpm_ck>; + reg = <0x4200>; + }; + + timer2_fck: timer2_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x4204>; + }; + + timer3_fck: timer3_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x4208>; + }; + + timer4_fck: timer4_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x420c>; + }; + + timer5_fck: timer5_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x4210>; + }; + + timer6_fck: timer6_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x4214>; + }; + + timer7_fck: timer7_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x4218>; + }; + + wdt1_fck: wdt1_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&clk_rc32k_ck>, <&clkdiv32k_ick>; + reg = <0x422c>; + }; + + l3_gclk: l3_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_core_m4_div2_ck: dpll_core_m4_div2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sysclk_div>; + clock-mult = <1>; + clock-div = <2>; + }; + + l4hs_gclk: l4hs_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l3s_gclk: l3s_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_div2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l4ls_gclk: l4ls_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_div2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + cpsw_125mhz_gclk: cpsw_125mhz_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m5_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + cpsw_cpts_rft_clk: cpsw_cpts_rft_clk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sysclk_div>, <&dpll_core_m5_ck>, <&dpll_disp_m2_ck>; + reg = <0x4238>; + }; + + clk_32k_mosc_ck: clk_32k_mosc_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + gpio0_dbclk_mux_ck: gpio0_dbclk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&clk_rc32k_ck>, <&clk_32768_ck>, <&clkdiv32k_ick>, <&clk_32k_mosc_ck>, <&clk_32k_tpm_ck>; + reg = <0x4240>; + }; + + gpio0_dbclk: gpio0_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&gpio0_dbclk_mux_ck>; + ti,bit-shift = <8>; + reg = <0x2b68>; + }; + + gpio1_dbclk: gpio1_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ick>; + ti,bit-shift = <8>; + reg = <0x8c78>; + }; + + gpio2_dbclk: gpio2_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ick>; + ti,bit-shift = <8>; + reg = <0x8c80>; + }; + + gpio3_dbclk: gpio3_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ick>; + ti,bit-shift = <8>; + reg = <0x8c88>; + }; + + gpio4_dbclk: gpio4_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ick>; + ti,bit-shift = <8>; + reg = <0x8c90>; + }; + + gpio5_dbclk: gpio5_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ick>; + ti,bit-shift = <8>; + reg = <0x8c98>; + }; + + mmc_clk: mmc_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + gfx_fclk_clksel_ck: gfx_fclk_clksel_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sysclk_div>, <&dpll_per_m2_ck>; + ti,bit-shift = <1>; + reg = <0x423c>; + }; + + gfx_fck_div_ck: gfx_fck_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&gfx_fclk_clksel_ck>; + reg = <0x423c>; + ti,max-div = <2>; + }; + + disp_clk: disp_clk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_disp_m2_ck>, <&dpll_core_m5_ck>, <&dpll_per_m2_ck>; + reg = <0x4244>; + }; + + dpll_extdev_ck: dpll_extdev_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x2e60>, <0x2e64>, <0x2e6c>; + }; + + dpll_extdev_m2_ck: dpll_extdev_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_extdev_ck>; + ti,max-div = <127>; + ti,autoidle-shift = <8>; + reg = <0x2e70>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + mux_synctimer32k_ck: mux_synctimer32k_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&clk_32768_ck>, <&clk_32k_tpm_ck>, <&clkdiv32k_ick>; + reg = <0x4230>; + }; + + synctimer_32kclk: synctimer_32kclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&mux_synctimer32k_ck>; + ti,bit-shift = <8>; + reg = <0x2a30>; + }; + + timer8_fck: timer8_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>, <&clk_32k_tpm_ck>; + reg = <0x421c>; + }; + + timer9_fck: timer9_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>, <&clk_32k_tpm_ck>; + reg = <0x4220>; + }; + + timer10_fck: timer10_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>, <&clk_32k_tpm_ck>; + reg = <0x4224>; + }; + + timer11_fck: timer11_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>, <&clk_32k_tpm_ck>; + reg = <0x4228>; + }; + + cpsw_50m_clkdiv: cpsw_50m_clkdiv { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m5_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + cpsw_5m_clkdiv: cpsw_5m_clkdiv { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&cpsw_50m_clkdiv>; + clock-mult = <1>; + clock-div = <10>; + }; + + dpll_ddr_x2_ck: dpll_ddr_x2_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-x2-clock"; + clocks = <&dpll_ddr_ck>; + }; + + dpll_ddr_m4_ck: dpll_ddr_m4_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_ddr_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x2db8>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_clkdcoldo: dpll_per_clkdcoldo { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dll_aging_clk_div: dll_aging_clk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sys_clkin_ck>; + reg = <0x4250>; + ti,dividers = <8>, <16>, <32>; + }; + + div_core_25m_ck: div_core_25m_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sysclk_div>; + clock-mult = <1>; + clock-div = <8>; + }; + + func_12m_clk: func_12m_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <16>; + }; + + vtp_clk_div: vtp_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + usbphy_32khz_clkmux: usbphy_32khz_clkmux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&clk_32768_ck>, <&clk_32k_tpm_ck>; + reg = <0x4260>; + }; +}; diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts new file mode 100644 index 00000000000000..ce1375595e5f27 --- /dev/null +++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts @@ -0,0 +1,229 @@ +/* + * at91-sama5d3_xplained.dts - Device Tree file for the SAMA5D3 Xplained board + * + * Copyright (C) 2014 Atmel, + * 2014 Nicolas Ferre + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d36.dtsi" + +/ { + model = "SAMA5D3 Xplained"; + compatible = "atmel,sama5d3-xplained", "atmel,sama5d3", "atmel,sama5"; + + chosen { + bootargs = "console=ttyS0,115200"; + }; + + memory { + reg = <0x20000000 0x10000000>; + }; + + ahb { + apb { + mmc0: mmc@f0000000 { + pinctrl-0 = <&pinctrl_mmc0_clk_cmd_dat0 &pinctrl_mmc0_dat1_3 &pinctrl_mmc0_dat4_7 &pinctrl_mmc0_cd>; + status = "okay"; + slot@0 { + reg = <0>; + bus-width = <8>; + cd-gpios = <&pioE 0 GPIO_ACTIVE_LOW>; + }; + }; + + spi0: spi@f0004000 { + cs-gpios = <&pioD 13 0>; + status = "okay"; + }; + + can0: can@f000c000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb0: ethernet@f0028000 { + phy-mode = "rgmii"; + status = "okay"; + }; + + usart0: serial@f001c000 { + status = "okay"; + }; + + usart1: serial@f0020000 { + pinctrl-0 = <&pinctrl_usart1 &pinctrl_usart1_rts_cts>; + status = "okay"; + }; + + uart0: serial@f0024000 { + status = "okay"; + }; + + mmc1: mmc@f8000000 { + pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3 &pinctrl_mmc1_cd>; + status = "okay"; + slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioE 1 GPIO_ACTIVE_HIGH>; + }; + }; + + spi1: spi@f8008000 { + cs-gpios = <&pioC 25 0>, <0>, <0>, <&pioD 16 0>; + status = "okay"; + }; + + adc0: adc@f8018000 { + pinctrl-0 = < + &pinctrl_adc0_adtrg + &pinctrl_adc0_ad0 + &pinctrl_adc0_ad1 + &pinctrl_adc0_ad2 + &pinctrl_adc0_ad3 + &pinctrl_adc0_ad4 + &pinctrl_adc0_ad5 + &pinctrl_adc0_ad6 + &pinctrl_adc0_ad7 + &pinctrl_adc0_ad8 + &pinctrl_adc0_ad9 + >; + status = "okay"; + }; + + i2c2: i2c@f801c000 { + dmas = <0>, <0>; /* Do not use DMA for i2c2 */ + status = "okay"; + }; + + macb1: ethernet@f802c000 { + phy-mode = "rmii"; + status = "okay"; + }; + + dbgu: serial@ffffee00 { + status = "okay"; + }; + + pinctrl@fffff200 { + board { + pinctrl_mmc0_cd: mmc0_cd { + atmel,pins = + ; + }; + + pinctrl_mmc1_cd: mmc1_cd { + atmel,pins = + ; + }; + + pinctrl_usba_vbus: usba_vbus { + atmel,pins = + ; /* PE9, conflicts with A9 */ + }; + }; + }; + + pmc: pmc@fffffc00 { + main: mainck { + clock-frequency = <12000000>; + }; + }; + }; + + nand0: nand@60000000 { + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + atmel,has-pmecc; + atmel,pmecc-cap = <4>; + atmel,pmecc-sector-size = <512>; + nand-on-flash-bbt; + status = "okay"; + + at91bootstrap@0 { + label = "at91bootstrap"; + reg = <0x0 0x40000>; + }; + + bootloader@40000 { + label = "bootloader"; + reg = <0x40000 0x80000>; + }; + + bootloaderenv@c0000 { + label = "bootloader env"; + reg = <0xc0000 0xc0000>; + }; + + dtb@180000 { + label = "device tree"; + reg = <0x180000 0x80000>; + }; + + kernel@200000 { + label = "kernel"; + reg = <0x200000 0x600000>; + }; + + rootfs@800000 { + label = "rootfs"; + reg = <0x800000 0x0f800000>; + }; + }; + + usb0: gadget@00500000 { + atmel,vbus-gpio = <&pioE 9 GPIO_ACTIVE_HIGH>; /* PE9, conflicts with A9 */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usba_vbus>; + status = "okay"; + }; + + usb1: ohci@00600000 { + num-ports = <3>; + atmel,vbus-gpio = <0 + &pioE 3 GPIO_ACTIVE_LOW + &pioE 4 GPIO_ACTIVE_LOW + >; + status = "okay"; + }; + + usb2: ehci@00700000 { + status = "okay"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + bp3 { + label = "PB_USER"; + gpios = <&pioE 29 GPIO_ACTIVE_LOW>; + linux,code = <0x104>; + gpio-key,wakeup; + }; + }; + + leds { + compatible = "gpio-leds"; + + d2 { + label = "d2"; + gpios = <&pioE 23 GPIO_ACTIVE_LOW>; /* PE23, conflicts with A23, CTS2 */ + linux,default-trigger = "heartbeat"; + }; + + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; +}; diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi index 56ee8282a7a8ef..997901f7ed7381 100644 --- a/arch/arm/boot/dts/at91sam9260.dtsi +++ b/arch/arm/boot/dts/at91sam9260.dtsi @@ -648,6 +648,11 @@ watchdog@fffffd40 { compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffd40 0x10>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + atmel,watchdog-type = "hardware"; + atmel,reset-type = "all"; + atmel,dbg-halt; + atmel,idle-halt; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi index c8fa9b9f07e34e..fece8665fb63ad 100644 --- a/arch/arm/boot/dts/at91sam9263.dtsi +++ b/arch/arm/boot/dts/at91sam9263.dtsi @@ -523,7 +523,7 @@ }; i2c0: i2c@fff88000 { - compatible = "atmel,at91sam9263-i2c"; + compatible = "atmel,at91sam9260-i2c"; reg = <0xfff88000 0x100>; interrupts = <13 IRQ_TYPE_LEVEL_HIGH 6>; #address-cells = <1>; @@ -552,6 +552,11 @@ watchdog@fffffd40 { compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffd40 0x10>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + atmel,watchdog-type = "hardware"; + atmel,reset-type = "all"; + atmel,dbg-halt; + atmel,idle-halt; status = "disabled"; }; diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index ef0857cb171c4a..cbcc058b26b4eb 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi @@ -706,6 +706,11 @@ watchdog@fffffd40 { compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffd40 0x10>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + atmel,watchdog-type = "hardware"; + atmel,reset-type = "all"; + atmel,dbg-halt; + atmel,idle-halt; status = "disabled"; }; diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi index 7248270a3ea615..394e6ce2afb755 100644 --- a/arch/arm/boot/dts/at91sam9n12.dtsi +++ b/arch/arm/boot/dts/at91sam9n12.dtsi @@ -541,6 +541,11 @@ watchdog@fffffe40 { compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffe40 0x10>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + atmel,watchdog-type = "hardware"; + atmel,reset-type = "all"; + atmel,dbg-halt; + atmel,idle-halt; status = "disabled"; }; diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts index e9487f6f016604..924a6a6ffd0f0a 100644 --- a/arch/arm/boot/dts/at91sam9n12ek.dts +++ b/arch/arm/boot/dts/at91sam9n12ek.dts @@ -124,6 +124,10 @@ nand-on-flash-bbt; status = "okay"; }; + + usb0: ohci@00500000 { + status = "okay"; + }; }; leds { diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index 6e5e9cfc3c4997..174219de92fa73 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi @@ -754,6 +754,11 @@ watchdog@fffffe40 { compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffe40 0x10>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + atmel,watchdog-type = "hardware"; + atmel,reset-type = "all"; + atmel,dbg-halt; + atmel,idle-halt; status = "disabled"; }; diff --git a/arch/arm/boot/dts/bcm11351-brt.dts b/arch/arm/boot/dts/bcm11351-brt.dts index 23cd16d736bf78..396b70459cdc0b 100644 --- a/arch/arm/boot/dts/bcm11351-brt.dts +++ b/arch/arm/boot/dts/bcm11351-brt.dts @@ -44,5 +44,11 @@ status = "okay"; }; + usbotg: usb@3f120000 { + status = "okay"; + }; + usbphy: usb-phy@3f130000 { + status = "okay"; + }; }; diff --git a/arch/arm/boot/dts/bcm11351.dtsi b/arch/arm/boot/dts/bcm11351.dtsi index dd8e878741c098..e491b82f8d6709 100644 --- a/arch/arm/boot/dts/bcm11351.dtsi +++ b/arch/arm/boot/dts/bcm11351.dtsi @@ -43,7 +43,7 @@ compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart"; status = "disabled"; reg = <0x3e000000 0x1000>; - clock-frequency = <13000000>; + clocks = <&uartb_clk>; interrupts = ; reg-shift = <2>; reg-io-width = <4>; @@ -53,7 +53,7 @@ compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart"; status = "disabled"; reg = <0x3e001000 0x1000>; - clock-frequency = <13000000>; + clocks = <&uartb2_clk>; interrupts = ; reg-shift = <2>; reg-io-width = <4>; @@ -63,7 +63,7 @@ compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart"; status = "disabled"; reg = <0x3e002000 0x1000>; - clock-frequency = <13000000>; + clocks = <&uartb3_clk>; interrupts = ; reg-shift = <2>; reg-io-width = <4>; @@ -73,7 +73,7 @@ compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart"; status = "disabled"; reg = <0x3e003000 0x1000>; - clock-frequency = <13000000>; + clocks = <&uartb4_clk>; interrupts = ; reg-shift = <2>; reg-io-width = <4>; @@ -95,7 +95,7 @@ compatible = "brcm,kona-timer"; reg = <0x35006000 0x1000>; interrupts = ; - clock-frequency = <32768>; + clocks = <&hub_timer_clk>; }; gpio: gpio@35003000 { @@ -118,6 +118,7 @@ compatible = "brcm,kona-sdhci"; reg = <0x3f180000 0x10000>; interrupts = ; + clocks = <&sdio1_clk>; status = "disabled"; }; @@ -125,6 +126,7 @@ compatible = "brcm,kona-sdhci"; reg = <0x3f190000 0x10000>; interrupts = ; + clocks = <&sdio2_clk>; status = "disabled"; }; @@ -132,6 +134,7 @@ compatible = "brcm,kona-sdhci"; reg = <0x3f1a0000 0x10000>; interrupts = ; + clocks = <&sdio3_clk>; status = "disabled"; }; @@ -139,6 +142,7 @@ compatible = "brcm,kona-sdhci"; reg = <0x3f1b0000 0x10000>; interrupts = ; + clocks = <&sdio4_clk>; status = "disabled"; }; @@ -146,4 +150,160 @@ compatible = "brcm,capri-pinctrl"; reg = <0x35004800 0x430>; }; + + i2c@3e016000 { + compatible = "brcm,bcm11351-i2c", "brcm,kona-i2c"; + reg = <0x3e016000 0x80>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&bsc1_clk>; + status = "disabled"; + }; + + i2c@3e017000 { + compatible = "brcm,bcm11351-i2c", "brcm,kona-i2c"; + reg = <0x3e017000 0x80>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&bsc2_clk>; + status = "disabled"; + }; + + i2c@3e018000 { + compatible = "brcm,bcm11351-i2c", "brcm,kona-i2c"; + reg = <0x3e018000 0x80>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&bsc3_clk>; + status = "disabled"; + }; + + i2c@3500d000 { + compatible = "brcm,bcm11351-i2c", "brcm,kona-i2c"; + reg = <0x3500d000 0x80>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmu_bsc_clk>; + status = "disabled"; + }; + + clocks { + bsc1_clk: bsc1 { + compatible = "fixed-clock"; + clock-frequency = <13000000>; + #clock-cells = <0>; + }; + + bsc2_clk: bsc2 { + compatible = "fixed-clock"; + clock-frequency = <13000000>; + #clock-cells = <0>; + }; + + bsc3_clk: bsc3 { + compatible = "fixed-clock"; + clock-frequency = <13000000>; + #clock-cells = <0>; + }; + + pmu_bsc_clk: pmu_bsc { + compatible = "fixed-clock"; + clock-frequency = <13000000>; + #clock-cells = <0>; + }; + + hub_timer_clk: hub_timer { + compatible = "fixed-clock"; + clock-frequency = <32768>; + #clock-cells = <0>; + }; + + pwm_clk: pwm { + compatible = "fixed-clock"; + clock-frequency = <26000000>; + #clock-cells = <0>; + }; + + sdio1_clk: sdio1 { + compatible = "fixed-clock"; + clock-frequency = <48000000>; + #clock-cells = <0>; + }; + + sdio2_clk: sdio2 { + compatible = "fixed-clock"; + clock-frequency = <48000000>; + #clock-cells = <0>; + }; + + sdio3_clk: sdio3 { + compatible = "fixed-clock"; + clock-frequency = <48000000>; + #clock-cells = <0>; + }; + + sdio4_clk: sdio4 { + compatible = "fixed-clock"; + clock-frequency = <48000000>; + #clock-cells = <0>; + }; + + tmon_1m_clk: tmon_1m { + compatible = "fixed-clock"; + clock-frequency = <1000000>; + #clock-cells = <0>; + }; + + uartb_clk: uartb { + compatible = "fixed-clock"; + clock-frequency = <13000000>; + #clock-cells = <0>; + }; + + uartb2_clk: uartb2 { + compatible = "fixed-clock"; + clock-frequency = <13000000>; + #clock-cells = <0>; + }; + + uartb3_clk: uartb3 { + compatible = "fixed-clock"; + clock-frequency = <13000000>; + #clock-cells = <0>; + }; + + uartb4_clk: uartb4 { + compatible = "fixed-clock"; + clock-frequency = <13000000>; + #clock-cells = <0>; + }; + + usb_otg_ahb_clk: usb_otg_ahb { + compatible = "fixed-clock"; + clock-frequency = <52000000>; + #clock-cells = <0>; + }; + }; + + usbotg: usb@3f120000 { + compatible = "snps,dwc2"; + reg = <0x3f120000 0x10000>; + interrupts = ; + clocks = <&usb_otg_ahb_clk>; + clock-names = "otg"; + phys = <&usbphy>; + phy-names = "usb2-phy"; + status = "disabled"; + }; + + usbphy: usb-phy@3f130000 { + compatible = "brcm,kona-usb2-phy"; + reg = <0x3f130000 0x28>; + #phy-cells = <0>; + status = "disabled"; + }; }; diff --git a/arch/arm/boot/dts/bcm28155-ap.dts b/arch/arm/boot/dts/bcm28155-ap.dts index 08e47c285227a9..5ff2382a49e413 100644 --- a/arch/arm/boot/dts/bcm28155-ap.dts +++ b/arch/arm/boot/dts/bcm28155-ap.dts @@ -13,6 +13,8 @@ /dts-v1/; +#include + #include "bcm11351.dtsi" / { @@ -27,6 +29,26 @@ status = "okay"; }; + i2c@3e016000 { + status="okay"; + clock-frequency = <400000>; + }; + + i2c@3e017000 { + status="okay"; + clock-frequency = <400000>; + }; + + i2c@3e018000 { + status="okay"; + clock-frequency = <400000>; + }; + + i2c@3500d000 { + status="okay"; + clock-frequency = <400000>; + }; + sdio1: sdio@3f180000 { max-frequency = <48000000>; status = "okay"; @@ -40,7 +62,15 @@ sdio4: sdio@3f1b0000 { max-frequency = <48000000>; - cd-gpios = <&gpio 14 0>; + cd-gpios = <&gpio 14 GPIO_ACTIVE_LOW>; + status = "okay"; + }; + + usbotg: usb@3f120000 { + status = "okay"; + }; + + usbphy: usb-phy@3f130000 { status = "okay"; }; }; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index d0df4c4e8b0a1b..1fd75aa4639da2 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -104,6 +104,45 @@ interrupts = , ; + prm: prm@4ae06000 { + compatible = "ti,dra7-prm"; + reg = <0x4ae06000 0x3000>; + + prm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + prm_clockdomains: clockdomains { + }; + }; + + cm_core_aon: cm_core_aon@4a005000 { + compatible = "ti,dra7-cm-core-aon"; + reg = <0x4a005000 0x2000>; + + cm_core_aon_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + cm_core_aon_clockdomains: clockdomains { + }; + }; + + cm_core: cm_core@4a008000 { + compatible = "ti,dra7-cm-core"; + reg = <0x4a008000 0x3000>; + + cm_core_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + cm_core_clockdomains: clockdomains { + }; + }; + counter32k: counter@4ae04000 { compatible = "ti,omap-counter32k"; reg = <0x4ae04000 0x40>; @@ -584,3 +623,5 @@ }; }; }; + +/include/ "dra7xx-clocks.dtsi" diff --git a/arch/arm/boot/dts/dra7xx-clocks.dtsi b/arch/arm/boot/dts/dra7xx-clocks.dtsi new file mode 100644 index 00000000000000..e96da9a898ad5c --- /dev/null +++ b/arch/arm/boot/dts/dra7xx-clocks.dtsi @@ -0,0 +1,2015 @@ +/* + * Device Tree Source for DRA7xx clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * 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. + */ +&cm_core_aon_clocks { + atl_clkin0_ck: atl_clkin0_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + atl_clkin1_ck: atl_clkin1_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + atl_clkin2_ck: atl_clkin2_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + atlclkin3_ck: atlclkin3_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + hdmi_clkin_ck: hdmi_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + mlb_clkin_ck: mlb_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + mlbp_clkin_ck: mlbp_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + pciesref_acs_clk_ck: pciesref_acs_clk_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <100000000>; + }; + + ref_clkin0_ck: ref_clkin0_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + ref_clkin1_ck: ref_clkin1_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + ref_clkin2_ck: ref_clkin2_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + ref_clkin3_ck: ref_clkin3_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + rmii_clk_ck: rmii_clk_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + sdvenc_clkin_ck: sdvenc_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + secure_32k_clk_src_ck: secure_32k_clk_src_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + sys_32k_ck: sys_32k_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + virt_12000000_ck: virt_12000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + virt_13000000_ck: virt_13000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <13000000>; + }; + + virt_16800000_ck: virt_16800000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <16800000>; + }; + + virt_19200000_ck: virt_19200000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <19200000>; + }; + + virt_20000000_ck: virt_20000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <20000000>; + }; + + virt_26000000_ck: virt_26000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <26000000>; + }; + + virt_27000000_ck: virt_27000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <27000000>; + }; + + virt_38400000_ck: virt_38400000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <38400000>; + }; + + sys_clkin2: sys_clkin2 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <22579200>; + }; + + usb_otg_clkin_ck: usb_otg_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + video1_clkin_ck: video1_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + video1_m2_clkin_ck: video1_m2_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + video2_clkin_ck: video2_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + video2_m2_clkin_ck: video2_m2_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + dpll_abe_ck: dpll_abe_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-m4xen-clock"; + clocks = <&abe_dpll_clk_mux>, <&abe_dpll_bypass_clk_mux>; + reg = <0x01e0>, <0x01e4>, <0x01ec>, <0x01e8>; + }; + + dpll_abe_x2_ck: dpll_abe_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_abe_ck>; + }; + + dpll_abe_m2x2_ck: dpll_abe_m2x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01f0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + abe_clk: abe_clk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_m2x2_ck>; + ti,max-div = <4>; + reg = <0x0108>; + ti,index-power-of-two; + }; + + dpll_abe_m2_ck: dpll_abe_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01f0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_abe_m3x2_ck: dpll_abe_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01f4>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_ck: dpll_core_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-core-clock"; + clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>; + reg = <0x0120>, <0x0124>, <0x012c>, <0x0128>; + }; + + dpll_core_x2_ck: dpll_core_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_core_ck>; + }; + + dpll_core_h12x2_ck: dpll_core_h12x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x013c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + mpu_dpll_hs_clk_div: mpu_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h12x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_mpu_ck: dpll_mpu_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&mpu_dpll_hs_clk_div>; + reg = <0x0160>, <0x0164>, <0x016c>, <0x0168>; + }; + + dpll_mpu_m2_ck: dpll_mpu_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_mpu_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0170>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + mpu_dclk_div: mpu_dclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_mpu_m2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dsp_dpll_hs_clk_div: dsp_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h12x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_dsp_ck: dpll_dsp_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&dsp_dpll_hs_clk_div>; + reg = <0x0234>, <0x0238>, <0x0240>, <0x023c>; + }; + + dpll_dsp_m2_ck: dpll_dsp_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_dsp_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0244>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + iva_dpll_hs_clk_div: iva_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h12x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_iva_ck: dpll_iva_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&iva_dpll_hs_clk_div>; + reg = <0x01a0>, <0x01a4>, <0x01ac>, <0x01a8>; + }; + + dpll_iva_m2_ck: dpll_iva_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_iva_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01b0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + iva_dclk: iva_dclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_iva_m2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_gpu_ck: dpll_gpu_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>; + reg = <0x02d8>, <0x02dc>, <0x02e4>, <0x02e0>; + }; + + dpll_gpu_m2_ck: dpll_gpu_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gpu_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x02e8>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_m2_ck: dpll_core_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0130>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + core_dpll_out_dclk_div: core_dpll_out_dclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_ddr_ck: dpll_ddr_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>; + reg = <0x0210>, <0x0214>, <0x021c>, <0x0218>; + }; + + dpll_ddr_m2_ck: dpll_ddr_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_ddr_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0220>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_gmac_ck: dpll_gmac_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>; + reg = <0x02a8>, <0x02ac>, <0x02b4>, <0x02b0>; + }; + + dpll_gmac_m2_ck: dpll_gmac_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gmac_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x02b8>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + video2_dclk_div: video2_dclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&video2_m2_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + video1_dclk_div: video1_dclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&video1_m2_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + hdmi_dclk_div: hdmi_dclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&hdmi_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + per_dpll_hs_clk_div: per_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m3x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + usb_dpll_hs_clk_div: usb_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m3x2_ck>; + clock-mult = <1>; + clock-div = <3>; + }; + + eve_dpll_hs_clk_div: eve_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h12x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_eve_ck: dpll_eve_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&eve_dpll_hs_clk_div>; + reg = <0x0284>, <0x0288>, <0x0290>, <0x028c>; + }; + + dpll_eve_m2_ck: dpll_eve_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_eve_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0294>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + eve_dclk_div: eve_dclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_eve_m2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_core_h13x2_ck: dpll_core_h13x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0140>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h14x2_ck: dpll_core_h14x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0144>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h22x2_ck: dpll_core_h22x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0154>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h23x2_ck: dpll_core_h23x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0158>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h24x2_ck: dpll_core_h24x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x015c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_ddr_x2_ck: dpll_ddr_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_ddr_ck>; + }; + + dpll_ddr_h11x2_ck: dpll_ddr_h11x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_ddr_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0228>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_dsp_x2_ck: dpll_dsp_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_dsp_ck>; + }; + + dpll_dsp_m3x2_ck: dpll_dsp_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_dsp_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0248>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_gmac_x2_ck: dpll_gmac_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_gmac_ck>; + }; + + dpll_gmac_h11x2_ck: dpll_gmac_h11x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gmac_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x02c0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_gmac_h12x2_ck: dpll_gmac_h12x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gmac_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x02c4>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_gmac_h13x2_ck: dpll_gmac_h13x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gmac_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x02c8>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_gmac_m3x2_ck: dpll_gmac_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gmac_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x02bc>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + gmii_m_clk_div: gmii_m_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_gmac_h11x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + hdmi_clk2_div: hdmi_clk2_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&hdmi_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + hdmi_div_clk: hdmi_div_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&hdmi_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l3_iclk_div: l3_iclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h12x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l4_root_clk_div: l4_root_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l3_iclk_div>; + clock-mult = <1>; + clock-div = <1>; + }; + + video1_clk2_div: video1_clk2_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&video1_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + video1_div_clk: video1_div_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&video1_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + video2_clk2_div: video2_clk2_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&video2_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + video2_div_clk: video2_div_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&video2_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + ipu1_gfclk_mux: ipu1_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_abe_m2x2_ck>, <&dpll_core_h22x2_ck>; + ti,bit-shift = <24>; + reg = <0x0520>; + }; + + mcasp1_ahclkr_mux: mcasp1_ahclkr_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <28>; + reg = <0x0550>; + }; + + mcasp1_ahclkx_mux: mcasp1_ahclkx_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <24>; + reg = <0x0550>; + }; + + mcasp1_aux_gfclk_mux: mcasp1_aux_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; + ti,bit-shift = <22>; + reg = <0x0550>; + }; + + timer5_gfclk_mux: timer5_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>, <&clkoutmux0_clk_mux>; + ti,bit-shift = <24>; + reg = <0x0558>; + }; + + timer6_gfclk_mux: timer6_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>, <&clkoutmux0_clk_mux>; + ti,bit-shift = <24>; + reg = <0x0560>; + }; + + timer7_gfclk_mux: timer7_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>, <&clkoutmux0_clk_mux>; + ti,bit-shift = <24>; + reg = <0x0568>; + }; + + timer8_gfclk_mux: timer8_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>, <&clkoutmux0_clk_mux>; + ti,bit-shift = <24>; + reg = <0x0570>; + }; + + uart6_gfclk_mux: uart6_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x0580>; + }; + + dummy_ck: dummy_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; +}; +&prm_clocks { + sys_clkin1: sys_clkin1 { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&virt_12000000_ck>, <&virt_20000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>; + reg = <0x0110>; + ti,index-starts-at-one; + }; + + abe_dpll_sys_clk_mux: abe_dpll_sys_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin1>, <&sys_clkin2>; + reg = <0x0118>; + }; + + abe_dpll_bypass_clk_mux: abe_dpll_bypass_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_dpll_sys_clk_mux>, <&sys_32k_ck>; + reg = <0x0114>; + }; + + abe_dpll_clk_mux: abe_dpll_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_dpll_sys_clk_mux>, <&sys_32k_ck>; + reg = <0x010c>; + }; + + abe_24m_fclk: abe_24m_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_m2x2_ck>; + reg = <0x011c>; + ti,dividers = <8>, <16>; + }; + + aess_fclk: aess_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&abe_clk>; + reg = <0x0178>; + ti,max-div = <2>; + }; + + abe_giclk_div: abe_giclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&aess_fclk>; + reg = <0x0174>; + ti,max-div = <2>; + }; + + abe_lp_clk_div: abe_lp_clk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_m2x2_ck>; + reg = <0x01d8>; + ti,dividers = <16>, <32>; + }; + + abe_sys_clk_div: abe_sys_clk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sys_clkin1>; + reg = <0x0120>; + ti,max-div = <2>; + }; + + adc_gfclk_mux: adc_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin1>, <&sys_clkin2>, <&sys_32k_ck>; + reg = <0x01dc>; + }; + + sys_clk1_dclk_div: sys_clk1_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sys_clkin1>; + ti,max-div = <64>; + reg = <0x01c8>; + ti,index-power-of-two; + }; + + sys_clk2_dclk_div: sys_clk2_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sys_clkin2>; + ti,max-div = <64>; + reg = <0x01cc>; + ti,index-power-of-two; + }; + + per_abe_x1_dclk_div: per_abe_x1_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_m2_ck>; + ti,max-div = <64>; + reg = <0x01bc>; + ti,index-power-of-two; + }; + + dsp_gclk_div: dsp_gclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_dsp_m2_ck>; + ti,max-div = <64>; + reg = <0x018c>; + ti,index-power-of-two; + }; + + gpu_dclk: gpu_dclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gpu_m2_ck>; + ti,max-div = <64>; + reg = <0x01a0>; + ti,index-power-of-two; + }; + + emif_phy_dclk_div: emif_phy_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_ddr_m2_ck>; + ti,max-div = <64>; + reg = <0x0190>; + ti,index-power-of-two; + }; + + gmac_250m_dclk_div: gmac_250m_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gmac_m2_ck>; + ti,max-div = <64>; + reg = <0x019c>; + ti,index-power-of-two; + }; + + l3init_480m_dclk_div: l3init_480m_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_m2_ck>; + ti,max-div = <64>; + reg = <0x01ac>; + ti,index-power-of-two; + }; + + usb_otg_dclk_div: usb_otg_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&usb_otg_clkin_ck>; + ti,max-div = <64>; + reg = <0x0184>; + ti,index-power-of-two; + }; + + sata_dclk_div: sata_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sys_clkin1>; + ti,max-div = <64>; + reg = <0x01c0>; + ti,index-power-of-two; + }; + + pcie2_dclk_div: pcie2_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_pcie_ref_m2_ck>; + ti,max-div = <64>; + reg = <0x01b8>; + ti,index-power-of-two; + }; + + pcie_dclk_div: pcie_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&apll_pcie_m2_ck>; + ti,max-div = <64>; + reg = <0x01b4>; + ti,index-power-of-two; + }; + + emu_dclk_div: emu_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sys_clkin1>; + ti,max-div = <64>; + reg = <0x0194>; + ti,index-power-of-two; + }; + + secure_32k_dclk_div: secure_32k_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&secure_32k_clk_src_ck>; + ti,max-div = <64>; + reg = <0x01c4>; + ti,index-power-of-two; + }; + + clkoutmux0_clk_mux: clkoutmux0_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clk1_dclk_div>, <&sys_clk2_dclk_div>, <&per_abe_x1_dclk_div>, <&mpu_dclk_div>, <&dsp_gclk_div>, <&iva_dclk>, <&gpu_dclk>, <&core_dpll_out_dclk_div>, <&emif_phy_dclk_div>, <&gmac_250m_dclk_div>, <&video2_dclk_div>, <&video1_dclk_div>, <&hdmi_dclk_div>, <&func_96m_aon_dclk_div>, <&l3init_480m_dclk_div>, <&usb_otg_dclk_div>, <&sata_dclk_div>, <&pcie2_dclk_div>, <&pcie_dclk_div>, <&emu_dclk_div>, <&secure_32k_dclk_div>, <&eve_dclk_div>; + reg = <0x0158>; + }; + + clkoutmux1_clk_mux: clkoutmux1_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clk1_dclk_div>, <&sys_clk2_dclk_div>, <&per_abe_x1_dclk_div>, <&mpu_dclk_div>, <&dsp_gclk_div>, <&iva_dclk>, <&gpu_dclk>, <&core_dpll_out_dclk_div>, <&emif_phy_dclk_div>, <&gmac_250m_dclk_div>, <&video2_dclk_div>, <&video1_dclk_div>, <&hdmi_dclk_div>, <&func_96m_aon_dclk_div>, <&l3init_480m_dclk_div>, <&usb_otg_dclk_div>, <&sata_dclk_div>, <&pcie2_dclk_div>, <&pcie_dclk_div>, <&emu_dclk_div>, <&secure_32k_dclk_div>, <&eve_dclk_div>; + reg = <0x015c>; + }; + + clkoutmux2_clk_mux: clkoutmux2_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clk1_dclk_div>, <&sys_clk2_dclk_div>, <&per_abe_x1_dclk_div>, <&mpu_dclk_div>, <&dsp_gclk_div>, <&iva_dclk>, <&gpu_dclk>, <&core_dpll_out_dclk_div>, <&emif_phy_dclk_div>, <&gmac_250m_dclk_div>, <&video2_dclk_div>, <&video1_dclk_div>, <&hdmi_dclk_div>, <&func_96m_aon_dclk_div>, <&l3init_480m_dclk_div>, <&usb_otg_dclk_div>, <&sata_dclk_div>, <&pcie2_dclk_div>, <&pcie_dclk_div>, <&emu_dclk_div>, <&secure_32k_dclk_div>, <&eve_dclk_div>; + reg = <0x0160>; + }; + + custefuse_sys_gfclk_div: custefuse_sys_gfclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin1>; + clock-mult = <1>; + clock-div = <2>; + }; + + eve_clk: eve_clk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_eve_m2_ck>, <&dpll_dsp_m3x2_ck>; + reg = <0x0180>; + }; + + hdmi_dpll_clk_mux: hdmi_dpll_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin1>, <&sys_clkin2>; + reg = <0x01a4>; + }; + + mlb_clk: mlb_clk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mlb_clkin_ck>; + ti,max-div = <64>; + reg = <0x0134>; + ti,index-power-of-two; + }; + + mlbp_clk: mlbp_clk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mlbp_clkin_ck>; + ti,max-div = <64>; + reg = <0x0130>; + ti,index-power-of-two; + }; + + per_abe_x1_gfclk2_div: per_abe_x1_gfclk2_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_m2_ck>; + ti,max-div = <64>; + reg = <0x0138>; + ti,index-power-of-two; + }; + + timer_sys_clk_div: timer_sys_clk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sys_clkin1>; + reg = <0x0144>; + ti,max-div = <2>; + }; + + video1_dpll_clk_mux: video1_dpll_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin1>, <&sys_clkin2>; + reg = <0x01d0>; + }; + + video2_dpll_clk_mux: video2_dpll_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin1>, <&sys_clkin2>; + reg = <0x01d4>; + }; + + wkupaon_iclk_mux: wkupaon_iclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin1>, <&abe_lp_clk_div>; + reg = <0x0108>; + }; + + gpio1_dbclk: gpio1_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1838>; + }; + + dcan1_sys_clk_mux: dcan1_sys_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin1>, <&sys_clkin2>; + ti,bit-shift = <24>; + reg = <0x1888>; + }; + + timer1_gfclk_mux: timer1_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x1840>; + }; + + uart10_gfclk_mux: uart10_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1880>; + }; +}; +&cm_core_clocks { + dpll_pcie_ref_ck: dpll_pcie_ref_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&sys_clkin1>; + reg = <0x0200>, <0x0204>, <0x020c>, <0x0208>; + }; + + dpll_pcie_ref_m2ldo_ck: dpll_pcie_ref_m2ldo_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_pcie_ref_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0210>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + apll_pcie_in_clk_mux: apll_pcie_in_clk_mux@4ae06118 { + compatible = "ti,mux-clock"; + clocks = <&dpll_pcie_ref_ck>, <&pciesref_acs_clk_ck>; + #clock-cells = <0>; + reg = <0x021c 0x4>; + ti,bit-shift = <7>; + }; + + apll_pcie_ck: apll_pcie_ck { + #clock-cells = <0>; + compatible = "ti,dra7-apll-clock"; + clocks = <&apll_pcie_in_clk_mux>, <&dpll_pcie_ref_ck>; + reg = <0x021c>, <0x0220>; + }; + + optfclk_pciephy_div: optfclk_pciephy_div@4a00821c { + compatible = "ti,divider-clock"; + clocks = <&apll_pcie_ck>; + #clock-cells = <0>; + reg = <0x021c>; + ti,bit-shift = <8>; + ti,max-div = <2>; + }; + + optfclk_pciephy_clk: optfclk_pciephy_clk@4a0093b0 { + compatible = "ti,gate-clock"; + clocks = <&apll_pcie_ck>; + #clock-cells = <0>; + reg = <0x13b0>; + ti,bit-shift = <9>; + }; + + optfclk_pciephy_div_clk: optfclk_pciephy_div_clk@4a0093b0 { + compatible = "ti,gate-clock"; + clocks = <&optfclk_pciephy_div>; + #clock-cells = <0>; + reg = <0x13b0>; + ti,bit-shift = <10>; + }; + + apll_pcie_clkvcoldo: apll_pcie_clkvcoldo { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&apll_pcie_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + apll_pcie_clkvcoldo_div: apll_pcie_clkvcoldo_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&apll_pcie_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + apll_pcie_m2_ck: apll_pcie_m2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&apll_pcie_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_per_ck: dpll_per_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&per_dpll_hs_clk_div>; + reg = <0x0140>, <0x0144>, <0x014c>, <0x0148>; + }; + + dpll_per_m2_ck: dpll_per_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0150>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + func_96m_aon_dclk_div: func_96m_aon_dclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_usb_ck: dpll_usb_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-j-type-clock"; + clocks = <&sys_clkin1>, <&usb_dpll_hs_clk_div>; + reg = <0x0180>, <0x0184>, <0x018c>, <0x0188>; + }; + + dpll_usb_m2_ck: dpll_usb_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_ck>; + ti,max-div = <127>; + ti,autoidle-shift = <8>; + reg = <0x0190>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_pcie_ref_m2_ck: dpll_pcie_ref_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_pcie_ref_ck>; + ti,max-div = <127>; + ti,autoidle-shift = <8>; + reg = <0x0210>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_x2_ck: dpll_per_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_per_ck>; + }; + + dpll_per_h11x2_ck: dpll_per_h11x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0158>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_h12x2_ck: dpll_per_h12x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x015c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_h13x2_ck: dpll_per_h13x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0160>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_h14x2_ck: dpll_per_h14x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0164>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m2x2_ck: dpll_per_m2x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0150>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_usb_clkdcoldo: dpll_usb_clkdcoldo { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_usb_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + func_128m_clk: func_128m_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_h11x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + func_12m_fclk: func_12m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <16>; + }; + + func_24m_clk: func_24m_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + func_48m_fclk: func_48m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + func_96m_fclk: func_96m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + l3init_60m_fclk: l3init_60m_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_m2_ck>; + reg = <0x0104>; + ti,dividers = <1>, <8>; + }; + + dss_32khz_clk: dss_32khz_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <11>; + reg = <0x1120>; + }; + + dss_48mhz_clk: dss_48mhz_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_48m_fclk>; + ti,bit-shift = <9>; + reg = <0x1120>; + }; + + dss_dss_clk: dss_dss_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_per_h12x2_ck>; + ti,bit-shift = <8>; + reg = <0x1120>; + }; + + dss_hdmi_clk: dss_hdmi_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&hdmi_dpll_clk_mux>; + ti,bit-shift = <10>; + reg = <0x1120>; + }; + + dss_video1_clk: dss_video1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&video1_dpll_clk_mux>; + ti,bit-shift = <12>; + reg = <0x1120>; + }; + + dss_video2_clk: dss_video2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&video2_dpll_clk_mux>; + ti,bit-shift = <13>; + reg = <0x1120>; + }; + + gpio2_dbclk: gpio2_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1760>; + }; + + gpio3_dbclk: gpio3_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1768>; + }; + + gpio4_dbclk: gpio4_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1770>; + }; + + gpio5_dbclk: gpio5_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1778>; + }; + + gpio6_dbclk: gpio6_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1780>; + }; + + gpio7_dbclk: gpio7_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1810>; + }; + + gpio8_dbclk: gpio8_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1818>; + }; + + mmc1_clk32k: mmc1_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1328>; + }; + + mmc2_clk32k: mmc2_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1330>; + }; + + mmc3_clk32k: mmc3_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1820>; + }; + + mmc4_clk32k: mmc4_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1828>; + }; + + sata_ref_clk: sata_ref_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_clkin1>; + ti,bit-shift = <8>; + reg = <0x1388>; + }; + + usb_otg_ss1_refclk960m: usb_otg_ss1_refclk960m { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_usb_clkdcoldo>; + ti,bit-shift = <8>; + reg = <0x13f0>; + }; + + usb_otg_ss2_refclk960m: usb_otg_ss2_refclk960m { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_usb_clkdcoldo>; + ti,bit-shift = <8>; + reg = <0x1340>; + }; + + usb_phy1_always_on_clk32k: usb_phy1_always_on_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x0640>; + }; + + usb_phy2_always_on_clk32k: usb_phy2_always_on_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x0688>; + }; + + usb_phy3_always_on_clk32k: usb_phy3_always_on_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x0698>; + }; + + atl_dpll_clk_mux: atl_dpll_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_32k_ck>, <&video1_clkin_ck>, <&video2_clkin_ck>, <&hdmi_clkin_ck>; + ti,bit-shift = <24>; + reg = <0x0c00>; + }; + + atl_gfclk_mux: atl_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&l3_iclk_div>, <&dpll_abe_m2_ck>, <&atl_dpll_clk_mux>; + ti,bit-shift = <26>; + reg = <0x0c00>; + }; + + gmac_gmii_ref_clk_div: gmac_gmii_ref_clk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gmac_m2_ck>; + ti,bit-shift = <24>; + reg = <0x13d0>; + ti,dividers = <2>; + }; + + gmac_rft_clk_mux: gmac_rft_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&video1_clkin_ck>, <&video2_clkin_ck>, <&dpll_abe_m2_ck>, <&hdmi_clkin_ck>, <&l3_iclk_div>; + ti,bit-shift = <25>; + reg = <0x13d0>; + }; + + gpu_core_gclk_mux: gpu_core_gclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_core_h14x2_ck>, <&dpll_per_h14x2_ck>, <&dpll_gpu_m2_ck>; + ti,bit-shift = <24>; + reg = <0x1220>; + }; + + gpu_hyd_gclk_mux: gpu_hyd_gclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_core_h14x2_ck>, <&dpll_per_h14x2_ck>, <&dpll_gpu_m2_ck>; + ti,bit-shift = <26>; + reg = <0x1220>; + }; + + l3instr_ts_gclk_div: l3instr_ts_gclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&wkupaon_iclk_mux>; + ti,bit-shift = <24>; + reg = <0x0e50>; + ti,dividers = <8>, <16>, <32>; + }; + + mcasp2_ahclkr_mux: mcasp2_ahclkr_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <28>; + reg = <0x1860>; + }; + + mcasp2_ahclkx_mux: mcasp2_ahclkx_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <28>; + reg = <0x1860>; + }; + + mcasp2_aux_gfclk_mux: mcasp2_aux_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; + ti,bit-shift = <22>; + reg = <0x1860>; + }; + + mcasp3_ahclkx_mux: mcasp3_ahclkx_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <24>; + reg = <0x1868>; + }; + + mcasp3_aux_gfclk_mux: mcasp3_aux_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; + ti,bit-shift = <22>; + reg = <0x1868>; + }; + + mcasp4_ahclkx_mux: mcasp4_ahclkx_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <24>; + reg = <0x1898>; + }; + + mcasp4_aux_gfclk_mux: mcasp4_aux_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; + ti,bit-shift = <22>; + reg = <0x1898>; + }; + + mcasp5_ahclkx_mux: mcasp5_ahclkx_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <24>; + reg = <0x1878>; + }; + + mcasp5_aux_gfclk_mux: mcasp5_aux_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; + ti,bit-shift = <22>; + reg = <0x1878>; + }; + + mcasp6_ahclkx_mux: mcasp6_ahclkx_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <24>; + reg = <0x1904>; + }; + + mcasp6_aux_gfclk_mux: mcasp6_aux_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; + ti,bit-shift = <22>; + reg = <0x1904>; + }; + + mcasp7_ahclkx_mux: mcasp7_ahclkx_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <24>; + reg = <0x1908>; + }; + + mcasp7_aux_gfclk_mux: mcasp7_aux_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; + ti,bit-shift = <22>; + reg = <0x1908>; + }; + + mcasp8_ahclk_mux: mcasp8_ahclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <22>; + reg = <0x1890>; + }; + + mcasp8_aux_gfclk_mux: mcasp8_aux_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; + ti,bit-shift = <24>; + reg = <0x1890>; + }; + + mmc1_fclk_mux: mmc1_fclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_128m_clk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1328>; + }; + + mmc1_fclk_div: mmc1_fclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mmc1_fclk_mux>; + ti,bit-shift = <25>; + ti,max-div = <4>; + reg = <0x1328>; + ti,index-power-of-two; + }; + + mmc2_fclk_mux: mmc2_fclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_128m_clk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1330>; + }; + + mmc2_fclk_div: mmc2_fclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mmc2_fclk_mux>; + ti,bit-shift = <25>; + ti,max-div = <4>; + reg = <0x1330>; + ti,index-power-of-two; + }; + + mmc3_gfclk_mux: mmc3_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1820>; + }; + + mmc3_gfclk_div: mmc3_gfclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mmc3_gfclk_mux>; + ti,bit-shift = <25>; + ti,max-div = <4>; + reg = <0x1820>; + ti,index-power-of-two; + }; + + mmc4_gfclk_mux: mmc4_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1828>; + }; + + mmc4_gfclk_div: mmc4_gfclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mmc4_gfclk_mux>; + ti,bit-shift = <25>; + ti,max-div = <4>; + reg = <0x1828>; + ti,index-power-of-two; + }; + + qspi_gfclk_mux: qspi_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_128m_clk>, <&dpll_per_h13x2_ck>; + ti,bit-shift = <24>; + reg = <0x1838>; + }; + + qspi_gfclk_div: qspi_gfclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&qspi_gfclk_mux>; + ti,bit-shift = <25>; + ti,max-div = <4>; + reg = <0x1838>; + ti,index-power-of-two; + }; + + timer10_gfclk_mux: timer10_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x1728>; + }; + + timer11_gfclk_mux: timer11_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x1730>; + }; + + timer13_gfclk_mux: timer13_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x17c8>; + }; + + timer14_gfclk_mux: timer14_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x17d0>; + }; + + timer15_gfclk_mux: timer15_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x17d8>; + }; + + timer16_gfclk_mux: timer16_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x1830>; + }; + + timer2_gfclk_mux: timer2_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x1738>; + }; + + timer3_gfclk_mux: timer3_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x1740>; + }; + + timer4_gfclk_mux: timer4_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x1748>; + }; + + timer9_gfclk_mux: timer9_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x1750>; + }; + + uart1_gfclk_mux: uart1_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1840>; + }; + + uart2_gfclk_mux: uart2_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1848>; + }; + + uart3_gfclk_mux: uart3_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1850>; + }; + + uart4_gfclk_mux: uart4_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1858>; + }; + + uart5_gfclk_mux: uart5_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1870>; + }; + + uart7_gfclk_mux: uart7_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x18d0>; + }; + + uart8_gfclk_mux: uart8_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x18e0>; + }; + + uart9_gfclk_mux: uart9_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x18e8>; + }; + + vip1_gclk_mux: vip1_gclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&l3_iclk_div>, <&dpll_core_h23x2_ck>; + ti,bit-shift = <24>; + reg = <0x1020>; + }; + + vip2_gclk_mux: vip2_gclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&l3_iclk_div>, <&dpll_core_h23x2_ck>; + ti,bit-shift = <24>; + reg = <0x1028>; + }; + + vip3_gclk_mux: vip3_gclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&l3_iclk_div>, <&dpll_core_h23x2_ck>; + ti,bit-shift = <24>; + reg = <0x1030>; + }; +}; + +&cm_core_clockdomains { + coreaon_clkdm: coreaon_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll_usb_ck>; + }; +}; diff --git a/arch/arm/boot/dts/imx6dl-cubox-i.dts b/arch/arm/boot/dts/imx6dl-cubox-i.dts new file mode 100644 index 00000000000000..58aa8f2b0f260f --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-cubox-i.dts @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2014 Russell King + */ +/dts-v1/; + +#include "imx6dl.dtsi" +#include "imx6qdl-cubox-i.dtsi" + +/ { + model = "SolidRun Cubox-i Solo/DualLite"; + compatible = "solidrun,cubox-i/dl", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6dl-hummingboard.dts b/arch/arm/boot/dts/imx6dl-hummingboard.dts new file mode 100644 index 00000000000000..5bfae54fb7806f --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-hummingboard.dts @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2013,2014 Russell King + */ +/dts-v1/; + +#include "imx6dl.dtsi" +#include "imx6qdl-microsom.dtsi" +#include "imx6qdl-microsom-ar8035.dtsi" + +/ { + model = "SolidRun HummingBoard DL/Solo"; + compatible = "solidrun,hummingboard", "fsl,imx6dl"; + + ir_recv: ir-receiver { + compatible = "gpio-ir-receiver"; + gpios = <&gpio1 2 1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard_gpio1_2>; + }; + + regulators { + compatible = "simple-bus"; + + reg_3p3v: 3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_usbh1_vbus: usb-h1-vbus { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio1 0 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard_usbh1_vbus>; + regulator-name = "usb_h1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + reg_usbotg_vbus: usb-otg-vbus { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio3 22 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard_usbotg_vbus>; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + }; + + sound-spdif { + compatible = "fsl,imx-audio-spdif"; + model = "imx-spdif"; + /* IMX6 doesn't implement this yet */ + spdif-controller = <&spdif>; + spdif-out; + }; +}; + +&can1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard_flexcan1>; + status = "okay"; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard_i2c1>; + + /* + * Not fitted on Carrier-1 board... yet + status = "okay"; + + rtc: pcf8523@68 { + compatible = "nxp,pcf8523"; + reg = <0x68>; + }; + */ +}; + +&iomuxc { + hummingboard { + pinctrl_hummingboard_flexcan1: hummingboard-flexcan1 { + fsl,pins = < + MX6QDL_PAD_SD3_CLK__FLEXCAN1_RX 0x80000000 + MX6QDL_PAD_SD3_CMD__FLEXCAN1_TX 0x80000000 + >; + }; + + pinctrl_hummingboard_gpio1_2: hummingboard-gpio1_2 { + fsl,pins = < + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 + >; + }; + + pinctrl_hummingboard_i2c1: hummingboard-i2c1 { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; + + pinctrl_hummingboard_spdif: hummingboard-spdif { + fsl,pins = ; + }; + + pinctrl_hummingboard_usbh1_vbus: hummingboard-usbh1-vbus { + fsl,pins = ; + }; + + pinctrl_hummingboard_usbotg_vbus: hummingboard-usbotg-vbus { + fsl,pins = ; + }; + + pinctrl_hummingboard_usdhc2_aux: hummingboard-usdhc2-aux { + fsl,pins = < + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 + >; + }; + + pinctrl_hummingboard_usdhc2: hummingboard-usdhc2 { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 + >; + }; + }; +}; + +&spdif { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard_spdif>; + status = "okay"; +}; + +&usbh1 { + vbus-supply = <®_usbh1_vbus>; + status = "okay"; +}; + +&usbotg { + vbus-supply = <®_usbotg_vbus>; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default"; + pinctrl-0 = < + &pinctrl_hummingboard_usdhc2_aux + &pinctrl_hummingboard_usdhc2 + >; + vmmc-supply = <®_3p3v>; + cd-gpios = <&gpio1 4 0>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6q-cubox-i.dts b/arch/arm/boot/dts/imx6q-cubox-i.dts new file mode 100644 index 00000000000000..bc5f31e3e892f2 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-cubox-i.dts @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2014 Russell King + */ +/dts-v1/; + +#include "imx6q.dtsi" +#include "imx6qdl-cubox-i.dtsi" + +/ { + model = "SolidRun Cubox-i Dual/Quad"; + compatible = "solidrun,cubox-i/q", "fsl,imx6q"; +}; + +&sata { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi new file mode 100644 index 00000000000000..c2a24888a27689 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2014 Russell King + */ +#include "imx6qdl-microsom.dtsi" +#include "imx6qdl-microsom-ar8035.dtsi" + +/ { + ir_recv: ir-receiver { + compatible = "gpio-ir-receiver"; + gpios = <&gpio3 9 1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cubox_i_ir>; + }; + + regulators { + compatible = "simple-bus"; + + reg_3p3v: 3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_usbh1_vbus: usb-h1-vbus { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio1 0 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cubox_i_usbh1_vbus>; + regulator-name = "usb_h1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + reg_usbotg_vbus: usb-otg-vbus { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio3 22 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cubox_i_usbotg_vbus>; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + }; + + sound-spdif { + compatible = "fsl,imx-audio-spdif"; + model = "imx-spdif"; + /* IMX6 doesn't implement this yet */ + spdif-controller = <&spdif>; + spdif-out; + }; +}; + +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cubox_i_i2c3>; + + status = "okay"; + + rtc: pcf8523@68 { + compatible = "nxp,pcf8523"; + reg = <0x68>; + }; +}; + +&iomuxc { + cubox_i { + pinctrl_cubox_i_i2c3: cubox-i-i2c3 { + fsl,pins = < + MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 + >; + }; + + pinctrl_cubox_i_ir: cubox-i-ir { + fsl,pins = < + MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000 + >; + }; + + pinctrl_cubox_i_spdif: cubox-i-spdif { + fsl,pins = ; + }; + + pinctrl_cubox_i_usbh1_vbus: cubox-i-usbh1-vbus { + fsl,pins = ; + }; + + pinctrl_cubox_i_usbotg_vbus: cubox-i-usbotg-vbus { + fsl,pins = ; + }; + + pinctrl_cubox_i_usdhc2_aux: cubox-i-usdhc2-aux { + fsl,pins = < + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 + MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b071 + >; + }; + + pinctrl_cubox_i_usdhc2: cubox-i-usdhc2 { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 + >; + }; + }; +}; + +&spdif { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cubox_i_spdif>; + status = "okay"; +}; + +&usbh1 { + vbus-supply = <®_usbh1_vbus>; + status = "okay"; +}; + +&usbotg { + vbus-supply = <®_usbotg_vbus>; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2>; + vmmc-supply = <®_3p3v>; + cd-gpios = <&gpio1 4 0>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi b/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi new file mode 100644 index 00000000000000..a3cb2fff8f6121 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2013,2014 Russell King + * + * This describes the hookup for an AR8035 to the iMX6 on the SolidRun + * MicroSOM. + */ +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_microsom_enet_ar8035>; + phy-mode = "rgmii"; + phy-reset-duration = <2>; + phy-reset-gpios = <&gpio4 15 0>; + status = "okay"; +}; + +&iomuxc { + enet { + pinctrl_microsom_enet_ar8035: microsom-enet-ar8035 { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + /* AR8035 reset */ + MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x130b0 + /* AR8035 interrupt */ + MX6QDL_PAD_DI0_PIN2__GPIO4_IO18 0x80000000 + /* GPIO16 -> AR8035 25MHz */ + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0xc0000000 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x80000000 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + /* AR8035 CLK_25M --> ENET_REF_CLK (V22) */ + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x0a0b1 + /* AR8035 pin strapping: IO voltage: pull up */ + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + /* AR8035 pin strapping: PHYADDR#0: pull down */ + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x130b0 + /* AR8035 pin strapping: PHYADDR#1: pull down */ + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x130b0 + /* AR8035 pin strapping: MODE#1: pull up */ + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + /* AR8035 pin strapping: MODE#3: pull up */ + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + /* AR8035 pin strapping: MODE#0: pull down */ + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x130b0 + + /* + * As the RMII pins are also connected to RGMII + * so that an AR8030 can be placed, set these + * to high-z with the same pulls as above. + * Use the GPIO settings to avoid changing the + * input select registers. + */ + MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x03000 + MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x03000 + MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x03000 + >; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx6qdl-microsom.dtsi b/arch/arm/boot/dts/imx6qdl-microsom.dtsi new file mode 100644 index 00000000000000..d729d0b15f251b --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-microsom.dtsi @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2013,2014 Russell King + */ + +&iomuxc { + microsom { + pinctrl_microsom_uart1: microsom-uart1 { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_microsom_usbotg: microsom-usbotg { + /* + * Similar to pinctrl_usbotg_2, but we want it + * pulled down for a fixed host connection. + */ + fsl,pins = ; + }; + }; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_microsom_uart1>; + status = "okay"; +}; + +&usbotg { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_microsom_usbotg>; +}; diff --git a/arch/arm/boot/dts/kizbox.dts b/arch/arm/boot/dts/kizbox.dts index 02df1914a47c8f..928f6eef2d592c 100644 --- a/arch/arm/boot/dts/kizbox.dts +++ b/arch/arm/boot/dts/kizbox.dts @@ -53,6 +53,12 @@ status = "okay"; }; + watchdog@fffffd40 { + timeout-sec = <15>; + atmel,max-heartbeat-sec = <16>; + atmel,min-heartbeat-sec = <0>; + status = "okay"; + }; }; nand0: nand@40000000 { diff --git a/arch/arm/boot/dts/moxart-uc7112lx.dts b/arch/arm/boot/dts/moxart-uc7112lx.dts index 90749d55de0d45..10d088df0c3517 100644 --- a/arch/arm/boot/dts/moxart-uc7112lx.dts +++ b/arch/arm/boot/dts/moxart-uc7112lx.dts @@ -17,6 +17,14 @@ reg = <0x0 0x2000000>; }; + clocks { + ref12: ref12M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; + }; + flash@80000000,0 { compatible = "numonyx,js28f128", "cfi-flash"; reg = <0x80000000 0x1000000>; diff --git a/arch/arm/boot/dts/moxart.dtsi b/arch/arm/boot/dts/moxart.dtsi index da1d8effef9797..1fd27ed65a01fc 100644 --- a/arch/arm/boot/dts/moxart.dtsi +++ b/arch/arm/boot/dts/moxart.dtsi @@ -26,12 +26,6 @@ clocks { #address-cells = <1>; #size-cells = <0>; - - ref12: ref12M { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <12000000>; - }; }; soc { diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index 427395c083f59e..a5fc83b9c83545 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -89,6 +89,45 @@ interrupts = <0>; }; + prm: prm@48306000 { + compatible = "ti,omap3-prm"; + reg = <0x48306000 0x4000>; + + prm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + prm_clockdomains: clockdomains { + }; + }; + + cm: cm@48004000 { + compatible = "ti,omap3-cm"; + reg = <0x48004000 0x4000>; + + cm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + cm_clockdomains: clockdomains { + }; + }; + + scrm: scrm@48002000 { + compatible = "ti,omap3-scrm"; + reg = <0x48002000 0x2000>; + + scrm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + scrm_clockdomains: clockdomains { + }; + }; + counter32k: counter@48320000 { compatible = "ti,omap-counter32k"; reg = <0x48320000 0x20>; @@ -632,3 +671,5 @@ }; }; }; + +/include/ "omap3xxx-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap3430es1-clocks.dtsi b/arch/arm/boot/dts/omap3430es1-clocks.dtsi new file mode 100644 index 00000000000000..02f6c7fabbec9c --- /dev/null +++ b/arch/arm/boot/dts/omap3430es1-clocks.dtsi @@ -0,0 +1,208 @@ +/* + * Device Tree Source for OMAP3430 ES1 clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * 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. + */ +&cm_clocks { + gfx_l3_ck: gfx_l3_ck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&l3_ick>; + reg = <0x0b10>; + ti,bit-shift = <0>; + }; + + gfx_l3_fck: gfx_l3_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&l3_ick>; + ti,max-div = <7>; + reg = <0x0b40>; + ti,index-starts-at-one; + }; + + gfx_l3_ick: gfx_l3_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&gfx_l3_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + gfx_cg1_ck: gfx_cg1_ck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&gfx_l3_fck>; + reg = <0x0b00>; + ti,bit-shift = <1>; + }; + + gfx_cg2_ck: gfx_cg2_ck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&gfx_l3_fck>; + reg = <0x0b00>; + ti,bit-shift = <2>; + }; + + d2d_26m_fck: d2d_26m_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&sys_ck>; + reg = <0x0a00>; + ti,bit-shift = <3>; + }; + + fshostusb_fck: fshostusb_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <5>; + }; + + ssi_ssr_gate_fck_3430es1: ssi_ssr_gate_fck_3430es1 { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&corex2_fck>; + ti,bit-shift = <0>; + reg = <0x0a00>; + }; + + ssi_ssr_div_fck_3430es1: ssi_ssr_div_fck_3430es1 { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&corex2_fck>; + ti,bit-shift = <8>; + reg = <0x0a40>; + ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>; + }; + + ssi_ssr_fck_3430es1: ssi_ssr_fck_3430es1 { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&ssi_ssr_gate_fck_3430es1>, <&ssi_ssr_div_fck_3430es1>; + }; + + ssi_sst_fck_3430es1: ssi_sst_fck_3430es1 { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&ssi_ssr_fck_3430es1>; + clock-mult = <1>; + clock-div = <2>; + }; + + hsotgusb_ick_3430es1: hsotgusb_ick_3430es1 { + #clock-cells = <0>; + compatible = "ti,omap3-no-wait-interface-clock"; + clocks = <&core_l3_ick>; + reg = <0x0a10>; + ti,bit-shift = <4>; + }; + + fac_ick: fac_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <8>; + }; + + ssi_l4_ick: ssi_l4_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l4_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + ssi_ick_3430es1: ssi_ick_3430es1 { + #clock-cells = <0>; + compatible = "ti,omap3-no-wait-interface-clock"; + clocks = <&ssi_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <0>; + }; + + usb_l4_gate_ick: usb_l4_gate_ick { + #clock-cells = <0>; + compatible = "ti,composite-interface-clock"; + clocks = <&l4_ick>; + ti,bit-shift = <5>; + reg = <0x0a10>; + }; + + usb_l4_div_ick: usb_l4_div_ick { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&l4_ick>; + ti,bit-shift = <4>; + ti,max-div = <1>; + reg = <0x0a40>; + ti,index-starts-at-one; + }; + + usb_l4_ick: usb_l4_ick { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&usb_l4_gate_ick>, <&usb_l4_div_ick>; + }; + + dss1_alwon_fck_3430es1: dss1_alwon_fck_3430es1 { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll4_m4x2_ck>; + ti,bit-shift = <0>; + reg = <0x0e00>; + ti,set-rate-parent; + }; + + dss_ick_3430es1: dss_ick_3430es1 { + #clock-cells = <0>; + compatible = "ti,omap3-no-wait-interface-clock"; + clocks = <&l4_ick>; + reg = <0x0e10>; + ti,bit-shift = <0>; + }; +}; + +&cm_clockdomains { + core_l3_clkdm: core_l3_clkdm { + compatible = "ti,clockdomain"; + clocks = <&sdrc_ick>, <&hsotgusb_ick_3430es1>; + }; + + gfx_3430es1_clkdm: gfx_3430es1_clkdm { + compatible = "ti,clockdomain"; + clocks = <&gfx_l3_ck>, <&gfx_cg1_ck>, <&gfx_cg2_ck>; + }; + + dss_clkdm: dss_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dss_tv_fck>, <&dss_96m_fck>, <&dss2_alwon_fck>, + <&dss1_alwon_fck_3430es1>, <&dss_ick_3430es1>; + }; + + d2d_clkdm: d2d_clkdm { + compatible = "ti,clockdomain"; + clocks = <&d2d_26m_fck>; + }; + + core_l4_clkdm: core_l4_clkdm { + compatible = "ti,clockdomain"; + clocks = <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>, + <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>, + <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>, + <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>, + <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>, + <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>, + <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>, + <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>, + <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>, + <&fshostusb_fck>, <&fac_ick>, <&ssi_ick_3430es1>; + }; +}; diff --git a/arch/arm/boot/dts/omap34xx-omap36xx-clocks.dtsi b/arch/arm/boot/dts/omap34xx-omap36xx-clocks.dtsi new file mode 100644 index 00000000000000..b02017b7630e52 --- /dev/null +++ b/arch/arm/boot/dts/omap34xx-omap36xx-clocks.dtsi @@ -0,0 +1,268 @@ +/* + * Device Tree Source for OMAP34XX/OMAP36XX clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * 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. + */ +&cm_clocks { + security_l4_ick2: security_l4_ick2 { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l4_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + aes1_ick: aes1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&security_l4_ick2>; + ti,bit-shift = <3>; + reg = <0x0a14>; + }; + + rng_ick: rng_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&security_l4_ick2>; + reg = <0x0a14>; + ti,bit-shift = <2>; + }; + + sha11_ick: sha11_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&security_l4_ick2>; + reg = <0x0a14>; + ti,bit-shift = <1>; + }; + + des1_ick: des1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&security_l4_ick2>; + reg = <0x0a14>; + ti,bit-shift = <0>; + }; + + cam_mclk: cam_mclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll4_m5x2_ck>; + ti,bit-shift = <0>; + reg = <0x0f00>; + ti,set-rate-parent; + }; + + cam_ick: cam_ick { + #clock-cells = <0>; + compatible = "ti,omap3-no-wait-interface-clock"; + clocks = <&l4_ick>; + reg = <0x0f10>; + ti,bit-shift = <0>; + }; + + csi2_96m_fck: csi2_96m_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x0f00>; + ti,bit-shift = <1>; + }; + + security_l3_ick: security_l3_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l3_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + pka_ick: pka_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&security_l3_ick>; + reg = <0x0a14>; + ti,bit-shift = <4>; + }; + + icr_ick: icr_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <29>; + }; + + des2_ick: des2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <26>; + }; + + mspro_ick: mspro_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <23>; + }; + + mailboxes_ick: mailboxes_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <7>; + }; + + ssi_l4_ick: ssi_l4_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l4_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + sr1_fck: sr1_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&sys_ck>; + reg = <0x0c00>; + ti,bit-shift = <6>; + }; + + sr2_fck: sr2_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&sys_ck>; + reg = <0x0c00>; + ti,bit-shift = <7>; + }; + + sr_l4_ick: sr_l4_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l4_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll2_fck: dpll2_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&core_ck>; + ti,bit-shift = <19>; + ti,max-div = <7>; + reg = <0x0040>; + ti,index-starts-at-one; + }; + + dpll2_ck: dpll2_ck { + #clock-cells = <0>; + compatible = "ti,omap3-dpll-clock"; + clocks = <&sys_ck>, <&dpll2_fck>; + reg = <0x0004>, <0x0024>, <0x0040>, <0x0034>; + ti,low-power-stop; + ti,lock; + ti,low-power-bypass; + }; + + dpll2_m2_ck: dpll2_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll2_ck>; + ti,max-div = <31>; + reg = <0x0044>; + ti,index-starts-at-one; + }; + + iva2_ck: iva2_ck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&dpll2_m2_ck>; + reg = <0x0000>; + ti,bit-shift = <0>; + }; + + modem_fck: modem_fck { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&sys_ck>; + reg = <0x0a00>; + ti,bit-shift = <31>; + }; + + sad2d_ick: sad2d_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&l3_ick>; + reg = <0x0a10>; + ti,bit-shift = <3>; + }; + + mad2d_ick: mad2d_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&l3_ick>; + reg = <0x0a18>; + ti,bit-shift = <3>; + }; + + mspro_fck: mspro_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x0a00>; + ti,bit-shift = <23>; + }; +}; + +&cm_clockdomains { + cam_clkdm: cam_clkdm { + compatible = "ti,clockdomain"; + clocks = <&cam_ick>, <&csi2_96m_fck>; + }; + + iva2_clkdm: iva2_clkdm { + compatible = "ti,clockdomain"; + clocks = <&iva2_ck>; + }; + + dpll2_clkdm: dpll2_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll2_ck>; + }; + + wkup_clkdm: wkup_clkdm { + compatible = "ti,clockdomain"; + clocks = <&gpio1_dbck>, <&wdt2_fck>, <&wdt2_ick>, <&wdt1_ick>, + <&gpio1_ick>, <&omap_32ksync_ick>, <&gpt12_ick>, + <&gpt1_ick>, <&sr1_fck>, <&sr2_fck>; + }; + + d2d_clkdm: d2d_clkdm { + compatible = "ti,clockdomain"; + clocks = <&modem_fck>, <&sad2d_ick>, <&mad2d_ick>; + }; + + core_l4_clkdm: core_l4_clkdm { + compatible = "ti,clockdomain"; + clocks = <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>, + <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>, + <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>, + <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>, + <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>, + <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>, + <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>, + <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>, + <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>, <&icr_ick>, + <&des2_ick>, <&mspro_ick>, <&mailboxes_ick>, + <&mspro_fck>; + }; +}; diff --git a/arch/arm/boot/dts/omap34xx.dtsi b/arch/arm/boot/dts/omap34xx.dtsi index 77d124678c9587..2e92360da1f36d 100644 --- a/arch/arm/boot/dts/omap34xx.dtsi +++ b/arch/arm/boot/dts/omap34xx.dtsi @@ -39,3 +39,7 @@ }; }; }; + +/include/ "omap34xx-omap36xx-clocks.dtsi" +/include/ "omap36xx-omap3430es2plus-clocks.dtsi" +/include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi b/arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi new file mode 100644 index 00000000000000..af9ae5346bf2e9 --- /dev/null +++ b/arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi @@ -0,0 +1,242 @@ +/* + * Device Tree Source for OMAP36xx/AM35xx/OMAP34xx clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * 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. + */ +&prm_clocks { + corex2_d3_fck: corex2_d3_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&corex2_fck>; + clock-mult = <1>; + clock-div = <3>; + }; + + corex2_d5_fck: corex2_d5_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&corex2_fck>; + clock-mult = <1>; + clock-div = <5>; + }; +}; +&cm_clocks { + dpll5_ck: dpll5_ck { + #clock-cells = <0>; + compatible = "ti,omap3-dpll-clock"; + clocks = <&sys_ck>, <&sys_ck>; + reg = <0x0d04>, <0x0d24>, <0x0d4c>, <0x0d34>; + ti,low-power-stop; + ti,lock; + }; + + dpll5_m2_ck: dpll5_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll5_ck>; + ti,max-div = <31>; + reg = <0x0d50>; + ti,index-starts-at-one; + }; + + sgx_gate_fck: sgx_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&core_ck>; + ti,bit-shift = <1>; + reg = <0x0b00>; + }; + + core_d3_ck: core_d3_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&core_ck>; + clock-mult = <1>; + clock-div = <3>; + }; + + core_d4_ck: core_d4_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&core_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + core_d6_ck: core_d6_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&core_ck>; + clock-mult = <1>; + clock-div = <6>; + }; + + omap_192m_alwon_fck: omap_192m_alwon_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_m2x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + core_d2_ck: core_d2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&core_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + sgx_mux_fck: sgx_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&core_d3_ck>, <&core_d4_ck>, <&core_d6_ck>, <&cm_96m_fck>, <&omap_192m_alwon_fck>, <&core_d2_ck>, <&corex2_d3_fck>, <&corex2_d5_fck>; + reg = <0x0b40>; + }; + + sgx_fck: sgx_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&sgx_gate_fck>, <&sgx_mux_fck>; + }; + + sgx_ick: sgx_ick { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&l3_ick>; + reg = <0x0b10>; + ti,bit-shift = <0>; + }; + + cpefuse_fck: cpefuse_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_ck>; + reg = <0x0a08>; + ti,bit-shift = <0>; + }; + + ts_fck: ts_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&omap_32k_fck>; + reg = <0x0a08>; + ti,bit-shift = <1>; + }; + + usbtll_fck: usbtll_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&dpll5_m2_ck>; + reg = <0x0a08>; + ti,bit-shift = <2>; + }; + + usbtll_ick: usbtll_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a18>; + ti,bit-shift = <2>; + }; + + mmchs3_ick: mmchs3_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <30>; + }; + + mmchs3_fck: mmchs3_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x0a00>; + ti,bit-shift = <30>; + }; + + dss1_alwon_fck_3430es2: dss1_alwon_fck_3430es2 { + #clock-cells = <0>; + compatible = "ti,dss-gate-clock"; + clocks = <&dpll4_m4x2_ck>; + ti,bit-shift = <0>; + reg = <0x0e00>; + ti,set-rate-parent; + }; + + dss_ick_3430es2: dss_ick_3430es2 { + #clock-cells = <0>; + compatible = "ti,omap3-dss-interface-clock"; + clocks = <&l4_ick>; + reg = <0x0e10>; + ti,bit-shift = <0>; + }; + + usbhost_120m_fck: usbhost_120m_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll5_m2_ck>; + reg = <0x1400>; + ti,bit-shift = <1>; + }; + + usbhost_48m_fck: usbhost_48m_fck { + #clock-cells = <0>; + compatible = "ti,dss-gate-clock"; + clocks = <&omap_48m_fck>; + reg = <0x1400>; + ti,bit-shift = <0>; + }; + + usbhost_ick: usbhost_ick { + #clock-cells = <0>; + compatible = "ti,omap3-dss-interface-clock"; + clocks = <&l4_ick>; + reg = <0x1410>; + ti,bit-shift = <0>; + }; +}; + +&cm_clockdomains { + dpll5_clkdm: dpll5_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll5_ck>; + }; + + sgx_clkdm: sgx_clkdm { + compatible = "ti,clockdomain"; + clocks = <&sgx_ick>; + }; + + dss_clkdm: dss_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dss_tv_fck>, <&dss_96m_fck>, <&dss2_alwon_fck>, + <&dss1_alwon_fck_3430es2>, <&dss_ick_3430es2>; + }; + + core_l4_clkdm: core_l4_clkdm { + compatible = "ti,clockdomain"; + clocks = <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>, + <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>, + <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>, + <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>, + <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>, + <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>, + <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>, + <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>, + <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>, + <&cpefuse_fck>, <&ts_fck>, <&usbtll_fck>, + <&usbtll_ick>, <&mmchs3_ick>, <&mmchs3_fck>; + }; + + usbhost_clkdm: usbhost_clkdm { + compatible = "ti,clockdomain"; + clocks = <&usbhost_120m_fck>, <&usbhost_48m_fck>, + <&usbhost_ick>; + }; +}; diff --git a/arch/arm/boot/dts/omap36xx-clocks.dtsi b/arch/arm/boot/dts/omap36xx-clocks.dtsi new file mode 100644 index 00000000000000..2fcf253b677c05 --- /dev/null +++ b/arch/arm/boot/dts/omap36xx-clocks.dtsi @@ -0,0 +1,90 @@ +/* + * Device Tree Source for OMAP36xx clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * 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. + */ +&cm_clocks { + dpll4_ck: dpll4_ck { + #clock-cells = <0>; + compatible = "ti,omap3-dpll-per-j-type-clock"; + clocks = <&sys_ck>, <&sys_ck>; + reg = <0x0d00>, <0x0d20>, <0x0d44>, <0x0d30>; + }; + + dpll4_m5x2_ck: dpll4_m5x2_ck { + #clock-cells = <0>; + compatible = "ti,hsdiv-gate-clock"; + clocks = <&dpll4_m5x2_mul_ck>; + ti,bit-shift = <0x1e>; + reg = <0x0d00>; + ti,set-rate-parent; + ti,set-bit-to-disable; + }; + + dpll4_m2x2_ck: dpll4_m2x2_ck { + #clock-cells = <0>; + compatible = "ti,hsdiv-gate-clock"; + clocks = <&dpll4_m2x2_mul_ck>; + ti,bit-shift = <0x1b>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + dpll3_m3x2_ck: dpll3_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,hsdiv-gate-clock"; + clocks = <&dpll3_m3x2_mul_ck>; + ti,bit-shift = <0xc>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + dpll4_m3x2_ck: dpll4_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,hsdiv-gate-clock"; + clocks = <&dpll4_m3x2_mul_ck>; + ti,bit-shift = <0x1c>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + dpll4_m6x2_ck: dpll4_m6x2_ck { + #clock-cells = <0>; + compatible = "ti,hsdiv-gate-clock"; + clocks = <&dpll4_m6x2_mul_ck>; + ti,bit-shift = <0x1f>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + uart4_fck: uart4_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&per_48m_fck>; + reg = <0x1000>; + ti,bit-shift = <18>; + }; +}; + +&cm_clockdomains { + dpll4_clkdm: dpll4_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll4_ck>; + }; + + per_clkdm: per_clkdm { + compatible = "ti,clockdomain"; + clocks = <&uart3_fck>, <&gpio6_dbck>, <&gpio5_dbck>, + <&gpio4_dbck>, <&gpio3_dbck>, <&gpio2_dbck>, + <&wdt3_fck>, <&gpio6_ick>, <&gpio5_ick>, <&gpio4_ick>, + <&gpio3_ick>, <&gpio2_ick>, <&wdt3_ick>, <&uart3_ick>, + <&uart4_ick>, <&gpt9_ick>, <&gpt8_ick>, <&gpt7_ick>, + <&gpt6_ick>, <&gpt5_ick>, <&gpt4_ick>, <&gpt3_ick>, + <&gpt2_ick>, <&mcbsp2_ick>, <&mcbsp3_ick>, + <&mcbsp4_ick>, <&uart4_fck>; + }; +}; diff --git a/arch/arm/boot/dts/omap36xx-omap3430es2plus-clocks.dtsi b/arch/arm/boot/dts/omap36xx-omap3430es2plus-clocks.dtsi new file mode 100644 index 00000000000000..8ed475dd63c982 --- /dev/null +++ b/arch/arm/boot/dts/omap36xx-omap3430es2plus-clocks.dtsi @@ -0,0 +1,198 @@ +/* + * Device Tree Source for OMAP34xx/OMAP36xx clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * 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. + */ +&cm_clocks { + ssi_ssr_gate_fck_3430es2: ssi_ssr_gate_fck_3430es2 { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&corex2_fck>; + ti,bit-shift = <0>; + reg = <0x0a00>; + }; + + ssi_ssr_div_fck_3430es2: ssi_ssr_div_fck_3430es2 { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&corex2_fck>; + ti,bit-shift = <8>; + reg = <0x0a40>; + ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>; + }; + + ssi_ssr_fck_3430es2: ssi_ssr_fck_3430es2 { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&ssi_ssr_gate_fck_3430es2>, <&ssi_ssr_div_fck_3430es2>; + }; + + ssi_sst_fck_3430es2: ssi_sst_fck_3430es2 { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&ssi_ssr_fck_3430es2>; + clock-mult = <1>; + clock-div = <2>; + }; + + hsotgusb_ick_3430es2: hsotgusb_ick_3430es2 { + #clock-cells = <0>; + compatible = "ti,omap3-hsotgusb-interface-clock"; + clocks = <&core_l3_ick>; + reg = <0x0a10>; + ti,bit-shift = <4>; + }; + + ssi_l4_ick: ssi_l4_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l4_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + ssi_ick_3430es2: ssi_ick_3430es2 { + #clock-cells = <0>; + compatible = "ti,omap3-ssi-interface-clock"; + clocks = <&ssi_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <0>; + }; + + usim_gate_fck: usim_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&omap_96m_fck>; + ti,bit-shift = <9>; + reg = <0x0c00>; + }; + + sys_d2_ck: sys_d2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + omap_96m_d2_fck: omap_96m_d2_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_96m_fck>; + clock-mult = <1>; + clock-div = <2>; + }; + + omap_96m_d4_fck: omap_96m_d4_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_96m_fck>; + clock-mult = <1>; + clock-div = <4>; + }; + + omap_96m_d8_fck: omap_96m_d8_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_96m_fck>; + clock-mult = <1>; + clock-div = <8>; + }; + + omap_96m_d10_fck: omap_96m_d10_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_96m_fck>; + clock-mult = <1>; + clock-div = <10>; + }; + + dpll5_m2_d4_ck: dpll5_m2_d4_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll5_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + dpll5_m2_d8_ck: dpll5_m2_d8_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll5_m2_ck>; + clock-mult = <1>; + clock-div = <8>; + }; + + dpll5_m2_d16_ck: dpll5_m2_d16_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll5_m2_ck>; + clock-mult = <1>; + clock-div = <16>; + }; + + dpll5_m2_d20_ck: dpll5_m2_d20_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll5_m2_ck>; + clock-mult = <1>; + clock-div = <20>; + }; + + usim_mux_fck: usim_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_ck>, <&sys_d2_ck>, <&omap_96m_d2_fck>, <&omap_96m_d4_fck>, <&omap_96m_d8_fck>, <&omap_96m_d10_fck>, <&dpll5_m2_d4_ck>, <&dpll5_m2_d8_ck>, <&dpll5_m2_d16_ck>, <&dpll5_m2_d20_ck>; + ti,bit-shift = <3>; + reg = <0x0c40>; + ti,index-starts-at-one; + }; + + usim_fck: usim_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&usim_gate_fck>, <&usim_mux_fck>; + }; + + usim_ick: usim_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&wkup_l4_ick>; + reg = <0x0c10>; + ti,bit-shift = <9>; + }; +}; + +&cm_clockdomains { + core_l3_clkdm: core_l3_clkdm { + compatible = "ti,clockdomain"; + clocks = <&sdrc_ick>, <&hsotgusb_ick_3430es2>; + }; + + wkup_clkdm: wkup_clkdm { + compatible = "ti,clockdomain"; + clocks = <&gpio1_dbck>, <&wdt2_fck>, <&wdt2_ick>, <&wdt1_ick>, + <&gpio1_ick>, <&omap_32ksync_ick>, <&gpt12_ick>, + <&gpt1_ick>, <&usim_ick>; + }; + + core_l4_clkdm: core_l4_clkdm { + compatible = "ti,clockdomain"; + clocks = <&cpefuse_fck>, <&ts_fck>, <&usbtll_fck>, + <&usbtll_ick>, <&mmchs3_ick>, <&mmchs3_fck>, + <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>, + <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>, + <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>, + <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>, + <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>, + <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>, + <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>, + <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>, + <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>, + <&ssi_ick_3430es2>; + }; +}; diff --git a/arch/arm/boot/dts/omap36xx.dtsi b/arch/arm/boot/dts/omap36xx.dtsi index b7c7bd96c4041e..7e8dee9175d6a4 100644 --- a/arch/arm/boot/dts/omap36xx.dtsi +++ b/arch/arm/boot/dts/omap36xx.dtsi @@ -51,3 +51,8 @@ }; }; }; + +/include/ "omap36xx-clocks.dtsi" +/include/ "omap34xx-omap36xx-clocks.dtsi" +/include/ "omap36xx-omap3430es2plus-clocks.dtsi" +/include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap3xxx-clocks.dtsi b/arch/arm/boot/dts/omap3xxx-clocks.dtsi new file mode 100644 index 00000000000000..cb04d4b37e7f0f --- /dev/null +++ b/arch/arm/boot/dts/omap3xxx-clocks.dtsi @@ -0,0 +1,1660 @@ +/* + * Device Tree Source for OMAP3 clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * 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. + */ +&prm_clocks { + virt_16_8m_ck: virt_16_8m_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <16800000>; + }; + + osc_sys_ck: osc_sys_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&virt_12m_ck>, <&virt_13m_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_38_4m_ck>, <&virt_16_8m_ck>; + reg = <0x0d40>; + }; + + sys_ck: sys_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&osc_sys_ck>; + ti,bit-shift = <6>; + ti,max-div = <3>; + reg = <0x1270>; + ti,index-starts-at-one; + }; + + sys_clkout1: sys_clkout1 { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&osc_sys_ck>; + reg = <0x0d70>; + ti,bit-shift = <7>; + }; + + dpll3_x2_ck: dpll3_x2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll3_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll3_m2x2_ck: dpll3_m2x2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll3_m2_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll4_x2_ck: dpll4_x2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + corex2_fck: corex2_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll3_m2x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + wkup_l4_ick: wkup_l4_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_ck>; + clock-mult = <1>; + clock-div = <1>; + }; +}; +&scrm_clocks { + mcbsp5_mux_fck: mcbsp5_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&core_96m_fck>, <&mcbsp_clks>; + ti,bit-shift = <4>; + reg = <0x02d8>; + }; + + mcbsp5_fck: mcbsp5_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&mcbsp5_gate_fck>, <&mcbsp5_mux_fck>; + }; + + mcbsp1_mux_fck: mcbsp1_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&core_96m_fck>, <&mcbsp_clks>; + ti,bit-shift = <2>; + reg = <0x0274>; + }; + + mcbsp1_fck: mcbsp1_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&mcbsp1_gate_fck>, <&mcbsp1_mux_fck>; + }; + + mcbsp2_mux_fck: mcbsp2_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&per_96m_fck>, <&mcbsp_clks>; + ti,bit-shift = <6>; + reg = <0x0274>; + }; + + mcbsp2_fck: mcbsp2_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&mcbsp2_gate_fck>, <&mcbsp2_mux_fck>; + }; + + mcbsp3_mux_fck: mcbsp3_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&per_96m_fck>, <&mcbsp_clks>; + reg = <0x02d8>; + }; + + mcbsp3_fck: mcbsp3_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&mcbsp3_gate_fck>, <&mcbsp3_mux_fck>; + }; + + mcbsp4_mux_fck: mcbsp4_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&per_96m_fck>, <&mcbsp_clks>; + ti,bit-shift = <2>; + reg = <0x02d8>; + }; + + mcbsp4_fck: mcbsp4_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&mcbsp4_gate_fck>, <&mcbsp4_mux_fck>; + }; +}; +&cm_clocks { + dummy_apb_pclk: dummy_apb_pclk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0x0>; + }; + + omap_32k_fck: omap_32k_fck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + virt_12m_ck: virt_12m_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + virt_13m_ck: virt_13m_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <13000000>; + }; + + virt_19200000_ck: virt_19200000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <19200000>; + }; + + virt_26000000_ck: virt_26000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <26000000>; + }; + + virt_38_4m_ck: virt_38_4m_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <38400000>; + }; + + dpll4_ck: dpll4_ck { + #clock-cells = <0>; + compatible = "ti,omap3-dpll-per-clock"; + clocks = <&sys_ck>, <&sys_ck>; + reg = <0x0d00>, <0x0d20>, <0x0d44>, <0x0d30>; + }; + + dpll4_m2_ck: dpll4_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll4_ck>; + ti,max-div = <63>; + reg = <0x0d48>; + ti,index-starts-at-one; + }; + + dpll4_m2x2_mul_ck: dpll4_m2x2_mul_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_m2_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll4_m2x2_ck: dpll4_m2x2_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll4_m2x2_mul_ck>; + ti,bit-shift = <0x1b>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + omap_96m_alwon_fck: omap_96m_alwon_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_m2x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll3_ck: dpll3_ck { + #clock-cells = <0>; + compatible = "ti,omap3-dpll-core-clock"; + clocks = <&sys_ck>, <&sys_ck>; + reg = <0x0d00>, <0x0d20>, <0x0d40>, <0x0d30>; + }; + + dpll3_m3_ck: dpll3_m3_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll3_ck>; + ti,bit-shift = <16>; + ti,max-div = <31>; + reg = <0x1140>; + ti,index-starts-at-one; + }; + + dpll3_m3x2_mul_ck: dpll3_m3x2_mul_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll3_m3_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll3_m3x2_ck: dpll3_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll3_m3x2_mul_ck>; + ti,bit-shift = <0xc>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + emu_core_alwon_ck: emu_core_alwon_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll3_m3x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + sys_altclk: sys_altclk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0x0>; + }; + + mcbsp_clks: mcbsp_clks { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0x0>; + }; + + dpll3_m2_ck: dpll3_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll3_ck>; + ti,bit-shift = <27>; + ti,max-div = <31>; + reg = <0x0d40>; + ti,index-starts-at-one; + }; + + core_ck: core_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll3_m2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll1_fck: dpll1_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&core_ck>; + ti,bit-shift = <19>; + ti,max-div = <7>; + reg = <0x0940>; + ti,index-starts-at-one; + }; + + dpll1_ck: dpll1_ck { + #clock-cells = <0>; + compatible = "ti,omap3-dpll-clock"; + clocks = <&sys_ck>, <&dpll1_fck>; + reg = <0x0904>, <0x0924>, <0x0940>, <0x0934>; + }; + + dpll1_x2_ck: dpll1_x2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll1_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll1_x2m2_ck: dpll1_x2m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll1_x2_ck>; + ti,max-div = <31>; + reg = <0x0944>; + ti,index-starts-at-one; + }; + + cm_96m_fck: cm_96m_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_96m_alwon_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + omap_96m_fck: omap_96m_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&cm_96m_fck>, <&sys_ck>; + ti,bit-shift = <6>; + reg = <0x0d40>; + }; + + dpll4_m3_ck: dpll4_m3_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll4_ck>; + ti,bit-shift = <8>; + ti,max-div = <32>; + reg = <0x0e40>; + ti,index-starts-at-one; + }; + + dpll4_m3x2_mul_ck: dpll4_m3x2_mul_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_m3_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll4_m3x2_ck: dpll4_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll4_m3x2_mul_ck>; + ti,bit-shift = <0x1c>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + omap_54m_fck: omap_54m_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll4_m3x2_ck>, <&sys_altclk>; + ti,bit-shift = <5>; + reg = <0x0d40>; + }; + + cm_96m_d2_fck: cm_96m_d2_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&cm_96m_fck>; + clock-mult = <1>; + clock-div = <2>; + }; + + omap_48m_fck: omap_48m_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&cm_96m_d2_fck>, <&sys_altclk>; + ti,bit-shift = <3>; + reg = <0x0d40>; + }; + + omap_12m_fck: omap_12m_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_48m_fck>; + clock-mult = <1>; + clock-div = <4>; + }; + + dpll4_m4_ck: dpll4_m4_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll4_ck>; + ti,max-div = <32>; + reg = <0x0e40>; + ti,index-starts-at-one; + }; + + dpll4_m4x2_mul_ck: dpll4_m4x2_mul_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_m4_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll4_m4x2_ck: dpll4_m4x2_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll4_m4x2_mul_ck>; + ti,bit-shift = <0x1d>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + dpll4_m5_ck: dpll4_m5_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll4_ck>; + ti,max-div = <63>; + reg = <0x0f40>; + ti,index-starts-at-one; + }; + + dpll4_m5x2_mul_ck: dpll4_m5x2_mul_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_m5_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll4_m5x2_ck: dpll4_m5x2_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll4_m5x2_mul_ck>; + ti,bit-shift = <0x1e>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + dpll4_m6_ck: dpll4_m6_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll4_ck>; + ti,bit-shift = <24>; + ti,max-div = <63>; + reg = <0x1140>; + ti,index-starts-at-one; + }; + + dpll4_m6x2_mul_ck: dpll4_m6x2_mul_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_m6_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll4_m6x2_ck: dpll4_m6x2_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll4_m6x2_mul_ck>; + ti,bit-shift = <0x1f>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + emu_per_alwon_ck: emu_per_alwon_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_m6x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + clkout2_src_gate_ck: clkout2_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&core_ck>; + ti,bit-shift = <7>; + reg = <0x0d70>; + }; + + clkout2_src_mux_ck: clkout2_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&core_ck>, <&sys_ck>, <&cm_96m_fck>, <&omap_54m_fck>; + reg = <0x0d70>; + }; + + clkout2_src_ck: clkout2_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&clkout2_src_gate_ck>, <&clkout2_src_mux_ck>; + }; + + sys_clkout2: sys_clkout2 { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&clkout2_src_ck>; + ti,bit-shift = <3>; + ti,max-div = <64>; + reg = <0x0d70>; + ti,index-power-of-two; + }; + + mpu_ck: mpu_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll1_x2m2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + arm_fck: arm_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mpu_ck>; + reg = <0x0924>; + ti,max-div = <2>; + }; + + emu_mpu_alwon_ck: emu_mpu_alwon_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&mpu_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l3_ick: l3_ick { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&core_ck>; + ti,max-div = <3>; + reg = <0x0a40>; + ti,index-starts-at-one; + }; + + l4_ick: l4_ick { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&l3_ick>; + ti,bit-shift = <2>; + ti,max-div = <3>; + reg = <0x0a40>; + ti,index-starts-at-one; + }; + + rm_ick: rm_ick { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&l4_ick>; + ti,bit-shift = <1>; + ti,max-div = <3>; + reg = <0x0c40>; + ti,index-starts-at-one; + }; + + gpt10_gate_fck: gpt10_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <11>; + reg = <0x0a00>; + }; + + gpt10_mux_fck: gpt10_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <6>; + reg = <0x0a40>; + }; + + gpt10_fck: gpt10_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt10_gate_fck>, <&gpt10_mux_fck>; + }; + + gpt11_gate_fck: gpt11_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <12>; + reg = <0x0a00>; + }; + + gpt11_mux_fck: gpt11_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <7>; + reg = <0x0a40>; + }; + + gpt11_fck: gpt11_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt11_gate_fck>, <&gpt11_mux_fck>; + }; + + core_96m_fck: core_96m_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_96m_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + mmchs2_fck: mmchs2_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x0a00>; + ti,bit-shift = <25>; + }; + + mmchs1_fck: mmchs1_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x0a00>; + ti,bit-shift = <24>; + }; + + i2c3_fck: i2c3_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x0a00>; + ti,bit-shift = <17>; + }; + + i2c2_fck: i2c2_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x0a00>; + ti,bit-shift = <16>; + }; + + i2c1_fck: i2c1_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x0a00>; + ti,bit-shift = <15>; + }; + + mcbsp5_gate_fck: mcbsp5_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&mcbsp_clks>; + ti,bit-shift = <10>; + reg = <0x0a00>; + }; + + mcbsp1_gate_fck: mcbsp1_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&mcbsp_clks>; + ti,bit-shift = <9>; + reg = <0x0a00>; + }; + + core_48m_fck: core_48m_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_48m_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + mcspi4_fck: mcspi4_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <21>; + }; + + mcspi3_fck: mcspi3_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <20>; + }; + + mcspi2_fck: mcspi2_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <19>; + }; + + mcspi1_fck: mcspi1_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <18>; + }; + + uart2_fck: uart2_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <14>; + }; + + uart1_fck: uart1_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <13>; + }; + + core_12m_fck: core_12m_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_12m_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + hdq_fck: hdq_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_12m_fck>; + reg = <0x0a00>; + ti,bit-shift = <22>; + }; + + core_l3_ick: core_l3_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l3_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + sdrc_ick: sdrc_ick { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_l3_ick>; + reg = <0x0a10>; + ti,bit-shift = <1>; + }; + + gpmc_fck: gpmc_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&core_l3_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + core_l4_ick: core_l4_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l4_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + mmchs2_ick: mmchs2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <25>; + }; + + mmchs1_ick: mmchs1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <24>; + }; + + hdq_ick: hdq_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <22>; + }; + + mcspi4_ick: mcspi4_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <21>; + }; + + mcspi3_ick: mcspi3_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <20>; + }; + + mcspi2_ick: mcspi2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <19>; + }; + + mcspi1_ick: mcspi1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <18>; + }; + + i2c3_ick: i2c3_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <17>; + }; + + i2c2_ick: i2c2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <16>; + }; + + i2c1_ick: i2c1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <15>; + }; + + uart2_ick: uart2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <14>; + }; + + uart1_ick: uart1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <13>; + }; + + gpt11_ick: gpt11_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <12>; + }; + + gpt10_ick: gpt10_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <11>; + }; + + mcbsp5_ick: mcbsp5_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <10>; + }; + + mcbsp1_ick: mcbsp1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <9>; + }; + + omapctrl_ick: omapctrl_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <6>; + }; + + dss_tv_fck: dss_tv_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&omap_54m_fck>; + reg = <0x0e00>; + ti,bit-shift = <2>; + }; + + dss_96m_fck: dss_96m_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&omap_96m_fck>; + reg = <0x0e00>; + ti,bit-shift = <2>; + }; + + dss2_alwon_fck: dss2_alwon_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_ck>; + reg = <0x0e00>; + ti,bit-shift = <1>; + }; + + dummy_ck: dummy_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + gpt1_gate_fck: gpt1_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <0>; + reg = <0x0c00>; + }; + + gpt1_mux_fck: gpt1_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + reg = <0x0c40>; + }; + + gpt1_fck: gpt1_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt1_gate_fck>, <&gpt1_mux_fck>; + }; + + aes2_ick: aes2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + ti,bit-shift = <28>; + reg = <0x0a10>; + }; + + wkup_32k_fck: wkup_32k_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_32k_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + gpio1_dbck: gpio1_dbck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&wkup_32k_fck>; + reg = <0x0c00>; + ti,bit-shift = <3>; + }; + + sha12_ick: sha12_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <27>; + }; + + wdt2_fck: wdt2_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&wkup_32k_fck>; + reg = <0x0c00>; + ti,bit-shift = <5>; + }; + + wdt2_ick: wdt2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&wkup_l4_ick>; + reg = <0x0c10>; + ti,bit-shift = <5>; + }; + + wdt1_ick: wdt1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&wkup_l4_ick>; + reg = <0x0c10>; + ti,bit-shift = <4>; + }; + + gpio1_ick: gpio1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&wkup_l4_ick>; + reg = <0x0c10>; + ti,bit-shift = <3>; + }; + + omap_32ksync_ick: omap_32ksync_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&wkup_l4_ick>; + reg = <0x0c10>; + ti,bit-shift = <2>; + }; + + gpt12_ick: gpt12_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&wkup_l4_ick>; + reg = <0x0c10>; + ti,bit-shift = <1>; + }; + + gpt1_ick: gpt1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&wkup_l4_ick>; + reg = <0x0c10>; + ti,bit-shift = <0>; + }; + + per_96m_fck: per_96m_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_96m_alwon_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + per_48m_fck: per_48m_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_48m_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + uart3_fck: uart3_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&per_48m_fck>; + reg = <0x1000>; + ti,bit-shift = <11>; + }; + + gpt2_gate_fck: gpt2_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <3>; + reg = <0x1000>; + }; + + gpt2_mux_fck: gpt2_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + reg = <0x1040>; + }; + + gpt2_fck: gpt2_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt2_gate_fck>, <&gpt2_mux_fck>; + }; + + gpt3_gate_fck: gpt3_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <4>; + reg = <0x1000>; + }; + + gpt3_mux_fck: gpt3_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <1>; + reg = <0x1040>; + }; + + gpt3_fck: gpt3_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt3_gate_fck>, <&gpt3_mux_fck>; + }; + + gpt4_gate_fck: gpt4_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <5>; + reg = <0x1000>; + }; + + gpt4_mux_fck: gpt4_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <2>; + reg = <0x1040>; + }; + + gpt4_fck: gpt4_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt4_gate_fck>, <&gpt4_mux_fck>; + }; + + gpt5_gate_fck: gpt5_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <6>; + reg = <0x1000>; + }; + + gpt5_mux_fck: gpt5_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <3>; + reg = <0x1040>; + }; + + gpt5_fck: gpt5_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt5_gate_fck>, <&gpt5_mux_fck>; + }; + + gpt6_gate_fck: gpt6_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <7>; + reg = <0x1000>; + }; + + gpt6_mux_fck: gpt6_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <4>; + reg = <0x1040>; + }; + + gpt6_fck: gpt6_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt6_gate_fck>, <&gpt6_mux_fck>; + }; + + gpt7_gate_fck: gpt7_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <8>; + reg = <0x1000>; + }; + + gpt7_mux_fck: gpt7_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <5>; + reg = <0x1040>; + }; + + gpt7_fck: gpt7_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt7_gate_fck>, <&gpt7_mux_fck>; + }; + + gpt8_gate_fck: gpt8_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <9>; + reg = <0x1000>; + }; + + gpt8_mux_fck: gpt8_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <6>; + reg = <0x1040>; + }; + + gpt8_fck: gpt8_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt8_gate_fck>, <&gpt8_mux_fck>; + }; + + gpt9_gate_fck: gpt9_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <10>; + reg = <0x1000>; + }; + + gpt9_mux_fck: gpt9_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <7>; + reg = <0x1040>; + }; + + gpt9_fck: gpt9_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt9_gate_fck>, <&gpt9_mux_fck>; + }; + + per_32k_alwon_fck: per_32k_alwon_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_32k_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + gpio6_dbck: gpio6_dbck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&per_32k_alwon_fck>; + reg = <0x1000>; + ti,bit-shift = <17>; + }; + + gpio5_dbck: gpio5_dbck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&per_32k_alwon_fck>; + reg = <0x1000>; + ti,bit-shift = <16>; + }; + + gpio4_dbck: gpio4_dbck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&per_32k_alwon_fck>; + reg = <0x1000>; + ti,bit-shift = <15>; + }; + + gpio3_dbck: gpio3_dbck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&per_32k_alwon_fck>; + reg = <0x1000>; + ti,bit-shift = <14>; + }; + + gpio2_dbck: gpio2_dbck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&per_32k_alwon_fck>; + reg = <0x1000>; + ti,bit-shift = <13>; + }; + + wdt3_fck: wdt3_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&per_32k_alwon_fck>; + reg = <0x1000>; + ti,bit-shift = <12>; + }; + + per_l4_ick: per_l4_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l4_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + gpio6_ick: gpio6_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <17>; + }; + + gpio5_ick: gpio5_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <16>; + }; + + gpio4_ick: gpio4_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <15>; + }; + + gpio3_ick: gpio3_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <14>; + }; + + gpio2_ick: gpio2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <13>; + }; + + wdt3_ick: wdt3_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <12>; + }; + + uart3_ick: uart3_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <11>; + }; + + uart4_ick: uart4_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <18>; + }; + + gpt9_ick: gpt9_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <10>; + }; + + gpt8_ick: gpt8_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <9>; + }; + + gpt7_ick: gpt7_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <8>; + }; + + gpt6_ick: gpt6_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <7>; + }; + + gpt5_ick: gpt5_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <6>; + }; + + gpt4_ick: gpt4_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <5>; + }; + + gpt3_ick: gpt3_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <4>; + }; + + gpt2_ick: gpt2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <3>; + }; + + mcbsp2_ick: mcbsp2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <0>; + }; + + mcbsp3_ick: mcbsp3_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <1>; + }; + + mcbsp4_ick: mcbsp4_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <2>; + }; + + mcbsp2_gate_fck: mcbsp2_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&mcbsp_clks>; + ti,bit-shift = <0>; + reg = <0x1000>; + }; + + mcbsp3_gate_fck: mcbsp3_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&mcbsp_clks>; + ti,bit-shift = <1>; + reg = <0x1000>; + }; + + mcbsp4_gate_fck: mcbsp4_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&mcbsp_clks>; + ti,bit-shift = <2>; + reg = <0x1000>; + }; + + emu_src_mux_ck: emu_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_ck>, <&emu_core_alwon_ck>, <&emu_per_alwon_ck>, <&emu_mpu_alwon_ck>; + reg = <0x1140>; + }; + + emu_src_ck: emu_src_ck { + #clock-cells = <0>; + compatible = "ti,clkdm-gate-clock"; + clocks = <&emu_src_mux_ck>; + }; + + pclk_fck: pclk_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&emu_src_ck>; + ti,bit-shift = <8>; + ti,max-div = <7>; + reg = <0x1140>; + ti,index-starts-at-one; + }; + + pclkx2_fck: pclkx2_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&emu_src_ck>; + ti,bit-shift = <6>; + ti,max-div = <3>; + reg = <0x1140>; + ti,index-starts-at-one; + }; + + atclk_fck: atclk_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&emu_src_ck>; + ti,bit-shift = <4>; + ti,max-div = <3>; + reg = <0x1140>; + ti,index-starts-at-one; + }; + + traceclk_src_fck: traceclk_src_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_ck>, <&emu_core_alwon_ck>, <&emu_per_alwon_ck>, <&emu_mpu_alwon_ck>; + ti,bit-shift = <2>; + reg = <0x1140>; + }; + + traceclk_fck: traceclk_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&traceclk_src_fck>; + ti,bit-shift = <11>; + ti,max-div = <7>; + reg = <0x1140>; + ti,index-starts-at-one; + }; + + secure_32k_fck: secure_32k_fck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + gpt12_fck: gpt12_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&secure_32k_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + wdt1_fck: wdt1_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&secure_32k_fck>; + clock-mult = <1>; + clock-div = <1>; + }; +}; + +&cm_clockdomains { + core_l3_clkdm: core_l3_clkdm { + compatible = "ti,clockdomain"; + clocks = <&sdrc_ick>; + }; + + dpll3_clkdm: dpll3_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll3_ck>; + }; + + dpll1_clkdm: dpll1_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll1_ck>; + }; + + per_clkdm: per_clkdm { + compatible = "ti,clockdomain"; + clocks = <&uart3_fck>, <&gpio6_dbck>, <&gpio5_dbck>, + <&gpio4_dbck>, <&gpio3_dbck>, <&gpio2_dbck>, + <&wdt3_fck>, <&gpio6_ick>, <&gpio5_ick>, <&gpio4_ick>, + <&gpio3_ick>, <&gpio2_ick>, <&wdt3_ick>, <&uart3_ick>, + <&uart4_ick>, <&gpt9_ick>, <&gpt8_ick>, <&gpt7_ick>, + <&gpt6_ick>, <&gpt5_ick>, <&gpt4_ick>, <&gpt3_ick>, + <&gpt2_ick>, <&mcbsp2_ick>, <&mcbsp3_ick>, + <&mcbsp4_ick>; + }; + + emu_clkdm: emu_clkdm { + compatible = "ti,clockdomain"; + clocks = <&emu_src_ck>; + }; + + dpll4_clkdm: dpll4_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll4_ck>; + }; + + wkup_clkdm: wkup_clkdm { + compatible = "ti,clockdomain"; + clocks = <&gpio1_dbck>, <&wdt2_fck>, <&wdt2_ick>, <&wdt1_ick>, + <&gpio1_ick>, <&omap_32ksync_ick>, <&gpt12_ick>, + <&gpt1_ick>; + }; + + dss_clkdm: dss_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dss_tv_fck>, <&dss_96m_fck>, <&dss2_alwon_fck>; + }; + + core_l4_clkdm: core_l4_clkdm { + compatible = "ti,clockdomain"; + clocks = <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>, + <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>, + <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>, + <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>, + <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>, + <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>, + <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>, + <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>, + <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>; + }; +}; diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index a1e05853afcd58..d3f8a6e8ca205e 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -107,6 +107,58 @@ interrupts = , ; + cm1: cm1@4a004000 { + compatible = "ti,omap4-cm1"; + reg = <0x4a004000 0x2000>; + + cm1_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + cm1_clockdomains: clockdomains { + }; + }; + + prm: prm@4a306000 { + compatible = "ti,omap4-prm"; + reg = <0x4a306000 0x3000>; + + prm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + prm_clockdomains: clockdomains { + }; + }; + + cm2: cm2@4a008000 { + compatible = "ti,omap4-cm2"; + reg = <0x4a008000 0x3000>; + + cm2_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + cm2_clockdomains: clockdomains { + }; + }; + + scrm: scrm@4a30a000 { + compatible = "ti,omap4-scrm"; + reg = <0x4a30a000 0x2000>; + + scrm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + scrm_clockdomains: clockdomains { + }; + }; + counter32k: counter@4a304000 { compatible = "ti,omap-counter32k"; reg = <0x4a304000 0x20>; @@ -707,3 +759,5 @@ }; }; }; + +/include/ "omap44xx-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap443x-clocks.dtsi b/arch/arm/boot/dts/omap443x-clocks.dtsi new file mode 100644 index 00000000000000..2bd2166f88d346 --- /dev/null +++ b/arch/arm/boot/dts/omap443x-clocks.dtsi @@ -0,0 +1,18 @@ +/* + * Device Tree Source for OMAP4 clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * 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. + */ +&prm_clocks { + bandgap_fclk: bandgap_fclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1888>; + }; +}; diff --git a/arch/arm/boot/dts/omap443x.dtsi b/arch/arm/boot/dts/omap443x.dtsi index ab607a19a6137f..8c1cfad30d6037 100644 --- a/arch/arm/boot/dts/omap443x.dtsi +++ b/arch/arm/boot/dts/omap443x.dtsi @@ -44,3 +44,5 @@ }; }; }; + +/include/ "omap443x-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap4460.dtsi b/arch/arm/boot/dts/omap4460.dtsi index 11566bed003584..6b32f520741a9c 100644 --- a/arch/arm/boot/dts/omap4460.dtsi +++ b/arch/arm/boot/dts/omap4460.dtsi @@ -52,3 +52,5 @@ }; }; }; + +/include/ "omap446x-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap446x-clocks.dtsi b/arch/arm/boot/dts/omap446x-clocks.dtsi new file mode 100644 index 00000000000000..be033e9803e9c5 --- /dev/null +++ b/arch/arm/boot/dts/omap446x-clocks.dtsi @@ -0,0 +1,27 @@ +/* + * Device Tree Source for OMAP4 clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * 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. + */ +&prm_clocks { + div_ts_ck: div_ts_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&l4_wkup_clk_mux_ck>; + ti,bit-shift = <24>; + reg = <0x1888>; + ti,dividers = <8>, <16>, <32>; + }; + + bandgap_ts_fclk: bandgap_ts_fclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&div_ts_ck>; + ti,bit-shift = <8>; + reg = <0x1888>; + }; +}; diff --git a/arch/arm/boot/dts/omap44xx-clocks.dtsi b/arch/arm/boot/dts/omap44xx-clocks.dtsi new file mode 100644 index 00000000000000..c821ff5e9b8da0 --- /dev/null +++ b/arch/arm/boot/dts/omap44xx-clocks.dtsi @@ -0,0 +1,1651 @@ +/* + * Device Tree Source for OMAP4 clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * 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. + */ +&cm1_clocks { + extalt_clkin_ck: extalt_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <59000000>; + }; + + pad_clks_src_ck: pad_clks_src_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + pad_clks_ck: pad_clks_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&pad_clks_src_ck>; + ti,bit-shift = <8>; + reg = <0x0108>; + }; + + pad_slimbus_core_clks_ck: pad_slimbus_core_clks_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + secure_32k_clk_src_ck: secure_32k_clk_src_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + slimbus_src_clk: slimbus_src_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + slimbus_clk: slimbus_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&slimbus_src_clk>; + ti,bit-shift = <10>; + reg = <0x0108>; + }; + + sys_32k_ck: sys_32k_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + virt_12000000_ck: virt_12000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + virt_13000000_ck: virt_13000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <13000000>; + }; + + virt_16800000_ck: virt_16800000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <16800000>; + }; + + virt_19200000_ck: virt_19200000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <19200000>; + }; + + virt_26000000_ck: virt_26000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <26000000>; + }; + + virt_27000000_ck: virt_27000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <27000000>; + }; + + virt_38400000_ck: virt_38400000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <38400000>; + }; + + tie_low_clock_ck: tie_low_clock_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + utmi_phy_clkout_ck: utmi_phy_clkout_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <60000000>; + }; + + xclk60mhsp1_ck: xclk60mhsp1_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <60000000>; + }; + + xclk60mhsp2_ck: xclk60mhsp2_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <60000000>; + }; + + xclk60motg_ck: xclk60motg_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <60000000>; + }; + + dpll_abe_ck: dpll_abe_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-m4xen-clock"; + clocks = <&abe_dpll_refclk_mux_ck>, <&abe_dpll_bypass_clk_mux_ck>; + reg = <0x01e0>, <0x01e4>, <0x01ec>, <0x01e8>; + }; + + dpll_abe_x2_ck: dpll_abe_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_abe_ck>; + reg = <0x01f0>; + }; + + dpll_abe_m2x2_ck: dpll_abe_m2x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01f0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + abe_24m_fclk: abe_24m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m2x2_ck>; + clock-mult = <1>; + clock-div = <8>; + }; + + abe_clk: abe_clk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_m2x2_ck>; + ti,max-div = <4>; + reg = <0x0108>; + ti,index-power-of-two; + }; + + aess_fclk: aess_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&abe_clk>; + ti,bit-shift = <24>; + ti,max-div = <2>; + reg = <0x0528>; + }; + + dpll_abe_m3x2_ck: dpll_abe_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01f4>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + core_hsd_byp_clk_mux_ck: core_hsd_byp_clk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_abe_m3x2_ck>; + ti,bit-shift = <23>; + reg = <0x012c>; + }; + + dpll_core_ck: dpll_core_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-core-clock"; + clocks = <&sys_clkin_ck>, <&core_hsd_byp_clk_mux_ck>; + reg = <0x0120>, <0x0124>, <0x012c>, <0x0128>; + }; + + dpll_core_x2_ck: dpll_core_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_core_ck>; + }; + + dpll_core_m6x2_ck: dpll_core_m6x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0140>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_m2_ck: dpll_core_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0130>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + ddrphy_ck: ddrphy_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + dpll_core_m5x2_ck: dpll_core_m5x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x013c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + div_core_ck: div_core_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_m5x2_ck>; + reg = <0x0100>; + ti,max-div = <2>; + }; + + div_iva_hs_clk: div_iva_hs_clk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_m5x2_ck>; + ti,max-div = <4>; + reg = <0x01dc>; + ti,index-power-of-two; + }; + + div_mpu_hs_clk: div_mpu_hs_clk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_m5x2_ck>; + ti,max-div = <4>; + reg = <0x019c>; + ti,index-power-of-two; + }; + + dpll_core_m4x2_ck: dpll_core_m4x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0138>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dll_clk_div_ck: dll_clk_div_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + dpll_abe_m2_ck: dpll_abe_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_ck>; + ti,max-div = <31>; + reg = <0x01f0>; + ti,index-starts-at-one; + }; + + dpll_core_m3x2_gate_ck: dpll_core_m3x2_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_x2_ck>; + ti,bit-shift = <8>; + reg = <0x0134>; + }; + + dpll_core_m3x2_div_ck: dpll_core_m3x2_div_ck { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + reg = <0x0134>; + ti,index-starts-at-one; + }; + + dpll_core_m3x2_ck: dpll_core_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&dpll_core_m3x2_gate_ck>, <&dpll_core_m3x2_div_ck>; + }; + + dpll_core_m7x2_ck: dpll_core_m7x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0144>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + iva_hsd_byp_clk_mux_ck: iva_hsd_byp_clk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&div_iva_hs_clk>; + ti,bit-shift = <23>; + reg = <0x01ac>; + }; + + dpll_iva_ck: dpll_iva_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin_ck>, <&iva_hsd_byp_clk_mux_ck>; + reg = <0x01a0>, <0x01a4>, <0x01ac>, <0x01a8>; + }; + + dpll_iva_x2_ck: dpll_iva_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_iva_ck>; + }; + + dpll_iva_m4x2_ck: dpll_iva_m4x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_iva_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01b8>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_iva_m5x2_ck: dpll_iva_m5x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_iva_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01bc>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_mpu_ck: dpll_mpu_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin_ck>, <&div_mpu_hs_clk>; + reg = <0x0160>, <0x0164>, <0x016c>, <0x0168>; + }; + + dpll_mpu_m2_ck: dpll_mpu_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_mpu_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0170>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + per_hs_clk_div_ck: per_hs_clk_div_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m3x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + usb_hs_clk_div_ck: usb_hs_clk_div_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m3x2_ck>; + clock-mult = <1>; + clock-div = <3>; + }; + + l3_div_ck: l3_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&div_core_ck>; + ti,bit-shift = <4>; + ti,max-div = <2>; + reg = <0x0100>; + }; + + l4_div_ck: l4_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&l3_div_ck>; + ti,bit-shift = <8>; + ti,max-div = <2>; + reg = <0x0100>; + }; + + lp_clk_div_ck: lp_clk_div_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m2x2_ck>; + clock-mult = <1>; + clock-div = <16>; + }; + + mpu_periphclk: mpu_periphclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_mpu_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + ocp_abe_iclk: ocp_abe_iclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&aess_fclk>; + ti,bit-shift = <24>; + reg = <0x0528>; + ti,dividers = <2>, <1>; + }; + + per_abe_24m_fclk: per_abe_24m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + dmic_sync_mux_ck: dmic_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>; + ti,bit-shift = <25>; + reg = <0x0538>; + }; + + func_dmic_abe_gfclk: func_dmic_abe_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dmic_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0538>; + }; + + mcasp_sync_mux_ck: mcasp_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>; + ti,bit-shift = <25>; + reg = <0x0540>; + }; + + func_mcasp_abe_gfclk: func_mcasp_abe_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcasp_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0540>; + }; + + mcbsp1_sync_mux_ck: mcbsp1_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>; + ti,bit-shift = <25>; + reg = <0x0548>; + }; + + func_mcbsp1_gfclk: func_mcbsp1_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcbsp1_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0548>; + }; + + mcbsp2_sync_mux_ck: mcbsp2_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>; + ti,bit-shift = <25>; + reg = <0x0550>; + }; + + func_mcbsp2_gfclk: func_mcbsp2_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcbsp2_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0550>; + }; + + mcbsp3_sync_mux_ck: mcbsp3_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>; + ti,bit-shift = <25>; + reg = <0x0558>; + }; + + func_mcbsp3_gfclk: func_mcbsp3_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcbsp3_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0558>; + }; + + slimbus1_fclk_1: slimbus1_fclk_1 { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_24m_clk>; + ti,bit-shift = <9>; + reg = <0x0560>; + }; + + slimbus1_fclk_0: slimbus1_fclk_0 { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&abe_24m_fclk>; + ti,bit-shift = <8>; + reg = <0x0560>; + }; + + slimbus1_fclk_2: slimbus1_fclk_2 { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&pad_clks_ck>; + ti,bit-shift = <10>; + reg = <0x0560>; + }; + + slimbus1_slimbus_clk: slimbus1_slimbus_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&slimbus_clk>; + ti,bit-shift = <11>; + reg = <0x0560>; + }; + + timer5_sync_mux: timer5_sync_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&syc_clk_div_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0568>; + }; + + timer6_sync_mux: timer6_sync_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&syc_clk_div_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0570>; + }; + + timer7_sync_mux: timer7_sync_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&syc_clk_div_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0578>; + }; + + timer8_sync_mux: timer8_sync_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&syc_clk_div_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0580>; + }; + + dummy_ck: dummy_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; +}; +&prm_clocks { + sys_clkin_ck: sys_clkin_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>; + reg = <0x0110>; + ti,index-starts-at-one; + }; + + abe_dpll_bypass_clk_mux_ck: abe_dpll_bypass_clk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0108>; + }; + + abe_dpll_refclk_mux_ck: abe_dpll_refclk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + reg = <0x010c>; + }; + + dbgclk_mux_ck: dbgclk_mux_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l4_wkup_clk_mux_ck: l4_wkup_clk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&lp_clk_div_ck>; + reg = <0x0108>; + }; + + syc_clk_div_ck: syc_clk_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sys_clkin_ck>; + reg = <0x0100>; + ti,max-div = <2>; + }; + + gpio1_dbclk: gpio1_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1838>; + }; + + dmt1_clk_mux: dmt1_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1840>; + }; + + usim_ck: usim_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_m4x2_ck>; + ti,bit-shift = <24>; + reg = <0x1858>; + ti,dividers = <14>, <18>; + }; + + usim_fclk: usim_fclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&usim_ck>; + ti,bit-shift = <8>; + reg = <0x1858>; + }; + + pmd_stm_clock_mux_ck: pmd_stm_clock_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_core_m6x2_ck>, <&tie_low_clock_ck>; + ti,bit-shift = <20>; + reg = <0x1a20>; + }; + + pmd_trace_clk_mux_ck: pmd_trace_clk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_core_m6x2_ck>, <&tie_low_clock_ck>; + ti,bit-shift = <22>; + reg = <0x1a20>; + }; + + stm_clk_div_ck: stm_clk_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&pmd_stm_clock_mux_ck>; + ti,bit-shift = <27>; + ti,max-div = <64>; + reg = <0x1a20>; + ti,index-power-of-two; + }; + + trace_clk_div_div_ck: trace_clk_div_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&pmd_trace_clk_mux_ck>; + ti,bit-shift = <24>; + reg = <0x1a20>; + ti,dividers = <0>, <1>, <2>, <0>, <4>; + }; + + trace_clk_div_ck: trace_clk_div_ck { + #clock-cells = <0>; + compatible = "ti,clkdm-gate-clock"; + clocks = <&trace_clk_div_div_ck>; + }; +}; + +&prm_clockdomains { + emu_sys_clkdm: emu_sys_clkdm { + compatible = "ti,clockdomain"; + clocks = <&trace_clk_div_ck>; + }; +}; + +&cm2_clocks { + per_hsd_byp_clk_mux_ck: per_hsd_byp_clk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&per_hs_clk_div_ck>; + ti,bit-shift = <23>; + reg = <0x014c>; + }; + + dpll_per_ck: dpll_per_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin_ck>, <&per_hsd_byp_clk_mux_ck>; + reg = <0x0140>, <0x0144>, <0x014c>, <0x0148>; + }; + + dpll_per_m2_ck: dpll_per_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_ck>; + ti,max-div = <31>; + reg = <0x0150>; + ti,index-starts-at-one; + }; + + dpll_per_x2_ck: dpll_per_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_per_ck>; + reg = <0x0150>; + }; + + dpll_per_m2x2_ck: dpll_per_m2x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0150>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m3x2_gate_ck: dpll_per_m3x2_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_per_x2_ck>; + ti,bit-shift = <8>; + reg = <0x0154>; + }; + + dpll_per_m3x2_div_ck: dpll_per_m3x2_div_ck { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + reg = <0x0154>; + ti,index-starts-at-one; + }; + + dpll_per_m3x2_ck: dpll_per_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&dpll_per_m3x2_gate_ck>, <&dpll_per_m3x2_div_ck>; + }; + + dpll_per_m4x2_ck: dpll_per_m4x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0158>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m5x2_ck: dpll_per_m5x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x015c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m6x2_ck: dpll_per_m6x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0160>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m7x2_ck: dpll_per_m7x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0164>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_usb_ck: dpll_usb_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-j-type-clock"; + clocks = <&sys_clkin_ck>, <&usb_hs_clk_div_ck>; + reg = <0x0180>, <0x0184>, <0x018c>, <0x0188>; + }; + + dpll_usb_clkdcoldo_ck: dpll_usb_clkdcoldo_ck { + #clock-cells = <0>; + compatible = "ti,fixed-factor-clock"; + clocks = <&dpll_usb_ck>; + ti,clock-div = <1>; + ti,autoidle-shift = <8>; + reg = <0x01b4>; + ti,clock-mult = <1>; + ti,invert-autoidle-bit; + }; + + dpll_usb_m2_ck: dpll_usb_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_ck>; + ti,max-div = <127>; + ti,autoidle-shift = <8>; + reg = <0x0190>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + ducati_clk_mux_ck: ducati_clk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&div_core_ck>, <&dpll_per_m6x2_ck>; + reg = <0x0100>; + }; + + func_12m_fclk: func_12m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <16>; + }; + + func_24m_clk: func_24m_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + func_24mc_fclk: func_24mc_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <8>; + }; + + func_48m_fclk: func_48m_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_m2x2_ck>; + reg = <0x0108>; + ti,dividers = <4>, <8>; + }; + + func_48mc_fclk: func_48mc_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + func_64m_fclk: func_64m_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_m4x2_ck>; + reg = <0x0108>; + ti,dividers = <2>, <4>; + }; + + func_96m_fclk: func_96m_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_m2x2_ck>; + reg = <0x0108>; + ti,dividers = <2>, <4>; + }; + + init_60m_fclk: init_60m_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_m2_ck>; + reg = <0x0104>; + ti,dividers = <1>, <8>; + }; + + per_abe_nc_fclk: per_abe_nc_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_m2_ck>; + reg = <0x0108>; + ti,max-div = <2>; + }; + + aes1_fck: aes1_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3_div_ck>; + ti,bit-shift = <1>; + reg = <0x15a0>; + }; + + aes2_fck: aes2_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3_div_ck>; + ti,bit-shift = <1>; + reg = <0x15a8>; + }; + + dss_sys_clk: dss_sys_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&syc_clk_div_ck>; + ti,bit-shift = <10>; + reg = <0x1120>; + }; + + dss_tv_clk: dss_tv_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&extalt_clkin_ck>; + ti,bit-shift = <11>; + reg = <0x1120>; + }; + + dss_dss_clk: dss_dss_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_per_m5x2_ck>; + ti,bit-shift = <8>; + reg = <0x1120>; + ti,set-rate-parent; + }; + + dss_48mhz_clk: dss_48mhz_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_48mc_fclk>; + ti,bit-shift = <9>; + reg = <0x1120>; + }; + + dss_fck: dss_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3_div_ck>; + ti,bit-shift = <1>; + reg = <0x1120>; + }; + + fdif_fck: fdif_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_m4x2_ck>; + ti,bit-shift = <24>; + ti,max-div = <4>; + reg = <0x1028>; + ti,index-power-of-two; + }; + + gpio2_dbclk: gpio2_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1460>; + }; + + gpio3_dbclk: gpio3_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1468>; + }; + + gpio4_dbclk: gpio4_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1470>; + }; + + gpio5_dbclk: gpio5_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1478>; + }; + + gpio6_dbclk: gpio6_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1480>; + }; + + sgx_clk_mux: sgx_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_core_m7x2_ck>, <&dpll_per_m7x2_ck>; + ti,bit-shift = <24>; + reg = <0x1220>; + }; + + hsi_fck: hsi_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + ti,max-div = <4>; + reg = <0x1338>; + ti,index-power-of-two; + }; + + iss_ctrlclk: iss_ctrlclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_96m_fclk>; + ti,bit-shift = <8>; + reg = <0x1020>; + }; + + mcbsp4_sync_mux_ck: mcbsp4_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_96m_fclk>, <&per_abe_nc_fclk>; + ti,bit-shift = <25>; + reg = <0x14e0>; + }; + + per_mcbsp4_gfclk: per_mcbsp4_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcbsp4_sync_mux_ck>, <&pad_clks_ck>; + ti,bit-shift = <24>; + reg = <0x14e0>; + }; + + hsmmc1_fclk: hsmmc1_fclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_64m_fclk>, <&func_96m_fclk>; + ti,bit-shift = <24>; + reg = <0x1328>; + }; + + hsmmc2_fclk: hsmmc2_fclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_64m_fclk>, <&func_96m_fclk>; + ti,bit-shift = <24>; + reg = <0x1330>; + }; + + ocp2scp_usb_phy_phy_48m: ocp2scp_usb_phy_phy_48m { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_48m_fclk>; + ti,bit-shift = <8>; + reg = <0x13e0>; + }; + + sha2md5_fck: sha2md5_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3_div_ck>; + ti,bit-shift = <1>; + reg = <0x15c8>; + }; + + slimbus2_fclk_1: slimbus2_fclk_1 { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&per_abe_24m_fclk>; + ti,bit-shift = <9>; + reg = <0x1538>; + }; + + slimbus2_fclk_0: slimbus2_fclk_0 { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_24mc_fclk>; + ti,bit-shift = <8>; + reg = <0x1538>; + }; + + slimbus2_slimbus_clk: slimbus2_slimbus_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&pad_slimbus_core_clks_ck>; + ti,bit-shift = <10>; + reg = <0x1538>; + }; + + smartreflex_core_fck: smartreflex_core_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l4_wkup_clk_mux_ck>; + ti,bit-shift = <1>; + reg = <0x0638>; + }; + + smartreflex_iva_fck: smartreflex_iva_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l4_wkup_clk_mux_ck>; + ti,bit-shift = <1>; + reg = <0x0630>; + }; + + smartreflex_mpu_fck: smartreflex_mpu_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l4_wkup_clk_mux_ck>; + ti,bit-shift = <1>; + reg = <0x0628>; + }; + + cm2_dm10_mux: cm2_dm10_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1428>; + }; + + cm2_dm11_mux: cm2_dm11_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1430>; + }; + + cm2_dm2_mux: cm2_dm2_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1438>; + }; + + cm2_dm3_mux: cm2_dm3_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1440>; + }; + + cm2_dm4_mux: cm2_dm4_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1448>; + }; + + cm2_dm9_mux: cm2_dm9_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1450>; + }; + + usb_host_fs_fck: usb_host_fs_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_48mc_fclk>; + ti,bit-shift = <1>; + reg = <0x13d0>; + }; + + utmi_p1_gfclk: utmi_p1_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&init_60m_fclk>, <&xclk60mhsp1_ck>; + ti,bit-shift = <24>; + reg = <0x1358>; + }; + + usb_host_hs_utmi_p1_clk: usb_host_hs_utmi_p1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&utmi_p1_gfclk>; + ti,bit-shift = <8>; + reg = <0x1358>; + }; + + utmi_p2_gfclk: utmi_p2_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&init_60m_fclk>, <&xclk60mhsp2_ck>; + ti,bit-shift = <25>; + reg = <0x1358>; + }; + + usb_host_hs_utmi_p2_clk: usb_host_hs_utmi_p2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&utmi_p2_gfclk>; + ti,bit-shift = <9>; + reg = <0x1358>; + }; + + usb_host_hs_utmi_p3_clk: usb_host_hs_utmi_p3_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&init_60m_fclk>; + ti,bit-shift = <10>; + reg = <0x1358>; + }; + + usb_host_hs_hsic480m_p1_clk: usb_host_hs_hsic480m_p1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_usb_m2_ck>; + ti,bit-shift = <13>; + reg = <0x1358>; + }; + + usb_host_hs_hsic60m_p1_clk: usb_host_hs_hsic60m_p1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&init_60m_fclk>; + ti,bit-shift = <11>; + reg = <0x1358>; + }; + + usb_host_hs_hsic60m_p2_clk: usb_host_hs_hsic60m_p2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&init_60m_fclk>; + ti,bit-shift = <12>; + reg = <0x1358>; + }; + + usb_host_hs_hsic480m_p2_clk: usb_host_hs_hsic480m_p2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_usb_m2_ck>; + ti,bit-shift = <14>; + reg = <0x1358>; + }; + + usb_host_hs_func48mclk: usb_host_hs_func48mclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_48mc_fclk>; + ti,bit-shift = <15>; + reg = <0x1358>; + }; + + usb_host_hs_fck: usb_host_hs_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&init_60m_fclk>; + ti,bit-shift = <1>; + reg = <0x1358>; + }; + + otg_60m_gfclk: otg_60m_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&utmi_phy_clkout_ck>, <&xclk60motg_ck>; + ti,bit-shift = <24>; + reg = <0x1360>; + }; + + usb_otg_hs_xclk: usb_otg_hs_xclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&otg_60m_gfclk>; + ti,bit-shift = <8>; + reg = <0x1360>; + }; + + usb_otg_hs_ick: usb_otg_hs_ick { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3_div_ck>; + ti,bit-shift = <0>; + reg = <0x1360>; + }; + + usb_phy_cm_clk32k: usb_phy_cm_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x0640>; + }; + + usb_tll_hs_usb_ch2_clk: usb_tll_hs_usb_ch2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&init_60m_fclk>; + ti,bit-shift = <10>; + reg = <0x1368>; + }; + + usb_tll_hs_usb_ch0_clk: usb_tll_hs_usb_ch0_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&init_60m_fclk>; + ti,bit-shift = <8>; + reg = <0x1368>; + }; + + usb_tll_hs_usb_ch1_clk: usb_tll_hs_usb_ch1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&init_60m_fclk>; + ti,bit-shift = <9>; + reg = <0x1368>; + }; + + usb_tll_hs_ick: usb_tll_hs_ick { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l4_div_ck>; + ti,bit-shift = <0>; + reg = <0x1368>; + }; +}; + +&cm2_clockdomains { + l3_init_clkdm: l3_init_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll_usb_ck>, <&usb_host_fs_fck>; + }; +}; + +&scrm_clocks { + auxclk0_src_gate_ck: auxclk0_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0310>; + }; + + auxclk0_src_mux_ck: auxclk0_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0310>; + }; + + auxclk0_src_ck: auxclk0_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk0_src_gate_ck>, <&auxclk0_src_mux_ck>; + }; + + auxclk0_ck: auxclk0_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk0_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0310>; + }; + + auxclk1_src_gate_ck: auxclk1_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0314>; + }; + + auxclk1_src_mux_ck: auxclk1_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0314>; + }; + + auxclk1_src_ck: auxclk1_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk1_src_gate_ck>, <&auxclk1_src_mux_ck>; + }; + + auxclk1_ck: auxclk1_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk1_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0314>; + }; + + auxclk2_src_gate_ck: auxclk2_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0318>; + }; + + auxclk2_src_mux_ck: auxclk2_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0318>; + }; + + auxclk2_src_ck: auxclk2_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk2_src_gate_ck>, <&auxclk2_src_mux_ck>; + }; + + auxclk2_ck: auxclk2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk2_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0318>; + }; + + auxclk3_src_gate_ck: auxclk3_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x031c>; + }; + + auxclk3_src_mux_ck: auxclk3_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x031c>; + }; + + auxclk3_src_ck: auxclk3_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk3_src_gate_ck>, <&auxclk3_src_mux_ck>; + }; + + auxclk3_ck: auxclk3_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk3_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x031c>; + }; + + auxclk4_src_gate_ck: auxclk4_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0320>; + }; + + auxclk4_src_mux_ck: auxclk4_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0320>; + }; + + auxclk4_src_ck: auxclk4_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk4_src_gate_ck>, <&auxclk4_src_mux_ck>; + }; + + auxclk4_ck: auxclk4_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk4_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0320>; + }; + + auxclk5_src_gate_ck: auxclk5_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0324>; + }; + + auxclk5_src_mux_ck: auxclk5_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0324>; + }; + + auxclk5_src_ck: auxclk5_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk5_src_gate_ck>, <&auxclk5_src_mux_ck>; + }; + + auxclk5_ck: auxclk5_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk5_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0324>; + }; + + auxclkreq0_ck: auxclkreq0_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>; + ti,bit-shift = <2>; + reg = <0x0210>; + }; + + auxclkreq1_ck: auxclkreq1_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>; + ti,bit-shift = <2>; + reg = <0x0214>; + }; + + auxclkreq2_ck: auxclkreq2_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>; + ti,bit-shift = <2>; + reg = <0x0218>; + }; + + auxclkreq3_ck: auxclkreq3_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>; + ti,bit-shift = <2>; + reg = <0x021c>; + }; + + auxclkreq4_ck: auxclkreq4_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>; + ti,bit-shift = <2>; + reg = <0x0220>; + }; + + auxclkreq5_ck: auxclkreq5_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>; + ti,bit-shift = <2>; + reg = <0x0224>; + }; +}; diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index ab9a21ae82f34a..a72813a9663ecc 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -117,6 +117,58 @@ interrupts = , ; + prm: prm@4ae06000 { + compatible = "ti,omap5-prm"; + reg = <0x4ae06000 0x3000>; + + prm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + prm_clockdomains: clockdomains { + }; + }; + + cm_core_aon: cm_core_aon@4a004000 { + compatible = "ti,omap5-cm-core-aon"; + reg = <0x4a004000 0x2000>; + + cm_core_aon_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + cm_core_aon_clockdomains: clockdomains { + }; + }; + + scrm: scrm@4ae0a000 { + compatible = "ti,omap5-scrm"; + reg = <0x4ae0a000 0x2000>; + + scrm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + scrm_clockdomains: clockdomains { + }; + }; + + cm_core: cm_core@4a008000 { + compatible = "ti,omap5-cm-core"; + reg = <0x4a008000 0x3000>; + + cm_core_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + cm_core_clockdomains: clockdomains { + }; + }; + counter32k: counter@4ae04000 { compatible = "ti,omap-counter32k"; reg = <0x4ae04000 0x40>; @@ -751,3 +803,5 @@ }; }; }; + +/include/ "omap54xx-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap54xx-clocks.dtsi b/arch/arm/boot/dts/omap54xx-clocks.dtsi new file mode 100644 index 00000000000000..d487fdab392169 --- /dev/null +++ b/arch/arm/boot/dts/omap54xx-clocks.dtsi @@ -0,0 +1,1399 @@ +/* + * Device Tree Source for OMAP5 clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * 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. + */ +&cm_core_aon_clocks { + pad_clks_src_ck: pad_clks_src_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + pad_clks_ck: pad_clks_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&pad_clks_src_ck>; + ti,bit-shift = <8>; + reg = <0x0108>; + }; + + secure_32k_clk_src_ck: secure_32k_clk_src_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + slimbus_src_clk: slimbus_src_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + slimbus_clk: slimbus_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&slimbus_src_clk>; + ti,bit-shift = <10>; + reg = <0x0108>; + }; + + sys_32k_ck: sys_32k_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + virt_12000000_ck: virt_12000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + virt_13000000_ck: virt_13000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <13000000>; + }; + + virt_16800000_ck: virt_16800000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <16800000>; + }; + + virt_19200000_ck: virt_19200000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <19200000>; + }; + + virt_26000000_ck: virt_26000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <26000000>; + }; + + virt_27000000_ck: virt_27000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <27000000>; + }; + + virt_38400000_ck: virt_38400000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <38400000>; + }; + + xclk60mhsp1_ck: xclk60mhsp1_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <60000000>; + }; + + xclk60mhsp2_ck: xclk60mhsp2_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <60000000>; + }; + + dpll_abe_ck: dpll_abe_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-m4xen-clock"; + clocks = <&abe_dpll_clk_mux>, <&abe_dpll_bypass_clk_mux>; + reg = <0x01e0>, <0x01e4>, <0x01ec>, <0x01e8>; + }; + + dpll_abe_x2_ck: dpll_abe_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_abe_ck>; + }; + + dpll_abe_m2x2_ck: dpll_abe_m2x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01f0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + abe_24m_fclk: abe_24m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m2x2_ck>; + clock-mult = <1>; + clock-div = <8>; + }; + + abe_clk: abe_clk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_m2x2_ck>; + ti,max-div = <4>; + reg = <0x0108>; + ti,index-power-of-two; + }; + + abe_iclk: abe_iclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&abe_clk>; + clock-mult = <1>; + clock-div = <2>; + }; + + abe_lp_clk_div: abe_lp_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m2x2_ck>; + clock-mult = <1>; + clock-div = <16>; + }; + + dpll_abe_m3x2_ck: dpll_abe_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01f4>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_ck: dpll_core_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-core-clock"; + clocks = <&sys_clkin>, <&dpll_abe_m3x2_ck>; + reg = <0x0120>, <0x0124>, <0x012c>, <0x0128>; + }; + + dpll_core_x2_ck: dpll_core_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_core_ck>; + }; + + dpll_core_h21x2_ck: dpll_core_h21x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0150>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + c2c_fclk: c2c_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h21x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + c2c_iclk: c2c_iclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&c2c_fclk>; + clock-mult = <1>; + clock-div = <2>; + }; + + dpll_core_h11x2_ck: dpll_core_h11x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0138>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h12x2_ck: dpll_core_h12x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x013c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h13x2_ck: dpll_core_h13x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0140>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h14x2_ck: dpll_core_h14x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0144>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h22x2_ck: dpll_core_h22x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0154>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h23x2_ck: dpll_core_h23x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0158>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h24x2_ck: dpll_core_h24x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x015c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_m2_ck: dpll_core_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0130>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_m3x2_ck: dpll_core_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0134>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + iva_dpll_hs_clk_div: iva_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h12x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_iva_ck: dpll_iva_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin>, <&iva_dpll_hs_clk_div>; + reg = <0x01a0>, <0x01a4>, <0x01ac>, <0x01a8>; + }; + + dpll_iva_x2_ck: dpll_iva_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_iva_ck>; + }; + + dpll_iva_h11x2_ck: dpll_iva_h11x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_iva_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x01b8>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_iva_h12x2_ck: dpll_iva_h12x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_iva_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x01bc>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + mpu_dpll_hs_clk_div: mpu_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h12x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_mpu_ck: dpll_mpu_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin>, <&mpu_dpll_hs_clk_div>; + reg = <0x0160>, <0x0164>, <0x016c>, <0x0168>; + }; + + dpll_mpu_m2_ck: dpll_mpu_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_mpu_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0170>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + per_dpll_hs_clk_div: per_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m3x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + usb_dpll_hs_clk_div: usb_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m3x2_ck>; + clock-mult = <1>; + clock-div = <3>; + }; + + l3_iclk_div: l3_iclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h12x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + gpu_l3_iclk: gpu_l3_iclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l3_iclk_div>; + clock-mult = <1>; + clock-div = <1>; + }; + + l4_root_clk_div: l4_root_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l3_iclk_div>; + clock-mult = <1>; + clock-div = <1>; + }; + + slimbus1_slimbus_clk: slimbus1_slimbus_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&slimbus_clk>; + ti,bit-shift = <11>; + reg = <0x0560>; + }; + + aess_fclk: aess_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&abe_clk>; + ti,bit-shift = <24>; + ti,max-div = <2>; + reg = <0x0528>; + }; + + dmic_sync_mux_ck: dmic_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>; + ti,bit-shift = <26>; + reg = <0x0538>; + }; + + dmic_gfclk: dmic_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dmic_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0538>; + }; + + mcasp_sync_mux_ck: mcasp_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>; + ti,bit-shift = <26>; + reg = <0x0540>; + }; + + mcasp_gfclk: mcasp_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcasp_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0540>; + }; + + mcbsp1_sync_mux_ck: mcbsp1_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>; + ti,bit-shift = <26>; + reg = <0x0548>; + }; + + mcbsp1_gfclk: mcbsp1_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcbsp1_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0548>; + }; + + mcbsp2_sync_mux_ck: mcbsp2_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>; + ti,bit-shift = <26>; + reg = <0x0550>; + }; + + mcbsp2_gfclk: mcbsp2_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcbsp2_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0550>; + }; + + mcbsp3_sync_mux_ck: mcbsp3_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>; + ti,bit-shift = <26>; + reg = <0x0558>; + }; + + mcbsp3_gfclk: mcbsp3_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcbsp3_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0558>; + }; + + timer5_gfclk_mux: timer5_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dss_syc_gfclk_div>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0568>; + }; + + timer6_gfclk_mux: timer6_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dss_syc_gfclk_div>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0570>; + }; + + timer7_gfclk_mux: timer7_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dss_syc_gfclk_div>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0578>; + }; + + timer8_gfclk_mux: timer8_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dss_syc_gfclk_div>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0580>; + }; + + dummy_ck: dummy_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; +}; +&prm_clocks { + sys_clkin: sys_clkin { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>; + reg = <0x0110>; + ti,index-starts-at-one; + }; + + abe_dpll_bypass_clk_mux: abe_dpll_bypass_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + reg = <0x0108>; + }; + + abe_dpll_clk_mux: abe_dpll_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + reg = <0x010c>; + }; + + custefuse_sys_gfclk_div: custefuse_sys_gfclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin>; + clock-mult = <1>; + clock-div = <2>; + }; + + dss_syc_gfclk_div: dss_syc_gfclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin>; + clock-mult = <1>; + clock-div = <1>; + }; + + wkupaon_iclk_mux: wkupaon_iclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&abe_lp_clk_div>; + reg = <0x0108>; + }; + + l3instr_ts_gclk_div: l3instr_ts_gclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&wkupaon_iclk_mux>; + clock-mult = <1>; + clock-div = <1>; + }; + + gpio1_dbclk: gpio1_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1938>; + }; + + timer1_gfclk_mux: timer1_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1940>; + }; +}; +&cm_core_clocks { + dpll_per_ck: dpll_per_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin>, <&per_dpll_hs_clk_div>; + reg = <0x0140>, <0x0144>, <0x014c>, <0x0148>; + }; + + dpll_per_x2_ck: dpll_per_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_per_ck>; + }; + + dpll_per_h11x2_ck: dpll_per_h11x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0158>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_h12x2_ck: dpll_per_h12x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x015c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_h14x2_ck: dpll_per_h14x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0164>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m2_ck: dpll_per_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0150>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m2x2_ck: dpll_per_m2x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0150>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m3x2_ck: dpll_per_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0154>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_unipro1_ck: dpll_unipro1_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin>, <&sys_clkin>; + reg = <0x0200>, <0x0204>, <0x020c>, <0x0208>; + }; + + dpll_unipro1_clkdcoldo: dpll_unipro1_clkdcoldo { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_unipro1_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_unipro1_m2_ck: dpll_unipro1_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_unipro1_ck>; + ti,max-div = <127>; + ti,autoidle-shift = <8>; + reg = <0x0210>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_unipro2_ck: dpll_unipro2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin>, <&sys_clkin>; + reg = <0x01c0>, <0x01c4>, <0x01cc>, <0x01c8>; + }; + + dpll_unipro2_clkdcoldo: dpll_unipro2_clkdcoldo { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_unipro2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_unipro2_m2_ck: dpll_unipro2_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_unipro2_ck>; + ti,max-div = <127>; + ti,autoidle-shift = <8>; + reg = <0x01d0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_usb_ck: dpll_usb_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-j-type-clock"; + clocks = <&sys_clkin>, <&usb_dpll_hs_clk_div>; + reg = <0x0180>, <0x0184>, <0x018c>, <0x0188>; + }; + + dpll_usb_clkdcoldo: dpll_usb_clkdcoldo { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_usb_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_usb_m2_ck: dpll_usb_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_ck>; + ti,max-div = <127>; + ti,autoidle-shift = <8>; + reg = <0x0190>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + func_128m_clk: func_128m_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_h11x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + func_12m_fclk: func_12m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <16>; + }; + + func_24m_clk: func_24m_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + func_48m_fclk: func_48m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + func_96m_fclk: func_96m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + l3init_60m_fclk: l3init_60m_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_m2_ck>; + reg = <0x0104>; + ti,dividers = <1>, <8>; + }; + + dss_32khz_clk: dss_32khz_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <11>; + reg = <0x1420>; + }; + + dss_48mhz_clk: dss_48mhz_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_48m_fclk>; + ti,bit-shift = <9>; + reg = <0x1420>; + }; + + dss_dss_clk: dss_dss_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_per_h12x2_ck>; + ti,bit-shift = <8>; + reg = <0x1420>; + }; + + dss_sys_clk: dss_sys_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dss_syc_gfclk_div>; + ti,bit-shift = <10>; + reg = <0x1420>; + }; + + gpio2_dbclk: gpio2_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1060>; + }; + + gpio3_dbclk: gpio3_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1068>; + }; + + gpio4_dbclk: gpio4_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1070>; + }; + + gpio5_dbclk: gpio5_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1078>; + }; + + gpio6_dbclk: gpio6_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1080>; + }; + + gpio7_dbclk: gpio7_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1110>; + }; + + gpio8_dbclk: gpio8_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1118>; + }; + + iss_ctrlclk: iss_ctrlclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_96m_fclk>; + ti,bit-shift = <8>; + reg = <0x1320>; + }; + + lli_txphy_clk: lli_txphy_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_unipro1_clkdcoldo>; + ti,bit-shift = <8>; + reg = <0x0f20>; + }; + + lli_txphy_ls_clk: lli_txphy_ls_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_unipro1_m2_ck>; + ti,bit-shift = <9>; + reg = <0x0f20>; + }; + + mmc1_32khz_clk: mmc1_32khz_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1628>; + }; + + sata_ref_clk: sata_ref_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_clkin>; + ti,bit-shift = <8>; + reg = <0x1688>; + }; + + usb_host_hs_hsic480m_p1_clk: usb_host_hs_hsic480m_p1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_usb_m2_ck>; + ti,bit-shift = <13>; + reg = <0x1658>; + }; + + usb_host_hs_hsic480m_p2_clk: usb_host_hs_hsic480m_p2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_usb_m2_ck>; + ti,bit-shift = <14>; + reg = <0x1658>; + }; + + usb_host_hs_hsic480m_p3_clk: usb_host_hs_hsic480m_p3_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_usb_m2_ck>; + ti,bit-shift = <7>; + reg = <0x1658>; + }; + + usb_host_hs_hsic60m_p1_clk: usb_host_hs_hsic60m_p1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3init_60m_fclk>; + ti,bit-shift = <11>; + reg = <0x1658>; + }; + + usb_host_hs_hsic60m_p2_clk: usb_host_hs_hsic60m_p2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3init_60m_fclk>; + ti,bit-shift = <12>; + reg = <0x1658>; + }; + + usb_host_hs_hsic60m_p3_clk: usb_host_hs_hsic60m_p3_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3init_60m_fclk>; + ti,bit-shift = <6>; + reg = <0x1658>; + }; + + utmi_p1_gfclk: utmi_p1_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&l3init_60m_fclk>, <&xclk60mhsp1_ck>; + ti,bit-shift = <24>; + reg = <0x1658>; + }; + + usb_host_hs_utmi_p1_clk: usb_host_hs_utmi_p1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&utmi_p1_gfclk>; + ti,bit-shift = <8>; + reg = <0x1658>; + }; + + utmi_p2_gfclk: utmi_p2_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&l3init_60m_fclk>, <&xclk60mhsp2_ck>; + ti,bit-shift = <25>; + reg = <0x1658>; + }; + + usb_host_hs_utmi_p2_clk: usb_host_hs_utmi_p2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&utmi_p2_gfclk>; + ti,bit-shift = <9>; + reg = <0x1658>; + }; + + usb_host_hs_utmi_p3_clk: usb_host_hs_utmi_p3_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3init_60m_fclk>; + ti,bit-shift = <10>; + reg = <0x1658>; + }; + + usb_otg_ss_refclk960m: usb_otg_ss_refclk960m { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_usb_clkdcoldo>; + ti,bit-shift = <8>; + reg = <0x16f0>; + }; + + usb_phy_cm_clk32k: usb_phy_cm_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x0640>; + }; + + usb_tll_hs_usb_ch0_clk: usb_tll_hs_usb_ch0_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3init_60m_fclk>; + ti,bit-shift = <8>; + reg = <0x1668>; + }; + + usb_tll_hs_usb_ch1_clk: usb_tll_hs_usb_ch1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3init_60m_fclk>; + ti,bit-shift = <9>; + reg = <0x1668>; + }; + + usb_tll_hs_usb_ch2_clk: usb_tll_hs_usb_ch2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3init_60m_fclk>; + ti,bit-shift = <10>; + reg = <0x1668>; + }; + + fdif_fclk: fdif_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_h11x2_ck>; + ti,bit-shift = <24>; + ti,max-div = <2>; + reg = <0x1328>; + }; + + gpu_core_gclk_mux: gpu_core_gclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_core_h14x2_ck>, <&dpll_per_h14x2_ck>; + ti,bit-shift = <24>; + reg = <0x1520>; + }; + + gpu_hyd_gclk_mux: gpu_hyd_gclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_core_h14x2_ck>, <&dpll_per_h14x2_ck>; + ti,bit-shift = <25>; + reg = <0x1520>; + }; + + hsi_fclk: hsi_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + ti,max-div = <2>; + reg = <0x1638>; + }; + + mmc1_fclk_mux: mmc1_fclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_128m_clk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1628>; + }; + + mmc1_fclk: mmc1_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mmc1_fclk_mux>; + ti,bit-shift = <25>; + ti,max-div = <2>; + reg = <0x1628>; + }; + + mmc2_fclk_mux: mmc2_fclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_128m_clk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1630>; + }; + + mmc2_fclk: mmc2_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mmc2_fclk_mux>; + ti,bit-shift = <25>; + ti,max-div = <2>; + reg = <0x1630>; + }; + + timer10_gfclk_mux: timer10_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1028>; + }; + + timer11_gfclk_mux: timer11_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1030>; + }; + + timer2_gfclk_mux: timer2_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1038>; + }; + + timer3_gfclk_mux: timer3_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1040>; + }; + + timer4_gfclk_mux: timer4_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1048>; + }; + + timer9_gfclk_mux: timer9_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1050>; + }; +}; + +&cm_core_clockdomains { + l3init_clkdm: l3init_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll_usb_ck>; + }; +}; + +&scrm_clocks { + auxclk0_src_gate_ck: auxclk0_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0310>; + }; + + auxclk0_src_mux_ck: auxclk0_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0310>; + }; + + auxclk0_src_ck: auxclk0_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk0_src_gate_ck>, <&auxclk0_src_mux_ck>; + }; + + auxclk0_ck: auxclk0_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk0_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0310>; + }; + + auxclk1_src_gate_ck: auxclk1_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0314>; + }; + + auxclk1_src_mux_ck: auxclk1_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0314>; + }; + + auxclk1_src_ck: auxclk1_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk1_src_gate_ck>, <&auxclk1_src_mux_ck>; + }; + + auxclk1_ck: auxclk1_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk1_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0314>; + }; + + auxclk2_src_gate_ck: auxclk2_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0318>; + }; + + auxclk2_src_mux_ck: auxclk2_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0318>; + }; + + auxclk2_src_ck: auxclk2_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk2_src_gate_ck>, <&auxclk2_src_mux_ck>; + }; + + auxclk2_ck: auxclk2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk2_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0318>; + }; + + auxclk3_src_gate_ck: auxclk3_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x031c>; + }; + + auxclk3_src_mux_ck: auxclk3_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x031c>; + }; + + auxclk3_src_ck: auxclk3_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk3_src_gate_ck>, <&auxclk3_src_mux_ck>; + }; + + auxclk3_ck: auxclk3_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk3_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x031c>; + }; + + auxclk4_src_gate_ck: auxclk4_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0320>; + }; + + auxclk4_src_mux_ck: auxclk4_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0320>; + }; + + auxclk4_src_ck: auxclk4_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk4_src_gate_ck>, <&auxclk4_src_mux_ck>; + }; + + auxclk4_ck: auxclk4_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk4_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0320>; + }; + + auxclkreq0_ck: auxclkreq0_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>; + ti,bit-shift = <2>; + reg = <0x0210>; + }; + + auxclkreq1_ck: auxclkreq1_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>; + ti,bit-shift = <2>; + reg = <0x0214>; + }; + + auxclkreq2_ck: auxclkreq2_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>; + ti,bit-shift = <2>; + reg = <0x0218>; + }; + + auxclkreq3_ck: auxclkreq3_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>; + ti,bit-shift = <2>; + reg = <0x021c>; + }; +}; diff --git a/arch/arm/boot/dts/qcom-msm8660-surf.dts b/arch/arm/boot/dts/qcom-msm8660-surf.dts index 1187185cf25bb2..68a72f5507b9a8 100644 --- a/arch/arm/boot/dts/qcom-msm8660-surf.dts +++ b/arch/arm/boot/dts/qcom-msm8660-surf.dts @@ -2,6 +2,8 @@ /include/ "skeleton.dtsi" +#include + / { model = "Qualcomm MSM8660 SURF"; compatible = "qcom,msm8660-surf", "qcom,msm8660"; @@ -37,11 +39,20 @@ #interrupt-cells = <2>; }; + gcc: clock-controller@900000 { + compatible = "qcom,gcc-msm8660"; + #clock-cells = <1>; + #reset-cells = <1>; + reg = <0x900000 0x4000>; + }; + serial@19c40000 { compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; reg = <0x19c40000 0x1000>, <0x19c00000 0x1000>; interrupts = <0 195 0x0>; + clocks = <&gcc GSBI12_UART_CLK>, <&gcc GSBI12_H_CLK>; + clock-names = "core", "iface"; }; qcom,ssbi@500000 { diff --git a/arch/arm/boot/dts/qcom-msm8960-cdp.dts b/arch/arm/boot/dts/qcom-msm8960-cdp.dts index 6ccbac77931e21..7c30de4fa3022e 100644 --- a/arch/arm/boot/dts/qcom-msm8960-cdp.dts +++ b/arch/arm/boot/dts/qcom-msm8960-cdp.dts @@ -2,6 +2,8 @@ /include/ "skeleton.dtsi" +#include + / { model = "Qualcomm MSM8960 CDP"; compatible = "qcom,msm8960-cdp", "qcom,msm8960"; @@ -37,11 +39,27 @@ reg = <0x800000 0x4000>; }; + gcc: clock-controller@900000 { + compatible = "qcom,gcc-msm8960"; + #clock-cells = <1>; + #reset-cells = <1>; + reg = <0x900000 0x4000>; + }; + + clock-controller@4000000 { + compatible = "qcom,mmcc-msm8960"; + reg = <0x4000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + serial@16440000 { compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; reg = <0x16440000 0x1000>, <0x16400000 0x1000>; interrupts = <0 154 0x0>; + clocks = <&gcc GSBI5_UART_CLK>, <&gcc GSBI5_H_CLK>; + clock-names = "core", "iface"; }; qcom,ssbi@500000 { diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi index 6ac94967d2d389..9e5dadb101ebe3 100644 --- a/arch/arm/boot/dts/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi @@ -2,6 +2,8 @@ #include "skeleton.dtsi" +#include + / { model = "Qualcomm MSM8974"; compatible = "qcom,msm8974"; @@ -93,5 +95,27 @@ compatible = "qcom,pshold"; reg = <0xfc4ab000 0x4>; }; + + gcc: clock-controller@fc400000 { + compatible = "qcom,gcc-msm8974"; + #clock-cells = <1>; + #reset-cells = <1>; + reg = <0xfc400000 0x4000>; + }; + + mmcc: clock-controller@fd8c0000 { + compatible = "qcom,mmcc-msm8974"; + #clock-cells = <1>; + #reset-cells = <1>; + reg = <0xfd8c0000 0x6000>; + }; + + serial@f991e000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0xf991e000 0x1000>; + interrupts = <0 108 0x0>; + clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + }; }; }; diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index f48487c2a970aa..71b1251f79c73d 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -197,7 +197,7 @@ reg = <0 0xe6508000 0 0x40>; interrupt-parent = <&gic>; interrupts = <0 287 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&mstp3_clks R8A7790_CLK_I2C0>; + clocks = <&mstp9_clks R8A7790_CLK_I2C0>; status = "disabled"; }; @@ -208,7 +208,7 @@ reg = <0 0xe6518000 0 0x40>; interrupt-parent = <&gic>; interrupts = <0 288 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&mstp3_clks R8A7790_CLK_I2C1>; + clocks = <&mstp9_clks R8A7790_CLK_I2C1>; status = "disabled"; }; @@ -219,7 +219,7 @@ reg = <0 0xe6530000 0 0x40>; interrupt-parent = <&gic>; interrupts = <0 286 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&mstp3_clks R8A7790_CLK_I2C2>; + clocks = <&mstp9_clks R8A7790_CLK_I2C2>; status = "disabled"; }; @@ -230,7 +230,7 @@ reg = <0 0xe6540000 0 0x40>; interrupt-parent = <&gic>; interrupts = <0 290 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&mstp3_clks R8A7790_CLK_I2C3>; + clocks = <&mstp9_clks R8A7790_CLK_I2C3>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index 1105558d188b2f..3d5faf85f51be4 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi @@ -1092,6 +1092,11 @@ watchdog@fffffe40 { compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffe40 0x10>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH 7>; + atmel,watchdog-type = "hardware"; + atmel,reset-type = "all"; + atmel,dbg-halt; + atmel,idle-halt; status = "disabled"; }; @@ -1223,7 +1228,7 @@ compatible = "atmel,at91rm9200-ohci", "usb-ohci"; reg = <0x00600000 0x100000>; interrupts = <32 IRQ_TYPE_LEVEL_HIGH 2>; - clocks = <&usb>, <&uhphs_clk>, <&udphs_clk>, + clocks = <&usb>, <&uhphs_clk>, <&uhphs_clk>, <&uhpck>; clock-names = "usb_clk", "ohci_clk", "hclk", "uhpck"; status = "disabled"; diff --git a/arch/arm/boot/dts/ste-href.dtsi b/arch/arm/boot/dts/ste-href.dtsi index 0c1e8d871ed1a4..6cb9b68e2188a5 100644 --- a/arch/arm/boot/dts/ste-href.dtsi +++ b/arch/arm/boot/dts/ste-href.dtsi @@ -188,7 +188,6 @@ msp2: msp@80117000 { pinctrl-names = "default"; pinctrl-0 = <&msp2_default_mode>; - status = "okay"; }; msp3: msp@80125000 { diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi index 040bb0eba1526f..10666ca8aee1c4 100644 --- a/arch/arm/boot/dts/sun4i-a10.dtsi +++ b/arch/arm/boot/dts/sun4i-a10.dtsi @@ -315,7 +315,7 @@ ranges; emac: ethernet@01c0b000 { - compatible = "allwinner,sun4i-emac"; + compatible = "allwinner,sun4i-a10-emac"; reg = <0x01c0b000 0x1000>; interrupts = <55>; clocks = <&ahb_gates 17>; @@ -323,7 +323,7 @@ }; mdio@01c0b080 { - compatible = "allwinner,sun4i-mdio"; + compatible = "allwinner,sun4i-a10-mdio"; reg = <0x01c0b080 0x14>; status = "disabled"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi index ea16054857a497..64961595e8d63c 100644 --- a/arch/arm/boot/dts/sun5i-a10s.dtsi +++ b/arch/arm/boot/dts/sun5i-a10s.dtsi @@ -278,7 +278,7 @@ ranges; emac: ethernet@01c0b000 { - compatible = "allwinner,sun4i-emac"; + compatible = "allwinner,sun4i-a10-emac"; reg = <0x01c0b000 0x1000>; interrupts = <55>; clocks = <&ahb_gates 17>; @@ -286,7 +286,7 @@ }; mdio@01c0b080 { - compatible = "allwinner,sun4i-mdio"; + compatible = "allwinner,sun4i-a10-mdio"; reg = <0x01c0b080 0x14>; status = "disabled"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index 119f066f0d98aa..9ff09484847b9c 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -340,7 +340,7 @@ ranges; emac: ethernet@01c0b000 { - compatible = "allwinner,sun4i-emac"; + compatible = "allwinner,sun4i-a10-emac"; reg = <0x01c0b000 0x1000>; interrupts = <0 55 4>; clocks = <&ahb_gates 17>; @@ -348,7 +348,7 @@ }; mdio@01c0b080 { - compatible = "allwinner,sun4i-mdio"; + compatible = "allwinner,sun4i-a10-mdio"; reg = <0x01c0b080 0x14>; status = "disabled"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/testcases/tests.dtsi b/arch/arm/boot/dts/testcases/tests.dtsi deleted file mode 100644 index 3f123ecc9dd75d..00000000000000 --- a/arch/arm/boot/dts/testcases/tests.dtsi +++ /dev/null @@ -1,2 +0,0 @@ -/include/ "tests-phandle.dtsi" -/include/ "tests-interrupts.dtsi" diff --git a/arch/arm/boot/dts/versatile-pb.dts b/arch/arm/boot/dts/versatile-pb.dts index f43907c40c93a8..65f65771132357 100644 --- a/arch/arm/boot/dts/versatile-pb.dts +++ b/arch/arm/boot/dts/versatile-pb.dts @@ -1,4 +1,4 @@ -/include/ "versatile-ab.dts" +#include / { model = "ARM Versatile PB"; @@ -47,4 +47,4 @@ }; }; -/include/ "testcases/tests.dtsi" +#include diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi index 5d7681be058027..8b67b19392eca7 100644 --- a/arch/arm/boot/dts/zynq-7000.dtsi +++ b/arch/arm/boot/dts/zynq-7000.dtsi @@ -102,6 +102,26 @@ clock-names = "pclk", "hclk", "tx_clk"; }; + sdhci0: ps7-sdhci@e0100000 { + compatible = "arasan,sdhci-8.9a"; + status = "disabled"; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&clkc 21>, <&clkc 32>; + interrupt-parent = <&intc>; + interrupts = <0 24 4>; + reg = <0xe0100000 0x1000>; + } ; + + sdhci1: ps7-sdhci@e0101000 { + compatible = "arasan,sdhci-8.9a"; + status = "disabled"; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&clkc 22>, <&clkc 33>; + interrupt-parent = <&intc>; + interrupts = <0 47 4>; + reg = <0xe0101000 0x1000>; + } ; + slcr: slcr@f8000000 { compatible = "xlnx,zynq-slcr"; reg = <0xF8000000 0x1000>; diff --git a/arch/arm/boot/dts/zynq-zc702.dts b/arch/arm/boot/dts/zynq-zc702.dts index 34d680a46b7e60..c913f77a21ebfb 100644 --- a/arch/arm/boot/dts/zynq-zc702.dts +++ b/arch/arm/boot/dts/zynq-zc702.dts @@ -34,6 +34,10 @@ phy-mode = "rgmii"; }; +&sdhci0 { + status = "okay"; +}; + &uart1 { status = "okay"; }; diff --git a/arch/arm/boot/dts/zynq-zc706.dts b/arch/arm/boot/dts/zynq-zc706.dts index b2835d5fc09a7d..88f62c50382ec5 100644 --- a/arch/arm/boot/dts/zynq-zc706.dts +++ b/arch/arm/boot/dts/zynq-zc706.dts @@ -35,6 +35,10 @@ phy-mode = "rgmii"; }; +&sdhci0 { + status = "okay"; +}; + &uart1 { status = "okay"; }; diff --git a/arch/arm/boot/dts/zynq-zed.dts b/arch/arm/boot/dts/zynq-zed.dts index 2eda06889dfc24..82d7ef1a9a9c6c 100644 --- a/arch/arm/boot/dts/zynq-zed.dts +++ b/arch/arm/boot/dts/zynq-zed.dts @@ -35,6 +35,10 @@ phy-mode = "rgmii"; }; +&sdhci0 { + status = "okay"; +}; + &uart1 { status = "okay"; }; diff --git a/arch/arm/configs/bcm_defconfig b/arch/arm/configs/bcm_defconfig index 2c38fdf1951d37..2519d6de064012 100644 --- a/arch/arm/configs/bcm_defconfig +++ b/arch/arm/configs/bcm_defconfig @@ -126,3 +126,6 @@ CONFIG_CRC7=y CONFIG_XZ_DEC=y CONFIG_AVERAGE=y CONFIG_PINCTRL_CAPRI=y +CONFIG_WATCHDOG=y +CONFIG_BCM_KONA_WDT=y +CONFIG_BCM_KONA_WDT_DEBUG=y diff --git a/arch/arm/configs/keystone_defconfig b/arch/arm/configs/keystone_defconfig index a0182447d1334d..4582e160feab4e 100644 --- a/arch/arm/configs/keystone_defconfig +++ b/arch/arm/configs/keystone_defconfig @@ -142,6 +142,7 @@ CONFIG_USB_DWC3_DEBUG=y CONFIG_USB_DWC3_VERBOSE=y CONFIG_KEYSTONE_USB_PHY=y CONFIG_DMADEVICES=y +CONFIG_TI_EDMA=y CONFIG_COMMON_CLK_DEBUG=y CONFIG_MEMORY=y CONFIG_EXT4_FS=y diff --git a/arch/arm/configs/msm_defconfig b/arch/arm/configs/msm_defconfig index 0219c65cefd5ab..c5858b9eb51609 100644 --- a/arch/arm/configs/msm_defconfig +++ b/arch/arm/configs/msm_defconfig @@ -114,6 +114,10 @@ CONFIG_USB_GADGET_VBUS_DRAW=500 CONFIG_NEW_LEDS=y CONFIG_RTC_CLASS=y CONFIG_STAGING=y +CONFIG_COMMON_CLK_QCOM=y +CONFIG_MSM_GCC_8660=y +CONFIG_MSM_MMCC_8960=y +CONFIG_MSM_MMCC_8974=y CONFIG_MSM_IOMMU=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 687e4e811b2aa0..ee6982976d661d 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -1,7 +1,12 @@ +CONFIG_SYSVIPC=y CONFIG_IRQ_DOMAIN_DEBUG=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_BLK_DEV_INITRD=y +CONFIG_EMBEDDED=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_MVEBU=y CONFIG_MACH_ARMADA_370=y CONFIG_MACH_ARMADA_XP=y @@ -24,6 +29,7 @@ CONFIG_ARCH_OMAP3=y CONFIG_ARCH_OMAP4=y CONFIG_SOC_OMAP5=y CONFIG_SOC_AM33XX=y +CONFIG_SOC_DRA7XX=y CONFIG_SOC_AM43XX=y CONFIG_ARCH_ROCKCHIP=y CONFIG_ARCH_SOCFPGA=y @@ -38,7 +44,7 @@ CONFIG_ARCH_TEGRA=y CONFIG_ARCH_TEGRA_2x_SOC=y CONFIG_ARCH_TEGRA_3x_SOC=y CONFIG_ARCH_TEGRA_114_SOC=y -CONFIG_TEGRA_PCI=y +CONFIG_ARCH_TEGRA_124_SOC=y CONFIG_TEGRA_EMC_SCALING_ENABLE=y CONFIG_ARCH_U8500=y CONFIG_MACH_HREFV60=y @@ -49,19 +55,55 @@ CONFIG_ARCH_VEXPRESS_CA9X4=y CONFIG_ARCH_VIRT=y CONFIG_ARCH_WM8850=y CONFIG_ARCH_ZYNQ=y +CONFIG_TRUSTED_FOUNDATIONS=y +CONFIG_PCI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MVEBU=y +CONFIG_PCI_TEGRA=y CONFIG_SMP=y CONFIG_HIGHPTE=y +CONFIG_CMA=y CONFIG_ARM_APPENDED_DTB=y CONFIG_ARM_ATAG_DTB_COMPAT=y +CONFIG_KEXEC=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +CONFIG_CPU_IDLE=y CONFIG_NET=y +CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_INET=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_MIP6=m +CONFIG_IPV6_TUNNEL=m +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_CFG80211=m +CONFIG_MAC80211=m +CONFIG_RFKILL=y +CONFIG_RFKILL_INPUT=y +CONFIG_RFKILL_GPIO=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DMA_CMA=y CONFIG_OMAP_OCP2SCP=y +CONFIG_MTD=y +CONFIG_MTD_M25P80=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_ICS932S401=y +CONFIG_APDS9802ALS=y +CONFIG_ISL29003=y CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_SCSI_MULTI_LUN=y CONFIG_ATA=y CONFIG_SATA_AHCI_PLATFORM=y CONFIG_SATA_HIGHBANK=y @@ -69,13 +111,30 @@ CONFIG_SATA_MV=y CONFIG_NETDEVICES=y CONFIG_SUN4I_EMAC=y CONFIG_NET_CALXEDA_XGMAC=y +CONFIG_MVNETA=y CONFIG_KS8851=y +CONFIG_R8169=y CONFIG_SMSC911X=y CONFIG_STMMAC_ETH=y -CONFIG_ICPLUS_PHY=y -CONFIG_MDIO_SUN4I=y CONFIG_TI_CPSW=y +CONFIG_AT803X_PHY=y +CONFIG_MARVELL_PHY=y +CONFIG_ICPLUS_PHY=y +CONFIG_USB_PEGASUS=y +CONFIG_USB_USBNET=y +CONFIG_USB_NET_SMSC75XX=y +CONFIG_USB_NET_SMSC95XX=y +CONFIG_BRCMFMAC=m +CONFIG_RT2X00=m +CONFIG_RT2800USB=m +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYBOARD_TEGRA=y CONFIG_KEYBOARD_SPEAR=y +CONFIG_KEYBOARD_CROS_EC=y +CONFIG_MOUSE_PS2_ELANTECH=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_MPU3050=y CONFIG_SERIO_AMBAKMI=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y @@ -98,30 +157,81 @@ CONFIG_SERIAL_FSL_LPUART=y CONFIG_SERIAL_FSL_LPUART_CONSOLE=y CONFIG_SERIAL_ST_ASC=y CONFIG_SERIAL_ST_ASC_CONSOLE=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y +CONFIG_I2C_MUX_PINCTRL=y CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_I2C_MV64XXX=y CONFIG_I2C_SIRF=y CONFIG_I2C_TEGRA=y CONFIG_SPI=y CONFIG_SPI_OMAP24XX=y +CONFIG_SPI_ORION=y CONFIG_SPI_PL022=y CONFIG_SPI_SIRF=y CONFIG_SPI_TEGRA114=y +CONFIG_SPI_TEGRA20_SFLASH=y CONFIG_SPI_TEGRA20_SLINK=y -CONFIG_PINCTRL_SINGLE=y +CONFIG_PINCTRL_AS3722=y +CONFIG_PINCTRL_PALMAS=y +CONFIG_GPIO_SYSFS=y CONFIG_GPIO_GENERIC_PLATFORM=y +CONFIG_GPIO_PCA953X_IRQ=y CONFIG_GPIO_TWL4030=y -CONFIG_REGULATOR_GPIO=y +CONFIG_GPIO_PALMAS=y +CONFIG_GPIO_TPS6586X=y +CONFIG_GPIO_TPS65910=y +CONFIG_BATTERY_SBS=y +CONFIG_CHARGER_TPS65090=y +CONFIG_POWER_RESET_AS3722=y +CONFIG_POWER_RESET_GPIO=y +CONFIG_SENSORS_LM90=y +CONFIG_THERMAL=y +CONFIG_ARMADA_THERMAL=y +CONFIG_MFD_AS3722=y +CONFIG_MFD_CROS_EC=y +CONFIG_MFD_CROS_EC_SPI=y +CONFIG_MFD_MAX8907=y +CONFIG_MFD_PALMAS=y +CONFIG_MFD_TPS65090=y +CONFIG_MFD_TPS6586X=y +CONFIG_MFD_TPS65910=y +CONFIG_REGULATOR_VIRTUAL_CONSUMER=y CONFIG_REGULATOR_AB8500=y +CONFIG_REGULATOR_AS3722=y +CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_MAX8907=y +CONFIG_REGULATOR_PALMAS=y CONFIG_REGULATOR_TPS51632=y CONFIG_REGULATOR_TPS62360=y +CONFIG_REGULATOR_TPS65090=y +CONFIG_REGULATOR_TPS6586X=y +CONFIG_REGULATOR_TPS65910=y CONFIG_REGULATOR_TWL4030=y CONFIG_REGULATOR_VEXPRESS=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_USB_SUPPORT=y CONFIG_DRM=y -CONFIG_TEGRA_HOST1X=y CONFIG_DRM_TEGRA=y +CONFIG_DRM_PANEL_SIMPLE=y CONFIG_FB_ARMCLCD=y CONFIG_FB_WM8505=y CONFIG_FB_SIMPLE=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_PWM=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_TEGRA=y +CONFIG_SND_SOC_TEGRA_RT5640=y +CONFIG_SND_SOC_TEGRA_WM8753=y +CONFIG_SND_SOC_TEGRA_WM8903=y +CONFIG_SND_SOC_TEGRA_TRIMSLICE=y +CONFIG_SND_SOC_TEGRA_ALC5632=y +CONFIG_SND_SOC_TEGRA_MAX98090=y CONFIG_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y @@ -132,8 +242,6 @@ CONFIG_USB_STORAGE=y CONFIG_USB_CHIPIDEA=y CONFIG_USB_CHIPIDEA_HOST=y CONFIG_AB8500_USB=y -CONFIG_NOP_USB_XCEIV=y -CONFIG_OMAP_USB2=y CONFIG_OMAP_USB3=y CONFIG_SAMSUNG_USB2PHY=y CONFIG_SAMSUNG_USB3PHY=y @@ -144,24 +252,32 @@ CONFIG_MMC=y CONFIG_MMC_BLOCK_MINORS=16 CONFIG_MMC_ARMMMCI=y CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_ESDHC_IMX=y CONFIG_MMC_SDHCI_TEGRA=y CONFIG_MMC_SDHCI_SPEAR=y CONFIG_MMC_SDHCI_BCM_KONA=y CONFIG_MMC_OMAP=y CONFIG_MMC_OMAP_HS=y +CONFIG_MMC_MVSDIO=y CONFIG_EDAC=y CONFIG_EDAC_MM_EDAC=y CONFIG_EDAC_HIGHBANK_MC=y CONFIG_EDAC_HIGHBANK_L2=y CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_AS3722=y +CONFIG_RTC_DRV_MAX8907=y +CONFIG_RTC_DRV_PALMAS=y CONFIG_RTC_DRV_TWL4030=y +CONFIG_RTC_DRV_TPS6586X=y +CONFIG_RTC_DRV_TPS65910=y +CONFIG_RTC_DRV_EM3027=y CONFIG_RTC_DRV_PL031=y CONFIG_RTC_DRV_VT8500=y +CONFIG_RTC_DRV_MV=y CONFIG_RTC_DRV_TEGRA=y CONFIG_DMADEVICES=y CONFIG_DW_DMAC=y +CONFIG_MV_XOR=y CONFIG_TEGRA20_APB_DMA=y CONFIG_STE_DMA40=y CONFIG_SIRF_DMA=y @@ -171,15 +287,34 @@ CONFIG_IMX_SDMA=y CONFIG_IMX_DMA=y CONFIG_MXS_DMA=y CONFIG_DMA_OMAP=y +CONFIG_STAGING=y +CONFIG_SENSORS_ISL29018=y +CONFIG_SENSORS_ISL29028=y +CONFIG_MFD_NVEC=y +CONFIG_KEYBOARD_NVEC=y +CONFIG_SERIO_NVEC_PS2=y +CONFIG_NVEC_POWER=y +CONFIG_TEGRA_IOMMU_GART=y +CONFIG_TEGRA_IOMMU_SMMU=y +CONFIG_MEMORY=y +CONFIG_IIO=y +CONFIG_AK8975=y CONFIG_PWM=y +CONFIG_PWM_TEGRA=y CONFIG_PWM_VT8500=y +CONFIG_OMAP_USB2=y CONFIG_EXT4_FS=y +CONFIG_VFAT_FS=y CONFIG_TMPFS=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y CONFIG_NFS_FS=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_PRINTK_TIME=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y CONFIG_LOCKUP_DETECTOR=y +CONFIG_CRYPTO_DEV_TEGRA_AES=y diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig index 5fdc9a09d33919..00fe9e9710fd77 100644 --- a/arch/arm/configs/tegra_defconfig +++ b/arch/arm/configs/tegra_defconfig @@ -29,11 +29,11 @@ CONFIG_ARCH_TEGRA_3x_SOC=y CONFIG_ARCH_TEGRA_114_SOC=y CONFIG_ARCH_TEGRA_124_SOC=y CONFIG_TEGRA_EMC_SCALING_ENABLE=y +CONFIG_TRUSTED_FOUNDATIONS=y CONFIG_PCI=y CONFIG_PCI_MSI=y CONFIG_PCI_TEGRA=y CONFIG_PCIEPORTBUS=y -CONFIG_TRUSTED_FOUNDATIONS=y CONFIG_SMP=y CONFIG_PREEMPT=y CONFIG_AEABI=y @@ -125,7 +125,6 @@ CONFIG_SERIAL_TEGRA=y CONFIG_SERIAL_OF_PLATFORM=y # CONFIG_HW_RANDOM is not set # CONFIG_I2C_COMPAT is not set -CONFIG_I2C_MUX=y CONFIG_I2C_MUX_PINCTRL=y CONFIG_I2C_TEGRA=y CONFIG_SPI=y @@ -169,9 +168,8 @@ CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_USB_SUPPORT=y CONFIG_USB_VIDEO_CLASS=m CONFIG_DRM=y -CONFIG_DRM_PANEL=y -CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_TEGRA=y +CONFIG_DRM_PANEL_SIMPLE=y CONFIG_BACKLIGHT_LCD_SUPPORT=y # CONFIG_LCD_CLASS_DEVICE is not set CONFIG_BACKLIGHT_CLASS_DEVICE=y @@ -206,10 +204,7 @@ CONFIG_MMC_BLOCK_MINORS=16 CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_TEGRA=y -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y -CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_LEDS_TRIGGER_ONESHOT=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y @@ -235,7 +230,6 @@ CONFIG_KEYBOARD_NVEC=y CONFIG_SERIO_NVEC_PS2=y CONFIG_NVEC_POWER=y CONFIG_NVEC_PAZ00=y -CONFIG_COMMON_CLK_DEBUG=y CONFIG_TEGRA_IOMMU_GART=y CONFIG_TEGRA_IOMMU_SMMU=y CONFIG_MEMORY=y @@ -265,6 +259,7 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_FS=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_SLAB=y CONFIG_DEBUG_VM=y diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index e9a49fe0284e41..8b8b61685a3436 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -212,6 +212,7 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *, static inline void __flush_icache_all(void) { __flush_icache_preferred(); + dsb(); } /* diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index fbeb39c869e9fd..8aa4cca74501f3 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -37,6 +37,12 @@ #define isa_page_to_bus page_to_phys #define isa_bus_to_virt phys_to_virt +/* + * Atomic MMIO-wide IO modify + */ +extern void atomic_io_modify(void __iomem *reg, u32 mask, u32 set); +extern void atomic_io_modify_relaxed(void __iomem *reg, u32 mask, u32 set); + /* * Generic IO read/write. These perform native-endian accesses. Note * that some architectures will want to re-define __raw_{read,write}w. diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h index 03243f7eeddfc5..85c60adc8b60bd 100644 --- a/arch/arm/include/asm/pgtable-3level.h +++ b/arch/arm/include/asm/pgtable-3level.h @@ -120,13 +120,16 @@ /* * 2nd stage PTE definitions for LPAE. */ -#define L_PTE_S2_MT_UNCACHED (_AT(pteval_t, 0x5) << 2) /* MemAttr[3:0] */ -#define L_PTE_S2_MT_WRITETHROUGH (_AT(pteval_t, 0xa) << 2) /* MemAttr[3:0] */ -#define L_PTE_S2_MT_WRITEBACK (_AT(pteval_t, 0xf) << 2) /* MemAttr[3:0] */ -#define L_PTE_S2_RDONLY (_AT(pteval_t, 1) << 6) /* HAP[1] */ -#define L_PTE_S2_RDWR (_AT(pteval_t, 3) << 6) /* HAP[2:1] */ +#define L_PTE_S2_MT_UNCACHED (_AT(pteval_t, 0x0) << 2) /* strongly ordered */ +#define L_PTE_S2_MT_WRITETHROUGH (_AT(pteval_t, 0xa) << 2) /* normal inner write-through */ +#define L_PTE_S2_MT_WRITEBACK (_AT(pteval_t, 0xf) << 2) /* normal inner write-back */ +#define L_PTE_S2_MT_DEV_SHARED (_AT(pteval_t, 0x1) << 2) /* device */ +#define L_PTE_S2_MT_MASK (_AT(pteval_t, 0xf) << 2) -#define L_PMD_S2_RDWR (_AT(pmdval_t, 3) << 6) /* HAP[2:1] */ +#define L_PTE_S2_RDONLY (_AT(pteval_t, 1) << 6) /* HAP[1] */ +#define L_PTE_S2_RDWR (_AT(pteval_t, 3) << 6) /* HAP[2:1] */ + +#define L_PMD_S2_RDWR (_AT(pmdval_t, 3) << 6) /* HAP[2:1] */ /* * Hyp-mode PL2 PTE definitions for LPAE. diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h index ef3c6072aa4534..ac4bfae26702b0 100644 --- a/arch/arm/include/asm/spinlock.h +++ b/arch/arm/include/asm/spinlock.h @@ -37,18 +37,9 @@ static inline void dsb_sev(void) { -#if __LINUX_ARM_ARCH__ >= 7 - __asm__ __volatile__ ( - "dsb ishst\n" - SEV - ); -#else - __asm__ __volatile__ ( - "mcr p15, 0, %0, c7, c10, 4\n" - SEV - : : "r" (0) - ); -#endif + + dsb(ishst); + __asm__(SEV); } /* diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index b3fb8c9e1ff2d7..1879e8dd2acc18 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -451,9 +451,11 @@ __und_usr_thumb: .arch armv6t2 #endif 2: ldrht r5, [r4] +ARM_BE8(rev16 r5, r5) @ little endian instruction cmp r5, #0xe800 @ 32bit instruction if xx != 0 blo __und_usr_fault_16 @ 16bit undefined instruction 3: ldrht r0, [r2] +ARM_BE8(rev16 r0, r0) @ little endian instruction add r2, r2, #2 @ r2 is PC + 2, make it PC + 4 str r2, [sp, #S_PC] @ it's a 2x16bit instr, update orr r0, r0, r5, lsl #16 diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 32f317e5828ada..914616e0bdcd0c 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -52,7 +52,8 @@ .equ swapper_pg_dir, KERNEL_RAM_VADDR - PG_DIR_SIZE .macro pgtbl, rd, phys - add \rd, \phys, #TEXT_OFFSET - PG_DIR_SIZE + add \rd, \phys, #TEXT_OFFSET + sub \rd, \rd, #PG_DIR_SIZE .endm /* diff --git a/arch/arm/kernel/io.c b/arch/arm/kernel/io.c index dcd5b4d8614374..9203cf883330a3 100644 --- a/arch/arm/kernel/io.c +++ b/arch/arm/kernel/io.c @@ -1,6 +1,41 @@ #include #include #include +#include + +static DEFINE_RAW_SPINLOCK(__io_lock); + +/* + * Generic atomic MMIO modify. + * + * Allows thread-safe access to registers shared by unrelated subsystems. + * The access is protected by a single MMIO-wide lock. + */ +void atomic_io_modify_relaxed(void __iomem *reg, u32 mask, u32 set) +{ + unsigned long flags; + u32 value; + + raw_spin_lock_irqsave(&__io_lock, flags); + value = readl_relaxed(reg) & ~mask; + value |= (set & mask); + writel_relaxed(value, reg); + raw_spin_unlock_irqrestore(&__io_lock, flags); +} +EXPORT_SYMBOL(atomic_io_modify_relaxed); + +void atomic_io_modify(void __iomem *reg, u32 mask, u32 set) +{ + unsigned long flags; + u32 value; + + raw_spin_lock_irqsave(&__io_lock, flags); + value = readl_relaxed(reg) & ~mask; + value |= (set & mask); + writel(value, reg); + raw_spin_unlock_irqrestore(&__io_lock, flags); +} +EXPORT_SYMBOL(atomic_io_modify); /* * Copy data from IO memory space to "real" memory space. diff --git a/arch/arm/mach-hisi/Kconfig b/arch/arm/mach-hisi/Kconfig index 018ad67f1b3875..1abae5f6a41810 100644 --- a/arch/arm/mach-hisi/Kconfig +++ b/arch/arm/mach-hisi/Kconfig @@ -8,10 +8,9 @@ config ARCH_HI3xxx select CLKSRC_OF select GENERIC_CLOCKEVENTS select HAVE_ARM_SCU - select HAVE_ARM_TWD + select HAVE_ARM_TWD if SMP select HAVE_SMP select PINCTRL select PINCTRL_SINGLE - select SMP help Support for Hisilicon Hi36xx/Hi37xx processor family diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index af2e582d2b7427..4d677f4425399c 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -482,6 +482,9 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) if (IS_ENABLED(CONFIG_PCI_IMX6)) clk_set_parent(clk[lvds1_sel], clk[sata_ref]); + /* Set initial power mode */ + imx6q_set_lpm(WAIT_CLOCKED); + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt"); base = of_iomap(np, 0); WARN_ON(!base); diff --git a/arch/arm/mach-imx/clk-imx6sl.c b/arch/arm/mach-imx/clk-imx6sl.c index 3781a1853998c3..4c86f303520573 100644 --- a/arch/arm/mach-imx/clk-imx6sl.c +++ b/arch/arm/mach-imx/clk-imx6sl.c @@ -266,6 +266,9 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) /* Audio-related clocks configuration */ clk_set_parent(clks[IMX6SL_CLK_SPDIF0_SEL], clks[IMX6SL_CLK_PLL3_PFD3]); + /* Set initial power mode */ + imx6q_set_lpm(WAIT_CLOCKED); + np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-gpt"); base = of_iomap(np, 0); WARN_ON(!base); diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index d2ea6e60ea7b20..76e5db4fce35a9 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -133,6 +133,39 @@ static int ar8031_phy_fixup(struct phy_device *dev) #define PHY_ID_AR8031 0x004dd074 +static int ar8035_phy_fixup(struct phy_device *dev) +{ + u16 val; + + /* Ar803x phy SmartEEE feature cause link status generates glitch, + * which cause ethernet link down/up issue, so disable SmartEEE + */ + phy_write(dev, 0xd, 0x3); + phy_write(dev, 0xe, 0x805d); + phy_write(dev, 0xd, 0x4003); + + val = phy_read(dev, 0xe); + phy_write(dev, 0xe, val & ~(1 << 8)); + + /* + * Enable 125MHz clock from CLK_25M on the AR8031. This + * is fed in to the IMX6 on the ENET_REF_CLK (V22) pad. + * Also, introduce a tx clock delay. + * + * This is the same as is the AR8031 fixup. + */ + ar8031_phy_fixup(dev); + + /*check phy power*/ + val = phy_read(dev, 0x0); + if (val & BMCR_PDOWN) + phy_write(dev, 0x0, val & ~BMCR_PDOWN); + + return 0; +} + +#define PHY_ID_AR8035 0x004dd072 + static void __init imx6q_enet_phy_init(void) { if (IS_BUILTIN(CONFIG_PHYLIB)) { @@ -142,6 +175,8 @@ static void __init imx6q_enet_phy_init(void) ksz9031rn_phy_fixup); phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff, ar8031_phy_fixup); + phy_register_fixup_for_uid(PHY_ID_AR8035, 0xffffffef, + ar8035_phy_fixup); } } diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c index 6f424eced18169..b3738e616f197b 100644 --- a/arch/arm/mach-imx/mach-mx31moboard.c +++ b/arch/arm/mach-imx/mach-mx31moboard.c @@ -236,32 +236,26 @@ static struct mc13xxx_led_platform_data moboard_led[] = { { .id = MC13783_LED_R1, .name = "coreboard-led-4:red", - .max_current = 2, }, { .id = MC13783_LED_G1, .name = "coreboard-led-4:green", - .max_current = 2, }, { .id = MC13783_LED_B1, .name = "coreboard-led-4:blue", - .max_current = 2, }, { .id = MC13783_LED_R2, .name = "coreboard-led-5:red", - .max_current = 3, }, { .id = MC13783_LED_G2, .name = "coreboard-led-5:green", - .max_current = 3, }, { .id = MC13783_LED_B2, .name = "coreboard-led-5:blue", - .max_current = 3, }, }; @@ -271,8 +265,14 @@ static struct mc13xxx_leds_platform_data moboard_leds = { .led_control[0] = MC13783_LED_C0_ENABLE | MC13783_LED_C0_ABMODE(0), .led_control[1] = MC13783_LED_C1_SLEWLIM, .led_control[2] = MC13783_LED_C2_SLEWLIM, - .led_control[3] = MC13783_LED_C3_PERIOD(0), - .led_control[4] = MC13783_LED_C3_PERIOD(0), + .led_control[3] = MC13783_LED_C3_PERIOD(0) | + MC13783_LED_C3_CURRENT_R1(2) | + MC13783_LED_C3_CURRENT_G1(2) | + MC13783_LED_C3_CURRENT_B1(2), + .led_control[4] = MC13783_LED_C4_PERIOD(0) | + MC13783_LED_C4_CURRENT_R2(3) | + MC13783_LED_C4_CURRENT_G2(3) | + MC13783_LED_C4_CURRENT_B2(3), }; static struct mc13xxx_buttons_platform_data moboard_buttons = { diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c index 9d47adc078aa76..7a9b98589db726 100644 --- a/arch/arm/mach-imx/pm-imx6q.c +++ b/arch/arm/mach-imx/pm-imx6q.c @@ -236,8 +236,6 @@ void __init imx6q_pm_init(void) regmap_update_bits(gpr, IOMUXC_GPR1, IMX6Q_GPR1_GINT, IMX6Q_GPR1_GINT); - /* Set initial power mode */ - imx6q_set_lpm(WAIT_CLOCKED); suspend_set_ops(&imx6q_pm_ops); } diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 5e84149d1790dc..a3ef961e4a9333 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -64,6 +64,7 @@ static void __iomem *intcp_con_base; /* * Logical Physical + * f1000000 10000000 Core module registers * f1300000 13000000 Counter/Timer * f1400000 14000000 Interrupt controller * f1600000 16000000 UART 0 @@ -75,6 +76,11 @@ static void __iomem *intcp_con_base; static struct map_desc intcp_io_desc[] __initdata __maybe_unused = { { + .virtual = IO_ADDRESS(INTEGRATOR_HDR_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_HDR_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE), .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE), .length = SZ_4K, diff --git a/arch/arm/mach-iop32x/em7210.c b/arch/arm/mach-iop32x/em7210.c index 177cd073a83bf4..77e1ff057303f0 100644 --- a/arch/arm/mach-iop32x/em7210.c +++ b/arch/arm/mach-iop32x/em7210.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -176,11 +177,35 @@ static struct platform_device em7210_serial_device = { .resource = &em7210_uart_resource, }; +#define EM7210_HARDWARE_POWER 0 + void em7210_power_off(void) { - *IOP3XX_GPOE &= 0xfe; - *IOP3XX_GPOD |= 0x01; + int ret; + + ret = gpio_direction_output(EM7210_HARDWARE_POWER, 1); + if (ret) + pr_crit("could not drive power off GPIO high\n"); +} + +static int __init em7210_request_gpios(void) +{ + int ret; + + if (!machine_is_em7210()) + return 0; + + ret = gpio_request(EM7210_HARDWARE_POWER, "power"); + if (ret) { + pr_err("could not request power off GPIO\n"); + return 0; + } + + pm_power_off = em7210_power_off; + + return 0; } +device_initcall(em7210_request_gpios); static void __init em7210_init_machine(void) { @@ -194,9 +219,6 @@ static void __init em7210_init_machine(void) i2c_register_board_info(0, em7210_i2c_devices, ARRAY_SIZE(em7210_i2c_devices)); - - - pm_power_off = em7210_power_off; } MACHINE_START(EM7210, "Lanner EM7210") diff --git a/arch/arm/mach-keystone/Kconfig b/arch/arm/mach-keystone/Kconfig index dabc5eee52e71b..90a708fef54136 100644 --- a/arch/arm/mach-keystone/Kconfig +++ b/arch/arm/mach-keystone/Kconfig @@ -10,7 +10,6 @@ config ARCH_KEYSTONE select ARCH_WANT_OPTIONAL_GPIOLIB select ARM_ERRATA_798181 if SMP select COMMON_CLK_KEYSTONE - select TI_EDMA select ARCH_SUPPORTS_BIG_ENDIAN select ZONE_DMA if ARM_LPAE help diff --git a/arch/arm/mach-kirkwood/pm.c b/arch/arm/mach-kirkwood/pm.c index 8783a7184e733f..c6ab8d9303a5b3 100644 --- a/arch/arm/mach-kirkwood/pm.c +++ b/arch/arm/mach-kirkwood/pm.c @@ -18,6 +18,7 @@ #include #include #include +#include "common.h" static void __iomem *ddr_operation_base; @@ -65,9 +66,8 @@ static const struct platform_suspend_ops kirkwood_suspend_ops = { .valid = kirkwood_pm_valid_standby, }; -int __init kirkwood_pm_init(void) +void __init kirkwood_pm_init(void) { ddr_operation_base = ioremap(DDR_OPERATION_BASE, 4); suspend_set_ops(&kirkwood_suspend_ops); - return 0; } diff --git a/arch/arm/mach-moxart/Kconfig b/arch/arm/mach-moxart/Kconfig index ba470d64493bc1..3795ae28a61346 100644 --- a/arch/arm/mach-moxart/Kconfig +++ b/arch/arm/mach-moxart/Kconfig @@ -2,7 +2,6 @@ config ARCH_MOXART bool "MOXA ART SoC" if ARCH_MULTI_V4T select CPU_FA526 select ARM_DMA_MEM_BUFFERABLE - select DMA_OF select USE_OF select CLKSRC_OF select CLKSRC_MMIO diff --git a/arch/arm/mach-mvebu/mvebu-soc-id.c b/arch/arm/mach-mvebu/mvebu-soc-id.c index fe4fc1cbdfaf4f..f3b325f6cbd4e8 100644 --- a/arch/arm/mach-mvebu/mvebu-soc-id.c +++ b/arch/arm/mach-mvebu/mvebu-soc-id.c @@ -88,7 +88,7 @@ static int __init mvebu_soc_id_init(void) } pci_base = of_iomap(child, 0); - if (IS_ERR(pci_base)) { + if (pci_base == NULL) { pr_err("cannot map registers\n"); ret = -ENOMEM; goto res_ioremap; diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 4191ae08f4c81a..e2ce4f8366a785 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -54,7 +54,7 @@ config SOC_OMAP5 select ARM_GIC select CPU_V7 select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if LOCAL_TIMERS + select HAVE_ARM_TWD if SMP select HAVE_SMP select HAVE_ARM_ARCH_TIMER select ARM_ERRATA_798181 if SMP @@ -76,6 +76,16 @@ config SOC_AM43XX select ARM_GIC select MACH_OMAP_GENERIC +config SOC_DRA7XX + bool "TI DRA7XX" + depends on ARCH_MULTI_V7 + select ARCH_OMAP2PLUS + select ARM_CPU_SUSPEND if PM + select ARM_GIC + select CPU_V7 + select HAVE_SMP + select HAVE_ARM_ARCH_TIMER + config ARCH_OMAP2PLUS bool select ARCH_HAS_BANDGAP @@ -128,14 +138,6 @@ config SOC_HAS_REALTIME_COUNTER depends on SOC_OMAP5 || SOC_DRA7XX default y -config SOC_DRA7XX - bool "TI DRA7XX" - select ARM_ARCH_TIMER - select CPU_V7 - select ARM_GIC - select HAVE_SMP - select COMMON_CLK - comment "OMAP Core Type" depends on ARCH_OMAP2 diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index f78b177e8f4fd1..e6eec6f72fd3ed 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -130,6 +130,7 @@ obj-$(CONFIG_SOC_AM33XX) += $(voltagedomain-common) obj-$(CONFIG_SOC_AM43XX) += $(voltagedomain-common) obj-$(CONFIG_SOC_OMAP5) += $(voltagedomain-common) obj-$(CONFIG_SOC_OMAP5) += voltagedomains54xx_data.o +obj-$(CONFIG_SOC_DRA7XX) += $(voltagedomain-common) # OMAP powerdomain framework powerdomain-common += powerdomain.o powerdomain-common.o @@ -184,12 +185,14 @@ obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o clkt34xx_dpll3m2.o obj-$(CONFIG_ARCH_OMAP3) += clock3517.o clock36xx.o obj-$(CONFIG_ARCH_OMAP3) += dpll3xxx.o cclock3xxx_data.o obj-$(CONFIG_ARCH_OMAP3) += clkt_iclk.o -obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) cclock44xx_data.o +obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) obj-$(CONFIG_ARCH_OMAP4) += dpll3xxx.o dpll44xx.o obj-$(CONFIG_SOC_AM33XX) += $(clock-common) dpll3xxx.o -obj-$(CONFIG_SOC_AM33XX) += cclock33xx_data.o obj-$(CONFIG_SOC_OMAP5) += $(clock-common) obj-$(CONFIG_SOC_OMAP5) += dpll3xxx.o dpll44xx.o +obj-$(CONFIG_SOC_DRA7XX) += $(clock-common) +obj-$(CONFIG_SOC_DRA7XX) += dpll3xxx.o dpll44xx.o +obj-$(CONFIG_SOC_AM43XX) += $(clock-common) dpll3xxx.o # OMAP2 clock rate set data (old "OPP" data) obj-$(CONFIG_SOC_OMAP2420) += opp2420_data.o diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index f093af17f5e6a9..8760bbe3baab92 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -760,7 +760,14 @@ static struct regulator_init_data rx51_vintdig = { }, }; +static const char * const si4713_supply_names[] = { + "vio", + "vdd", +}; + static struct si4713_platform_data rx51_si4713_i2c_data __initdata_or_module = { + .supplies = ARRAY_SIZE(si4713_supply_names), + .supply_names = si4713_supply_names, .gpio_reset = RX51_FMTX_RESET_GPIO, }; diff --git a/arch/arm/mach-omap2/cclock33xx_data.c b/arch/arm/mach-omap2/cclock33xx_data.c deleted file mode 100644 index 865d30ee812f19..00000000000000 --- a/arch/arm/mach-omap2/cclock33xx_data.c +++ /dev/null @@ -1,1064 +0,0 @@ -/* - * AM33XX Clock data - * - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ - * Vaibhav Hiremath - * - * 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 "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include - -#include "am33xx.h" -#include "soc.h" -#include "iomap.h" -#include "clock.h" -#include "control.h" -#include "cm.h" -#include "cm33xx.h" -#include "cm-regbits-33xx.h" -#include "prm.h" - -/* Modulemode control */ -#define AM33XX_MODULEMODE_HWCTRL_SHIFT 0 -#define AM33XX_MODULEMODE_SWCTRL_SHIFT 1 - -/*LIST_HEAD(clocks);*/ - -/* Root clocks */ - -/* RTC 32k */ -DEFINE_CLK_FIXED_RATE(clk_32768_ck, CLK_IS_ROOT, 32768, 0x0); - -/* On-Chip 32KHz RC OSC */ -DEFINE_CLK_FIXED_RATE(clk_rc32k_ck, CLK_IS_ROOT, 32000, 0x0); - -/* Crystal input clks */ -DEFINE_CLK_FIXED_RATE(virt_19200000_ck, CLK_IS_ROOT, 19200000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_24000000_ck, CLK_IS_ROOT, 24000000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_25000000_ck, CLK_IS_ROOT, 25000000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_26000000_ck, CLK_IS_ROOT, 26000000, 0x0); - -/* Oscillator clock */ -/* 19.2, 24, 25 or 26 MHz */ -static const char *sys_clkin_ck_parents[] = { - "virt_19200000_ck", "virt_24000000_ck", "virt_25000000_ck", - "virt_26000000_ck", -}; - -/* - * sys_clk in: input to the dpll and also used as funtional clock for, - * adc_tsc, smartreflex0-1, timer1-7, mcasp0-1, dcan0-1, cefuse - * - */ -DEFINE_CLK_MUX(sys_clkin_ck, sys_clkin_ck_parents, NULL, 0x0, - AM33XX_CTRL_REGADDR(AM33XX_CONTROL_STATUS), - AM33XX_CONTROL_STATUS_SYSBOOT1_SHIFT, - AM33XX_CONTROL_STATUS_SYSBOOT1_WIDTH, - 0, NULL); - -/* External clock - 12 MHz */ -DEFINE_CLK_FIXED_RATE(tclkin_ck, CLK_IS_ROOT, 12000000, 0x0); - -/* Module clocks and DPLL outputs */ - -/* DPLL_CORE */ -static struct dpll_data dpll_core_dd = { - .mult_div1_reg = AM33XX_CM_CLKSEL_DPLL_CORE, - .clk_bypass = &sys_clkin_ck, - .clk_ref = &sys_clkin_ck, - .control_reg = AM33XX_CM_CLKMODE_DPLL_CORE, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .idlest_reg = AM33XX_CM_IDLEST_DPLL_CORE, - .mult_mask = AM33XX_DPLL_MULT_MASK, - .div1_mask = AM33XX_DPLL_DIV_MASK, - .enable_mask = AM33XX_DPLL_EN_MASK, - .idlest_mask = AM33XX_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - -/* CLKDCOLDO output */ -static const char *dpll_core_ck_parents[] = { - "sys_clkin_ck", -}; - -static struct clk dpll_core_ck; - -static const struct clk_ops dpll_core_ck_ops = { - .recalc_rate = &omap3_dpll_recalc, - .get_parent = &omap2_init_dpll_parent, -}; - -static struct clk_hw_omap dpll_core_ck_hw = { - .hw = { - .clk = &dpll_core_ck, - }, - .dpll_data = &dpll_core_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_core_ck, dpll_core_ck_parents, dpll_core_ck_ops); - -static const char *dpll_core_x2_ck_parents[] = { - "dpll_core_ck", -}; - -static struct clk dpll_core_x2_ck; - -static const struct clk_ops dpll_x2_ck_ops = { - .recalc_rate = &omap3_clkoutx2_recalc, -}; - -static struct clk_hw_omap dpll_core_x2_ck_hw = { - .hw = { - .clk = &dpll_core_x2_ck, - }, - .flags = CLOCK_CLKOUTX2, -}; - -DEFINE_STRUCT_CLK(dpll_core_x2_ck, dpll_core_x2_ck_parents, dpll_x2_ck_ops); - -DEFINE_CLK_DIVIDER(dpll_core_m4_ck, "dpll_core_x2_ck", &dpll_core_x2_ck, - 0x0, AM33XX_CM_DIV_M4_DPLL_CORE, - AM33XX_HSDIVIDER_CLKOUT1_DIV_SHIFT, - AM33XX_HSDIVIDER_CLKOUT1_DIV_WIDTH, CLK_DIVIDER_ONE_BASED, - NULL); - -DEFINE_CLK_DIVIDER(dpll_core_m5_ck, "dpll_core_x2_ck", &dpll_core_x2_ck, - 0x0, AM33XX_CM_DIV_M5_DPLL_CORE, - AM33XX_HSDIVIDER_CLKOUT2_DIV_SHIFT, - AM33XX_HSDIVIDER_CLKOUT2_DIV_WIDTH, - CLK_DIVIDER_ONE_BASED, NULL); - -DEFINE_CLK_DIVIDER(dpll_core_m6_ck, "dpll_core_x2_ck", &dpll_core_x2_ck, - 0x0, AM33XX_CM_DIV_M6_DPLL_CORE, - AM33XX_HSDIVIDER_CLKOUT3_DIV_SHIFT, - AM33XX_HSDIVIDER_CLKOUT3_DIV_WIDTH, - CLK_DIVIDER_ONE_BASED, NULL); - - -/* DPLL_MPU */ -static struct dpll_data dpll_mpu_dd = { - .mult_div1_reg = AM33XX_CM_CLKSEL_DPLL_MPU, - .clk_bypass = &sys_clkin_ck, - .clk_ref = &sys_clkin_ck, - .control_reg = AM33XX_CM_CLKMODE_DPLL_MPU, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .idlest_reg = AM33XX_CM_IDLEST_DPLL_MPU, - .mult_mask = AM33XX_DPLL_MULT_MASK, - .div1_mask = AM33XX_DPLL_DIV_MASK, - .enable_mask = AM33XX_DPLL_EN_MASK, - .idlest_mask = AM33XX_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - -/* CLKOUT: fdpll/M2 */ -static struct clk dpll_mpu_ck; - -static const struct clk_ops dpll_mpu_ck_ops = { - .enable = &omap3_noncore_dpll_enable, - .disable = &omap3_noncore_dpll_disable, - .recalc_rate = &omap3_dpll_recalc, - .round_rate = &omap2_dpll_round_rate, - .set_rate = &omap3_noncore_dpll_set_rate, - .get_parent = &omap2_init_dpll_parent, -}; - -static struct clk_hw_omap dpll_mpu_ck_hw = { - .hw = { - .clk = &dpll_mpu_ck, - }, - .dpll_data = &dpll_mpu_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_mpu_ck, dpll_core_ck_parents, dpll_mpu_ck_ops); - -/* - * TODO: Add clksel here (sys_clkin, CORE_CLKOUTM6, PER_CLKOUTM2 - * and ALT_CLK1/2) - */ -DEFINE_CLK_DIVIDER(dpll_mpu_m2_ck, "dpll_mpu_ck", &dpll_mpu_ck, - 0x0, AM33XX_CM_DIV_M2_DPLL_MPU, AM33XX_DPLL_CLKOUT_DIV_SHIFT, - AM33XX_DPLL_CLKOUT_DIV_WIDTH, CLK_DIVIDER_ONE_BASED, NULL); - -/* DPLL_DDR */ -static struct dpll_data dpll_ddr_dd = { - .mult_div1_reg = AM33XX_CM_CLKSEL_DPLL_DDR, - .clk_bypass = &sys_clkin_ck, - .clk_ref = &sys_clkin_ck, - .control_reg = AM33XX_CM_CLKMODE_DPLL_DDR, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .idlest_reg = AM33XX_CM_IDLEST_DPLL_DDR, - .mult_mask = AM33XX_DPLL_MULT_MASK, - .div1_mask = AM33XX_DPLL_DIV_MASK, - .enable_mask = AM33XX_DPLL_EN_MASK, - .idlest_mask = AM33XX_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - -/* CLKOUT: fdpll/M2 */ -static struct clk dpll_ddr_ck; - -static const struct clk_ops dpll_ddr_ck_ops = { - .recalc_rate = &omap3_dpll_recalc, - .get_parent = &omap2_init_dpll_parent, - .round_rate = &omap2_dpll_round_rate, - .set_rate = &omap3_noncore_dpll_set_rate, -}; - -static struct clk_hw_omap dpll_ddr_ck_hw = { - .hw = { - .clk = &dpll_ddr_ck, - }, - .dpll_data = &dpll_ddr_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_ddr_ck, dpll_core_ck_parents, dpll_ddr_ck_ops); - -/* - * TODO: Add clksel here (sys_clkin, CORE_CLKOUTM6, PER_CLKOUTM2 - * and ALT_CLK1/2) - */ -DEFINE_CLK_DIVIDER(dpll_ddr_m2_ck, "dpll_ddr_ck", &dpll_ddr_ck, - 0x0, AM33XX_CM_DIV_M2_DPLL_DDR, - AM33XX_DPLL_CLKOUT_DIV_SHIFT, AM33XX_DPLL_CLKOUT_DIV_WIDTH, - CLK_DIVIDER_ONE_BASED, NULL); - -/* emif_fck functional clock */ -DEFINE_CLK_FIXED_FACTOR(dpll_ddr_m2_div2_ck, "dpll_ddr_m2_ck", &dpll_ddr_m2_ck, - 0x0, 1, 2); - -/* DPLL_DISP */ -static struct dpll_data dpll_disp_dd = { - .mult_div1_reg = AM33XX_CM_CLKSEL_DPLL_DISP, - .clk_bypass = &sys_clkin_ck, - .clk_ref = &sys_clkin_ck, - .control_reg = AM33XX_CM_CLKMODE_DPLL_DISP, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .idlest_reg = AM33XX_CM_IDLEST_DPLL_DISP, - .mult_mask = AM33XX_DPLL_MULT_MASK, - .div1_mask = AM33XX_DPLL_DIV_MASK, - .enable_mask = AM33XX_DPLL_EN_MASK, - .idlest_mask = AM33XX_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - -/* CLKOUT: fdpll/M2 */ -static struct clk dpll_disp_ck; - -static struct clk_hw_omap dpll_disp_ck_hw = { - .hw = { - .clk = &dpll_disp_ck, - }, - .dpll_data = &dpll_disp_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_disp_ck, dpll_core_ck_parents, dpll_ddr_ck_ops); - -/* - * TODO: Add clksel here (sys_clkin, CORE_CLKOUTM6, PER_CLKOUTM2 - * and ALT_CLK1/2) - */ -DEFINE_CLK_DIVIDER(dpll_disp_m2_ck, "dpll_disp_ck", &dpll_disp_ck, - CLK_SET_RATE_PARENT, AM33XX_CM_DIV_M2_DPLL_DISP, - AM33XX_DPLL_CLKOUT_DIV_SHIFT, AM33XX_DPLL_CLKOUT_DIV_WIDTH, - CLK_DIVIDER_ONE_BASED, NULL); - -/* DPLL_PER */ -static struct dpll_data dpll_per_dd = { - .mult_div1_reg = AM33XX_CM_CLKSEL_DPLL_PERIPH, - .clk_bypass = &sys_clkin_ck, - .clk_ref = &sys_clkin_ck, - .control_reg = AM33XX_CM_CLKMODE_DPLL_PER, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .idlest_reg = AM33XX_CM_IDLEST_DPLL_PER, - .mult_mask = AM33XX_DPLL_MULT_PERIPH_MASK, - .div1_mask = AM33XX_DPLL_PER_DIV_MASK, - .enable_mask = AM33XX_DPLL_EN_MASK, - .idlest_mask = AM33XX_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, - .flags = DPLL_J_TYPE, -}; - -/* CLKDCOLDO */ -static struct clk dpll_per_ck; - -static struct clk_hw_omap dpll_per_ck_hw = { - .hw = { - .clk = &dpll_per_ck, - }, - .dpll_data = &dpll_per_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_per_ck, dpll_core_ck_parents, dpll_ddr_ck_ops); - -/* CLKOUT: fdpll/M2 */ -DEFINE_CLK_DIVIDER(dpll_per_m2_ck, "dpll_per_ck", &dpll_per_ck, 0x0, - AM33XX_CM_DIV_M2_DPLL_PER, AM33XX_DPLL_CLKOUT_DIV_SHIFT, - AM33XX_DPLL_CLKOUT_DIV_WIDTH, CLK_DIVIDER_ONE_BASED, - NULL); - -DEFINE_CLK_FIXED_FACTOR(dpll_per_m2_div4_wkupdm_ck, "dpll_per_m2_ck", - &dpll_per_m2_ck, 0x0, 1, 4); - -DEFINE_CLK_FIXED_FACTOR(dpll_per_m2_div4_ck, "dpll_per_m2_ck", - &dpll_per_m2_ck, 0x0, 1, 4); - -DEFINE_CLK_FIXED_FACTOR(dpll_core_m4_div2_ck, "dpll_core_m4_ck", - &dpll_core_m4_ck, 0x0, 1, 2); - -DEFINE_CLK_FIXED_FACTOR(l4_rtc_gclk, "dpll_core_m4_ck", &dpll_core_m4_ck, 0x0, - 1, 2); - -DEFINE_CLK_FIXED_FACTOR(clk_24mhz, "dpll_per_m2_ck", &dpll_per_m2_ck, 0x0, 1, - 8); - -/* - * Below clock nodes describes clockdomains derived out - * of core clock. - */ -static const struct clk_ops clk_ops_null = { -}; - -static const char *l3_gclk_parents[] = { - "dpll_core_m4_ck" -}; - -static struct clk l3_gclk; -DEFINE_STRUCT_CLK_HW_OMAP(l3_gclk, NULL); -DEFINE_STRUCT_CLK(l3_gclk, l3_gclk_parents, clk_ops_null); - -static struct clk l4hs_gclk; -DEFINE_STRUCT_CLK_HW_OMAP(l4hs_gclk, NULL); -DEFINE_STRUCT_CLK(l4hs_gclk, l3_gclk_parents, clk_ops_null); - -static const char *l3s_gclk_parents[] = { - "dpll_core_m4_div2_ck" -}; - -static struct clk l3s_gclk; -DEFINE_STRUCT_CLK_HW_OMAP(l3s_gclk, NULL); -DEFINE_STRUCT_CLK(l3s_gclk, l3s_gclk_parents, clk_ops_null); - -static struct clk l4fw_gclk; -DEFINE_STRUCT_CLK_HW_OMAP(l4fw_gclk, NULL); -DEFINE_STRUCT_CLK(l4fw_gclk, l3s_gclk_parents, clk_ops_null); - -static struct clk l4ls_gclk; -DEFINE_STRUCT_CLK_HW_OMAP(l4ls_gclk, NULL); -DEFINE_STRUCT_CLK(l4ls_gclk, l3s_gclk_parents, clk_ops_null); - -static struct clk sysclk_div_ck; -DEFINE_STRUCT_CLK_HW_OMAP(sysclk_div_ck, NULL); -DEFINE_STRUCT_CLK(sysclk_div_ck, l3_gclk_parents, clk_ops_null); - -/* - * In order to match the clock domain with hwmod clockdomain entry, - * separate clock nodes is required for the modules which are - * directly getting their funtioncal clock from sys_clkin. - */ -static struct clk adc_tsc_fck; -DEFINE_STRUCT_CLK_HW_OMAP(adc_tsc_fck, NULL); -DEFINE_STRUCT_CLK(adc_tsc_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk dcan0_fck; -DEFINE_STRUCT_CLK_HW_OMAP(dcan0_fck, NULL); -DEFINE_STRUCT_CLK(dcan0_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk dcan1_fck; -DEFINE_STRUCT_CLK_HW_OMAP(dcan1_fck, NULL); -DEFINE_STRUCT_CLK(dcan1_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk mcasp0_fck; -DEFINE_STRUCT_CLK_HW_OMAP(mcasp0_fck, NULL); -DEFINE_STRUCT_CLK(mcasp0_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk mcasp1_fck; -DEFINE_STRUCT_CLK_HW_OMAP(mcasp1_fck, NULL); -DEFINE_STRUCT_CLK(mcasp1_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk smartreflex0_fck; -DEFINE_STRUCT_CLK_HW_OMAP(smartreflex0_fck, NULL); -DEFINE_STRUCT_CLK(smartreflex0_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk smartreflex1_fck; -DEFINE_STRUCT_CLK_HW_OMAP(smartreflex1_fck, NULL); -DEFINE_STRUCT_CLK(smartreflex1_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk sha0_fck; -DEFINE_STRUCT_CLK_HW_OMAP(sha0_fck, NULL); -DEFINE_STRUCT_CLK(sha0_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk aes0_fck; -DEFINE_STRUCT_CLK_HW_OMAP(aes0_fck, NULL); -DEFINE_STRUCT_CLK(aes0_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk rng_fck; -DEFINE_STRUCT_CLK_HW_OMAP(rng_fck, NULL); -DEFINE_STRUCT_CLK(rng_fck, dpll_core_ck_parents, clk_ops_null); - -/* - * Modules clock nodes - * - * The following clock leaf nodes are added for the moment because: - * - * - hwmod data is not present for these modules, either hwmod - * control is not required or its not populated. - * - Driver code is not yet migrated to use hwmod/runtime pm - * - Modules outside kernel access (to disable them by default) - * - * - mmu (gfx domain) - * - cefuse - * - usbotg_fck (its additional clock and not really a modulemode) - * - ieee5000 - */ - -DEFINE_CLK_GATE(mmu_fck, "dpll_core_m4_ck", &dpll_core_m4_ck, 0x0, - AM33XX_CM_GFX_MMUDATA_CLKCTRL, AM33XX_MODULEMODE_SWCTRL_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(cefuse_fck, "sys_clkin_ck", &sys_clkin_ck, 0x0, - AM33XX_CM_CEFUSE_CEFUSE_CLKCTRL, AM33XX_MODULEMODE_SWCTRL_SHIFT, - 0x0, NULL); - -/* - * clkdiv32 is generated from fixed division of 732.4219 - */ -DEFINE_CLK_FIXED_FACTOR(clkdiv32k_ck, "clk_24mhz", &clk_24mhz, 0x0, 1, 732); - -static struct clk clkdiv32k_ick; - -static const char *clkdiv32k_ick_parent_names[] = { - "clkdiv32k_ck", -}; - -static const struct clk_ops clkdiv32k_ick_ops = { - .enable = &omap2_dflt_clk_enable, - .disable = &omap2_dflt_clk_disable, - .is_enabled = &omap2_dflt_clk_is_enabled, - .init = &omap2_init_clk_clkdm, -}; - -static struct clk_hw_omap clkdiv32k_ick_hw = { - .hw = { - .clk = &clkdiv32k_ick, - }, - .enable_reg = AM33XX_CM_PER_CLKDIV32K_CLKCTRL, - .enable_bit = AM33XX_MODULEMODE_SWCTRL_SHIFT, - .clkdm_name = "clk_24mhz_clkdm", -}; - -DEFINE_STRUCT_CLK(clkdiv32k_ick, clkdiv32k_ick_parent_names, clkdiv32k_ick_ops); - -/* "usbotg_fck" is an additional clock and not really a modulemode */ -DEFINE_CLK_GATE(usbotg_fck, "dpll_per_ck", &dpll_per_ck, 0x0, - AM33XX_CM_CLKDCOLDO_DPLL_PER, AM33XX_ST_DPLL_CLKDCOLDO_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(ieee5000_fck, "dpll_core_m4_div2_ck", &dpll_core_m4_div2_ck, - 0x0, AM33XX_CM_PER_IEEE5000_CLKCTRL, - AM33XX_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -/* Timers */ -static const struct clksel timer1_clkmux_sel[] = { - { .parent = &sys_clkin_ck, .rates = div_1_0_rates }, - { .parent = &clkdiv32k_ick, .rates = div_1_1_rates }, - { .parent = &tclkin_ck, .rates = div_1_2_rates }, - { .parent = &clk_rc32k_ck, .rates = div_1_3_rates }, - { .parent = &clk_32768_ck, .rates = div_1_4_rates }, - { .parent = NULL }, -}; - -static const char *timer1_ck_parents[] = { - "sys_clkin_ck", "clkdiv32k_ick", "tclkin_ck", "clk_rc32k_ck", - "clk_32768_ck", -}; - -static struct clk timer1_fck; - -static const struct clk_ops timer1_fck_ops = { - .recalc_rate = &omap2_clksel_recalc, - .get_parent = &omap2_clksel_find_parent_index, - .set_parent = &omap2_clksel_set_parent, - .init = &omap2_init_clk_clkdm, -}; - -static struct clk_hw_omap timer1_fck_hw = { - .hw = { - .clk = &timer1_fck, - }, - .clkdm_name = "l4ls_clkdm", - .clksel = timer1_clkmux_sel, - .clksel_reg = AM33XX_CLKSEL_TIMER1MS_CLK, - .clksel_mask = AM33XX_CLKSEL_0_2_MASK, -}; - -DEFINE_STRUCT_CLK(timer1_fck, timer1_ck_parents, timer1_fck_ops); - -static const struct clksel timer2_to_7_clk_sel[] = { - { .parent = &tclkin_ck, .rates = div_1_0_rates }, - { .parent = &sys_clkin_ck, .rates = div_1_1_rates }, - { .parent = &clkdiv32k_ick, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static const char *timer2_to_7_ck_parents[] = { - "tclkin_ck", "sys_clkin_ck", "clkdiv32k_ick", -}; - -static struct clk timer2_fck; - -static struct clk_hw_omap timer2_fck_hw = { - .hw = { - .clk = &timer2_fck, - }, - .clkdm_name = "l4ls_clkdm", - .clksel = timer2_to_7_clk_sel, - .clksel_reg = AM33XX_CLKSEL_TIMER2_CLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK(timer2_fck, timer2_to_7_ck_parents, timer1_fck_ops); - -static struct clk timer3_fck; - -static struct clk_hw_omap timer3_fck_hw = { - .hw = { - .clk = &timer3_fck, - }, - .clkdm_name = "l4ls_clkdm", - .clksel = timer2_to_7_clk_sel, - .clksel_reg = AM33XX_CLKSEL_TIMER3_CLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK(timer3_fck, timer2_to_7_ck_parents, timer1_fck_ops); - -static struct clk timer4_fck; - -static struct clk_hw_omap timer4_fck_hw = { - .hw = { - .clk = &timer4_fck, - }, - .clkdm_name = "l4ls_clkdm", - .clksel = timer2_to_7_clk_sel, - .clksel_reg = AM33XX_CLKSEL_TIMER4_CLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK(timer4_fck, timer2_to_7_ck_parents, timer1_fck_ops); - -static struct clk timer5_fck; - -static struct clk_hw_omap timer5_fck_hw = { - .hw = { - .clk = &timer5_fck, - }, - .clkdm_name = "l4ls_clkdm", - .clksel = timer2_to_7_clk_sel, - .clksel_reg = AM33XX_CLKSEL_TIMER5_CLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK(timer5_fck, timer2_to_7_ck_parents, timer1_fck_ops); - -static struct clk timer6_fck; - -static struct clk_hw_omap timer6_fck_hw = { - .hw = { - .clk = &timer6_fck, - }, - .clkdm_name = "l4ls_clkdm", - .clksel = timer2_to_7_clk_sel, - .clksel_reg = AM33XX_CLKSEL_TIMER6_CLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK(timer6_fck, timer2_to_7_ck_parents, timer1_fck_ops); - -static struct clk timer7_fck; - -static struct clk_hw_omap timer7_fck_hw = { - .hw = { - .clk = &timer7_fck, - }, - .clkdm_name = "l4ls_clkdm", - .clksel = timer2_to_7_clk_sel, - .clksel_reg = AM33XX_CLKSEL_TIMER7_CLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK(timer7_fck, timer2_to_7_ck_parents, timer1_fck_ops); - -DEFINE_CLK_FIXED_FACTOR(cpsw_125mhz_gclk, - "dpll_core_m5_ck", - &dpll_core_m5_ck, - 0x0, - 1, 2); - -static const struct clk_ops cpsw_fck_ops = { - .recalc_rate = &omap2_clksel_recalc, - .get_parent = &omap2_clksel_find_parent_index, - .set_parent = &omap2_clksel_set_parent, -}; - -static const struct clksel cpsw_cpts_rft_clkmux_sel[] = { - { .parent = &dpll_core_m5_ck, .rates = div_1_0_rates }, - { .parent = &dpll_core_m4_ck, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -static const char *cpsw_cpts_rft_ck_parents[] = { - "dpll_core_m5_ck", "dpll_core_m4_ck", -}; - -static struct clk cpsw_cpts_rft_clk; - -static struct clk_hw_omap cpsw_cpts_rft_clk_hw = { - .hw = { - .clk = &cpsw_cpts_rft_clk, - }, - .clkdm_name = "cpsw_125mhz_clkdm", - .clksel = cpsw_cpts_rft_clkmux_sel, - .clksel_reg = AM33XX_CM_CPTS_RFT_CLKSEL, - .clksel_mask = AM33XX_CLKSEL_0_0_MASK, -}; - -DEFINE_STRUCT_CLK(cpsw_cpts_rft_clk, cpsw_cpts_rft_ck_parents, cpsw_fck_ops); - - -/* gpio */ -static const char *gpio0_ck_parents[] = { - "clk_rc32k_ck", "clk_32768_ck", "clkdiv32k_ick", -}; - -static const struct clksel gpio0_dbclk_mux_sel[] = { - { .parent = &clk_rc32k_ck, .rates = div_1_0_rates }, - { .parent = &clk_32768_ck, .rates = div_1_1_rates }, - { .parent = &clkdiv32k_ick, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static const struct clk_ops gpio_fck_ops = { - .recalc_rate = &omap2_clksel_recalc, - .get_parent = &omap2_clksel_find_parent_index, - .set_parent = &omap2_clksel_set_parent, - .init = &omap2_init_clk_clkdm, -}; - -static struct clk gpio0_dbclk_mux_ck; - -static struct clk_hw_omap gpio0_dbclk_mux_ck_hw = { - .hw = { - .clk = &gpio0_dbclk_mux_ck, - }, - .clkdm_name = "l4_wkup_clkdm", - .clksel = gpio0_dbclk_mux_sel, - .clksel_reg = AM33XX_CLKSEL_GPIO0_DBCLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK(gpio0_dbclk_mux_ck, gpio0_ck_parents, gpio_fck_ops); - -DEFINE_CLK_GATE(gpio0_dbclk, "gpio0_dbclk_mux_ck", &gpio0_dbclk_mux_ck, 0x0, - AM33XX_CM_WKUP_GPIO0_CLKCTRL, - AM33XX_OPTFCLKEN_GPIO0_GDBCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(gpio1_dbclk, "clkdiv32k_ick", &clkdiv32k_ick, 0x0, - AM33XX_CM_PER_GPIO1_CLKCTRL, - AM33XX_OPTFCLKEN_GPIO_1_GDBCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(gpio2_dbclk, "clkdiv32k_ick", &clkdiv32k_ick, 0x0, - AM33XX_CM_PER_GPIO2_CLKCTRL, - AM33XX_OPTFCLKEN_GPIO_2_GDBCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(gpio3_dbclk, "clkdiv32k_ick", &clkdiv32k_ick, 0x0, - AM33XX_CM_PER_GPIO3_CLKCTRL, - AM33XX_OPTFCLKEN_GPIO_3_GDBCLK_SHIFT, 0x0, NULL); - - -static const char *pruss_ck_parents[] = { - "l3_gclk", "dpll_disp_m2_ck", -}; - -static const struct clksel pruss_ocp_clk_mux_sel[] = { - { .parent = &l3_gclk, .rates = div_1_0_rates }, - { .parent = &dpll_disp_m2_ck, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -static struct clk pruss_ocp_gclk; - -static struct clk_hw_omap pruss_ocp_gclk_hw = { - .hw = { - .clk = &pruss_ocp_gclk, - }, - .clkdm_name = "pruss_ocp_clkdm", - .clksel = pruss_ocp_clk_mux_sel, - .clksel_reg = AM33XX_CLKSEL_PRUSS_OCP_CLK, - .clksel_mask = AM33XX_CLKSEL_0_0_MASK, -}; - -DEFINE_STRUCT_CLK(pruss_ocp_gclk, pruss_ck_parents, gpio_fck_ops); - -static const char *lcd_ck_parents[] = { - "dpll_disp_m2_ck", "dpll_core_m5_ck", "dpll_per_m2_ck", -}; - -static const struct clksel lcd_clk_mux_sel[] = { - { .parent = &dpll_disp_m2_ck, .rates = div_1_0_rates }, - { .parent = &dpll_core_m5_ck, .rates = div_1_1_rates }, - { .parent = &dpll_per_m2_ck, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static struct clk lcd_gclk; - -static struct clk_hw_omap lcd_gclk_hw = { - .hw = { - .clk = &lcd_gclk, - }, - .clkdm_name = "lcdc_clkdm", - .clksel = lcd_clk_mux_sel, - .clksel_reg = AM33XX_CLKSEL_LCDC_PIXEL_CLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK_FLAGS(lcd_gclk, lcd_ck_parents, - gpio_fck_ops, CLK_SET_RATE_PARENT); - -DEFINE_CLK_FIXED_FACTOR(mmc_clk, "dpll_per_m2_ck", &dpll_per_m2_ck, 0x0, 1, 2); - -static const char *gfx_ck_parents[] = { - "dpll_core_m4_ck", "dpll_per_m2_ck", -}; - -static const struct clksel gfx_clksel_sel[] = { - { .parent = &dpll_core_m4_ck, .rates = div_1_0_rates }, - { .parent = &dpll_per_m2_ck, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -static struct clk gfx_fclk_clksel_ck; - -static struct clk_hw_omap gfx_fclk_clksel_ck_hw = { - .hw = { - .clk = &gfx_fclk_clksel_ck, - }, - .clksel = gfx_clksel_sel, - .clksel_reg = AM33XX_CLKSEL_GFX_FCLK, - .clksel_mask = AM33XX_CLKSEL_GFX_FCLK_MASK, -}; - -DEFINE_STRUCT_CLK(gfx_fclk_clksel_ck, gfx_ck_parents, gpio_fck_ops); - -static const struct clk_div_table div_1_0_2_1_rates[] = { - { .div = 1, .val = 0, }, - { .div = 2, .val = 1, }, - { .div = 0 }, -}; - -DEFINE_CLK_DIVIDER_TABLE(gfx_fck_div_ck, "gfx_fclk_clksel_ck", - &gfx_fclk_clksel_ck, 0x0, AM33XX_CLKSEL_GFX_FCLK, - AM33XX_CLKSEL_0_0_SHIFT, AM33XX_CLKSEL_0_0_WIDTH, - 0x0, div_1_0_2_1_rates, NULL); - -static const char *sysclkout_ck_parents[] = { - "clk_32768_ck", "l3_gclk", "dpll_ddr_m2_ck", "dpll_per_m2_ck", - "lcd_gclk", -}; - -static const struct clksel sysclkout_pre_sel[] = { - { .parent = &clk_32768_ck, .rates = div_1_0_rates }, - { .parent = &l3_gclk, .rates = div_1_1_rates }, - { .parent = &dpll_ddr_m2_ck, .rates = div_1_2_rates }, - { .parent = &dpll_per_m2_ck, .rates = div_1_3_rates }, - { .parent = &lcd_gclk, .rates = div_1_4_rates }, - { .parent = NULL }, -}; - -static struct clk sysclkout_pre_ck; - -static struct clk_hw_omap sysclkout_pre_ck_hw = { - .hw = { - .clk = &sysclkout_pre_ck, - }, - .clksel = sysclkout_pre_sel, - .clksel_reg = AM33XX_CM_CLKOUT_CTRL, - .clksel_mask = AM33XX_CLKOUT2SOURCE_MASK, -}; - -DEFINE_STRUCT_CLK(sysclkout_pre_ck, sysclkout_ck_parents, gpio_fck_ops); - -/* Divide by 8 clock rates with default clock is 1/1*/ -static const struct clk_div_table div8_rates[] = { - { .div = 1, .val = 0, }, - { .div = 2, .val = 1, }, - { .div = 3, .val = 2, }, - { .div = 4, .val = 3, }, - { .div = 5, .val = 4, }, - { .div = 6, .val = 5, }, - { .div = 7, .val = 6, }, - { .div = 8, .val = 7, }, - { .div = 0 }, -}; - -DEFINE_CLK_DIVIDER_TABLE(clkout2_div_ck, "sysclkout_pre_ck", &sysclkout_pre_ck, - 0x0, AM33XX_CM_CLKOUT_CTRL, AM33XX_CLKOUT2DIV_SHIFT, - AM33XX_CLKOUT2DIV_WIDTH, 0x0, div8_rates, NULL); - -DEFINE_CLK_GATE(clkout2_ck, "clkout2_div_ck", &clkout2_div_ck, 0x0, - AM33XX_CM_CLKOUT_CTRL, AM33XX_CLKOUT2EN_SHIFT, 0x0, NULL); - -static const char *wdt_ck_parents[] = { - "clk_rc32k_ck", "clkdiv32k_ick", -}; - -static const struct clksel wdt_clkmux_sel[] = { - { .parent = &clk_rc32k_ck, .rates = div_1_0_rates }, - { .parent = &clkdiv32k_ick, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -static struct clk wdt1_fck; - -static struct clk_hw_omap wdt1_fck_hw = { - .hw = { - .clk = &wdt1_fck, - }, - .clkdm_name = "l4_wkup_clkdm", - .clksel = wdt_clkmux_sel, - .clksel_reg = AM33XX_CLKSEL_WDT1_CLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK(wdt1_fck, wdt_ck_parents, gpio_fck_ops); - -static const char *pwmss_clk_parents[] = { - "dpll_per_m2_ck", -}; - -static const struct clk_ops ehrpwm_tbclk_ops = { - .enable = &omap2_dflt_clk_enable, - .disable = &omap2_dflt_clk_disable, -}; - -DEFINE_CLK_OMAP_MUX_GATE(ehrpwm0_tbclk, "l4ls_clkdm", - NULL, NULL, 0, - AM33XX_CTRL_REGADDR(AM33XX_PWMSS_TBCLK_CLKCTRL), - AM33XX_PWMSS0_TBCLKEN_SHIFT, - NULL, pwmss_clk_parents, ehrpwm_tbclk_ops); - -DEFINE_CLK_OMAP_MUX_GATE(ehrpwm1_tbclk, "l4ls_clkdm", - NULL, NULL, 0, - AM33XX_CTRL_REGADDR(AM33XX_PWMSS_TBCLK_CLKCTRL), - AM33XX_PWMSS1_TBCLKEN_SHIFT, - NULL, pwmss_clk_parents, ehrpwm_tbclk_ops); - -DEFINE_CLK_OMAP_MUX_GATE(ehrpwm2_tbclk, "l4ls_clkdm", - NULL, NULL, 0, - AM33XX_CTRL_REGADDR(AM33XX_PWMSS_TBCLK_CLKCTRL), - AM33XX_PWMSS2_TBCLKEN_SHIFT, - NULL, pwmss_clk_parents, ehrpwm_tbclk_ops); - -/* - * debugss optional clocks - */ -DEFINE_CLK_GATE(dbg_sysclk_ck, "sys_clkin_ck", &sys_clkin_ck, - 0x0, AM33XX_CM_WKUP_DEBUGSS_CLKCTRL, - AM33XX_OPTFCLKEN_DBGSYSCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(dbg_clka_ck, "dpll_core_m4_ck", &dpll_core_m4_ck, - 0x0, AM33XX_CM_WKUP_DEBUGSS_CLKCTRL, - AM33XX_OPTCLK_DEBUG_CLKA_SHIFT, 0x0, NULL); - -static const char *stm_pmd_clock_mux_ck_parents[] = { - "dbg_sysclk_ck", "dbg_clka_ck", -}; - -DEFINE_CLK_MUX(stm_pmd_clock_mux_ck, stm_pmd_clock_mux_ck_parents, NULL, 0x0, - AM33XX_CM_WKUP_DEBUGSS_CLKCTRL, AM33XX_STM_PMD_CLKSEL_SHIFT, - AM33XX_STM_PMD_CLKSEL_WIDTH, 0x0, NULL); - -DEFINE_CLK_MUX(trace_pmd_clk_mux_ck, stm_pmd_clock_mux_ck_parents, NULL, 0x0, - AM33XX_CM_WKUP_DEBUGSS_CLKCTRL, - AM33XX_TRC_PMD_CLKSEL_SHIFT, - AM33XX_TRC_PMD_CLKSEL_WIDTH, 0x0, NULL); - -DEFINE_CLK_DIVIDER(stm_clk_div_ck, "stm_pmd_clock_mux_ck", - &stm_pmd_clock_mux_ck, 0x0, AM33XX_CM_WKUP_DEBUGSS_CLKCTRL, - AM33XX_STM_PMD_CLKDIVSEL_SHIFT, - AM33XX_STM_PMD_CLKDIVSEL_WIDTH, CLK_DIVIDER_POWER_OF_TWO, - NULL); - -DEFINE_CLK_DIVIDER(trace_clk_div_ck, "trace_pmd_clk_mux_ck", - &trace_pmd_clk_mux_ck, 0x0, AM33XX_CM_WKUP_DEBUGSS_CLKCTRL, - AM33XX_TRC_PMD_CLKDIVSEL_SHIFT, - AM33XX_TRC_PMD_CLKDIVSEL_WIDTH, CLK_DIVIDER_POWER_OF_TWO, - NULL); - -/* - * clkdev - */ -static struct omap_clk am33xx_clks[] = { - CLK(NULL, "clk_32768_ck", &clk_32768_ck), - CLK(NULL, "clk_rc32k_ck", &clk_rc32k_ck), - CLK(NULL, "virt_19200000_ck", &virt_19200000_ck), - CLK(NULL, "virt_24000000_ck", &virt_24000000_ck), - CLK(NULL, "virt_25000000_ck", &virt_25000000_ck), - CLK(NULL, "virt_26000000_ck", &virt_26000000_ck), - CLK(NULL, "sys_clkin_ck", &sys_clkin_ck), - CLK(NULL, "tclkin_ck", &tclkin_ck), - CLK(NULL, "dpll_core_ck", &dpll_core_ck), - CLK(NULL, "dpll_core_x2_ck", &dpll_core_x2_ck), - CLK(NULL, "dpll_core_m4_ck", &dpll_core_m4_ck), - CLK(NULL, "dpll_core_m5_ck", &dpll_core_m5_ck), - CLK(NULL, "dpll_core_m6_ck", &dpll_core_m6_ck), - CLK(NULL, "dpll_mpu_ck", &dpll_mpu_ck), - CLK("cpu0", NULL, &dpll_mpu_ck), - CLK(NULL, "dpll_mpu_m2_ck", &dpll_mpu_m2_ck), - CLK(NULL, "dpll_ddr_ck", &dpll_ddr_ck), - CLK(NULL, "dpll_ddr_m2_ck", &dpll_ddr_m2_ck), - CLK(NULL, "dpll_ddr_m2_div2_ck", &dpll_ddr_m2_div2_ck), - CLK(NULL, "dpll_disp_ck", &dpll_disp_ck), - CLK(NULL, "dpll_disp_m2_ck", &dpll_disp_m2_ck), - CLK(NULL, "dpll_per_ck", &dpll_per_ck), - CLK(NULL, "dpll_per_m2_ck", &dpll_per_m2_ck), - CLK(NULL, "dpll_per_m2_div4_wkupdm_ck", &dpll_per_m2_div4_wkupdm_ck), - CLK(NULL, "dpll_per_m2_div4_ck", &dpll_per_m2_div4_ck), - CLK(NULL, "adc_tsc_fck", &adc_tsc_fck), - CLK(NULL, "cefuse_fck", &cefuse_fck), - CLK(NULL, "clkdiv32k_ck", &clkdiv32k_ck), - CLK(NULL, "clkdiv32k_ick", &clkdiv32k_ick), - CLK(NULL, "dcan0_fck", &dcan0_fck), - CLK("481cc000.d_can", NULL, &dcan0_fck), - CLK(NULL, "dcan1_fck", &dcan1_fck), - CLK("481d0000.d_can", NULL, &dcan1_fck), - CLK(NULL, "pruss_ocp_gclk", &pruss_ocp_gclk), - CLK(NULL, "mcasp0_fck", &mcasp0_fck), - CLK(NULL, "mcasp1_fck", &mcasp1_fck), - CLK(NULL, "mmu_fck", &mmu_fck), - CLK(NULL, "smartreflex0_fck", &smartreflex0_fck), - CLK(NULL, "smartreflex1_fck", &smartreflex1_fck), - CLK(NULL, "sha0_fck", &sha0_fck), - CLK(NULL, "aes0_fck", &aes0_fck), - CLK(NULL, "rng_fck", &rng_fck), - CLK(NULL, "timer1_fck", &timer1_fck), - CLK(NULL, "timer2_fck", &timer2_fck), - CLK(NULL, "timer3_fck", &timer3_fck), - CLK(NULL, "timer4_fck", &timer4_fck), - CLK(NULL, "timer5_fck", &timer5_fck), - CLK(NULL, "timer6_fck", &timer6_fck), - CLK(NULL, "timer7_fck", &timer7_fck), - CLK(NULL, "usbotg_fck", &usbotg_fck), - CLK(NULL, "ieee5000_fck", &ieee5000_fck), - CLK(NULL, "wdt1_fck", &wdt1_fck), - CLK(NULL, "l4_rtc_gclk", &l4_rtc_gclk), - CLK(NULL, "l3_gclk", &l3_gclk), - CLK(NULL, "dpll_core_m4_div2_ck", &dpll_core_m4_div2_ck), - CLK(NULL, "l4hs_gclk", &l4hs_gclk), - CLK(NULL, "l3s_gclk", &l3s_gclk), - CLK(NULL, "l4fw_gclk", &l4fw_gclk), - CLK(NULL, "l4ls_gclk", &l4ls_gclk), - CLK(NULL, "clk_24mhz", &clk_24mhz), - CLK(NULL, "sysclk_div_ck", &sysclk_div_ck), - CLK(NULL, "cpsw_125mhz_gclk", &cpsw_125mhz_gclk), - CLK(NULL, "cpsw_cpts_rft_clk", &cpsw_cpts_rft_clk), - CLK(NULL, "gpio0_dbclk_mux_ck", &gpio0_dbclk_mux_ck), - CLK(NULL, "gpio0_dbclk", &gpio0_dbclk), - CLK(NULL, "gpio1_dbclk", &gpio1_dbclk), - CLK(NULL, "gpio2_dbclk", &gpio2_dbclk), - CLK(NULL, "gpio3_dbclk", &gpio3_dbclk), - CLK(NULL, "lcd_gclk", &lcd_gclk), - CLK(NULL, "mmc_clk", &mmc_clk), - CLK(NULL, "gfx_fclk_clksel_ck", &gfx_fclk_clksel_ck), - CLK(NULL, "gfx_fck_div_ck", &gfx_fck_div_ck), - CLK(NULL, "sysclkout_pre_ck", &sysclkout_pre_ck), - CLK(NULL, "clkout2_div_ck", &clkout2_div_ck), - CLK(NULL, "timer_32k_ck", &clkdiv32k_ick), - CLK(NULL, "timer_sys_ck", &sys_clkin_ck), - CLK(NULL, "dbg_sysclk_ck", &dbg_sysclk_ck), - CLK(NULL, "dbg_clka_ck", &dbg_clka_ck), - CLK(NULL, "stm_pmd_clock_mux_ck", &stm_pmd_clock_mux_ck), - CLK(NULL, "trace_pmd_clk_mux_ck", &trace_pmd_clk_mux_ck), - CLK(NULL, "stm_clk_div_ck", &stm_clk_div_ck), - CLK(NULL, "trace_clk_div_ck", &trace_clk_div_ck), - CLK(NULL, "clkout2_ck", &clkout2_ck), - CLK("48300200.ehrpwm", "tbclk", &ehrpwm0_tbclk), - CLK("48302200.ehrpwm", "tbclk", &ehrpwm1_tbclk), - CLK("48304200.ehrpwm", "tbclk", &ehrpwm2_tbclk), -}; - - -static const char *enable_init_clks[] = { - "dpll_ddr_m2_ck", - "dpll_mpu_m2_ck", - "l3_gclk", - "l4hs_gclk", - "l4fw_gclk", - "l4ls_gclk", - "clkout2_ck", /* Required for external peripherals like, Audio codecs */ -}; - -int __init am33xx_clk_init(void) -{ - if (soc_is_am33xx()) - cpu_mask = RATE_IN_AM33XX; - - omap_clocks_register(am33xx_clks, ARRAY_SIZE(am33xx_clks)); - - omap2_clk_disable_autoidle_all(); - - omap2_clk_enable_init_clocks(enable_init_clks, - ARRAY_SIZE(enable_init_clks)); - - /* TRM ERRATA: Timer 3 & 6 default parent (TCLKIN) may not be always - * physically present, in such a case HWMOD enabling of - * clock would be failure with default parent. And timer - * probe thinks clock is already enabled, this leads to - * crash upon accessing timer 3 & 6 registers in probe. - * Fix by setting parent of both these timers to master - * oscillator clock. - */ - - clk_set_parent(&timer3_fck, &sys_clkin_ck); - clk_set_parent(&timer6_fck, &sys_clkin_ck); - /* - * The On-Chip 32K RC Osc clock is not an accurate clock-source as per - * the design/spec, so as a result, for example, timer which supposed - * to get expired @60Sec, but will expire somewhere ~@40Sec, which is - * not expected by any use-case, so change WDT1 clock source to PRCM - * 32KHz clock. - */ - clk_set_parent(&wdt1_fck, &clkdiv32k_ick); - - return 0; -} diff --git a/arch/arm/mach-omap2/cclock44xx_data.c b/arch/arm/mach-omap2/cclock44xx_data.c deleted file mode 100644 index ec0dc0b1755ef9..00000000000000 --- a/arch/arm/mach-omap2/cclock44xx_data.c +++ /dev/null @@ -1,1735 +0,0 @@ -/* - * OMAP4 Clock data - * - * Copyright (C) 2009-2012 Texas Instruments, Inc. - * Copyright (C) 2009-2010 Nokia Corporation - * - * Paul Walmsley (paul@pwsan.com) - * Rajendra Nayak (rnayak@ti.com) - * Benoit Cousson (b-cousson@ti.com) - * Mike Turquette (mturquette@ti.com) - * - * 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. - * - * XXX Some of the ES1 clocks have been removed/changed; once support - * is added for discriminating clocks by ES level, these should be added back - * in. - * - * XXX All of the remaining MODULEMODE clock nodes should be removed - * once the drivers are updated to use pm_runtime or to use the appropriate - * upstream clock node for rate/parent selection. - */ - -#include -#include -#include -#include -#include - -#include "soc.h" -#include "iomap.h" -#include "clock.h" -#include "clock44xx.h" -#include "cm1_44xx.h" -#include "cm2_44xx.h" -#include "cm-regbits-44xx.h" -#include "prm44xx.h" -#include "prm-regbits-44xx.h" -#include "control.h" -#include "scrm44xx.h" - -/* OMAP4 modulemode control */ -#define OMAP4430_MODULEMODE_HWCTRL_SHIFT 0 -#define OMAP4430_MODULEMODE_SWCTRL_SHIFT 1 - -/* - * OMAP4 ABE DPLL default frequency. In OMAP4460 TRM version V, section - * "3.6.3.2.3 CM1_ABE Clock Generator" states that the "DPLL_ABE_X2_CLK - * must be set to 196.608 MHz" and hence, the DPLL locked frequency is - * half of this value. - */ -#define OMAP4_DPLL_ABE_DEFFREQ 98304000 - -/* - * OMAP4 USB DPLL default frequency. In OMAP4430 TRM version V, section - * "3.6.3.9.5 DPLL_USB Preferred Settings" shows that the preferred - * locked frequency for the USB DPLL is 960MHz. - */ -#define OMAP4_DPLL_USB_DEFFREQ 960000000 - -/* Root clocks */ - -DEFINE_CLK_FIXED_RATE(extalt_clkin_ck, CLK_IS_ROOT, 59000000, 0x0); - -DEFINE_CLK_FIXED_RATE(pad_clks_src_ck, CLK_IS_ROOT, 12000000, 0x0); - -DEFINE_CLK_GATE(pad_clks_ck, "pad_clks_src_ck", &pad_clks_src_ck, 0x0, - OMAP4430_CM_CLKSEL_ABE, OMAP4430_PAD_CLKS_GATE_SHIFT, - 0x0, NULL); - -DEFINE_CLK_FIXED_RATE(pad_slimbus_core_clks_ck, CLK_IS_ROOT, 12000000, 0x0); - -DEFINE_CLK_FIXED_RATE(secure_32k_clk_src_ck, CLK_IS_ROOT, 32768, 0x0); - -DEFINE_CLK_FIXED_RATE(slimbus_src_clk, CLK_IS_ROOT, 12000000, 0x0); - -DEFINE_CLK_GATE(slimbus_clk, "slimbus_src_clk", &slimbus_src_clk, 0x0, - OMAP4430_CM_CLKSEL_ABE, OMAP4430_SLIMBUS_CLK_GATE_SHIFT, - 0x0, NULL); - -DEFINE_CLK_FIXED_RATE(sys_32k_ck, CLK_IS_ROOT, 32768, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_12000000_ck, CLK_IS_ROOT, 12000000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_13000000_ck, CLK_IS_ROOT, 13000000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_16800000_ck, CLK_IS_ROOT, 16800000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_19200000_ck, CLK_IS_ROOT, 19200000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_26000000_ck, CLK_IS_ROOT, 26000000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_27000000_ck, CLK_IS_ROOT, 27000000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_38400000_ck, CLK_IS_ROOT, 38400000, 0x0); - -static const char *sys_clkin_ck_parents[] = { - "virt_12000000_ck", "virt_13000000_ck", "virt_16800000_ck", - "virt_19200000_ck", "virt_26000000_ck", "virt_27000000_ck", - "virt_38400000_ck", -}; - -DEFINE_CLK_MUX(sys_clkin_ck, sys_clkin_ck_parents, NULL, 0x0, - OMAP4430_CM_SYS_CLKSEL, OMAP4430_SYS_CLKSEL_SHIFT, - OMAP4430_SYS_CLKSEL_WIDTH, CLK_MUX_INDEX_ONE, NULL); - -DEFINE_CLK_FIXED_RATE(tie_low_clock_ck, CLK_IS_ROOT, 0, 0x0); - -DEFINE_CLK_FIXED_RATE(utmi_phy_clkout_ck, CLK_IS_ROOT, 60000000, 0x0); - -DEFINE_CLK_FIXED_RATE(xclk60mhsp1_ck, CLK_IS_ROOT, 60000000, 0x0); - -DEFINE_CLK_FIXED_RATE(xclk60mhsp2_ck, CLK_IS_ROOT, 60000000, 0x0); - -DEFINE_CLK_FIXED_RATE(xclk60motg_ck, CLK_IS_ROOT, 60000000, 0x0); - -/* Module clocks and DPLL outputs */ - -static const char *abe_dpll_bypass_clk_mux_ck_parents[] = { - "sys_clkin_ck", "sys_32k_ck", -}; - -DEFINE_CLK_MUX(abe_dpll_bypass_clk_mux_ck, abe_dpll_bypass_clk_mux_ck_parents, - NULL, 0x0, OMAP4430_CM_L4_WKUP_CLKSEL, OMAP4430_CLKSEL_SHIFT, - OMAP4430_CLKSEL_WIDTH, 0x0, NULL); - -DEFINE_CLK_MUX(abe_dpll_refclk_mux_ck, abe_dpll_bypass_clk_mux_ck_parents, NULL, - 0x0, OMAP4430_CM_ABE_PLL_REF_CLKSEL, OMAP4430_CLKSEL_0_0_SHIFT, - OMAP4430_CLKSEL_0_0_WIDTH, 0x0, NULL); - -/* DPLL_ABE */ -static struct dpll_data dpll_abe_dd = { - .mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_ABE, - .clk_bypass = &abe_dpll_bypass_clk_mux_ck, - .clk_ref = &abe_dpll_refclk_mux_ck, - .control_reg = OMAP4430_CM_CLKMODE_DPLL_ABE, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_ABE, - .idlest_reg = OMAP4430_CM_IDLEST_DPLL_ABE, - .mult_mask = OMAP4430_DPLL_MULT_MASK, - .div1_mask = OMAP4430_DPLL_DIV_MASK, - .enable_mask = OMAP4430_DPLL_EN_MASK, - .autoidle_mask = OMAP4430_AUTO_DPLL_MODE_MASK, - .idlest_mask = OMAP4430_ST_DPLL_CLK_MASK, - .m4xen_mask = OMAP4430_DPLL_REGM4XEN_MASK, - .lpmode_mask = OMAP4430_DPLL_LPMODE_EN_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - - -static const char *dpll_abe_ck_parents[] = { - "abe_dpll_refclk_mux_ck", -}; - -static struct clk dpll_abe_ck; - -static const struct clk_ops dpll_abe_ck_ops = { - .enable = &omap3_noncore_dpll_enable, - .disable = &omap3_noncore_dpll_disable, - .recalc_rate = &omap4_dpll_regm4xen_recalc, - .round_rate = &omap4_dpll_regm4xen_round_rate, - .set_rate = &omap3_noncore_dpll_set_rate, - .get_parent = &omap2_init_dpll_parent, -}; - -static struct clk_hw_omap dpll_abe_ck_hw = { - .hw = { - .clk = &dpll_abe_ck, - }, - .dpll_data = &dpll_abe_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_abe_ck, dpll_abe_ck_parents, dpll_abe_ck_ops); - -static const char *dpll_abe_x2_ck_parents[] = { - "dpll_abe_ck", -}; - -static struct clk dpll_abe_x2_ck; - -static const struct clk_ops dpll_abe_x2_ck_ops = { - .recalc_rate = &omap3_clkoutx2_recalc, -}; - -static struct clk_hw_omap dpll_abe_x2_ck_hw = { - .hw = { - .clk = &dpll_abe_x2_ck, - }, - .flags = CLOCK_CLKOUTX2, - .clksel_reg = OMAP4430_CM_DIV_M2_DPLL_ABE, - .ops = &clkhwops_omap4_dpllmx, -}; - -DEFINE_STRUCT_CLK(dpll_abe_x2_ck, dpll_abe_x2_ck_parents, dpll_abe_x2_ck_ops); - -static const struct clk_ops omap_hsdivider_ops = { - .set_rate = &omap2_clksel_set_rate, - .recalc_rate = &omap2_clksel_recalc, - .round_rate = &omap2_clksel_round_rate, -}; - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_abe_m2x2_ck, "dpll_abe_x2_ck", &dpll_abe_x2_ck, - 0x0, OMAP4430_CM_DIV_M2_DPLL_ABE, - OMAP4430_DPLL_CLKOUT_DIV_MASK); - -DEFINE_CLK_FIXED_FACTOR(abe_24m_fclk, "dpll_abe_m2x2_ck", &dpll_abe_m2x2_ck, - 0x0, 1, 8); - -DEFINE_CLK_DIVIDER(abe_clk, "dpll_abe_m2x2_ck", &dpll_abe_m2x2_ck, 0x0, - OMAP4430_CM_CLKSEL_ABE, OMAP4430_CLKSEL_OPP_SHIFT, - OMAP4430_CLKSEL_OPP_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL); - -DEFINE_CLK_DIVIDER(aess_fclk, "abe_clk", &abe_clk, 0x0, - OMAP4430_CM1_ABE_AESS_CLKCTRL, - OMAP4430_CLKSEL_AESS_FCLK_SHIFT, - OMAP4430_CLKSEL_AESS_FCLK_WIDTH, - 0x0, NULL); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_abe_m3x2_ck, "dpll_abe_x2_ck", &dpll_abe_x2_ck, - 0x0, OMAP4430_CM_DIV_M3_DPLL_ABE, - OMAP4430_DPLL_CLKOUTHIF_DIV_MASK); - -static const char *core_hsd_byp_clk_mux_ck_parents[] = { - "sys_clkin_ck", "dpll_abe_m3x2_ck", -}; - -DEFINE_CLK_MUX(core_hsd_byp_clk_mux_ck, core_hsd_byp_clk_mux_ck_parents, NULL, - 0x0, OMAP4430_CM_CLKSEL_DPLL_CORE, - OMAP4430_DPLL_BYP_CLKSEL_SHIFT, OMAP4430_DPLL_BYP_CLKSEL_WIDTH, - 0x0, NULL); - -/* DPLL_CORE */ -static struct dpll_data dpll_core_dd = { - .mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_CORE, - .clk_bypass = &core_hsd_byp_clk_mux_ck, - .clk_ref = &sys_clkin_ck, - .control_reg = OMAP4430_CM_CLKMODE_DPLL_CORE, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_CORE, - .idlest_reg = OMAP4430_CM_IDLEST_DPLL_CORE, - .mult_mask = OMAP4430_DPLL_MULT_MASK, - .div1_mask = OMAP4430_DPLL_DIV_MASK, - .enable_mask = OMAP4430_DPLL_EN_MASK, - .autoidle_mask = OMAP4430_AUTO_DPLL_MODE_MASK, - .idlest_mask = OMAP4430_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - - -static const char *dpll_core_ck_parents[] = { - "sys_clkin_ck", "core_hsd_byp_clk_mux_ck" -}; - -static struct clk dpll_core_ck; - -static const struct clk_ops dpll_core_ck_ops = { - .recalc_rate = &omap3_dpll_recalc, - .get_parent = &omap2_init_dpll_parent, -}; - -static struct clk_hw_omap dpll_core_ck_hw = { - .hw = { - .clk = &dpll_core_ck, - }, - .dpll_data = &dpll_core_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_core_ck, dpll_core_ck_parents, dpll_core_ck_ops); - -static const char *dpll_core_x2_ck_parents[] = { - "dpll_core_ck", -}; - -static struct clk dpll_core_x2_ck; - -static struct clk_hw_omap dpll_core_x2_ck_hw = { - .hw = { - .clk = &dpll_core_x2_ck, - }, -}; - -DEFINE_STRUCT_CLK(dpll_core_x2_ck, dpll_core_x2_ck_parents, dpll_abe_x2_ck_ops); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m6x2_ck, "dpll_core_x2_ck", - &dpll_core_x2_ck, 0x0, OMAP4430_CM_DIV_M6_DPLL_CORE, - OMAP4430_HSDIVIDER_CLKOUT3_DIV_MASK); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m2_ck, "dpll_core_ck", &dpll_core_ck, 0x0, - OMAP4430_CM_DIV_M2_DPLL_CORE, - OMAP4430_DPLL_CLKOUT_DIV_MASK); - -DEFINE_CLK_FIXED_FACTOR(ddrphy_ck, "dpll_core_m2_ck", &dpll_core_m2_ck, 0x0, 1, - 2); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m5x2_ck, "dpll_core_x2_ck", - &dpll_core_x2_ck, 0x0, OMAP4430_CM_DIV_M5_DPLL_CORE, - OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK); - -DEFINE_CLK_DIVIDER(div_core_ck, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck, 0x0, - OMAP4430_CM_CLKSEL_CORE, OMAP4430_CLKSEL_CORE_SHIFT, - OMAP4430_CLKSEL_CORE_WIDTH, 0x0, NULL); - -DEFINE_CLK_DIVIDER(div_iva_hs_clk, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck, - 0x0, OMAP4430_CM_BYPCLK_DPLL_IVA, OMAP4430_CLKSEL_0_1_SHIFT, - OMAP4430_CLKSEL_0_1_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL); - -DEFINE_CLK_DIVIDER(div_mpu_hs_clk, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck, - 0x0, OMAP4430_CM_BYPCLK_DPLL_MPU, OMAP4430_CLKSEL_0_1_SHIFT, - OMAP4430_CLKSEL_0_1_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m4x2_ck, "dpll_core_x2_ck", - &dpll_core_x2_ck, 0x0, OMAP4430_CM_DIV_M4_DPLL_CORE, - OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK); - -DEFINE_CLK_FIXED_FACTOR(dll_clk_div_ck, "dpll_core_m4x2_ck", &dpll_core_m4x2_ck, - 0x0, 1, 2); - -DEFINE_CLK_DIVIDER(dpll_abe_m2_ck, "dpll_abe_ck", &dpll_abe_ck, 0x0, - OMAP4430_CM_DIV_M2_DPLL_ABE, OMAP4430_DPLL_CLKOUT_DIV_SHIFT, - OMAP4430_DPLL_CLKOUT_DIV_WIDTH, CLK_DIVIDER_ONE_BASED, NULL); - -static const struct clk_ops dpll_hsd_ops = { - .enable = &omap2_dflt_clk_enable, - .disable = &omap2_dflt_clk_disable, - .is_enabled = &omap2_dflt_clk_is_enabled, - .recalc_rate = &omap2_clksel_recalc, - .get_parent = &omap2_clksel_find_parent_index, - .set_parent = &omap2_clksel_set_parent, - .init = &omap2_init_clk_clkdm, -}; - -static const struct clk_ops func_dmic_abe_gfclk_ops = { - .recalc_rate = &omap2_clksel_recalc, - .get_parent = &omap2_clksel_find_parent_index, - .set_parent = &omap2_clksel_set_parent, -}; - -static const char *dpll_core_m3x2_ck_parents[] = { - "dpll_core_x2_ck", -}; - -static const struct clksel dpll_core_m3x2_div[] = { - { .parent = &dpll_core_x2_ck, .rates = div31_1to31_rates }, - { .parent = NULL }, -}; - -/* XXX Missing round_rate, set_rate in ops */ -DEFINE_CLK_OMAP_MUX_GATE(dpll_core_m3x2_ck, NULL, dpll_core_m3x2_div, - OMAP4430_CM_DIV_M3_DPLL_CORE, - OMAP4430_DPLL_CLKOUTHIF_DIV_MASK, - OMAP4430_CM_DIV_M3_DPLL_CORE, - OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT, NULL, - dpll_core_m3x2_ck_parents, dpll_hsd_ops); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m7x2_ck, "dpll_core_x2_ck", - &dpll_core_x2_ck, 0x0, OMAP4430_CM_DIV_M7_DPLL_CORE, - OMAP4430_HSDIVIDER_CLKOUT4_DIV_MASK); - -static const char *iva_hsd_byp_clk_mux_ck_parents[] = { - "sys_clkin_ck", "div_iva_hs_clk", -}; - -DEFINE_CLK_MUX(iva_hsd_byp_clk_mux_ck, iva_hsd_byp_clk_mux_ck_parents, NULL, - 0x0, OMAP4430_CM_CLKSEL_DPLL_IVA, OMAP4430_DPLL_BYP_CLKSEL_SHIFT, - OMAP4430_DPLL_BYP_CLKSEL_WIDTH, 0x0, NULL); - -/* DPLL_IVA */ -static struct dpll_data dpll_iva_dd = { - .mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_IVA, - .clk_bypass = &iva_hsd_byp_clk_mux_ck, - .clk_ref = &sys_clkin_ck, - .control_reg = OMAP4430_CM_CLKMODE_DPLL_IVA, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_IVA, - .idlest_reg = OMAP4430_CM_IDLEST_DPLL_IVA, - .mult_mask = OMAP4430_DPLL_MULT_MASK, - .div1_mask = OMAP4430_DPLL_DIV_MASK, - .enable_mask = OMAP4430_DPLL_EN_MASK, - .autoidle_mask = OMAP4430_AUTO_DPLL_MODE_MASK, - .idlest_mask = OMAP4430_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - -static const char *dpll_iva_ck_parents[] = { - "sys_clkin_ck", "iva_hsd_byp_clk_mux_ck" -}; - -static struct clk dpll_iva_ck; - -static const struct clk_ops dpll_ck_ops = { - .enable = &omap3_noncore_dpll_enable, - .disable = &omap3_noncore_dpll_disable, - .recalc_rate = &omap3_dpll_recalc, - .round_rate = &omap2_dpll_round_rate, - .set_rate = &omap3_noncore_dpll_set_rate, - .get_parent = &omap2_init_dpll_parent, -}; - -static struct clk_hw_omap dpll_iva_ck_hw = { - .hw = { - .clk = &dpll_iva_ck, - }, - .dpll_data = &dpll_iva_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_iva_ck, dpll_iva_ck_parents, dpll_ck_ops); - -static const char *dpll_iva_x2_ck_parents[] = { - "dpll_iva_ck", -}; - -static struct clk dpll_iva_x2_ck; - -static struct clk_hw_omap dpll_iva_x2_ck_hw = { - .hw = { - .clk = &dpll_iva_x2_ck, - }, -}; - -DEFINE_STRUCT_CLK(dpll_iva_x2_ck, dpll_iva_x2_ck_parents, dpll_abe_x2_ck_ops); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_iva_m4x2_ck, "dpll_iva_x2_ck", &dpll_iva_x2_ck, - 0x0, OMAP4430_CM_DIV_M4_DPLL_IVA, - OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_iva_m5x2_ck, "dpll_iva_x2_ck", &dpll_iva_x2_ck, - 0x0, OMAP4430_CM_DIV_M5_DPLL_IVA, - OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK); - -/* DPLL_MPU */ -static struct dpll_data dpll_mpu_dd = { - .mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_MPU, - .clk_bypass = &div_mpu_hs_clk, - .clk_ref = &sys_clkin_ck, - .control_reg = OMAP4430_CM_CLKMODE_DPLL_MPU, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_MPU, - .idlest_reg = OMAP4430_CM_IDLEST_DPLL_MPU, - .mult_mask = OMAP4430_DPLL_MULT_MASK, - .div1_mask = OMAP4430_DPLL_DIV_MASK, - .enable_mask = OMAP4430_DPLL_EN_MASK, - .autoidle_mask = OMAP4430_AUTO_DPLL_MODE_MASK, - .idlest_mask = OMAP4430_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - -static const char *dpll_mpu_ck_parents[] = { - "sys_clkin_ck", "div_mpu_hs_clk" -}; - -static struct clk dpll_mpu_ck; - -static struct clk_hw_omap dpll_mpu_ck_hw = { - .hw = { - .clk = &dpll_mpu_ck, - }, - .dpll_data = &dpll_mpu_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_mpu_ck, dpll_mpu_ck_parents, dpll_ck_ops); - -DEFINE_CLK_FIXED_FACTOR(mpu_periphclk, "dpll_mpu_ck", &dpll_mpu_ck, 0x0, 1, 2); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_mpu_m2_ck, "dpll_mpu_ck", &dpll_mpu_ck, 0x0, - OMAP4430_CM_DIV_M2_DPLL_MPU, - OMAP4430_DPLL_CLKOUT_DIV_MASK); - -DEFINE_CLK_FIXED_FACTOR(per_hs_clk_div_ck, "dpll_abe_m3x2_ck", - &dpll_abe_m3x2_ck, 0x0, 1, 2); - -static const char *per_hsd_byp_clk_mux_ck_parents[] = { - "sys_clkin_ck", "per_hs_clk_div_ck", -}; - -DEFINE_CLK_MUX(per_hsd_byp_clk_mux_ck, per_hsd_byp_clk_mux_ck_parents, NULL, - 0x0, OMAP4430_CM_CLKSEL_DPLL_PER, OMAP4430_DPLL_BYP_CLKSEL_SHIFT, - OMAP4430_DPLL_BYP_CLKSEL_WIDTH, 0x0, NULL); - -/* DPLL_PER */ -static struct dpll_data dpll_per_dd = { - .mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_PER, - .clk_bypass = &per_hsd_byp_clk_mux_ck, - .clk_ref = &sys_clkin_ck, - .control_reg = OMAP4430_CM_CLKMODE_DPLL_PER, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_PER, - .idlest_reg = OMAP4430_CM_IDLEST_DPLL_PER, - .mult_mask = OMAP4430_DPLL_MULT_MASK, - .div1_mask = OMAP4430_DPLL_DIV_MASK, - .enable_mask = OMAP4430_DPLL_EN_MASK, - .autoidle_mask = OMAP4430_AUTO_DPLL_MODE_MASK, - .idlest_mask = OMAP4430_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - -static const char *dpll_per_ck_parents[] = { - "sys_clkin_ck", "per_hsd_byp_clk_mux_ck" -}; - -static struct clk dpll_per_ck; - -static struct clk_hw_omap dpll_per_ck_hw = { - .hw = { - .clk = &dpll_per_ck, - }, - .dpll_data = &dpll_per_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_per_ck, dpll_per_ck_parents, dpll_ck_ops); - -DEFINE_CLK_DIVIDER(dpll_per_m2_ck, "dpll_per_ck", &dpll_per_ck, 0x0, - OMAP4430_CM_DIV_M2_DPLL_PER, OMAP4430_DPLL_CLKOUT_DIV_SHIFT, - OMAP4430_DPLL_CLKOUT_DIV_WIDTH, CLK_DIVIDER_ONE_BASED, NULL); - -static const char *dpll_per_x2_ck_parents[] = { - "dpll_per_ck", -}; - -static struct clk dpll_per_x2_ck; - -static struct clk_hw_omap dpll_per_x2_ck_hw = { - .hw = { - .clk = &dpll_per_x2_ck, - }, - .flags = CLOCK_CLKOUTX2, - .clksel_reg = OMAP4430_CM_DIV_M2_DPLL_PER, - .ops = &clkhwops_omap4_dpllmx, -}; - -DEFINE_STRUCT_CLK(dpll_per_x2_ck, dpll_per_x2_ck_parents, dpll_abe_x2_ck_ops); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m2x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck, - 0x0, OMAP4430_CM_DIV_M2_DPLL_PER, - OMAP4430_DPLL_CLKOUT_DIV_MASK); - -static const char *dpll_per_m3x2_ck_parents[] = { - "dpll_per_x2_ck", -}; - -static const struct clksel dpll_per_m3x2_div[] = { - { .parent = &dpll_per_x2_ck, .rates = div31_1to31_rates }, - { .parent = NULL }, -}; - -/* XXX Missing round_rate, set_rate in ops */ -DEFINE_CLK_OMAP_MUX_GATE(dpll_per_m3x2_ck, NULL, dpll_per_m3x2_div, - OMAP4430_CM_DIV_M3_DPLL_PER, - OMAP4430_DPLL_CLKOUTHIF_DIV_MASK, - OMAP4430_CM_DIV_M3_DPLL_PER, - OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT, NULL, - dpll_per_m3x2_ck_parents, dpll_hsd_ops); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m4x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck, - 0x0, OMAP4430_CM_DIV_M4_DPLL_PER, - OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m5x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck, - 0x0, OMAP4430_CM_DIV_M5_DPLL_PER, - OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m6x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck, - 0x0, OMAP4430_CM_DIV_M6_DPLL_PER, - OMAP4430_HSDIVIDER_CLKOUT3_DIV_MASK); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m7x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck, - 0x0, OMAP4430_CM_DIV_M7_DPLL_PER, - OMAP4430_HSDIVIDER_CLKOUT4_DIV_MASK); - -DEFINE_CLK_FIXED_FACTOR(usb_hs_clk_div_ck, "dpll_abe_m3x2_ck", - &dpll_abe_m3x2_ck, 0x0, 1, 3); - -/* DPLL_USB */ -static struct dpll_data dpll_usb_dd = { - .mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_USB, - .clk_bypass = &usb_hs_clk_div_ck, - .flags = DPLL_J_TYPE, - .clk_ref = &sys_clkin_ck, - .control_reg = OMAP4430_CM_CLKMODE_DPLL_USB, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_USB, - .idlest_reg = OMAP4430_CM_IDLEST_DPLL_USB, - .mult_mask = OMAP4430_DPLL_MULT_USB_MASK, - .div1_mask = OMAP4430_DPLL_DIV_0_7_MASK, - .enable_mask = OMAP4430_DPLL_EN_MASK, - .autoidle_mask = OMAP4430_AUTO_DPLL_MODE_MASK, - .idlest_mask = OMAP4430_ST_DPLL_CLK_MASK, - .sddiv_mask = OMAP4430_DPLL_SD_DIV_MASK, - .max_multiplier = 4095, - .max_divider = 256, - .min_divider = 1, -}; - -static const char *dpll_usb_ck_parents[] = { - "sys_clkin_ck", "usb_hs_clk_div_ck" -}; - -static struct clk dpll_usb_ck; - -static const struct clk_ops dpll_usb_ck_ops = { - .enable = &omap3_noncore_dpll_enable, - .disable = &omap3_noncore_dpll_disable, - .recalc_rate = &omap3_dpll_recalc, - .round_rate = &omap2_dpll_round_rate, - .set_rate = &omap3_noncore_dpll_set_rate, - .get_parent = &omap2_init_dpll_parent, - .init = &omap2_init_clk_clkdm, -}; - -static struct clk_hw_omap dpll_usb_ck_hw = { - .hw = { - .clk = &dpll_usb_ck, - }, - .dpll_data = &dpll_usb_dd, - .clkdm_name = "l3_init_clkdm", - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_usb_ck, dpll_usb_ck_parents, dpll_usb_ck_ops); - -static const char *dpll_usb_clkdcoldo_ck_parents[] = { - "dpll_usb_ck", -}; - -static struct clk dpll_usb_clkdcoldo_ck; - -static const struct clk_ops dpll_usb_clkdcoldo_ck_ops = { -}; - -static struct clk_hw_omap dpll_usb_clkdcoldo_ck_hw = { - .hw = { - .clk = &dpll_usb_clkdcoldo_ck, - }, - .clksel_reg = OMAP4430_CM_CLKDCOLDO_DPLL_USB, - .ops = &clkhwops_omap4_dpllmx, -}; - -DEFINE_STRUCT_CLK(dpll_usb_clkdcoldo_ck, dpll_usb_clkdcoldo_ck_parents, - dpll_usb_clkdcoldo_ck_ops); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_usb_m2_ck, "dpll_usb_ck", &dpll_usb_ck, 0x0, - OMAP4430_CM_DIV_M2_DPLL_USB, - OMAP4430_DPLL_CLKOUT_DIV_0_6_MASK); - -static const char *ducati_clk_mux_ck_parents[] = { - "div_core_ck", "dpll_per_m6x2_ck", -}; - -DEFINE_CLK_MUX(ducati_clk_mux_ck, ducati_clk_mux_ck_parents, NULL, 0x0, - OMAP4430_CM_CLKSEL_DUCATI_ISS_ROOT, OMAP4430_CLKSEL_0_0_SHIFT, - OMAP4430_CLKSEL_0_0_WIDTH, 0x0, NULL); - -DEFINE_CLK_FIXED_FACTOR(func_12m_fclk, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, - 0x0, 1, 16); - -DEFINE_CLK_FIXED_FACTOR(func_24m_clk, "dpll_per_m2_ck", &dpll_per_m2_ck, 0x0, - 1, 4); - -DEFINE_CLK_FIXED_FACTOR(func_24mc_fclk, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, - 0x0, 1, 8); - -static const struct clk_div_table func_48m_fclk_rates[] = { - { .div = 4, .val = 0 }, - { .div = 8, .val = 1 }, - { .div = 0 }, -}; -DEFINE_CLK_DIVIDER_TABLE(func_48m_fclk, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, - 0x0, OMAP4430_CM_SCALE_FCLK, OMAP4430_SCALE_FCLK_SHIFT, - OMAP4430_SCALE_FCLK_WIDTH, 0x0, func_48m_fclk_rates, - NULL); - -DEFINE_CLK_FIXED_FACTOR(func_48mc_fclk, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, - 0x0, 1, 4); - -static const struct clk_div_table func_64m_fclk_rates[] = { - { .div = 2, .val = 0 }, - { .div = 4, .val = 1 }, - { .div = 0 }, -}; -DEFINE_CLK_DIVIDER_TABLE(func_64m_fclk, "dpll_per_m4x2_ck", &dpll_per_m4x2_ck, - 0x0, OMAP4430_CM_SCALE_FCLK, OMAP4430_SCALE_FCLK_SHIFT, - OMAP4430_SCALE_FCLK_WIDTH, 0x0, func_64m_fclk_rates, - NULL); - -static const struct clk_div_table func_96m_fclk_rates[] = { - { .div = 2, .val = 0 }, - { .div = 4, .val = 1 }, - { .div = 0 }, -}; -DEFINE_CLK_DIVIDER_TABLE(func_96m_fclk, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, - 0x0, OMAP4430_CM_SCALE_FCLK, OMAP4430_SCALE_FCLK_SHIFT, - OMAP4430_SCALE_FCLK_WIDTH, 0x0, func_96m_fclk_rates, - NULL); - -static const struct clk_div_table init_60m_fclk_rates[] = { - { .div = 1, .val = 0 }, - { .div = 8, .val = 1 }, - { .div = 0 }, -}; -DEFINE_CLK_DIVIDER_TABLE(init_60m_fclk, "dpll_usb_m2_ck", &dpll_usb_m2_ck, - 0x0, OMAP4430_CM_CLKSEL_USB_60MHZ, - OMAP4430_CLKSEL_0_0_SHIFT, OMAP4430_CLKSEL_0_0_WIDTH, - 0x0, init_60m_fclk_rates, NULL); - -DEFINE_CLK_DIVIDER(l3_div_ck, "div_core_ck", &div_core_ck, 0x0, - OMAP4430_CM_CLKSEL_CORE, OMAP4430_CLKSEL_L3_SHIFT, - OMAP4430_CLKSEL_L3_WIDTH, 0x0, NULL); - -DEFINE_CLK_DIVIDER(l4_div_ck, "l3_div_ck", &l3_div_ck, 0x0, - OMAP4430_CM_CLKSEL_CORE, OMAP4430_CLKSEL_L4_SHIFT, - OMAP4430_CLKSEL_L4_WIDTH, 0x0, NULL); - -DEFINE_CLK_FIXED_FACTOR(lp_clk_div_ck, "dpll_abe_m2x2_ck", &dpll_abe_m2x2_ck, - 0x0, 1, 16); - -static const char *l4_wkup_clk_mux_ck_parents[] = { - "sys_clkin_ck", "lp_clk_div_ck", -}; - -DEFINE_CLK_MUX(l4_wkup_clk_mux_ck, l4_wkup_clk_mux_ck_parents, NULL, 0x0, - OMAP4430_CM_L4_WKUP_CLKSEL, OMAP4430_CLKSEL_0_0_SHIFT, - OMAP4430_CLKSEL_0_0_WIDTH, 0x0, NULL); - -static const struct clk_div_table ocp_abe_iclk_rates[] = { - { .div = 2, .val = 0 }, - { .div = 1, .val = 1 }, - { .div = 0 }, -}; -DEFINE_CLK_DIVIDER_TABLE(ocp_abe_iclk, "aess_fclk", &aess_fclk, 0x0, - OMAP4430_CM1_ABE_AESS_CLKCTRL, - OMAP4430_CLKSEL_AESS_FCLK_SHIFT, - OMAP4430_CLKSEL_AESS_FCLK_WIDTH, - 0x0, ocp_abe_iclk_rates, NULL); - -DEFINE_CLK_FIXED_FACTOR(per_abe_24m_fclk, "dpll_abe_m2_ck", &dpll_abe_m2_ck, - 0x0, 1, 4); - -DEFINE_CLK_DIVIDER(per_abe_nc_fclk, "dpll_abe_m2_ck", &dpll_abe_m2_ck, 0x0, - OMAP4430_CM_SCALE_FCLK, OMAP4430_SCALE_FCLK_SHIFT, - OMAP4430_SCALE_FCLK_WIDTH, 0x0, NULL); - -DEFINE_CLK_DIVIDER(syc_clk_div_ck, "sys_clkin_ck", &sys_clkin_ck, 0x0, - OMAP4430_CM_ABE_DSS_SYS_CLKSEL, OMAP4430_CLKSEL_0_0_SHIFT, - OMAP4430_CLKSEL_0_0_WIDTH, 0x0, NULL); - -static const char *dbgclk_mux_ck_parents[] = { - "sys_clkin_ck" -}; - -static struct clk dbgclk_mux_ck; -DEFINE_STRUCT_CLK_HW_OMAP(dbgclk_mux_ck, NULL); -DEFINE_STRUCT_CLK(dbgclk_mux_ck, dbgclk_mux_ck_parents, - dpll_usb_clkdcoldo_ck_ops); - -/* Leaf clocks controlled by modules */ - -DEFINE_CLK_GATE(aes1_fck, "l3_div_ck", &l3_div_ck, 0x0, - OMAP4430_CM_L4SEC_AES1_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(aes2_fck, "l3_div_ck", &l3_div_ck, 0x0, - OMAP4430_CM_L4SEC_AES2_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(bandgap_fclk, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_WKUP_BANDGAP_CLKCTRL, - OMAP4430_OPTFCLKEN_BGAP_32K_SHIFT, 0x0, NULL); - -static const struct clk_div_table div_ts_ck_rates[] = { - { .div = 8, .val = 0 }, - { .div = 16, .val = 1 }, - { .div = 32, .val = 2 }, - { .div = 0 }, -}; -DEFINE_CLK_DIVIDER_TABLE(div_ts_ck, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck, - 0x0, OMAP4430_CM_WKUP_BANDGAP_CLKCTRL, - OMAP4430_CLKSEL_24_25_SHIFT, - OMAP4430_CLKSEL_24_25_WIDTH, 0x0, div_ts_ck_rates, - NULL); - -DEFINE_CLK_GATE(bandgap_ts_fclk, "div_ts_ck", &div_ts_ck, 0x0, - OMAP4430_CM_WKUP_BANDGAP_CLKCTRL, - OMAP4460_OPTFCLKEN_TS_FCLK_SHIFT, - 0x0, NULL); - -static const char *dmic_sync_mux_ck_parents[] = { - "abe_24m_fclk", "syc_clk_div_ck", "func_24m_clk", -}; - -DEFINE_CLK_MUX(dmic_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, - 0x0, OMAP4430_CM1_ABE_DMIC_CLKCTRL, - OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT, - OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL); - -static const struct clksel func_dmic_abe_gfclk_sel[] = { - { .parent = &dmic_sync_mux_ck, .rates = div_1_0_rates }, - { .parent = &pad_clks_ck, .rates = div_1_1_rates }, - { .parent = &slimbus_clk, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static const char *func_dmic_abe_gfclk_parents[] = { - "dmic_sync_mux_ck", "pad_clks_ck", "slimbus_clk", -}; - -DEFINE_CLK_OMAP_MUX(func_dmic_abe_gfclk, "abe_clkdm", func_dmic_abe_gfclk_sel, - OMAP4430_CM1_ABE_DMIC_CLKCTRL, OMAP4430_CLKSEL_SOURCE_MASK, - func_dmic_abe_gfclk_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_GATE(dss_sys_clk, "syc_clk_div_ck", &syc_clk_div_ck, 0x0, - OMAP4430_CM_DSS_DSS_CLKCTRL, - OMAP4430_OPTFCLKEN_SYS_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(dss_tv_clk, "extalt_clkin_ck", &extalt_clkin_ck, 0x0, - OMAP4430_CM_DSS_DSS_CLKCTRL, - OMAP4430_OPTFCLKEN_TV_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(dss_dss_clk, "dpll_per_m5x2_ck", &dpll_per_m5x2_ck, - CLK_SET_RATE_PARENT, - OMAP4430_CM_DSS_DSS_CLKCTRL, OMAP4430_OPTFCLKEN_DSSCLK_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(dss_48mhz_clk, "func_48mc_fclk", &func_48mc_fclk, 0x0, - OMAP4430_CM_DSS_DSS_CLKCTRL, OMAP4430_OPTFCLKEN_48MHZ_CLK_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(dss_fck, "l3_div_ck", &l3_div_ck, 0x0, - OMAP4430_CM_DSS_DSS_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, - 0x0, NULL); - -DEFINE_CLK_DIVIDER(fdif_fck, "dpll_per_m4x2_ck", &dpll_per_m4x2_ck, 0x0, - OMAP4430_CM_CAM_FDIF_CLKCTRL, OMAP4430_CLKSEL_FCLK_SHIFT, - OMAP4430_CLKSEL_FCLK_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL); - -DEFINE_CLK_GATE(gpio1_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_WKUP_GPIO1_CLKCTRL, - OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(gpio2_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_L4PER_GPIO2_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(gpio3_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_L4PER_GPIO3_CLKCTRL, - OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(gpio4_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_L4PER_GPIO4_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(gpio5_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_L4PER_GPIO5_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(gpio6_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_L4PER_GPIO6_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, - 0x0, NULL); - -static const struct clksel sgx_clk_mux_sel[] = { - { .parent = &dpll_core_m7x2_ck, .rates = div_1_0_rates }, - { .parent = &dpll_per_m7x2_ck, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -static const char *sgx_clk_mux_parents[] = { - "dpll_core_m7x2_ck", "dpll_per_m7x2_ck", -}; - -DEFINE_CLK_OMAP_MUX(sgx_clk_mux, "l3_gfx_clkdm", sgx_clk_mux_sel, - OMAP4430_CM_GFX_GFX_CLKCTRL, OMAP4430_CLKSEL_SGX_FCLK_MASK, - sgx_clk_mux_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_DIVIDER(hsi_fck, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, 0x0, - OMAP4430_CM_L3INIT_HSI_CLKCTRL, OMAP4430_CLKSEL_24_25_SHIFT, - OMAP4430_CLKSEL_24_25_WIDTH, CLK_DIVIDER_POWER_OF_TWO, - NULL); - -DEFINE_CLK_GATE(iss_ctrlclk, "func_96m_fclk", &func_96m_fclk, 0x0, - OMAP4430_CM_CAM_ISS_CLKCTRL, OMAP4430_OPTFCLKEN_CTRLCLK_SHIFT, - 0x0, NULL); - -DEFINE_CLK_MUX(mcasp_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0, - OMAP4430_CM1_ABE_MCASP_CLKCTRL, - OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT, - OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL); - -static const struct clksel func_mcasp_abe_gfclk_sel[] = { - { .parent = &mcasp_sync_mux_ck, .rates = div_1_0_rates }, - { .parent = &pad_clks_ck, .rates = div_1_1_rates }, - { .parent = &slimbus_clk, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static const char *func_mcasp_abe_gfclk_parents[] = { - "mcasp_sync_mux_ck", "pad_clks_ck", "slimbus_clk", -}; - -DEFINE_CLK_OMAP_MUX(func_mcasp_abe_gfclk, "abe_clkdm", func_mcasp_abe_gfclk_sel, - OMAP4430_CM1_ABE_MCASP_CLKCTRL, OMAP4430_CLKSEL_SOURCE_MASK, - func_mcasp_abe_gfclk_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_MUX(mcbsp1_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0, - OMAP4430_CM1_ABE_MCBSP1_CLKCTRL, - OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT, - OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL); - -static const struct clksel func_mcbsp1_gfclk_sel[] = { - { .parent = &mcbsp1_sync_mux_ck, .rates = div_1_0_rates }, - { .parent = &pad_clks_ck, .rates = div_1_1_rates }, - { .parent = &slimbus_clk, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static const char *func_mcbsp1_gfclk_parents[] = { - "mcbsp1_sync_mux_ck", "pad_clks_ck", "slimbus_clk", -}; - -DEFINE_CLK_OMAP_MUX(func_mcbsp1_gfclk, "abe_clkdm", func_mcbsp1_gfclk_sel, - OMAP4430_CM1_ABE_MCBSP1_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp1_gfclk_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_MUX(mcbsp2_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0, - OMAP4430_CM1_ABE_MCBSP2_CLKCTRL, - OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT, - OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL); - -static const struct clksel func_mcbsp2_gfclk_sel[] = { - { .parent = &mcbsp2_sync_mux_ck, .rates = div_1_0_rates }, - { .parent = &pad_clks_ck, .rates = div_1_1_rates }, - { .parent = &slimbus_clk, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static const char *func_mcbsp2_gfclk_parents[] = { - "mcbsp2_sync_mux_ck", "pad_clks_ck", "slimbus_clk", -}; - -DEFINE_CLK_OMAP_MUX(func_mcbsp2_gfclk, "abe_clkdm", func_mcbsp2_gfclk_sel, - OMAP4430_CM1_ABE_MCBSP2_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp2_gfclk_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_MUX(mcbsp3_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0, - OMAP4430_CM1_ABE_MCBSP3_CLKCTRL, - OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT, - OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL); - -static const struct clksel func_mcbsp3_gfclk_sel[] = { - { .parent = &mcbsp3_sync_mux_ck, .rates = div_1_0_rates }, - { .parent = &pad_clks_ck, .rates = div_1_1_rates }, - { .parent = &slimbus_clk, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static const char *func_mcbsp3_gfclk_parents[] = { - "mcbsp3_sync_mux_ck", "pad_clks_ck", "slimbus_clk", -}; - -DEFINE_CLK_OMAP_MUX(func_mcbsp3_gfclk, "abe_clkdm", func_mcbsp3_gfclk_sel, - OMAP4430_CM1_ABE_MCBSP3_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp3_gfclk_parents, - func_dmic_abe_gfclk_ops); - -static const char *mcbsp4_sync_mux_ck_parents[] = { - "func_96m_fclk", "per_abe_nc_fclk", -}; - -DEFINE_CLK_MUX(mcbsp4_sync_mux_ck, mcbsp4_sync_mux_ck_parents, NULL, 0x0, - OMAP4430_CM_L4PER_MCBSP4_CLKCTRL, - OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT, - OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL); - -static const struct clksel per_mcbsp4_gfclk_sel[] = { - { .parent = &mcbsp4_sync_mux_ck, .rates = div_1_0_rates }, - { .parent = &pad_clks_ck, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -static const char *per_mcbsp4_gfclk_parents[] = { - "mcbsp4_sync_mux_ck", "pad_clks_ck", -}; - -DEFINE_CLK_OMAP_MUX(per_mcbsp4_gfclk, "l4_per_clkdm", per_mcbsp4_gfclk_sel, - OMAP4430_CM_L4PER_MCBSP4_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_24_24_MASK, per_mcbsp4_gfclk_parents, - func_dmic_abe_gfclk_ops); - -static const struct clksel hsmmc1_fclk_sel[] = { - { .parent = &func_64m_fclk, .rates = div_1_0_rates }, - { .parent = &func_96m_fclk, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -static const char *hsmmc1_fclk_parents[] = { - "func_64m_fclk", "func_96m_fclk", -}; - -DEFINE_CLK_OMAP_MUX(hsmmc1_fclk, "l3_init_clkdm", hsmmc1_fclk_sel, - OMAP4430_CM_L3INIT_MMC1_CLKCTRL, OMAP4430_CLKSEL_MASK, - hsmmc1_fclk_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(hsmmc2_fclk, "l3_init_clkdm", hsmmc1_fclk_sel, - OMAP4430_CM_L3INIT_MMC2_CLKCTRL, OMAP4430_CLKSEL_MASK, - hsmmc1_fclk_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_GATE(ocp2scp_usb_phy_phy_48m, "func_48m_fclk", &func_48m_fclk, 0x0, - OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL, - OMAP4430_OPTFCLKEN_PHY_48M_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(sha2md5_fck, "l3_div_ck", &l3_div_ck, 0x0, - OMAP4430_CM_L4SEC_SHA2MD51_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(slimbus1_fclk_1, "func_24m_clk", &func_24m_clk, 0x0, - OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, - OMAP4430_OPTFCLKEN_FCLK1_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(slimbus1_fclk_0, "abe_24m_fclk", &abe_24m_fclk, 0x0, - OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, - OMAP4430_OPTFCLKEN_FCLK0_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(slimbus1_fclk_2, "pad_clks_ck", &pad_clks_ck, 0x0, - OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, - OMAP4430_OPTFCLKEN_FCLK2_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(slimbus1_slimbus_clk, "slimbus_clk", &slimbus_clk, 0x0, - OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, - OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(slimbus2_fclk_1, "per_abe_24m_fclk", &per_abe_24m_fclk, 0x0, - OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL, - OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(slimbus2_fclk_0, "func_24mc_fclk", &func_24mc_fclk, 0x0, - OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL, - OMAP4430_OPTFCLKEN_PER24MC_GFCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(slimbus2_slimbus_clk, "pad_slimbus_core_clks_ck", - &pad_slimbus_core_clks_ck, 0x0, - OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL, - OMAP4430_OPTFCLKEN_SLIMBUS_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(smartreflex_core_fck, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck, - 0x0, OMAP4430_CM_ALWON_SR_CORE_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(smartreflex_iva_fck, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck, - 0x0, OMAP4430_CM_ALWON_SR_IVA_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(smartreflex_mpu_fck, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck, - 0x0, OMAP4430_CM_ALWON_SR_MPU_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -static const struct clksel dmt1_clk_mux_sel[] = { - { .parent = &sys_clkin_ck, .rates = div_1_0_rates }, - { .parent = &sys_32k_ck, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -DEFINE_CLK_OMAP_MUX(dmt1_clk_mux, "l4_wkup_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_WKUP_TIMER1_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(cm2_dm10_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(cm2_dm11_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(cm2_dm2_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(cm2_dm3_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(cm2_dm4_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -static const struct clksel timer5_sync_mux_sel[] = { - { .parent = &syc_clk_div_ck, .rates = div_1_0_rates }, - { .parent = &sys_32k_ck, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -static const char *timer5_sync_mux_parents[] = { - "syc_clk_div_ck", "sys_32k_ck", -}; - -DEFINE_CLK_OMAP_MUX(timer5_sync_mux, "abe_clkdm", timer5_sync_mux_sel, - OMAP4430_CM1_ABE_TIMER5_CLKCTRL, OMAP4430_CLKSEL_MASK, - timer5_sync_mux_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(timer6_sync_mux, "abe_clkdm", timer5_sync_mux_sel, - OMAP4430_CM1_ABE_TIMER6_CLKCTRL, OMAP4430_CLKSEL_MASK, - timer5_sync_mux_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(timer7_sync_mux, "abe_clkdm", timer5_sync_mux_sel, - OMAP4430_CM1_ABE_TIMER7_CLKCTRL, OMAP4430_CLKSEL_MASK, - timer5_sync_mux_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(timer8_sync_mux, "abe_clkdm", timer5_sync_mux_sel, - OMAP4430_CM1_ABE_TIMER8_CLKCTRL, OMAP4430_CLKSEL_MASK, - timer5_sync_mux_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(cm2_dm9_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -static struct clk usb_host_fs_fck; - -static const char *usb_host_fs_fck_parent_names[] = { - "func_48mc_fclk", -}; - -static const struct clk_ops usb_host_fs_fck_ops = { - .enable = &omap2_dflt_clk_enable, - .disable = &omap2_dflt_clk_disable, - .is_enabled = &omap2_dflt_clk_is_enabled, -}; - -static struct clk_hw_omap usb_host_fs_fck_hw = { - .hw = { - .clk = &usb_host_fs_fck, - }, - .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_FS_CLKCTRL, - .enable_bit = OMAP4430_MODULEMODE_SWCTRL_SHIFT, - .clkdm_name = "l3_init_clkdm", -}; - -DEFINE_STRUCT_CLK(usb_host_fs_fck, usb_host_fs_fck_parent_names, - usb_host_fs_fck_ops); - -static const char *utmi_p1_gfclk_parents[] = { - "init_60m_fclk", "xclk60mhsp1_ck", -}; - -DEFINE_CLK_MUX(utmi_p1_gfclk, utmi_p1_gfclk_parents, NULL, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_CLKSEL_UTMI_P1_SHIFT, OMAP4430_CLKSEL_UTMI_P1_WIDTH, - 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_utmi_p1_clk, "utmi_p1_gfclk", &utmi_p1_gfclk, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_OPTFCLKEN_UTMI_P1_CLK_SHIFT, 0x0, NULL); - -static const char *utmi_p2_gfclk_parents[] = { - "init_60m_fclk", "xclk60mhsp2_ck", -}; - -DEFINE_CLK_MUX(utmi_p2_gfclk, utmi_p2_gfclk_parents, NULL, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_CLKSEL_UTMI_P2_SHIFT, OMAP4430_CLKSEL_UTMI_P2_WIDTH, - 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_utmi_p2_clk, "utmi_p2_gfclk", &utmi_p2_gfclk, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_OPTFCLKEN_UTMI_P2_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_utmi_p3_clk, "init_60m_fclk", &init_60m_fclk, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_OPTFCLKEN_UTMI_P3_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_hsic480m_p1_clk, "dpll_usb_m2_ck", - &dpll_usb_m2_ck, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_hsic60m_p1_clk, "init_60m_fclk", - &init_60m_fclk, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_hsic60m_p2_clk, "init_60m_fclk", - &init_60m_fclk, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_hsic480m_p2_clk, "dpll_usb_m2_ck", - &dpll_usb_m2_ck, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_func48mclk, "func_48mc_fclk", &func_48mc_fclk, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_OPTFCLKEN_FUNC48MCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_fck, "init_60m_fclk", &init_60m_fclk, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -static const char *otg_60m_gfclk_parents[] = { - "utmi_phy_clkout_ck", "xclk60motg_ck", -}; - -DEFINE_CLK_MUX(otg_60m_gfclk, otg_60m_gfclk_parents, NULL, 0x0, - OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL, OMAP4430_CLKSEL_60M_SHIFT, - OMAP4430_CLKSEL_60M_WIDTH, 0x0, NULL); - -DEFINE_CLK_GATE(usb_otg_hs_xclk, "otg_60m_gfclk", &otg_60m_gfclk, 0x0, - OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL, - OMAP4430_OPTFCLKEN_XCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_otg_hs_ick, "l3_div_ck", &l3_div_ck, 0x0, - OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL, - OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_phy_cm_clk32k, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_ALWON_USBPHY_CLKCTRL, - OMAP4430_OPTFCLKEN_CLK32K_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_tll_hs_usb_ch2_clk, "init_60m_fclk", &init_60m_fclk, 0x0, - OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL, - OMAP4430_OPTFCLKEN_USB_CH2_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_tll_hs_usb_ch0_clk, "init_60m_fclk", &init_60m_fclk, 0x0, - OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL, - OMAP4430_OPTFCLKEN_USB_CH0_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_tll_hs_usb_ch1_clk, "init_60m_fclk", &init_60m_fclk, 0x0, - OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL, - OMAP4430_OPTFCLKEN_USB_CH1_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_tll_hs_ick, "l4_div_ck", &l4_div_ck, 0x0, - OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL, - OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); - -static const struct clk_div_table usim_ck_rates[] = { - { .div = 14, .val = 0 }, - { .div = 18, .val = 1 }, - { .div = 0 }, -}; -DEFINE_CLK_DIVIDER_TABLE(usim_ck, "dpll_per_m4x2_ck", &dpll_per_m4x2_ck, 0x0, - OMAP4430_CM_WKUP_USIM_CLKCTRL, - OMAP4430_CLKSEL_DIV_SHIFT, OMAP4430_CLKSEL_DIV_WIDTH, - 0x0, usim_ck_rates, NULL); - -DEFINE_CLK_GATE(usim_fclk, "usim_ck", &usim_ck, 0x0, - OMAP4430_CM_WKUP_USIM_CLKCTRL, OMAP4430_OPTFCLKEN_FCLK_SHIFT, - 0x0, NULL); - -/* Remaining optional clocks */ -static const char *pmd_stm_clock_mux_ck_parents[] = { - "sys_clkin_ck", "dpll_core_m6x2_ck", "tie_low_clock_ck", -}; - -DEFINE_CLK_MUX(pmd_stm_clock_mux_ck, pmd_stm_clock_mux_ck_parents, NULL, 0x0, - OMAP4430_CM_EMU_DEBUGSS_CLKCTRL, OMAP4430_PMD_STM_MUX_CTRL_SHIFT, - OMAP4430_PMD_STM_MUX_CTRL_WIDTH, 0x0, NULL); - -DEFINE_CLK_MUX(pmd_trace_clk_mux_ck, pmd_stm_clock_mux_ck_parents, NULL, 0x0, - OMAP4430_CM_EMU_DEBUGSS_CLKCTRL, - OMAP4430_PMD_TRACE_MUX_CTRL_SHIFT, - OMAP4430_PMD_TRACE_MUX_CTRL_WIDTH, 0x0, NULL); - -DEFINE_CLK_DIVIDER(stm_clk_div_ck, "pmd_stm_clock_mux_ck", - &pmd_stm_clock_mux_ck, 0x0, OMAP4430_CM_EMU_DEBUGSS_CLKCTRL, - OMAP4430_CLKSEL_PMD_STM_CLK_SHIFT, - OMAP4430_CLKSEL_PMD_STM_CLK_WIDTH, CLK_DIVIDER_POWER_OF_TWO, - NULL); - -static const char *trace_clk_div_ck_parents[] = { - "pmd_trace_clk_mux_ck", -}; - -static const struct clksel trace_clk_div_div[] = { - { .parent = &pmd_trace_clk_mux_ck, .rates = div3_1to4_rates }, - { .parent = NULL }, -}; - -static struct clk trace_clk_div_ck; - -static const struct clk_ops trace_clk_div_ck_ops = { - .recalc_rate = &omap2_clksel_recalc, - .set_rate = &omap2_clksel_set_rate, - .round_rate = &omap2_clksel_round_rate, - .init = &omap2_init_clk_clkdm, - .enable = &omap2_clkops_enable_clkdm, - .disable = &omap2_clkops_disable_clkdm, -}; - -static struct clk_hw_omap trace_clk_div_ck_hw = { - .hw = { - .clk = &trace_clk_div_ck, - }, - .clkdm_name = "emu_sys_clkdm", - .clksel = trace_clk_div_div, - .clksel_reg = OMAP4430_CM_EMU_DEBUGSS_CLKCTRL, - .clksel_mask = OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK, -}; - -DEFINE_STRUCT_CLK(trace_clk_div_ck, trace_clk_div_ck_parents, - trace_clk_div_ck_ops); - -/* SCRM aux clk nodes */ - -static const struct clksel auxclk_src_sel[] = { - { .parent = &sys_clkin_ck, .rates = div_1_0_rates }, - { .parent = &dpll_core_m3x2_ck, .rates = div_1_1_rates }, - { .parent = &dpll_per_m3x2_ck, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static const char *auxclk_src_ck_parents[] = { - "sys_clkin_ck", "dpll_core_m3x2_ck", "dpll_per_m3x2_ck", -}; - -static const struct clk_ops auxclk_src_ck_ops = { - .enable = &omap2_dflt_clk_enable, - .disable = &omap2_dflt_clk_disable, - .is_enabled = &omap2_dflt_clk_is_enabled, - .recalc_rate = &omap2_clksel_recalc, - .get_parent = &omap2_clksel_find_parent_index, -}; - -DEFINE_CLK_OMAP_MUX_GATE(auxclk0_src_ck, NULL, auxclk_src_sel, - OMAP4_SCRM_AUXCLK0, OMAP4_SRCSELECT_MASK, - OMAP4_SCRM_AUXCLK0, OMAP4_ENABLE_SHIFT, NULL, - auxclk_src_ck_parents, auxclk_src_ck_ops); - -DEFINE_CLK_DIVIDER(auxclk0_ck, "auxclk0_src_ck", &auxclk0_src_ck, 0x0, - OMAP4_SCRM_AUXCLK0, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH, - 0x0, NULL); - -DEFINE_CLK_OMAP_MUX_GATE(auxclk1_src_ck, NULL, auxclk_src_sel, - OMAP4_SCRM_AUXCLK1, OMAP4_SRCSELECT_MASK, - OMAP4_SCRM_AUXCLK1, OMAP4_ENABLE_SHIFT, NULL, - auxclk_src_ck_parents, auxclk_src_ck_ops); - -DEFINE_CLK_DIVIDER(auxclk1_ck, "auxclk1_src_ck", &auxclk1_src_ck, 0x0, - OMAP4_SCRM_AUXCLK1, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH, - 0x0, NULL); - -DEFINE_CLK_OMAP_MUX_GATE(auxclk2_src_ck, NULL, auxclk_src_sel, - OMAP4_SCRM_AUXCLK2, OMAP4_SRCSELECT_MASK, - OMAP4_SCRM_AUXCLK2, OMAP4_ENABLE_SHIFT, NULL, - auxclk_src_ck_parents, auxclk_src_ck_ops); - -DEFINE_CLK_DIVIDER(auxclk2_ck, "auxclk2_src_ck", &auxclk2_src_ck, 0x0, - OMAP4_SCRM_AUXCLK2, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH, - 0x0, NULL); - -DEFINE_CLK_OMAP_MUX_GATE(auxclk3_src_ck, NULL, auxclk_src_sel, - OMAP4_SCRM_AUXCLK3, OMAP4_SRCSELECT_MASK, - OMAP4_SCRM_AUXCLK3, OMAP4_ENABLE_SHIFT, NULL, - auxclk_src_ck_parents, auxclk_src_ck_ops); - -DEFINE_CLK_DIVIDER(auxclk3_ck, "auxclk3_src_ck", &auxclk3_src_ck, 0x0, - OMAP4_SCRM_AUXCLK3, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH, - 0x0, NULL); - -DEFINE_CLK_OMAP_MUX_GATE(auxclk4_src_ck, NULL, auxclk_src_sel, - OMAP4_SCRM_AUXCLK4, OMAP4_SRCSELECT_MASK, - OMAP4_SCRM_AUXCLK4, OMAP4_ENABLE_SHIFT, NULL, - auxclk_src_ck_parents, auxclk_src_ck_ops); - -DEFINE_CLK_DIVIDER(auxclk4_ck, "auxclk4_src_ck", &auxclk4_src_ck, 0x0, - OMAP4_SCRM_AUXCLK4, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH, - 0x0, NULL); - -DEFINE_CLK_OMAP_MUX_GATE(auxclk5_src_ck, NULL, auxclk_src_sel, - OMAP4_SCRM_AUXCLK5, OMAP4_SRCSELECT_MASK, - OMAP4_SCRM_AUXCLK5, OMAP4_ENABLE_SHIFT, NULL, - auxclk_src_ck_parents, auxclk_src_ck_ops); - -DEFINE_CLK_DIVIDER(auxclk5_ck, "auxclk5_src_ck", &auxclk5_src_ck, 0x0, - OMAP4_SCRM_AUXCLK5, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH, - 0x0, NULL); - -static const char *auxclkreq_ck_parents[] = { - "auxclk0_ck", "auxclk1_ck", "auxclk2_ck", "auxclk3_ck", "auxclk4_ck", - "auxclk5_ck", -}; - -DEFINE_CLK_MUX(auxclkreq0_ck, auxclkreq_ck_parents, NULL, 0x0, - OMAP4_SCRM_AUXCLKREQ0, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH, - 0x0, NULL); - -DEFINE_CLK_MUX(auxclkreq1_ck, auxclkreq_ck_parents, NULL, 0x0, - OMAP4_SCRM_AUXCLKREQ1, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH, - 0x0, NULL); - -DEFINE_CLK_MUX(auxclkreq2_ck, auxclkreq_ck_parents, NULL, 0x0, - OMAP4_SCRM_AUXCLKREQ2, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH, - 0x0, NULL); - -DEFINE_CLK_MUX(auxclkreq3_ck, auxclkreq_ck_parents, NULL, 0x0, - OMAP4_SCRM_AUXCLKREQ3, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH, - 0x0, NULL); - -DEFINE_CLK_MUX(auxclkreq4_ck, auxclkreq_ck_parents, NULL, 0x0, - OMAP4_SCRM_AUXCLKREQ4, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH, - 0x0, NULL); - -DEFINE_CLK_MUX(auxclkreq5_ck, auxclkreq_ck_parents, NULL, 0x0, - OMAP4_SCRM_AUXCLKREQ5, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH, - 0x0, NULL); - -/* - * clocks specific to omap4460 - */ -static struct omap_clk omap446x_clks[] = { - CLK(NULL, "div_ts_ck", &div_ts_ck), - CLK(NULL, "bandgap_ts_fclk", &bandgap_ts_fclk), -}; - -/* - * clocks specific to omap4430 - */ -static struct omap_clk omap443x_clks[] = { - CLK(NULL, "bandgap_fclk", &bandgap_fclk), -}; - -/* - * clocks common to omap44xx - */ -static struct omap_clk omap44xx_clks[] = { - CLK(NULL, "extalt_clkin_ck", &extalt_clkin_ck), - CLK(NULL, "pad_clks_src_ck", &pad_clks_src_ck), - CLK(NULL, "pad_clks_ck", &pad_clks_ck), - CLK(NULL, "pad_slimbus_core_clks_ck", &pad_slimbus_core_clks_ck), - CLK(NULL, "secure_32k_clk_src_ck", &secure_32k_clk_src_ck), - CLK(NULL, "slimbus_src_clk", &slimbus_src_clk), - CLK(NULL, "slimbus_clk", &slimbus_clk), - CLK(NULL, "sys_32k_ck", &sys_32k_ck), - CLK(NULL, "virt_12000000_ck", &virt_12000000_ck), - CLK(NULL, "virt_13000000_ck", &virt_13000000_ck), - CLK(NULL, "virt_16800000_ck", &virt_16800000_ck), - CLK(NULL, "virt_19200000_ck", &virt_19200000_ck), - CLK(NULL, "virt_26000000_ck", &virt_26000000_ck), - CLK(NULL, "virt_27000000_ck", &virt_27000000_ck), - CLK(NULL, "virt_38400000_ck", &virt_38400000_ck), - CLK(NULL, "sys_clkin_ck", &sys_clkin_ck), - CLK(NULL, "tie_low_clock_ck", &tie_low_clock_ck), - CLK(NULL, "utmi_phy_clkout_ck", &utmi_phy_clkout_ck), - CLK(NULL, "xclk60mhsp1_ck", &xclk60mhsp1_ck), - CLK(NULL, "xclk60mhsp2_ck", &xclk60mhsp2_ck), - CLK(NULL, "xclk60motg_ck", &xclk60motg_ck), - CLK(NULL, "abe_dpll_bypass_clk_mux_ck", &abe_dpll_bypass_clk_mux_ck), - CLK(NULL, "abe_dpll_refclk_mux_ck", &abe_dpll_refclk_mux_ck), - CLK(NULL, "dpll_abe_ck", &dpll_abe_ck), - CLK(NULL, "dpll_abe_x2_ck", &dpll_abe_x2_ck), - CLK(NULL, "dpll_abe_m2x2_ck", &dpll_abe_m2x2_ck), - CLK(NULL, "abe_24m_fclk", &abe_24m_fclk), - CLK(NULL, "abe_clk", &abe_clk), - CLK(NULL, "aess_fclk", &aess_fclk), - CLK(NULL, "dpll_abe_m3x2_ck", &dpll_abe_m3x2_ck), - CLK(NULL, "core_hsd_byp_clk_mux_ck", &core_hsd_byp_clk_mux_ck), - CLK(NULL, "dpll_core_ck", &dpll_core_ck), - CLK(NULL, "dpll_core_x2_ck", &dpll_core_x2_ck), - CLK(NULL, "dpll_core_m6x2_ck", &dpll_core_m6x2_ck), - CLK(NULL, "dbgclk_mux_ck", &dbgclk_mux_ck), - CLK(NULL, "dpll_core_m2_ck", &dpll_core_m2_ck), - CLK(NULL, "ddrphy_ck", &ddrphy_ck), - CLK(NULL, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck), - CLK(NULL, "div_core_ck", &div_core_ck), - CLK(NULL, "div_iva_hs_clk", &div_iva_hs_clk), - CLK(NULL, "div_mpu_hs_clk", &div_mpu_hs_clk), - CLK(NULL, "dpll_core_m4x2_ck", &dpll_core_m4x2_ck), - CLK(NULL, "dll_clk_div_ck", &dll_clk_div_ck), - CLK(NULL, "dpll_abe_m2_ck", &dpll_abe_m2_ck), - CLK(NULL, "dpll_core_m3x2_ck", &dpll_core_m3x2_ck), - CLK(NULL, "dpll_core_m7x2_ck", &dpll_core_m7x2_ck), - CLK(NULL, "iva_hsd_byp_clk_mux_ck", &iva_hsd_byp_clk_mux_ck), - CLK(NULL, "dpll_iva_ck", &dpll_iva_ck), - CLK(NULL, "dpll_iva_x2_ck", &dpll_iva_x2_ck), - CLK(NULL, "dpll_iva_m4x2_ck", &dpll_iva_m4x2_ck), - CLK(NULL, "dpll_iva_m5x2_ck", &dpll_iva_m5x2_ck), - CLK(NULL, "dpll_mpu_ck", &dpll_mpu_ck), - CLK(NULL, "dpll_mpu_m2_ck", &dpll_mpu_m2_ck), - CLK(NULL, "per_hs_clk_div_ck", &per_hs_clk_div_ck), - CLK(NULL, "per_hsd_byp_clk_mux_ck", &per_hsd_byp_clk_mux_ck), - CLK(NULL, "dpll_per_ck", &dpll_per_ck), - CLK(NULL, "dpll_per_m2_ck", &dpll_per_m2_ck), - CLK(NULL, "dpll_per_x2_ck", &dpll_per_x2_ck), - CLK(NULL, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck), - CLK(NULL, "dpll_per_m3x2_ck", &dpll_per_m3x2_ck), - CLK(NULL, "dpll_per_m4x2_ck", &dpll_per_m4x2_ck), - CLK(NULL, "dpll_per_m5x2_ck", &dpll_per_m5x2_ck), - CLK(NULL, "dpll_per_m6x2_ck", &dpll_per_m6x2_ck), - CLK(NULL, "dpll_per_m7x2_ck", &dpll_per_m7x2_ck), - CLK(NULL, "usb_hs_clk_div_ck", &usb_hs_clk_div_ck), - CLK(NULL, "dpll_usb_ck", &dpll_usb_ck), - CLK(NULL, "dpll_usb_clkdcoldo_ck", &dpll_usb_clkdcoldo_ck), - CLK(NULL, "dpll_usb_m2_ck", &dpll_usb_m2_ck), - CLK(NULL, "ducati_clk_mux_ck", &ducati_clk_mux_ck), - CLK(NULL, "func_12m_fclk", &func_12m_fclk), - CLK(NULL, "func_24m_clk", &func_24m_clk), - CLK(NULL, "func_24mc_fclk", &func_24mc_fclk), - CLK(NULL, "func_48m_fclk", &func_48m_fclk), - CLK(NULL, "func_48mc_fclk", &func_48mc_fclk), - CLK(NULL, "func_64m_fclk", &func_64m_fclk), - CLK(NULL, "func_96m_fclk", &func_96m_fclk), - CLK(NULL, "init_60m_fclk", &init_60m_fclk), - CLK(NULL, "l3_div_ck", &l3_div_ck), - CLK(NULL, "l4_div_ck", &l4_div_ck), - CLK(NULL, "lp_clk_div_ck", &lp_clk_div_ck), - CLK(NULL, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck), - CLK("smp_twd", NULL, &mpu_periphclk), - CLK(NULL, "ocp_abe_iclk", &ocp_abe_iclk), - CLK(NULL, "per_abe_24m_fclk", &per_abe_24m_fclk), - CLK(NULL, "per_abe_nc_fclk", &per_abe_nc_fclk), - CLK(NULL, "syc_clk_div_ck", &syc_clk_div_ck), - CLK(NULL, "aes1_fck", &aes1_fck), - CLK(NULL, "aes2_fck", &aes2_fck), - CLK(NULL, "dmic_sync_mux_ck", &dmic_sync_mux_ck), - CLK(NULL, "func_dmic_abe_gfclk", &func_dmic_abe_gfclk), - CLK(NULL, "dss_sys_clk", &dss_sys_clk), - CLK(NULL, "dss_tv_clk", &dss_tv_clk), - CLK(NULL, "dss_dss_clk", &dss_dss_clk), - CLK(NULL, "dss_48mhz_clk", &dss_48mhz_clk), - CLK(NULL, "dss_fck", &dss_fck), - CLK("omapdss_dss", "ick", &dss_fck), - CLK(NULL, "fdif_fck", &fdif_fck), - CLK(NULL, "gpio1_dbclk", &gpio1_dbclk), - CLK(NULL, "gpio2_dbclk", &gpio2_dbclk), - CLK(NULL, "gpio3_dbclk", &gpio3_dbclk), - CLK(NULL, "gpio4_dbclk", &gpio4_dbclk), - CLK(NULL, "gpio5_dbclk", &gpio5_dbclk), - CLK(NULL, "gpio6_dbclk", &gpio6_dbclk), - CLK(NULL, "sgx_clk_mux", &sgx_clk_mux), - CLK(NULL, "hsi_fck", &hsi_fck), - CLK(NULL, "iss_ctrlclk", &iss_ctrlclk), - CLK(NULL, "mcasp_sync_mux_ck", &mcasp_sync_mux_ck), - CLK(NULL, "func_mcasp_abe_gfclk", &func_mcasp_abe_gfclk), - CLK(NULL, "mcbsp1_sync_mux_ck", &mcbsp1_sync_mux_ck), - CLK(NULL, "func_mcbsp1_gfclk", &func_mcbsp1_gfclk), - CLK(NULL, "mcbsp2_sync_mux_ck", &mcbsp2_sync_mux_ck), - CLK(NULL, "func_mcbsp2_gfclk", &func_mcbsp2_gfclk), - CLK(NULL, "mcbsp3_sync_mux_ck", &mcbsp3_sync_mux_ck), - CLK(NULL, "func_mcbsp3_gfclk", &func_mcbsp3_gfclk), - CLK(NULL, "mcbsp4_sync_mux_ck", &mcbsp4_sync_mux_ck), - CLK(NULL, "per_mcbsp4_gfclk", &per_mcbsp4_gfclk), - CLK(NULL, "hsmmc1_fclk", &hsmmc1_fclk), - CLK(NULL, "hsmmc2_fclk", &hsmmc2_fclk), - CLK(NULL, "ocp2scp_usb_phy_phy_48m", &ocp2scp_usb_phy_phy_48m), - CLK(NULL, "sha2md5_fck", &sha2md5_fck), - CLK(NULL, "slimbus1_fclk_1", &slimbus1_fclk_1), - CLK(NULL, "slimbus1_fclk_0", &slimbus1_fclk_0), - CLK(NULL, "slimbus1_fclk_2", &slimbus1_fclk_2), - CLK(NULL, "slimbus1_slimbus_clk", &slimbus1_slimbus_clk), - CLK(NULL, "slimbus2_fclk_1", &slimbus2_fclk_1), - CLK(NULL, "slimbus2_fclk_0", &slimbus2_fclk_0), - CLK(NULL, "slimbus2_slimbus_clk", &slimbus2_slimbus_clk), - CLK(NULL, "smartreflex_core_fck", &smartreflex_core_fck), - CLK(NULL, "smartreflex_iva_fck", &smartreflex_iva_fck), - CLK(NULL, "smartreflex_mpu_fck", &smartreflex_mpu_fck), - CLK(NULL, "dmt1_clk_mux", &dmt1_clk_mux), - CLK(NULL, "cm2_dm10_mux", &cm2_dm10_mux), - CLK(NULL, "cm2_dm11_mux", &cm2_dm11_mux), - CLK(NULL, "cm2_dm2_mux", &cm2_dm2_mux), - CLK(NULL, "cm2_dm3_mux", &cm2_dm3_mux), - CLK(NULL, "cm2_dm4_mux", &cm2_dm4_mux), - CLK(NULL, "timer5_sync_mux", &timer5_sync_mux), - CLK(NULL, "timer6_sync_mux", &timer6_sync_mux), - CLK(NULL, "timer7_sync_mux", &timer7_sync_mux), - CLK(NULL, "timer8_sync_mux", &timer8_sync_mux), - CLK(NULL, "cm2_dm9_mux", &cm2_dm9_mux), - CLK(NULL, "usb_host_fs_fck", &usb_host_fs_fck), - CLK("usbhs_omap", "fs_fck", &usb_host_fs_fck), - CLK(NULL, "utmi_p1_gfclk", &utmi_p1_gfclk), - CLK(NULL, "usb_host_hs_utmi_p1_clk", &usb_host_hs_utmi_p1_clk), - CLK(NULL, "utmi_p2_gfclk", &utmi_p2_gfclk), - CLK(NULL, "usb_host_hs_utmi_p2_clk", &usb_host_hs_utmi_p2_clk), - CLK(NULL, "usb_host_hs_utmi_p3_clk", &usb_host_hs_utmi_p3_clk), - CLK(NULL, "usb_host_hs_hsic480m_p1_clk", &usb_host_hs_hsic480m_p1_clk), - CLK(NULL, "usb_host_hs_hsic60m_p1_clk", &usb_host_hs_hsic60m_p1_clk), - CLK(NULL, "usb_host_hs_hsic60m_p2_clk", &usb_host_hs_hsic60m_p2_clk), - CLK(NULL, "usb_host_hs_hsic480m_p2_clk", &usb_host_hs_hsic480m_p2_clk), - CLK(NULL, "usb_host_hs_func48mclk", &usb_host_hs_func48mclk), - CLK(NULL, "usb_host_hs_fck", &usb_host_hs_fck), - CLK("usbhs_omap", "hs_fck", &usb_host_hs_fck), - CLK(NULL, "otg_60m_gfclk", &otg_60m_gfclk), - CLK(NULL, "usb_otg_hs_xclk", &usb_otg_hs_xclk), - CLK(NULL, "usb_otg_hs_ick", &usb_otg_hs_ick), - CLK("musb-omap2430", "ick", &usb_otg_hs_ick), - CLK(NULL, "usb_phy_cm_clk32k", &usb_phy_cm_clk32k), - CLK(NULL, "usb_tll_hs_usb_ch2_clk", &usb_tll_hs_usb_ch2_clk), - CLK(NULL, "usb_tll_hs_usb_ch0_clk", &usb_tll_hs_usb_ch0_clk), - CLK(NULL, "usb_tll_hs_usb_ch1_clk", &usb_tll_hs_usb_ch1_clk), - CLK(NULL, "usb_tll_hs_ick", &usb_tll_hs_ick), - CLK("usbhs_omap", "usbtll_ick", &usb_tll_hs_ick), - CLK("usbhs_tll", "usbtll_ick", &usb_tll_hs_ick), - CLK(NULL, "usim_ck", &usim_ck), - CLK(NULL, "usim_fclk", &usim_fclk), - CLK(NULL, "pmd_stm_clock_mux_ck", &pmd_stm_clock_mux_ck), - CLK(NULL, "pmd_trace_clk_mux_ck", &pmd_trace_clk_mux_ck), - CLK(NULL, "stm_clk_div_ck", &stm_clk_div_ck), - CLK(NULL, "trace_clk_div_ck", &trace_clk_div_ck), - CLK(NULL, "auxclk0_src_ck", &auxclk0_src_ck), - CLK(NULL, "auxclk0_ck", &auxclk0_ck), - CLK(NULL, "auxclkreq0_ck", &auxclkreq0_ck), - CLK(NULL, "auxclk1_src_ck", &auxclk1_src_ck), - CLK(NULL, "auxclk1_ck", &auxclk1_ck), - CLK(NULL, "auxclkreq1_ck", &auxclkreq1_ck), - CLK(NULL, "auxclk2_src_ck", &auxclk2_src_ck), - CLK(NULL, "auxclk2_ck", &auxclk2_ck), - CLK(NULL, "auxclkreq2_ck", &auxclkreq2_ck), - CLK(NULL, "auxclk3_src_ck", &auxclk3_src_ck), - CLK(NULL, "auxclk3_ck", &auxclk3_ck), - CLK(NULL, "auxclkreq3_ck", &auxclkreq3_ck), - CLK(NULL, "auxclk4_src_ck", &auxclk4_src_ck), - CLK(NULL, "auxclk4_ck", &auxclk4_ck), - CLK(NULL, "auxclkreq4_ck", &auxclkreq4_ck), - CLK(NULL, "auxclk5_src_ck", &auxclk5_src_ck), - CLK(NULL, "auxclk5_ck", &auxclk5_ck), - CLK(NULL, "auxclkreq5_ck", &auxclkreq5_ck), - CLK("50000000.gpmc", "fck", &dummy_ck), - CLK("omap_i2c.1", "ick", &dummy_ck), - CLK("omap_i2c.2", "ick", &dummy_ck), - CLK("omap_i2c.3", "ick", &dummy_ck), - CLK("omap_i2c.4", "ick", &dummy_ck), - CLK(NULL, "mailboxes_ick", &dummy_ck), - CLK("omap_hsmmc.0", "ick", &dummy_ck), - CLK("omap_hsmmc.1", "ick", &dummy_ck), - CLK("omap_hsmmc.2", "ick", &dummy_ck), - CLK("omap_hsmmc.3", "ick", &dummy_ck), - CLK("omap_hsmmc.4", "ick", &dummy_ck), - CLK("omap-mcbsp.1", "ick", &dummy_ck), - CLK("omap-mcbsp.2", "ick", &dummy_ck), - CLK("omap-mcbsp.3", "ick", &dummy_ck), - CLK("omap-mcbsp.4", "ick", &dummy_ck), - CLK("omap2_mcspi.1", "ick", &dummy_ck), - CLK("omap2_mcspi.2", "ick", &dummy_ck), - CLK("omap2_mcspi.3", "ick", &dummy_ck), - CLK("omap2_mcspi.4", "ick", &dummy_ck), - CLK(NULL, "uart1_ick", &dummy_ck), - CLK(NULL, "uart2_ick", &dummy_ck), - CLK(NULL, "uart3_ick", &dummy_ck), - CLK(NULL, "uart4_ick", &dummy_ck), - CLK("usbhs_omap", "usbhost_ick", &dummy_ck), - CLK("usbhs_omap", "usbtll_fck", &dummy_ck), - CLK("usbhs_tll", "usbtll_fck", &dummy_ck), - CLK("omap_wdt", "ick", &dummy_ck), - CLK(NULL, "timer_32k_ck", &sys_32k_ck), - /* TODO: Remove "omap_timer.X" aliases once DT migration is complete */ - CLK("omap_timer.1", "timer_sys_ck", &sys_clkin_ck), - CLK("omap_timer.2", "timer_sys_ck", &sys_clkin_ck), - CLK("omap_timer.3", "timer_sys_ck", &sys_clkin_ck), - CLK("omap_timer.4", "timer_sys_ck", &sys_clkin_ck), - CLK("omap_timer.9", "timer_sys_ck", &sys_clkin_ck), - CLK("omap_timer.10", "timer_sys_ck", &sys_clkin_ck), - CLK("omap_timer.11", "timer_sys_ck", &sys_clkin_ck), - CLK("omap_timer.5", "timer_sys_ck", &syc_clk_div_ck), - CLK("omap_timer.6", "timer_sys_ck", &syc_clk_div_ck), - CLK("omap_timer.7", "timer_sys_ck", &syc_clk_div_ck), - CLK("omap_timer.8", "timer_sys_ck", &syc_clk_div_ck), - CLK("4a318000.timer", "timer_sys_ck", &sys_clkin_ck), - CLK("48032000.timer", "timer_sys_ck", &sys_clkin_ck), - CLK("48034000.timer", "timer_sys_ck", &sys_clkin_ck), - CLK("48036000.timer", "timer_sys_ck", &sys_clkin_ck), - CLK("4803e000.timer", "timer_sys_ck", &sys_clkin_ck), - CLK("48086000.timer", "timer_sys_ck", &sys_clkin_ck), - CLK("48088000.timer", "timer_sys_ck", &sys_clkin_ck), - CLK("40138000.timer", "timer_sys_ck", &syc_clk_div_ck), - CLK("4013a000.timer", "timer_sys_ck", &syc_clk_div_ck), - CLK("4013c000.timer", "timer_sys_ck", &syc_clk_div_ck), - CLK("4013e000.timer", "timer_sys_ck", &syc_clk_div_ck), - CLK(NULL, "cpufreq_ck", &dpll_mpu_ck), -}; - -int __init omap4xxx_clk_init(void) -{ - int rc; - - if (cpu_is_omap443x()) { - cpu_mask = RATE_IN_4430; - omap_clocks_register(omap443x_clks, ARRAY_SIZE(omap443x_clks)); - } else if (cpu_is_omap446x() || cpu_is_omap447x()) { - cpu_mask = RATE_IN_4460 | RATE_IN_4430; - omap_clocks_register(omap446x_clks, ARRAY_SIZE(omap446x_clks)); - if (cpu_is_omap447x()) - pr_warn("WARNING: OMAP4470 clock data incomplete!\n"); - } else { - return 0; - } - - omap_clocks_register(omap44xx_clks, ARRAY_SIZE(omap44xx_clks)); - - omap2_clk_disable_autoidle_all(); - - /* - * A set rate of ABE DPLL inturn triggers a set rate of USB DPLL - * when its in bypass. So always lock USB before ABE DPLL. - */ - /* - * Lock USB DPLL on OMAP4 devices so that the L3INIT power - * domain can transition to retention state when not in use. - */ - rc = clk_set_rate(&dpll_usb_ck, OMAP4_DPLL_USB_DEFFREQ); - if (rc) - pr_err("%s: failed to configure USB DPLL!\n", __func__); - - /* - * On OMAP4460 the ABE DPLL fails to turn on if in idle low-power - * state when turning the ABE clock domain. Workaround this by - * locking the ABE DPLL on boot. - * Lock the ABE DPLL in any case to avoid issues with audio. - */ - rc = clk_set_parent(&abe_dpll_refclk_mux_ck, &sys_32k_ck); - if (!rc) - rc = clk_set_rate(&dpll_abe_ck, OMAP4_DPLL_ABE_DEFFREQ); - if (rc) - pr_err("%s: failed to configure ABE DPLL!\n", __func__); - - return 0; -} diff --git a/arch/arm/mach-omap2/clkt_clksel.c b/arch/arm/mach-omap2/clkt_clksel.c index 0ec9f6fdf0463b..7ee26108ac0d36 100644 --- a/arch/arm/mach-omap2/clkt_clksel.c +++ b/arch/arm/mach-omap2/clkt_clksel.c @@ -97,12 +97,12 @@ static void _write_clksel_reg(struct clk_hw_omap *clk, u32 field_val) { u32 v; - v = __raw_readl(clk->clksel_reg); + v = omap2_clk_readl(clk, clk->clksel_reg); v &= ~clk->clksel_mask; v |= field_val << __ffs(clk->clksel_mask); - __raw_writel(v, clk->clksel_reg); + omap2_clk_writel(v, clk, clk->clksel_reg); - v = __raw_readl(clk->clksel_reg); /* OCP barrier */ + v = omap2_clk_readl(clk, clk->clksel_reg); /* OCP barrier */ } /** @@ -204,7 +204,7 @@ static u32 _read_divisor(struct clk_hw_omap *clk) if (!clk->clksel || !clk->clksel_mask) return 0; - v = __raw_readl(clk->clksel_reg); + v = omap2_clk_readl(clk, clk->clksel_reg); v &= clk->clksel_mask; v >>= __ffs(clk->clksel_mask); @@ -320,7 +320,7 @@ u8 omap2_clksel_find_parent_index(struct clk_hw *hw) WARN((!clk->clksel || !clk->clksel_mask), "clock: %s: attempt to call on a non-clksel clock", clk_name); - r = __raw_readl(clk->clksel_reg) & clk->clksel_mask; + r = omap2_clk_readl(clk, clk->clksel_reg) & clk->clksel_mask; r >>= __ffs(clk->clksel_mask); for (clks = clk->clksel; clks->parent && !found; clks++) { diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c index 924c230f894844..47f9562ca7aa0f 100644 --- a/arch/arm/mach-omap2/clkt_dpll.c +++ b/arch/arm/mach-omap2/clkt_dpll.c @@ -196,7 +196,7 @@ u8 omap2_init_dpll_parent(struct clk_hw *hw) if (!dd) return -EINVAL; - v = __raw_readl(dd->control_reg); + v = omap2_clk_readl(clk, dd->control_reg); v &= dd->enable_mask; v >>= __ffs(dd->enable_mask); @@ -243,7 +243,7 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk) return 0; /* Return bypass rate if DPLL is bypassed */ - v = __raw_readl(dd->control_reg); + v = omap2_clk_readl(clk, dd->control_reg); v &= dd->enable_mask; v >>= __ffs(dd->enable_mask); @@ -262,7 +262,7 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk) return __clk_get_rate(dd->clk_bypass); } - v = __raw_readl(dd->mult_div1_reg); + v = omap2_clk_readl(clk, dd->mult_div1_reg); dpll_mult = v & dd->mult_mask; dpll_mult >>= __ffs(dd->mult_mask); dpll_div = v & dd->div1_mask; diff --git a/arch/arm/mach-omap2/clkt_iclk.c b/arch/arm/mach-omap2/clkt_iclk.c index f10eb03ce3e274..333f0a66617165 100644 --- a/arch/arm/mach-omap2/clkt_iclk.c +++ b/arch/arm/mach-omap2/clkt_iclk.c @@ -25,25 +25,29 @@ /* XXX */ void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk) { - u32 v, r; + u32 v; + void __iomem *r; - r = ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); + r = (__force void __iomem *) + ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); - v = __raw_readl((__force void __iomem *)r); + v = omap2_clk_readl(clk, r); v |= (1 << clk->enable_bit); - __raw_writel(v, (__force void __iomem *)r); + omap2_clk_writel(v, clk, r); } /* XXX */ void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk) { - u32 v, r; + u32 v; + void __iomem *r; - r = ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); + r = (__force void __iomem *) + ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); - v = __raw_readl((__force void __iomem *)r); + v = omap2_clk_readl(clk, r); v &= ~(1 << clk->enable_bit); - __raw_writel(v, (__force void __iomem *)r); + omap2_clk_writel(v, clk, r); } /* Public data */ diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index c7c5d31e908291..591581a665321c 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -26,7 +26,6 @@ #include #include - #include #include "soc.h" @@ -56,6 +55,31 @@ u16 cpu_mask; static bool clkdm_control = true; static LIST_HEAD(clk_hw_omap_clocks); +void __iomem *clk_memmaps[CLK_MAX_MEMMAPS]; + +void omap2_clk_writel(u32 val, struct clk_hw_omap *clk, void __iomem *reg) +{ + if (clk->flags & MEMMAP_ADDRESSING) { + struct clk_omap_reg *r = (struct clk_omap_reg *)® + writel_relaxed(val, clk_memmaps[r->index] + r->offset); + } else { + writel_relaxed(val, reg); + } +} + +u32 omap2_clk_readl(struct clk_hw_omap *clk, void __iomem *reg) +{ + u32 val; + + if (clk->flags & MEMMAP_ADDRESSING) { + struct clk_omap_reg *r = (struct clk_omap_reg *)® + val = readl_relaxed(clk_memmaps[r->index] + r->offset); + } else { + val = readl_relaxed(reg); + } + + return val; +} /* * Used for clocks that have the same value as the parent clock, @@ -87,6 +111,7 @@ unsigned long omap_fixed_divisor_recalc(struct clk_hw *hw, /** * _wait_idlest_generic - wait for a module to leave the idle state + * @clk: module clock to wait for (needed for register offsets) * @reg: virtual address of module IDLEST register * @mask: value to mask against to determine if the module is active * @idlest: idle state indicator (0 or 1) for the clock @@ -98,14 +123,14 @@ unsigned long omap_fixed_divisor_recalc(struct clk_hw *hw, * elapsed. XXX Deprecated - should be moved into drivers for the * individual IP block that the IDLEST register exists in. */ -static int _wait_idlest_generic(void __iomem *reg, u32 mask, u8 idlest, - const char *name) +static int _wait_idlest_generic(struct clk_hw_omap *clk, void __iomem *reg, + u32 mask, u8 idlest, const char *name) { int i = 0, ena = 0; ena = (idlest) ? 0 : mask; - omap_test_timeout(((__raw_readl(reg) & mask) == ena), + omap_test_timeout(((omap2_clk_readl(clk, reg) & mask) == ena), MAX_MODULE_ENABLE_WAIT, i); if (i < MAX_MODULE_ENABLE_WAIT) @@ -138,7 +163,7 @@ static void _omap2_module_wait_ready(struct clk_hw_omap *clk) /* Not all modules have multiple clocks that their IDLEST depends on */ if (clk->ops->find_companion) { clk->ops->find_companion(clk, &companion_reg, &other_bit); - if (!(__raw_readl(companion_reg) & (1 << other_bit))) + if (!(omap2_clk_readl(clk, companion_reg) & (1 << other_bit))) return; } @@ -146,8 +171,8 @@ static void _omap2_module_wait_ready(struct clk_hw_omap *clk) r = cm_split_idlest_reg(idlest_reg, &prcm_mod, &idlest_reg_id); if (r) { /* IDLEST register not in the CM module */ - _wait_idlest_generic(idlest_reg, (1 << idlest_bit), idlest_val, - __clk_get_name(clk->hw.clk)); + _wait_idlest_generic(clk, idlest_reg, (1 << idlest_bit), + idlest_val, __clk_get_name(clk->hw.clk)); } else { cm_wait_module_ready(prcm_mod, idlest_reg_id, idlest_bit); }; @@ -309,13 +334,13 @@ int omap2_dflt_clk_enable(struct clk_hw *hw) } /* FIXME should not have INVERT_ENABLE bit here */ - v = __raw_readl(clk->enable_reg); + v = omap2_clk_readl(clk, clk->enable_reg); if (clk->flags & INVERT_ENABLE) v &= ~(1 << clk->enable_bit); else v |= (1 << clk->enable_bit); - __raw_writel(v, clk->enable_reg); - v = __raw_readl(clk->enable_reg); /* OCP barrier */ + omap2_clk_writel(v, clk, clk->enable_reg); + v = omap2_clk_readl(clk, clk->enable_reg); /* OCP barrier */ if (clk->ops && clk->ops->find_idlest) _omap2_module_wait_ready(clk); @@ -353,12 +378,12 @@ void omap2_dflt_clk_disable(struct clk_hw *hw) return; } - v = __raw_readl(clk->enable_reg); + v = omap2_clk_readl(clk, clk->enable_reg); if (clk->flags & INVERT_ENABLE) v |= (1 << clk->enable_bit); else v &= ~(1 << clk->enable_bit); - __raw_writel(v, clk->enable_reg); + omap2_clk_writel(v, clk, clk->enable_reg); /* No OCP barrier needed here since it is a disable operation */ if (clkdm_control && clk->clkdm) @@ -454,7 +479,7 @@ int omap2_dflt_clk_is_enabled(struct clk_hw *hw) struct clk_hw_omap *clk = to_clk_hw_omap(hw); u32 v; - v = __raw_readl(clk->enable_reg); + v = omap2_clk_readl(clk, clk->enable_reg); if (clk->flags & INVERT_ENABLE) v ^= BIT(clk->enable_bit); @@ -520,6 +545,9 @@ int omap2_clk_enable_autoidle_all(void) list_for_each_entry(c, &clk_hw_omap_clocks, node) if (c->ops && c->ops->allow_idle) c->ops->allow_idle(c); + + of_ti_clk_allow_autoidle_all(); + return 0; } @@ -539,6 +567,9 @@ int omap2_clk_disable_autoidle_all(void) list_for_each_entry(c, &clk_hw_omap_clocks, node) if (c->ops && c->ops->deny_idle) c->ops->deny_idle(c); + + of_ti_clk_deny_autoidle_all(); + return 0; } diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 82916cc82c920d..bda767a9dea862 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -21,6 +21,7 @@ #include #include +#include struct omap_clk { u16 cpu; @@ -37,7 +38,6 @@ struct omap_clk { } struct clockdomain; -#define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw) #define DEFINE_STRUCT_CLK(_name, _parent_array_name, _clkops_name) \ static struct clk _name = { \ @@ -178,141 +178,6 @@ struct clksel { const struct clksel_rate *rates; }; -/** - * struct dpll_data - DPLL registers and integration data - * @mult_div1_reg: register containing the DPLL M and N bitfields - * @mult_mask: mask of the DPLL M bitfield in @mult_div1_reg - * @div1_mask: mask of the DPLL N bitfield in @mult_div1_reg - * @clk_bypass: struct clk pointer to the clock's bypass clock input - * @clk_ref: struct clk pointer to the clock's reference clock input - * @control_reg: register containing the DPLL mode bitfield - * @enable_mask: mask of the DPLL mode bitfield in @control_reg - * @last_rounded_rate: cache of the last rate result of omap2_dpll_round_rate() - * @last_rounded_m: cache of the last M result of omap2_dpll_round_rate() - * @last_rounded_m4xen: cache of the last M4X result of - * omap4_dpll_regm4xen_round_rate() - * @last_rounded_lpmode: cache of the last lpmode result of - * omap4_dpll_lpmode_recalc() - * @max_multiplier: maximum valid non-bypass multiplier value (actual) - * @last_rounded_n: cache of the last N result of omap2_dpll_round_rate() - * @min_divider: minimum valid non-bypass divider value (actual) - * @max_divider: maximum valid non-bypass divider value (actual) - * @modes: possible values of @enable_mask - * @autoidle_reg: register containing the DPLL autoidle mode bitfield - * @idlest_reg: register containing the DPLL idle status bitfield - * @autoidle_mask: mask of the DPLL autoidle mode bitfield in @autoidle_reg - * @freqsel_mask: mask of the DPLL jitter correction bitfield in @control_reg - * @idlest_mask: mask of the DPLL idle status bitfield in @idlest_reg - * @lpmode_mask: mask of the DPLL low-power mode bitfield in @control_reg - * @m4xen_mask: mask of the DPLL M4X multiplier bitfield in @control_reg - * @auto_recal_bit: bitshift of the driftguard enable bit in @control_reg - * @recal_en_bit: bitshift of the PRM_IRQENABLE_* bit for recalibration IRQs - * @recal_st_bit: bitshift of the PRM_IRQSTATUS_* bit for recalibration IRQs - * @flags: DPLL type/features (see below) - * - * Possible values for @flags: - * DPLL_J_TYPE: "J-type DPLL" (only some 36xx, 4xxx DPLLs) - * - * @freqsel_mask is only used on the OMAP34xx family and AM35xx. - * - * XXX Some DPLLs have multiple bypass inputs, so it's not technically - * correct to only have one @clk_bypass pointer. - * - * XXX The runtime-variable fields (@last_rounded_rate, @last_rounded_m, - * @last_rounded_n) should be separated from the runtime-fixed fields - * and placed into a different structure, so that the runtime-fixed data - * can be placed into read-only space. - */ -struct dpll_data { - void __iomem *mult_div1_reg; - u32 mult_mask; - u32 div1_mask; - struct clk *clk_bypass; - struct clk *clk_ref; - void __iomem *control_reg; - u32 enable_mask; - unsigned long last_rounded_rate; - u16 last_rounded_m; - u8 last_rounded_m4xen; - u8 last_rounded_lpmode; - u16 max_multiplier; - u8 last_rounded_n; - u8 min_divider; - u16 max_divider; - u8 modes; - void __iomem *autoidle_reg; - void __iomem *idlest_reg; - u32 autoidle_mask; - u32 freqsel_mask; - u32 idlest_mask; - u32 dco_mask; - u32 sddiv_mask; - u32 lpmode_mask; - u32 m4xen_mask; - u8 auto_recal_bit; - u8 recal_en_bit; - u8 recal_st_bit; - u8 flags; -}; - -/* - * struct clk.flags possibilities - * - * XXX document the rest of the clock flags here - * - * CLOCK_CLKOUTX2: (OMAP4 only) DPLL CLKOUT and CLKOUTX2 GATE_CTRL - * bits share the same register. This flag allows the - * omap4_dpllmx*() code to determine which GATE_CTRL bit field - * should be used. This is a temporary solution - a better approach - * would be to associate clock type-specific data with the clock, - * similar to the struct dpll_data approach. - */ -#define ENABLE_REG_32BIT (1 << 0) /* Use 32-bit access */ -#define CLOCK_IDLE_CONTROL (1 << 1) -#define CLOCK_NO_IDLE_PARENT (1 << 2) -#define ENABLE_ON_INIT (1 << 3) /* Enable upon framework init */ -#define INVERT_ENABLE (1 << 4) /* 0 enables, 1 disables */ -#define CLOCK_CLKOUTX2 (1 << 5) - -/** - * struct clk_hw_omap - OMAP struct clk - * @node: list_head connecting this clock into the full clock list - * @enable_reg: register to write to enable the clock (see @enable_bit) - * @enable_bit: bitshift to write to enable/disable the clock (see @enable_reg) - * @flags: see "struct clk.flags possibilities" above - * @clksel_reg: for clksel clks, register va containing src/divisor select - * @clksel_mask: bitmask in @clksel_reg for the src/divisor selector - * @clksel: for clksel clks, pointer to struct clksel for this clock - * @dpll_data: for DPLLs, pointer to struct dpll_data for this clock - * @clkdm_name: clockdomain name that this clock is contained in - * @clkdm: pointer to struct clockdomain, resolved from @clkdm_name at runtime - * @rate_offset: bitshift for rate selection bitfield (OMAP1 only) - * @src_offset: bitshift for source selection bitfield (OMAP1 only) - * - * XXX @rate_offset, @src_offset should probably be removed and OMAP1 - * clock code converted to use clksel. - * - */ - -struct clk_hw_omap_ops; - -struct clk_hw_omap { - struct clk_hw hw; - struct list_head node; - unsigned long fixed_rate; - u8 fixed_div; - void __iomem *enable_reg; - u8 enable_bit; - u8 flags; - void __iomem *clksel_reg; - u32 clksel_mask; - const struct clksel *clksel; - struct dpll_data *dpll_data; - const char *clkdm_name; - struct clockdomain *clkdm; - const struct clk_hw_omap_ops *ops; -}; - struct clk_hw_omap_ops { void (*find_idlest)(struct clk_hw_omap *oclk, void __iomem **idlest_reg, @@ -348,36 +213,13 @@ unsigned long omap_fixed_divisor_recalc(struct clk_hw *hw, #define OMAP4XXX_EN_DPLL_FRBYPASS 0x6 #define OMAP4XXX_EN_DPLL_LOCKED 0x7 -/* CM_CLKEN_PLL*.EN* bit values - not all are available for every DPLL */ -#define DPLL_LOW_POWER_STOP 0x1 -#define DPLL_LOW_POWER_BYPASS 0x5 -#define DPLL_LOCKED 0x7 - -/* DPLL Type and DCO Selection Flags */ -#define DPLL_J_TYPE 0x1 - -long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, - unsigned long *parent_rate); -unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); -int omap3_noncore_dpll_enable(struct clk_hw *hw); -void omap3_noncore_dpll_disable(struct clk_hw *hw); -int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate); u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk); void omap3_dpll_allow_idle(struct clk_hw_omap *clk); void omap3_dpll_deny_idle(struct clk_hw_omap *clk); -unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, - unsigned long parent_rate); int omap4_dpllmx_gatectrl_read(struct clk_hw_omap *clk); void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk); void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk); -unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, - unsigned long parent_rate); -long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, - unsigned long target_rate, - unsigned long *parent_rate); -void omap2_init_clk_clkdm(struct clk_hw *clk); void __init omap2_clk_disable_clkdm_control(void); /* clkt_clksel.c public functions */ @@ -396,29 +238,25 @@ int omap2_clksel_set_parent(struct clk_hw *hw, u8 field_val); extern void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk); extern void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk); -u8 omap2_init_dpll_parent(struct clk_hw *hw); unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk); -int omap2_dflt_clk_enable(struct clk_hw *hw); -void omap2_dflt_clk_disable(struct clk_hw *hw); -int omap2_dflt_clk_is_enabled(struct clk_hw *hw); void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, void __iomem **other_reg, u8 *other_bit); void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, void __iomem **idlest_reg, u8 *idlest_bit, u8 *idlest_val); -void omap2_init_clk_hw_omap_clocks(struct clk *clk); int omap2_clk_enable_autoidle_all(void); -int omap2_clk_disable_autoidle_all(void); int omap2_clk_allow_idle(struct clk *clk); int omap2_clk_deny_idle(struct clk *clk); -void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks); int omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name); void omap2_clk_print_new_rates(const char *hfclkin_ck_name, const char *core_ck_name, const char *mpu_ck_name); +u32 omap2_clk_readl(struct clk_hw_omap *clk, void __iomem *reg); +void omap2_clk_writel(u32 val, struct clk_hw_omap *clk, void __iomem *reg); + extern u16 cpu_mask; extern const struct clkops clkops_omap2_dflt_wait; @@ -433,19 +271,12 @@ extern const struct clksel_rate gfx_l3_rates[]; extern const struct clksel_rate dsp_ick_rates[]; extern struct clk dummy_ck; -extern const struct clk_hw_omap_ops clkhwops_omap3_dpll; extern const struct clk_hw_omap_ops clkhwops_iclk_wait; extern const struct clk_hw_omap_ops clkhwops_wait; -extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; -extern const struct clk_hw_omap_ops clkhwops_iclk; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_ssi_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_hsotgusb_wait; extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; -extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait; extern const struct clk_hw_omap_ops clkhwops_apll54; extern const struct clk_hw_omap_ops clkhwops_apll96; extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll; @@ -460,6 +291,8 @@ extern const struct clksel_rate div_1_3_rates[]; extern const struct clksel_rate div_1_4_rates[]; extern const struct clksel_rate div31_1to31_rates[]; +extern void __iomem *clk_memmaps[]; + extern int am33xx_clk_init(void); extern int omap2_clkops_enable_clkdm(struct clk_hw *hw); diff --git a/arch/arm/mach-omap2/clock36xx.c b/arch/arm/mach-omap2/clock36xx.c index bbd6a3f717e64e..91ccb962e09e9e 100644 --- a/arch/arm/mach-omap2/clock36xx.c +++ b/arch/arm/mach-omap2/clock36xx.c @@ -43,6 +43,7 @@ int omap36xx_pwrdn_clk_enable_with_hsdiv_restore(struct clk_hw *clk) struct clk_divider *parent; struct clk_hw *parent_hw; u32 dummy_v, orig_v; + struct clk_hw_omap *omap_clk = to_clk_hw_omap(clk); int ret; /* Clear PWRDN bit of HSDIVIDER */ @@ -53,15 +54,15 @@ int omap36xx_pwrdn_clk_enable_with_hsdiv_restore(struct clk_hw *clk) /* Restore the dividers */ if (!ret) { - orig_v = __raw_readl(parent->reg); + orig_v = omap2_clk_readl(omap_clk, parent->reg); dummy_v = orig_v; /* Write any other value different from the Read value */ dummy_v ^= (1 << parent->shift); - __raw_writel(dummy_v, parent->reg); + omap2_clk_writel(dummy_v, omap_clk, parent->reg); /* Write the original divider */ - __raw_writel(orig_v, parent->reg); + omap2_clk_writel(orig_v, omap_clk, parent->reg); } return ret; diff --git a/arch/arm/mach-omap2/clock3xxx.h b/arch/arm/mach-omap2/clock3xxx.h index 8cd4b0a882aec3..78d9f562e3ce79 100644 --- a/arch/arm/mach-omap2/clock3xxx.h +++ b/arch/arm/mach-omap2/clock3xxx.h @@ -9,11 +9,8 @@ #define __ARCH_ARM_MACH_OMAP2_CLOCK3XXX_H int omap3xxx_clk_init(void); -int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate, - unsigned long parent_rate); int omap3_core_dpll_m2_set_rate(struct clk_hw *clk, unsigned long rate, unsigned long parent_rate); -void omap3_clk_lock_dpll5(void); extern struct clk *sdrc_ick_p; extern struct clk *arm_fck_p; diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index 240db38f232c66..a6aae300542cd8 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -62,11 +62,17 @@ static inline int omap3_pm_init(void) #if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP4) int omap4_pm_init(void); +int omap4_pm_init_early(void); #else static inline int omap4_pm_init(void) { return 0; } + +static inline int omap4_pm_init_early(void) +{ + return 0; +} #endif #ifdef CONFIG_OMAP_MUX @@ -236,6 +242,7 @@ static inline void __iomem *omap4_get_scu_base(void) extern void __init gic_init_irq(void); extern void gic_dist_disable(void); +extern void gic_dist_enable(void); extern bool gic_dist_disabled(void); extern void gic_timer_retrigger(void); extern void omap_smc1(u32 fn, u32 arg); @@ -306,7 +313,7 @@ struct omap_hwmod; extern int omap_dss_reset(struct omap_hwmod *); /* SoC specific clock initializer */ -extern int (*omap_clk_init)(void); +int omap_clk_init(void); #endif /* __ASSEMBLER__ */ #endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */ diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index 4c8982ae95295f..4c158c838d4062 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -80,6 +80,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, int index) { struct idle_statedata *cx = state_ptr + index; + u32 mpuss_can_lose_context = 0; /* * CPU0 has to wait and stay ON until CPU1 is OFF state. @@ -104,6 +105,9 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, } } + mpuss_can_lose_context = (cx->mpu_state == PWRDM_POWER_RET) && + (cx->mpu_logic_state == PWRDM_POWER_OFF); + /* * Call idle CPU PM enter notifier chain so that * VFP and per CPU interrupt context is saved. @@ -118,9 +122,8 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, * Call idle CPU cluster PM enter notifier chain * to save GIC and wakeupgen context. */ - if ((cx->mpu_state == PWRDM_POWER_RET) && - (cx->mpu_logic_state == PWRDM_POWER_OFF)) - cpu_cluster_pm_enter(); + if (mpuss_can_lose_context) + cpu_cluster_pm_enter(); } omap4_enter_lowpower(dev->cpu, cx->cpu_state); @@ -128,9 +131,23 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, /* Wakeup CPU1 only if it is not offlined */ if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) { + + if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) && + mpuss_can_lose_context) + gic_dist_disable(); + clkdm_wakeup(cpu_clkdm[1]); omap_set_pwrdm_state(cpu_pd[1], PWRDM_POWER_ON); clkdm_allow_idle(cpu_clkdm[1]); + + if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) && + mpuss_can_lose_context) { + while (gic_dist_disabled()) { + udelay(1); + cpu_relax(); + } + gic_timer_retrigger(); + } } /* @@ -143,8 +160,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, * Call idle CPU cluster PM exit notifier chain * to restore GIC and wakeupgen context. */ - if (dev->cpu == 0 && (cx->mpu_state == PWRDM_POWER_RET) && - (cx->mpu_logic_state == PWRDM_POWER_OFF)) + if (dev->cpu == 0 && mpuss_can_lose_context) cpu_cluster_pm_exit(); fail: diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index 3a0296cfcace87..3185ced807c952 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c @@ -50,10 +50,10 @@ static void _omap3_dpll_write_clken(struct clk_hw_omap *clk, u8 clken_bits) dd = clk->dpll_data; - v = __raw_readl(dd->control_reg); + v = omap2_clk_readl(clk, dd->control_reg); v &= ~dd->enable_mask; v |= clken_bits << __ffs(dd->enable_mask); - __raw_writel(v, dd->control_reg); + omap2_clk_writel(v, clk, dd->control_reg); } /* _omap3_wait_dpll_status: wait for a DPLL to enter a specific state */ @@ -69,8 +69,8 @@ static int _omap3_wait_dpll_status(struct clk_hw_omap *clk, u8 state) state <<= __ffs(dd->idlest_mask); - while (((__raw_readl(dd->idlest_reg) & dd->idlest_mask) != state) && - i < MAX_DPLL_WAIT_TRIES) { + while (((omap2_clk_readl(clk, dd->idlest_reg) & dd->idlest_mask) + != state) && i < MAX_DPLL_WAIT_TRIES) { i++; udelay(1); } @@ -147,7 +147,7 @@ static int _omap3_noncore_dpll_lock(struct clk_hw_omap *clk) state <<= __ffs(dd->idlest_mask); /* Check if already locked */ - if ((__raw_readl(dd->idlest_reg) & dd->idlest_mask) == state) + if ((omap2_clk_readl(clk, dd->idlest_reg) & dd->idlest_mask) == state) goto done; ai = omap3_dpll_autoidle_read(clk); @@ -311,14 +311,14 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) * only since freqsel field is no longer present on other devices. */ if (cpu_is_omap343x()) { - v = __raw_readl(dd->control_reg); + v = omap2_clk_readl(clk, dd->control_reg); v &= ~dd->freqsel_mask; v |= freqsel << __ffs(dd->freqsel_mask); - __raw_writel(v, dd->control_reg); + omap2_clk_writel(v, clk, dd->control_reg); } /* Set DPLL multiplier, divider */ - v = __raw_readl(dd->mult_div1_reg); + v = omap2_clk_readl(clk, dd->mult_div1_reg); v &= ~(dd->mult_mask | dd->div1_mask); v |= dd->last_rounded_m << __ffs(dd->mult_mask); v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask); @@ -336,11 +336,11 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) v |= sd_div << __ffs(dd->sddiv_mask); } - __raw_writel(v, dd->mult_div1_reg); + omap2_clk_writel(v, clk, dd->mult_div1_reg); /* Set 4X multiplier and low-power mode */ if (dd->m4xen_mask || dd->lpmode_mask) { - v = __raw_readl(dd->control_reg); + v = omap2_clk_readl(clk, dd->control_reg); if (dd->m4xen_mask) { if (dd->last_rounded_m4xen) @@ -356,7 +356,7 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) v &= ~dd->lpmode_mask; } - __raw_writel(v, dd->control_reg); + omap2_clk_writel(v, clk, dd->control_reg); } /* We let the clock framework set the other output dividers later */ @@ -554,7 +554,7 @@ u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk) if (!dd->autoidle_reg) return -EINVAL; - v = __raw_readl(dd->autoidle_reg); + v = omap2_clk_readl(clk, dd->autoidle_reg); v &= dd->autoidle_mask; v >>= __ffs(dd->autoidle_mask); @@ -588,10 +588,10 @@ void omap3_dpll_allow_idle(struct clk_hw_omap *clk) * by writing 0x5 instead of 0x1. Add some mechanism to * optionally enter this mode. */ - v = __raw_readl(dd->autoidle_reg); + v = omap2_clk_readl(clk, dd->autoidle_reg); v &= ~dd->autoidle_mask; v |= DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask); - __raw_writel(v, dd->autoidle_reg); + omap2_clk_writel(v, clk, dd->autoidle_reg); } @@ -614,10 +614,10 @@ void omap3_dpll_deny_idle(struct clk_hw_omap *clk) if (!dd->autoidle_reg) return; - v = __raw_readl(dd->autoidle_reg); + v = omap2_clk_readl(clk, dd->autoidle_reg); v &= ~dd->autoidle_mask; v |= DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask); - __raw_writel(v, dd->autoidle_reg); + omap2_clk_writel(v, clk, dd->autoidle_reg); } @@ -639,6 +639,9 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, struct clk_hw_omap *pclk = NULL; struct clk *parent; + if (!parent_rate) + return 0; + /* Walk up the parents of clk, looking for a DPLL */ do { do { @@ -660,7 +663,7 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, WARN_ON(!dd->enable_mask); - v = __raw_readl(dd->control_reg) & dd->enable_mask; + v = omap2_clk_readl(pclk, dd->control_reg) & dd->enable_mask; v >>= __ffs(dd->enable_mask); if ((v != OMAP3XXX_EN_DPLL_LOCKED) || (dd->flags & DPLL_J_TYPE)) rate = parent_rate; diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c index d28b0f7267151d..52f9438b92f2a5 100644 --- a/arch/arm/mach-omap2/dpll44xx.c +++ b/arch/arm/mach-omap2/dpll44xx.c @@ -42,7 +42,7 @@ int omap4_dpllmx_gatectrl_read(struct clk_hw_omap *clk) OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK : OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK; - v = __raw_readl(clk->clksel_reg); + v = omap2_clk_readl(clk, clk->clksel_reg); v &= mask; v >>= __ffs(mask); @@ -61,10 +61,10 @@ void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk) OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK : OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK; - v = __raw_readl(clk->clksel_reg); + v = omap2_clk_readl(clk, clk->clksel_reg); /* Clear the bit to allow gatectrl */ v &= ~mask; - __raw_writel(v, clk->clksel_reg); + omap2_clk_writel(v, clk, clk->clksel_reg); } void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk) @@ -79,10 +79,10 @@ void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk) OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK : OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK; - v = __raw_readl(clk->clksel_reg); + v = omap2_clk_readl(clk, clk->clksel_reg); /* Set the bit to deny gatectrl */ v |= mask; - __raw_writel(v, clk->clksel_reg); + omap2_clk_writel(v, clk, clk->clksel_reg); } const struct clk_hw_omap_ops clkhwops_omap4_dpllmx = { @@ -140,7 +140,7 @@ unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, rate = omap2_get_dpll_rate(clk); /* regm4xen adds a multiplier of 4 to DPLL calculations */ - v = __raw_readl(dd->control_reg); + v = omap2_clk_readl(clk, dd->control_reg); if (v & OMAP4430_DPLL_REGM4XEN_MASK) rate *= OMAP4430_REGM4XEN_MULT; diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 07b68d5a7940e4..d408b15b4fbfd9 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -55,10 +55,10 @@ #include "prm44xx.h" /* - * omap_clk_init: points to a function that does the SoC-specific + * omap_clk_soc_init: points to a function that does the SoC-specific * clock initializations */ -int (*omap_clk_init)(void); +static int (*omap_clk_soc_init)(void); /* * The machine specific code may provide the extra mapping besides the @@ -419,7 +419,7 @@ void __init omap2420_init_early(void) omap242x_clockdomains_init(); omap2420_hwmod_init(); omap_hwmod_init_postsetup(); - omap_clk_init = omap2420_clk_init; + omap_clk_soc_init = omap2420_clk_init; } void __init omap2420_init_late(void) @@ -448,7 +448,7 @@ void __init omap2430_init_early(void) omap243x_clockdomains_init(); omap2430_hwmod_init(); omap_hwmod_init_postsetup(); - omap_clk_init = omap2430_clk_init; + omap_clk_soc_init = omap2430_clk_init; } void __init omap2430_init_late(void) @@ -482,27 +482,35 @@ void __init omap3_init_early(void) omap3xxx_clockdomains_init(); omap3xxx_hwmod_init(); omap_hwmod_init_postsetup(); - omap_clk_init = omap3xxx_clk_init; + omap_clk_soc_init = omap3xxx_clk_init; } void __init omap3430_init_early(void) { omap3_init_early(); + if (of_have_populated_dt()) + omap_clk_soc_init = omap3430_dt_clk_init; } void __init omap35xx_init_early(void) { omap3_init_early(); + if (of_have_populated_dt()) + omap_clk_soc_init = omap3430_dt_clk_init; } void __init omap3630_init_early(void) { omap3_init_early(); + if (of_have_populated_dt()) + omap_clk_soc_init = omap3630_dt_clk_init; } void __init am35xx_init_early(void) { omap3_init_early(); + if (of_have_populated_dt()) + omap_clk_soc_init = am35xx_dt_clk_init; } void __init ti81xx_init_early(void) @@ -520,7 +528,10 @@ void __init ti81xx_init_early(void) omap3xxx_clockdomains_init(); omap3xxx_hwmod_init(); omap_hwmod_init_postsetup(); - omap_clk_init = omap3xxx_clk_init; + if (of_have_populated_dt()) + omap_clk_soc_init = ti81xx_dt_clk_init; + else + omap_clk_soc_init = omap3xxx_clk_init; } void __init omap3_init_late(void) @@ -581,7 +592,7 @@ void __init am33xx_init_early(void) am33xx_clockdomains_init(); am33xx_hwmod_init(); omap_hwmod_init_postsetup(); - omap_clk_init = am33xx_clk_init; + omap_clk_soc_init = am33xx_dt_clk_init; } void __init am33xx_init_late(void) @@ -606,6 +617,7 @@ void __init am43xx_init_early(void) am43xx_clockdomains_init(); am43xx_hwmod_init(); omap_hwmod_init_postsetup(); + omap_clk_soc_init = am43xx_dt_clk_init; } void __init am43xx_init_late(void) @@ -629,13 +641,14 @@ void __init omap4430_init_early(void) omap_cm_base_init(); omap4xxx_check_revision(); omap4xxx_check_features(); + omap4_pm_init_early(); omap44xx_prm_init(); omap44xx_voltagedomains_init(); omap44xx_powerdomains_init(); omap44xx_clockdomains_init(); omap44xx_hwmod_init(); omap_hwmod_init_postsetup(); - omap_clk_init = omap4xxx_clk_init; + omap_clk_soc_init = omap4xxx_dt_clk_init; } void __init omap4430_init_late(void) @@ -666,6 +679,7 @@ void __init omap5_init_early(void) omap54xx_clockdomains_init(); omap54xx_hwmod_init(); omap_hwmod_init_postsetup(); + omap_clk_soc_init = omap5xxx_dt_clk_init; } void __init omap5_init_late(void) @@ -691,6 +705,7 @@ void __init dra7xx_init_early(void) dra7xx_clockdomains_init(); dra7xx_hwmod_init(); omap_hwmod_init_postsetup(); + omap_clk_soc_init = dra7xx_dt_clk_init; } void __init dra7xx_init_late(void) @@ -710,3 +725,17 @@ void __init omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0, _omap2_init_reprogram_sdrc(); } } + +int __init omap_clk_init(void) +{ + int ret = 0; + + if (!omap_clk_soc_init) + return 0; + + ret = of_prcm_init(); + if (!ret) + ret = omap_clk_soc_init(); + + return ret; +} diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c index f991016e2a6ac3..667915d236f3db 100644 --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c @@ -271,6 +271,9 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) else omap_pm_ops.finish_suspend(save_state); + if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) && cpu) + gic_dist_enable(); + /* * Restore the CPUx power state to ON otherwise CPUx * power domain can transitions to programmed low power diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 75e95d4fb448cd..17550aa39d0f39 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -39,8 +39,6 @@ #define OMAP5_CORE_COUNT 0x2 -u16 pm44xx_errata; - /* SCU base address */ static void __iomem *scu_base; @@ -217,10 +215,8 @@ static void __init omap4_smp_prepare_cpus(unsigned int max_cpus) if (scu_base) scu_enable(scu_base); - if (cpu_is_omap446x()) { + if (cpu_is_omap446x()) startup_addr = omap4460_secondary_startup; - pm44xx_errata |= PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD; - } /* * Write the address of secondary startup routine into the diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index dd893ec4c8f271..6cd3f3772ecf4e 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c @@ -127,6 +127,12 @@ void gic_dist_disable(void) __raw_writel(0x0, gic_dist_base_addr + GIC_DIST_CTRL); } +void gic_dist_enable(void) +{ + if (gic_dist_base_addr) + __raw_writel(0x1, gic_dist_base_addr + GIC_DIST_CTRL); +} + bool gic_dist_disabled(void) { return !(__raw_readl(gic_dist_base_addr + GIC_DIST_CTRL) & 0x1); diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index f7a6fd35b1e43f..42d81885c700c4 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -686,6 +686,8 @@ static struct clockdomain *_get_clkdm(struct omap_hwmod *oh) if (oh->clkdm) { return oh->clkdm; } else if (oh->_clk) { + if (__clk_get_flags(oh->_clk) & CLK_IS_BASIC) + return NULL; clk = to_clk_hw_omap(__clk_get_hw(oh->_clk)); return clk->clkdm; } @@ -1576,7 +1578,7 @@ static int _init_clkdm(struct omap_hwmod *oh) if (!oh->clkdm) { pr_warning("omap_hwmod: %s: could not associate to clkdm %s\n", oh->name, oh->clkdm_name); - return -EINVAL; + return 0; } pr_debug("omap_hwmod: %s: associated to clkdm %s\n", @@ -4231,6 +4233,7 @@ void __init omap_hwmod_init(void) soc_ops.assert_hardreset = _omap2_assert_hardreset; soc_ops.deassert_hardreset = _omap2_deassert_hardreset; soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted; + soc_ops.init_clkdm = _init_clkdm; } else if (cpu_is_omap44xx() || soc_is_omap54xx() || soc_is_dra7xx()) { soc_ops.enable_module = _omap4_enable_module; soc_ops.disable_module = _omap4_disable_module; diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 82f0698933d85a..eefb30cfcabdae 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -24,6 +24,8 @@ #include "powerdomain.h" #include "pm.h" +u16 pm44xx_errata; + struct power_state { struct powerdomain *pwrdm; u32 next_state; @@ -198,6 +200,19 @@ static inline int omap4_init_static_deps(void) return ret; } +/** + * omap4_pm_init_early - Does early initialization necessary for OMAP4+ devices + * + * Initializes basic stuff for power management functionality. + */ +int __init omap4_pm_init_early(void) +{ + if (cpu_is_omap446x()) + pm44xx_errata |= PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD; + + return 0; +} + /** * omap4_pm_init - Init routine for OMAP4+ devices * diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h index ac25ae6667cf92..623db40fdbbda4 100644 --- a/arch/arm/mach-omap2/prm.h +++ b/arch/arm/mach-omap2/prm.h @@ -18,6 +18,7 @@ # ifndef __ASSEMBLER__ extern void __iomem *prm_base; extern void omap2_set_globals_prm(void __iomem *prm); +int of_prcm_init(void); # endif diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c index a2e1174ad1b6a6..b4c4ab9c804447 100644 --- a/arch/arm/mach-omap2/prm_common.c +++ b/arch/arm/mach-omap2/prm_common.c @@ -23,6 +23,10 @@ #include #include #include +#include +#include +#include +#include #include "soc.h" #include "prm2xxx_3xxx.h" @@ -30,6 +34,7 @@ #include "prm3xxx.h" #include "prm44xx.h" #include "common.h" +#include "clock.h" /* * OMAP_PRCM_MAX_NR_PENDING_REG: maximum number of PRM_IRQ*_MPU regs @@ -464,3 +469,64 @@ int prm_unregister(struct prm_ll_data *pld) return 0; } + +static struct of_device_id omap_prcm_dt_match_table[] = { + { .compatible = "ti,am3-prcm" }, + { .compatible = "ti,am3-scrm" }, + { .compatible = "ti,am4-prcm" }, + { .compatible = "ti,am4-scrm" }, + { .compatible = "ti,omap3-prm" }, + { .compatible = "ti,omap3-cm" }, + { .compatible = "ti,omap3-scrm" }, + { .compatible = "ti,omap4-cm1" }, + { .compatible = "ti,omap4-prm" }, + { .compatible = "ti,omap4-cm2" }, + { .compatible = "ti,omap4-scrm" }, + { .compatible = "ti,omap5-prm" }, + { .compatible = "ti,omap5-cm-core-aon" }, + { .compatible = "ti,omap5-scrm" }, + { .compatible = "ti,omap5-cm-core" }, + { .compatible = "ti,dra7-prm" }, + { .compatible = "ti,dra7-cm-core-aon" }, + { .compatible = "ti,dra7-cm-core" }, + { } +}; + +static struct clk_hw_omap memmap_dummy_ck = { + .flags = MEMMAP_ADDRESSING, +}; + +static u32 prm_clk_readl(void __iomem *reg) +{ + return omap2_clk_readl(&memmap_dummy_ck, reg); +} + +static void prm_clk_writel(u32 val, void __iomem *reg) +{ + omap2_clk_writel(val, &memmap_dummy_ck, reg); +} + +static struct ti_clk_ll_ops omap_clk_ll_ops = { + .clk_readl = prm_clk_readl, + .clk_writel = prm_clk_writel, +}; + +int __init of_prcm_init(void) +{ + struct device_node *np; + void __iomem *mem; + int memmap_index = 0; + + ti_clk_ll_ops = &omap_clk_ll_ops; + + for_each_matching_node(np, omap_prcm_dt_match_table) { + mem = of_iomap(np, 0); + clk_memmaps[memmap_index] = mem; + ti_dt_clk_init_provider(np, memmap_index); + memmap_index++; + } + + ti_dt_clockdomains_setup(); + + return 0; +} diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index ec084d158f642b..74044aaf438b6f 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -570,8 +570,7 @@ static inline void __init realtime_counter_init(void) clksrc_nr, clksrc_src, clksrc_prop) \ void __init omap##name##_gptimer_timer_init(void) \ { \ - if (omap_clk_init) \ - omap_clk_init(); \ + omap_clk_init(); \ omap_dmtimer_init(); \ omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \ omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src, \ @@ -582,8 +581,7 @@ void __init omap##name##_gptimer_timer_init(void) \ clksrc_nr, clksrc_src, clksrc_prop) \ void __init omap##name##_sync32k_timer_init(void) \ { \ - if (omap_clk_init) \ - omap_clk_init(); \ + omap_clk_init(); \ omap_dmtimer_init(); \ omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \ /* Enable the use of clocksource="gp_timer" kernel parameter */ \ diff --git a/arch/arm/mach-pxa/am300epd.c b/arch/arm/mach-pxa/am300epd.c index c9f309ae88c5b5..8b90c4f2d43082 100644 --- a/arch/arm/mach-pxa/am300epd.c +++ b/arch/arm/mach-pxa/am300epd.c @@ -30,6 +30,7 @@ #include #include +#include #include #include "generic.h" diff --git a/arch/arm/mach-pxa/include/mach/balloon3.h b/arch/arm/mach-pxa/include/mach/balloon3.h index 954641e6c8b1ce..1b0825911e62c1 100644 --- a/arch/arm/mach-pxa/include/mach/balloon3.h +++ b/arch/arm/mach-pxa/include/mach/balloon3.h @@ -14,6 +14,8 @@ #ifndef ASM_ARCH_BALLOON3_H #define ASM_ARCH_BALLOON3_H +#include "irqs.h" /* PXA_NR_BUILTIN_GPIO */ + enum balloon3_features { BALLOON3_FEATURE_OHCI, BALLOON3_FEATURE_MMC, diff --git a/arch/arm/mach-pxa/include/mach/corgi.h b/arch/arm/mach-pxa/include/mach/corgi.h index f3c3493b468dff..c030d955bbd7ad 100644 --- a/arch/arm/mach-pxa/include/mach/corgi.h +++ b/arch/arm/mach-pxa/include/mach/corgi.h @@ -13,6 +13,7 @@ #ifndef __ASM_ARCH_CORGI_H #define __ASM_ARCH_CORGI_H 1 +#include "irqs.h" /* PXA_NR_BUILTIN_GPIO */ /* * Corgi (Non Standard) GPIO Definitions diff --git a/arch/arm/mach-pxa/include/mach/csb726.h b/arch/arm/mach-pxa/include/mach/csb726.h index 2628e7b721168c..00cfbbbf73f78d 100644 --- a/arch/arm/mach-pxa/include/mach/csb726.h +++ b/arch/arm/mach-pxa/include/mach/csb726.h @@ -11,6 +11,8 @@ #ifndef CSB726_H #define CSB726_H +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + #define CSB726_GPIO_IRQ_LAN 52 #define CSB726_GPIO_IRQ_SM501 53 #define CSB726_GPIO_MMC_DETECT 100 diff --git a/arch/arm/mach-pxa/include/mach/gumstix.h b/arch/arm/mach-pxa/include/mach/gumstix.h index dba14b6503ad17..f7df27bbb42e00 100644 --- a/arch/arm/mach-pxa/include/mach/gumstix.h +++ b/arch/arm/mach-pxa/include/mach/gumstix.h @@ -6,6 +6,7 @@ * published by the Free Software Foundation. */ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ /* BTRESET - Reset line to Bluetooth module, active low signal. */ #define GPIO_GUMSTIX_BTRESET 7 diff --git a/arch/arm/mach-pxa/include/mach/idp.h b/arch/arm/mach-pxa/include/mach/idp.h index 22a96f87232b5d..7e63f4680271f3 100644 --- a/arch/arm/mach-pxa/include/mach/idp.h +++ b/arch/arm/mach-pxa/include/mach/idp.h @@ -23,6 +23,7 @@ * IDP hardware. */ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ #define IDP_FLASH_PHYS (PXA_CS0_PHYS) #define IDP_ALT_FLASH_PHYS (PXA_CS1_PHYS) diff --git a/arch/arm/mach-pxa/include/mach/palmld.h b/arch/arm/mach-pxa/include/mach/palmld.h index 2c4471336570f0..b184f296023bbf 100644 --- a/arch/arm/mach-pxa/include/mach/palmld.h +++ b/arch/arm/mach-pxa/include/mach/palmld.h @@ -13,6 +13,8 @@ #ifndef _INCLUDE_PALMLD_H_ #define _INCLUDE_PALMLD_H_ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /** HERE ARE GPIOs **/ /* GPIOs */ diff --git a/arch/arm/mach-pxa/include/mach/palmt5.h b/arch/arm/mach-pxa/include/mach/palmt5.h index 0bd4f036c72fbb..e342c59214053c 100644 --- a/arch/arm/mach-pxa/include/mach/palmt5.h +++ b/arch/arm/mach-pxa/include/mach/palmt5.h @@ -15,6 +15,8 @@ #ifndef _INCLUDE_PALMT5_H_ #define _INCLUDE_PALMT5_H_ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /** HERE ARE GPIOs **/ /* GPIOs */ diff --git a/arch/arm/mach-pxa/include/mach/palmtc.h b/arch/arm/mach-pxa/include/mach/palmtc.h index c383a21680b699..81c727b3cfd23c 100644 --- a/arch/arm/mach-pxa/include/mach/palmtc.h +++ b/arch/arm/mach-pxa/include/mach/palmtc.h @@ -16,6 +16,8 @@ #ifndef _INCLUDE_PALMTC_H_ #define _INCLUDE_PALMTC_H_ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /** HERE ARE GPIOs **/ /* GPIOs */ diff --git a/arch/arm/mach-pxa/include/mach/palmtx.h b/arch/arm/mach-pxa/include/mach/palmtx.h index f2e5303802537d..92bc1f05300dde 100644 --- a/arch/arm/mach-pxa/include/mach/palmtx.h +++ b/arch/arm/mach-pxa/include/mach/palmtx.h @@ -16,6 +16,8 @@ #ifndef _INCLUDE_PALMTX_H_ #define _INCLUDE_PALMTX_H_ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /** HERE ARE GPIOs **/ /* GPIOs */ diff --git a/arch/arm/mach-pxa/include/mach/pcm027.h b/arch/arm/mach-pxa/include/mach/pcm027.h index 6bf28de228bdeb..86ebd7b6c96028 100644 --- a/arch/arm/mach-pxa/include/mach/pcm027.h +++ b/arch/arm/mach-pxa/include/mach/pcm027.h @@ -23,6 +23,8 @@ * Definitions of CPU card resources only */ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /* phyCORE-PXA270 (PCM027) Interrupts */ #define PCM027_IRQ(x) (IRQ_BOARD_START + (x)) #define PCM027_BTDET_IRQ PCM027_IRQ(0) diff --git a/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h b/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h index 0260aaa2fc1786..7e544c14967ed4 100644 --- a/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h +++ b/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h @@ -20,6 +20,7 @@ */ #include +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ /* * definitions relevant only when the PCM-990 diff --git a/arch/arm/mach-pxa/include/mach/poodle.h b/arch/arm/mach-pxa/include/mach/poodle.h index f32ff75dcca83a..b56b19351a0389 100644 --- a/arch/arm/mach-pxa/include/mach/poodle.h +++ b/arch/arm/mach-pxa/include/mach/poodle.h @@ -15,6 +15,8 @@ #ifndef __ASM_ARCH_POODLE_H #define __ASM_ARCH_POODLE_H 1 +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /* * GPIOs */ diff --git a/arch/arm/mach-pxa/include/mach/spitz.h b/arch/arm/mach-pxa/include/mach/spitz.h index 0bfe6507c95dd2..25c9f62e46aa3f 100644 --- a/arch/arm/mach-pxa/include/mach/spitz.h +++ b/arch/arm/mach-pxa/include/mach/spitz.h @@ -15,8 +15,8 @@ #define __ASM_ARCH_SPITZ_H 1 #endif +#include "irqs.h" /* PXA_NR_BUILTIN_GPIO, PXA_GPIO_TO_IRQ */ #include -#include /* Spitz/Akita GPIOs */ diff --git a/arch/arm/mach-pxa/include/mach/tosa.h b/arch/arm/mach-pxa/include/mach/tosa.h index 2bb0e862598c41..0497d95cef2554 100644 --- a/arch/arm/mach-pxa/include/mach/tosa.h +++ b/arch/arm/mach-pxa/include/mach/tosa.h @@ -13,6 +13,8 @@ #ifndef _ASM_ARCH_TOSA_H_ #define _ASM_ARCH_TOSA_H_ 1 +#include "irqs.h" /* PXA_NR_BUILTIN_GPIO */ + /* TOSA Chip selects */ #define TOSA_LCDC_PHYS PXA_CS4_PHYS /* Internel Scoop */ diff --git a/arch/arm/mach-pxa/include/mach/trizeps4.h b/arch/arm/mach-pxa/include/mach/trizeps4.h index d2ca01053f697d..ae3ca013afabe8 100644 --- a/arch/arm/mach-pxa/include/mach/trizeps4.h +++ b/arch/arm/mach-pxa/include/mach/trizeps4.h @@ -10,6 +10,8 @@ #ifndef _TRIPEPS4_H_ #define _TRIPEPS4_H_ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /* physical memory regions */ #define TRIZEPS4_FLASH_PHYS (PXA_CS0_PHYS) /* Flash region */ #define TRIZEPS4_DISK_PHYS (PXA_CS1_PHYS) /* Disk On Chip region */ diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 338640631e0823..05fa505df5850d 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -8,7 +8,7 @@ config ARCH_SHMOBILE_MULTI select CPU_V7 select GENERIC_CLOCKEVENTS select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if LOCAL_TIMERS + select HAVE_ARM_TWD if SMP select HAVE_SMP select ARM_GIC select MIGHT_HAVE_CACHE_L2X0 diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index 4ae0286b468db6..f55b05a29b55f3 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index 1db2a5ca9ab8c8..8c09a8393fb630 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,18 @@ void __iomem *zynq_scu_base; +/** + * zynq_memory_init - Initialize special memory + * + * We need to stop things allocating the low memory as DMA can't work in + * the 1st 512K of memory. + */ +static void __init zynq_memory_init(void) +{ + if (!__pa(PAGE_OFFSET)) + memblock_reserve(__pa(PAGE_OFFSET), __pa(swapper_pg_dir)); +} + static struct platform_device zynq_cpuidle_device = { .name = "cpuidle-zynq", }; @@ -117,5 +130,6 @@ DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform") .init_machine = zynq_init_machine, .init_time = zynq_timer_init, .dt_compat = zynq_dt_match, + .reserve = zynq_memory_init, .restart = zynq_system_reset, MACHINE_END diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 1a77450e728ad1..11b3914660d2a9 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1358,7 +1358,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, *handle = DMA_ERROR_CODE; size = PAGE_ALIGN(size); - if (gfp & GFP_ATOMIC) + if (!(gfp & __GFP_WAIT)) return __iommu_alloc_atomic(dev, size, handle); /* diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index f57fb338cc8aaa..804d61566a53dd 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -290,10 +290,11 @@ void __init arm_memblock_init(struct meminfo *mi, #endif #ifdef CONFIG_BLK_DEV_INITRD /* FDT scan will populate initrd_start */ - if (initrd_start) { + if (initrd_start && !phys_initrd_size) { phys_initrd_start = __virt_to_phys(initrd_start); phys_initrd_size = initrd_end - initrd_start; } + initrd_start = initrd_end = 0; if (phys_initrd_size && !memblock_is_region_memory(phys_initrd_start, phys_initrd_size)) { pr_err("INITRD: 0x%08llx+0x%08lx is not a memory region - disabling initrd\n", diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h index d5a982d15a88e2..7ea641b7aa7d2b 100644 --- a/arch/arm/mm/mm.h +++ b/arch/arm/mm/mm.h @@ -38,6 +38,7 @@ static inline pmd_t *pmd_off_k(unsigned long virt) struct mem_type { pteval_t prot_pte; + pteval_t prot_pte_s2; pmdval_t prot_l1; pmdval_t prot_sect; unsigned int domain; diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 4f08c133cc255e..a623cb3ad012b1 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -232,12 +232,16 @@ __setup("noalign", noalign_setup); #endif /* ifdef CONFIG_CPU_CP15 / else */ #define PROT_PTE_DEVICE L_PTE_PRESENT|L_PTE_YOUNG|L_PTE_DIRTY|L_PTE_XN +#define PROT_PTE_S2_DEVICE PROT_PTE_DEVICE #define PROT_SECT_DEVICE PMD_TYPE_SECT|PMD_SECT_AP_WRITE static struct mem_type mem_types[] = { [MT_DEVICE] = { /* Strongly ordered / ARMv6 shared device */ .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED | L_PTE_SHARED, + .prot_pte_s2 = s2_policy(PROT_PTE_S2_DEVICE) | + s2_policy(L_PTE_S2_MT_DEV_SHARED) | + L_PTE_SHARED, .prot_l1 = PMD_TYPE_TABLE, .prot_sect = PROT_SECT_DEVICE | PMD_SECT_S, .domain = DOMAIN_IO, @@ -508,7 +512,8 @@ static void __init build_mem_type_table(void) cp = &cache_policies[cachepolicy]; vecs_pgprot = kern_pgprot = user_pgprot = cp->pte; s2_pgprot = cp->pte_s2; - hyp_device_pgprot = s2_device_pgprot = mem_types[MT_DEVICE].prot_pte; + hyp_device_pgprot = mem_types[MT_DEVICE].prot_pte; + s2_device_pgprot = mem_types[MT_DEVICE].prot_pte_s2; /* * ARMv6 and above have extended page tables. diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index 45dc29f85d56ca..32b3558321c40d 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S @@ -208,7 +208,6 @@ __v6_setup: mcr p15, 0, r0, c7, c14, 0 @ clean+invalidate D cache mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache mcr p15, 0, r0, c7, c15, 0 @ clean+invalidate cache - mcr p15, 0, r0, c7, c10, 4 @ drain write buffer #ifdef CONFIG_MMU mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs mcr p15, 0, r0, c2, c0, 2 @ TTB control register @@ -218,6 +217,8 @@ __v6_setup: ALT_UP(orr r8, r8, #TTB_FLAGS_UP) mcr p15, 0, r8, c2, c0, 1 @ load TTB1 #endif /* CONFIG_MMU */ + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer and + @ complete invalidations adr r5, v6_crval ldmia r5, {r5, r6} ARM_BE8(orr r6, r6, #1 << 25) @ big-endian page tables diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index bd1781979a3918..74f6033e76dd17 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -351,7 +351,6 @@ __v7_setup: 4: mov r10, #0 mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate - dsb #ifdef CONFIG_MMU mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs v7_ttb_setup r10, r4, r8, r5 @ TTBCR, TTBRx setup @@ -360,6 +359,7 @@ __v7_setup: mcr p15, 0, r5, c10, c2, 0 @ write PRRR mcr p15, 0, r6, c10, c2, 1 @ write NMRR #endif + dsb @ Complete invalidations #ifndef CONFIG_ARM_THUMBEE mrc p15, 0, r0, c0, c1, 0 @ read ID_PFR0 for ThumbEE and r0, r0, #(0xf << 12) @ ThumbEE enabled field diff --git a/arch/arm/plat-orion/irq.c b/arch/arm/plat-orion/irq.c index c492e1b3dfdb29..807df142444b4f 100644 --- a/arch/arm/plat-orion/irq.c +++ b/arch/arm/plat-orion/irq.c @@ -15,8 +15,51 @@ #include #include #include +#include #include #include +#include + +#ifdef CONFIG_MULTI_IRQ_HANDLER +/* + * Compiling with both non-DT and DT support enabled, will + * break asm irq handler used by non-DT boards. Therefore, + * we provide a C-style irq handler even for non-DT boards, + * if MULTI_IRQ_HANDLER is set. + * + * Notes: + * - this is prepared for Kirkwood and Dove only, update + * accordingly if you add Orion5x or MV78x00. + * - Orion5x uses different macro names and has only one + * set of CAUSE/MASK registers. + * - MV78x00 uses the same macro names but has a third + * set of CAUSE/MASK registers. + * + */ + +static void __iomem *orion_irq_base = IRQ_VIRT_BASE; + +asmlinkage void +__exception_irq_entry orion_legacy_handle_irq(struct pt_regs *regs) +{ + u32 stat; + + stat = readl_relaxed(orion_irq_base + IRQ_CAUSE_LOW_OFF); + stat &= readl_relaxed(orion_irq_base + IRQ_MASK_LOW_OFF); + if (stat) { + unsigned int hwirq = __fls(stat); + handle_IRQ(hwirq, regs); + return; + } + stat = readl_relaxed(orion_irq_base + IRQ_CAUSE_HIGH_OFF); + stat &= readl_relaxed(orion_irq_base + IRQ_MASK_HIGH_OFF); + if (stat) { + unsigned int hwirq = 32 + __fls(stat); + handle_IRQ(hwirq, regs); + return; + } +} +#endif void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr) { @@ -35,6 +78,10 @@ void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr) ct->chip.irq_unmask = irq_gc_mask_set_bit; irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); + +#ifdef CONFIG_MULTI_IRQ_HANDLER + set_handle_irq(orion_legacy_handle_irq); +#endif } #ifdef CONFIG_OF diff --git a/arch/arm/plat-samsung/include/plat/regs-nand.h b/arch/arm/plat-samsung/include/plat/regs-nand.h deleted file mode 100644 index 238efea7b9e49c..00000000000000 --- a/arch/arm/plat-samsung/include/plat/regs-nand.h +++ /dev/null @@ -1,123 +0,0 @@ -/* arch/arm/mach-s3c2410/include/mach/regs-nand.h - * - * Copyright (c) 2004-2005 Simtec Electronics - * http://www.simtec.co.uk/products/SWLINUX/ - * - * 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. - * - * S3C2410 NAND register definitions -*/ - -#ifndef __ASM_ARM_REGS_NAND -#define __ASM_ARM_REGS_NAND - - -#define S3C2410_NFREG(x) (x) - -#define S3C2410_NFCONF S3C2410_NFREG(0x00) -#define S3C2410_NFCMD S3C2410_NFREG(0x04) -#define S3C2410_NFADDR S3C2410_NFREG(0x08) -#define S3C2410_NFDATA S3C2410_NFREG(0x0C) -#define S3C2410_NFSTAT S3C2410_NFREG(0x10) -#define S3C2410_NFECC S3C2410_NFREG(0x14) - -#define S3C2440_NFCONT S3C2410_NFREG(0x04) -#define S3C2440_NFCMD S3C2410_NFREG(0x08) -#define S3C2440_NFADDR S3C2410_NFREG(0x0C) -#define S3C2440_NFDATA S3C2410_NFREG(0x10) -#define S3C2440_NFECCD0 S3C2410_NFREG(0x14) -#define S3C2440_NFECCD1 S3C2410_NFREG(0x18) -#define S3C2440_NFECCD S3C2410_NFREG(0x1C) -#define S3C2440_NFSTAT S3C2410_NFREG(0x20) -#define S3C2440_NFESTAT0 S3C2410_NFREG(0x24) -#define S3C2440_NFESTAT1 S3C2410_NFREG(0x28) -#define S3C2440_NFMECC0 S3C2410_NFREG(0x2C) -#define S3C2440_NFMECC1 S3C2410_NFREG(0x30) -#define S3C2440_NFSECC S3C2410_NFREG(0x34) -#define S3C2440_NFSBLK S3C2410_NFREG(0x38) -#define S3C2440_NFEBLK S3C2410_NFREG(0x3C) - -#define S3C2412_NFSBLK S3C2410_NFREG(0x20) -#define S3C2412_NFEBLK S3C2410_NFREG(0x24) -#define S3C2412_NFSTAT S3C2410_NFREG(0x28) -#define S3C2412_NFMECC_ERR0 S3C2410_NFREG(0x2C) -#define S3C2412_NFMECC_ERR1 S3C2410_NFREG(0x30) -#define S3C2412_NFMECC0 S3C2410_NFREG(0x34) -#define S3C2412_NFMECC1 S3C2410_NFREG(0x38) -#define S3C2412_NFSECC S3C2410_NFREG(0x3C) - -#define S3C2410_NFCONF_EN (1<<15) -#define S3C2410_NFCONF_512BYTE (1<<14) -#define S3C2410_NFCONF_4STEP (1<<13) -#define S3C2410_NFCONF_INITECC (1<<12) -#define S3C2410_NFCONF_nFCE (1<<11) -#define S3C2410_NFCONF_TACLS(x) ((x)<<8) -#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4) -#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0) - -#define S3C2410_NFSTAT_BUSY (1<<0) - -#define S3C2440_NFCONF_BUSWIDTH_8 (0<<0) -#define S3C2440_NFCONF_BUSWIDTH_16 (1<<0) -#define S3C2440_NFCONF_ADVFLASH (1<<3) -#define S3C2440_NFCONF_TACLS(x) ((x)<<12) -#define S3C2440_NFCONF_TWRPH0(x) ((x)<<8) -#define S3C2440_NFCONF_TWRPH1(x) ((x)<<4) - -#define S3C2440_NFCONT_LOCKTIGHT (1<<13) -#define S3C2440_NFCONT_SOFTLOCK (1<<12) -#define S3C2440_NFCONT_ILLEGALACC_EN (1<<10) -#define S3C2440_NFCONT_RNBINT_EN (1<<9) -#define S3C2440_NFCONT_RN_FALLING (1<<8) -#define S3C2440_NFCONT_SPARE_ECCLOCK (1<<6) -#define S3C2440_NFCONT_MAIN_ECCLOCK (1<<5) -#define S3C2440_NFCONT_INITECC (1<<4) -#define S3C2440_NFCONT_nFCE (1<<1) -#define S3C2440_NFCONT_ENABLE (1<<0) - -#define S3C2440_NFSTAT_READY (1<<0) -#define S3C2440_NFSTAT_nCE (1<<1) -#define S3C2440_NFSTAT_RnB_CHANGE (1<<2) -#define S3C2440_NFSTAT_ILLEGAL_ACCESS (1<<3) - -#define S3C2412_NFCONF_NANDBOOT (1<<31) -#define S3C2412_NFCONF_ECCCLKCON (1<<30) -#define S3C2412_NFCONF_ECC_MLC (1<<24) -#define S3C2412_NFCONF_TACLS_MASK (7<<12) /* 1 extra bit of Tacls */ - -#define S3C2412_NFCONT_ECC4_DIRWR (1<<18) -#define S3C2412_NFCONT_LOCKTIGHT (1<<17) -#define S3C2412_NFCONT_SOFTLOCK (1<<16) -#define S3C2412_NFCONT_ECC4_ENCINT (1<<13) -#define S3C2412_NFCONT_ECC4_DECINT (1<<12) -#define S3C2412_NFCONT_MAIN_ECC_LOCK (1<<7) -#define S3C2412_NFCONT_INIT_MAIN_ECC (1<<5) -#define S3C2412_NFCONT_nFCE1 (1<<2) -#define S3C2412_NFCONT_nFCE0 (1<<1) - -#define S3C2412_NFSTAT_ECC_ENCDONE (1<<7) -#define S3C2412_NFSTAT_ECC_DECDONE (1<<6) -#define S3C2412_NFSTAT_ILLEGAL_ACCESS (1<<5) -#define S3C2412_NFSTAT_RnB_CHANGE (1<<4) -#define S3C2412_NFSTAT_nFCE1 (1<<3) -#define S3C2412_NFSTAT_nFCE0 (1<<2) -#define S3C2412_NFSTAT_Res1 (1<<1) -#define S3C2412_NFSTAT_READY (1<<0) - -#define S3C2412_NFECCERR_SERRDATA(x) (((x) >> 21) & 0xf) -#define S3C2412_NFECCERR_SERRBIT(x) (((x) >> 18) & 0x7) -#define S3C2412_NFECCERR_MERRDATA(x) (((x) >> 7) & 0x3ff) -#define S3C2412_NFECCERR_MERRBIT(x) (((x) >> 4) & 0x7) -#define S3C2412_NFECCERR_SPARE_ERR(x) (((x) >> 2) & 0x3) -#define S3C2412_NFECCERR_MAIN_ERR(x) (((x) >> 2) & 0x3) -#define S3C2412_NFECCERR_NONE (0) -#define S3C2412_NFECCERR_1BIT (1) -#define S3C2412_NFECCERR_MULTIBIT (2) -#define S3C2412_NFECCERR_ECCAREA (3) - - - -#endif /* __ASM_ARM_REGS_NAND */ - diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c index 2162172c0ddc76..b96723e258a085 100644 --- a/arch/arm/xen/enlighten.c +++ b/arch/arm/xen/enlighten.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -154,7 +155,7 @@ int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, } EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range); -static void __init xen_percpu_init(void *unused) +static void xen_percpu_init(void) { struct vcpu_register_vcpu_info info; struct vcpu_info *vcpup; @@ -193,6 +194,31 @@ static void xen_power_off(void) BUG(); } +static int xen_cpu_notification(struct notifier_block *self, + unsigned long action, + void *hcpu) +{ + switch (action) { + case CPU_STARTING: + xen_percpu_init(); + break; + default: + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block xen_cpu_notifier = { + .notifier_call = xen_cpu_notification, +}; + +static irqreturn_t xen_arm_callback(int irq, void *arg) +{ + xen_hvm_evtchn_do_upcall(); + return IRQ_HANDLED; +} + /* * see Documentation/devicetree/bindings/arm/xen.txt for the * documentation of the Xen Device Tree format. @@ -208,7 +234,7 @@ static int __init xen_guest_init(void) const char *version = NULL; const char *xen_prefix = "xen,xen-"; struct resource res; - unsigned long grant_frames; + phys_addr_t grant_frames; node = of_find_compatible_node(NULL, NULL, "xen,xen"); if (!node) { @@ -227,8 +253,12 @@ static int __init xen_guest_init(void) return 0; grant_frames = res.start; xen_events_irq = irq_of_parse_and_map(node, 0); - pr_info("Xen %s support found, events_irq=%d gnttab_frame_pfn=%lx\n", - version, xen_events_irq, (grant_frames >> PAGE_SHIFT)); + pr_info("Xen %s support found, events_irq=%d gnttab_frame=%pa\n", + version, xen_events_irq, &grant_frames); + + if (xen_events_irq < 0) + return -ENODEV; + xen_domain_type = XEN_HVM_DOMAIN; xen_setup_features(); @@ -281,9 +311,21 @@ static int __init xen_guest_init(void) disable_cpuidle(); disable_cpufreq(); + xen_init_IRQ(); + + if (request_percpu_irq(xen_events_irq, xen_arm_callback, + "events", &xen_vcpu)) { + pr_err("Error request IRQ %d\n", xen_events_irq); + return -EINVAL; + } + + xen_percpu_init(); + + register_cpu_notifier(&xen_cpu_notifier); + return 0; } -core_initcall(xen_guest_init); +early_initcall(xen_guest_init); static int __init xen_pm_init(void) { @@ -297,31 +339,6 @@ static int __init xen_pm_init(void) } late_initcall(xen_pm_init); -static irqreturn_t xen_arm_callback(int irq, void *arg) -{ - xen_hvm_evtchn_do_upcall(); - return IRQ_HANDLED; -} - -static int __init xen_init_events(void) -{ - if (!xen_domain() || xen_events_irq < 0) - return -ENODEV; - - xen_init_IRQ(); - - if (request_percpu_irq(xen_events_irq, xen_arm_callback, - "events", &xen_vcpu)) { - pr_err("Error requesting IRQ %d\n", xen_events_irq); - return -EINVAL; - } - - on_each_cpu(xen_percpu_init, NULL, 0); - - return 0; -} -postcore_initcall(xen_init_events); - /* In the hypervisor.S file. */ EXPORT_SYMBOL_GPL(HYPERVISOR_event_channel_op); EXPORT_SYMBOL_GPL(HYPERVISOR_grant_table_op); diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index dd4327f09ba45b..27bbcfc7202a8d 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -36,6 +36,7 @@ config ARM64 select HAVE_GENERIC_DMA_COHERENT select HAVE_HW_BREAKPOINT if PERF_EVENTS select HAVE_MEMBLOCK + select HAVE_PATA_PLATFORM select HAVE_PERF_EVENTS select IRQ_DOMAIN select MODULES_USE_ELF_RELA diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 84139be62ae663..7959dd0ca5d5ed 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -1,4 +1,3 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set # CONFIG_SWAP is not set CONFIG_SYSVIPC=y @@ -19,6 +18,7 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_KALLSYMS_ALL=y # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y +CONFIG_JUMP_LABEL=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set @@ -27,6 +27,7 @@ CONFIG_ARCH_VEXPRESS=y CONFIG_ARCH_XGENE=y CONFIG_SMP=y CONFIG_PREEMPT=y +CONFIG_CMA=y CONFIG_CMDLINE="console=ttyAMA0" # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y @@ -42,14 +43,17 @@ CONFIG_IP_PNP_BOOTP=y # CONFIG_WIRELESS is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y -CONFIG_BLK_DEV=y +CONFIG_DMA_CMA=y CONFIG_SCSI=y # CONFIG_SCSI_PROC_FS is not set CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_LOWLEVEL is not set +CONFIG_ATA=y +CONFIG_PATA_PLATFORM=y +CONFIG_PATA_OF_PLATFORM=y CONFIG_NETDEVICES=y -CONFIG_MII=y CONFIG_SMC91X=y +CONFIG_SMSC911X=y # CONFIG_WLAN is not set CONFIG_INPUT_EVDEV=y # CONFIG_SERIO_I8042 is not set @@ -62,13 +66,19 @@ CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y # CONFIG_HW_RANDOM is not set # CONFIG_HWMON is not set +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_FB=y # CONFIG_VGA_CONSOLE is not set CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set -# CONFIG_USB_SUPPORT is not set +CONFIG_USB=y +CONFIG_USB_ISP1760_HCD=y +CONFIG_USB_STORAGE=y +CONFIG_MMC=y +CONFIG_MMC_ARMMMCI=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 01de5aaa3edc11..0237f0867e377a 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h @@ -54,8 +54,7 @@ static inline void atomic_add(int i, atomic_t *v) " stxr %w1, %w0, %2\n" " cbnz %w1, 1b" : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) - : "Ir" (i) - : "cc"); + : "Ir" (i)); } static inline int atomic_add_return(int i, atomic_t *v) @@ -64,14 +63,15 @@ static inline int atomic_add_return(int i, atomic_t *v) int result; asm volatile("// atomic_add_return\n" -"1: ldaxr %w0, %2\n" +"1: ldxr %w0, %2\n" " add %w0, %w0, %w3\n" " stlxr %w1, %w0, %2\n" " cbnz %w1, 1b" : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) : "Ir" (i) - : "cc", "memory"); + : "memory"); + smp_mb(); return result; } @@ -86,8 +86,7 @@ static inline void atomic_sub(int i, atomic_t *v) " stxr %w1, %w0, %2\n" " cbnz %w1, 1b" : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) - : "Ir" (i) - : "cc"); + : "Ir" (i)); } static inline int atomic_sub_return(int i, atomic_t *v) @@ -96,14 +95,15 @@ static inline int atomic_sub_return(int i, atomic_t *v) int result; asm volatile("// atomic_sub_return\n" -"1: ldaxr %w0, %2\n" +"1: ldxr %w0, %2\n" " sub %w0, %w0, %w3\n" " stlxr %w1, %w0, %2\n" " cbnz %w1, 1b" : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) : "Ir" (i) - : "cc", "memory"); + : "memory"); + smp_mb(); return result; } @@ -112,17 +112,20 @@ static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) unsigned long tmp; int oldval; + smp_mb(); + asm volatile("// atomic_cmpxchg\n" -"1: ldaxr %w1, %2\n" +"1: ldxr %w1, %2\n" " cmp %w1, %w3\n" " b.ne 2f\n" -" stlxr %w0, %w4, %2\n" +" stxr %w0, %w4, %2\n" " cbnz %w0, 1b\n" "2:" : "=&r" (tmp), "=&r" (oldval), "+Q" (ptr->counter) : "Ir" (old), "r" (new) - : "cc", "memory"); + : "cc"); + smp_mb(); return oldval; } @@ -173,8 +176,7 @@ static inline void atomic64_add(u64 i, atomic64_t *v) " stxr %w1, %0, %2\n" " cbnz %w1, 1b" : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) - : "Ir" (i) - : "cc"); + : "Ir" (i)); } static inline long atomic64_add_return(long i, atomic64_t *v) @@ -183,14 +185,15 @@ static inline long atomic64_add_return(long i, atomic64_t *v) unsigned long tmp; asm volatile("// atomic64_add_return\n" -"1: ldaxr %0, %2\n" +"1: ldxr %0, %2\n" " add %0, %0, %3\n" " stlxr %w1, %0, %2\n" " cbnz %w1, 1b" : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) : "Ir" (i) - : "cc", "memory"); + : "memory"); + smp_mb(); return result; } @@ -205,8 +208,7 @@ static inline void atomic64_sub(u64 i, atomic64_t *v) " stxr %w1, %0, %2\n" " cbnz %w1, 1b" : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) - : "Ir" (i) - : "cc"); + : "Ir" (i)); } static inline long atomic64_sub_return(long i, atomic64_t *v) @@ -215,14 +217,15 @@ static inline long atomic64_sub_return(long i, atomic64_t *v) unsigned long tmp; asm volatile("// atomic64_sub_return\n" -"1: ldaxr %0, %2\n" +"1: ldxr %0, %2\n" " sub %0, %0, %3\n" " stlxr %w1, %0, %2\n" " cbnz %w1, 1b" : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) : "Ir" (i) - : "cc", "memory"); + : "memory"); + smp_mb(); return result; } @@ -231,17 +234,20 @@ static inline long atomic64_cmpxchg(atomic64_t *ptr, long old, long new) long oldval; unsigned long res; + smp_mb(); + asm volatile("// atomic64_cmpxchg\n" -"1: ldaxr %1, %2\n" +"1: ldxr %1, %2\n" " cmp %1, %3\n" " b.ne 2f\n" -" stlxr %w0, %4, %2\n" +" stxr %w0, %4, %2\n" " cbnz %w0, 1b\n" "2:" : "=&r" (res), "=&r" (oldval), "+Q" (ptr->counter) : "Ir" (old), "r" (new) - : "cc", "memory"); + : "cc"); + smp_mb(); return oldval; } @@ -253,11 +259,12 @@ static inline long atomic64_dec_if_positive(atomic64_t *v) unsigned long tmp; asm volatile("// atomic64_dec_if_positive\n" -"1: ldaxr %0, %2\n" +"1: ldxr %0, %2\n" " subs %0, %0, #1\n" " b.mi 2f\n" " stlxr %w1, %0, %2\n" " cbnz %w1, 1b\n" +" dmb ish\n" "2:" : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) : diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h index 78e20ba8806b8b..409ca370cfe2dd 100644 --- a/arch/arm64/include/asm/barrier.h +++ b/arch/arm64/include/asm/barrier.h @@ -25,7 +25,7 @@ #define wfi() asm volatile("wfi" : : : "memory") #define isb() asm volatile("isb" : : : "memory") -#define dsb() asm volatile("dsb sy" : : : "memory") +#define dsb(opt) asm volatile("dsb sy" : : : "memory") #define mb() dsb() #define rmb() asm volatile("dsb ld" : : : "memory") diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h index fea9ee32720678..889324981aa4f5 100644 --- a/arch/arm64/include/asm/cacheflush.h +++ b/arch/arm64/include/asm/cacheflush.h @@ -116,6 +116,7 @@ extern void flush_dcache_page(struct page *); static inline void __flush_icache_all(void) { asm("ic ialluis"); + dsb(); } #define flush_dcache_mmap_lock(mapping) \ diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h index 56166d7f4a2588..57c0fa7bf71141 100644 --- a/arch/arm64/include/asm/cmpxchg.h +++ b/arch/arm64/include/asm/cmpxchg.h @@ -29,44 +29,45 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size switch (size) { case 1: asm volatile("// __xchg1\n" - "1: ldaxrb %w0, %2\n" + "1: ldxrb %w0, %2\n" " stlxrb %w1, %w3, %2\n" " cbnz %w1, 1b\n" : "=&r" (ret), "=&r" (tmp), "+Q" (*(u8 *)ptr) : "r" (x) - : "cc", "memory"); + : "memory"); break; case 2: asm volatile("// __xchg2\n" - "1: ldaxrh %w0, %2\n" + "1: ldxrh %w0, %2\n" " stlxrh %w1, %w3, %2\n" " cbnz %w1, 1b\n" : "=&r" (ret), "=&r" (tmp), "+Q" (*(u16 *)ptr) : "r" (x) - : "cc", "memory"); + : "memory"); break; case 4: asm volatile("// __xchg4\n" - "1: ldaxr %w0, %2\n" + "1: ldxr %w0, %2\n" " stlxr %w1, %w3, %2\n" " cbnz %w1, 1b\n" : "=&r" (ret), "=&r" (tmp), "+Q" (*(u32 *)ptr) : "r" (x) - : "cc", "memory"); + : "memory"); break; case 8: asm volatile("// __xchg8\n" - "1: ldaxr %0, %2\n" + "1: ldxr %0, %2\n" " stlxr %w1, %3, %2\n" " cbnz %w1, 1b\n" : "=&r" (ret), "=&r" (tmp), "+Q" (*(u64 *)ptr) : "r" (x) - : "cc", "memory"); + : "memory"); break; default: BUILD_BUG(); } + smp_mb(); return ret; } diff --git a/arch/arm64/include/asm/dma-contiguous.h b/arch/arm64/include/asm/dma-contiguous.h index d6aacb61ff4ae1..14c4c0ca7f2a21 100644 --- a/arch/arm64/include/asm/dma-contiguous.h +++ b/arch/arm64/include/asm/dma-contiguous.h @@ -18,7 +18,6 @@ #ifdef CONFIG_DMA_CMA #include -#include static inline void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) { } diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h index 78834123a32ef0..c4a7f940b3870c 100644 --- a/arch/arm64/include/asm/esr.h +++ b/arch/arm64/include/asm/esr.h @@ -42,7 +42,7 @@ #define ESR_EL1_EC_SP_ALIGN (0x26) #define ESR_EL1_EC_FP_EXC32 (0x28) #define ESR_EL1_EC_FP_EXC64 (0x2C) -#define ESR_EL1_EC_SERRROR (0x2F) +#define ESR_EL1_EC_SERROR (0x2F) #define ESR_EL1_EC_BREAKPT_EL0 (0x30) #define ESR_EL1_EC_BREAKPT_EL1 (0x31) #define ESR_EL1_EC_SOFTSTP_EL0 (0x32) diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h index 78cc3aba5d69e9..5f750dc96e0fd6 100644 --- a/arch/arm64/include/asm/futex.h +++ b/arch/arm64/include/asm/futex.h @@ -24,10 +24,11 @@ #define __futex_atomic_op(insn, ret, oldval, uaddr, tmp, oparg) \ asm volatile( \ -"1: ldaxr %w1, %2\n" \ +"1: ldxr %w1, %2\n" \ insn "\n" \ "2: stlxr %w3, %w0, %2\n" \ " cbnz %w3, 1b\n" \ +" dmb ish\n" \ "3:\n" \ " .pushsection .fixup,\"ax\"\n" \ " .align 2\n" \ @@ -40,7 +41,7 @@ " .popsection\n" \ : "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp) \ : "r" (oparg), "Ir" (-EFAULT) \ - : "cc", "memory") + : "memory") static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) @@ -111,11 +112,12 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, return -EFAULT; asm volatile("// futex_atomic_cmpxchg_inatomic\n" -"1: ldaxr %w1, %2\n" +"1: ldxr %w1, %2\n" " sub %w3, %w1, %w4\n" " cbnz %w3, 3f\n" "2: stlxr %w3, %w5, %2\n" " cbnz %w3, 1b\n" +" dmb ish\n" "3:\n" " .pushsection .fixup,\"ax\"\n" "4: mov %w0, %w6\n" @@ -127,7 +129,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, " .popsection\n" : "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp) : "r" (oldval), "r" (newval), "Ir" (-EFAULT) - : "cc", "memory"); + : "memory"); *uval = val; return ret; diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index c98ef4771c7389..0eb39865537839 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -231,7 +231,7 @@ #define ESR_EL2_EC_SP_ALIGN (0x26) #define ESR_EL2_EC_FP_EXC32 (0x28) #define ESR_EL2_EC_FP_EXC64 (0x2C) -#define ESR_EL2_EC_SERRROR (0x2F) +#define ESR_EL2_EC_SERROR (0x2F) #define ESR_EL2_EC_BREAKPT (0x30) #define ESR_EL2_EC_BREAKPT_HYP (0x31) #define ESR_EL2_EC_SOFTSTP (0x32) diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 7f2b60affbb495..b524dcd17243d7 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -28,7 +28,7 @@ #define PTE_FILE (_AT(pteval_t, 1) << 2) /* only when !pte_present() */ #define PTE_DIRTY (_AT(pteval_t, 1) << 55) #define PTE_SPECIAL (_AT(pteval_t, 1) << 56) - /* bit 57 for PMD_SECT_SPLITTING */ +#define PTE_WRITE (_AT(pteval_t, 1) << 57) #define PTE_PROT_NONE (_AT(pteval_t, 1) << 58) /* only when !PTE_VALID */ /* @@ -67,15 +67,15 @@ extern pgprot_t pgprot_default; #define _MOD_PROT(p, b) __pgprot_modify(p, 0, b) -#define PAGE_NONE __pgprot_modify(pgprot_default, PTE_TYPE_MASK, PTE_PROT_NONE | PTE_RDONLY | PTE_PXN | PTE_UXN) -#define PAGE_SHARED _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) -#define PAGE_SHARED_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN) -#define PAGE_COPY _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) -#define PAGE_COPY_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_RDONLY) -#define PAGE_READONLY _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) -#define PAGE_READONLY_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_RDONLY) -#define PAGE_KERNEL _MOD_PROT(pgprot_default, PTE_PXN | PTE_UXN | PTE_DIRTY) -#define PAGE_KERNEL_EXEC _MOD_PROT(pgprot_default, PTE_UXN | PTE_DIRTY) +#define PAGE_NONE __pgprot_modify(pgprot_default, PTE_TYPE_MASK, PTE_PROT_NONE | PTE_PXN | PTE_UXN) +#define PAGE_SHARED _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE) +#define PAGE_SHARED_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_WRITE) +#define PAGE_COPY _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) +#define PAGE_COPY_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN) +#define PAGE_READONLY _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) +#define PAGE_READONLY_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN) +#define PAGE_KERNEL _MOD_PROT(pgprot_default, PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE) +#define PAGE_KERNEL_EXEC _MOD_PROT(pgprot_default, PTE_UXN | PTE_DIRTY | PTE_WRITE) #define PAGE_HYP _MOD_PROT(pgprot_default, PTE_HYP) #define PAGE_HYP_DEVICE __pgprot(PROT_DEVICE_nGnRE | PTE_HYP) @@ -83,13 +83,13 @@ extern pgprot_t pgprot_default; #define PAGE_S2 __pgprot_modify(pgprot_default, PTE_S2_MEMATTR_MASK, PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY) #define PAGE_S2_DEVICE __pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDWR | PTE_UXN) -#define __PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_TYPE_MASK) | PTE_PROT_NONE | PTE_RDONLY | PTE_PXN | PTE_UXN) -#define __PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) -#define __PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN) -#define __PAGE_COPY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) -#define __PAGE_COPY_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_RDONLY) -#define __PAGE_READONLY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) -#define __PAGE_READONLY_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_RDONLY) +#define __PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_TYPE_MASK) | PTE_PROT_NONE | PTE_PXN | PTE_UXN) +#define __PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE) +#define __PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_WRITE) +#define __PAGE_COPY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) +#define __PAGE_COPY_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN) +#define __PAGE_READONLY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) +#define __PAGE_READONLY_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN) #endif /* __ASSEMBLY__ */ @@ -140,22 +140,53 @@ extern struct page *empty_zero_page; #define pte_dirty(pte) (pte_val(pte) & PTE_DIRTY) #define pte_young(pte) (pte_val(pte) & PTE_AF) #define pte_special(pte) (pte_val(pte) & PTE_SPECIAL) -#define pte_write(pte) (!(pte_val(pte) & PTE_RDONLY)) +#define pte_write(pte) (pte_val(pte) & PTE_WRITE) #define pte_exec(pte) (!(pte_val(pte) & PTE_UXN)) #define pte_valid_user(pte) \ ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) -#define PTE_BIT_FUNC(fn,op) \ -static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } +static inline pte_t pte_wrprotect(pte_t pte) +{ + pte_val(pte) &= ~PTE_WRITE; + return pte; +} + +static inline pte_t pte_mkwrite(pte_t pte) +{ + pte_val(pte) |= PTE_WRITE; + return pte; +} + +static inline pte_t pte_mkclean(pte_t pte) +{ + pte_val(pte) &= ~PTE_DIRTY; + return pte; +} + +static inline pte_t pte_mkdirty(pte_t pte) +{ + pte_val(pte) |= PTE_DIRTY; + return pte; +} -PTE_BIT_FUNC(wrprotect, |= PTE_RDONLY); -PTE_BIT_FUNC(mkwrite, &= ~PTE_RDONLY); -PTE_BIT_FUNC(mkclean, &= ~PTE_DIRTY); -PTE_BIT_FUNC(mkdirty, |= PTE_DIRTY); -PTE_BIT_FUNC(mkold, &= ~PTE_AF); -PTE_BIT_FUNC(mkyoung, |= PTE_AF); -PTE_BIT_FUNC(mkspecial, |= PTE_SPECIAL); +static inline pte_t pte_mkold(pte_t pte) +{ + pte_val(pte) &= ~PTE_AF; + return pte; +} + +static inline pte_t pte_mkyoung(pte_t pte) +{ + pte_val(pte) |= PTE_AF; + return pte; +} + +static inline pte_t pte_mkspecial(pte_t pte) +{ + pte_val(pte) |= PTE_SPECIAL; + return pte; +} static inline void set_pte(pte_t *ptep, pte_t pte) { @@ -170,8 +201,10 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, if (pte_valid_user(pte)) { if (pte_exec(pte)) __sync_icache_dcache(pte, addr); - if (!pte_dirty(pte)) - pte = pte_wrprotect(pte); + if (pte_dirty(pte) && pte_write(pte)) + pte_val(pte) &= ~PTE_RDONLY; + else + pte_val(pte) |= PTE_RDONLY; } set_pte(ptep, pte); @@ -345,7 +378,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr) static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY | - PTE_PROT_NONE | PTE_VALID; + PTE_PROT_NONE | PTE_VALID | PTE_WRITE; pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask); return pte; } diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h index 3d5cf064d7a170..c45b7b1b71978c 100644 --- a/arch/arm64/include/asm/spinlock.h +++ b/arch/arm64/include/asm/spinlock.h @@ -132,7 +132,7 @@ static inline void arch_write_lock(arch_rwlock_t *rw) " cbnz %w0, 2b\n" : "=&r" (tmp), "+Q" (rw->lock) : "r" (0x80000000) - : "cc", "memory"); + : "memory"); } static inline int arch_write_trylock(arch_rwlock_t *rw) @@ -146,7 +146,7 @@ static inline int arch_write_trylock(arch_rwlock_t *rw) "1:\n" : "=&r" (tmp), "+Q" (rw->lock) : "r" (0x80000000) - : "cc", "memory"); + : "memory"); return !tmp; } @@ -187,7 +187,7 @@ static inline void arch_read_lock(arch_rwlock_t *rw) " cbnz %w1, 2b\n" : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock) : - : "cc", "memory"); + : "memory"); } static inline void arch_read_unlock(arch_rwlock_t *rw) @@ -201,7 +201,7 @@ static inline void arch_read_unlock(arch_rwlock_t *rw) " cbnz %w1, 1b\n" : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock) : - : "cc", "memory"); + : "memory"); } static inline int arch_read_trylock(arch_rwlock_t *rw) @@ -216,7 +216,7 @@ static inline int arch_read_trylock(arch_rwlock_t *rw) "1:\n" : "=&r" (tmp), "+r" (tmp2), "+Q" (rw->lock) : - : "cc", "memory"); + : "memory"); return !tmp2; } diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h index 58125bf008d3e6..bb8eb8a78e67d2 100644 --- a/arch/arm64/include/asm/unistd32.h +++ b/arch/arm64/include/asm/unistd32.h @@ -399,7 +399,10 @@ __SYSCALL(374, compat_sys_sendmmsg) __SYSCALL(375, sys_setns) __SYSCALL(376, compat_sys_process_vm_readv) __SYSCALL(377, compat_sys_process_vm_writev) -__SYSCALL(378, sys_ni_syscall) /* 378 for kcmp */ +__SYSCALL(378, sys_kcmp) +__SYSCALL(379, sys_finit_module) +__SYSCALL(380, sys_sched_setattr) +__SYSCALL(381, sys_sched_getattr) #define __NR_compat_syscalls 379 diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 495ab6f84a6117..eaf54a30bedcef 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -148,6 +148,15 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_TIMER_CNT ARM64_SYS_REG(3, 3, 14, 3, 2) #define KVM_REG_ARM_TIMER_CVAL ARM64_SYS_REG(3, 3, 14, 0, 2) +/* Device Control API: ARM VGIC */ +#define KVM_DEV_ARM_VGIC_GRP_ADDR 0 +#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 +#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2 +#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32 +#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT) +#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0 +#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) + /* KVM_IRQ_LINE irq field index values */ #define KVM_ARM_IRQ_TYPE_SHIFT 24 #define KVM_ARM_IRQ_TYPE_MASK 0xff diff --git a/arch/arm64/kernel/kuser32.S b/arch/arm64/kernel/kuser32.S index 63c48ffdf23012..7787208e8cc6af 100644 --- a/arch/arm64/kernel/kuser32.S +++ b/arch/arm64/kernel/kuser32.S @@ -38,12 +38,13 @@ __kuser_cmpxchg64: // 0xffff0f60 .inst 0xe92d00f0 // push {r4, r5, r6, r7} .inst 0xe1c040d0 // ldrd r4, r5, [r0] .inst 0xe1c160d0 // ldrd r6, r7, [r1] - .inst 0xe1b20e9f // 1: ldaexd r0, r1, [r2] + .inst 0xe1b20f9f // 1: ldrexd r0, r1, [r2] .inst 0xe0303004 // eors r3, r0, r4 .inst 0x00313005 // eoreqs r3, r1, r5 .inst 0x01a23e96 // stlexdeq r3, r6, [r2] .inst 0x03330001 // teqeq r3, #1 .inst 0x0afffff9 // beq 1b + .inst 0xf57ff05b // dmb ish .inst 0xe2730000 // rsbs r0, r3, #0 .inst 0xe8bd00f0 // pop {r4, r5, r6, r7} .inst 0xe12fff1e // bx lr @@ -55,11 +56,12 @@ __kuser_memory_barrier: // 0xffff0fa0 .align 5 __kuser_cmpxchg: // 0xffff0fc0 - .inst 0xe1923e9f // 1: ldaex r3, [r2] + .inst 0xe1923f9f // 1: ldrex r3, [r2] .inst 0xe0533000 // subs r3, r3, r0 .inst 0x01823e91 // stlexeq r3, r1, [r2] .inst 0x03330001 // teqeq r3, #1 .inst 0x0afffffa // beq 1b + .inst 0xf57ff05b // dmb ish .inst 0xe2730000 // rsbs r0, r3, #0 .inst 0xe12fff1e // bx lr diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 248a15db37f2c0..1c0a9be2ffa85a 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -85,11 +85,6 @@ EXPORT_SYMBOL_GPL(pm_power_off); void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd); EXPORT_SYMBOL_GPL(arm_pm_restart); -void arch_cpu_idle_prepare(void) -{ - local_fiq_enable(); -} - /* * This is our default idle handler. */ @@ -138,7 +133,6 @@ void machine_restart(char *cmd) /* Disable interrupts first */ local_irq_disable(); - local_fiq_disable(); /* Now call the architecture specific reboot code. */ if (arm_pm_restart) diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 1b7617ab499be7..7cfb92a4ab6652 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -161,7 +161,6 @@ asmlinkage void secondary_start_kernel(void) complete(&cpu_running); local_irq_enable(); - local_fiq_enable(); local_async_enable(); /* @@ -495,7 +494,6 @@ static void ipi_cpu_stop(unsigned int cpu) set_cpu_online(cpu, false); - local_fiq_disable(); local_irq_disable(); while (1) diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c index 430344e2c98957..1fa9ce4afd8fa2 100644 --- a/arch/arm64/kernel/suspend.c +++ b/arch/arm64/kernel/suspend.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -89,6 +90,13 @@ int cpu_suspend(unsigned long arg) if (ret == 0) { cpu_switch_mm(mm->pgd, mm); flush_tlb_all(); + + /* + * Restore per-cpu offset before any kernel + * subsystem relying on it has a chance to run. + */ + set_my_cpu_offset(per_cpu_offset(cpu)); + /* * Restore HW breakpoint registers to sane values * before debug exceptions are possibly reenabled diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c index 65d40cf6945ac2..a7149cae16153b 100644 --- a/arch/arm64/kernel/vdso.c +++ b/arch/arm64/kernel/vdso.c @@ -238,6 +238,8 @@ void update_vsyscall(struct timekeeper *tk) vdso_data->use_syscall = use_syscall; vdso_data->xtime_coarse_sec = xtime_coarse.tv_sec; vdso_data->xtime_coarse_nsec = xtime_coarse.tv_nsec; + vdso_data->wtm_clock_sec = tk->wall_to_monotonic.tv_sec; + vdso_data->wtm_clock_nsec = tk->wall_to_monotonic.tv_nsec; if (!use_syscall) { vdso_data->cs_cycle_last = tk->clock->cycle_last; @@ -245,8 +247,6 @@ void update_vsyscall(struct timekeeper *tk) vdso_data->xtime_clock_nsec = tk->xtime_nsec; vdso_data->cs_mult = tk->mult; vdso_data->cs_shift = tk->shift; - vdso_data->wtm_clock_sec = tk->wall_to_monotonic.tv_sec; - vdso_data->wtm_clock_nsec = tk->wall_to_monotonic.tv_nsec; } smp_wmb(); diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile index d8064af42e6217..6d20b7d162d834 100644 --- a/arch/arm64/kernel/vdso/Makefile +++ b/arch/arm64/kernel/vdso/Makefile @@ -48,7 +48,7 @@ $(obj-vdso): %.o: %.S # Actual build commands quiet_cmd_vdsold = VDSOL $@ - cmd_vdsold = $(CC) $(c_flags) -Wl,-T $^ -o $@ + cmd_vdsold = $(CC) $(c_flags) -Wl,-n -Wl,-T $^ -o $@ quiet_cmd_vdsoas = VDSOA $@ cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $< diff --git a/arch/arm64/kernel/vdso/gettimeofday.S b/arch/arm64/kernel/vdso/gettimeofday.S index f0a6d10b521149..fe652ffd34c280 100644 --- a/arch/arm64/kernel/vdso/gettimeofday.S +++ b/arch/arm64/kernel/vdso/gettimeofday.S @@ -103,6 +103,8 @@ ENTRY(__kernel_clock_gettime) bl __do_get_tspec seqcnt_check w9, 1b + mov x30, x2 + cmp w0, #CLOCK_MONOTONIC b.ne 6f @@ -118,6 +120,9 @@ ENTRY(__kernel_clock_gettime) ccmp w0, #CLOCK_MONOTONIC_COARSE, #0x4, ne b.ne 8f + /* xtime_coarse_nsec is already right-shifted */ + mov x12, #0 + /* Get coarse timespec. */ adr vdso_data, _vdso_data 3: seqcnt_acquire @@ -156,7 +161,7 @@ ENTRY(__kernel_clock_gettime) lsr x11, x11, x12 stp x10, x11, [x1, #TSPEC_TV_SEC] mov x0, xzr - ret x2 + ret 7: mov x30, x2 8: /* Syscall fallback. */ diff --git a/arch/arm64/lib/bitops.S b/arch/arm64/lib/bitops.S index e5db797790d326..7dac371cc9a2f8 100644 --- a/arch/arm64/lib/bitops.S +++ b/arch/arm64/lib/bitops.S @@ -46,11 +46,12 @@ ENTRY( \name ) mov x2, #1 add x1, x1, x0, lsr #3 // Get word offset lsl x4, x2, x3 // Create mask -1: ldaxr x2, [x1] +1: ldxr x2, [x1] lsr x0, x2, x3 // Save old value of bit \instr x2, x2, x4 // toggle bit stlxr w5, x2, [x1] cbnz w5, 1b + dmb ish and x0, x0, #1 3: ret ENDPROC(\name ) diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S index 48a386094fa3cf..1ea9f26d1b7035 100644 --- a/arch/arm64/mm/cache.S +++ b/arch/arm64/mm/cache.S @@ -146,7 +146,7 @@ ENDPROC(flush_icache_range) ENDPROC(__flush_cache_user_range) /* - * __flush_kern_dcache_page(kaddr) + * __flush_dcache_area(kaddr, size) * * Ensure that the data held in the page kaddr is written back to the * page in question. diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 45b5ab54c9eeb0..fbd76785c5db64 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -45,6 +45,7 @@ static void *arm64_swiotlb_alloc_coherent(struct device *dev, size_t size, if (IS_ENABLED(CONFIG_DMA_CMA)) { struct page *page; + size = PAGE_ALIGN(size); page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT, get_order(size)); if (!page) diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index f557ebbe7013ed..f8dc7e8fce6fea 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -203,10 +203,18 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, do { next = pmd_addr_end(addr, end); /* try section mapping first */ - if (((addr | next | phys) & ~SECTION_MASK) == 0) + if (((addr | next | phys) & ~SECTION_MASK) == 0) { + pmd_t old_pmd =*pmd; set_pmd(pmd, __pmd(phys | prot_sect_kernel)); - else + /* + * Check for previous table entries created during + * boot (__create_page_tables) and flush them. + */ + if (!pmd_none(old_pmd)) + flush_tlb_all(); + } else { alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys)); + } phys += next - addr; } while (pmd++, addr = next, addr != end); } diff --git a/arch/arm64/mm/pgd.c b/arch/arm64/mm/pgd.c index 7083cdada657f2..62c6101df260e6 100644 --- a/arch/arm64/mm/pgd.c +++ b/arch/arm64/mm/pgd.c @@ -32,17 +32,10 @@ pgd_t *pgd_alloc(struct mm_struct *mm) { - pgd_t *new_pgd; - if (PGD_SIZE == PAGE_SIZE) - new_pgd = (pgd_t *)get_zeroed_page(GFP_KERNEL); + return (pgd_t *)get_zeroed_page(GFP_KERNEL); else - new_pgd = kzalloc(PGD_SIZE, GFP_KERNEL); - - if (!new_pgd) - return NULL; - - return new_pgd; + return kzalloc(PGD_SIZE, GFP_KERNEL); } void pgd_free(struct mm_struct *mm, pgd_t *pgd) diff --git a/arch/arm64/mm/proc-macros.S b/arch/arm64/mm/proc-macros.S index 8957b822010b47..005d29e2977da0 100644 --- a/arch/arm64/mm/proc-macros.S +++ b/arch/arm64/mm/proc-macros.S @@ -38,8 +38,7 @@ */ .macro dcache_line_size, reg, tmp mrs \tmp, ctr_el0 // read CTR - lsr \tmp, \tmp, #16 - and \tmp, \tmp, #0xf // cache line size encoding + ubfm \tmp, \tmp, #16, #19 // cache line size encoding mov \reg, #4 // bytes per word lsl \reg, \reg, \tmp // actual cache line size .endm diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index bed1f1de1caf07..1333e6f9a8e50b 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -150,7 +150,7 @@ ENDPROC(cpu_do_resume) #endif /* - * cpu_switch_mm(pgd_phys, tsk) + * cpu_do_switch_mm(pgd_phys, tsk) * * Set the translation table base pointer to be pgd_phys. * diff --git a/arch/avr32/Makefile b/arch/avr32/Makefile index 22fb66590dcd0e..dba48a5d5bb9db 100644 --- a/arch/avr32/Makefile +++ b/arch/avr32/Makefile @@ -11,7 +11,7 @@ all: uImage vmlinux.elf KBUILD_DEFCONFIG := atstk1002_defconfig -KBUILD_CFLAGS += -pipe -fno-builtin -mno-pic +KBUILD_CFLAGS += -pipe -fno-builtin -mno-pic -D__linux__ KBUILD_AFLAGS += -mrelax -mno-pic KBUILD_CFLAGS_MODULE += -mno-relax LDFLAGS_vmlinux += --relax diff --git a/arch/avr32/boards/mimc200/fram.c b/arch/avr32/boards/mimc200/fram.c index 9764a1a1073e93..c1466a872b9c85 100644 --- a/arch/avr32/boards/mimc200/fram.c +++ b/arch/avr32/boards/mimc200/fram.c @@ -11,6 +11,7 @@ #define FRAM_VERSION "1.0" #include +#include #include #include #include diff --git a/arch/avr32/include/asm/Kbuild b/arch/avr32/include/asm/Kbuild index cfb9fe1b8df952..c7c64a63c29f47 100644 --- a/arch/avr32/include/asm/Kbuild +++ b/arch/avr32/include/asm/Kbuild @@ -17,5 +17,6 @@ generic-y += scatterlist.h generic-y += sections.h generic-y += topology.h generic-y += trace_clock.h +generic-y += vga.h generic-y += xor.h generic-y += hash.h diff --git a/arch/avr32/include/asm/io.h b/arch/avr32/include/asm/io.h index fc6483f83ccca7..4f5ec2bb717272 100644 --- a/arch/avr32/include/asm/io.h +++ b/arch/avr32/include/asm/io.h @@ -295,6 +295,8 @@ extern void __iounmap(void __iomem *addr); #define iounmap(addr) \ __iounmap(addr) +#define ioremap_wc ioremap_nocache + #define cached(addr) P1SEGADDR(addr) #define uncached(addr) P2SEGADDR(addr) diff --git a/arch/blackfin/configs/BF527-EZKIT_defconfig b/arch/blackfin/configs/BF527-EZKIT_defconfig index 90b1753236446f..af2738c7441b4c 100644 --- a/arch/blackfin/configs/BF527-EZKIT_defconfig +++ b/arch/blackfin/configs/BF527-EZKIT_defconfig @@ -146,6 +146,7 @@ CONFIG_USB_DEVICEFS=y CONFIG_USB_OTG_BLACKLIST_HUB=y CONFIG_USB_MON=y CONFIG_USB_MUSB_HDRC=y +CONFIG_MUSB_PIO_ONLY=y CONFIG_USB_MUSB_BLACKFIN=y CONFIG_MUSB_PIO_ONLY=y CONFIG_USB_STORAGE=y diff --git a/arch/blackfin/configs/BF538-EZKIT_defconfig b/arch/blackfin/configs/BF538-EZKIT_defconfig index 972aa6263ad0a9..be03be6ba5436e 100644 --- a/arch/blackfin/configs/BF538-EZKIT_defconfig +++ b/arch/blackfin/configs/BF538-EZKIT_defconfig @@ -59,7 +59,6 @@ CONFIG_BFIN_SIR=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=m CONFIG_MTD_BLOCK=y diff --git a/arch/blackfin/configs/BF561-ACVILON_defconfig b/arch/blackfin/configs/BF561-ACVILON_defconfig index 91988370b75e03..802f9c42162176 100644 --- a/arch/blackfin/configs/BF561-ACVILON_defconfig +++ b/arch/blackfin/configs/BF561-ACVILON_defconfig @@ -49,7 +49,6 @@ CONFIG_SYN_COOKIES=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y diff --git a/arch/blackfin/configs/BlackStamp_defconfig b/arch/blackfin/configs/BlackStamp_defconfig index 7b982d0502addd..3853c473b44319 100644 --- a/arch/blackfin/configs/BlackStamp_defconfig +++ b/arch/blackfin/configs/BlackStamp_defconfig @@ -44,7 +44,6 @@ CONFIG_IP_PNP=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=m CONFIG_MTD_BLOCK=y diff --git a/arch/blackfin/configs/CM-BF533_defconfig b/arch/blackfin/configs/CM-BF533_defconfig index c940a1e3ab3685..5e0db82b679ea6 100644 --- a/arch/blackfin/configs/CM-BF533_defconfig +++ b/arch/blackfin/configs/CM-BF533_defconfig @@ -36,7 +36,6 @@ CONFIG_UNIX=y # CONFIG_WIRELESS is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y diff --git a/arch/blackfin/configs/CM-BF548_defconfig b/arch/blackfin/configs/CM-BF548_defconfig index e961483f1879bf..b9af4fa69984d2 100644 --- a/arch/blackfin/configs/CM-BF548_defconfig +++ b/arch/blackfin/configs/CM-BF548_defconfig @@ -53,7 +53,6 @@ CONFIG_INET_XFRM_MODE_BEET=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y diff --git a/arch/blackfin/configs/CM-BF561_defconfig b/arch/blackfin/configs/CM-BF561_defconfig index 24936b91a6ee22..d6dd98e671463b 100644 --- a/arch/blackfin/configs/CM-BF561_defconfig +++ b/arch/blackfin/configs/CM-BF561_defconfig @@ -51,7 +51,6 @@ CONFIG_INET=y # CONFIG_WIRELESS is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y diff --git a/arch/blackfin/configs/DNP5370_defconfig b/arch/blackfin/configs/DNP5370_defconfig index 89162d0fff9ea6..2b58cb2212837f 100644 --- a/arch/blackfin/configs/DNP5370_defconfig +++ b/arch/blackfin/configs/DNP5370_defconfig @@ -36,7 +36,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y CONFIG_MTD_DEBUG=y CONFIG_MTD_DEBUG_VERBOSE=1 -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_NFTL=y diff --git a/arch/blackfin/configs/H8606_defconfig b/arch/blackfin/configs/H8606_defconfig index a26436bf50fff2..f754e490bbfd00 100644 --- a/arch/blackfin/configs/H8606_defconfig +++ b/arch/blackfin/configs/H8606_defconfig @@ -36,7 +36,6 @@ CONFIG_IRTTY_SIR=m # CONFIG_WIRELESS is not set # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_RAM=y diff --git a/arch/blackfin/configs/IP0X_defconfig b/arch/blackfin/configs/IP0X_defconfig index 647991514ac9b8..629516578760cf 100644 --- a/arch/blackfin/configs/IP0X_defconfig +++ b/arch/blackfin/configs/IP0X_defconfig @@ -43,7 +43,6 @@ CONFIG_IP_NF_TARGET_REJECT=y CONFIG_IP_NF_MANGLE=y # CONFIG_WIRELESS is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y diff --git a/arch/blackfin/configs/PNAV-10_defconfig b/arch/blackfin/configs/PNAV-10_defconfig index 8fd9b446d6583f..a6a7298962edcd 100644 --- a/arch/blackfin/configs/PNAV-10_defconfig +++ b/arch/blackfin/configs/PNAV-10_defconfig @@ -46,7 +46,6 @@ CONFIG_IP_PNP=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=m CONFIG_MTD_BLOCK=y CONFIG_MTD_RAM=y diff --git a/arch/blackfin/configs/SRV1_defconfig b/arch/blackfin/configs/SRV1_defconfig index 0520c160230de1..bc216646fe1864 100644 --- a/arch/blackfin/configs/SRV1_defconfig +++ b/arch/blackfin/configs/SRV1_defconfig @@ -38,7 +38,6 @@ CONFIG_IRTTY_SIR=m # CONFIG_WIRELESS is not set # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=m CONFIG_MTD_BLOCK=y CONFIG_MTD_JEDECPROBE=m diff --git a/arch/blackfin/configs/TCM-BF518_defconfig b/arch/blackfin/configs/TCM-BF518_defconfig index e4ed865b885e3a..ea88158ab432c7 100644 --- a/arch/blackfin/configs/TCM-BF518_defconfig +++ b/arch/blackfin/configs/TCM-BF518_defconfig @@ -54,7 +54,6 @@ CONFIG_IP_PNP=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y diff --git a/arch/blackfin/include/asm/def_LPBlackfin.h b/arch/blackfin/include/asm/def_LPBlackfin.h index ca67145c6a4598..c5c8d8a3a5fada 100644 --- a/arch/blackfin/include/asm/def_LPBlackfin.h +++ b/arch/blackfin/include/asm/def_LPBlackfin.h @@ -544,6 +544,7 @@ do { \ #define DCBS_P 0x04 /* L1 Data Cache Bank Select */ #define PORT_PREF0_P 0x12 /* DAG0 Port Preference */ #define PORT_PREF1_P 0x13 /* DAG1 Port Preference */ +#define RDCHK 0x9 /* Enable L1 Parity Check */ /* Masks */ #define ENDM 0x00000001 /* (doesn't really exist) Enable diff --git a/arch/blackfin/include/uapi/asm/byteorder.h b/arch/blackfin/include/uapi/asm/byteorder.h index 9558416d578b58..3b125da5dcb233 100644 --- a/arch/blackfin/include/uapi/asm/byteorder.h +++ b/arch/blackfin/include/uapi/asm/byteorder.h @@ -1 +1,6 @@ +#ifndef _UAPI__BFIN_ASM_BYTEORDER_H +#define _UAPI__BFIN_ASM_BYTEORDER_H + #include + +#endif /* _UAPI__BFIN_ASM_BYTEORDER_H */ diff --git a/arch/blackfin/include/uapi/asm/cachectl.h b/arch/blackfin/include/uapi/asm/cachectl.h index 03255df6c1ea0a..4fdab75dee1597 100644 --- a/arch/blackfin/include/uapi/asm/cachectl.h +++ b/arch/blackfin/include/uapi/asm/cachectl.h @@ -7,8 +7,8 @@ * Licensed under the GPL-2 or later. */ -#ifndef _ASM_CACHECTL -#define _ASM_CACHECTL +#ifndef _UAPI_ASM_CACHECTL +#define _UAPI_ASM_CACHECTL /* * Options for cacheflush system call @@ -17,4 +17,4 @@ #define DCACHE (1<<1) /* writeback and flush data cache */ #define BCACHE (ICACHE|DCACHE) /* flush both caches */ -#endif /* _ASM_CACHECTL */ +#endif /* _UAPI_ASM_CACHECTL */ diff --git a/arch/blackfin/include/uapi/asm/fcntl.h b/arch/blackfin/include/uapi/asm/fcntl.h index 251c911d59c118..f51ad9a4f617ad 100644 --- a/arch/blackfin/include/uapi/asm/fcntl.h +++ b/arch/blackfin/include/uapi/asm/fcntl.h @@ -4,8 +4,8 @@ * Licensed under the GPL-2 or later. */ -#ifndef _BFIN_FCNTL_H -#define _BFIN_FCNTL_H +#ifndef _UAPI_BFIN_FCNTL_H +#define _UAPI_BFIN_FCNTL_H #define O_DIRECTORY 040000 /* must be a directory */ #define O_NOFOLLOW 0100000 /* don't follow links */ @@ -14,4 +14,4 @@ #include -#endif +#endif /* _UAPI_BFIN_FCNTL_H */ diff --git a/arch/blackfin/include/uapi/asm/ioctls.h b/arch/blackfin/include/uapi/asm/ioctls.h index eca8d75b0a8a4c..9a41c20fc83da4 100644 --- a/arch/blackfin/include/uapi/asm/ioctls.h +++ b/arch/blackfin/include/uapi/asm/ioctls.h @@ -1,7 +1,7 @@ -#ifndef __ARCH_BFIN_IOCTLS_H__ -#define __ARCH_BFIN_IOCTLS_H__ +#ifndef _UAPI__ARCH_BFIN_IOCTLS_H__ +#define _UAPI__ARCH_BFIN_IOCTLS_H__ #define FIOQSIZE 0x545E #include -#endif +#endif /* _UAPI__ARCH_BFIN_IOCTLS_H__ */ diff --git a/arch/blackfin/include/uapi/asm/poll.h b/arch/blackfin/include/uapi/asm/poll.h index 072d8966c5c3cc..99c7d6816da0bd 100644 --- a/arch/blackfin/include/uapi/asm/poll.h +++ b/arch/blackfin/include/uapi/asm/poll.h @@ -5,12 +5,12 @@ * */ -#ifndef __BFIN_POLL_H -#define __BFIN_POLL_H +#ifndef _UAPI__BFIN_POLL_H +#define _UAPI__BFIN_POLL_H #define POLLWRNORM 4 /* POLLOUT */ #define POLLWRBAND 256 #include -#endif +#endif /* _UAPI__BFIN_POLL_H */ diff --git a/arch/blackfin/include/uapi/asm/posix_types.h b/arch/blackfin/include/uapi/asm/posix_types.h index 1bd3436db6a7b7..9608ef64dc473d 100644 --- a/arch/blackfin/include/uapi/asm/posix_types.h +++ b/arch/blackfin/include/uapi/asm/posix_types.h @@ -4,8 +4,8 @@ * Licensed under the GPL-2 or later. */ -#ifndef __ARCH_BFIN_POSIX_TYPES_H -#define __ARCH_BFIN_POSIX_TYPES_H +#ifndef _UAPI__ARCH_BFIN_POSIX_TYPES_H +#define _UAPI__ARCH_BFIN_POSIX_TYPES_H typedef unsigned short __kernel_mode_t; #define __kernel_mode_t __kernel_mode_t @@ -27,4 +27,4 @@ typedef unsigned short __kernel_old_dev_t; #include -#endif +#endif /* _UAPI__ARCH_BFIN_POSIX_TYPES_H */ diff --git a/arch/blackfin/include/uapi/asm/sigcontext.h b/arch/blackfin/include/uapi/asm/sigcontext.h index 906bdc1f5fda7c..b58f12dc27bd23 100644 --- a/arch/blackfin/include/uapi/asm/sigcontext.h +++ b/arch/blackfin/include/uapi/asm/sigcontext.h @@ -4,8 +4,8 @@ * Licensed under the GPL-2 or later. */ -#ifndef _ASM_BLACKFIN_SIGCONTEXT_H -#define _ASM_BLACKFIN_SIGCONTEXT_H +#ifndef _UAPI_ASM_BLACKFIN_SIGCONTEXT_H +#define _UAPI_ASM_BLACKFIN_SIGCONTEXT_H /* Add new entries at the end of the structure only. */ struct sigcontext { @@ -58,4 +58,4 @@ struct sigcontext { unsigned long sc_seqstat; }; -#endif +#endif /* _UAPI_ASM_BLACKFIN_SIGCONTEXT_H */ diff --git a/arch/blackfin/include/uapi/asm/siginfo.h b/arch/blackfin/include/uapi/asm/siginfo.h index 3e81306394e20f..c72f4e6e386fa3 100644 --- a/arch/blackfin/include/uapi/asm/siginfo.h +++ b/arch/blackfin/include/uapi/asm/siginfo.h @@ -4,8 +4,8 @@ * Licensed under the GPL-2 or later. */ -#ifndef _BFIN_SIGINFO_H -#define _BFIN_SIGINFO_H +#ifndef _UAPI_BFIN_SIGINFO_H +#define _UAPI_BFIN_SIGINFO_H #include #include @@ -38,4 +38,4 @@ */ #define SEGV_STACKFLOW (__SI_FAULT|3) /* stack overflow */ -#endif +#endif /* _UAPI_BFIN_SIGINFO_H */ diff --git a/arch/blackfin/include/uapi/asm/signal.h b/arch/blackfin/include/uapi/asm/signal.h index 77a3bf37b69d6b..f0a0d8b6663a69 100644 --- a/arch/blackfin/include/uapi/asm/signal.h +++ b/arch/blackfin/include/uapi/asm/signal.h @@ -1,7 +1,7 @@ -#ifndef _BLACKFIN_SIGNAL_H -#define _BLACKFIN_SIGNAL_H +#ifndef _UAPI_BLACKFIN_SIGNAL_H +#define _UAPI_BLACKFIN_SIGNAL_H #define SA_RESTORER 0x04000000 #include -#endif +#endif /* _UAPI_BLACKFIN_SIGNAL_H */ diff --git a/arch/blackfin/include/uapi/asm/stat.h b/arch/blackfin/include/uapi/asm/stat.h index 2e27665c4e9195..d3068a750b94fd 100644 --- a/arch/blackfin/include/uapi/asm/stat.h +++ b/arch/blackfin/include/uapi/asm/stat.h @@ -4,8 +4,8 @@ * Licensed under the GPL-2. */ -#ifndef _BFIN_STAT_H -#define _BFIN_STAT_H +#ifndef _UAPI_BFIN_STAT_H +#define _UAPI_BFIN_STAT_H struct stat { unsigned short st_dev; @@ -66,4 +66,4 @@ struct stat64 { unsigned long long st_ino; }; -#endif /* _BFIN_STAT_H */ +#endif /* _UAPI_BFIN_STAT_H */ diff --git a/arch/blackfin/include/uapi/asm/swab.h b/arch/blackfin/include/uapi/asm/swab.h index 89de6507ca2bbd..f5626b77684a71 100644 --- a/arch/blackfin/include/uapi/asm/swab.h +++ b/arch/blackfin/include/uapi/asm/swab.h @@ -4,8 +4,8 @@ * Licensed under the GPL-2 or later. */ -#ifndef _BLACKFIN_SWAB_H -#define _BLACKFIN_SWAB_H +#ifndef _UAPI_BLACKFIN_SWAB_H +#define _UAPI_BLACKFIN_SWAB_H #include #include @@ -47,4 +47,4 @@ static __inline__ __attribute_const__ __u16 __arch_swab16(__u16 xx) #endif /* __GNUC__ */ -#endif /* _BLACKFIN_SWAB_H */ +#endif /* _UAPI_BLACKFIN_SWAB_H */ diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 3961930421274b..4f424ae3b36de8 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -17,7 +17,7 @@ #ifdef CONFIG_MTD_UCLINUX #include #include -#include +#include #include #endif diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c index 4a8c2e3fd7e564..4da70c47cc0552 100644 --- a/arch/blackfin/mach-bf533/boards/stamp.c +++ b/arch/blackfin/mach-bf533/boards/stamp.c @@ -370,7 +370,8 @@ static struct platform_device bfin_sir0_device = { #endif #endif -#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE) +#if defined(CONFIG_SERIAL_BFIN_SPORT) || \ + defined(CONFIG_SERIAL_BFIN_SPORT_MODULE) #ifdef CONFIG_SERIAL_BFIN_SPORT0_UART static struct resource bfin_sport0_uart_resources[] = { { @@ -441,6 +442,50 @@ static struct platform_device bfin_sport1_uart_device = { #endif #endif +#if defined(CONFIG_BFIN_SPORT) || defined(CONFIG_BFIN_SPORT_MODULE) +static struct resource bfin_sport0_resources[] = { + { + .start = SPORT0_TCR1, + .end = SPORT0_MRCS3+4, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_SPORT0_TX, + .end = IRQ_SPORT0_TX+1, + .flags = IORESOURCE_IRQ, + }, + { + .start = IRQ_SPORT0_RX, + .end = IRQ_SPORT0_RX+1, + .flags = IORESOURCE_IRQ, + }, + { + .start = IRQ_SPORT0_ERROR, + .end = IRQ_SPORT0_ERROR, + .flags = IORESOURCE_IRQ, + }, + { + .start = CH_SPORT0_TX, + .end = CH_SPORT0_TX, + .flags = IORESOURCE_DMA, + }, + { + .start = CH_SPORT0_RX, + .end = CH_SPORT0_RX, + .flags = IORESOURCE_DMA, + }, +}; +static struct platform_device bfin_sport0_device = { + .name = "bfin_sport_raw", + .id = 0, + .num_resources = ARRAY_SIZE(bfin_sport0_resources), + .resource = bfin_sport0_resources, + .dev = { + .platform_data = &bfin_sport0_peripherals, + }, +}; +#endif + #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) #include #include diff --git a/arch/blackfin/mach-bf609/Kconfig b/arch/blackfin/mach-bf609/Kconfig index b0fca44110b032..6584190faeb809 100644 --- a/arch/blackfin/mach-bf609/Kconfig +++ b/arch/blackfin/mach-bf609/Kconfig @@ -17,6 +17,12 @@ config SEC_IRQ_PRIORITY_LEVELS Divide the total number of interrupt priority levels into sub-levels. There is 2 ^ (SEC_IRQ_PRIORITY_LEVELS + 1) different levels. +config L1_PARITY_CHECK + bool "Enable L1 parity check" + default n + help + Enable the L1 parity check in L1 sram. A fault event is raised + when L1 parity error is found. comment "System Cross Bar Priority Assignment" diff --git a/arch/blackfin/mach-bf609/boards/ezkit.c b/arch/blackfin/mach-bf609/boards/ezkit.c index 05194e95981b8f..8de8bc690b36f8 100644 --- a/arch/blackfin/mach-bf609/boards/ezkit.c +++ b/arch/blackfin/mach-bf609/boards/ezkit.c @@ -1025,7 +1025,9 @@ static struct adv7842_platform_data adv7842_data = { .ain_sel = ADV7842_AIN10_11_12_NC_SYNC_4_1, .prim_mode = ADV7842_PRIM_MODE_SDP, .vid_std_select = ADV7842_SDP_VID_STD_CVBS_SD_4x1, - .inp_color_space = ADV7842_INP_COLOR_SPACE_AUTO, + .hdmi_free_run_enable = 1, + .sdp_free_run_auto = 1, + .llc_dll_phase = 0x10, .i2c_sdp_io = 0x40, .i2c_sdp = 0x41, .i2c_cp = 0x42, diff --git a/arch/blackfin/mach-bf609/clock.c b/arch/blackfin/mach-bf609/clock.c index dab8849af884a5..13644ed25489de 100644 --- a/arch/blackfin/mach-bf609/clock.c +++ b/arch/blackfin/mach-bf609/clock.c @@ -120,6 +120,7 @@ void clk_disable(struct clk *clk) } EXPORT_SYMBOL(clk_disable); + unsigned long clk_get_rate(struct clk *clk) { unsigned long ret = 0; @@ -131,7 +132,7 @@ EXPORT_SYMBOL(clk_get_rate); long clk_round_rate(struct clk *clk, unsigned long rate) { - long ret = -EIO; + long ret = 0; if (clk->ops && clk->ops->round_rate) ret = clk->ops->round_rate(clk, rate); return ret; diff --git a/arch/blackfin/mach-bf609/include/mach/anomaly.h b/arch/blackfin/mach-bf609/include/mach/anomaly.h index 7a07374308aca4..696786e9a53147 100644 --- a/arch/blackfin/mach-bf609/include/mach/anomaly.h +++ b/arch/blackfin/mach-bf609/include/mach/anomaly.h @@ -23,11 +23,11 @@ /* TRU_STAT.ADDRERR and TRU_ERRADDR.ADDR May Not Reflect the Correct Status */ #define ANOMALY_16000003 (1) /* The EPPI Data Enable (DEN) Signal is Not Functional */ -#define ANOMALY_16000004 (1) +#define ANOMALY_16000004 (__SILICON_REVISION__ < 1) /* Using L1 Instruction Cache with Parity Enabled is Unreliable */ -#define ANOMALY_16000005 (1) +#define ANOMALY_16000005 (__SILICON_REVISION__ < 1) /* SEQSTAT.SYSNMI Clears Upon Entering the NMI ISR */ -#define ANOMALY_16000006 (1) +#define ANOMALY_16000006 (__SILICON_REVISION__ < 1) /* DDR2 Memory Reads May Fail Intermittently */ #define ANOMALY_16000007 (1) /* Instruction Memory Stalls Can Cause IFLUSH to Fail */ @@ -49,19 +49,53 @@ /* Speculative Fetches Can Cause Undesired External FIFO Operations */ #define ANOMALY_16000017 (1) /* RSI Boot Cleanup Routine Does Not Clear Registers */ -#define ANOMALY_16000018 (1) +#define ANOMALY_16000018 (__SILICON_REVISION__ < 1) /* SPI Master Boot Device Auto-detection Frequency is Set Incorrectly */ -#define ANOMALY_16000019 (1) +#define ANOMALY_16000019 (__SILICON_REVISION__ < 1) /* rom_SysControl() Fails to Set DDR0_CTL.INIT for Wakeup From Hibernate */ -#define ANOMALY_16000020 (1) +#define ANOMALY_16000020 (__SILICON_REVISION__ < 1) /* rom_SysControl() Fails to Save and Restore DDR0_PHYCTL3 for Hibernate/Wakeup Sequence */ -#define ANOMALY_16000021 (1) +#define ANOMALY_16000021 (__SILICON_REVISION__ < 1) /* Boot Code Fails to Enable Parity Fault Detection */ -#define ANOMALY_16000022 (1) +#define ANOMALY_16000022 (__SILICON_REVISION__ < 1) +/* Rom_SysControl Does not Update CGU0_CLKOUTSEL */ +#define ANOMALY_16000023 (__SILICON_REVISION__ < 1) +/* Spurious Fault Signaled After Clearing an Externally Generated Fault */ +#define ANOMALY_16000024 (1) +/* SPORT May Drive Data Pins During Inactive Channels in Multichannel Mode */ +#define ANOMALY_16000025 (1) /* USB DMA interrupt status do not show the DMA channel interrupt in the DMA ISR */ -#define ANOMALY_16000027 (1) +#define ANOMALY_16000027 (__SILICON_REVISION__ < 1) +/* Default SPI Master Boot Mode Setting is Incorrect */ +#define ANOMALY_16000028 (__SILICON_REVISION__ < 1) +/* PPI tDFSPI Timing Does Not Meet Data Sheet Specification */ +#define ANOMALY_16000027 (__SILICON_REVISION__ < 1) /* Interrupted Core Reads of MMRs May Cause Data Loss */ -#define ANOMALY_16000030 (1) +#define ANOMALY_16000030 (__SILICON_REVISION__ < 1) +/* Incorrect Default USB_PLL_OSC.PLLM Value */ +#define ANOMALY_16000031 (__SILICON_REVISION__ < 1) +/* Core Reads of System MMRs May Cause the Core to Hang */ +#define ANOMALY_16000032 (__SILICON_REVISION__ < 1) +/* PPI Data Underflow on First Word Not Reported in Certain Modes */ +#define ANOMALY_16000033 (1) +/* CNV1 Red Pixel Substitution feature not functional in the PVP */ +#define ANOMALY_16000034 (__SILICON_REVISION__ < 1) +/* IPF0 Output Port Color Separation feature not functional */ +#define ANOMALY_16000035 (__SILICON_REVISION__ < 1) +/* Spurious USB Wake From Hibernate May Occur When USB_VBUS is Low */ +#define ANOMALY_16000036 (__SILICON_REVISION__ < 1) +/* Core RAISE 2 Instruction Not Latched When Executed at Priority Level 0, 1, or 2 */ +#define ANOMALY_16000037 (__SILICON_REVISION__ < 1) +/* Spurious Unhandled NMI or L1 Memory Parity Error Interrupt May Occur Upon Entering the NMI ISR */ +#define ANOMALY_16000038 (__SILICON_REVISION__ < 1) +/* CGU_STAT.PLOCKERR Bit May be Unreliable */ +#define ANOMALY_16000039 (1) +/* JTAG Emulator Reads of SDU_IDCODE Alter Register Contents */ +#define ANOMALY_16000040 (1) +/* IFLUSH Instruction Causes Parity Error When Parity Is Enabled */ +#define ANOMALY_16000041 (1) +/* Instruction Cache Failure When Parity Is Enabled */ +#define ANOMALY_16000042 (__SILICON_REVISION__ == 1) /* Anomalies that don't exist on this proc */ #define ANOMALY_05000158 (0) diff --git a/arch/blackfin/mach-common/cache-c.c b/arch/blackfin/mach-common/cache-c.c index 0e1e451fd7d81a..f4adedc9289563 100644 --- a/arch/blackfin/mach-common/cache-c.c +++ b/arch/blackfin/mach-common/cache-c.c @@ -6,7 +6,6 @@ * Licensed under the GPL-2 or later. */ -#include #include #include @@ -42,6 +41,16 @@ bfin_cache_init(struct cplb_entry *cplb_tbl, unsigned long cplb_addr, unsigned long mem_mask) { int i; +#ifdef CONFIG_L1_PARITY_CHECK + u32 ctrl; + + if (cplb_addr == DCPLB_ADDR0) { + ctrl = bfin_read32(mem_control) | (1 << RDCHK); + CSYNC(); + bfin_write32(mem_control, ctrl); + SSYNC(); + } +#endif for (i = 0; i < MAX_CPLBS; i++) { bfin_write32(cplb_addr + i * 4, cplb_tbl[i].addr); diff --git a/arch/blackfin/mach-common/clocks-init.c b/arch/blackfin/mach-common/clocks-init.c index 2308ce52f849b5..d436bd907fc8c6 100644 --- a/arch/blackfin/mach-common/clocks-init.c +++ b/arch/blackfin/mach-common/clocks-init.c @@ -7,7 +7,6 @@ */ #include -#include #include #include diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c index ca75613231c844..867b7cef204cb9 100644 --- a/arch/blackfin/mach-common/ints-priority.c +++ b/arch/blackfin/mach-common/ints-priority.c @@ -471,13 +471,8 @@ void handle_sec_ssi_fault(uint32_t gstat) } -void handle_sec_fault(unsigned int irq, struct irq_desc *desc) +void handle_sec_fault(uint32_t sec_gstat) { - uint32_t sec_gstat; - - raw_spin_lock(&desc->lock); - - sec_gstat = bfin_read32(SEC_GSTAT); if (sec_gstat & SEC_GSTAT_ERR) { switch (sec_gstat & SEC_GSTAT_ERRC) { @@ -494,18 +489,16 @@ void handle_sec_fault(unsigned int irq, struct irq_desc *desc) } - - raw_spin_unlock(&desc->lock); - - handle_fasteoi_irq(irq, desc); } -void handle_core_fault(unsigned int irq, struct irq_desc *desc) +static struct irqaction bfin_fault_irq = { + .name = "Blackfin fault", +}; + +static irqreturn_t bfin_fault_routine(int irq, void *data) { struct pt_regs *fp = get_irq_regs(); - raw_spin_lock(&desc->lock); - switch (irq) { case IRQ_C0_DBL_FAULT: double_fault_c(fp); @@ -522,11 +515,15 @@ void handle_core_fault(unsigned int irq, struct irq_desc *desc) case IRQ_C0_NMI_L1_PARITY_ERR: panic("Core 0 NMI L1 parity error"); break; + case IRQ_SEC_ERR: + pr_err("SEC error\n"); + handle_sec_fault(bfin_read32(SEC_GSTAT)); + break; default: - panic("Core 1 fault %d occurs unexpectedly", irq); + panic("Unknown fault %d", irq); } - raw_spin_unlock(&desc->lock); + return IRQ_HANDLED; } #endif /* SEC_GCTL */ @@ -1195,12 +1192,7 @@ int __init init_arch_irq(void) handle_percpu_irq); } else { irq_set_chip(irq, &bfin_sec_irqchip); - if (irq == IRQ_SEC_ERR) - irq_set_handler(irq, handle_sec_fault); - else if (irq >= IRQ_C0_DBL_FAULT && irq < CORE_IRQS) - irq_set_handler(irq, handle_core_fault); - else - irq_set_handler(irq, handle_fasteoi_irq); + irq_set_handler(irq, handle_fasteoi_irq); __irq_set_preflow_handler(irq, bfin_sec_preflow_handler); } } @@ -1239,6 +1231,13 @@ int __init init_arch_irq(void) register_syscore_ops(&sec_pm_syscore_ops); #endif + bfin_fault_irq.handler = bfin_fault_routine; +#ifdef CONFIG_L1_PARITY_CHECK + setup_irq(IRQ_C0_NMI_L1_PARITY_ERR, &bfin_fault_irq); +#endif + setup_irq(IRQ_C0_DBL_FAULT, &bfin_fault_irq); + setup_irq(IRQ_SEC_ERR, &bfin_fault_irq); + return 0; } diff --git a/arch/blackfin/mach-common/scb-init.c b/arch/blackfin/mach-common/scb-init.c index 2cbfb0b5679ee8..8923398db66f01 100644 --- a/arch/blackfin/mach-common/scb-init.c +++ b/arch/blackfin/mach-common/scb-init.c @@ -6,7 +6,6 @@ * Licensed under the GPL-2 or later. */ -#include #include #include #include diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c index 2bbae078381989..ba6c30d8534d0d 100644 --- a/arch/blackfin/mach-common/smp.c +++ b/arch/blackfin/mach-common/smp.c @@ -53,7 +53,6 @@ enum ipi_message_type { BFIN_IPI_TIMER, BFIN_IPI_RESCHEDULE, BFIN_IPI_CALL_FUNC, - BFIN_IPI_CALL_FUNC_SINGLE, BFIN_IPI_CPU_STOP, }; @@ -162,9 +161,6 @@ static irqreturn_t ipi_handler_int1(int irq, void *dev_instance) case BFIN_IPI_CALL_FUNC: generic_smp_call_function_interrupt(); break; - case BFIN_IPI_CALL_FUNC_SINGLE: - generic_smp_call_function_single_interrupt(); - break; case BFIN_IPI_CPU_STOP: ipi_cpu_stop(cpu); break; @@ -210,7 +206,7 @@ void send_ipi(const struct cpumask *cpumask, enum ipi_message_type msg) void arch_send_call_function_single_ipi(int cpu) { - send_ipi(cpumask_of(cpu), BFIN_IPI_CALL_FUNC_SINGLE); + send_ipi(cpumask_of(cpu), BFIN_IPI_CALL_FUNC); } void arch_send_call_function_ipi_mask(const struct cpumask *mask) diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index 9c957c81c6885a..ed0fcdf7e9905c 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -122,12 +122,6 @@ config ETRAX100LX_V2 help Support version 2 of the ETRAX 100LX. -config SVINTO_SIM - bool "ETRAX-100LX-for-xsim-simulator" - select ARCH_USES_GETTIMEOFFSET - help - Support the xsim ETRAX Simulator. - config ETRAXFS bool "ETRAX-FS-V32" help diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c index 609d5510410e06..f4374bae4fb4e6 100644 --- a/arch/cris/arch-v10/drivers/gpio.c +++ b/arch/cris/arch-v10/drivers/gpio.c @@ -838,13 +838,13 @@ static int __init gpio_init(void) * in some tests. */ res = request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt, - IRQF_SHARED | IRQF_DISABLED, "gpio poll", gpio_name); + IRQF_SHARED, "gpio poll", gpio_name); if (res) { printk(KERN_CRIT "err: timer0 irq for gpio\n"); return res; } res = request_irq(PA_IRQ_NBR, gpio_interrupt, - IRQF_SHARED | IRQF_DISABLED, "gpio PA", gpio_name); + IRQF_SHARED, "gpio PA", gpio_name); if (res) printk(KERN_CRIT "err: PA irq for gpio\n"); diff --git a/arch/cris/arch-v10/drivers/sync_serial.c b/arch/cris/arch-v10/drivers/sync_serial.c index a1c498d18d3184..29eb02ab3f259f 100644 --- a/arch/cris/arch-v10/drivers/sync_serial.c +++ b/arch/cris/arch-v10/drivers/sync_serial.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -580,7 +581,7 @@ static int sync_serial_open(struct inode *inode, struct file *file) if (port == &ports[0]) { if (request_irq(8, manual_interrupt, - IRQF_SHARED | IRQF_DISABLED, + IRQF_SHARED, "synchronous serial manual irq", &ports[0])) { printk(KERN_CRIT "Can't alloc " @@ -590,7 +591,7 @@ static int sync_serial_open(struct inode *inode, struct file *file) } else if (port == &ports[1]) { if (request_irq(8, manual_interrupt, - IRQF_SHARED | IRQF_DISABLED, + IRQF_SHARED, "synchronous serial manual irq", &ports[1])) { printk(KERN_CRIT "Can't alloc " @@ -1136,7 +1137,8 @@ static ssize_t sync_serial_read(struct file *file, char *buf, if (file->f_flags & O_NONBLOCK) return -EAGAIN; - interruptible_sleep_on(&port->in_wait_q); + wait_event_interruptible(port->in_wait_q, + !(start == end && !port->full)); if (signal_pending(current)) return -EINTR; diff --git a/arch/cris/arch-v10/kernel/Makefile b/arch/cris/arch-v10/kernel/Makefile index dcfec41d353300..4841e822cdd1ae 100644 --- a/arch/cris/arch-v10/kernel/Makefile +++ b/arch/cris/arch-v10/kernel/Makefile @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.6 2004/12/13 12:21:51 starvik Exp $ # # Makefile for the linux kernel. # diff --git a/arch/cris/arch-v10/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c index f932c85fbde484..7d307cce8bd8f6 100644 --- a/arch/cris/arch-v10/kernel/debugport.c +++ b/arch/cris/arch-v10/kernel/debugport.c @@ -19,7 +19,6 @@ #include #include #include -#include /* Get SIMCOUT. */ extern void reset_watchdog(void); @@ -318,12 +317,6 @@ console_write(struct console *co, const char *buf, unsigned int len) if (!port) return; -#ifdef CONFIG_SVINTO_SIM - /* no use to simulate the serial debug output */ - SIMCOUT(buf, len); - return; -#endif - console_write_direct(co, buf, len); } diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S index 897bba67bf7afe..81570fcd041281 100644 --- a/arch/cris/arch-v10/kernel/entry.S +++ b/arch/cris/arch-v10/kernel/entry.S @@ -13,8 +13,8 @@ * after a timer-interrupt and after each system call. * * Stack layout in 'ret_from_system_call': - * ptrace needs to have all regs on the stack. - * if the order here is changed, it needs to be + * ptrace needs to have all regs on the stack. + * if the order here is changed, it needs to be * updated in fork.c:copy_process, signal.c:do_signal, * ptrace.c and ptrace.h * @@ -31,7 +31,7 @@ #include ;; functions exported from this file - + .globl system_call .globl ret_from_intr .globl ret_from_fork @@ -46,10 +46,10 @@ .globl do_sigtrap .globl gdb_handle_breakpoint .globl sys_call_table - + ;; below are various parts of system_call which are not in the fast-path - -#ifdef CONFIG_PREEMPT + +#ifdef CONFIG_PREEMPT ; Check if preemptive kernel scheduling should be done _resume_kernel: di @@ -74,7 +74,7 @@ _need_resched: nop #else #define _resume_kernel _Rexit -#endif +#endif ; Called at exit from fork. schedule_tail must be called to drop ; spinlock if CONFIG_PREEMPT @@ -91,16 +91,16 @@ ret_from_kernel_thread: ba ret_from_sys_call ret_from_intr: - ;; check for resched if preemptive kernel or if we're going back to user-mode + ;; check for resched if preemptive kernel or if we're going back to user-mode ;; this test matches the user_regs(regs) macro ;; we cannot simply test $dccr, because that does not necessarily ;; reflect what mode we'll return into. - + move.d [$sp + PT_dccr], $r0; regs->dccr btstq 8, $r0 ; U-flag bpl _resume_kernel - ; Note that di below is in delay slot - + ; Note that di below is in delay slot + _resume_userspace: di ; so need_resched and sigpending don't change @@ -113,7 +113,7 @@ _resume_userspace: nop ba _Rexit nop - + ;; The system_call is called by a BREAK instruction, which works like ;; an interrupt call but it stores the return PC in BRP instead of IRP. ;; Since we dont really want to have two epilogues (one for system calls @@ -123,7 +123,7 @@ _resume_userspace: ;; ;; Since we can't have system calls inside interrupts, it should not matter ;; that we don't stack IRP. - ;; + ;; ;; In r9 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,mof,srp ;; ;; This function looks on the _surface_ like spaghetti programming, but it's @@ -140,7 +140,7 @@ system_call: movem $r13, [$sp] ; push r0-r13 push $r10 ; push orig_r10 clear.d [$sp=$sp-4] ; frametype == 0, normal stackframe - + movs.w -ENOSYS, $r0 move.d $r0, [$sp+PT_r10] ; put the default return value in r10 in the frame @@ -148,17 +148,17 @@ system_call: movs.w -8192, $r0 ; THREAD_SIZE == 8192 and.d $sp, $r0 - + move.d [$r0+TI_flags], $r0 btstq TIF_SYSCALL_TRACE, $r0 bmi _syscall_trace_entry - nop + nop -_syscall_traced: +_syscall_traced: ;; check for sanity in the requested syscall number - - cmpu.w NR_syscalls, $r9 + + cmpu.w NR_syscalls, $r9 bcc ret_from_sys_call lslq 2, $r9 ; multiply by 4, in the delay slot @@ -166,28 +166,28 @@ _syscall_traced: ;; of the register structure itself. some syscalls need this. push $sp - + ;; the parameter carrying registers r10, r11, r12 and 13 are intact. - ;; the fifth and sixth parameters (if any) was in mof and srp + ;; the fifth and sixth parameters (if any) was in mof and srp ;; respectively, and we need to put them on the stack. push $srp push $mof - + jsr [$r9+sys_call_table] ; actually do the system call addq 3*4, $sp ; pop the mof, srp and regs parameters move.d $r10, [$sp+PT_r10] ; save the return value moveq 1, $r9 ; "parameter" to ret_from_sys_call to show it was a sys call - + ;; fall through into ret_from_sys_call to return - + ret_from_sys_call: ;; r9 is a parameter - if >=1 we came from a syscall, if 0, from an irq - + ;; get the current task-struct pointer (see top for defs) - movs.w -8192, $r0 ; THREAD_SIZE == 8192 + movs.w -8192, $r0 ; THREAD_SIZE == 8192 and.d $sp, $r0 di ; make sure need_resched and sigpending don't change @@ -202,7 +202,7 @@ _Rexit: bne _RBFexit ; was not CRIS_FRAME_NORMAL, handle otherwise addq 4, $sp ; skip orig_r10, in delayslot movem [$sp+], $r13 ; registers r0-r13 - pop $mof ; multiply overflow register + pop $mof ; multiply overflow register pop $dccr ; condition codes pop $srp ; subroutine return pointer ;; now we have a 4-word SBFS frame which we do not want to restore @@ -216,14 +216,14 @@ _Rexit: _RBFexit: movem [$sp+], $r13 ; registers r0-r13, in delay slot - pop $mof ; multiply overflow register + pop $mof ; multiply overflow register pop $dccr ; condition codes pop $srp ; subroutine return pointer rbf [$sp+] ; return by popping the CPU status ;; We get here after doing a syscall if extra work might need to be done ;; perform syscall exit tracing if needed - + _syscall_exit_work: ;; $r0 contains current at this point and irq's are disabled @@ -231,22 +231,22 @@ _syscall_exit_work: btstq TIF_SYSCALL_TRACE, $r1 bpl _work_pending nop - + ei move.d $r9, $r1 ; preserve r9 jsr do_syscall_trace move.d $r1, $r9 - + ba _resume_userspace nop - + _work_pending: move.d [$r0+TI_flags], $r1 btstq TIF_NEED_RESCHED, $r1 bpl _work_notifysig ; was neither trace nor sched, must be signal/notify nop - + _work_resched: move.d $r9, $r1 ; preserve r9 jsr schedule @@ -268,17 +268,17 @@ _work_notifysig: move.d $sp, $r11 ; the regs param move.d $r1, $r12 ; the thread_info_flags parameter jsr do_notify_resume - + ba _Rexit nop ;; We get here as a sidetrack when we've entered a syscall with the ;; trace-bit set. We need to call do_syscall_trace and then continue ;; with the call. - + _syscall_trace_entry: ;; PT_r10 in the frame contains -ENOSYS as required, at this point - + jsr do_syscall_trace ;; now re-enter the syscall code to do the syscall itself @@ -292,10 +292,10 @@ _syscall_trace_entry: move.d [$sp+PT_r13], $r13 move [$sp+PT_mof], $mof move [$sp+PT_srp], $srp - + ba _syscall_traced nop - + ;; resume performs the actual task-switching, by switching stack pointers ;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct ;; returns old current in r10 @@ -303,29 +303,29 @@ _syscall_trace_entry: ;; TODO: see the i386 version. The switch_to which calls resume in our version ;; could really be an inline asm of this. -resume: - push $srp ; we keep the old/new PC on the stack +resume: + push $srp ; we keep the old/new PC on the stack add.d $r12, $r10 ; r10 = current tasks tss move $dccr, [$r10+THREAD_dccr]; save irq enable state di move $usp, [$r10+ THREAD_usp] ; save user-mode stackpointer - + ;; See copy_thread for the reason why register R9 is saved. subq 10*4, $sp movem $r9, [$sp] ; save non-scratch registers and R9. - + move.d $sp, [$r10+THREAD_ksp] ; save the kernel stack pointer for the old task move.d $sp, $r10 ; return last running task in r10 and.d -8192, $r10 ; get thread_info from stackpointer - move.d [$r10+TI_task], $r10 ; get task + move.d [$r10+TI_task], $r10 ; get task add.d $r12, $r11 ; find the new tasks tss move.d [$r11+THREAD_ksp], $sp ; switch into the new stackframe by restoring kernel sp movem [$sp+], $r9 ; restore non-scratch registers and R9. move [$r11+THREAD_usp], $usp ; restore user-mode stackpointer - + move [$r11+THREAD_dccr], $dccr ; restore irq enable status jump [$sp+] ; restore PC @@ -401,7 +401,7 @@ mmu_bus_fault: push $r10 ; frametype == 1, BUSFAULT frame type move.d $sp, $r10 ; pt_regs argument to handle_mmu_bus_fault - + jsr handle_mmu_bus_fault ; in arch/cris/arch-v10/mm/fault.c ;; now we need to return through the normal path, we cannot just @@ -410,10 +410,10 @@ mmu_bus_fault: ;; whatever. moveq 0, $r9 ; busfault is equivalent to an irq - + ba ret_from_intr nop - + ;; special handlers for breakpoint and NMI hwbreakpoint: push $dccr @@ -429,7 +429,7 @@ hwbreakpoint: pop $dccr retb nop - + IRQ1_interrupt: ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!! move $brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame @@ -457,7 +457,7 @@ IRQ1_interrupt: ba _Rexit ; Return the standard way nop wdog: -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) +#if defined(CONFIG_ETRAX_WATCHDOG) ;; Check if we're waiting for reset to happen, as signalled by ;; hard_reset_now setting cause_of_death to a magic value. If so, just ;; get stuck until reset happens. @@ -500,7 +500,7 @@ Watchdog_bite: move.d $r10, [$r11] #endif - + ;; Note that we don't do "setf m" here (or after two necessary NOPs), ;; since *not* doing that saves us from re-entrancy checks. We don't want ;; to get here again due to possible subsequent NMIs; we want the watchdog @@ -523,16 +523,16 @@ _watchdogmsg: .ascii "Oops: bitten by watchdog\n\0" .previous -#endif /* CONFIG_ETRAX_WATCHDOG and not CONFIG_SVINTO_SIM */ +#endif /* CONFIG_ETRAX_WATCHDOG */ -spurious_interrupt: +spurious_interrupt: di jump hard_reset_now ;; this handles the case when multiple interrupts arrive at the same time ;; we jump to the first set interrupt bit in a priority fashion ;; the hardware will call the unserved interrupts after the handler finishes - + multiple_interrupt: ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!! move $irp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame @@ -551,7 +551,7 @@ multiple_interrupt: jump ret_from_intr do_sigtrap: - ;; + ;; ;; SIGTRAP the process that executed the break instruction. ;; Make a frame that Rexit in entry.S expects. ;; @@ -568,30 +568,30 @@ do_sigtrap: movs.w -8192,$r9 ; THREAD_SIZE == 8192 and.d $sp, $r9 move.d [$r9+TI_task], $r10 - move.d [$r10+TASK_pid], $r10 ; current->pid as arg1. + move.d [$r10+TASK_pid], $r10 ; current->pid as arg1. moveq 5, $r11 ; SIGTRAP as arg2. - jsr sys_kill + jsr sys_kill jump ret_from_intr ; Use the return routine for interrupts. -gdb_handle_breakpoint: +gdb_handle_breakpoint: push $dccr push $r0 #ifdef CONFIG_ETRAX_KGDB - move $dccr, $r0 ; U-flag not affected by previous insns. + move $dccr, $r0 ; U-flag not affected by previous insns. btstq 8, $r0 ; Test the U-flag. - bmi _ugdb_handle_breakpoint ; Go to user mode debugging. - nop ; Empty delay slot (cannot pop r0 here). + bmi _ugdb_handle_breakpoint ; Go to user mode debugging. + nop ; Empty delay slot (cannot pop r0 here). pop $r0 ; Restore r0. - ba kgdb_handle_breakpoint ; Go to kernel debugging. + ba kgdb_handle_breakpoint ; Go to kernel debugging. pop $dccr ; Restore dccr in delay slot. #endif - -_ugdb_handle_breakpoint: + +_ugdb_handle_breakpoint: move $brp, $r0 ; Use r0 temporarily for calculation. subq 2, $r0 ; Set to address of previous instruction. move $r0, $brp - pop $r0 ; Restore r0. - ba do_sigtrap ; SIGTRAP the offending process. + pop $r0 ; Restore r0. + ba do_sigtrap ; SIGTRAP the offending process. pop $dccr ; Restore dccr in delay slot. .data @@ -602,7 +602,7 @@ hw_bp_trig_ptr: .dword hw_bp_trigs .section .rodata,"a" -sys_call_table: +sys_call_table: .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ .long sys_exit .long sys_fork @@ -713,7 +713,7 @@ sys_call_table: .long sys_newlstat .long sys_newfstat .long sys_ni_syscall /* old sys_uname holder */ - .long sys_ni_syscall /* sys_iopl in i386 */ + .long sys_ni_syscall /* 110 */ /* sys_iopl in i386 */ .long sys_vhangup .long sys_ni_syscall /* old "idle" system call */ .long sys_ni_syscall /* vm86old in i386 */ @@ -730,7 +730,7 @@ sys_call_table: .long sys_adjtimex .long sys_mprotect /* 125 */ .long sys_sigprocmask - .long sys_ni_syscall /* old "create_module" */ + .long sys_ni_syscall /* old "create_module" */ .long sys_init_module .long sys_delete_module .long sys_ni_syscall /* 130: old "get_kernel_syms" */ @@ -795,7 +795,7 @@ sys_call_table: .long sys_ni_syscall /* streams2 */ .long sys_vfork /* 190 */ .long sys_getrlimit - .long sys_mmap2 + .long sys_mmap2 /* mmap_pgoff */ .long sys_truncate64 .long sys_ftruncate64 .long sys_stat64 /* 195 */ @@ -861,21 +861,21 @@ sys_call_table: .long sys_epoll_ctl /* 255 */ .long sys_epoll_wait .long sys_remap_file_pages - .long sys_set_tid_address - .long sys_timer_create - .long sys_timer_settime /* 260 */ - .long sys_timer_gettime - .long sys_timer_getoverrun - .long sys_timer_delete - .long sys_clock_settime - .long sys_clock_gettime /* 265 */ - .long sys_clock_getres - .long sys_clock_nanosleep + .long sys_set_tid_address + .long sys_timer_create + .long sys_timer_settime /* 260 */ + .long sys_timer_gettime + .long sys_timer_getoverrun + .long sys_timer_delete + .long sys_clock_settime + .long sys_clock_gettime /* 265 */ + .long sys_clock_getres + .long sys_clock_nanosleep .long sys_statfs64 - .long sys_fstatfs64 - .long sys_tgkill /* 270 */ + .long sys_fstatfs64 + .long sys_tgkill /* 270 */ .long sys_utimes - .long sys_fadvise64_64 + .long sys_fadvise64_64 .long sys_ni_syscall /* sys_vserver */ .long sys_ni_syscall /* sys_mbind */ .long sys_ni_syscall /* 275 sys_get_mempolicy */ @@ -886,7 +886,7 @@ sys_call_table: .long sys_mq_timedreceive /* 280 */ .long sys_mq_notify .long sys_mq_getsetattr - .long sys_ni_syscall /* reserved for kexec */ + .long sys_ni_syscall .long sys_waitid .long sys_ni_syscall /* 285 */ /* available */ .long sys_add_key @@ -939,6 +939,22 @@ sys_call_table: .long sys_preadv .long sys_pwritev .long sys_setns /* 335 */ + .long sys_name_to_handle_at + .long sys_open_by_handle_at + .long sys_rt_tgsigqueueinfo + .long sys_perf_event_open + .long sys_recvmmsg /* 340 */ + .long sys_accept4 + .long sys_fanotify_init + .long sys_fanotify_mark + .long sys_prlimit64 + .long sys_clock_adjtime /* 345 */ + .long sys_syncfs + .long sys_sendmmsg + .long sys_process_vm_readv + .long sys_process_vm_writev + .long sys_kcmp /* 350 */ + .long sys_finit_module /* * NOTE!! This doesn't have to be exact - we just have @@ -950,4 +966,4 @@ sys_call_table: .rept NR_syscalls-(.-sys_call_table)/4 .long sys_ni_syscall .endr - + diff --git a/arch/cris/arch-v10/kernel/head.S b/arch/cris/arch-v10/kernel/head.S index a1f2014b4e3b3c..4a146e1749c93c 100644 --- a/arch/cris/arch-v10/kernel/head.S +++ b/arch/cris/arch-v10/kernel/head.S @@ -1,12 +1,10 @@ /* * Head of the kernel - alter with care * - * Copyright (C) 2000, 2001 Axis Communications AB + * Copyright (C) 2000, 2001, 2010 Axis Communications AB * - * Authors: Bjorn Wesen (bjornw@axis.com) - * */ - + #define ASSEMBLER_MACROS_ONLY /* The IO_* macros use the ## token concatenation operator, so -traditional must not be used when assembling this file. */ @@ -18,15 +16,15 @@ #define START_ETHERNET_CLOCK IO_STATE(R_NETWORK_GEN_CONFIG, enable, on) |\ IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) - + ;; exported symbols - + .globl etrax_irv .globl romfs_start .globl romfs_length .globl romfs_in_flash .globl swapper_pg_dir - + .text ;; This is the entry point of the kernel. We are in supervisor mode. @@ -35,10 +33,10 @@ ;; put a nop (2 bytes) here first so we dont accidentally skip the di ;; ;; NOTICE! The registers r8 and r9 are used as parameters carrying - ;; information from the decompressor (if the kernel was compressed). + ;; information from the decompressor (if the kernel was compressed). ;; They should not be used in the code below until read. - - nop + + nop di ;; First setup the kseg_c mapping from where the kernel is linked @@ -58,19 +56,19 @@ #ifdef CONFIG_CRIS_LOW_MAP ; kseg mappings, temporary map of 0xc0->0x40 - move.d IO_FIELD (R_MMU_KBASE_HI, base_c, 4) \ + move.d IO_FIELD (R_MMU_KBASE_HI, base_c, 4) \ | IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb) \ | IO_FIELD (R_MMU_KBASE_HI, base_9, 9) \ | IO_FIELD (R_MMU_KBASE_HI, base_8, 8), $r0 move.d $r0, [R_MMU_KBASE_HI] - ; temporary map of 0x40->0x40 and 0x60->0x40 - move.d IO_FIELD (R_MMU_KBASE_LO, base_6, 4) \ + ; temporary map of 0x40->0x40 and 0x60->0x40 + move.d IO_FIELD (R_MMU_KBASE_LO, base_6, 4) \ | IO_FIELD (R_MMU_KBASE_LO, base_4, 4), $r0 move.d $r0, [R_MMU_KBASE_LO] ; mmu enable, segs e,c,b,a,6,5,4,0 segment mapped - move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \ + move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \ | IO_STATE (R_MMU_CONFIG, inv_excp, enable) \ | IO_STATE (R_MMU_CONFIG, acc_excp, enable) \ | IO_STATE (R_MMU_CONFIG, we_excp, enable) \ @@ -93,17 +91,17 @@ move.d $r0, [R_MMU_CONFIG] #else ; kseg mappings - move.d IO_FIELD (R_MMU_KBASE_HI, base_e, 8) \ + move.d IO_FIELD (R_MMU_KBASE_HI, base_e, 8) \ | IO_FIELD (R_MMU_KBASE_HI, base_c, 4) \ | IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb), $r0 move.d $r0, [R_MMU_KBASE_HI] - ; temporary map of 0x40->0x40 and 0x00->0x00 + ; temporary map of 0x40->0x40 and 0x00->0x00 move.d IO_FIELD (R_MMU_KBASE_LO, base_4, 4), $r0 move.d $r0, [R_MMU_KBASE_LO] ; mmu enable, segs f,e,c,b,4,0 segment mapped - move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \ + move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \ | IO_STATE (R_MMU_CONFIG, inv_excp, enable) \ | IO_STATE (R_MMU_CONFIG, acc_excp, enable) \ | IO_STATE (R_MMU_CONFIG, we_excp, enable) \ @@ -141,12 +139,12 @@ ;; ;; In both cases, we start in un-cached mode, and need to jump into a ;; cached PC after we're done fiddling around with the segments. - ;; + ;; ;; arch/etrax100/etrax100.ld sets some symbols that define the start ;; and end of each segment. ;; Check if we start from DRAM or FLASH by testing PC - + move.d $pc,$r0 and.d 0x7fffffff,$r0 ; get rid of the non-cache bit cmp.d 0x10000,$r0 ; arbitrary... just something above this code @@ -163,30 +161,28 @@ _inflash0: ;; after init. .section ".init.text", "ax" _inflash: -#ifdef CONFIG_ETRAX_ETHERNET +#ifdef CONFIG_ETRAX_ETHERNET ;; Start MII clock to make sure it is running when tranceiver is reset move.d START_ETHERNET_CLOCK, $r0 move.d $r0, [R_NETWORK_GEN_CONFIG] #endif ;; Set up waitstates etc according to kernel configuration. -#ifndef CONFIG_SVINTO_SIM move.d CONFIG_ETRAX_DEF_R_WAITSTATES, $r0 move.d $r0, [R_WAITSTATES] move.d CONFIG_ETRAX_DEF_R_BUS_CONFIG, $r0 move.d $r0, [R_BUS_CONFIG] -#endif ;; We need to initialze DRAM registers before we start using the DRAM cmp.d RAM_INIT_MAGIC, $r8 ; Already initialized? beq _dram_init_finished nop - + #include "../lib/dram_init.S" -_dram_init_finished: +_dram_init_finished: ;; Copy text+data to DRAM ;; This is fragile - the calculation of r4 as the image size depends ;; on that the labels below actually are the first and last positions @@ -198,7 +194,7 @@ _dram_init_finished: ;; between the physical start of the flash and the flash-image start, ;; and when run with compression, the kernel is actually unpacked to ;; DRAM and we never get here in the first place :)) - + moveq 0, $r0 ; source move.d text_start, $r1 ; destination move.d __vmlinux_end, $r2 ; end destination @@ -229,10 +225,10 @@ _dram_init_finished: add.d 0xf0000000, $r4 ; add flash start in virtual memory (cached) #endif move.d $r4, [romfs_start] -1: +1: moveq 1, $r0 move.d $r0, [romfs_in_flash] - + jump _start_it ; enter code, cached this time _inram: @@ -241,7 +237,7 @@ _inram: moveq 0, $r0 move.d $r0, [romfs_length] ; default if there is no cramfs - + ;; The kernel could have been unpacked to DRAM by the loader, but ;; the cramfs image could still be in the Flash directly after the ;; compressed kernel image. The loader passes the address of the @@ -251,7 +247,7 @@ _inram: ;; (Notice that if this is not booted from the loader, r9 will be ;; garbage but we do sanity checks on it, the chance that it points ;; to a cramfs magic is small.. ) - + cmp.d 0x0ffffff8, $r9 bhs _no_romfs_in_flash ; r9 points outside the flash area nop @@ -274,7 +270,7 @@ _inram: jump _start_it ; enter code, cached this time _no_romfs_in_flash: - + ;; Check if there is a cramfs (magic value). ;; Notice that we check for cramfs magic value - which is ;; the "rom fs" we'll possibly use in 2.4 if not JFFS (which does @@ -286,8 +282,8 @@ _no_romfs_in_flash: bne 2f nop - ;; Ok. What is its size ? - + ;; Ok. What is its size ? + move.d [$r0 + 4], $r2 ; cramfs_super.size (again, no need to swapwb) ;; We want to copy it to the end of the BSS @@ -303,7 +299,7 @@ _no_romfs_in_flash: add.d $r2, $r0 add.d $r2, $r1 - + ;; Go ahead. Make my loop. lsrq 1, $r2 ; size is in bytes, we copy words @@ -314,14 +310,14 @@ _no_romfs_in_flash: bne 1b nop -2: +2: ;; Dont worry that the BSS is tainted. It will be cleared later. moveq 0, $r0 move.d $r0, [romfs_in_flash] jump _start_it ; better skip the additional cramfs check below - + _start_it: ;; Check if kernel command line is supplied @@ -348,7 +344,7 @@ no_command_line: move.d ibr_start,$r0 ; this symbol is set by the linker script move $r0,$ibr move.d $r0,[etrax_irv] ; set the interrupt base register and pointer - + ;; Clear BSS region, from _bss_start to _end move.d __bss_start, $r0 @@ -357,7 +353,7 @@ no_command_line: cmp.d $r1, $r0 blo 1b nop - + #ifdef CONFIG_BLK_DEV_ETRAXIDE ;; disable ATA before enabling it in genconfig below moveq 0,$r0 @@ -380,7 +376,7 @@ no_command_line: #ifdef CONFIG_JULIETTE ;; configure external DMA channel 0 before enabling it in genconfig - + moveq 0,$r0 move.d $r0,[R_EXT_DMA_0_ADDR] ; cnt enable, word size, output, stop, size 0 @@ -395,7 +391,7 @@ no_command_line: move.d $r0,[R_EXT_DMA_0_CMD] ;; reset dma4 and wait for completion - + moveq IO_STATE (R_DMA_CH4_CMD, cmd, reset),$r0 move.b $r0,[R_DMA_CH4_CMD] 1: move.b [R_DMA_CH4_CMD],$r0 @@ -405,7 +401,7 @@ no_command_line: nop ;; reset dma5 and wait for completion - + moveq IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0 move.b $r0,[R_DMA_CH5_CMD] 1: move.b [R_DMA_CH5_CMD],$r0 @@ -413,8 +409,8 @@ no_command_line: cmp.b IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0 beq 1b nop -#endif - +#endif + ;; Etrax product HW genconfig setup moveq 0,$r0 @@ -468,7 +464,6 @@ no_command_line: move.d $r0,[genconfig_shadow] ; init a shadow register of R_GEN_CONFIG -#ifndef CONFIG_SVINTO_SIM move.d $r0,[R_GEN_CONFIG] #if 0 @@ -486,7 +481,7 @@ no_command_line: beq 1b nop #endif - + moveq IO_STATE (R_DMA_CH8_CMD, cmd, reset),$r0 move.b $r0,[R_DMA_CH8_CMD] ; reset (ser1 dma out) move.b $r0,[R_DMA_CH9_CMD] ; reset (ser1 dma in) @@ -503,7 +498,7 @@ no_command_line: ;; setup port PA and PB default initial directions and data ;; including their shadow registers - + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR,$r0 #if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PA7) or.b IO_STATE (R_PORT_PA_DIR, dir7, output),$r0 @@ -520,7 +515,7 @@ no_command_line: #endif move.b $r0,[port_pa_data_shadow] move.b $r0,[R_PORT_PA_DATA] - + move.b CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG,$r0 move.b $r0,[port_pb_config_shadow] move.b $r0,[R_PORT_PB_CONFIG] @@ -562,13 +557,13 @@ no_command_line: #endif move.d $r0,[port_g_data_shadow] move.d $r0,[R_PORT_G_DATA] - + ;; setup the serial port 0 at 115200 baud for debug purposes - + moveq IO_STATE (R_SERIAL0_XOFF, tx_stop, enable) \ | IO_STATE (R_SERIAL0_XOFF, auto_xoff, disable) \ | IO_FIELD (R_SERIAL0_XOFF, xoff_char, 0),$r0 - move.d $r0,[R_SERIAL0_XOFF] + move.d $r0,[R_SERIAL0_XOFF] ; 115.2kbaud for both transmit and receive move.b IO_STATE (R_SERIAL0_BAUD, tr_baud, c115k2Hz) \ @@ -584,8 +579,8 @@ no_command_line: | IO_STATE (R_SERIAL0_REC_CTRL, rec_par, even) \ | IO_STATE (R_SERIAL0_REC_CTRL, rec_par_en, disable) \ | IO_STATE (R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit),$r0 - move.b $r0,[R_SERIAL0_REC_CTRL] - + move.b $r0,[R_SERIAL0_REC_CTRL] + ; Set up and enable the serial0 transmitter. move.b IO_FIELD (R_SERIAL0_TR_CTRL, txd, 0) \ | IO_STATE (R_SERIAL0_TR_CTRL, tr_enable, enable) \ @@ -598,11 +593,11 @@ no_command_line: move.b $r0,[R_SERIAL0_TR_CTRL] ;; setup the serial port 1 at 115200 baud for debug purposes - + moveq IO_STATE (R_SERIAL1_XOFF, tx_stop, enable) \ | IO_STATE (R_SERIAL1_XOFF, auto_xoff, disable) \ | IO_FIELD (R_SERIAL1_XOFF, xoff_char, 0),$r0 - move.d $r0,[R_SERIAL1_XOFF] + move.d $r0,[R_SERIAL1_XOFF] ; 115.2kbaud for both transmit and receive move.b IO_STATE (R_SERIAL1_BAUD, tr_baud, c115k2Hz) \ @@ -618,8 +613,8 @@ no_command_line: | IO_STATE (R_SERIAL1_REC_CTRL, rec_par, even) \ | IO_STATE (R_SERIAL1_REC_CTRL, rec_par_en, disable) \ | IO_STATE (R_SERIAL1_REC_CTRL, rec_bitnr, rec_8bit),$r0 - move.b $r0,[R_SERIAL1_REC_CTRL] - + move.b $r0,[R_SERIAL1_REC_CTRL] + ; Set up and enable the serial1 transmitter. move.b IO_FIELD (R_SERIAL1_TR_CTRL, txd, 0) \ | IO_STATE (R_SERIAL1_TR_CTRL, tr_enable, enable) \ @@ -666,14 +661,14 @@ no_command_line: | IO_STATE (R_SERIAL2_TR_CTRL, tr_bitnr, tr_8bit),$r0 move.b $r0,[R_SERIAL2_TR_CTRL] #endif - -#ifdef CONFIG_ETRAX_SERIAL_PORT3 + +#ifdef CONFIG_ETRAX_SERIAL_PORT3 ;; setup the serial port 3 at 115200 baud for debug purposes - + moveq IO_STATE (R_SERIAL3_XOFF, tx_stop, enable) \ | IO_STATE (R_SERIAL3_XOFF, auto_xoff, disable) \ | IO_FIELD (R_SERIAL3_XOFF, xoff_char, 0),$r0 - move.d $r0,[R_SERIAL3_XOFF] + move.d $r0,[R_SERIAL3_XOFF] ; 115.2kbaud for both transmit and receive move.b IO_STATE (R_SERIAL3_BAUD, tr_baud, c115k2Hz) \ @@ -689,8 +684,8 @@ no_command_line: | IO_STATE (R_SERIAL3_REC_CTRL, rec_par, even) \ | IO_STATE (R_SERIAL3_REC_CTRL, rec_par_en, disable) \ | IO_STATE (R_SERIAL3_REC_CTRL, rec_bitnr, rec_8bit),$r0 - move.b $r0,[R_SERIAL3_REC_CTRL] - + move.b $r0,[R_SERIAL3_REC_CTRL] + ; Set up and enable the serial3 transmitter. move.b IO_FIELD (R_SERIAL3_TR_CTRL, txd, 0) \ | IO_STATE (R_SERIAL3_TR_CTRL, tr_enable, enable) \ @@ -702,13 +697,11 @@ no_command_line: | IO_STATE (R_SERIAL3_TR_CTRL, tr_bitnr, tr_8bit),$r0 move.b $r0,[R_SERIAL3_TR_CTRL] #endif - -#endif /* CONFIG_SVINTO_SIM */ jump start_kernel ; jump into the C-function start_kernel in init/main.c - + .data -etrax_irv: +etrax_irv: .dword 0 romfs_start: .dword 0 @@ -716,13 +709,13 @@ romfs_length: .dword 0 romfs_in_flash: .dword 0 - + ;; put some special pages at the beginning of the kernel aligned ;; to page boundaries - the kernel cannot start until after this #ifdef CONFIG_CRIS_LOW_MAP swapper_pg_dir = 0x60002000 -#else +#else swapper_pg_dir = 0xc0002000 #endif diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c index ba0e5965d6e3ed..09cae80a834a34 100644 --- a/arch/cris/arch-v10/kernel/irq.c +++ b/arch/cris/arch-v10/kernel/irq.c @@ -5,7 +5,7 @@ * * Authors: Bjorn Wesen (bjornw@axis.com) * - * This file contains the interrupt vectors and some + * This file contains the interrupt vectors and some * helper functions * */ @@ -182,19 +182,14 @@ void do_multiple_IRQ(struct pt_regs* regs) setting the irq vector table. */ -void __init -init_IRQ(void) +void __init init_IRQ(void) { int i; /* clear all interrupt masks */ - -#ifndef CONFIG_SVINTO_SIM *R_IRQ_MASK0_CLR = 0xffffffff; *R_IRQ_MASK1_CLR = 0xffffffff; *R_IRQ_MASK2_CLR = 0xffffffff; -#endif - *R_VECT_MASK_CLR = 0xffffffff; for (i = 0; i < 256; i++) @@ -211,25 +206,20 @@ init_IRQ(void) executed by the associated break handler, rather than just a jump address. therefore we need to setup a default breakpoint handler for all breakpoints */ - for (i = 0; i < 16; i++) set_break_vector(i, do_sigtrap); - - /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */ + /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */ set_int_vector(15, multiple_interrupt); - - /* 0 and 1 which are special breakpoint/NMI traps */ + /* 0 and 1 which are special breakpoint/NMI traps */ set_int_vector(0, hwbreakpoint); set_int_vector(1, IRQ1_interrupt); /* and irq 14 which is the mmu bus fault handler */ - set_int_vector(14, mmu_bus_fault); /* setup the system-call trap, which is reached by BREAK 13 */ - set_break_vector(13, system_call); /* setup a breakpoint handler for debugging used for both user and diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c index 753e9a03cf8705..02b783457be0a9 100644 --- a/arch/cris/arch-v10/kernel/process.c +++ b/arch/cris/arch-v10/kernel/process.c @@ -56,14 +56,14 @@ void hard_reset_now (void) * code to know about it than the watchdog handler in entry.S and * this code, implementing hard reset through the watchdog. */ -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) +#if defined(CONFIG_ETRAX_WATCHDOG) extern int cause_of_death; #endif printk("*** HARD RESET ***\n"); local_irq_disable(); -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) +#if defined(CONFIG_ETRAX_WATCHDOG) cause_of_death = 0xbedead; #else /* Since we dont plan to keep on resetting the watchdog, diff --git a/arch/cris/arch-v10/kernel/time.c b/arch/cris/arch-v10/kernel/time.c index fce7c541d70de8..b5eb5cd2f60b13 100644 --- a/arch/cris/arch-v10/kernel/time.c +++ b/arch/cris/arch-v10/kernel/time.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -34,7 +33,7 @@ unsigned long get_ns_in_jiffie(void) local_irq_save(flags); timer_count = *R_TIMER0_DATA; - presc_count = *R_TIM_PRESC_STATUS; + presc_count = *R_TIM_PRESC_STATUS; /* presc_count might be wrapped */ t1 = *R_TIMER0_DATA; @@ -50,7 +49,7 @@ unsigned long get_ns_in_jiffie(void) presc_count = PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2; } - ns = ( (TIMER0_DIV - timer_count) * ((1000000000/HZ)/TIMER0_DIV )) + + ns = ( (TIMER0_DIV - timer_count) * ((1000000000/HZ)/TIMER0_DIV )) + ( (presc_count) * (1000000000/PRESCALE_FREQ)); return ns; } @@ -80,7 +79,7 @@ static u32 cris_v10_gettimeoffset(void) * by the R_WATCHDOG register. The R_WATCHDOG register contains an enable bit * and a 3-bit key value. The effect of writing to the R_WATCHDOG register is * described in the table below: - * + * * Watchdog Value written: * state: To enable: To key: Operation: * -------- ---------- ------- ---------- @@ -89,15 +88,15 @@ static u32 cris_v10_gettimeoffset(void) * started 0 ~key Stop watchdog * started 1 ~key Restart watchdog with key = ~key. * started X new_key_val Change key to new_key_val. - * + * * Note: '~' is the bitwise NOT operator. - * + * */ /* right now, starting the watchdog is the same as resetting it */ #define start_watchdog reset_watchdog -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) +#ifdef CONFIG_ETRAX_WATCHDOG static int watchdog_key = 0; /* arbitrary number */ #endif @@ -107,10 +106,9 @@ static int watchdog_key = 0; /* arbitrary number */ #define WATCHDOG_MIN_FREE_PAGES 8 -void -reset_watchdog(void) +void reset_watchdog(void) { -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) +#if defined(CONFIG_ETRAX_WATCHDOG) /* only keep watchdog happy as long as we have memory left! */ if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) { /* reset the watchdog with the inverse of the old key */ @@ -123,28 +121,23 @@ reset_watchdog(void) /* stop the watchdog - we still need the correct key */ -void -stop_watchdog(void) +void stop_watchdog(void) { -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) +#ifdef CONFIG_ETRAX_WATCHDOG watchdog_key ^= 0x7; /* invert key, which is 3 bits */ *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) | IO_STATE(R_WATCHDOG, enable, stop); -#endif +#endif } +extern void cris_do_profile(struct pt_regs *regs); + /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "xtime_update()" routine every clocktick */ - -//static unsigned short myjiff; /* used by our debug routine print_timestamp */ - -extern void cris_do_profile(struct pt_regs *regs); - -static inline irqreturn_t -timer_interrupt(int irq, void *dev_id) +static inline irqreturn_t timer_interrupt(int irq, void *dev_id) { struct pt_regs *regs = get_irq_regs(); /* acknowledge the timer irq */ @@ -160,44 +153,39 @@ timer_interrupt(int irq, void *dev_id) IO_STATE( R_TIMER_CTRL, tm0, run) | IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); #else - *R_TIMER_CTRL = r_timer_ctrl_shadow | - IO_STATE(R_TIMER_CTRL, i0, clr); + *R_TIMER_CTRL = r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i0, clr); #endif /* reset watchdog otherwise it resets us! */ reset_watchdog(); - + /* Update statistics. */ update_process_times(user_mode(regs)); /* call the real timer interrupt handler */ - xtime_update(1); - + cris_do_profile(regs); /* Save profiling information */ return IRQ_HANDLED; } -/* timer is IRQF_SHARED so drivers can add stuff to the timer irq chain - * it needs to be IRQF_DISABLED to make the jiffies update work properly - */ +/* timer is IRQF_SHARED so drivers can add stuff to the timer irq chain */ static struct irqaction irq2 = { .handler = timer_interrupt, - .flags = IRQF_SHARED | IRQF_DISABLED, + .flags = IRQF_SHARED, .name = "timer", }; -void __init -time_init(void) -{ +void __init time_init(void) +{ arch_gettimeoffset = cris_v10_gettimeoffset; - /* probe for the RTC and read it if it exists - * Before the RTC can be probed the loops_per_usec variable needs - * to be initialized to make usleep work. A better value for - * loops_per_usec is calculated by the kernel later once the - * clock has started. + /* probe for the RTC and read it if it exists + * Before the RTC can be probed the loops_per_usec variable needs + * to be initialized to make usleep work. A better value for + * loops_per_usec is calculated by the kernel later once the + * clock has started. */ loops_per_usec = 50; @@ -208,7 +196,7 @@ time_init(void) * Remember that linux/timex.h contains #defines that rely on the * timer settings below (hz and divide factor) !!! */ - + #ifdef USE_CASCADE_TIMERS *R_TIMER_CTRL = IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | @@ -219,8 +207,8 @@ time_init(void) IO_STATE( R_TIMER_CTRL, i0, nop) | IO_STATE( R_TIMER_CTRL, tm0, stop_ld) | IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); - - *R_TIMER_CTRL = r_timer_ctrl_shadow = + + *R_TIMER_CTRL = r_timer_ctrl_shadow = IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | IO_STATE( R_TIMER_CTRL, i1, nop) | @@ -230,18 +218,18 @@ time_init(void) IO_STATE( R_TIMER_CTRL, tm0, run) | IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); #else - *R_TIMER_CTRL = - IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | + *R_TIMER_CTRL = + IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV) | - IO_STATE(R_TIMER_CTRL, i1, nop) | + IO_STATE(R_TIMER_CTRL, i1, nop) | IO_STATE(R_TIMER_CTRL, tm1, stop_ld) | IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) | IO_STATE(R_TIMER_CTRL, i0, nop) | IO_STATE(R_TIMER_CTRL, tm0, stop_ld) | IO_STATE(R_TIMER_CTRL, clksel0, flexible); - + *R_TIMER_CTRL = r_timer_ctrl_shadow = - IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | + IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV) | IO_STATE(R_TIMER_CTRL, i1, nop) | IO_STATE(R_TIMER_CTRL, tm1, run) | @@ -253,16 +241,14 @@ time_init(void) *R_TIMER_PRESCALE = PRESCALE_VALUE; #endif - *R_IRQ_MASK0_SET = - IO_STATE(R_IRQ_MASK0_SET, timer0, set); /* unmask the timer irq */ - - /* now actually register the timer irq handler that calls timer_interrupt() */ - + /* unmask the timer irq */ + *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer0, set); + + /* now actually register the irq handler that calls timer_interrupt() */ setup_irq(2, &irq2); /* irq 2 is the timer0 irq in etrax */ /* enable watchdog if we should use one */ - -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) +#if defined(CONFIG_ETRAX_WATCHDOG) printk("Enabling watchdog...\n"); start_watchdog(); @@ -275,9 +261,7 @@ time_init(void) driver or infrastructure support yet. */ asm ("setf m"); - *R_IRQ_MASK0_SET = - IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set); - *R_VECT_MASK_SET = - IO_STATE(R_VECT_MASK_SET, nmi, set); + *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set); + *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, nmi, set); #endif } diff --git a/arch/cris/arch-v10/lib/dram_init.S b/arch/cris/arch-v10/lib/dram_init.S index b9190ff7d0a4de..e541d3d8f92239 100644 --- a/arch/cris/arch-v10/lib/dram_init.S +++ b/arch/cris/arch-v10/lib/dram_init.S @@ -5,9 +5,7 @@ * Note: This file may not modify r9 because r9 is used to carry * information from the decompresser to the kernel * - * Copyright (C) 2000, 2001 Axis Communications AB - * - * Authors: Mikael Starvik (starvik@axis.com) + * Copyright (C) 2000-2012 Axis Communications AB * */ @@ -18,16 +16,15 @@ ;; WARNING! The registers r8 and r9 are used as parameters carrying - ;; information from the decompressor (if the kernel was compressed). + ;; information from the decompressor (if the kernel was compressed). ;; They should not be used in the code below. -#ifndef CONFIG_SVINTO_SIM move.d CONFIG_ETRAX_DEF_R_WAITSTATES, $r0 move.d $r0, [R_WAITSTATES] move.d CONFIG_ETRAX_DEF_R_BUS_CONFIG, $r0 move.d $r0, [R_BUS_CONFIG] - + #ifndef CONFIG_ETRAX_SDRAM move.d CONFIG_ETRAX_DEF_R_DRAM_CONFIG, $r0 move.d $r0, [R_DRAM_CONFIG] @@ -38,14 +35,14 @@ ;; Samsung SDRAMs seem to require to be initialized twice to work properly. moveq 2, $r6 _sdram_init: - + ; Refer to ETRAX 100LX Designers Reference for a description of SDRAM initialization - + ; Bank configuration move.d CONFIG_ETRAX_DEF_R_SDRAM_CONFIG, $r0 move.d $r0, [R_SDRAM_CONFIG] - ; Calculate value of mrs_data + ; Calculate value of mrs_data ; CAS latency = 2 && bus_width = 32 => 0x40 ; CAS latency = 3 && bus_width = 32 => 0x60 ; CAS latency = 2 && bus_width = 16 => 0x20 @@ -56,22 +53,22 @@ _sdram_init: and.d 0x00ff0000, $r2 bne _set_timing lsrq 16, $r2 - + move.d 0x40, $r2 ; Assume 32 bits and CAS latency = 2 move.d CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r1 move.d $r1, $r3 - and.d 0x03, $r1 ; Get CAS latency + and.d 0x03, $r1 ; Get CAS latency and.d 0x1000, $r3 ; 50 or 100 MHz? beq _speed_50 nop -_speed_100: +_speed_100: cmp.d 0x00, $r1 ; CAS latency = 2? beq _bw_check nop - or.d 0x20, $r2 ; CAS latency = 3 + or.d 0x20, $r2 ; CAS latency = 3 ba _bw_check nop -_speed_50: +_speed_50: cmp.d 0x01, $r1 ; CAS latency = 2? beq _bw_check nop @@ -86,19 +83,19 @@ _bw_check: ; Set timing parameters. Starts master clock _set_timing: move.d CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r1 - and.d 0x8000f9ff, $r1 ; Make sure mrs data and command is 0 + and.d 0x8000f9ff, $r1 ; Make sure mrs data and command is 0 or.d 0x80000000, $r1 ; Make sure sdram enable bit is set move.d $r1, $r5 or.d 0x0000c000, $r1 ; ref = disable lslq 16, $r2 ; mrs data starts at bit 16 - or.d $r2, $r1 - move.d $r1, [R_SDRAM_TIMING] - + or.d $r2, $r1 + move.d $r1, [R_SDRAM_TIMING] + ; Wait 200us move.d 10000, $r2 1: bne 1b subq 1, $r2 - + ; Issue initialization command sequence move.d _sdram_commands_start, $r2 and.d 0x000fffff, $r2 ; Make sure commands are read from flash @@ -144,7 +141,6 @@ _sdram_commands_start: .byte 2 ; refresh .byte 0 ; nop .byte 1 ; mrs - .byte 0 ; nop -_sdram_commands_end: -#endif + .byte 0 ; nop +_sdram_commands_end: #endif diff --git a/arch/cris/arch-v32/drivers/axisflashmap.c b/arch/cris/arch-v32/drivers/axisflashmap.c index 1b6ad6247204c0..28dd77144e8fe8 100644 --- a/arch/cris/arch-v32/drivers/axisflashmap.c +++ b/arch/cris/arch-v32/drivers/axisflashmap.c @@ -24,8 +24,6 @@ #include #include -#include - #include #include diff --git a/arch/cris/arch-v32/drivers/mach-a3/gpio.c b/arch/cris/arch-v32/drivers/mach-a3/gpio.c index 0b86deedacb97b..74f9fe80940c73 100644 --- a/arch/cris/arch-v32/drivers/mach-a3/gpio.c +++ b/arch/cris/arch-v32/drivers/mach-a3/gpio.c @@ -978,7 +978,7 @@ static int __init gpio_init(void) CRIS_LED_DISK_WRITE(0); int res2 = request_irq(GIO_INTR_VECT, gpio_interrupt, - IRQF_SHARED | IRQF_DISABLED, "gpio", &alarmlist); + IRQF_SHARED, "gpio", &alarmlist); if (res2) { printk(KERN_ERR "err: irq for gpio\n"); return res2; diff --git a/arch/cris/arch-v32/drivers/mach-fs/gpio.c b/arch/cris/arch-v32/drivers/mach-fs/gpio.c index a2ac0917f1a615..9e54273af0ca81 100644 --- a/arch/cris/arch-v32/drivers/mach-fs/gpio.c +++ b/arch/cris/arch-v32/drivers/mach-fs/gpio.c @@ -964,11 +964,11 @@ gpio_init(void) * in some tests. */ if (request_irq(TIMER0_INTR_VECT, gpio_poll_timer_interrupt, - IRQF_SHARED | IRQF_DISABLED, "gpio poll", &alarmlist)) + IRQF_SHARED, "gpio poll", &alarmlist)) printk(KERN_ERR "timer0 irq for gpio\n"); if (request_irq(GIO_INTR_VECT, gpio_pa_interrupt, - IRQF_SHARED | IRQF_DISABLED, "gpio PA", &alarmlist)) + IRQF_SHARED, "gpio PA", &alarmlist)) printk(KERN_ERR "PA irq for gpio\n"); #ifdef CONFIG_ETRAX_VIRTUAL_GPIO diff --git a/arch/cris/arch-v32/drivers/sync_serial.c b/arch/cris/arch-v32/drivers/sync_serial.c index 219f704e3221b9..bbb806b68838e0 100644 --- a/arch/cris/arch-v32/drivers/sync_serial.c +++ b/arch/cris/arch-v32/drivers/sync_serial.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -1144,7 +1145,8 @@ static ssize_t sync_serial_read(struct file * file, char * buf, if (file->f_flags & O_NONBLOCK) return -EAGAIN; - interruptible_sleep_on(&port->in_wait_q); + wait_event_interruptible(port->in_wait_q, + !(start == end && !port->full)); if (signal_pending(current)) return -EINTR; diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S index faa644111feb7f..2f19ac6217aafd 100644 --- a/arch/cris/arch-v32/kernel/entry.S +++ b/arch/cris/arch-v32/kernel/entry.S @@ -424,7 +424,7 @@ nmi_interrupt: bpl 1f nop jsr handle_watchdog_bite ; In time.c. - move.d $sp, $r10 ; Pointer to registers + move.d $sp, $r10 ; Pointer to registers 1: btstq REG_BIT(intr_vect, r_nmi, ext), $r0 bpl 1f nop @@ -452,7 +452,7 @@ spurious_interrupt: nop ;; This handles the case when multiple interrupts arrive at the same - ;; time. Jump to the first set interrupt bit in a priotiry fashion. The + ;; time. Jump to the first set interrupt bit in a priority fashion. The ;; hardware will call the unserved interrupts after the handler ;; finishes. .type multiple_interrupt, @function @@ -885,13 +885,29 @@ sys_call_table: .long sys_preadv .long sys_pwritev .long sys_setns /* 335 */ - - /* - * NOTE!! This doesn't have to be exact - we just have - * to make sure we have _enough_ of the "sys_ni_syscall" - * entries. Don't panic if you notice that this hasn't - * been shrunk every time we add a new system call. - */ + .long sys_name_to_handle_at + .long sys_open_by_handle_at + .long sys_rt_tgsigqueueinfo + .long sys_perf_event_open + .long sys_recvmmsg /* 340 */ + .long sys_accept4 + .long sys_fanotify_init + .long sys_fanotify_mark + .long sys_prlimit64 + .long sys_clock_adjtime /* 345 */ + .long sys_syncfs + .long sys_sendmmsg + .long sys_process_vm_readv + .long sys_process_vm_writev + .long sys_kcmp /* 350 */ + .long sys_finit_module + + /* + * NOTE!! This doesn't have to be exact - we just have + * to make sure we have _enough_ of the "sys_ni_syscall" + * entries. Don't panic if you notice that this hasn't + * been shrunk every time we add a new system call. + */ .rept NR_syscalls - (.-sys_call_table) / 4 .long sys_ni_syscall diff --git a/arch/cris/arch-v32/kernel/fasttimer.c b/arch/cris/arch-v32/kernel/fasttimer.c index f6644535b17e19..b130c2c5fdd892 100644 --- a/arch/cris/arch-v32/kernel/fasttimer.c +++ b/arch/cris/arch-v32/kernel/fasttimer.c @@ -786,7 +786,7 @@ int fast_timer_init(void) proc_create("fasttimer", 0, NULL, &proc_fasttimer_fops); #endif /* PROC_FS */ if (request_irq(TIMER0_INTR_VECT, timer_trig_interrupt, - IRQF_SHARED | IRQF_DISABLED, + IRQF_SHARED, "fast timer int", &fast_timer_list)) printk(KERN_ERR "err: fasttimer irq\n"); fast_timer_is_init = 1; diff --git a/arch/cris/arch-v32/kernel/irq.c b/arch/cris/arch-v32/kernel/irq.c index 5ebe6e841820ec..25437ae2812838 100644 --- a/arch/cris/arch-v32/kernel/irq.c +++ b/arch/cris/arch-v32/kernel/irq.c @@ -331,11 +331,11 @@ extern void do_IRQ(int irq, struct pt_regs * regs); void crisv32_do_IRQ(int irq, int block, struct pt_regs* regs) { - /* Interrupts that may not be moved to another CPU and - * are IRQF_DISABLED may skip blocking. This is currently - * only valid for the timer IRQ and the IPI and is used - * for the timer interrupt to avoid watchdog starvation. - */ + /* Interrupts that may not be moved to another CPU may + * skip blocking. This is currently only valid for the + * timer IRQ and the IPI and is used for the timer + * interrupt to avoid watchdog starvation. + */ if (!block) { do_IRQ(irq, regs); return; diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c index fe8e6039db2a04..0698582467ca77 100644 --- a/arch/cris/arch-v32/kernel/smp.c +++ b/arch/cris/arch-v32/kernel/smp.c @@ -64,7 +64,7 @@ static irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id); static int send_ipi(int vector, int wait, cpumask_t cpu_mask); static struct irqaction irq_ipi = { .handler = crisv32_ipi_interrupt, - .flags = IRQF_DISABLED, + .flags = 0, .name = "ipi", }; diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c index 8c4b45efd7b671..ee66866538f891 100644 --- a/arch/cris/arch-v32/kernel/time.c +++ b/arch/cris/arch-v32/kernel/time.c @@ -216,12 +216,10 @@ static inline irqreturn_t timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -/* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain. - * It needs to be IRQF_DISABLED to make the jiffies update work properly. - */ +/* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain. */ static struct irqaction irq_timer = { .handler = timer_interrupt, - .flags = IRQF_SHARED | IRQF_DISABLED, + .flags = IRQF_SHARED, .name = "timer" }; diff --git a/arch/cris/arch-v32/mach-a3/arbiter.c b/arch/cris/arch-v32/mach-a3/arbiter.c index 15f5c9de263998..ab5c421a4de86f 100644 --- a/arch/cris/arch-v32/mach-a3/arbiter.c +++ b/arch/cris/arch-v32/mach-a3/arbiter.c @@ -256,11 +256,11 @@ static void crisv32_arbiter_init(void) crisv32_arbiter_config(1, EXT_REGION, 0); if (request_irq(MEMARB_FOO_INTR_VECT, crisv32_foo_arbiter_irq, - IRQF_DISABLED, "arbiter", NULL)) + 0, "arbiter", NULL)) printk(KERN_ERR "Couldn't allocate arbiter IRQ\n"); if (request_irq(MEMARB_BAR_INTR_VECT, crisv32_bar_arbiter_irq, - IRQF_DISABLED, "arbiter", NULL)) + 0, "arbiter", NULL)) printk(KERN_ERR "Couldn't allocate arbiter IRQ\n"); #ifndef CONFIG_ETRAX_KGDB diff --git a/arch/cris/arch-v32/mach-fs/arbiter.c b/arch/cris/arch-v32/mach-fs/arbiter.c index 3f8ebb5c147713..c97f4d8120f9e4 100644 --- a/arch/cris/arch-v32/mach-fs/arbiter.c +++ b/arch/cris/arch-v32/mach-fs/arbiter.c @@ -184,7 +184,7 @@ static void crisv32_arbiter_init(void) crisv32_arbiter_config(EXT_REGION, 0); crisv32_arbiter_config(INT_REGION, 0); - if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, IRQF_DISABLED, + if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, 0, "arbiter", NULL)) printk(KERN_ERR "Couldn't allocate arbiter IRQ\n"); diff --git a/arch/cris/boot/rescue/kimagerescue.S b/arch/cris/boot/rescue/kimagerescue.S index 6f7b3e61260bea..655b511fecf37f 100644 --- a/arch/cris/boot/rescue/kimagerescue.S +++ b/arch/cris/boot/rescue/kimagerescue.S @@ -50,7 +50,6 @@ nop di -#ifndef CONFIG_SVINTO_SIM ;; setup port PA and PB default initial directions and data ;; (so we can flash LEDs, and so that DTR and others are set) @@ -67,7 +66,6 @@ ;; We need to setup the bus registers before we start using the DRAM #include "../../lib/dram_init.S" -#endif ;; Setup the stack to a suitably high address. ;; We assume 8 MB is the minimum DRAM in an eLinux ;; product and put the sp at the top for now. diff --git a/arch/cris/include/arch-v10/arch/io.h b/arch/cris/include/arch-v10/arch/io.h index f627ad0b8a3d6a..4a724172877f81 100644 --- a/arch/cris/include/arch-v10/arch/io.h +++ b/arch/cris/include/arch-v10/arch/io.h @@ -1,8 +1,6 @@ #ifndef _ASM_ARCH_CRIS_IO_H #define _ASM_ARCH_CRIS_IO_H -#include - /* Etrax shadow registers - which live in arch/cris/kernel/shadows.c */ extern unsigned long gen_config_ii_shadow; @@ -34,7 +32,7 @@ extern volatile unsigned long *port_csp4_addr; /* The LED's on various Etrax-based products are set differently. */ -#if defined(CONFIG_ETRAX_NO_LEDS) || defined(CONFIG_SVINTO_SIM) +#if defined(CONFIG_ETRAX_NO_LEDS) #undef CONFIG_ETRAX_PA_LEDS #undef CONFIG_ETRAX_PB_LEDS #undef CONFIG_ETRAX_CSP0_LEDS @@ -171,29 +169,4 @@ extern volatile unsigned long *port_csp4_addr; #define SOFT_SHUTDOWN() #endif -/* Console I/O for simulated etrax100. Use #ifdef so erroneous - use will be evident. */ -#ifdef CONFIG_SVINTO_SIM - /* Let's use the ucsim interface since it lets us do write(2, ...) */ -#define SIMCOUT(s,len) \ - asm ("moveq 4,$r9 \n\t" \ - "moveq 2,$r10 \n\t" \ - "move.d %0,$r11 \n\t" \ - "move.d %1,$r12 \n\t" \ - "push $irp \n\t" \ - "move 0f,$irp \n\t" \ - "jump -6809 \n" \ - "0: \n\t" \ - "pop $irp" \ - : : "rm" (s), "rm" (len) : "r9","r10","r11","r12","memory") -#define TRACE_ON() __extension__ \ - ({ int _Foofoo; __asm__ volatile ("bmod [%0],%0" : "=r" (_Foofoo) : "0" \ - (255)); _Foofoo; }) - -#define TRACE_OFF() do { __asm__ volatile ("bmod [%0],%0" :: "r" (254)); } while (0) -#define SIM_END() do { __asm__ volatile ("bmod [%0],%0" :: "r" (28)); } while (0) -#define CRIS_CYCLES() __extension__ \ - ({ unsigned long c; asm ("bmod [%1],%0" : "=r" (c) : "r" (27)); c;}) -#endif /* ! defined CONFIG_SVINTO_SIM */ - #endif diff --git a/arch/cris/include/arch-v10/arch/irq.h b/arch/cris/include/arch-v10/arch/irq.h index ca2675ae08ed95..6aecb835037d3c 100644 --- a/arch/cris/include/arch-v10/arch/irq.h +++ b/arch/cris/include/arch-v10/arch/irq.h @@ -141,9 +141,9 @@ __asm__ ( \ * handler is run and it prioritizes the timer interrupt. However if we had BLOCK'ed * it here, we would not get the multiple_irq at all. * - * The non-blocking here is based on the knowledge that the timer interrupt is - * registered as a fast interrupt (IRQF_DISABLED) so that we _know_ there will not - * be an sti() before the timer irq handler is run to acknowledge the interrupt. + * The non-blocking here is based on the knowledge that the timer interrupt runs + * with interrupts disabled, and therefore there will not be an sti() before the + * timer irq handler is run to acknowledge the interrupt. */ #define BUILD_TIMER_IRQ(nr,mask) \ diff --git a/arch/cris/include/arch-v32/arch/irq.h b/arch/cris/include/arch-v32/arch/irq.h index fe3cdd22bed459..0c1b4d3a34e749 100644 --- a/arch/cris/include/arch-v32/arch/irq.h +++ b/arch/cris/include/arch-v32/arch/irq.h @@ -102,9 +102,9 @@ __asm__ ( \ * multiple_irq handler is run and it prioritizes the timer interrupt. However * if we had BLOCK'edit here, we would not get the multiple_irq at all. * - * The non-blocking here is based on the knowledge that the timer interrupt is - * registered as a fast interrupt (IRQF_DISABLED) so that we _know_ there will not - * be an sti() before the timer irq handler is run to acknowledge the interrupt. + * The non-blocking here is based on the knowledge that the timer interrupt runs + * with interrupts disabled, and therefore there will not be an sti() before the + * timer irq handler is run to acknowledge the interrupt. */ #define BUILD_TIMER_IRQ(nr, mask) \ void IRQ_NAME(nr); \ diff --git a/arch/cris/include/asm/unistd.h b/arch/cris/include/asm/unistd.h index 0ff3f6889842b7..5cc7d1991e482b 100644 --- a/arch/cris/include/asm/unistd.h +++ b/arch/cris/include/asm/unistd.h @@ -4,7 +4,7 @@ #include -#define NR_syscalls 336 +#define NR_syscalls 360 #include diff --git a/arch/cris/include/uapi/asm/unistd.h b/arch/cris/include/uapi/asm/unistd.h index 48842896f6c2fb..f3287face443b4 100644 --- a/arch/cris/include/uapi/asm/unistd.h +++ b/arch/cris/include/uapi/asm/unistd.h @@ -340,5 +340,21 @@ #define __NR_preadv 333 #define __NR_pwritev 334 #define __NR_setns 335 +#define __NR_name_to_handle_at 336 +#define __NR_open_by_handle_at 337 +#define __NR_rt_tgsigqueueinfo 338 +#define __NR_perf_event_open 339 +#define __NR_recvmmsg 340 +#define __NR_accept4 341 +#define __NR_fanotify_init 342 +#define __NR_fanotify_mark 343 +#define __NR_prlimit64 344 +#define __NR_clock_adjtime 345 +#define __NR_syncfs 346 +#define __NR_sendmmsg 347 +#define __NR_process_vm_readv 348 +#define __NR_process_vm_writev 349 +#define __NR_kcmp 350 +#define __NR_finit_module 351 #endif /* _UAPI_ASM_CRIS_UNISTD_H_ */ diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c index d36836dbbc0722..dd0be5de55d5b6 100644 --- a/arch/cris/kernel/irq.c +++ b/arch/cris/kernel/irq.c @@ -40,9 +40,6 @@ /* called by the assembler IRQ entry functions defined in irq.h * to dispatch the interrupts to registered handlers - * interrupts are disabled upon entry - depending on if the - * interrupt was registered with IRQF_DISABLED or not, interrupts - * are re-enabled or not. */ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) diff --git a/arch/frv/Makefile b/arch/frv/Makefile index 4d1b1e9baef102..2a8fb730d1caa1 100644 --- a/arch/frv/Makefile +++ b/arch/frv/Makefile @@ -74,13 +74,6 @@ KBUILD_CFLAGS += -mno-fdpic -mgpr-32 -msoft-float -mno-media KBUILD_CFLAGS += -ffixed-fcc3 -ffixed-cc3 -ffixed-gr15 -ffixed-icc2 KBUILD_AFLAGS += -mno-fdpic -# make sure the .S files get compiled with debug info -# and disable optimisations that are unhelpful whilst debugging -ifdef CONFIG_DEBUG_INFO -#KBUILD_CFLAGS += -O1 -KBUILD_AFLAGS += -Wa,--gdwarf2 -endif - head-y := arch/frv/kernel/head.o core-y += arch/frv/kernel/ arch/frv/mm/ diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h index afd45e0d552e13..ae763d8bf55acf 100644 --- a/arch/ia64/include/asm/unistd.h +++ b/arch/ia64/include/asm/unistd.h @@ -11,7 +11,7 @@ -#define NR_syscalls 312 /* length of syscall table */ +#define NR_syscalls 314 /* length of syscall table */ /* * The following defines stop scripts/checksyscalls.sh from complaining about diff --git a/arch/ia64/include/uapi/asm/unistd.h b/arch/ia64/include/uapi/asm/unistd.h index 34fd6fe46da1e6..715e85f858de5e 100644 --- a/arch/ia64/include/uapi/asm/unistd.h +++ b/arch/ia64/include/uapi/asm/unistd.h @@ -325,5 +325,7 @@ #define __NR_process_vm_writev 1333 #define __NR_accept4 1334 #define __NR_finit_module 1335 +#define __NR_sched_setattr 1336 +#define __NR_sched_getattr 1337 #endif /* _UAPI_ASM_IA64_UNISTD_H */ diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index ddea607f948aaa..fa8d61a312a7ee 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1773,6 +1773,8 @@ sys_call_table: data8 sys_process_vm_writev data8 sys_accept4 data8 sys_finit_module // 1335 + data8 sys_sched_setattr + data8 sys_sched_getattr .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */ diff --git a/arch/m68k/emu/nfblock.c b/arch/m68k/emu/nfblock.c index 0721858fbd1ef6..2d75ae246167a3 100644 --- a/arch/m68k/emu/nfblock.c +++ b/arch/m68k/emu/nfblock.c @@ -62,17 +62,18 @@ struct nfhd_device { static void nfhd_make_request(struct request_queue *queue, struct bio *bio) { struct nfhd_device *dev = queue->queuedata; - struct bio_vec *bvec; - int i, dir, len, shift; - sector_t sec = bio->bi_sector; + struct bio_vec bvec; + struct bvec_iter iter; + int dir, len, shift; + sector_t sec = bio->bi_iter.bi_sector; dir = bio_data_dir(bio); shift = dev->bshift; - bio_for_each_segment(bvec, bio, i) { - len = bvec->bv_len; + bio_for_each_segment(bvec, bio, iter) { + len = bvec.bv_len; len >>= 9; nfhd_read_write(dev->id, 0, dir, sec >> shift, len >> shift, - bvec_to_phys(bvec)); + bvec_to_phys(&bvec)); sec += len; } bio_endio(bio, 0); diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 8d581ab06c5df6..79b9bcdfe4982a 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -26,6 +26,8 @@ config MICROBLAZE select GENERIC_CPU_DEVICES select GENERIC_ATOMIC64 select GENERIC_CLOCKEVENTS + select COMMON_CLK + select GENERIC_SCHED_CLOCK select GENERIC_IDLE_POLL_SETUP select MODULES_USE_ELF_RELA select CLONE_BACKWARDS3 diff --git a/arch/microblaze/Makefile b/arch/microblaze/Makefile index 40350a3c24e907..a69eaf2ab13014 100644 --- a/arch/microblaze/Makefile +++ b/arch/microblaze/Makefile @@ -1,3 +1,5 @@ +KBUILD_DEFCONFIG := mmu_defconfig + ifeq ($(CONFIG_MMU),y) UTS_SYSNAME = -DUTS_SYSNAME=\"Linux\" else diff --git a/arch/microblaze/include/asm/cpuinfo.h b/arch/microblaze/include/asm/cpuinfo.h index 7d6831ac8a46ee..3337417fcdca3b 100644 --- a/arch/microblaze/include/asm/cpuinfo.h +++ b/arch/microblaze/include/asm/cpuinfo.h @@ -91,15 +91,18 @@ extern struct cpuinfo cpuinfo; /* fwd declarations of the various CPUinfo populators */ void setup_cpuinfo(void); +void setup_cpuinfo_clk(void); void set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu); void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu); static inline unsigned int fcpu(struct device_node *cpu, char *n) { - const __be32 *val; - return (val = of_get_property(cpu, n, NULL)) ? - be32_to_cpup(val) : 0; + u32 val = 0; + + of_property_read_u32(cpu, n, &val); + + return val; } #endif /* _ASM_MICROBLAZE_CPUINFO_H */ diff --git a/arch/microblaze/include/asm/delay.h b/arch/microblaze/include/asm/delay.h index 05b7d39e439121..66fc24c24238f6 100644 --- a/arch/microblaze/include/asm/delay.h +++ b/arch/microblaze/include/asm/delay.h @@ -13,6 +13,8 @@ #ifndef _ASM_MICROBLAZE_DELAY_H #define _ASM_MICROBLAZE_DELAY_H +#include + extern inline void __delay(unsigned long loops) { asm volatile ("# __delay \n\t" \ diff --git a/arch/microblaze/include/asm/io.h b/arch/microblaze/include/asm/io.h index 2565cb94f32f08..3fbb7f1db3bcdc 100644 --- a/arch/microblaze/include/asm/io.h +++ b/arch/microblaze/include/asm/io.h @@ -89,6 +89,11 @@ static inline unsigned int readl(const volatile void __iomem *addr) { return le32_to_cpu(*(volatile unsigned int __force *)addr); } +#define readq readq +static inline u64 readq(const volatile void __iomem *addr) +{ + return le64_to_cpu(__raw_readq(addr)); +} static inline void writeb(unsigned char v, volatile void __iomem *addr) { *(volatile unsigned char __force *)addr = v; @@ -101,6 +106,7 @@ static inline void writel(unsigned int v, volatile void __iomem *addr) { *(volatile unsigned int __force *)addr = cpu_to_le32(v); } +#define writeq(b, addr) __raw_writeq(cpu_to_le64(b), addr) /* ioread and iowrite variants. thease are for now same as __raw_ * variants of accessors. we might check for endianess in the feature @@ -342,4 +348,12 @@ static inline void outsl(unsigned long addr, const void *buffer, int count) #define iowrite32_rep(p, src, count) \ outsl((unsigned long) (p), (src), (count)) +#define readb_relaxed readb +#define readw_relaxed readw +#define readl_relaxed readl + +#define writeb_relaxed writeb +#define writew_relaxed writew +#define writel_relaxed writel + #endif /* _ASM_MICROBLAZE_IO_H */ diff --git a/arch/microblaze/include/asm/sections.h b/arch/microblaze/include/asm/sections.h index c07ed5d2a82034..1b281d3ea73441 100644 --- a/arch/microblaze/include/asm/sections.h +++ b/arch/microblaze/include/asm/sections.h @@ -16,7 +16,6 @@ # ifndef __ASSEMBLY__ extern char _ssbss[], _esbss[]; extern unsigned long __ivt_start[], __ivt_end[]; -extern char _etext[], _stext[]; extern u32 _fdt_start[], _fdt_end[]; diff --git a/arch/microblaze/include/uapi/asm/Kbuild b/arch/microblaze/include/uapi/asm/Kbuild index 6d7d7f4aaae867..1aac99f87df158 100644 --- a/arch/microblaze/include/uapi/asm/Kbuild +++ b/arch/microblaze/include/uapi/asm/Kbuild @@ -1,6 +1,8 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm +generic-y += types.h + header-y += auxvec.h header-y += bitsperlong.h header-y += byteorder.h @@ -31,5 +33,4 @@ header-y += statfs.h header-y += swab.h header-y += termbits.h header-y += termios.h -header-y += types.h header-y += unistd.h diff --git a/arch/microblaze/include/uapi/asm/types.h b/arch/microblaze/include/uapi/asm/types.h deleted file mode 100644 index b9e79bc580dd6c..00000000000000 --- a/arch/microblaze/include/uapi/asm/types.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c index ee46894154101c..93c26cf50de525 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c +++ b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c @@ -112,7 +112,4 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu) CI(num_wr_brk, NUMBER_OF_WR_ADDR_BRK); CI(fpga_family_code, TARGET_FAMILY); - - /* take timebase-frequency from DTS */ - ci->cpu_clock_freq = fcpu(cpu, "timebase-frequency"); } diff --git a/arch/microblaze/kernel/cpu/cpuinfo-static.c b/arch/microblaze/kernel/cpu/cpuinfo-static.c index 592bb2e838c4f5..4854285b26e778 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo-static.c +++ b/arch/microblaze/kernel/cpu/cpuinfo-static.c @@ -113,8 +113,6 @@ void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu) ci->num_rd_brk = fcpu(cpu, "xlnx,number-of-rd-addr-brk"); ci->num_wr_brk = fcpu(cpu, "xlnx,number-of-wr-addr-brk"); - ci->cpu_clock_freq = fcpu(cpu, "timebase-frequency"); - ci->pvr_user1 = fcpu(cpu, "xlnx,pvr-user1"); ci->pvr_user2 = fcpu(cpu, "xlnx,pvr-user2"); diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c index c9203b1007aad8..234acad79b9ec4 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo.c +++ b/arch/microblaze/kernel/cpu/cpuinfo.c @@ -8,6 +8,7 @@ * for more details. */ +#include #include #include #include @@ -39,6 +40,7 @@ const struct cpu_ver_key cpu_ver_lookup[] = { {"8.30.a", 0x17}, {"8.40.a", 0x18}, {"8.40.b", 0x19}, + {"8.50.a", 0x1a}, {"9.0", 0x1b}, {"9.1", 0x1d}, {NULL, 0}, @@ -68,11 +70,10 @@ const struct family_string_key family_string_lookup[] = { }; struct cpuinfo cpuinfo; +static struct device_node *cpu; void __init setup_cpuinfo(void) { - struct device_node *cpu = NULL; - cpu = (struct device_node *) of_find_node_by_type(NULL, "cpu"); if (!cpu) pr_err("You don't have cpu!!!\n"); @@ -102,3 +103,22 @@ void __init setup_cpuinfo(void) pr_warn("%s: Stream instructions enabled" " - USERSPACE CAN LOCK THIS KERNEL!\n", __func__); } + +void __init setup_cpuinfo_clk(void) +{ + struct clk *clk; + + clk = of_clk_get(cpu, 0); + if (IS_ERR(clk)) { + pr_err("ERROR: CPU CCF input clock not found\n"); + /* take timebase-frequency from DTS */ + cpuinfo.cpu_clock_freq = fcpu(cpu, "timebase-frequency"); + } else { + cpuinfo.cpu_clock_freq = clk_get_rate(clk); + } + + if (!cpuinfo.cpu_clock_freq) { + pr_err("ERROR: CPU clock frequency not setup\n"); + BUG(); + } +} diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S index 817b7eec95b6de..17645b2e2f075d 100644 --- a/arch/microblaze/kernel/head.S +++ b/arch/microblaze/kernel/head.S @@ -64,6 +64,10 @@ real_start: #endif mts rmsr, r0 +/* Disable stack protection from bootloader */ + mts rslr, r0 + addi r8, r0, 0xFFFFFFFF + mts rshr, r8 /* * According to Xilinx, msrclr instruction behaves like 'mfs rX,rpc' * if the msrclr instruction is not enabled. We use this to detect diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S index fc6b89f4dd31d2..0b11a4469debae 100644 --- a/arch/microblaze/kernel/hw_exception_handler.S +++ b/arch/microblaze/kernel/hw_exception_handler.S @@ -147,15 +147,14 @@ or r3, r0, NUM_TO_REG (regnum); /* Shift right instruction depending on available configuration */ - #if CONFIG_XILINX_MICROBLAZE0_USE_BARREL > 0 - #define BSRLI(rD, rA, imm) \ - bsrli rD, rA, imm - #else - #define BSRLI(rD, rA, imm) BSRLI ## imm (rD, rA) + #if CONFIG_XILINX_MICROBLAZE0_USE_BARREL == 0 /* Only the used shift constants defined here - add more if needed */ #define BSRLI2(rD, rA) \ srl rD, rA; /* << 1 */ \ srl rD, rD; /* << 2 */ + #define BSRLI4(rD, rA) \ + BSRLI2(rD, rA); \ + BSRLI2(rD, rD) #define BSRLI10(rD, rA) \ srl rD, rA; /* << 1 */ \ srl rD, rD; /* << 2 */ \ @@ -170,7 +169,33 @@ #define BSRLI20(rD, rA) \ BSRLI10(rD, rA); \ BSRLI10(rD, rD) + + .macro bsrli, rD, rA, IMM + .if (\IMM) == 2 + BSRLI2(\rD, \rA) + .elseif (\IMM) == 10 + BSRLI10(\rD, \rA) + .elseif (\IMM) == 12 + BSRLI2(\rD, \rA) + BSRLI10(\rD, \rD) + .elseif (\IMM) == 14 + BSRLI4(\rD, \rA) + BSRLI10(\rD, \rD) + .elseif (\IMM) == 20 + BSRLI20(\rD, \rA) + .elseif (\IMM) == 24 + BSRLI4(\rD, \rA) + BSRLI20(\rD, \rD) + .elseif (\IMM) == 28 + BSRLI4(\rD, \rA) + BSRLI4(\rD, \rD) + BSRLI20(\rD, \rD) + .else + .error "BSRLI shift macros \IMM" + .endif + .endm #endif + #endif /* CONFIG_MMU */ .extern other_exception_handler /* Defined in exception.c */ @@ -604,7 +629,7 @@ ex_handler_done: ex4: tophys(r4,r4) /* Create L1 (pgdir/pmd) address */ - BSRLI(r5,r3, PGDIR_SHIFT - 2) + bsrli r5, r3, PGDIR_SHIFT - 2 andi r5, r5, PAGE_SIZE - 4 /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */ or r4, r4, r5 @@ -613,7 +638,7 @@ ex_handler_done: beqi r5, ex2 /* Bail if no table */ tophys(r5,r5) - BSRLI(r6,r3,PTE_SHIFT) /* Compute PTE address */ + bsrli r6, r3, PTE_SHIFT /* Compute PTE address */ andi r6, r6, PAGE_SIZE - 4 or r5, r5, r6 lwi r4, r5, 0 /* Get Linux PTE */ @@ -705,7 +730,7 @@ ex_handler_done: ex6: tophys(r4,r4) /* Create L1 (pgdir/pmd) address */ - BSRLI(r5,r3, PGDIR_SHIFT - 2) + bsrli r5, r3, PGDIR_SHIFT - 2 andi r5, r5, PAGE_SIZE - 4 /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */ or r4, r4, r5 @@ -714,7 +739,7 @@ ex_handler_done: beqi r5, ex7 /* Bail if no table */ tophys(r5,r5) - BSRLI(r6,r3,PTE_SHIFT) /* Compute PTE address */ + bsrli r6, r3, PTE_SHIFT /* Compute PTE address */ andi r6, r6, PAGE_SIZE - 4 or r5, r5, r6 lwi r4, r5, 0 /* Get Linux PTE */ @@ -776,7 +801,7 @@ ex_handler_done: ex9: tophys(r4,r4) /* Create L1 (pgdir/pmd) address */ - BSRLI(r5,r3, PGDIR_SHIFT - 2) + bsrli r5, r3, PGDIR_SHIFT - 2 andi r5, r5, PAGE_SIZE - 4 /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */ or r4, r4, r5 @@ -785,7 +810,7 @@ ex_handler_done: beqi r5, ex10 /* Bail if no table */ tophys(r5,r5) - BSRLI(r6,r3,PTE_SHIFT) /* Compute PTE address */ + bsrli r6, r3, PTE_SHIFT /* Compute PTE address */ andi r6, r6, PAGE_SIZE - 4 or r5, r5, r6 lwi r4, r5, 0 /* Get Linux PTE */ @@ -922,7 +947,7 @@ ex_handler_done: .ent _unaligned_data_exception _unaligned_data_exception: andi r8, r3, 0x3E0; /* Mask and extract the register operand */ - BSRLI(r8,r8,2); /* r8 >> 2 = register operand * 8 */ + bsrli r8, r8, 2; /* r8 >> 2 = register operand * 8 */ andi r6, r3, 0x400; /* Extract ESR[S] */ bneid r6, ex_sw_vm; andi r6, r3, 0x800; /* Extract ESR[W] - delay slot */ diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index 8de8ebc309f15b..67cc4b282cc127 100644 --- a/arch/microblaze/kernel/setup.c +++ b/arch/microblaze/kernel/setup.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -136,7 +137,7 @@ void __init machine_early_init(const char *cmdline, unsigned int ram, lockdep_init(); /* initialize device tree for usage in early_printk */ - early_init_devtree((void *)_fdt_start); + early_init_devtree(_fdt_start); #ifdef CONFIG_EARLY_PRINTK setup_early_printk(NULL); @@ -152,8 +153,7 @@ void __init machine_early_init(const char *cmdline, unsigned int ram, if (fdt) pr_info("FDT at 0x%08x\n", fdt); else - pr_info("Compiled-in FDT at 0x%08x\n", - (unsigned int)_fdt_start); + pr_info("Compiled-in FDT at %p\n", _fdt_start); #ifdef CONFIG_MTD_UCLINUX pr_info("Found romfs @ 0x%08x (0x%08x)\n", @@ -175,7 +175,7 @@ void __init machine_early_init(const char *cmdline, unsigned int ram, #else if (!msr) { pr_info("!!!Your kernel not setup MSR instruction but "); - pr_cont"CPU have it %x\n", msr); + pr_cont("CPU have it %x\n", msr); } #endif @@ -196,6 +196,8 @@ void __init machine_early_init(const char *cmdline, unsigned int ram, void __init time_init(void) { + of_clk_init(NULL); + setup_cpuinfo_clk(); clocksource_of_init(); } diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c index 3e39b1082fdf84..fb0c61443f196e 100644 --- a/arch/microblaze/kernel/timer.c +++ b/arch/microblaze/kernel/timer.c @@ -12,12 +12,12 @@ #include #include #include +#include #include #include #include #include #include -#include static void __iomem *timer_baseaddr; @@ -167,10 +167,15 @@ static __init void xilinx_clockevent_init(void) clockevents_register_device(&clockevent_xilinx_timer); } +static u64 xilinx_clock_read(void) +{ + return in_be32(timer_baseaddr + TCR1); +} + static cycle_t xilinx_read(struct clocksource *cs) { /* reading actual value of timer 1 */ - return (cycle_t) (in_be32(timer_baseaddr + TCR1)); + return (cycle_t)xilinx_clock_read(); } static struct timecounter xilinx_tc = { @@ -222,17 +227,17 @@ static int __init xilinx_clocksource_init(void) return 0; } -/* - * We have to protect accesses before timer initialization - * and return 0 for sched_clock function below. - */ -static int timer_initialized; - static void __init xilinx_timer_init(struct device_node *timer) { + struct clk *clk; + static int initialized; u32 irq; u32 timer_num = 1; - int ret; + + if (initialized) + return; + + initialized = 1; timer_baseaddr = of_iomap(timer, 0); if (!timer_baseaddr) { @@ -250,10 +255,20 @@ static void __init xilinx_timer_init(struct device_node *timer) pr_info("%s: irq=%d\n", timer->full_name, irq); - /* If there is clock-frequency property than use it */ - ret = of_property_read_u32(timer, "clock-frequency", &timer_clock_freq); - if (ret < 0) + clk = of_clk_get(timer, 0); + if (IS_ERR(clk)) { + pr_err("ERROR: timer CCF input clock not found\n"); + /* If there is clock-frequency property than use it */ + of_property_read_u32(timer, "clock-frequency", + &timer_clock_freq); + } else { + timer_clock_freq = clk_get_rate(clk); + } + + if (!timer_clock_freq) { + pr_err("ERROR: Using CPU clock frequency\n"); timer_clock_freq = cpuinfo.cpu_clock_freq; + } freq_div_hz = timer_clock_freq / HZ; @@ -263,18 +278,8 @@ static void __init xilinx_timer_init(struct device_node *timer) #endif xilinx_clocksource_init(); xilinx_clockevent_init(); - timer_initialized = 1; -} -unsigned long long notrace sched_clock(void) -{ - if (timer_initialized) { - struct clocksource *cs = &clocksource_microblaze; - - cycle_t cyc = cnt32_to_63(cs->read(NULL)) & LLONG_MAX; - return clocksource_cyc2ns(cyc, cs->mult, cs->shift); - } - return 0; + sched_clock_register(xilinx_clock_read, 32, timer_clock_freq); } CLOCKSOURCE_OF_DECLARE(xilinx_timer, "xlnx,xps-timer-1.00.a", diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S index 936d01a689d741..be9488d697347c 100644 --- a/arch/microblaze/kernel/vmlinux.lds.S +++ b/arch/microblaze/kernel/vmlinux.lds.S @@ -51,6 +51,7 @@ SECTIONS { . = ALIGN(16); RODATA EXCEPTION_TABLE(16) + NOTES /* * sdata2 section can go anywhere, but must be word aligned diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index c02f1c03a22e7e..dcae3a7035db55 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -116,7 +116,6 @@ config BCM47XX select CEVT_R4K select CSRC_R4K select DMA_NONCOHERENT - select FW_CFE select HW_HAS_PCI select IRQ_CPU select SYS_HAS_CPU_MIPS32_R1 @@ -124,6 +123,7 @@ config BCM47XX select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_HAS_EARLY_PRINTK + select EARLY_PRINTK_8250 if EARLY_PRINTK help Support for BCM47XX based boards @@ -134,14 +134,13 @@ config BCM63XX select CSRC_R4K select DMA_NONCOHERENT select IRQ_CPU - select SYS_HAS_CPU_MIPS32_R1 - select SYS_HAS_CPU_BMIPS4350 if !BCM63XX_CPU_6338 && !BCM63XX_CPU_6345 && !BCM63XX_CPU_6348 select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN select SYS_HAS_EARLY_PRINTK select SWAP_IO_SPACE select ARCH_REQUIRE_GPIOLIB select HAVE_CLK + select MIPS_L1_CACHE_SHIFT_4 help Support for BCM63XX based boards @@ -186,6 +185,7 @@ config MACH_DECSTATION select SYS_SUPPORTS_128HZ select SYS_SUPPORTS_256HZ select SYS_SUPPORTS_1024HZ + select MIPS_L1_CACHE_SHIFT_4 help This enables support for DEC's MIPS based workstations. For details see the Linux/MIPS FAQ on and the @@ -305,7 +305,7 @@ config MIPS_MALTA select CEVT_R4K select CSRC_R4K select CSRC_GIC - select DMA_NONCOHERENT + select DMA_MAYBE_COHERENT select GENERIC_ISA_DMA select HAVE_PCSPKR_PLATFORM select IRQ_CPU @@ -324,7 +324,6 @@ config MIPS_MALTA select SYS_HAS_CPU_MIPS64_R2 select SYS_HAS_CPU_NEVADA select SYS_HAS_CPU_RM7000 - select SYS_HAS_EARLY_PRINTK select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN @@ -349,6 +348,7 @@ config MIPS_SEAD3 select DMA_NONCOHERENT select IRQ_CPU select IRQ_GIC + select LIBFDT select MIPS_MSC select SYS_HAS_CPU_MIPS32_R1 select SYS_HAS_CPU_MIPS32_R2 @@ -471,6 +471,7 @@ config SGI_IP22 select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN + select MIPS_L1_CACHE_SHIFT_7 help This are the SGI Indy, Challenge S and Indigo2, as well as certain OEM variants like the Tandem CMN B006S. To compile a Linux kernel @@ -491,6 +492,7 @@ config SGI_IP27 select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_NUMA select SYS_SUPPORTS_SMP + select MIPS_L1_CACHE_SHIFT_7 help This are the SGI Origin 200, Origin 2000 and Onyx 2 Graphics workstations. To compile a Linux kernel that runs on these, say Y @@ -697,6 +699,7 @@ config MIKROTIK_RB532 select SWAP_IO_SPACE select BOOT_RAW select ARCH_REQUIRE_GPIOLIB + select MIPS_L1_CACHE_SHIFT_4 help Support the Mikrotik(tm) RouterBoard 532 series, based on the IDT RC32434 SoC. @@ -779,6 +782,7 @@ config NLM_XLP_BOARD select CEVT_R4K select CSRC_R4K select IRQ_CPU + select ARCH_SUPPORTS_MSI select ZONE_DMA32 if 64BIT select SYNC_R4K select SYS_HAS_EARLY_PRINTK @@ -897,6 +901,10 @@ config FW_CFE config ARCH_DMA_ADDR_T_64BIT def_bool (HIGHMEM && 64BIT_PHYS_ADDR) || 64BIT +config DMA_MAYBE_COHERENT + select DMA_NONCOHERENT + bool + config DMA_COHERENT bool @@ -1091,11 +1099,24 @@ config FW_SNIPROM config BOOT_ELF32 bool +config MIPS_L1_CACHE_SHIFT_4 + bool + +config MIPS_L1_CACHE_SHIFT_5 + bool + +config MIPS_L1_CACHE_SHIFT_6 + bool + +config MIPS_L1_CACHE_SHIFT_7 + bool + config MIPS_L1_CACHE_SHIFT int - default "4" if MACH_DECSTATION || MIKROTIK_RB532 || PMC_MSP4200_EVAL || SOC_RT288X - default "6" if MIPS_CPU_SCACHE - default "7" if SGI_IP22 || SGI_IP27 || SGI_IP28 || SNI_RM || CPU_CAVIUM_OCTEON + default "4" if MIPS_L1_CACHE_SHIFT_4 + default "5" if MIPS_L1_CACHE_SHIFT_5 + default "6" if MIPS_L1_CACHE_SHIFT_6 + default "7" if MIPS_L1_CACHE_SHIFT_7 default "5" config HAVE_STD_PC_SERIAL_PORT @@ -1375,47 +1396,31 @@ config CPU_CAVIUM_OCTEON select LIBFDT select USE_OF select USB_EHCI_BIG_ENDIAN_MMIO + select SYS_HAS_DMA_OPS + select MIPS_L1_CACHE_SHIFT_7 help The Cavium Octeon processor is a highly integrated chip containing many ethernet hardware widgets for networking tasks. The processor can have up to 16 Mips64v2 cores and 8 integrated gigabit ethernets. Full details can be found at http://www.caviumnetworks.com. -config CPU_BMIPS3300 - bool "BMIPS3300" - depends on SYS_HAS_CPU_BMIPS3300 - select CPU_BMIPS - help - Broadcom BMIPS3300 processors. - -config CPU_BMIPS4350 - bool "BMIPS4350" - depends on SYS_HAS_CPU_BMIPS4350 - select CPU_BMIPS - select SYS_SUPPORTS_SMP - select SYS_SUPPORTS_HOTPLUG_CPU - help - Broadcom BMIPS4350 ("VIPER") processors. - -config CPU_BMIPS4380 - bool "BMIPS4380" - depends on SYS_HAS_CPU_BMIPS4380 - select CPU_BMIPS - select SYS_SUPPORTS_SMP - select SYS_SUPPORTS_HOTPLUG_CPU - help - Broadcom BMIPS4380 processors. - -config CPU_BMIPS5000 - bool "BMIPS5000" - depends on SYS_HAS_CPU_BMIPS5000 - select CPU_BMIPS +config CPU_BMIPS + bool "Broadcom BMIPS" + depends on SYS_HAS_CPU_BMIPS + select CPU_MIPS32 + select CPU_BMIPS32_3300 if SYS_HAS_CPU_BMIPS32_3300 + select CPU_BMIPS4350 if SYS_HAS_CPU_BMIPS4350 + select CPU_BMIPS4380 if SYS_HAS_CPU_BMIPS4380 + select CPU_BMIPS5000 if SYS_HAS_CPU_BMIPS5000 + select CPU_SUPPORTS_32BIT_KERNEL + select DMA_NONCOHERENT + select IRQ_CPU + select SWAP_IO_SPACE + select WEAK_ORDERING select CPU_SUPPORTS_HIGHMEM - select MIPS_CPU_SCACHE - select SYS_SUPPORTS_SMP - select SYS_SUPPORTS_HOTPLUG_CPU + select CPU_HAS_PREFETCH help - Broadcom BMIPS5000 processors. + Support for BMIPS32/3300/4350/4380 and BMIPS5000 processors. config CPU_XLR bool "Netlogic XLR SoC" @@ -1498,14 +1503,25 @@ config CPU_LOONGSON1 select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_HIGHMEM -config CPU_BMIPS +config CPU_BMIPS32_3300 + select SMP_UP if SMP bool - select CPU_MIPS32 - select CPU_SUPPORTS_32BIT_KERNEL - select DMA_NONCOHERENT - select IRQ_CPU - select SWAP_IO_SPACE - select WEAK_ORDERING + +config CPU_BMIPS4350 + bool + select SYS_SUPPORTS_SMP + select SYS_SUPPORTS_HOTPLUG_CPU + +config CPU_BMIPS4380 + bool + select SYS_SUPPORTS_SMP + select SYS_SUPPORTS_HOTPLUG_CPU + +config CPU_BMIPS5000 + bool + select MIPS_CPU_SCACHE + select SYS_SUPPORTS_SMP + select SYS_SUPPORTS_HOTPLUG_CPU config SYS_HAS_CPU_LOONGSON2E bool @@ -1579,17 +1595,24 @@ config SYS_HAS_CPU_SB1 config SYS_HAS_CPU_CAVIUM_OCTEON bool -config SYS_HAS_CPU_BMIPS3300 +config SYS_HAS_CPU_BMIPS + bool + +config SYS_HAS_CPU_BMIPS32_3300 bool + select SYS_HAS_CPU_BMIPS config SYS_HAS_CPU_BMIPS4350 bool + select SYS_HAS_CPU_BMIPS config SYS_HAS_CPU_BMIPS4380 bool + select SYS_HAS_CPU_BMIPS config SYS_HAS_CPU_BMIPS5000 bool + select SYS_HAS_CPU_BMIPS config SYS_HAS_CPU_XLR bool @@ -1797,6 +1820,7 @@ config IP22_CPU_SCACHE config MIPS_CPU_SCACHE bool select BOARD_SCACHE + select MIPS_L1_CACHE_SHIFT_6 config R5000_CPU_SCACHE bool @@ -1833,59 +1857,48 @@ choice prompt "MIPS MT options" config MIPS_MT_DISABLED - bool "Disable multithreading support." + bool "Disable multithreading support" help - Use this option if your workload can't take advantage of - MIPS hardware multithreading support. On systems that don't have - the option of an MT-enabled processor this option will be the only - option in this menu. + Use this option if your platform does not support the MT ASE + which is hardware multithreading support. On systems without + an MT-enabled processor, this will be the only option that is + available in this menu. config MIPS_MT_SMP bool "Use 1 TC on each available VPE for SMP" depends on SYS_SUPPORTS_MULTITHREADING select CPU_MIPSR2_IRQ_VI select CPU_MIPSR2_IRQ_EI + select SYNC_R4K select MIPS_MT select SMP - select SYS_SUPPORTS_SCHED_SMT if SMP - select SYS_SUPPORTS_SMP select SMP_UP + select SYS_SUPPORTS_SMP + select SYS_SUPPORTS_SCHED_SMT select MIPS_PERF_SHARED_TC_COUNTERS help - This is a kernel model which is known a VSMP but lately has been - marketesed into SMVP. - Virtual SMP uses the processor's VPEs to implement virtual - processors. In currently available configuration of the 34K processor - this allows for a dual processor. Both processors will share the same - primary caches; each will obtain the half of the TLB for it's own - exclusive use. For a layman this model can be described as similar to - what Intel calls Hyperthreading. - - For further information see http://www.linux-mips.org/wiki/34K#VSMP + This is a kernel model which is known as SMVP. This is supported + on cores with the MT ASE and uses the available VPEs to implement + virtual processors which supports SMP. This is equivalent to the + Intel Hyperthreading feature. For further information go to + . config MIPS_MT_SMTC - bool "SMTC: Use all TCs on all VPEs for SMP" + bool "Use all TCs on all VPEs for SMP (DEPRECATED)" depends on CPU_MIPS32_R2 - #depends on CPU_MIPS64_R2 # once there is hardware ... depends on SYS_SUPPORTS_MULTITHREADING select CPU_MIPSR2_IRQ_VI select CPU_MIPSR2_IRQ_EI select MIPS_MT - select NR_CPUS_DEFAULT_8 select SMP - select SYS_SUPPORTS_SMP select SMP_UP + select SYS_SUPPORTS_SMP + select NR_CPUS_DEFAULT_8 help - This is a kernel model which is known a SMTC or lately has been - marketesed into SMVP. - is presenting the available TC's of the core as processors to Linux. - On currently available 34K processors this means a Linux system will - see up to 5 processors. The implementation of the SMTC kernel differs - significantly from VSMP and cannot efficiently coexist in the same - kernel binary so the choice between VSMP and SMTC is a compile time - decision. - - For further information see http://www.linux-mips.org/wiki/34K#SMTC + This is a kernel model which is known as SMTC. This is + supported on cores with the MT ASE and presents all TCs + available on all VPEs to support SMP. For further + information see . endchoice @@ -1922,6 +1935,16 @@ config MIPS_VPE_LOADER Includes a loader for loading an elf relocatable object onto another VPE and running it. +config MIPS_VPE_LOADER_CMP + bool + default "y" + depends on MIPS_VPE_LOADER && MIPS_CMP + +config MIPS_VPE_LOADER_MT + bool + default "y" + depends on MIPS_VPE_LOADER && !MIPS_CMP + config MIPS_MT_SMTC_IM_BACKSTOP bool "Use per-TC register bits as backstop for inhibited IM bits" depends on MIPS_MT_SMTC @@ -1955,24 +1978,29 @@ config MIPS_VPE_LOADER_TOM you to ensure the amount you put in the option and the space your program requires is less or equal to the amount physically present. -# this should possibly be in drivers/char, but it is rather cpu related. Hmmm config MIPS_VPE_APSP_API bool "Enable support for AP/SP API (RTLX)" depends on MIPS_VPE_LOADER help +config MIPS_VPE_APSP_API_CMP + bool + default "y" + depends on MIPS_VPE_APSP_API && MIPS_CMP + +config MIPS_VPE_APSP_API_MT + bool + default "y" + depends on MIPS_VPE_APSP_API && !MIPS_CMP + config MIPS_CMP - bool "MIPS CMP framework support" - depends on SYS_SUPPORTS_MIPS_CMP - select SMP + bool "MIPS CMP support" + depends on SYS_SUPPORTS_MIPS_CMP && MIPS_MT_SMP select SYNC_R4K - select SYS_SUPPORTS_SMP - select SYS_SUPPORTS_SCHED_SMT if SMP select WEAK_ORDERING default n help - This is a placeholder option for the GCMP work. It will need to - be handled differently... + Enable Coherency Manager processor (CMP) support. config SB1_PASS_1_WORKAROUNDS bool @@ -2324,6 +2352,23 @@ config SECCOMP If unsure, say Y. Only embedded should say N here. +config MIPS_O32_FP64_SUPPORT + bool "Support for O32 binaries using 64-bit FP" + depends on 32BIT || MIPS32_O32 + default y + help + When this is enabled, the kernel will support use of 64-bit floating + point registers with binaries using the O32 ABI along with the + EF_MIPS_FP64 ELF header flag (typically built with -mfp64). On + 32-bit MIPS systems this support is at the cost of increasing the + size and complexity of the compiled FPU emulator. Thus if you are + running a MIPS32 system and know that none of your userland binaries + will require 64-bit floating point, you may wish to reduce the size + of your kernel & potentially improve FP emulation performance by + saying N here. + + If unsure, say Y. + config USE_OF bool select OF diff --git a/arch/mips/Makefile b/arch/mips/Makefile index efe50787cd897c..9b8556de999376 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -114,7 +114,7 @@ cflags-$(CONFIG_CPU_BIG_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*e cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL $(undef-all) $(predef-le)) cflags-$(CONFIG_CPU_HAS_SMARTMIPS) += $(call cc-option,-msmartmips) -cflags-$(CONFIG_CPU_MICROMIPS) += $(call cc-option,-mmicromips -mno-jals) +cflags-$(CONFIG_CPU_MICROMIPS) += $(call cc-option,-mmicromips) cflags-$(CONFIG_SB1XXX_CORELIS) += $(call cc-option,-mno-sched-prolog) \ -fno-omit-frame-pointer diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c index 0c7fce2a3c12f0..bdb28dee8fddcd 100644 --- a/arch/mips/alchemy/common/power.c +++ b/arch/mips/alchemy/common/power.c @@ -29,7 +29,6 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/arch/mips/alchemy/devboards/db1000.c b/arch/mips/alchemy/devboards/db1000.c index 11f3ad20321ca6..5483906e0f86d1 100644 --- a/arch/mips/alchemy/devboards/db1000.c +++ b/arch/mips/alchemy/devboards/db1000.c @@ -534,13 +534,10 @@ static int __init db1000_dev_init(void) s0 = AU1100_GPIO1_INT; s1 = AU1100_GPIO4_INT; + gpio_request(19, "sd0_cd"); + gpio_request(20, "sd1_cd"); gpio_direction_input(19); /* sd0 cd# */ gpio_direction_input(20); /* sd1 cd# */ - gpio_direction_input(21); /* touch pendown# */ - gpio_direction_input(207); /* SPI MISO */ - gpio_direction_output(208, 0); /* SPI MOSI */ - gpio_direction_output(209, 1); /* SPI SCK */ - gpio_direction_output(210, 1); /* SPI CS# */ /* spi_gpio on SSI0 pins */ pfc = __raw_readl((void __iomem *)SYS_PINFUNC); diff --git a/arch/mips/ar7/time.c b/arch/mips/ar7/time.c index 22c93213b233db..1dc6c3b37f91dd 100644 --- a/arch/mips/ar7/time.c +++ b/arch/mips/ar7/time.c @@ -18,7 +18,6 @@ * Setting up the clock on the MIPS boards. */ -#include #include #include #include diff --git a/arch/mips/ath79/common.h b/arch/mips/ath79/common.h index 648d2dafbc56bf..a3120714f0b754 100644 --- a/arch/mips/ath79/common.h +++ b/arch/mips/ath79/common.h @@ -15,7 +15,6 @@ #define __ATH79_COMMON_H #include -#include #define ATH79_MEM_SIZE_MIN (2 * 1024 * 1024) #define ATH79_MEM_SIZE_MAX (128 * 1024 * 1024) diff --git a/arch/mips/bcm47xx/Kconfig b/arch/mips/bcm47xx/Kconfig index 2b8b118398c458..09cb6f7aa3dbf4 100644 --- a/arch/mips/bcm47xx/Kconfig +++ b/arch/mips/bcm47xx/Kconfig @@ -2,6 +2,7 @@ if BCM47XX config BCM47XX_SSB bool "SSB Support for Broadcom BCM47XX" + select SYS_HAS_CPU_BMIPS32_3300 select SSB select SSB_DRIVER_MIPS select SSB_DRIVER_EXTIF @@ -11,6 +12,7 @@ config BCM47XX_SSB select SSB_PCICORE_HOSTMODE if PCI select SSB_DRIVER_GPIO select GPIOLIB + select LEDS_GPIO_REGISTER default y help Add support for old Broadcom BCM47xx boards with Sonics Silicon Backplane support. @@ -20,6 +22,7 @@ config BCM47XX_SSB config BCM47XX_BCMA bool "BCMA Support for Broadcom BCM47XX" select SYS_HAS_CPU_MIPS32_R2 + select CPU_MIPSR2_IRQ_VI select BCMA select BCMA_HOST_SOC select BCMA_DRIVER_MIPS @@ -27,6 +30,7 @@ config BCM47XX_BCMA select BCMA_DRIVER_PCI_HOSTMODE if PCI select BCMA_DRIVER_GPIO select GPIOLIB + select LEDS_GPIO_REGISTER default y help Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus. diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile index c52daf9b05c638..4688b6a6211b7a 100644 --- a/arch/mips/bcm47xx/Makefile +++ b/arch/mips/bcm47xx/Makefile @@ -4,5 +4,4 @@ # obj-y += irq.o nvram.o prom.o serial.o setup.o time.o sprom.o -obj-y += board.o -obj-$(CONFIG_BCM47XX_SSB) += wgt634u.o +obj-y += board.o buttons.o leds.o diff --git a/arch/mips/bcm47xx/bcm47xx_private.h b/arch/mips/bcm47xx/bcm47xx_private.h new file mode 100644 index 00000000000000..5c94acebf76a72 --- /dev/null +++ b/arch/mips/bcm47xx/bcm47xx_private.h @@ -0,0 +1,12 @@ +#ifndef LINUX_BCM47XX_PRIVATE_H_ +#define LINUX_BCM47XX_PRIVATE_H_ + +#include + +/* buttons.c */ +int __init bcm47xx_buttons_register(void); + +/* leds.c */ +void __init bcm47xx_leds_register(void); + +#endif diff --git a/arch/mips/bcm47xx/board.c b/arch/mips/bcm47xx/board.c index f3f6bfe68a2ae4..6d612e2b949b20 100644 --- a/arch/mips/bcm47xx/board.c +++ b/arch/mips/bcm47xx/board.c @@ -36,26 +36,32 @@ static const struct bcm47xx_board_type_list1 bcm47xx_board_list_model_name[] __initconst = { {{BCM47XX_BOARD_DLINK_DIR130, "D-Link DIR-130"}, "DIR-130"}, {{BCM47XX_BOARD_DLINK_DIR330, "D-Link DIR-330"}, "DIR-330"}, - { {0}, 0}, + { {0}, NULL}, }; /* model_no */ static const struct bcm47xx_board_type_list1 bcm47xx_board_list_model_no[] __initconst = { {{BCM47XX_BOARD_ASUS_WL700GE, "Asus WL700"}, "WL700"}, - { {0}, 0}, + { {0}, NULL}, }; /* machine_name */ static const struct bcm47xx_board_type_list1 bcm47xx_board_list_machine_name[] __initconst = { {{BCM47XX_BOARD_LINKSYS_WRTSL54GS, "Linksys WRTSL54GS"}, "WRTSL54GS"}, - { {0}, 0}, + { {0}, NULL}, }; /* hardware_version */ static const struct bcm47xx_board_type_list1 bcm47xx_board_list_hardware_version[] __initconst = { + {{BCM47XX_BOARD_ASUS_RTN10U, "Asus RT-N10U"}, "RTN10U"}, + {{BCM47XX_BOARD_ASUS_RTN12, "Asus RT-N12"}, "RT-N12"}, + {{BCM47XX_BOARD_ASUS_RTN12B1, "Asus RT-N12B1"}, "RTN12B1"}, + {{BCM47XX_BOARD_ASUS_RTN12C1, "Asus RT-N12C1"}, "RTN12C1"}, + {{BCM47XX_BOARD_ASUS_RTN12D1, "Asus RT-N12D1"}, "RTN12D1"}, + {{BCM47XX_BOARD_ASUS_RTN12HP, "Asus RT-N12HP"}, "RTN12HP"}, {{BCM47XX_BOARD_ASUS_RTN16, "Asus RT-N16"}, "RT-N16-"}, {{BCM47XX_BOARD_ASUS_WL320GE, "Asus WL320GE"}, "WL320G-"}, {{BCM47XX_BOARD_ASUS_WL330GE, "Asus WL330GE"}, "WL330GE-"}, @@ -66,7 +72,7 @@ struct bcm47xx_board_type_list1 bcm47xx_board_list_hardware_version[] __initcons {{BCM47XX_BOARD_ASUS_WL520GC, "Asus WL520GC"}, "WL520GC-"}, {{BCM47XX_BOARD_ASUS_WL520GU, "Asus WL520GU"}, "WL520GU-"}, {{BCM47XX_BOARD_BELKIN_F7D4301, "Belkin F7D4301"}, "F7D4301"}, - { {0}, 0}, + { {0}, NULL}, }; /* productid */ @@ -75,19 +81,13 @@ struct bcm47xx_board_type_list1 bcm47xx_board_list_productid[] __initconst = { {{BCM47XX_BOARD_ASUS_RTAC66U, "Asus RT-AC66U"}, "RT-AC66U"}, {{BCM47XX_BOARD_ASUS_RTN10, "Asus RT-N10"}, "RT-N10"}, {{BCM47XX_BOARD_ASUS_RTN10D, "Asus RT-N10D"}, "RT-N10D"}, - {{BCM47XX_BOARD_ASUS_RTN10U, "Asus RT-N10U"}, "RT-N10U"}, - {{BCM47XX_BOARD_ASUS_RTN12, "Asus RT-N12"}, "RT-N12"}, - {{BCM47XX_BOARD_ASUS_RTN12B1, "Asus RT-N12B1"}, "RT-N12B1"}, - {{BCM47XX_BOARD_ASUS_RTN12C1, "Asus RT-N12C1"}, "RT-N12C1"}, - {{BCM47XX_BOARD_ASUS_RTN12D1, "Asus RT-N12D1"}, "RT-N12D1"}, - {{BCM47XX_BOARD_ASUS_RTN12HP, "Asus RT-N12HP"}, "RT-N12HP"}, {{BCM47XX_BOARD_ASUS_RTN15U, "Asus RT-N15U"}, "RT-N15U"}, {{BCM47XX_BOARD_ASUS_RTN16, "Asus RT-N16"}, "RT-N16"}, {{BCM47XX_BOARD_ASUS_RTN53, "Asus RT-N53"}, "RT-N53"}, {{BCM47XX_BOARD_ASUS_RTN66U, "Asus RT-N66U"}, "RT-N66U"}, {{BCM47XX_BOARD_ASUS_WL300G, "Asus WL300G"}, "WL300g"}, {{BCM47XX_BOARD_ASUS_WLHDD, "Asus WLHDD"}, "WLHDD"}, - { {0}, 0}, + { {0}, NULL}, }; /* ModelId */ @@ -97,7 +97,7 @@ struct bcm47xx_board_type_list1 bcm47xx_board_list_ModelId[] __initconst = { {{BCM47XX_BOARD_MOTOROLA_WE800G, "Motorola WE800G"}, "WE800G"}, {{BCM47XX_BOARD_MOTOROLA_WR850GP, "Motorola WR850GP"}, "WR850GP"}, {{BCM47XX_BOARD_MOTOROLA_WR850GV2V3, "Motorola WR850G"}, "WR850G"}, - { {0}, 0}, + { {0}, NULL}, }; /* melco_id or buf1falo_id */ @@ -112,7 +112,7 @@ struct bcm47xx_board_type_list1 bcm47xx_board_list_melco_id[] __initconst = { {{BCM47XX_BOARD_BUFFALO_WZR_G300N, "Buffalo WZR-G300N"}, "31120"}, {{BCM47XX_BOARD_BUFFALO_WZR_RS_G54, "Buffalo WZR-RS-G54"}, "30083"}, {{BCM47XX_BOARD_BUFFALO_WZR_RS_G54HP, "Buffalo WZR-RS-G54HP"}, "30103"}, - { {0}, 0}, + { {0}, NULL}, }; /* boot_hw_model, boot_hw_ver */ @@ -143,7 +143,7 @@ struct bcm47xx_board_type_list2 bcm47xx_board_list_boot_hw[] __initconst = { {{BCM47XX_BOARD_LINKSYS_WRT54G3GV2, "Linksys WRT54G3GV2-VF"}, "WRT54G3GV2-VF", "1.0"}, {{BCM47XX_BOARD_LINKSYS_WRT610NV1, "Linksys WRT610N V1"}, "WRT610N", "1.0"}, {{BCM47XX_BOARD_LINKSYS_WRT610NV2, "Linksys WRT610N V2"}, "WRT610N", "2.0"}, - { {0}, 0}, + { {0}, NULL}, }; /* board_id */ @@ -165,7 +165,7 @@ struct bcm47xx_board_type_list1 bcm47xx_board_list_board_id[] __initconst = { {{BCM47XX_BOARD_NETGEAR_WNR3500V2, "Netgear WNR3500 V2"}, "U12H127T00_NETGEAR"}, {{BCM47XX_BOARD_NETGEAR_WNR3500V2VC, "Netgear WNR3500 V2vc"}, "U12H127T70_NETGEAR"}, {{BCM47XX_BOARD_NETGEAR_WNR834BV2, "Netgear WNR834B V2"}, "U12H081T00_NETGEAR"}, - { {0}, 0}, + { {0}, NULL}, }; /* boardtype, boardnum, boardrev */ @@ -174,7 +174,9 @@ struct bcm47xx_board_type_list3 bcm47xx_board_list_board[] __initconst = { {{BCM47XX_BOARD_HUAWEI_E970, "Huawei E970"}, "0x048e", "0x5347", "0x11"}, {{BCM47XX_BOARD_PHICOMM_M1, "Phicomm M1"}, "0x0590", "80", "0x1104"}, {{BCM47XX_BOARD_ZTE_H218N, "ZTE H218N"}, "0x053d", "1234", "0x1305"}, - { {0}, 0}, + {{BCM47XX_BOARD_NETGEAR_WNR3500L, "Netgear WNR3500L"}, "0x04CF", "3500", "02"}, + {{BCM47XX_BOARD_LINKSYS_WRT54GSV1, "Linksys WRT54GS V1"}, "0x0101", "42", "0x10"}, + { {0}, NULL}, }; static const diff --git a/arch/mips/bcm47xx/buttons.c b/arch/mips/bcm47xx/buttons.c new file mode 100644 index 00000000000000..872c62e93e0e4c --- /dev/null +++ b/arch/mips/bcm47xx/buttons.c @@ -0,0 +1,531 @@ +#include "bcm47xx_private.h" + +#include +#include +#include +#include +#include + +/************************************************** + * Database + **************************************************/ + +#define BCM47XX_GPIO_KEY(_gpio, _code) \ + { \ + .code = _code, \ + .gpio = _gpio, \ + .active_low = 1, \ + } + +/* Asus */ + +static const struct gpio_keys_button +bcm47xx_buttons_asus_rtn12[] __initconst = { + BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(1, KEY_RESTART), + BCM47XX_GPIO_KEY(4, BTN_0), /* Router mode */ + BCM47XX_GPIO_KEY(5, BTN_1), /* Repeater mode */ + BCM47XX_GPIO_KEY(6, BTN_2), /* AP mode */ +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_rtn16[] __initconst = { + BCM47XX_GPIO_KEY(6, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(8, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_rtn66u[] __initconst = { + BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(9, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl300g[] __initconst = { + BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl320ge[] __initconst = { + BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl330ge[] __initconst = { + BCM47XX_GPIO_KEY(2, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl500gd[] __initconst = { + BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl500gpv1[] __initconst = { + BCM47XX_GPIO_KEY(0, KEY_RESTART), + BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl500gpv2[] __initconst = { + BCM47XX_GPIO_KEY(2, KEY_RESTART), + BCM47XX_GPIO_KEY(3, KEY_WPS_BUTTON), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl500w[] __initconst = { + BCM47XX_GPIO_KEY(6, KEY_RESTART), + BCM47XX_GPIO_KEY(7, KEY_WPS_BUTTON), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl520gc[] __initconst = { + BCM47XX_GPIO_KEY(2, KEY_RESTART), + BCM47XX_GPIO_KEY(3, KEY_WPS_BUTTON), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl520gu[] __initconst = { + BCM47XX_GPIO_KEY(2, KEY_RESTART), + BCM47XX_GPIO_KEY(3, KEY_WPS_BUTTON), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl700ge[] __initconst = { + BCM47XX_GPIO_KEY(0, KEY_POWER), /* Hard disk power switch */ + BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), /* EZSetup */ + BCM47XX_GPIO_KEY(6, KEY_COPY), /* Copy data from USB to internal disk */ + BCM47XX_GPIO_KEY(7, KEY_RESTART), /* Hard reset */ +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wlhdd[] __initconst = { + BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +/* Huawei */ + +static const struct gpio_keys_button +bcm47xx_buttons_huawei_e970[] __initconst = { + BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +/* Belkin */ + +static const struct gpio_keys_button +bcm47xx_buttons_belkin_f7d4301[] __initconst = { + BCM47XX_GPIO_KEY(6, KEY_RESTART), + BCM47XX_GPIO_KEY(8, KEY_WPS_BUTTON), +}; + +/* Buffalo */ + +static const struct gpio_keys_button +bcm47xx_buttons_buffalo_whr2_a54g54[] __initconst = { + BCM47XX_GPIO_KEY(4, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_buffalo_whr_g125[] __initconst = { + BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(4, KEY_RESTART), + BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */ +}; + +static const struct gpio_keys_button +bcm47xx_buttons_buffalo_whr_g54s[] __initconst = { + BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(4, KEY_RESTART), + BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */ +}; + +static const struct gpio_keys_button +bcm47xx_buttons_buffalo_whr_hp_g54[] __initconst = { + BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(4, KEY_RESTART), + BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */ +}; + +static const struct gpio_keys_button +bcm47xx_buttons_buffalo_wzr_g300n[] __initconst = { + BCM47XX_GPIO_KEY(4, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_buffalo_wzr_rs_g54[] __initconst = { + BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(4, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_buffalo_wzr_rs_g54hp[] __initconst = { + BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(4, KEY_RESTART), +}; + +/* Dell */ + +static const struct gpio_keys_button +bcm47xx_buttons_dell_tm2300[] __initconst = { + BCM47XX_GPIO_KEY(0, KEY_RESTART), +}; + +/* D-Link */ + +static const struct gpio_keys_button +bcm47xx_buttons_dlink_dir130[] __initconst = { + BCM47XX_GPIO_KEY(3, KEY_RESTART), + BCM47XX_GPIO_KEY(7, KEY_UNKNOWN), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_dlink_dir330[] __initconst = { + BCM47XX_GPIO_KEY(3, KEY_RESTART), + BCM47XX_GPIO_KEY(7, KEY_UNKNOWN), +}; + +/* Linksys */ + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_e1000v1[] __initconst = { + BCM47XX_GPIO_KEY(5, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_e1000v21[] __initconst = { + BCM47XX_GPIO_KEY(9, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(10, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_e2000v1[] __initconst = { + BCM47XX_GPIO_KEY(5, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(8, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_e3000v1[] __initconst = { + BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_e3200v1[] __initconst = { + BCM47XX_GPIO_KEY(5, KEY_RESTART), + BCM47XX_GPIO_KEY(8, KEY_WPS_BUTTON), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_e4200v1[] __initconst = { + BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt150nv1[] __initconst = { + BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt150nv11[] __initconst = { + BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt160nv1[] __initconst = { + BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt160nv3[] __initconst = { + BCM47XX_GPIO_KEY(5, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt300nv11[] __initconst = { + BCM47XX_GPIO_KEY(4, KEY_UNKNOWN), + BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt310nv1[] __initconst = { + BCM47XX_GPIO_KEY(6, KEY_RESTART), + BCM47XX_GPIO_KEY(8, KEY_UNKNOWN), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt610nv1[] __initconst = { + BCM47XX_GPIO_KEY(6, KEY_RESTART), + BCM47XX_GPIO_KEY(8, KEY_WPS_BUTTON), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt610nv2[] __initconst = { + BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +/* Motorola */ + +static const struct gpio_keys_button +bcm47xx_buttons_motorola_we800g[] __initconst = { + BCM47XX_GPIO_KEY(0, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_motorola_wr850gp[] __initconst = { + BCM47XX_GPIO_KEY(5, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_motorola_wr850gv2v3[] __initconst = { + BCM47XX_GPIO_KEY(5, KEY_RESTART), +}; + +/* Netgear */ + +static const struct gpio_keys_button +bcm47xx_buttons_netgear_wndr3400v1[] __initconst = { + BCM47XX_GPIO_KEY(4, KEY_RESTART), + BCM47XX_GPIO_KEY(6, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(8, KEY_RFKILL), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_netgear_wndr3700v3[] __initconst = { + BCM47XX_GPIO_KEY(2, KEY_RFKILL), + BCM47XX_GPIO_KEY(3, KEY_RESTART), + BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_netgear_wndr4500v1[] __initconst = { + BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY(5, KEY_RFKILL), + BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_netgear_wnr834bv2[] __initconst = { + BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +/* SimpleTech */ + +static const struct gpio_keys_button +bcm47xx_buttons_simpletech_simpleshare[] __initconst = { + BCM47XX_GPIO_KEY(0, KEY_RESTART), +}; + +/************************************************** + * Init + **************************************************/ + +static struct gpio_keys_platform_data bcm47xx_button_pdata; + +static struct platform_device bcm47xx_buttons_gpio_keys = { + .name = "gpio-keys", + .dev = { + .platform_data = &bcm47xx_button_pdata, + } +}; + +/* Copy data from __initconst */ +static int __init bcm47xx_buttons_copy(const struct gpio_keys_button *buttons, + size_t nbuttons) +{ + size_t size = nbuttons * sizeof(*buttons); + + bcm47xx_button_pdata.buttons = kmalloc(size, GFP_KERNEL); + if (!bcm47xx_button_pdata.buttons) + return -ENOMEM; + memcpy(bcm47xx_button_pdata.buttons, buttons, size); + bcm47xx_button_pdata.nbuttons = nbuttons; + + return 0; +} + +#define bcm47xx_copy_bdata(dev_buttons) \ + bcm47xx_buttons_copy(dev_buttons, ARRAY_SIZE(dev_buttons)); + +int __init bcm47xx_buttons_register(void) +{ + enum bcm47xx_board board = bcm47xx_board_get(); + int err; + + switch (board) { + case BCM47XX_BOARD_ASUS_RTN12: + err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_rtn12); + break; + case BCM47XX_BOARD_ASUS_RTN16: + err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_rtn16); + break; + case BCM47XX_BOARD_ASUS_RTN66U: + err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_rtn66u); + break; + case BCM47XX_BOARD_ASUS_WL300G: + err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl300g); + break; + case BCM47XX_BOARD_ASUS_WL320GE: + err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl320ge); + break; + case BCM47XX_BOARD_ASUS_WL330GE: + err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl330ge); + break; + case BCM47XX_BOARD_ASUS_WL500GD: + err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl500gd); + break; + case BCM47XX_BOARD_ASUS_WL500GPV1: + err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl500gpv1); + break; + case BCM47XX_BOARD_ASUS_WL500GPV2: + err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl500gpv2); + break; + case BCM47XX_BOARD_ASUS_WL500W: + err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl500w); + break; + case BCM47XX_BOARD_ASUS_WL520GC: + err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl520gc); + break; + case BCM47XX_BOARD_ASUS_WL520GU: + err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl520gu); + break; + case BCM47XX_BOARD_ASUS_WL700GE: + err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl700ge); + break; + case BCM47XX_BOARD_ASUS_WLHDD: + err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wlhdd); + break; + + case BCM47XX_BOARD_BELKIN_F7D4301: + err = bcm47xx_copy_bdata(bcm47xx_buttons_belkin_f7d4301); + break; + + case BCM47XX_BOARD_BUFFALO_WHR2_A54G54: + err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_whr2_a54g54); + break; + case BCM47XX_BOARD_BUFFALO_WHR_G125: + err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_whr_g125); + break; + case BCM47XX_BOARD_BUFFALO_WHR_G54S: + err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_whr_g54s); + break; + case BCM47XX_BOARD_BUFFALO_WHR_HP_G54: + err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_whr_hp_g54); + break; + case BCM47XX_BOARD_BUFFALO_WZR_G300N: + err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_wzr_g300n); + break; + case BCM47XX_BOARD_BUFFALO_WZR_RS_G54: + err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_wzr_rs_g54); + break; + case BCM47XX_BOARD_BUFFALO_WZR_RS_G54HP: + err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_wzr_rs_g54hp); + break; + + case BCM47XX_BOARD_DELL_TM2300: + err = bcm47xx_copy_bdata(bcm47xx_buttons_dell_tm2300); + break; + + case BCM47XX_BOARD_DLINK_DIR130: + err = bcm47xx_copy_bdata(bcm47xx_buttons_dlink_dir130); + break; + case BCM47XX_BOARD_DLINK_DIR330: + err = bcm47xx_copy_bdata(bcm47xx_buttons_dlink_dir330); + break; + + case BCM47XX_BOARD_HUAWEI_E970: + err = bcm47xx_copy_bdata(bcm47xx_buttons_huawei_e970); + break; + + case BCM47XX_BOARD_LINKSYS_E1000V1: + err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e1000v1); + break; + case BCM47XX_BOARD_LINKSYS_E1000V21: + err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e1000v21); + break; + case BCM47XX_BOARD_LINKSYS_E2000V1: + err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e2000v1); + break; + case BCM47XX_BOARD_LINKSYS_E3000V1: + err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e3000v1); + break; + case BCM47XX_BOARD_LINKSYS_E3200V1: + err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e3200v1); + break; + case BCM47XX_BOARD_LINKSYS_E4200V1: + err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e4200v1); + break; + case BCM47XX_BOARD_LINKSYS_WRT150NV1: + err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt150nv1); + break; + case BCM47XX_BOARD_LINKSYS_WRT150NV11: + err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt150nv11); + break; + case BCM47XX_BOARD_LINKSYS_WRT160NV1: + err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt160nv1); + break; + case BCM47XX_BOARD_LINKSYS_WRT160NV3: + err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt160nv3); + break; + case BCM47XX_BOARD_LINKSYS_WRT300NV11: + err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt300nv11); + break; + case BCM47XX_BOARD_LINKSYS_WRT310NV1: + err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt310nv1); + break; + case BCM47XX_BOARD_LINKSYS_WRT610NV1: + err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt610nv1); + break; + case BCM47XX_BOARD_LINKSYS_WRT610NV2: + err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt610nv2); + break; + + case BCM47XX_BOARD_MOTOROLA_WE800G: + err = bcm47xx_copy_bdata(bcm47xx_buttons_motorola_we800g); + break; + case BCM47XX_BOARD_MOTOROLA_WR850GP: + err = bcm47xx_copy_bdata(bcm47xx_buttons_motorola_wr850gp); + break; + case BCM47XX_BOARD_MOTOROLA_WR850GV2V3: + err = bcm47xx_copy_bdata(bcm47xx_buttons_motorola_wr850gv2v3); + break; + + case BCM47XX_BOARD_NETGEAR_WNDR3400V1: + err = bcm47xx_copy_bdata(bcm47xx_buttons_netgear_wndr3400v1); + break; + case BCM47XX_BOARD_NETGEAR_WNDR3700V3: + err = bcm47xx_copy_bdata(bcm47xx_buttons_netgear_wndr3700v3); + break; + case BCM47XX_BOARD_NETGEAR_WNDR4500V1: + err = bcm47xx_copy_bdata(bcm47xx_buttons_netgear_wndr4500v1); + break; + case BCM47XX_BOARD_NETGEAR_WNR834BV2: + err = bcm47xx_copy_bdata(bcm47xx_buttons_netgear_wnr834bv2); + break; + + case BCM47XX_BOARD_SIMPLETECH_SIMPLESHARE: + err = bcm47xx_copy_bdata(bcm47xx_buttons_simpletech_simpleshare); + break; + + default: + pr_debug("No buttons configuration found for this device\n"); + return -ENOTSUPP; + } + + if (err) + return -ENOMEM; + + err = platform_device_register(&bcm47xx_buttons_gpio_keys); + if (err) { + pr_err("Failed to register platform device: %d\n", err); + return err; + } + + return 0; +} diff --git a/arch/mips/bcm47xx/irq.c b/arch/mips/bcm47xx/irq.c index 8cf3833b2d2936..e0585b76ec1941 100644 --- a/arch/mips/bcm47xx/irq.c +++ b/arch/mips/bcm47xx/irq.c @@ -25,10 +25,11 @@ #include #include #include +#include #include #include -void plat_irq_dispatch(void) +asmlinkage void plat_irq_dispatch(void) { u32 cause; @@ -50,6 +51,18 @@ void plat_irq_dispatch(void) do_IRQ(6); } +#define DEFINE_HWx_IRQDISPATCH(x) \ + static void bcm47xx_hw ## x ## _irqdispatch(void) \ + { \ + do_IRQ(x); \ + } +DEFINE_HWx_IRQDISPATCH(2) +DEFINE_HWx_IRQDISPATCH(3) +DEFINE_HWx_IRQDISPATCH(4) +DEFINE_HWx_IRQDISPATCH(5) +DEFINE_HWx_IRQDISPATCH(6) +DEFINE_HWx_IRQDISPATCH(7) + void __init arch_init_irq(void) { #ifdef CONFIG_BCM47XX_BCMA @@ -64,4 +77,14 @@ void __init arch_init_irq(void) } #endif mips_cpu_irq_init(); + + if (cpu_has_vint) { + pr_info("Setting up vectored interrupts\n"); + set_vi_handler(2, bcm47xx_hw2_irqdispatch); + set_vi_handler(3, bcm47xx_hw3_irqdispatch); + set_vi_handler(4, bcm47xx_hw4_irqdispatch); + set_vi_handler(5, bcm47xx_hw5_irqdispatch); + set_vi_handler(6, bcm47xx_hw6_irqdispatch); + set_vi_handler(7, bcm47xx_hw7_irqdispatch); + } } diff --git a/arch/mips/bcm47xx/leds.c b/arch/mips/bcm47xx/leds.c new file mode 100644 index 00000000000000..647d155270664d --- /dev/null +++ b/arch/mips/bcm47xx/leds.c @@ -0,0 +1,542 @@ +#include "bcm47xx_private.h" + +#include +#include + +/************************************************** + * Database + **************************************************/ + +#define BCM47XX_GPIO_LED(_gpio, _color, _function, _active_low, \ + _default_state) \ + { \ + .name = "bcm47xx:" _color ":" _function, \ + .gpio = _gpio, \ + .active_low = _active_low, \ + .default_state = _default_state, \ + } + +#define BCM47XX_GPIO_LED_TRIGGER(_gpio, _color, _function, _active_low, \ + _default_trigger) \ + { \ + .name = "bcm47xx:" _color ":" _function, \ + .gpio = _gpio, \ + .active_low = _active_low, \ + .default_state = LEDS_GPIO_DEFSTATE_OFF, \ + .default_trigger = _default_trigger, \ + } + +/* Asus */ + +static const struct gpio_led +bcm47xx_leds_asus_rtn12[] __initconst = { + BCM47XX_GPIO_LED(2, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(7, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_asus_rtn16[] __initconst = { + BCM47XX_GPIO_LED(1, "blue", "power", 1, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(7, "blue", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_asus_rtn66u[] __initconst = { + BCM47XX_GPIO_LED(12, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(15, "unk", "usb", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl300g[] __initconst = { + BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl320ge[] __initconst = { + BCM47XX_GPIO_LED(0, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(2, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(11, "unk", "link", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl330ge[] __initconst = { + BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl500gd[] __initconst = { + BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl500gpv1[] __initconst = { + BCM47XX_GPIO_LED(1, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl500gpv2[] __initconst = { + BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(1, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl500w[] __initconst = { + BCM47XX_GPIO_LED(5, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl520gc[] __initconst = { + BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(1, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl520gu[] __initconst = { + BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(1, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl700ge[] __initconst = { + BCM47XX_GPIO_LED(1, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), /* Labeled "READY" (there is no "power" LED). Originally ON, flashing on USB activity. */ +}; + +static const struct gpio_led +bcm47xx_leds_asus_wlhdd[] __initconst = { + BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(2, "unk", "usb", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +/* Belkin */ + +static const struct gpio_led +bcm47xx_leds_belkin_f7d4301[] __initconst = { + BCM47XX_GPIO_LED(10, "green", "power", 1, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(11, "amber", "power", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(12, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(13, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(14, "unk", "usb0", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(15, "unk", "usb1", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +/* Buffalo */ + +static const struct gpio_led +bcm47xx_leds_buffalo_whr2_a54g54[] __initconst = { + BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_buffalo_whr_g125[] __initconst = { + BCM47XX_GPIO_LED(1, "unk", "bridge", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(2, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(3, "unk", "internal", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_buffalo_whr_g54s[] __initconst = { + BCM47XX_GPIO_LED(1, "unk", "bridge", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(2, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(3, "unk", "internal", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_buffalo_whr_hp_g54[] __initconst = { + BCM47XX_GPIO_LED(1, "unk", "bridge", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(2, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(3, "unk", "internal", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_buffalo_wzr_g300n[] __initconst = { + BCM47XX_GPIO_LED(1, "unk", "bridge", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_buffalo_wzr_rs_g54[] __initconst = { + BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(1, "unk", "vpn", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_buffalo_wzr_rs_g54hp[] __initconst = { + BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(1, "unk", "vpn", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +/* Dell */ + +static const struct gpio_led +bcm47xx_leds_dell_tm2300[] __initconst = { + BCM47XX_GPIO_LED(6, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(7, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +}; + +/* D-Link */ + +static const struct gpio_led +bcm47xx_leds_dlink_dir130[] __initconst = { + BCM47XX_GPIO_LED_TRIGGER(0, "green", "status", 1, "timer"), /* Originally blinking when device is ready, separated from "power" LED */ + BCM47XX_GPIO_LED(6, "blue", "unk", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_dlink_dir330[] __initconst = { + BCM47XX_GPIO_LED_TRIGGER(0, "green", "status", 1, "timer"), /* Originally blinking when device is ready, separated from "power" LED */ + BCM47XX_GPIO_LED(4, "unk", "usb", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(6, "blue", "unk", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +/* Huawei */ + +static const struct gpio_led +bcm47xx_leds_huawei_e970[] __initconst = { + BCM47XX_GPIO_LED(0, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + +/* Linksys */ + +static const struct gpio_led +bcm47xx_leds_linksys_e1000v1[] __initconst = { + BCM47XX_GPIO_LED(0, "blue", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(1, "blue", "power", 0, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(2, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(4, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_e1000v21[] __initconst = { + BCM47XX_GPIO_LED(5, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(6, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(7, "amber", "wps", 0, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(8, "blue", "wps", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_e2000v1[] __initconst = { + BCM47XX_GPIO_LED(1, "blue", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(2, "blue", "power", 0, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(3, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(4, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_e3000v1[] __initconst = { + BCM47XX_GPIO_LED(0, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(1, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(3, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(5, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(7, "unk", "usb", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_e3200v1[] __initconst = { + BCM47XX_GPIO_LED(3, "green", "power", 1, LEDS_GPIO_DEFSTATE_ON), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_e4200v1[] __initconst = { + BCM47XX_GPIO_LED(5, "white", "power", 1, LEDS_GPIO_DEFSTATE_ON), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt150nv1[] __initconst = { + BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(5, "green", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt150nv11[] __initconst = { + BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(5, "green", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt160nv1[] __initconst = { + BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(5, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt160nv3[] __initconst = { + BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(2, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(4, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt300nv11[] __initconst = { + BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(5, "green", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt310nv1[] __initconst = { + BCM47XX_GPIO_LED(1, "blue", "power", 0, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(9, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt610nv1[] __initconst = { + BCM47XX_GPIO_LED(0, "unk", "usb", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(9, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt610nv2[] __initconst = { + BCM47XX_GPIO_LED(0, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(1, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(3, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(5, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(7, "unk", "usb", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + +/* Motorola */ + +static const struct gpio_led +bcm47xx_leds_motorola_we800g[] __initconst = { + BCM47XX_GPIO_LED(1, "amber", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(2, "unk", "unk", 1, LEDS_GPIO_DEFSTATE_OFF), /* There are only 3 LEDs: Power, Wireless and Device (ethernet) */ + BCM47XX_GPIO_LED(4, "green", "power", 0, LEDS_GPIO_DEFSTATE_ON), +}; + +static const struct gpio_led +bcm47xx_leds_motorola_wr850gp[] __initconst = { + BCM47XX_GPIO_LED(0, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(6, "unk", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_motorola_wr850gv2v3[] __initconst = { + BCM47XX_GPIO_LED(0, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +/* Netgear */ + +static const struct gpio_led +bcm47xx_leds_netgear_wndr3400v1[] __initconst = { + BCM47XX_GPIO_LED(2, "green", "usb", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(3, "green", "power", 0, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(7, "amber", "power", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_netgear_wndr4500v1[] __initconst = { + BCM47XX_GPIO_LED(1, "green", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(2, "green", "power", 1, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(3, "amber", "power", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(8, "green", "usb1", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(9, "green", "2ghz", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(11, "blue", "5ghz", 1, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(14, "green", "usb2", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_netgear_wnr834bv2[] __initconst = { + BCM47XX_GPIO_LED(2, "green", "power", 0, LEDS_GPIO_DEFSTATE_ON), + BCM47XX_GPIO_LED(3, "amber", "power", 0, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(7, "unk", "connected", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + +/* SimpleTech */ + +static const struct gpio_led +bcm47xx_leds_simpletech_simpleshare[] __initconst = { + BCM47XX_GPIO_LED(1, "unk", "status", 1, LEDS_GPIO_DEFSTATE_OFF), /* "Ready" LED */ +}; + +/************************************************** + * Init + **************************************************/ + +static struct gpio_led_platform_data bcm47xx_leds_pdata; + +#define bcm47xx_set_pdata(dev_leds) do { \ + bcm47xx_leds_pdata.leds = dev_leds; \ + bcm47xx_leds_pdata.num_leds = ARRAY_SIZE(dev_leds); \ +} while (0) + +void __init bcm47xx_leds_register(void) +{ + enum bcm47xx_board board = bcm47xx_board_get(); + + switch (board) { + case BCM47XX_BOARD_ASUS_RTN12: + bcm47xx_set_pdata(bcm47xx_leds_asus_rtn12); + break; + case BCM47XX_BOARD_ASUS_RTN16: + bcm47xx_set_pdata(bcm47xx_leds_asus_rtn16); + break; + case BCM47XX_BOARD_ASUS_RTN66U: + bcm47xx_set_pdata(bcm47xx_leds_asus_rtn66u); + break; + case BCM47XX_BOARD_ASUS_WL300G: + bcm47xx_set_pdata(bcm47xx_leds_asus_wl300g); + break; + case BCM47XX_BOARD_ASUS_WL320GE: + bcm47xx_set_pdata(bcm47xx_leds_asus_wl320ge); + break; + case BCM47XX_BOARD_ASUS_WL330GE: + bcm47xx_set_pdata(bcm47xx_leds_asus_wl330ge); + break; + case BCM47XX_BOARD_ASUS_WL500GD: + bcm47xx_set_pdata(bcm47xx_leds_asus_wl500gd); + break; + case BCM47XX_BOARD_ASUS_WL500GPV1: + bcm47xx_set_pdata(bcm47xx_leds_asus_wl500gpv1); + break; + case BCM47XX_BOARD_ASUS_WL500GPV2: + bcm47xx_set_pdata(bcm47xx_leds_asus_wl500gpv2); + break; + case BCM47XX_BOARD_ASUS_WL500W: + bcm47xx_set_pdata(bcm47xx_leds_asus_wl500w); + break; + case BCM47XX_BOARD_ASUS_WL520GC: + bcm47xx_set_pdata(bcm47xx_leds_asus_wl520gc); + break; + case BCM47XX_BOARD_ASUS_WL520GU: + bcm47xx_set_pdata(bcm47xx_leds_asus_wl520gu); + break; + case BCM47XX_BOARD_ASUS_WL700GE: + bcm47xx_set_pdata(bcm47xx_leds_asus_wl700ge); + break; + case BCM47XX_BOARD_ASUS_WLHDD: + bcm47xx_set_pdata(bcm47xx_leds_asus_wlhdd); + break; + + case BCM47XX_BOARD_BELKIN_F7D4301: + bcm47xx_set_pdata(bcm47xx_leds_belkin_f7d4301); + break; + + case BCM47XX_BOARD_BUFFALO_WHR2_A54G54: + bcm47xx_set_pdata(bcm47xx_leds_buffalo_whr2_a54g54); + break; + case BCM47XX_BOARD_BUFFALO_WHR_G125: + bcm47xx_set_pdata(bcm47xx_leds_buffalo_whr_g125); + break; + case BCM47XX_BOARD_BUFFALO_WHR_G54S: + bcm47xx_set_pdata(bcm47xx_leds_buffalo_whr_g54s); + break; + case BCM47XX_BOARD_BUFFALO_WHR_HP_G54: + bcm47xx_set_pdata(bcm47xx_leds_buffalo_whr_hp_g54); + break; + case BCM47XX_BOARD_BUFFALO_WZR_G300N: + bcm47xx_set_pdata(bcm47xx_leds_buffalo_wzr_g300n); + break; + case BCM47XX_BOARD_BUFFALO_WZR_RS_G54: + bcm47xx_set_pdata(bcm47xx_leds_buffalo_wzr_rs_g54); + break; + case BCM47XX_BOARD_BUFFALO_WZR_RS_G54HP: + bcm47xx_set_pdata(bcm47xx_leds_buffalo_wzr_rs_g54hp); + break; + + case BCM47XX_BOARD_DELL_TM2300: + bcm47xx_set_pdata(bcm47xx_leds_dell_tm2300); + break; + + case BCM47XX_BOARD_DLINK_DIR130: + bcm47xx_set_pdata(bcm47xx_leds_dlink_dir130); + break; + case BCM47XX_BOARD_DLINK_DIR330: + bcm47xx_set_pdata(bcm47xx_leds_dlink_dir330); + break; + + case BCM47XX_BOARD_HUAWEI_E970: + bcm47xx_set_pdata(bcm47xx_leds_huawei_e970); + break; + + case BCM47XX_BOARD_LINKSYS_E1000V1: + bcm47xx_set_pdata(bcm47xx_leds_linksys_e1000v1); + break; + case BCM47XX_BOARD_LINKSYS_E1000V21: + bcm47xx_set_pdata(bcm47xx_leds_linksys_e1000v21); + break; + case BCM47XX_BOARD_LINKSYS_E2000V1: + bcm47xx_set_pdata(bcm47xx_leds_linksys_e2000v1); + break; + case BCM47XX_BOARD_LINKSYS_E3000V1: + bcm47xx_set_pdata(bcm47xx_leds_linksys_e3000v1); + break; + case BCM47XX_BOARD_LINKSYS_E3200V1: + bcm47xx_set_pdata(bcm47xx_leds_linksys_e3200v1); + break; + case BCM47XX_BOARD_LINKSYS_E4200V1: + bcm47xx_set_pdata(bcm47xx_leds_linksys_e4200v1); + break; + case BCM47XX_BOARD_LINKSYS_WRT150NV1: + bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt150nv1); + break; + case BCM47XX_BOARD_LINKSYS_WRT150NV11: + bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt150nv11); + break; + case BCM47XX_BOARD_LINKSYS_WRT160NV1: + bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt160nv1); + break; + case BCM47XX_BOARD_LINKSYS_WRT160NV3: + bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt160nv3); + break; + case BCM47XX_BOARD_LINKSYS_WRT300NV11: + bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt300nv11); + break; + case BCM47XX_BOARD_LINKSYS_WRT310NV1: + bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt310nv1); + break; + case BCM47XX_BOARD_LINKSYS_WRT610NV1: + bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt610nv1); + break; + case BCM47XX_BOARD_LINKSYS_WRT610NV2: + bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt610nv2); + break; + + case BCM47XX_BOARD_MOTOROLA_WE800G: + bcm47xx_set_pdata(bcm47xx_leds_motorola_we800g); + break; + case BCM47XX_BOARD_MOTOROLA_WR850GP: + bcm47xx_set_pdata(bcm47xx_leds_motorola_wr850gp); + break; + case BCM47XX_BOARD_MOTOROLA_WR850GV2V3: + bcm47xx_set_pdata(bcm47xx_leds_motorola_wr850gv2v3); + break; + + case BCM47XX_BOARD_NETGEAR_WNDR3400V1: + bcm47xx_set_pdata(bcm47xx_leds_netgear_wndr3400v1); + break; + case BCM47XX_BOARD_NETGEAR_WNDR4500V1: + bcm47xx_set_pdata(bcm47xx_leds_netgear_wndr4500v1); + break; + case BCM47XX_BOARD_NETGEAR_WNR834BV2: + bcm47xx_set_pdata(bcm47xx_leds_netgear_wnr834bv2); + break; + + case BCM47XX_BOARD_SIMPLETECH_SIMPLESHARE: + bcm47xx_set_pdata(bcm47xx_leds_simpletech_simpleshare); + break; + + default: + pr_debug("No LEDs configuration found for this device\n"); + return; + } + + gpio_led_register_device(-1, &bcm47xx_leds_pdata); +} diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c index b4c585b1c62eb6..6decb27cf48b43 100644 --- a/arch/mips/bcm47xx/nvram.c +++ b/arch/mips/bcm47xx/nvram.c @@ -11,7 +11,6 @@ * option) any later version. */ -#include #include #include #include @@ -22,11 +21,11 @@ #include static char nvram_buf[NVRAM_SPACE]; +static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000}; static u32 find_nvram_size(u32 end) { struct nvram_header *header; - u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000}; int i; for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) { diff --git a/arch/mips/bcm47xx/prom.c b/arch/mips/bcm47xx/prom.c index 5cba318bc1cd8e..0af808dfd1ca77 100644 --- a/arch/mips/bcm47xx/prom.c +++ b/arch/mips/bcm47xx/prom.c @@ -28,126 +28,27 @@ #include #include #include +#include +#include #include #include -#include -#include #include #include -static int cfe_cons_handle; -static u16 get_chip_id(void) -{ - switch (bcm47xx_bus_type) { -#ifdef CONFIG_BCM47XX_SSB - case BCM47XX_BUS_TYPE_SSB: - return bcm47xx_bus.ssb.chip_id; -#endif -#ifdef CONFIG_BCM47XX_BCMA - case BCM47XX_BUS_TYPE_BCMA: - return bcm47xx_bus.bcma.bus.chipinfo.id; -#endif - } - return 0; -} +static char bcm47xx_system_type[20] = "Broadcom BCM47XX"; const char *get_system_type(void) { - static char buf[50]; - u16 chip_id = get_chip_id(); - - snprintf(buf, sizeof(buf), - (chip_id > 0x9999) ? "Broadcom BCM%d (%s)" : - "Broadcom BCM%04X (%s)", - chip_id, bcm47xx_board_get_name()); - - return buf; -} - -void prom_putchar(char c) -{ - while (cfe_write(cfe_cons_handle, &c, 1) == 0) - ; + return bcm47xx_system_type; } -static __init void prom_init_cfe(void) +__init void bcm47xx_set_system_type(u16 chip_id) { - uint32_t cfe_ept; - uint32_t cfe_handle; - uint32_t cfe_eptseal; - int argc = fw_arg0; - char **envp = (char **) fw_arg2; - int *prom_vec = (int *) fw_arg3; - - /* - * Check if a loader was used; if NOT, the 4 arguments are - * what CFE gives us (handle, 0, EPT and EPTSEAL) - */ - if (argc < 0) { - cfe_handle = (uint32_t)argc; - cfe_ept = (uint32_t)envp; - cfe_eptseal = (uint32_t)prom_vec; - } else { - if ((int)prom_vec < 0) { - /* - * Old loader; all it gives us is the handle, - * so use the "known" entrypoint and assume - * the seal. - */ - cfe_handle = (uint32_t)prom_vec; - cfe_ept = 0xBFC00500; - cfe_eptseal = CFE_EPTSEAL; - } else { - /* - * Newer loaders bundle the handle/ept/eptseal - * Note: prom_vec is in the loader's useg - * which is still alive in the TLB. - */ - cfe_handle = prom_vec[0]; - cfe_ept = prom_vec[2]; - cfe_eptseal = prom_vec[3]; - } - } - - if (cfe_eptseal != CFE_EPTSEAL) { - /* too early for panic to do any good */ - printk(KERN_ERR "CFE's entrypoint seal doesn't match."); - while (1) ; - } - - cfe_init(cfe_handle, cfe_ept); -} - -static __init void prom_init_console(void) -{ - /* Initialize CFE console */ - cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE); -} - -static __init void prom_init_cmdline(void) -{ - static char buf[COMMAND_LINE_SIZE] __initdata; - - /* Get the kernel command line from CFE */ - if (cfe_getenv("LINUX_CMDLINE", buf, COMMAND_LINE_SIZE) >= 0) { - buf[COMMAND_LINE_SIZE - 1] = 0; - strcpy(arcs_cmdline, buf); - } - - /* Force a console handover by adding a console= argument if needed, - * as CFE is not available anymore later in the boot process. */ - if ((strstr(arcs_cmdline, "console=")) == NULL) { - /* Try to read the default serial port used by CFE */ - if ((cfe_getenv("BOOT_CONSOLE", buf, COMMAND_LINE_SIZE) < 0) - || (strncmp("uart", buf, 4))) - /* Default to uart0 */ - strcpy(buf, "uart0"); - - /* Compute the new command line */ - snprintf(arcs_cmdline, COMMAND_LINE_SIZE, "%s console=ttyS%c,115200", - arcs_cmdline, buf[4]); - } + snprintf(bcm47xx_system_type, sizeof(bcm47xx_system_type), + (chip_id > 0x9999) ? "Broadcom BCM%d" : + "Broadcom BCM%04X", + chip_id); } static __init void prom_init_mem(void) @@ -195,12 +96,16 @@ static __init void prom_init_mem(void) add_memory_region(0, mem, BOOT_MEM_RAM); } +/* + * This is the first serial on the chip common core, it is at this position + * for sb (ssb) and ai (bcma) bus. + */ +#define BCM47XX_SERIAL_ADDR (SSB_ENUM_BASE + SSB_CHIPCO_UART0_DATA) + void __init prom_init(void) { - prom_init_cfe(); - prom_init_console(); - prom_init_cmdline(); prom_init_mem(); + setup_8250_early_printk_port(CKSEG1ADDR(BCM47XX_SERIAL_ADDR), 0, 0); } void __init prom_free_prom_memory(void) diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c index b8ef965705cf6c..2f5bbd68e9a0b7 100644 --- a/arch/mips/bcm47xx/serial.c +++ b/arch/mips/bcm47xx/serial.c @@ -31,7 +31,8 @@ static int __init uart8250_init_ssb(void) memset(&uart8250_data, 0, sizeof(uart8250_data)); - for (i = 0; i < mcore->nr_serial_ports; i++) { + for (i = 0; i < mcore->nr_serial_ports && + i < ARRAY_SIZE(uart8250_data) - 1; i++) { struct plat_serial8250_port *p = &(uart8250_data[i]); struct ssb_serial_port *ssb_port = &(mcore->serial_ports[i]); @@ -55,7 +56,8 @@ static int __init uart8250_init_bcma(void) memset(&uart8250_data, 0, sizeof(uart8250_data)); - for (i = 0; i < cc->nr_serial_ports; i++) { + for (i = 0; i < cc->nr_serial_ports && + i < ARRAY_SIZE(uart8250_data) - 1; i++) { struct plat_serial8250_port *p = &(uart8250_data[i]); struct bcma_serial_port *bcma_port; bcma_port = &(cc->serial_ports[i]); diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 9057728ac56b4c..025be218ea1518 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -26,6 +26,8 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "bcm47xx_private.h" + #include #include #include @@ -35,6 +37,8 @@ #include #include #include +#include +#include #include #include #include @@ -213,12 +217,14 @@ void __init plat_mem_setup(void) #ifdef CONFIG_BCM47XX_BCMA bcm47xx_bus_type = BCM47XX_BUS_TYPE_BCMA; bcm47xx_register_bcma(); + bcm47xx_set_system_type(bcm47xx_bus.bcma.bus.chipinfo.id); #endif } else { printk(KERN_INFO "bcm47xx: using ssb bus\n"); #ifdef CONFIG_BCM47XX_SSB bcm47xx_bus_type = BCM47XX_BUS_TYPE_SSB; bcm47xx_register_ssb(); + bcm47xx_set_system_type(bcm47xx_bus.ssb.chip_id); #endif } @@ -226,8 +232,34 @@ void __init plat_mem_setup(void) _machine_halt = bcm47xx_machine_halt; pm_power_off = bcm47xx_machine_halt; bcm47xx_board_detect(); + mips_set_machine_name(bcm47xx_board_get_name()); } +static int __init bcm47xx_cpu_fixes(void) +{ + switch (bcm47xx_bus_type) { +#ifdef CONFIG_BCM47XX_SSB + case BCM47XX_BUS_TYPE_SSB: + /* Nothing to do */ + break; +#endif +#ifdef CONFIG_BCM47XX_BCMA + case BCM47XX_BUS_TYPE_BCMA: + /* The BCM4706 has a problem with the CPU wait instruction. + * When r4k_wait or r4k_wait_irqoff is used will just hang and + * not return from a msleep(). Removing the cpu_wait + * functionality is a workaround for this problem. The BCM4716 + * does not have this problem. + */ + if (bcm47xx_bus.bcma.bus.chipinfo.id == BCMA_CHIP_ID_BCM4706) + cpu_wait = NULL; + break; +#endif + } + return 0; +} +arch_initcall(bcm47xx_cpu_fixes); + static struct fixed_phy_status bcm47xx_fixed_phy_status __initdata = { .link = 1, .speed = SPEED_100, @@ -248,6 +280,9 @@ static int __init bcm47xx_register_bus_complete(void) break; #endif } + bcm47xx_buttons_register(); + bcm47xx_leds_register(); + fixed_phy_add(PHY_POLL, 0, &bcm47xx_fixed_phy_status); return 0; } diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c index ad03c931b90557..a8b5408dd3495f 100644 --- a/arch/mips/bcm47xx/sprom.c +++ b/arch/mips/bcm47xx/sprom.c @@ -135,7 +135,7 @@ static void nvram_read_leddc(const char *prefix, const char *name, } static void nvram_read_macaddr(const char *prefix, const char *name, - u8 (*val)[6], bool fallback) + u8 val[6], bool fallback) { char buf[100]; int err; @@ -144,11 +144,11 @@ static void nvram_read_macaddr(const char *prefix, const char *name, if (err < 0) return; - bcm47xx_nvram_parse_macaddr(buf, *val); + bcm47xx_nvram_parse_macaddr(buf, val); } static void nvram_read_alpha2(const char *prefix, const char *name, - char (*val)[2], bool fallback) + char val[2], bool fallback) { char buf[10]; int err; @@ -162,7 +162,7 @@ static void nvram_read_alpha2(const char *prefix, const char *name, pr_warn("alpha2 is too long %s\n", buf); return; } - memcpy(val, buf, sizeof(val)); + memcpy(val, buf, 2); } static void bcm47xx_fill_sprom_r1234589(struct ssb_sprom *sprom, @@ -180,7 +180,7 @@ static void bcm47xx_fill_sprom_r1234589(struct ssb_sprom *sprom, fallback); nvram_read_s8(prefix, NULL, "ag1", &sprom->antenna_gain.a1, 0, fallback); - nvram_read_alpha2(prefix, "ccode", &sprom->alpha2, fallback); + nvram_read_alpha2(prefix, "ccode", sprom->alpha2, fallback); } static void bcm47xx_fill_sprom_r12389(struct ssb_sprom *sprom, @@ -633,20 +633,20 @@ static void bcm47xx_fill_sprom_path_r45(struct ssb_sprom *sprom, static void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom, const char *prefix, bool fallback) { - nvram_read_macaddr(prefix, "et0macaddr", &sprom->et0mac, fallback); + nvram_read_macaddr(prefix, "et0macaddr", sprom->et0mac, fallback); nvram_read_u8(prefix, NULL, "et0mdcport", &sprom->et0mdcport, 0, fallback); nvram_read_u8(prefix, NULL, "et0phyaddr", &sprom->et0phyaddr, 0, fallback); - nvram_read_macaddr(prefix, "et1macaddr", &sprom->et1mac, fallback); + nvram_read_macaddr(prefix, "et1macaddr", sprom->et1mac, fallback); nvram_read_u8(prefix, NULL, "et1mdcport", &sprom->et1mdcport, 0, fallback); nvram_read_u8(prefix, NULL, "et1phyaddr", &sprom->et1phyaddr, 0, fallback); - nvram_read_macaddr(prefix, "macaddr", &sprom->il0mac, fallback); - nvram_read_macaddr(prefix, "il0macaddr", &sprom->il0mac, fallback); + nvram_read_macaddr(prefix, "macaddr", sprom->il0mac, fallback); + nvram_read_macaddr(prefix, "il0macaddr", sprom->il0mac, fallback); } static void bcm47xx_fill_board_data(struct ssb_sprom *sprom, const char *prefix, diff --git a/arch/mips/bcm47xx/wgt634u.c b/arch/mips/bcm47xx/wgt634u.c deleted file mode 100644 index c63a4c287b5c21..00000000000000 --- a/arch/mips/bcm47xx/wgt634u.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2007 Aurelien Jarno - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* GPIO definitions for the WGT634U */ -#define WGT634U_GPIO_LED 3 -#define WGT634U_GPIO_RESET 2 -#define WGT634U_GPIO_TP1 7 -#define WGT634U_GPIO_TP2 6 -#define WGT634U_GPIO_TP3 5 -#define WGT634U_GPIO_TP4 4 -#define WGT634U_GPIO_TP5 1 - -static struct gpio_led wgt634u_leds[] = { - { - .name = "power", - .gpio = WGT634U_GPIO_LED, - .active_low = 1, - .default_trigger = "heartbeat", - }, -}; - -static struct gpio_led_platform_data wgt634u_led_data = { - .num_leds = ARRAY_SIZE(wgt634u_leds), - .leds = wgt634u_leds, -}; - -static struct platform_device wgt634u_gpio_leds = { - .name = "leds-gpio", - .id = -1, - .dev = { - .platform_data = &wgt634u_led_data, - } -}; - - -/* 8MiB flash. The struct mtd_partition matches original Netgear WGT634U - firmware. */ -static struct mtd_partition wgt634u_partitions[] = { - { - .name = "cfe", - .offset = 0, - .size = 0x60000, /* 384k */ - .mask_flags = MTD_WRITEABLE /* force read-only */ - }, - { - .name = "config", - .offset = 0x60000, - .size = 0x20000 /* 128k */ - }, - { - .name = "linux", - .offset = 0x80000, - .size = 0x140000 /* 1280k */ - }, - { - .name = "jffs", - .offset = 0x1c0000, - .size = 0x620000 /* 6272k */ - }, - { - .name = "nvram", - .offset = 0x7e0000, - .size = 0x20000 /* 128k */ - }, -}; - -static struct physmap_flash_data wgt634u_flash_data = { - .parts = wgt634u_partitions, - .nr_parts = ARRAY_SIZE(wgt634u_partitions) -}; - -static struct resource wgt634u_flash_resource = { - .flags = IORESOURCE_MEM, -}; - -static struct platform_device wgt634u_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { .platform_data = &wgt634u_flash_data, }, - .resource = &wgt634u_flash_resource, - .num_resources = 1, -}; - -/* Platform devices */ -static struct platform_device *wgt634u_devices[] __initdata = { - &wgt634u_flash, - &wgt634u_gpio_leds, -}; - -static irqreturn_t gpio_interrupt(int irq, void *ignored) -{ - int state; - - /* Interrupts are shared, check if the current one is - a GPIO interrupt. */ - if (!ssb_chipco_irq_status(&bcm47xx_bus.ssb.chipco, - SSB_CHIPCO_IRQ_GPIO)) - return IRQ_NONE; - - state = gpio_get_value(WGT634U_GPIO_RESET); - - /* Interrupt are level triggered, revert the interrupt polarity - to clear the interrupt. */ - ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << WGT634U_GPIO_RESET, - state ? 1 << WGT634U_GPIO_RESET : 0); - - if (!state) { - printk(KERN_INFO "Reset button pressed"); - ctrl_alt_del(); - } - - return IRQ_HANDLED; -} - -static int __init wgt634u_init(void) -{ - /* There is no easy way to detect that we are running on a WGT634U - * machine. Use the MAC address as an heuristic. Netgear Inc. has - * been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx. - */ - u8 *et0mac; - - if (bcm47xx_bus_type != BCM47XX_BUS_TYPE_SSB) - return -ENODEV; - - et0mac = bcm47xx_bus.ssb.sprom.et0mac; - - if (et0mac[0] == 0x00 && - ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) || - (et0mac[1] == 0x0f && et0mac[2] == 0xb5))) { - struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore; - - printk(KERN_INFO "WGT634U machine detected.\n"); - - if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET), - gpio_interrupt, IRQF_SHARED, - "WGT634U GPIO", &bcm47xx_bus.ssb.chipco)) { - gpio_direction_input(WGT634U_GPIO_RESET); - ssb_gpio_intmask(&bcm47xx_bus.ssb, - 1 << WGT634U_GPIO_RESET, - 1 << WGT634U_GPIO_RESET); - ssb_chipco_irq_mask(&bcm47xx_bus.ssb.chipco, - SSB_CHIPCO_IRQ_GPIO, - SSB_CHIPCO_IRQ_GPIO); - } - - wgt634u_flash_data.width = mcore->pflash.buswidth; - wgt634u_flash_resource.start = mcore->pflash.window; - wgt634u_flash_resource.end = mcore->pflash.window - + mcore->pflash.window_size - - 1; - return platform_add_devices(wgt634u_devices, - ARRAY_SIZE(wgt634u_devices)); - } else - return -ENODEV; -} - -module_init(wgt634u_init); diff --git a/arch/mips/bcm63xx/Kconfig b/arch/mips/bcm63xx/Kconfig index b78306ce56c73b..a057fdf111c6c3 100644 --- a/arch/mips/bcm63xx/Kconfig +++ b/arch/mips/bcm63xx/Kconfig @@ -3,33 +3,41 @@ menu "CPU support" config BCM63XX_CPU_3368 bool "support 3368 CPU" + select SYS_HAS_CPU_BMIPS4350 select HW_HAS_PCI config BCM63XX_CPU_6328 bool "support 6328 CPU" + select SYS_HAS_CPU_BMIPS4350 select HW_HAS_PCI config BCM63XX_CPU_6338 bool "support 6338 CPU" + select SYS_HAS_CPU_BMIPS32_3300 select HW_HAS_PCI config BCM63XX_CPU_6345 bool "support 6345 CPU" + select SYS_HAS_CPU_BMIPS32_3300 config BCM63XX_CPU_6348 bool "support 6348 CPU" + select SYS_HAS_CPU_BMIPS32_3300 select HW_HAS_PCI config BCM63XX_CPU_6358 bool "support 6358 CPU" + select SYS_HAS_CPU_BMIPS4350 select HW_HAS_PCI config BCM63XX_CPU_6362 bool "support 6362 CPU" + select SYS_HAS_CPU_BMIPS4350 select HW_HAS_PCI config BCM63XX_CPU_6368 bool "support 6368 CPU" + select SYS_HAS_CPU_BMIPS4350 select HW_HAS_PCI endmenu diff --git a/arch/mips/bcm63xx/Makefile b/arch/mips/bcm63xx/Makefile index ac2807397c1c8c..9019f54aee69fe 100644 --- a/arch/mips/bcm63xx/Makefile +++ b/arch/mips/bcm63xx/Makefile @@ -1,7 +1,7 @@ obj-y += clk.o cpu.o cs.o gpio.o irq.o nvram.o prom.o reset.o \ setup.o timer.o dev-dsp.o dev-enet.o dev-flash.o \ - dev-pcmcia.o dev-rng.o dev-spi.o dev-uart.o dev-wdt.o \ - dev-usb-usbd.o + dev-pcmcia.o dev-rng.o dev-spi.o dev-hsspi.o dev-uart.o \ + dev-wdt.o dev-usb-usbd.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-y += boards/ diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c index 5b974eb125fcee..33727e7f0c79f7 100644 --- a/arch/mips/bcm63xx/boards/board_bcm963xx.c +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -915,6 +916,8 @@ int __init board_register_devices(void) bcm63xx_spi_register(); + bcm63xx_hsspi_register(); + bcm63xx_flash_register(); bcm63xx_led_data.num_leds = ARRAY_SIZE(board.leds); diff --git a/arch/mips/bcm63xx/clk.c b/arch/mips/bcm63xx/clk.c index 43da4ae04cc248..637565284732d3 100644 --- a/arch/mips/bcm63xx/clk.c +++ b/arch/mips/bcm63xx/clk.c @@ -225,6 +225,28 @@ static struct clk clk_spi = { .set = spi_set, }; +/* + * HSSPI clock + */ +static void hsspi_set(struct clk *clk, int enable) +{ + u32 mask; + + if (BCMCPU_IS_6328()) + mask = CKCTL_6328_HSSPI_EN; + else if (BCMCPU_IS_6362()) + mask = CKCTL_6362_HSSPI_EN; + else + return; + + bcm_hwclock_set(mask, enable); +} + +static struct clk clk_hsspi = { + .set = hsspi_set, +}; + + /* * XTM clock */ @@ -346,6 +368,8 @@ struct clk *clk_get(struct device *dev, const char *id) return &clk_usbd; if (!strcmp(id, "spi")) return &clk_spi; + if (!strcmp(id, "hsspi")) + return &clk_hsspi; if (!strcmp(id, "xtm")) return &clk_xtm; if (!strcmp(id, "periph")) @@ -366,3 +390,21 @@ void clk_put(struct clk *clk) } EXPORT_SYMBOL(clk_put); + +#define HSSPI_PLL_HZ_6328 133333333 +#define HSSPI_PLL_HZ_6362 400000000 + +static int __init bcm63xx_clk_init(void) +{ + switch (bcm63xx_get_cpu_id()) { + case BCM6328_CPU_ID: + clk_hsspi.rate = HSSPI_PLL_HZ_6328; + break; + case BCM6362_CPU_ID: + clk_hsspi.rate = HSSPI_PLL_HZ_6362; + break; + } + + return 0; +} +arch_initcall(bcm63xx_clk_init); diff --git a/arch/mips/bcm63xx/cpu.c b/arch/mips/bcm63xx/cpu.c index b713cd64b08740..1b1b8a89959bb1 100644 --- a/arch/mips/bcm63xx/cpu.c +++ b/arch/mips/bcm63xx/cpu.c @@ -123,7 +123,9 @@ unsigned int bcm63xx_get_memory_size(void) static unsigned int detect_cpu_clock(void) { - switch (bcm63xx_get_cpu_id()) { + u16 cpu_id = bcm63xx_get_cpu_id(); + + switch (cpu_id) { case BCM3368_CPU_ID: return 300000000; @@ -249,7 +251,7 @@ static unsigned int detect_cpu_clock(void) } default: - BUG(); + panic("Failed to detect clock for CPU with id=%04X\n", cpu_id); } } diff --git a/arch/mips/bcm63xx/dev-hsspi.c b/arch/mips/bcm63xx/dev-hsspi.c new file mode 100644 index 00000000000000..696abc48e3c8b8 --- /dev/null +++ b/arch/mips/bcm63xx/dev-hsspi.c @@ -0,0 +1,47 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 Jonas Gorski + */ + +#include +#include +#include + +#include +#include +#include + +static struct resource spi_resources[] = { + { + .start = -1, /* filled at runtime */ + .end = -1, /* filled at runtime */ + .flags = IORESOURCE_MEM, + }, + { + .start = -1, /* filled at runtime */ + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bcm63xx_hsspi_device = { + .name = "bcm63xx-hsspi", + .id = 0, + .num_resources = ARRAY_SIZE(spi_resources), + .resource = spi_resources, +}; + +int __init bcm63xx_hsspi_register(void) +{ + if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362()) + return -ENODEV; + + spi_resources[0].start = bcm63xx_regset_address(RSET_HSSPI); + spi_resources[0].end = spi_resources[0].start; + spi_resources[0].end += RSET_HSSPI_SIZE - 1; + spi_resources[1].start = bcm63xx_get_irq_number(IRQ_HSSPI); + + return platform_device_register(&bcm63xx_hsspi_device); +} diff --git a/arch/mips/bcm63xx/early_printk.c b/arch/mips/bcm63xx/early_printk.c index aa8f7f9cc7a4b6..6092226a6d766e 100644 --- a/arch/mips/bcm63xx/early_printk.c +++ b/arch/mips/bcm63xx/early_printk.c @@ -6,9 +6,8 @@ * Copyright (C) 2008 Maxime Bizon */ -#include #include -#include +#include static void wait_xfered(void) { diff --git a/arch/mips/bcm63xx/prom.c b/arch/mips/bcm63xx/prom.c index 8ac4e095e68e24..e1f27d653f603d 100644 --- a/arch/mips/bcm63xx/prom.c +++ b/arch/mips/bcm63xx/prom.c @@ -59,14 +59,12 @@ void __init prom_init(void) /* do low level board init */ board_prom_init(); - if (IS_ENABLED(CONFIG_CPU_BMIPS4350) && IS_ENABLED(CONFIG_SMP)) { - /* set up SMP */ - register_smp_ops(&bmips_smp_ops); - + /* set up SMP */ + if (!register_bmips_smp_ops()) { /* - * BCM6328 might not have its second CPU enabled, while BCM6358 - * needs special handling for its shared TLB, so disable SMP - * for now. + * BCM6328 might not have its second CPU enabled, while BCM3368 + * and BCM6358 need special handling for their shared TLB, so + * disable SMP for now. */ if (BCMCPU_IS_6328()) { reg = bcm_readl(BCM_6328_OTP_BASE + @@ -74,7 +72,7 @@ void __init prom_init(void) if (reg & OTP_6328_REG3_TP1_DISABLED) bmips_smp_enabled = 0; - } else if (BCMCPU_IS_6358()) { + } else if (BCMCPU_IS_3368() || BCMCPU_IS_6358()) { bmips_smp_enabled = 0; } diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile index ca0c343c9ea5ed..61af6b6ab13da2 100644 --- a/arch/mips/boot/compressed/Makefile +++ b/arch/mips/boot/compressed/Makefile @@ -27,10 +27,10 @@ KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \ -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) \ -DKERNEL_ENTRY=$(VMLINUX_ENTRY_ADDRESS) -targets := head.o decompress.o dbg.o uart-16550.o uart-alchemy.o +targets := head.o decompress.o string.o dbg.o uart-16550.o uart-alchemy.o # decompressor objects (linked with vmlinuz) -vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/dbg.o +vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o $(obj)/dbg.o ifdef CONFIG_DEBUG_ZBOOT vmlinuzobjs-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o diff --git a/arch/mips/boot/compressed/dbg.c b/arch/mips/boot/compressed/dbg.c index 134a6162e39413..06c6a5bd175d97 100644 --- a/arch/mips/boot/compressed/dbg.c +++ b/arch/mips/boot/compressed/dbg.c @@ -6,7 +6,6 @@ * need to implement your own putc(). */ #include -#include #include void __weak putc(char c) diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c index a8c6fd6a440667..c00c4ddf451481 100644 --- a/arch/mips/boot/compressed/decompress.c +++ b/arch/mips/boot/compressed/decompress.c @@ -43,33 +43,11 @@ void error(char *x) /* activate the code for pre-boot environment */ #define STATIC static -#if defined(CONFIG_KERNEL_GZIP) || defined(CONFIG_KERNEL_XZ) || \ - defined(CONFIG_KERNEL_LZ4) -void *memcpy(void *dest, const void *src, size_t n) -{ - int i; - const char *s = src; - char *d = dest; - - for (i = 0; i < n; i++) - d[i] = s[i]; - return dest; -} -#endif #ifdef CONFIG_KERNEL_GZIP #include "../../../../lib/decompress_inflate.c" #endif #ifdef CONFIG_KERNEL_BZIP2 -void *memset(void *s, int c, size_t n) -{ - int i; - char *ss = s; - - for (i = 0; i < n; i++) - ss[i] = c; - return s; -} #include "../../../../lib/decompress_bunzip2.c" #endif diff --git a/arch/mips/boot/compressed/string.c b/arch/mips/boot/compressed/string.c new file mode 100644 index 00000000000000..9de9885acd0dbc --- /dev/null +++ b/arch/mips/boot/compressed/string.c @@ -0,0 +1,28 @@ +/* + * arch/mips/boot/compressed/string.c + * + * Very small subset of simple string routines + */ + +#include + +void *memcpy(void *dest, const void *src, size_t n) +{ + int i; + const char *s = src; + char *d = dest; + + for (i = 0; i < n; i++) + d[i] = s[i]; + return dest; +} + +void *memset(void *s, int c, size_t n) +{ + int i; + char *ss = s; + + for (i = 0; i < n; i++) + ss[i] = c; + return s; +} diff --git a/arch/mips/boot/compressed/uart-16550.c b/arch/mips/boot/compressed/uart-16550.c index c01d343ce6add9..237494b7a21afc 100644 --- a/arch/mips/boot/compressed/uart-16550.c +++ b/arch/mips/boot/compressed/uart-16550.c @@ -4,7 +4,6 @@ #include #include -#include #include @@ -19,8 +18,8 @@ #endif #ifdef CONFIG_MACH_JZ4740 -#define UART0_BASE 0xB0030000 -#define PORT(offset) (UART0_BASE + (4 * offset)) +#include +#define PORT(offset) (CKSEG1ADDR(JZ4740_UART0_BASE_ADDR) + (4 * offset)) #endif #ifdef CONFIG_CPU_XLR diff --git a/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c b/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c index 132bccc66a9365..8241fc6aa17d86 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c +++ b/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c @@ -47,6 +47,7 @@ * state. It points to a bootmem named block. */ __cvmx_cmd_queue_all_state_t *__cvmx_cmd_queue_state_ptr; +EXPORT_SYMBOL_GPL(__cvmx_cmd_queue_state_ptr); /** * Initialize the Global queue state pointer. diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c index 0a1283ce47f549..b764df64be4093 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c @@ -722,3 +722,30 @@ int __cvmx_helper_board_hardware_enable(int interface) } return 0; } + +/** + * Get the clock type used for the USB block based on board type. + * Used by the USB code for auto configuration of clock type. + * + * Return USB clock type enumeration + */ +enum cvmx_helper_board_usb_clock_types __cvmx_helper_board_usb_get_clock_type(void) +{ + switch (cvmx_sysinfo_get()->board_type) { + case CVMX_BOARD_TYPE_BBGW_REF: + case CVMX_BOARD_TYPE_LANAI2_A: + case CVMX_BOARD_TYPE_LANAI2_U: + case CVMX_BOARD_TYPE_LANAI2_G: + case CVMX_BOARD_TYPE_NIC10E_66: + case CVMX_BOARD_TYPE_UBNT_E100: + return USB_CLOCK_TYPE_CRYSTAL_12; + case CVMX_BOARD_TYPE_NIC10E: + return USB_CLOCK_TYPE_REF_12; + default: + break; + } + /* Most boards except NIC10e use a 12MHz crystal */ + if (OCTEON_IS_MODEL(OCTEON_FAM_2)) + return USB_CLOCK_TYPE_CRYSTAL_12; + return USB_CLOCK_TYPE_REF_48; +} diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-util.c b/arch/mips/cavium-octeon/executive/cvmx-helper-util.c index 65d2bc9a0bde4a..453d7f66459aab 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-util.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-util.c @@ -251,6 +251,7 @@ int cvmx_helper_setup_red(int pass_thresh, int drop_thresh) return 0; } +EXPORT_SYMBOL_GPL(cvmx_helper_setup_red); /** * Setup the common GMX settings that determine the number of @@ -384,6 +385,7 @@ int cvmx_helper_get_ipd_port(int interface, int port) } return -1; } +EXPORT_SYMBOL_GPL(cvmx_helper_get_ipd_port); /** * Returns the interface number for an IPD/PKO port number. @@ -408,6 +410,7 @@ int cvmx_helper_get_interface_num(int ipd_port) return -1; } +EXPORT_SYMBOL_GPL(cvmx_helper_get_interface_num); /** * Returns the interface index number for an IPD/PKO port @@ -431,3 +434,4 @@ int cvmx_helper_get_interface_index_num(int ipd_port) return -1; } +EXPORT_SYMBOL_GPL(cvmx_helper_get_interface_index_num); diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper.c b/arch/mips/cavium-octeon/executive/cvmx-helper.c index d63d20dfbfb0d0..8553ad5c72b61f 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper.c @@ -67,7 +67,7 @@ void (*cvmx_override_pko_queue_priority) (int pko_port, void (*cvmx_override_ipd_port_setup) (int ipd_port); /* Port count per interface */ -static int interface_port_count[4] = { 0, 0, 0, 0 }; +static int interface_port_count[5]; /* Port last configured link info index by IPD/PKO port */ static cvmx_helper_link_info_t @@ -88,6 +88,7 @@ int cvmx_helper_get_number_of_interfaces(void) else return 3; } +EXPORT_SYMBOL_GPL(cvmx_helper_get_number_of_interfaces); /** * Return the number of ports on an interface. Depending on the @@ -102,6 +103,7 @@ int cvmx_helper_ports_on_interface(int interface) { return interface_port_count[interface]; } +EXPORT_SYMBOL_GPL(cvmx_helper_ports_on_interface); /** * Get the operating mode of an interface. Depending on the Octeon @@ -179,6 +181,7 @@ cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int interface) return CVMX_HELPER_INTERFACE_MODE_RGMII; } } +EXPORT_SYMBOL_GPL(cvmx_helper_interface_get_mode); /** * Configure the IPD/PIP tagging and QoS options for a specific @@ -825,6 +828,7 @@ int cvmx_helper_ipd_and_packet_input_enable(void) __cvmx_helper_errata_fix_ipd_ptr_alignment(); return 0; } +EXPORT_SYMBOL_GPL(cvmx_helper_ipd_and_packet_input_enable); /** * Initialize the PIP, IPD, and PKO hardware to support @@ -903,6 +907,7 @@ int cvmx_helper_initialize_packet_io_global(void) #endif return result; } +EXPORT_SYMBOL_GPL(cvmx_helper_initialize_packet_io_global); /** * Does core local initialization for packet io @@ -947,6 +952,7 @@ cvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port) */ return port_link_info[ipd_port]; } +EXPORT_SYMBOL_GPL(cvmx_helper_link_autoconf); /** * Return the link state of an IPD/PKO port as returned by @@ -1005,6 +1011,7 @@ cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port) } return result; } +EXPORT_SYMBOL_GPL(cvmx_helper_link_get); /** * Configure an IPD/PKO port for the specified link state. This @@ -1060,6 +1067,7 @@ int cvmx_helper_link_set(int ipd_port, cvmx_helper_link_info_t link_info) port_link_info[ipd_port].u64 = link_info.u64; return result; } +EXPORT_SYMBOL_GPL(cvmx_helper_link_set); /** * Configure a port for internal and/or external loopback. Internal loopback diff --git a/arch/mips/cavium-octeon/executive/cvmx-pko.c b/arch/mips/cavium-octeon/executive/cvmx-pko.c index f2c877541597c6..008b881cdf6477 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-pko.c +++ b/arch/mips/cavium-octeon/executive/cvmx-pko.c @@ -140,7 +140,7 @@ void cvmx_pko_disable(void) pko_reg_flags.s.ena_pko = 0; cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64); } - +EXPORT_SYMBOL_GPL(cvmx_pko_disable); /** * Reset the packet output. @@ -182,6 +182,7 @@ void cvmx_pko_shutdown(void) } __cvmx_pko_reset(); } +EXPORT_SYMBOL_GPL(cvmx_pko_shutdown); /** * Configure a output port and the associated queues for use. diff --git a/arch/mips/cavium-octeon/executive/cvmx-spi.c b/arch/mips/cavium-octeon/executive/cvmx-spi.c index ef5198d13a0edd..459e3b1eb61f47 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-spi.c +++ b/arch/mips/cavium-octeon/executive/cvmx-spi.c @@ -177,6 +177,7 @@ int cvmx_spi_restart_interface(int interface, cvmx_spi_mode_t mode, int timeout) return res; } +EXPORT_SYMBOL_GPL(cvmx_spi_restart_interface); /** * Callback to perform SPI4 reset diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index 1830874ff1e24e..6df0f4d8f197a8 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c @@ -171,6 +171,7 @@ device_initcall(octeon_ohci_device_init); static struct of_device_id __initdata octeon_ids[] = { { .compatible = "simple-bus", }, { .compatible = "cavium,octeon-6335-uctl", }, + { .compatible = "cavium,octeon-5750-usbn", }, { .compatible = "cavium,octeon-3860-bootbus", }, { .compatible = "cavium,mdio-mux", }, { .compatible = "gpio-leds", }, @@ -336,14 +337,14 @@ static void __init octeon_fdt_pip_iface(int pip, int idx, u64 *pmac) int p; int count = 0; - if (cvmx_helper_interface_enumerate(idx) == 0) - count = cvmx_helper_ports_on_interface(idx); - snprintf(name_buffer, sizeof(name_buffer), "interface@%d", idx); iface = fdt_subnode_offset(initial_boot_params, pip, name_buffer); if (iface < 0) return; + if (cvmx_helper_interface_enumerate(idx) == 0) + count = cvmx_helper_ports_on_interface(idx); + for (p = 0; p < 16; p++) octeon_fdt_pip_port(iface, idx, p, count - 1, pmac); } @@ -682,6 +683,37 @@ int __init octeon_prune_device_tree(void) } } + /* DWC2 USB */ + alias_prop = fdt_getprop(initial_boot_params, aliases, + "usbn", NULL); + if (alias_prop) { + int usbn = fdt_path_offset(initial_boot_params, alias_prop); + + if (usbn >= 0 && (current_cpu_type() == CPU_CAVIUM_OCTEON2 || + !octeon_has_feature(OCTEON_FEATURE_USB))) { + pr_debug("Deleting usbn\n"); + fdt_nop_node(initial_boot_params, usbn); + fdt_nop_property(initial_boot_params, aliases, "usbn"); + } else { + __be32 new_f[1]; + enum cvmx_helper_board_usb_clock_types c; + c = __cvmx_helper_board_usb_get_clock_type(); + switch (c) { + case USB_CLOCK_TYPE_REF_48: + new_f[0] = cpu_to_be32(48000000); + fdt_setprop_inplace(initial_boot_params, usbn, + "refclk-frequency", new_f, sizeof(new_f)); + /* Fall through ...*/ + case USB_CLOCK_TYPE_REF_12: + /* Missing "refclk-type" defaults to external. */ + fdt_nop_property(initial_boot_params, usbn, "refclk-type"); + break; + default: + break; + } + } + } + return 0; } diff --git a/arch/mips/cavium-octeon/octeon_3xxx.dts b/arch/mips/cavium-octeon/octeon_3xxx.dts index 88cb42d4cc49f8..fa33115bde3337 100644 --- a/arch/mips/cavium-octeon/octeon_3xxx.dts +++ b/arch/mips/cavium-octeon/octeon_3xxx.dts @@ -550,6 +550,24 @@ big-endian-regs; }; }; + + usbn: usbn@1180068000000 { + compatible = "cavium,octeon-5750-usbn"; + reg = <0x11800 0x68000000 0x0 0x1000>; + ranges; /* Direct mapping */ + #address-cells = <2>; + #size-cells = <2>; + /* 12MHz, 24MHz and 48MHz allowed */ + refclk-frequency = <12000000>; + /* Either "crystal" or "external" */ + refclk-type = "crystal"; + + usbc@16f0010000000 { + compatible = "cavium,octeon-5750-usbc"; + reg = <0x16f00 0x10000000 0x0 0x80000>; + interrupts = <0 56>; + }; + }; }; aliases { @@ -566,6 +584,7 @@ flash0 = &flash0; cf0 = &cf0; uctl = &uctl; + usbn = &usbn; led0 = &led0; }; }; diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c index 24a2167db77803..67a078ffc4641a 100644 --- a/arch/mips/cavium-octeon/smp.c +++ b/arch/mips/cavium-octeon/smp.c @@ -6,7 +6,6 @@ * Copyright (C) 2004-2008, 2009, 2010 Cavium Networks */ #include -#include #include #include #include diff --git a/arch/mips/configs/ar7_defconfig b/arch/mips/configs/ar7_defconfig index 80e012fa409c8d..320772caf05461 100644 --- a/arch/mips/configs/ar7_defconfig +++ b/arch/mips/configs/ar7_defconfig @@ -86,7 +86,6 @@ CONFIG_MAC80211_RC_DEFAULT_PID=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y diff --git a/arch/mips/configs/bcm47xx_defconfig b/arch/mips/configs/bcm47xx_defconfig index 4ca8e5c99225f6..0db4eb319e0a3f 100644 --- a/arch/mips/configs/bcm47xx_defconfig +++ b/arch/mips/configs/bcm47xx_defconfig @@ -1,623 +1,86 @@ CONFIG_BCM47XX=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_KEXEC=y -# CONFIG_SECCOMP is not set -CONFIG_EXPERIMENTAL=y -# CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_BSD_PROCESS_ACCT_V3=y -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y -CONFIG_AUDIT=y -CONFIG_TINY_RCU=y -CONFIG_CGROUPS=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_RELAY=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_UIDGID_STRICT_TYPE_CHECKS=y CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_LZMA=y -CONFIG_EXPERT=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_EMBEDDED=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y -CONFIG_MODVERSIONS=y -# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y CONFIG_PCI=y -CONFIG_BINFMT_MISC=m +# CONFIG_SUSPEND is not set CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y -CONFIG_XFRM_USER=m -CONFIG_NET_KEY=m CONFIG_INET=y CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_MULTIPATH=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_NET_IPIP=m -CONFIG_NET_IPGRE=m -CONFIG_NET_IPGRE_BROADCAST=y CONFIG_IP_MROUTE=y -CONFIG_IP_PIMSM_V1=y -CONFIG_IP_PIMSM_V2=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y CONFIG_SYN_COOKIES=y -CONFIG_INET_AH=m -CONFIG_INET_ESP=m -CONFIG_INET_IPCOMP=m -CONFIG_INET_XFRM_MODE_TRANSPORT=m -CONFIG_INET_XFRM_MODE_TUNNEL=m -CONFIG_INET_XFRM_MODE_BEET=m -CONFIG_INET_DIAG=m CONFIG_TCP_CONG_ADVANCED=y -CONFIG_TCP_CONG_BIC=y -CONFIG_TCP_CONG_CUBIC=m -CONFIG_TCP_CONG_HSTCP=m -CONFIG_TCP_CONG_HYBLA=m -CONFIG_TCP_CONG_SCALABLE=m -CONFIG_TCP_CONG_LP=m -CONFIG_TCP_CONG_VENO=m -CONFIG_TCP_CONG_YEAH=m -CONFIG_TCP_CONG_ILLINOIS=m CONFIG_IPV6_PRIVACY=y -CONFIG_INET6_AH=m -CONFIG_INET6_ESP=m -CONFIG_INET6_IPCOMP=m -CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m -CONFIG_IPV6_TUNNEL=m CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y -CONFIG_NETWORK_SECMARK=y +CONFIG_IPV6_MROUTE=y CONFIG_NETFILTER=y -CONFIG_NETFILTER_NETLINK_QUEUE=m -CONFIG_NF_CONNTRACK=m -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_UDPLITE=m -CONFIG_NF_CONNTRACK_AMANDA=m -CONFIG_NF_CONNTRACK_FTP=m -CONFIG_NF_CONNTRACK_H323=m -CONFIG_NF_CONNTRACK_IRC=m -CONFIG_NF_CONNTRACK_NETBIOS_NS=m -CONFIG_NF_CONNTRACK_PPTP=m -CONFIG_NF_CONNTRACK_SANE=m -CONFIG_NF_CONNTRACK_SIP=m -CONFIG_NF_CONNTRACK_TFTP=m -CONFIG_NF_CT_NETLINK=m -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m -CONFIG_NETFILTER_XT_TARGET_CONNMARK=m -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m -CONFIG_NETFILTER_XT_TARGET_DSCP=m -CONFIG_NETFILTER_XT_TARGET_MARK=m -CONFIG_NETFILTER_XT_TARGET_NFLOG=m -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_TRACE=m -CONFIG_NETFILTER_XT_TARGET_SECMARK=m -CONFIG_NETFILTER_XT_TARGET_TCPMSS=m -CONFIG_NETFILTER_XT_MATCH_COMMENT=m -CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m -CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m -CONFIG_NETFILTER_XT_MATCH_CONNMARK=m -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m -CONFIG_NETFILTER_XT_MATCH_DSCP=m -CONFIG_NETFILTER_XT_MATCH_ESP=m -CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m -CONFIG_NETFILTER_XT_MATCH_HELPER=m -CONFIG_NETFILTER_XT_MATCH_LENGTH=m -CONFIG_NETFILTER_XT_MATCH_LIMIT=m -CONFIG_NETFILTER_XT_MATCH_MAC=m -CONFIG_NETFILTER_XT_MATCH_MARK=m -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m -CONFIG_NETFILTER_XT_MATCH_POLICY=m -CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m -CONFIG_NETFILTER_XT_MATCH_QUOTA=m -CONFIG_NETFILTER_XT_MATCH_REALM=m -CONFIG_NETFILTER_XT_MATCH_STATE=m -CONFIG_NETFILTER_XT_MATCH_STATISTIC=m -CONFIG_NETFILTER_XT_MATCH_STRING=m -CONFIG_NETFILTER_XT_MATCH_TCPMSS=m -CONFIG_NETFILTER_XT_MATCH_TIME=m -CONFIG_NETFILTER_XT_MATCH_U32=m -CONFIG_IP_VS=m -CONFIG_IP_VS_PROTO_TCP=y -CONFIG_IP_VS_PROTO_UDP=y -CONFIG_IP_VS_PROTO_ESP=y -CONFIG_IP_VS_PROTO_AH=y -CONFIG_IP_VS_RR=m -CONFIG_IP_VS_WRR=m -CONFIG_IP_VS_LC=m -CONFIG_IP_VS_WLC=m -CONFIG_IP_VS_LBLC=m -CONFIG_IP_VS_LBLCR=m -CONFIG_IP_VS_DH=m -CONFIG_IP_VS_SH=m -CONFIG_IP_VS_SED=m -CONFIG_IP_VS_NQ=m -CONFIG_IP_VS_FTP=m -CONFIG_NF_CONNTRACK_IPV4=m -CONFIG_IP_NF_QUEUE=m -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_ADDRTYPE=m -CONFIG_IP_NF_MATCH_AH=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_FILTER=m -CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_TARGET_LOG=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT=m -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_REDIRECT=m -CONFIG_NF_NAT_SNMP_BASIC=m -CONFIG_IP_NF_MANGLE=m -CONFIG_IP_NF_TARGET_CLUSTERIP=m -CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_TTL=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_ARPTABLES=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m -CONFIG_NF_CONNTRACK_IPV6=m -CONFIG_IP6_NF_QUEUE=m -CONFIG_IP6_NF_IPTABLES=m -CONFIG_IP6_NF_MATCH_AH=m -CONFIG_IP6_NF_MATCH_EUI64=m -CONFIG_IP6_NF_MATCH_FRAG=m -CONFIG_IP6_NF_MATCH_OPTS=m -CONFIG_IP6_NF_MATCH_HL=m -CONFIG_IP6_NF_MATCH_IPV6HEADER=m -CONFIG_IP6_NF_MATCH_MH=m -CONFIG_IP6_NF_MATCH_RT=m -CONFIG_IP6_NF_TARGET_HL=m -CONFIG_IP6_NF_TARGET_LOG=m -CONFIG_IP6_NF_FILTER=m -CONFIG_IP6_NF_TARGET_REJECT=m -CONFIG_IP6_NF_MANGLE=m -CONFIG_IP6_NF_RAW=m -CONFIG_BRIDGE_NF_EBTABLES=m -CONFIG_BRIDGE_EBT_BROUTE=m -CONFIG_BRIDGE_EBT_T_FILTER=m -CONFIG_BRIDGE_EBT_T_NAT=m -CONFIG_BRIDGE_EBT_802_3=m -CONFIG_BRIDGE_EBT_AMONG=m -CONFIG_BRIDGE_EBT_ARP=m -CONFIG_BRIDGE_EBT_IP=m -CONFIG_BRIDGE_EBT_LIMIT=m -CONFIG_BRIDGE_EBT_MARK=m -CONFIG_BRIDGE_EBT_PKTTYPE=m -CONFIG_BRIDGE_EBT_STP=m -CONFIG_BRIDGE_EBT_VLAN=m -CONFIG_BRIDGE_EBT_ARPREPLY=m -CONFIG_BRIDGE_EBT_DNAT=m -CONFIG_BRIDGE_EBT_MARK_T=m -CONFIG_BRIDGE_EBT_REDIRECT=m -CONFIG_BRIDGE_EBT_SNAT=m -CONFIG_BRIDGE_EBT_LOG=m -CONFIG_BRIDGE_EBT_ULOG=m -CONFIG_IP_DCCP=m -CONFIG_TIPC=m -CONFIG_TIPC_ADVANCED=y -CONFIG_ATM=m -CONFIG_ATM_CLIP=m -CONFIG_ATM_LANE=m -CONFIG_ATM_MPOA=m -CONFIG_ATM_BR2684=m -CONFIG_BRIDGE=m -CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q=y CONFIG_NET_SCHED=y -CONFIG_NET_SCH_CBQ=m -CONFIG_NET_SCH_HTB=m -CONFIG_NET_SCH_HFSC=m -CONFIG_NET_SCH_ATM=m -CONFIG_NET_SCH_PRIO=m -CONFIG_NET_SCH_RED=m -CONFIG_NET_SCH_SFQ=m -CONFIG_NET_SCH_TEQL=m -CONFIG_NET_SCH_TBF=m -CONFIG_NET_SCH_GRED=m -CONFIG_NET_SCH_DSMARK=m -CONFIG_NET_SCH_NETEM=m -CONFIG_NET_SCH_INGRESS=m -CONFIG_NET_CLS_BASIC=m -CONFIG_NET_CLS_TCINDEX=m -CONFIG_NET_CLS_ROUTE4=m -CONFIG_NET_CLS_FW=m -CONFIG_NET_CLS_U32=m -CONFIG_CLS_U32_PERF=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_RSVP=m -CONFIG_NET_CLS_RSVP6=m -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_CMP=m -CONFIG_NET_EMATCH_NBYTE=m -CONFIG_NET_EMATCH_U32=m -CONFIG_NET_EMATCH_META=m -CONFIG_NET_EMATCH_TEXT=m -CONFIG_NET_CLS_ACT=y -CONFIG_NET_ACT_POLICE=m -CONFIG_NET_ACT_GACT=m -CONFIG_GACT_PROB=y -CONFIG_NET_ACT_MIRRED=m -CONFIG_NET_ACT_IPT=m -CONFIG_NET_ACT_NAT=m -CONFIG_NET_ACT_PEDIT=m -CONFIG_NET_ACT_SIMP=m -CONFIG_NET_CLS_IND=y -CONFIG_NET_PKTGEN=m -CONFIG_BT=m -CONFIG_BT_HCIUART=m -CONFIG_BT_HCIUART_H4=y -CONFIG_BT_HCIUART_BCSP=y -CONFIG_BT_HCIUART_LL=y -CONFIG_BT_HCIBCM203X=m -CONFIG_BT_HCIBPA10X=m -CONFIG_BT_HCIBFUSB=m -CONFIG_BT_HCIVHCI=m -CONFIG_CFG80211=m -CONFIG_MAC80211=m -CONFIG_MAC80211_RC_PID=y -CONFIG_MAC80211_RC_DEFAULT_PID=y -CONFIG_MAC80211_MESH=y -CONFIG_RFKILL=m -CONFIG_RFKILL_INPUT=y -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_FW_LOADER=m -CONFIG_CONNECTOR=m +CONFIG_NET_SCH_FQ_CODEL=y +CONFIG_HAMRADIO=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y CONFIG_MTD=y -CONFIG_MTD_CONCAT=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CHAR=y +CONFIG_MTD_BCM47XX_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_CFI_STAA=y -CONFIG_MTD_RAM=y -CONFIG_MTD_ROM=y -CONFIG_MTD_ABSENT=y +CONFIG_MTD_COMPLEX_MAPPINGS=y CONFIG_MTD_PHYSMAP=y -CONFIG_BLK_DEV_LOOP=m -CONFIG_BLK_DEV_CRYPTOLOOP=m -CONFIG_BLK_DEV_NBD=m -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=16384 -CONFIG_ATA_OVER_ETH=m -CONFIG_RAID_ATTRS=m -CONFIG_SCSI=y -CONFIG_SCSI_TGT=m -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=m -CONFIG_CHR_DEV_OSST=m -CONFIG_BLK_DEV_SR=m -CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_CHR_DEV_SG=m -CONFIG_CHR_DEV_SCH=m -CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_ISCSI_TCP=m +CONFIG_MTD_BCM47XXSFLASH=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_BCM47XXNFLASH=y CONFIG_NETDEVICES=y -CONFIG_DUMMY=m -CONFIG_EQUALIZER=m -CONFIG_TUN=m -CONFIG_VETH=m -CONFIG_PHYLIB=m -CONFIG_MARVELL_PHY=m -CONFIG_DAVICOM_PHY=m -CONFIG_QSEMI_PHY=m -CONFIG_LXT_PHY=m -CONFIG_CICADA_PHY=m -CONFIG_VITESSE_PHY=m -CONFIG_SMSC_PHY=m -CONFIG_BROADCOM_PHY=m -CONFIG_ICPLUS_PHY=m -CONFIG_MDIO_BITBANG=m -CONFIG_NET_ETHERNET=y -CONFIG_NET_PCI=y CONFIG_B44=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set -CONFIG_ATH_COMMON=m -CONFIG_ATH5K=m -CONFIG_B43=m -CONFIG_B43LEGACY=m -CONFIG_ZD1211RW=m -CONFIG_USB_CATC=m -CONFIG_USB_KAWETH=m -CONFIG_USB_PEGASUS=m -CONFIG_USB_RTL8150=m -CONFIG_USB_USBNET=m -CONFIG_USB_NET_DM9601=m -CONFIG_USB_NET_GL620A=m -CONFIG_USB_NET_PLUSB=m -CONFIG_USB_NET_MCS7830=m -CONFIG_USB_NET_RNDIS_HOST=m -CONFIG_USB_ALI_M5632=y -CONFIG_USB_AN2720=y -CONFIG_USB_EPSON2888=y -CONFIG_USB_KC2190=y -CONFIG_USB_SIERRA_NET=m -CONFIG_ATM_DUMMY=m -CONFIG_ATM_TCP=m -CONFIG_PPP=m -CONFIG_PPP_ASYNC=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPP_MPPE=m -CONFIG_PPPOE=m -CONFIG_PPPOATM=m -CONFIG_SLIP=m -CONFIG_INPUT_EVDEV=m -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set +CONFIG_TIGON3=y +CONFIG_BGMAC=y +CONFIG_ATH_CARDS=y +CONFIG_ATH5K=y +CONFIG_B43=y +CONFIG_B43LEGACY=y +CONFIG_BRCMSMAC=y +CONFIG_ISDN=y CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set CONFIG_SERIAL_8250_CONSOLE=y # CONFIG_SERIAL_8250_PCI is not set CONFIG_SERIAL_8250_NR_UARTS=2 CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -# CONFIG_LEGACY_PTYS is not set -# CONFIG_HW_RANDOM is not set -CONFIG_W1=m -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2760=m -# CONFIG_HWMON is not set -CONFIG_THERMAL=y +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_HW_RANDOM=y +CONFIG_GPIO_SYSFS=y CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_NOWAYOUT=y CONFIG_BCM47XX_WDT=y +CONFIG_SSB_DEBUG=y CONFIG_SSB_DRIVER_GIGE=y -CONFIG_DISPLAY_SUPPORT=m -CONFIG_SOUND=m -CONFIG_SND=m -CONFIG_SND_SEQUENCER=m -CONFIG_SND_SEQ_DUMMY=m -CONFIG_SND_MIXER_OSS=m -CONFIG_SND_PCM_OSS=m -CONFIG_SND_SEQUENCER_OSS=y -CONFIG_SND_DUMMY=m -CONFIG_SND_VIRMIDI=m -CONFIG_SND_USB_AUDIO=m -CONFIG_HID=m -CONFIG_USB_HID=m -CONFIG_USB_HIDDEV=y +CONFIG_BCMA_DRIVER_GMAC_CMN=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y -# CONFIG_USB_DEVICE_CLASS is not set -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_ROOT_HUB_TT=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_U132_HCD=m -CONFIG_USB_R8A66597_HCD=m -CONFIG_USB_ACM=m -CONFIG_USB_PRINTER=m -CONFIG_USB_STORAGE=y -CONFIG_USB_STORAGE_DATAFAB=y -CONFIG_USB_STORAGE_FREECOM=y -CONFIG_USB_STORAGE_USBAT=y -CONFIG_USB_STORAGE_SDDR09=y -CONFIG_USB_STORAGE_SDDR55=y -CONFIG_USB_STORAGE_JUMPSHOT=y -CONFIG_USB_STORAGE_ALAUDA=y -CONFIG_USB_STORAGE_ONETOUCH=y -CONFIG_USB_STORAGE_KARMA=y -CONFIG_USB_MDC800=m -CONFIG_USB_MICROTEK=m -CONFIG_USB_SERIAL=m -CONFIG_USB_SERIAL_GENERIC=y -CONFIG_USB_SERIAL_AIRCABLE=m -CONFIG_USB_SERIAL_ARK3116=m -CONFIG_USB_SERIAL_BELKIN=m -CONFIG_USB_SERIAL_CH341=m -CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m -CONFIG_USB_SERIAL_CYPRESS_M8=m -CONFIG_USB_SERIAL_EMPEG=m -CONFIG_USB_SERIAL_FTDI_SIO=m -CONFIG_USB_SERIAL_FUNSOFT=m -CONFIG_USB_SERIAL_VISOR=m -CONFIG_USB_SERIAL_IPAQ=m -CONFIG_USB_SERIAL_IR=m -CONFIG_USB_SERIAL_GARMIN=m -CONFIG_USB_SERIAL_IPW=m -CONFIG_USB_SERIAL_KEYSPAN_PDA=m -CONFIG_USB_SERIAL_KLSI=m -CONFIG_USB_SERIAL_KOBIL_SCT=m -CONFIG_USB_SERIAL_MCT_U232=m -CONFIG_USB_SERIAL_MOS7720=m -CONFIG_USB_SERIAL_MOS7840=m -CONFIG_USB_SERIAL_NAVMAN=m -CONFIG_USB_SERIAL_PL2303=m -CONFIG_USB_SERIAL_OTI6858=m -CONFIG_USB_SERIAL_HP4X=m -CONFIG_USB_SERIAL_SAFE=m -CONFIG_USB_SERIAL_SIERRAWIRELESS=m -CONFIG_USB_SERIAL_CYBERJACK=m -CONFIG_USB_SERIAL_XIRCOM=m -CONFIG_USB_SERIAL_OPTION=m -CONFIG_USB_SERIAL_OMNINET=m -CONFIG_USB_SERIAL_DEBUG=m -CONFIG_USB_ADUTUX=m -CONFIG_USB_RIO500=m -CONFIG_USB_LEGOTOWER=m -CONFIG_USB_LCD=m -CONFIG_USB_LED=m -CONFIG_USB_CYPRESS_CY7C63=m -CONFIG_USB_CYTHERM=m -CONFIG_USB_IDMOUSE=m -CONFIG_USB_FTDI_ELAN=m -CONFIG_USB_SISUSBVGA=m -CONFIG_USB_LD=m -CONFIG_USB_TRANCEVIBRATOR=m -CONFIG_USB_IOWARRIOR=m -CONFIG_USB_TEST=m -CONFIG_USB_ATM=m -CONFIG_USB_SPEEDTOUCH=m -CONFIG_USB_CXACRU=m -CONFIG_USB_UEAGLEATM=m -CONFIG_USB_XUSBATM=m -CONFIG_USB_GADGET=m -CONFIG_USB_GADGET_NET2280=y -CONFIG_USB_ZERO=m -CONFIG_USB_ETH=m -CONFIG_USB_GADGETFS=m -CONFIG_USB_MASS_STORAGE=m -CONFIG_USB_G_SERIAL=m -CONFIG_USB_MIDI_GADGET=m -CONFIG_LEDS_CLASS=y -CONFIG_LEDS_GPIO=y +CONFIG_USB_HCD_BCMA=y +CONFIG_USB_HCD_SSB=y CONFIG_LEDS_TRIGGER_TIMER=y -CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_LEDS_TRIGGER_DEFAULT_ON=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT2_FS_POSIX_ACL=y -CONFIG_EXT2_FS_SECURITY=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_EXT3_FS_SECURITY=y -CONFIG_REISERFS_FS=m -CONFIG_REISERFS_FS_XATTR=y -CONFIG_REISERFS_FS_POSIX_ACL=y -CONFIG_REISERFS_FS_SECURITY=y -CONFIG_JFS_FS=m -CONFIG_JFS_POSIX_ACL=y -CONFIG_JFS_SECURITY=y -CONFIG_XFS_FS=m -CONFIG_XFS_QUOTA=y -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_RT=y -CONFIG_GFS2_FS=m -CONFIG_QUOTA=y -CONFIG_QUOTA_NETLINK_INTERFACE=y -CONFIG_QFMT_V1=m -CONFIG_QFMT_V2=m -CONFIG_AUTOFS_FS=m -CONFIG_AUTOFS4_FS=m -CONFIG_FUSE_FS=m -CONFIG_ISO9660_FS=m -CONFIG_JOLIET=y -CONFIG_ZISOFS=y -CONFIG_UDF_FS=m -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=m -CONFIG_NTFS_FS=m -CONFIG_NTFS_RW=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_ADFS_FS=m -CONFIG_AFFS_FS=m -CONFIG_HFS_FS=m -CONFIG_HFSPLUS_FS=m -CONFIG_BEFS_FS=m -CONFIG_BFS_FS=m -CONFIG_EFS_FS=m -CONFIG_JFFS2_FS=m -CONFIG_JFFS2_FS_XATTR=y -CONFIG_CRAMFS=m -CONFIG_VXFS_FS=m -CONFIG_MINIX_FS=m -CONFIG_HPFS_FS=m -CONFIG_QNX4FS_FS=m -CONFIG_ROMFS_FS=m -CONFIG_SYSV_FS=m -CONFIG_UFS_FS=m -CONFIG_NFS_FS=m -CONFIG_NFS_V3=y -CONFIG_NFS_V3_ACL=y -CONFIG_NFS_V4=y -CONFIG_NFSD=m -CONFIG_NFSD_V3_ACL=y -CONFIG_NFSD_V4=y -CONFIG_RPCSEC_GSS_SPKM3=m -CONFIG_CIFS=m -CONFIG_CIFS_XATTR=y -CONFIG_CIFS_POSIX=y -CONFIG_NCP_FS=m -CONFIG_NCPFS_NFS_NS=y -CONFIG_NCPFS_OS2_NS=y -CONFIG_NCPFS_NLS=y -CONFIG_NCPFS_EXTRAS=y -CONFIG_CODA_FS=m -CONFIG_PARTITION_ADVANCED=y -CONFIG_KARMA_PARTITION=y -CONFIG_NLS_CODEPAGE_437=m -CONFIG_NLS_CODEPAGE_737=m -CONFIG_NLS_CODEPAGE_775=m -CONFIG_NLS_CODEPAGE_850=m -CONFIG_NLS_CODEPAGE_852=m -CONFIG_NLS_CODEPAGE_855=m -CONFIG_NLS_CODEPAGE_857=m -CONFIG_NLS_CODEPAGE_860=m -CONFIG_NLS_CODEPAGE_861=m -CONFIG_NLS_CODEPAGE_862=m -CONFIG_NLS_CODEPAGE_863=m -CONFIG_NLS_CODEPAGE_864=m -CONFIG_NLS_CODEPAGE_865=m -CONFIG_NLS_CODEPAGE_866=m -CONFIG_NLS_CODEPAGE_869=m -CONFIG_NLS_CODEPAGE_936=m -CONFIG_NLS_CODEPAGE_950=m -CONFIG_NLS_CODEPAGE_932=m -CONFIG_NLS_CODEPAGE_949=m -CONFIG_NLS_CODEPAGE_874=m -CONFIG_NLS_ISO8859_8=m -CONFIG_NLS_CODEPAGE_1250=m -CONFIG_NLS_CODEPAGE_1251=m -CONFIG_NLS_ASCII=m -CONFIG_NLS_ISO8859_1=m -CONFIG_NLS_ISO8859_2=m -CONFIG_NLS_ISO8859_3=m -CONFIG_NLS_ISO8859_4=m -CONFIG_NLS_ISO8859_5=m -CONFIG_NLS_ISO8859_6=m -CONFIG_NLS_ISO8859_7=m -CONFIG_NLS_ISO8859_9=m -CONFIG_NLS_ISO8859_13=m -CONFIG_NLS_ISO8859_14=m -CONFIG_NLS_ISO8859_15=m -CONFIG_NLS_KOI8_R=m -CONFIG_NLS_KOI8_U=m -CONFIG_DLM=m -CONFIG_DLM_DEBUG=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_INFO_REDUCED=y +CONFIG_STRIP_ASM_SYMS=y CONFIG_DEBUG_FS=y -CONFIG_CRYPTO_NULL=m -CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_LRW=m -CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_XTS=m -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_XCBC=m -CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_SHA256=m -CONFIG_CRYPTO_SHA512=m -CONFIG_CRYPTO_TGR192=m -CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_ANUBIS=m -CONFIG_CRYPTO_BLOWFISH=m -CONFIG_CRYPTO_CAMELLIA=m -CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_FCRYPT=m -CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SEED=m -CONFIG_CRYPTO_SERPENT=m -CONFIG_CRYPTO_TEA=m -CONFIG_CRYPTO_TWOFISH=m -CONFIG_CRC16=m -CONFIG_CRC7=m +CONFIG_MAGIC_SYSRQ=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttyS0,115200" +CONFIG_CRC32_SARWATE=y diff --git a/arch/mips/configs/bcm63xx_defconfig b/arch/mips/configs/bcm63xx_defconfig index 919005139f5a31..3fec26410f344f 100644 --- a/arch/mips/configs/bcm63xx_defconfig +++ b/arch/mips/configs/bcm63xx_defconfig @@ -44,7 +44,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y diff --git a/arch/mips/configs/cobalt_defconfig b/arch/mips/configs/cobalt_defconfig index 5419adb219a840..23b66934e18d1f 100644 --- a/arch/mips/configs/cobalt_defconfig +++ b/arch/mips/configs/cobalt_defconfig @@ -19,7 +19,6 @@ CONFIG_INET=y # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLKDEVS=y CONFIG_MTD_JEDECPROBE=y diff --git a/arch/mips/configs/gpr_defconfig b/arch/mips/configs/gpr_defconfig index fb64589015fc2b..8f219dac95988c 100644 --- a/arch/mips/configs/gpr_defconfig +++ b/arch/mips/configs/gpr_defconfig @@ -165,7 +165,6 @@ CONFIG_YAM=m CONFIG_CFG80211=y CONFIG_MAC80211=y CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y diff --git a/arch/mips/configs/jmr3927_defconfig b/arch/mips/configs/jmr3927_defconfig index db5705e18b3665..9bc08f2751206f 100644 --- a/arch/mips/configs/jmr3927_defconfig +++ b/arch/mips/configs/jmr3927_defconfig @@ -22,7 +22,6 @@ CONFIG_IP_PNP_BOOTP=y # CONFIG_INET_DIAG is not set # CONFIG_IPV6 is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=y CONFIG_MTD_CFI=y diff --git a/arch/mips/configs/lasat_defconfig b/arch/mips/configs/lasat_defconfig index d9f3db29ab95aa..0179c7fa014f1c 100644 --- a/arch/mips/configs/lasat_defconfig +++ b/arch/mips/configs/lasat_defconfig @@ -31,7 +31,6 @@ CONFIG_INET=y # CONFIG_INET_DIAG is not set # CONFIG_IPV6 is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y diff --git a/arch/mips/configs/maltasmvp_defconfig b/arch/mips/configs/maltasmvp_defconfig index 8a666021b870ca..d75931850392a1 100644 --- a/arch/mips/configs/maltasmvp_defconfig +++ b/arch/mips/configs/maltasmvp_defconfig @@ -4,7 +4,7 @@ CONFIG_CPU_MIPS32_R2=y CONFIG_MIPS_MT_SMP=y CONFIG_SCHED_SMT=y CONFIG_MIPS_CMP=y -CONFIG_NR_CPUS=8 +CONFIG_NR_CPUS=2 CONFIG_HZ_100=y CONFIG_LOCALVERSION="cmp" CONFIG_SYSVIPC=y @@ -58,7 +58,6 @@ CONFIG_ATALK=m CONFIG_DEV_APPLETALK=m CONFIG_IPDDP=m CONFIG_IPDDP_ENCAP=y -CONFIG_IPDDP_DECAP=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_CBQ=m CONFIG_NET_SCH_HTB=m diff --git a/arch/mips/configs/markeins_defconfig b/arch/mips/configs/markeins_defconfig index 636f82b89fd30e..4c2c0c4b9bb1dc 100644 --- a/arch/mips/configs/markeins_defconfig +++ b/arch/mips/configs/markeins_defconfig @@ -124,7 +124,6 @@ CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m CONFIG_FW_LOADER=m CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index 9fa8f16068d8c2..593946afc483ec 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -246,7 +246,6 @@ CONFIG_BT_HCIBTUART=m CONFIG_BT_HCIVHCI=m CONFIG_CONNECTOR=m CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y diff --git a/arch/mips/configs/pnx8335_stb225_defconfig b/arch/mips/configs/pnx8335_stb225_defconfig index f2925769dfa3b5..c887066ecc2a78 100644 --- a/arch/mips/configs/pnx8335_stb225_defconfig +++ b/arch/mips/configs/pnx8335_stb225_defconfig @@ -31,7 +31,6 @@ CONFIG_INET_AH=y # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y diff --git a/arch/mips/configs/qi_lb60_defconfig b/arch/mips/configs/qi_lb60_defconfig new file mode 100644 index 00000000000000..2b965470c35b94 --- /dev/null +++ b/arch/mips/configs/qi_lb60_defconfig @@ -0,0 +1,188 @@ +CONFIG_MACH_JZ4740=y +# CONFIG_COMPACTION is not set +# CONFIG_CROSS_MEMORY_ATTACH is not set +CONFIG_HZ_100=y +CONFIG_PREEMPT=y +# CONFIG_SECCOMP is not set +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS_ALL=y +CONFIG_EMBEDDED=y +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_EFI_PARTITION is not set +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +# CONFIG_TCP_CONG_CUBIC is not set +CONFIG_TCP_CONG_WESTWOOD=y +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_IPV6 is not set +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_MTD=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_JZ4740=y +CONFIG_MTD_UBI=y +CONFIG_NETDEVICES=y +# CONFIG_WLAN is not set +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYBOARD_MATRIX=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_MISC=y +# CONFIG_SERIO is not set +CONFIG_LEGACY_PTY_COUNT=2 +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_DMA is not set +CONFIG_SERIAL_8250_NR_UARTS=2 +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +# CONFIG_HW_RANDOM is not set +CONFIG_SPI=y +CONFIG_SPI_GPIO=y +CONFIG_POWER_SUPPLY=y +CONFIG_BATTERY_JZ4740=y +CONFIG_CHARGER_GPIO=y +# CONFIG_HWMON is not set +CONFIG_MFD_JZ4740_ADC=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_FB=y +CONFIG_FB_JZ4740=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set +# CONFIG_VGA_CONSOLE is not set +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +# CONFIG_LOGO_LINUX_CLUT224 is not set +CONFIG_SOUND=y +CONFIG_SND=y +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_SPI is not set +# CONFIG_SND_MIPS is not set +CONFIG_SND_SOC=y +CONFIG_SND_JZ4740_SOC=y +CONFIG_SND_JZ4740_SOC_QI_LB60=y +CONFIG_USB=y +CONFIG_USB_OTG_BLACKLIST_HUB=y +CONFIG_USB_MUSB_HDRC=y +CONFIG_USB_MUSB_GADGET=y +CONFIG_USB_MUSB_JZ4740=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG=y +CONFIG_USB_ETH=y +# CONFIG_USB_ETH_RNDIS is not set +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +# CONFIG_MMC_BLOCK_BOUNCE is not set +CONFIG_MMC_JZ4740=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_JZ4740=y +CONFIG_DMADEVICES=y +CONFIG_DMA_JZ4740=y +CONFIG_PWM=y +CONFIG_PWM_JZ4740=y +CONFIG_EXT2_FS=y +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +# CONFIG_EXT3_FS_XATTR is not set +# CONFIG_DNOTIFY is not set +CONFIG_VFAT_FS=y +CONFIG_PROC_KCORE=y +# CONFIG_PROC_PAGE_MONITOR is not set +CONFIG_TMPFS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +# CONFIG_JFFS2_ZLIB is not set +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_737=y +CONFIG_NLS_CODEPAGE_775=y +CONFIG_NLS_CODEPAGE_850=y +CONFIG_NLS_CODEPAGE_852=y +CONFIG_NLS_CODEPAGE_855=y +CONFIG_NLS_CODEPAGE_857=y +CONFIG_NLS_CODEPAGE_860=y +CONFIG_NLS_CODEPAGE_861=y +CONFIG_NLS_CODEPAGE_862=y +CONFIG_NLS_CODEPAGE_863=y +CONFIG_NLS_CODEPAGE_864=y +CONFIG_NLS_CODEPAGE_865=y +CONFIG_NLS_CODEPAGE_866=y +CONFIG_NLS_CODEPAGE_869=y +CONFIG_NLS_CODEPAGE_936=y +CONFIG_NLS_CODEPAGE_950=y +CONFIG_NLS_CODEPAGE_932=y +CONFIG_NLS_CODEPAGE_949=y +CONFIG_NLS_CODEPAGE_874=y +CONFIG_NLS_ISO8859_8=y +CONFIG_NLS_CODEPAGE_1250=y +CONFIG_NLS_CODEPAGE_1251=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_2=y +CONFIG_NLS_ISO8859_3=y +CONFIG_NLS_ISO8859_4=y +CONFIG_NLS_ISO8859_5=y +CONFIG_NLS_ISO8859_6=y +CONFIG_NLS_ISO8859_7=y +CONFIG_NLS_ISO8859_9=y +CONFIG_NLS_ISO8859_13=y +CONFIG_NLS_ISO8859_14=y +CONFIG_NLS_ISO8859_15=y +CONFIG_NLS_KOI8_R=y +CONFIG_NLS_KOI8_U=y +CONFIG_NLS_UTF8=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_STRIP_ASM_SYMS=y +CONFIG_READABLE_ASM=y +CONFIG_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_DEBUG_STACKOVERFLOW=y +CONFIG_PANIC_ON_OOPS=y +# CONFIG_FTRACE is not set +CONFIG_KGDB=y +CONFIG_RUNTIME_DEBUG=y +CONFIG_CRYPTO_ZLIB=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_FONTS=y +CONFIG_FONT_SUN8x16=y diff --git a/arch/mips/configs/rb532_defconfig b/arch/mips/configs/rb532_defconfig index b85b121397c841..5d9d708e12e512 100644 --- a/arch/mips/configs/rb532_defconfig +++ b/arch/mips/configs/rb532_defconfig @@ -114,7 +114,6 @@ CONFIG_NET_CLS_IND=y CONFIG_HAMRADIO=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_BLOCK2MTD=y diff --git a/arch/mips/configs/rbtx49xx_defconfig b/arch/mips/configs/rbtx49xx_defconfig index 9cba856277ff91..f8bf9b4c1343d0 100644 --- a/arch/mips/configs/rbtx49xx_defconfig +++ b/arch/mips/configs/rbtx49xx_defconfig @@ -35,7 +35,6 @@ CONFIG_IP_PNP=y # CONFIG_IPV6 is not set # CONFIG_WIRELESS is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=m diff --git a/arch/mips/fw/arc/file.c b/arch/mips/fw/arc/file.c index a8b08032348fb5..49fd3ff13fe594 100644 --- a/arch/mips/fw/arc/file.c +++ b/arch/mips/fw/arc/file.c @@ -8,7 +8,6 @@ * Copyright (C) 1994, 1995, 1996, 1999 Ralf Baechle * Copyright (C) 1999 Silicon Graphics, Inc. */ -#include #include #include diff --git a/arch/mips/include/asm/amon.h b/arch/mips/include/asm/amon.h index c3dc1a68dd8d90..3cc03c64a9c790 100644 --- a/arch/mips/include/asm/amon.h +++ b/arch/mips/include/asm/amon.h @@ -1,7 +1,12 @@ /* - * Amon support + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2013 Imagination Technologies Ltd. + * + * Arbitrary Monitor Support (AMON) */ - -int amon_cpu_avail(int); -void amon_cpu_start(int, unsigned long, unsigned long, - unsigned long, unsigned long); +int amon_cpu_avail(int cpu); +int amon_cpu_start(int cpu, unsigned long pc, unsigned long sp, + unsigned long gp, unsigned long a0); diff --git a/arch/mips/include/asm/asmmacro-32.h b/arch/mips/include/asm/asmmacro-32.h index 2413afe21b3369..70e1f176f123c1 100644 --- a/arch/mips/include/asm/asmmacro-32.h +++ b/arch/mips/include/asm/asmmacro-32.h @@ -12,27 +12,6 @@ #include #include - .macro fpu_save_double thread status tmp1=t0 - cfc1 \tmp1, fcr31 - sdc1 $f0, THREAD_FPR0(\thread) - sdc1 $f2, THREAD_FPR2(\thread) - sdc1 $f4, THREAD_FPR4(\thread) - sdc1 $f6, THREAD_FPR6(\thread) - sdc1 $f8, THREAD_FPR8(\thread) - sdc1 $f10, THREAD_FPR10(\thread) - sdc1 $f12, THREAD_FPR12(\thread) - sdc1 $f14, THREAD_FPR14(\thread) - sdc1 $f16, THREAD_FPR16(\thread) - sdc1 $f18, THREAD_FPR18(\thread) - sdc1 $f20, THREAD_FPR20(\thread) - sdc1 $f22, THREAD_FPR22(\thread) - sdc1 $f24, THREAD_FPR24(\thread) - sdc1 $f26, THREAD_FPR26(\thread) - sdc1 $f28, THREAD_FPR28(\thread) - sdc1 $f30, THREAD_FPR30(\thread) - sw \tmp1, THREAD_FCR31(\thread) - .endm - .macro fpu_save_single thread tmp=t0 cfc1 \tmp, fcr31 swc1 $f0, THREAD_FPR0(\thread) @@ -70,27 +49,6 @@ sw \tmp, THREAD_FCR31(\thread) .endm - .macro fpu_restore_double thread status tmp=t0 - lw \tmp, THREAD_FCR31(\thread) - ldc1 $f0, THREAD_FPR0(\thread) - ldc1 $f2, THREAD_FPR2(\thread) - ldc1 $f4, THREAD_FPR4(\thread) - ldc1 $f6, THREAD_FPR6(\thread) - ldc1 $f8, THREAD_FPR8(\thread) - ldc1 $f10, THREAD_FPR10(\thread) - ldc1 $f12, THREAD_FPR12(\thread) - ldc1 $f14, THREAD_FPR14(\thread) - ldc1 $f16, THREAD_FPR16(\thread) - ldc1 $f18, THREAD_FPR18(\thread) - ldc1 $f20, THREAD_FPR20(\thread) - ldc1 $f22, THREAD_FPR22(\thread) - ldc1 $f24, THREAD_FPR24(\thread) - ldc1 $f26, THREAD_FPR26(\thread) - ldc1 $f28, THREAD_FPR28(\thread) - ldc1 $f30, THREAD_FPR30(\thread) - ctc1 \tmp, fcr31 - .endm - .macro fpu_restore_single thread tmp=t0 lw \tmp, THREAD_FCR31(\thread) lwc1 $f0, THREAD_FPR0(\thread) diff --git a/arch/mips/include/asm/asmmacro-64.h b/arch/mips/include/asm/asmmacro-64.h index 08a527dfe4a32d..38ea609465b10c 100644 --- a/arch/mips/include/asm/asmmacro-64.h +++ b/arch/mips/include/asm/asmmacro-64.h @@ -13,102 +13,6 @@ #include #include - .macro fpu_save_16even thread tmp=t0 - cfc1 \tmp, fcr31 - sdc1 $f0, THREAD_FPR0(\thread) - sdc1 $f2, THREAD_FPR2(\thread) - sdc1 $f4, THREAD_FPR4(\thread) - sdc1 $f6, THREAD_FPR6(\thread) - sdc1 $f8, THREAD_FPR8(\thread) - sdc1 $f10, THREAD_FPR10(\thread) - sdc1 $f12, THREAD_FPR12(\thread) - sdc1 $f14, THREAD_FPR14(\thread) - sdc1 $f16, THREAD_FPR16(\thread) - sdc1 $f18, THREAD_FPR18(\thread) - sdc1 $f20, THREAD_FPR20(\thread) - sdc1 $f22, THREAD_FPR22(\thread) - sdc1 $f24, THREAD_FPR24(\thread) - sdc1 $f26, THREAD_FPR26(\thread) - sdc1 $f28, THREAD_FPR28(\thread) - sdc1 $f30, THREAD_FPR30(\thread) - sw \tmp, THREAD_FCR31(\thread) - .endm - - .macro fpu_save_16odd thread - sdc1 $f1, THREAD_FPR1(\thread) - sdc1 $f3, THREAD_FPR3(\thread) - sdc1 $f5, THREAD_FPR5(\thread) - sdc1 $f7, THREAD_FPR7(\thread) - sdc1 $f9, THREAD_FPR9(\thread) - sdc1 $f11, THREAD_FPR11(\thread) - sdc1 $f13, THREAD_FPR13(\thread) - sdc1 $f15, THREAD_FPR15(\thread) - sdc1 $f17, THREAD_FPR17(\thread) - sdc1 $f19, THREAD_FPR19(\thread) - sdc1 $f21, THREAD_FPR21(\thread) - sdc1 $f23, THREAD_FPR23(\thread) - sdc1 $f25, THREAD_FPR25(\thread) - sdc1 $f27, THREAD_FPR27(\thread) - sdc1 $f29, THREAD_FPR29(\thread) - sdc1 $f31, THREAD_FPR31(\thread) - .endm - - .macro fpu_save_double thread status tmp - sll \tmp, \status, 5 - bgez \tmp, 2f - fpu_save_16odd \thread -2: - fpu_save_16even \thread \tmp - .endm - - .macro fpu_restore_16even thread tmp=t0 - lw \tmp, THREAD_FCR31(\thread) - ldc1 $f0, THREAD_FPR0(\thread) - ldc1 $f2, THREAD_FPR2(\thread) - ldc1 $f4, THREAD_FPR4(\thread) - ldc1 $f6, THREAD_FPR6(\thread) - ldc1 $f8, THREAD_FPR8(\thread) - ldc1 $f10, THREAD_FPR10(\thread) - ldc1 $f12, THREAD_FPR12(\thread) - ldc1 $f14, THREAD_FPR14(\thread) - ldc1 $f16, THREAD_FPR16(\thread) - ldc1 $f18, THREAD_FPR18(\thread) - ldc1 $f20, THREAD_FPR20(\thread) - ldc1 $f22, THREAD_FPR22(\thread) - ldc1 $f24, THREAD_FPR24(\thread) - ldc1 $f26, THREAD_FPR26(\thread) - ldc1 $f28, THREAD_FPR28(\thread) - ldc1 $f30, THREAD_FPR30(\thread) - ctc1 \tmp, fcr31 - .endm - - .macro fpu_restore_16odd thread - ldc1 $f1, THREAD_FPR1(\thread) - ldc1 $f3, THREAD_FPR3(\thread) - ldc1 $f5, THREAD_FPR5(\thread) - ldc1 $f7, THREAD_FPR7(\thread) - ldc1 $f9, THREAD_FPR9(\thread) - ldc1 $f11, THREAD_FPR11(\thread) - ldc1 $f13, THREAD_FPR13(\thread) - ldc1 $f15, THREAD_FPR15(\thread) - ldc1 $f17, THREAD_FPR17(\thread) - ldc1 $f19, THREAD_FPR19(\thread) - ldc1 $f21, THREAD_FPR21(\thread) - ldc1 $f23, THREAD_FPR23(\thread) - ldc1 $f25, THREAD_FPR25(\thread) - ldc1 $f27, THREAD_FPR27(\thread) - ldc1 $f29, THREAD_FPR29(\thread) - ldc1 $f31, THREAD_FPR31(\thread) - .endm - - .macro fpu_restore_double thread status tmp - sll \tmp, \status, 5 - bgez \tmp, 1f # 16 register mode? - - fpu_restore_16odd \thread -1: fpu_restore_16even \thread \tmp - .endm - .macro cpu_save_nonscratch thread LONG_S s0, THREAD_REG16(\thread) LONG_S s1, THREAD_REG17(\thread) diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h index 6c8342ae74db88..3220c93ea981da 100644 --- a/arch/mips/include/asm/asmmacro.h +++ b/arch/mips/include/asm/asmmacro.h @@ -62,6 +62,113 @@ .endm #endif /* CONFIG_MIPS_MT_SMTC */ + .macro fpu_save_16even thread tmp=t0 + cfc1 \tmp, fcr31 + sdc1 $f0, THREAD_FPR0(\thread) + sdc1 $f2, THREAD_FPR2(\thread) + sdc1 $f4, THREAD_FPR4(\thread) + sdc1 $f6, THREAD_FPR6(\thread) + sdc1 $f8, THREAD_FPR8(\thread) + sdc1 $f10, THREAD_FPR10(\thread) + sdc1 $f12, THREAD_FPR12(\thread) + sdc1 $f14, THREAD_FPR14(\thread) + sdc1 $f16, THREAD_FPR16(\thread) + sdc1 $f18, THREAD_FPR18(\thread) + sdc1 $f20, THREAD_FPR20(\thread) + sdc1 $f22, THREAD_FPR22(\thread) + sdc1 $f24, THREAD_FPR24(\thread) + sdc1 $f26, THREAD_FPR26(\thread) + sdc1 $f28, THREAD_FPR28(\thread) + sdc1 $f30, THREAD_FPR30(\thread) + sw \tmp, THREAD_FCR31(\thread) + .endm + + .macro fpu_save_16odd thread + .set push + .set mips64r2 + sdc1 $f1, THREAD_FPR1(\thread) + sdc1 $f3, THREAD_FPR3(\thread) + sdc1 $f5, THREAD_FPR5(\thread) + sdc1 $f7, THREAD_FPR7(\thread) + sdc1 $f9, THREAD_FPR9(\thread) + sdc1 $f11, THREAD_FPR11(\thread) + sdc1 $f13, THREAD_FPR13(\thread) + sdc1 $f15, THREAD_FPR15(\thread) + sdc1 $f17, THREAD_FPR17(\thread) + sdc1 $f19, THREAD_FPR19(\thread) + sdc1 $f21, THREAD_FPR21(\thread) + sdc1 $f23, THREAD_FPR23(\thread) + sdc1 $f25, THREAD_FPR25(\thread) + sdc1 $f27, THREAD_FPR27(\thread) + sdc1 $f29, THREAD_FPR29(\thread) + sdc1 $f31, THREAD_FPR31(\thread) + .set pop + .endm + + .macro fpu_save_double thread status tmp +#if defined(CONFIG_MIPS64) || defined(CONFIG_CPU_MIPS32_R2) + sll \tmp, \status, 5 + bgez \tmp, 10f + fpu_save_16odd \thread +10: +#endif + fpu_save_16even \thread \tmp + .endm + + .macro fpu_restore_16even thread tmp=t0 + lw \tmp, THREAD_FCR31(\thread) + ldc1 $f0, THREAD_FPR0(\thread) + ldc1 $f2, THREAD_FPR2(\thread) + ldc1 $f4, THREAD_FPR4(\thread) + ldc1 $f6, THREAD_FPR6(\thread) + ldc1 $f8, THREAD_FPR8(\thread) + ldc1 $f10, THREAD_FPR10(\thread) + ldc1 $f12, THREAD_FPR12(\thread) + ldc1 $f14, THREAD_FPR14(\thread) + ldc1 $f16, THREAD_FPR16(\thread) + ldc1 $f18, THREAD_FPR18(\thread) + ldc1 $f20, THREAD_FPR20(\thread) + ldc1 $f22, THREAD_FPR22(\thread) + ldc1 $f24, THREAD_FPR24(\thread) + ldc1 $f26, THREAD_FPR26(\thread) + ldc1 $f28, THREAD_FPR28(\thread) + ldc1 $f30, THREAD_FPR30(\thread) + ctc1 \tmp, fcr31 + .endm + + .macro fpu_restore_16odd thread + .set push + .set mips64r2 + ldc1 $f1, THREAD_FPR1(\thread) + ldc1 $f3, THREAD_FPR3(\thread) + ldc1 $f5, THREAD_FPR5(\thread) + ldc1 $f7, THREAD_FPR7(\thread) + ldc1 $f9, THREAD_FPR9(\thread) + ldc1 $f11, THREAD_FPR11(\thread) + ldc1 $f13, THREAD_FPR13(\thread) + ldc1 $f15, THREAD_FPR15(\thread) + ldc1 $f17, THREAD_FPR17(\thread) + ldc1 $f19, THREAD_FPR19(\thread) + ldc1 $f21, THREAD_FPR21(\thread) + ldc1 $f23, THREAD_FPR23(\thread) + ldc1 $f25, THREAD_FPR25(\thread) + ldc1 $f27, THREAD_FPR27(\thread) + ldc1 $f29, THREAD_FPR29(\thread) + ldc1 $f31, THREAD_FPR31(\thread) + .set pop + .endm + + .macro fpu_restore_double thread status tmp +#if defined(CONFIG_MIPS64) || defined(CONFIG_CPU_MIPS32_R2) + sll \tmp, \status, 5 + bgez \tmp, 10f # 16 register mode? + + fpu_restore_16odd \thread +10: +#endif + fpu_restore_16even \thread \tmp + .endm + /* * Temporary until all gas have MT ASE support */ diff --git a/arch/mips/include/asm/bmips.h b/arch/mips/include/asm/bmips.h index 27bd060d716e33..cbaccebf5065cd 100644 --- a/arch/mips/include/asm/bmips.h +++ b/arch/mips/include/asm/bmips.h @@ -46,8 +46,35 @@ #include #include +#include + +extern struct plat_smp_ops bmips43xx_smp_ops; +extern struct plat_smp_ops bmips5000_smp_ops; + +static inline int register_bmips_smp_ops(void) +{ +#if IS_ENABLED(CONFIG_CPU_BMIPS) && IS_ENABLED(CONFIG_SMP) + switch (current_cpu_type()) { + case CPU_BMIPS32: + case CPU_BMIPS3300: + return register_up_smp_ops(); + case CPU_BMIPS4350: + case CPU_BMIPS4380: + register_smp_ops(&bmips43xx_smp_ops); + break; + case CPU_BMIPS5000: + register_smp_ops(&bmips5000_smp_ops); + break; + default: + return -ENODEV; + } + + return 0; +#else + return -ENODEV; +#endif +} -extern struct plat_smp_ops bmips_smp_ops; extern char bmips_reset_nmi_vec; extern char bmips_reset_nmi_vec_end; extern char bmips_smp_movevec; diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index d445d060e346ab..6e70b03b6aab8d 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -20,6 +20,13 @@ #ifndef cpu_has_tlb #define cpu_has_tlb (cpu_data[0].options & MIPS_CPU_TLB) #endif +#ifndef cpu_has_tlbinv +#define cpu_has_tlbinv (cpu_data[0].options & MIPS_CPU_TLBINV) +#endif +#ifndef cpu_has_segments +#define cpu_has_segments (cpu_data[0].options & MIPS_CPU_SEGMENTS) +#endif + /* * For the moment we don't consider R6000 and R8000 so we can assume that diff --git a/arch/mips/include/asm/cpu-info.h b/arch/mips/include/asm/cpu-info.h index 21c8e29c8f91e8..8f7adf0ac1e383 100644 --- a/arch/mips/include/asm/cpu-info.h +++ b/arch/mips/include/asm/cpu-info.h @@ -52,6 +52,9 @@ struct cpuinfo_mips { unsigned int cputype; int isa_level; int tlbsize; + int tlbsizevtlb; + int tlbsizeftlbsets; + int tlbsizeftlbways; struct cache_desc icache; /* Primary I-cache */ struct cache_desc dcache; /* Primary D or combined I/D cache */ struct cache_desc scache; /* Secondary cache */ diff --git a/arch/mips/include/asm/cpu-type.h b/arch/mips/include/asm/cpu-type.h index 4a402cc60c03e4..02f591bd95ca63 100644 --- a/arch/mips/include/asm/cpu-type.h +++ b/arch/mips/include/asm/cpu-type.h @@ -27,10 +27,7 @@ static inline int __pure __get_cpu_type(const int cpu_type) #ifdef CONFIG_SYS_HAS_CPU_MIPS32_R1 case CPU_4KC: case CPU_ALCHEMY: - case CPU_BMIPS3300: - case CPU_BMIPS4350: case CPU_PR4450: - case CPU_BMIPS32: case CPU_JZRISC: #endif @@ -47,6 +44,8 @@ static inline int __pure __get_cpu_type(const int cpu_type) case CPU_74K: case CPU_M14KC: case CPU_M14KEC: + case CPU_INTERAPTIV: + case CPU_PROAPTIV: #endif #ifdef CONFIG_SYS_HAS_CPU_MIPS64_R1 @@ -163,6 +162,16 @@ static inline int __pure __get_cpu_type(const int cpu_type) case CPU_CAVIUM_OCTEON2: #endif +#if defined(CONFIG_SYS_HAS_CPU_BMIPS32_3300) || \ + defined (CONFIG_SYS_HAS_CPU_MIPS32_R1) + case CPU_BMIPS32: + case CPU_BMIPS3300: +#endif + +#ifdef CONFIG_SYS_HAS_CPU_BMIPS4350 + case CPU_BMIPS4350: +#endif + #ifdef CONFIG_SYS_HAS_CPU_BMIPS4380 case CPU_BMIPS4380: #endif diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index d2035e16502a7d..76411df3d971ef 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -111,6 +111,10 @@ #define PRID_IMP_1074K 0x9a00 #define PRID_IMP_M14KC 0x9c00 #define PRID_IMP_M14KEC 0x9e00 +#define PRID_IMP_INTERAPTIV_UP 0xa000 +#define PRID_IMP_INTERAPTIV_MP 0xa100 +#define PRID_IMP_PROAPTIV_UP 0xa200 +#define PRID_IMP_PROAPTIV_MP 0xa300 /* * These are the PRID's for when 23:16 == PRID_COMP_SIBYTE @@ -194,6 +198,7 @@ #define PRID_IMP_NETLOGIC_XLP8XX 0x1000 #define PRID_IMP_NETLOGIC_XLP3XX 0x1100 #define PRID_IMP_NETLOGIC_XLP2XX 0x1200 +#define PRID_IMP_NETLOGIC_XLP9XX 0x1500 /* * Particular Revision values for bits 7:0 of the PRId register. @@ -249,6 +254,8 @@ #define FPIR_IMP_NONE 0x0000 +#if !defined(__ASSEMBLY__) + enum cpu_type_enum { CPU_UNKNOWN, @@ -289,7 +296,7 @@ enum cpu_type_enum { CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K, CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350, CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_LOONGSON1, CPU_M14KC, - CPU_M14KEC, + CPU_M14KEC, CPU_INTERAPTIV, CPU_PROAPTIV, /* * MIPS64 class processors @@ -301,6 +308,7 @@ enum cpu_type_enum { CPU_LAST }; +#endif /* !__ASSEMBLY */ /* * ISA Level encodings @@ -348,6 +356,8 @@ enum cpu_type_enum { #define MIPS_CPU_PCI 0x00400000 /* CPU has Perf Ctr Int indicator */ #define MIPS_CPU_RIXI 0x00800000 /* CPU has TLB Read/eXec Inhibit */ #define MIPS_CPU_MICROMIPS 0x01000000 /* CPU has microMIPS capability */ +#define MIPS_CPU_TLBINV 0x02000000 /* CPU supports TLBINV/F */ +#define MIPS_CPU_SEGMENTS 0x04000000 /* CPU supports Segmentation Control registers */ /* * CPU ASE encodings diff --git a/arch/mips/include/asm/dma-coherence.h b/arch/mips/include/asm/dma-coherence.h index 242cbb3ca58273..bc5e85d579e607 100644 --- a/arch/mips/include/asm/dma-coherence.h +++ b/arch/mips/include/asm/dma-coherence.h @@ -9,7 +9,16 @@ #ifndef __ASM_DMA_COHERENCE_H #define __ASM_DMA_COHERENCE_H +#ifdef CONFIG_DMA_MAYBE_COHERENT extern int coherentio; extern int hw_coherentio; +#else +#ifdef CONFIG_DMA_COHERENT +#define coherentio 1 +#else +#define coherentio 0 +#endif +#define hw_coherentio 0 +#endif /* CONFIG_DMA_MAYBE_COHERENT */ #endif diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index a66359ef4ece77..d4144056e9287c 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -36,6 +36,7 @@ #define EF_MIPS_ABI2 0x00000020 #define EF_MIPS_OPTIONS_FIRST 0x00000080 #define EF_MIPS_32BITMODE 0x00000100 +#define EF_MIPS_FP64 0x00000200 #define EF_MIPS_ABI 0x0000f000 #define EF_MIPS_ARCH 0xf0000000 @@ -175,6 +176,18 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #ifdef CONFIG_32BIT +/* + * In order to be sure that we don't attempt to execute an O32 binary which + * requires 64 bit FP (FR=1) on a system which does not support it we refuse + * to execute any binary which has bits specified by the following macro set + * in its ELF header flags. + */ +#ifdef CONFIG_MIPS_O32_FP64_SUPPORT +# define __MIPS_O32_FP64_MUST_BE_ZERO 0 +#else +# define __MIPS_O32_FP64_MUST_BE_ZERO EF_MIPS_FP64 +#endif + /* * This is used to ensure we don't load something for the wrong architecture. */ @@ -191,6 +204,8 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; __res = 0; \ if (((__h->e_flags & EF_MIPS_ABI) != 0) && \ ((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \ + __res = 0; \ + if (__h->e_flags & __MIPS_O32_FP64_MUST_BE_ZERO) \ __res = 0; \ \ __res; \ @@ -249,6 +264,11 @@ extern struct mips_abi mips_abi_n32; #define SET_PERSONALITY(ex) \ do { \ + if ((ex).e_flags & EF_MIPS_FP64) \ + clear_thread_flag(TIF_32BIT_FPREGS); \ + else \ + set_thread_flag(TIF_32BIT_FPREGS); \ + \ if (personality(current->personality) != PER_LINUX) \ set_personality(PER_LINUX); \ \ @@ -271,14 +291,18 @@ do { \ #endif #ifdef CONFIG_MIPS32_O32 -#define __SET_PERSONALITY32_O32() \ +#define __SET_PERSONALITY32_O32(ex) \ do { \ set_thread_flag(TIF_32BIT_REGS); \ set_thread_flag(TIF_32BIT_ADDR); \ + \ + if (!((ex).e_flags & EF_MIPS_FP64)) \ + set_thread_flag(TIF_32BIT_FPREGS); \ + \ current->thread.abi = &mips_abi_32; \ } while (0) #else -#define __SET_PERSONALITY32_O32() \ +#define __SET_PERSONALITY32_O32(ex) \ do { } while (0) #endif @@ -289,7 +313,7 @@ do { \ ((ex).e_flags & EF_MIPS_ABI) == 0) \ __SET_PERSONALITY32_N32(); \ else \ - __SET_PERSONALITY32_O32(); \ + __SET_PERSONALITY32_O32(ex); \ } while (0) #else #define __SET_PERSONALITY32(ex) do { } while (0) @@ -300,6 +324,7 @@ do { \ unsigned int p; \ \ clear_thread_flag(TIF_32BIT_REGS); \ + clear_thread_flag(TIF_32BIT_FPREGS); \ clear_thread_flag(TIF_32BIT_ADDR); \ \ if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \ diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h index d088e5db49032b..6b9749540edffe 100644 --- a/arch/mips/include/asm/fpu.h +++ b/arch/mips/include/asm/fpu.h @@ -33,11 +33,50 @@ extern void _init_fpu(void); extern void _save_fp(struct task_struct *); extern void _restore_fp(struct task_struct *); -#define __enable_fpu() \ -do { \ - set_c0_status(ST0_CU1); \ - enable_fpu_hazard(); \ -} while (0) +/* + * This enum specifies a mode in which we want the FPU to operate, for cores + * which implement the Status.FR bit. Note that FPU_32BIT & FPU_64BIT + * purposefully have the values 0 & 1 respectively, so that an integer value + * of Status.FR can be trivially casted to the corresponding enum fpu_mode. + */ +enum fpu_mode { + FPU_32BIT = 0, /* FR = 0 */ + FPU_64BIT, /* FR = 1 */ + FPU_AS_IS, +}; + +static inline int __enable_fpu(enum fpu_mode mode) +{ + int fr; + + switch (mode) { + case FPU_AS_IS: + /* just enable the FPU in its current mode */ + set_c0_status(ST0_CU1); + enable_fpu_hazard(); + return 0; + + case FPU_64BIT: +#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_MIPS64)) + /* we only have a 32-bit FPU */ + return SIGFPE; +#endif + /* fall through */ + case FPU_32BIT: + /* set CU1 & change FR appropriately */ + fr = (int)mode; + change_c0_status(ST0_CU1 | ST0_FR, ST0_CU1 | (fr ? ST0_FR : 0)); + enable_fpu_hazard(); + + /* check FR has the desired value */ + return (!!(read_c0_status() & ST0_FR) == !!fr) ? 0 : SIGFPE; + + default: + BUG(); + } + + return SIGFPE; +} #define __disable_fpu() \ do { \ @@ -45,19 +84,6 @@ do { \ disable_fpu_hazard(); \ } while (0) -#define enable_fpu() \ -do { \ - if (cpu_has_fpu) \ - __enable_fpu(); \ -} while (0) - -#define disable_fpu() \ -do { \ - if (cpu_has_fpu) \ - __disable_fpu(); \ -} while (0) - - #define clear_fpu_owner() clear_thread_flag(TIF_USEDFPU) static inline int __is_fpu_owner(void) @@ -70,27 +96,46 @@ static inline int is_fpu_owner(void) return cpu_has_fpu && __is_fpu_owner(); } -static inline void __own_fpu(void) +static inline int __own_fpu(void) { - __enable_fpu(); + enum fpu_mode mode; + int ret; + + mode = !test_thread_flag(TIF_32BIT_FPREGS); + ret = __enable_fpu(mode); + if (ret) + return ret; + KSTK_STATUS(current) |= ST0_CU1; + if (mode == FPU_64BIT) + KSTK_STATUS(current) |= ST0_FR; + else /* mode == FPU_32BIT */ + KSTK_STATUS(current) &= ~ST0_FR; + set_thread_flag(TIF_USEDFPU); + return 0; } -static inline void own_fpu_inatomic(int restore) +static inline int own_fpu_inatomic(int restore) { + int ret = 0; + if (cpu_has_fpu && !__is_fpu_owner()) { - __own_fpu(); - if (restore) + ret = __own_fpu(); + if (restore && !ret) _restore_fp(current); } + return ret; } -static inline void own_fpu(int restore) +static inline int own_fpu(int restore) { + int ret; + preempt_disable(); - own_fpu_inatomic(restore); + ret = own_fpu_inatomic(restore); preempt_enable(); + return ret; } static inline void lose_fpu(int save) @@ -106,16 +151,21 @@ static inline void lose_fpu(int save) preempt_enable(); } -static inline void init_fpu(void) +static inline int init_fpu(void) { + int ret = 0; + preempt_disable(); if (cpu_has_fpu) { - __own_fpu(); - _init_fpu(); + ret = __own_fpu(); + if (!ret) + _init_fpu(); } else { fpu_emulator_init_fpu(); } + preempt_enable(); + return ret; } static inline void save_fp(struct task_struct *tsk) diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h index b0dd0c84df7040..572e63ec2a38fe 100644 --- a/arch/mips/include/asm/highmem.h +++ b/arch/mips/include/asm/highmem.h @@ -19,7 +19,6 @@ #ifdef __KERNEL__ -#include #include #include #include diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h index 32966969f2f975..a995fce8779103 100644 --- a/arch/mips/include/asm/kvm_host.h +++ b/arch/mips/include/asm/kvm_host.h @@ -391,9 +391,6 @@ struct kvm_vcpu_arch { uint32_t guest_kernel_asid[NR_CPUS]; struct mm_struct guest_kernel_mm, guest_user_mm; - struct kvm_mips_tlb shadow_tlb[NR_CPUS][KVM_MIPS_GUEST_TLB_SIZE]; - - struct hrtimer comparecount_timer; int last_sched_cpu; @@ -529,7 +526,6 @@ extern enum emulation_result kvm_mips_handle_tlbmod(unsigned long cause, extern void kvm_mips_dump_host_tlbs(void); extern void kvm_mips_dump_guest_tlbs(struct kvm_vcpu *vcpu); -extern void kvm_mips_dump_shadow_tlbs(struct kvm_vcpu *vcpu); extern void kvm_mips_flush_host_tlb(int skip_kseg0); extern int kvm_mips_host_tlb_inv(struct kvm_vcpu *vcpu, unsigned long entryhi); extern int kvm_mips_host_tlb_inv_index(struct kvm_vcpu *vcpu, int index); @@ -541,10 +537,7 @@ extern unsigned long kvm_mips_translate_guest_kseg0_to_hpa(struct kvm_vcpu *vcpu unsigned long gva); extern void kvm_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu, struct kvm_vcpu *vcpu); -extern void kvm_shadow_tlb_put(struct kvm_vcpu *vcpu); -extern void kvm_shadow_tlb_load(struct kvm_vcpu *vcpu); extern void kvm_local_flush_tlb_all(void); -extern void kvm_mips_init_shadow_tlb(struct kvm_vcpu *vcpu); extern void kvm_mips_alloc_new_mmu_context(struct kvm_vcpu *vcpu); extern void kvm_mips_vcpu_load(struct kvm_vcpu *vcpu, int cpu); extern void kvm_mips_vcpu_put(struct kvm_vcpu *vcpu); diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index b86a1253a5bf71..cd41e93bc1d801 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -16,7 +16,6 @@ #define __ASM_MACH_AR71XX_REGS_H #include -#include #include #include diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h index cc7563ba1cbf57..7527c1d33d029a 100644 --- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h +++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h @@ -56,4 +56,6 @@ void bcm47xx_fill_bcma_boardinfo(struct bcma_boardinfo *boardinfo, const char *prefix); #endif +void bcm47xx_set_system_type(u16 chip_id); + #endif /* __ASM_BCM47XX_H */ diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h index 00867dd05a6988..40005fb39618ad 100644 --- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h +++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h @@ -66,6 +66,7 @@ enum bcm47xx_board { BCM47XX_BOARD_LINKSYS_WRT310NV1, BCM47XX_BOARD_LINKSYS_WRT310NV2, BCM47XX_BOARD_LINKSYS_WRT54G3GV2, + BCM47XX_BOARD_LINKSYS_WRT54GSV1, BCM47XX_BOARD_LINKSYS_WRT610NV1, BCM47XX_BOARD_LINKSYS_WRT610NV2, BCM47XX_BOARD_LINKSYS_WRTSL54GS, diff --git a/arch/mips/include/asm/mach-bcm47xx/cpu-feature-overrides.h b/arch/mips/include/asm/mach-bcm47xx/cpu-feature-overrides.h new file mode 100644 index 00000000000000..b7992cd4aaf9b1 --- /dev/null +++ b/arch/mips/include/asm/mach-bcm47xx/cpu-feature-overrides.h @@ -0,0 +1,82 @@ +#ifndef __ASM_MACH_BCM47XX_CPU_FEATURE_OVERRIDES_H +#define __ASM_MACH_BCM47XX_CPU_FEATURE_OVERRIDES_H + +#define cpu_has_tlb 1 +#define cpu_has_4kex 1 +#define cpu_has_3k_cache 0 +#define cpu_has_4k_cache 1 +#define cpu_has_tx39_cache 0 +#define cpu_has_fpu 0 +#define cpu_has_32fpr 0 +#define cpu_has_counter 1 +#if defined(CONFIG_BCM47XX_BCMA) && !defined(CONFIG_BCM47XX_SSB) +#define cpu_has_watch 1 +#elif defined(CONFIG_BCM47XX_SSB) && !defined(CONFIG_BCM47XX_BCMA) +#define cpu_has_watch 0 +#endif +#define cpu_has_divec 1 +#define cpu_has_vce 0 +#define cpu_has_cache_cdex_p 0 +#define cpu_has_cache_cdex_s 0 +#define cpu_has_prefetch 1 +#define cpu_has_mcheck 1 +#define cpu_has_ejtag 1 +#define cpu_has_llsc 1 + +/* cpu_has_mips16 */ +#define cpu_has_mdmx 0 +#define cpu_has_mips3d 0 +#define cpu_has_rixi 0 +#define cpu_has_mmips 0 +#define cpu_has_smartmips 0 +#define cpu_has_vtag_icache 0 +/* cpu_has_dc_aliases */ +#define cpu_has_ic_fills_f_dc 0 +#define cpu_has_pindexed_dcache 0 +#define cpu_icache_snoops_remote_store 0 + +#define cpu_has_mips_2 1 +#define cpu_has_mips_3 0 +#define cpu_has_mips32r1 1 +#if defined(CONFIG_BCM47XX_BCMA) && !defined(CONFIG_BCM47XX_SSB) +#define cpu_has_mips32r2 1 +#elif defined(CONFIG_BCM47XX_SSB) && !defined(CONFIG_BCM47XX_BCMA) +#define cpu_has_mips32r2 0 +#endif +#define cpu_has_mips64r1 0 +#define cpu_has_mips64r2 0 + +#if defined(CONFIG_BCM47XX_BCMA) && !defined(CONFIG_BCM47XX_SSB) +#define cpu_has_dsp 1 +#define cpu_has_dsp2 1 +#elif defined(CONFIG_BCM47XX_SSB) && !defined(CONFIG_BCM47XX_BCMA) +#define cpu_has_dsp 0 +#define cpu_has_dsp2 0 +#endif +#define cpu_has_mipsmt 0 +/* cpu_has_userlocal */ + +#define cpu_has_nofpuex 0 +#define cpu_has_64bits 0 +#define cpu_has_64bit_zero_reg 0 +#if defined(CONFIG_BCM47XX_BCMA) && !defined(CONFIG_BCM47XX_SSB) +#define cpu_has_vint 1 +#elif defined(CONFIG_BCM47XX_SSB) && !defined(CONFIG_BCM47XX_BCMA) +#define cpu_has_vint 0 +#endif +#define cpu_has_veic 0 +#define cpu_has_inclusive_pcaches 0 + +#if defined(CONFIG_BCM47XX_BCMA) && !defined(CONFIG_BCM47XX_SSB) +#define cpu_dcache_line_size() 32 +#define cpu_icache_line_size() 32 +#define cpu_has_perf_cntr_intr_bit 1 +#elif defined(CONFIG_BCM47XX_SSB) && !defined(CONFIG_BCM47XX_BCMA) +#define cpu_dcache_line_size() 16 +#define cpu_icache_line_size() 16 +#define cpu_has_perf_cntr_intr_bit 0 +#endif +#define cpu_scache_line_size() 0 +#define cpu_has_vz 0 + +#endif /* __ASM_MACH_BCM47XX_CPU_FEATURE_OVERRIDES_H */ diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h index 19f9134bfe2fec..3112f08f0c7281 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h @@ -145,6 +145,7 @@ enum bcm63xx_regs_set { RSET_UART1, RSET_GPIO, RSET_SPI, + RSET_HSSPI, RSET_UDC0, RSET_OHCI0, RSET_OHCI_PRIV, @@ -193,6 +194,7 @@ enum bcm63xx_regs_set { #define RSET_ENETDMAS_SIZE(chans) (16 * (chans)) #define RSET_ENETSW_SIZE 65536 #define RSET_UART_SIZE 24 +#define RSET_HSSPI_SIZE 1536 #define RSET_UDC_SIZE 256 #define RSET_OHCI_SIZE 256 #define RSET_EHCI_SIZE 256 @@ -265,6 +267,7 @@ enum bcm63xx_regs_set { #define BCM_6328_UART1_BASE (0xb0000120) #define BCM_6328_GPIO_BASE (0xb0000080) #define BCM_6328_SPI_BASE (0xdeadbeef) +#define BCM_6328_HSSPI_BASE (0xb0001000) #define BCM_6328_UDC0_BASE (0xdeadbeef) #define BCM_6328_USBDMA_BASE (0xb000c000) #define BCM_6328_OHCI0_BASE (0xb0002600) @@ -313,6 +316,7 @@ enum bcm63xx_regs_set { #define BCM_6338_UART1_BASE (0xdeadbeef) #define BCM_6338_GPIO_BASE (0xfffe0400) #define BCM_6338_SPI_BASE (0xfffe0c00) +#define BCM_6338_HSSPI_BASE (0xdeadbeef) #define BCM_6338_UDC0_BASE (0xdeadbeef) #define BCM_6338_USBDMA_BASE (0xfffe2400) #define BCM_6338_OHCI0_BASE (0xdeadbeef) @@ -360,6 +364,7 @@ enum bcm63xx_regs_set { #define BCM_6345_UART1_BASE (0xdeadbeef) #define BCM_6345_GPIO_BASE (0xfffe0400) #define BCM_6345_SPI_BASE (0xdeadbeef) +#define BCM_6345_HSSPI_BASE (0xdeadbeef) #define BCM_6345_UDC0_BASE (0xdeadbeef) #define BCM_6345_USBDMA_BASE (0xfffe2800) #define BCM_6345_ENET0_BASE (0xfffe1800) @@ -406,6 +411,7 @@ enum bcm63xx_regs_set { #define BCM_6348_UART1_BASE (0xdeadbeef) #define BCM_6348_GPIO_BASE (0xfffe0400) #define BCM_6348_SPI_BASE (0xfffe0c00) +#define BCM_6348_HSSPI_BASE (0xdeadbeef) #define BCM_6348_UDC0_BASE (0xfffe1000) #define BCM_6348_USBDMA_BASE (0xdeadbeef) #define BCM_6348_OHCI0_BASE (0xfffe1b00) @@ -451,6 +457,7 @@ enum bcm63xx_regs_set { #define BCM_6358_UART1_BASE (0xfffe0120) #define BCM_6358_GPIO_BASE (0xfffe0080) #define BCM_6358_SPI_BASE (0xfffe0800) +#define BCM_6358_HSSPI_BASE (0xdeadbeef) #define BCM_6358_UDC0_BASE (0xfffe0800) #define BCM_6358_USBDMA_BASE (0xdeadbeef) #define BCM_6358_OHCI0_BASE (0xfffe1400) @@ -553,6 +560,7 @@ enum bcm63xx_regs_set { #define BCM_6368_UART1_BASE (0xb0000120) #define BCM_6368_GPIO_BASE (0xb0000080) #define BCM_6368_SPI_BASE (0xb0000800) +#define BCM_6368_HSSPI_BASE (0xdeadbeef) #define BCM_6368_UDC0_BASE (0xdeadbeef) #define BCM_6368_USBDMA_BASE (0xb0004800) #define BCM_6368_OHCI0_BASE (0xb0001600) @@ -604,6 +612,7 @@ extern const unsigned long *bcm63xx_regs_base; __GEN_RSET_BASE(__cpu, UART1) \ __GEN_RSET_BASE(__cpu, GPIO) \ __GEN_RSET_BASE(__cpu, SPI) \ + __GEN_RSET_BASE(__cpu, HSSPI) \ __GEN_RSET_BASE(__cpu, UDC0) \ __GEN_RSET_BASE(__cpu, OHCI0) \ __GEN_RSET_BASE(__cpu, OHCI_PRIV) \ @@ -647,6 +656,7 @@ extern const unsigned long *bcm63xx_regs_base; [RSET_UART1] = BCM_## __cpu ##_UART1_BASE, \ [RSET_GPIO] = BCM_## __cpu ##_GPIO_BASE, \ [RSET_SPI] = BCM_## __cpu ##_SPI_BASE, \ + [RSET_HSSPI] = BCM_## __cpu ##_HSSPI_BASE, \ [RSET_UDC0] = BCM_## __cpu ##_UDC0_BASE, \ [RSET_OHCI0] = BCM_## __cpu ##_OHCI0_BASE, \ [RSET_OHCI_PRIV] = BCM_## __cpu ##_OHCI_PRIV_BASE, \ @@ -727,6 +737,7 @@ enum bcm63xx_irq { IRQ_ENET0, IRQ_ENET1, IRQ_ENET_PHY, + IRQ_HSSPI, IRQ_OHCI0, IRQ_EHCI0, IRQ_USBD, @@ -815,6 +826,7 @@ enum bcm63xx_irq { #define BCM_6328_ENET0_IRQ 0 #define BCM_6328_ENET1_IRQ 0 #define BCM_6328_ENET_PHY_IRQ (IRQ_INTERNAL_BASE + 12) +#define BCM_6328_HSSPI_IRQ (IRQ_INTERNAL_BASE + 29) #define BCM_6328_OHCI0_IRQ (BCM_6328_HIGH_IRQ_BASE + 9) #define BCM_6328_EHCI0_IRQ (BCM_6328_HIGH_IRQ_BASE + 10) #define BCM_6328_USBD_IRQ (IRQ_INTERNAL_BASE + 4) @@ -860,6 +872,7 @@ enum bcm63xx_irq { #define BCM_6338_ENET0_IRQ (IRQ_INTERNAL_BASE + 8) #define BCM_6338_ENET1_IRQ 0 #define BCM_6338_ENET_PHY_IRQ (IRQ_INTERNAL_BASE + 9) +#define BCM_6338_HSSPI_IRQ 0 #define BCM_6338_OHCI0_IRQ 0 #define BCM_6338_EHCI0_IRQ 0 #define BCM_6338_USBD_IRQ 0 @@ -898,6 +911,7 @@ enum bcm63xx_irq { #define BCM_6345_ENET0_IRQ (IRQ_INTERNAL_BASE + 8) #define BCM_6345_ENET1_IRQ 0 #define BCM_6345_ENET_PHY_IRQ (IRQ_INTERNAL_BASE + 12) +#define BCM_6345_HSSPI_IRQ 0 #define BCM_6345_OHCI0_IRQ 0 #define BCM_6345_EHCI0_IRQ 0 #define BCM_6345_USBD_IRQ 0 @@ -936,6 +950,7 @@ enum bcm63xx_irq { #define BCM_6348_ENET0_IRQ (IRQ_INTERNAL_BASE + 8) #define BCM_6348_ENET1_IRQ (IRQ_INTERNAL_BASE + 7) #define BCM_6348_ENET_PHY_IRQ (IRQ_INTERNAL_BASE + 9) +#define BCM_6348_HSSPI_IRQ 0 #define BCM_6348_OHCI0_IRQ (IRQ_INTERNAL_BASE + 12) #define BCM_6348_EHCI0_IRQ 0 #define BCM_6348_USBD_IRQ 0 @@ -974,6 +989,7 @@ enum bcm63xx_irq { #define BCM_6358_ENET0_IRQ (IRQ_INTERNAL_BASE + 8) #define BCM_6358_ENET1_IRQ (IRQ_INTERNAL_BASE + 6) #define BCM_6358_ENET_PHY_IRQ (IRQ_INTERNAL_BASE + 9) +#define BCM_6358_HSSPI_IRQ 0 #define BCM_6358_OHCI0_IRQ (IRQ_INTERNAL_BASE + 5) #define BCM_6358_EHCI0_IRQ (IRQ_INTERNAL_BASE + 10) #define BCM_6358_USBD_IRQ 0 @@ -1086,6 +1102,7 @@ enum bcm63xx_irq { #define BCM_6368_ENET0_IRQ 0 #define BCM_6368_ENET1_IRQ 0 #define BCM_6368_ENET_PHY_IRQ (IRQ_INTERNAL_BASE + 15) +#define BCM_6368_HSSPI_IRQ 0 #define BCM_6368_OHCI0_IRQ (IRQ_INTERNAL_BASE + 5) #define BCM_6368_EHCI0_IRQ (IRQ_INTERNAL_BASE + 7) #define BCM_6368_USBD_IRQ (IRQ_INTERNAL_BASE + 8) @@ -1133,6 +1150,7 @@ extern const int *bcm63xx_irqs; [IRQ_ENET0] = BCM_## __cpu ##_ENET0_IRQ, \ [IRQ_ENET1] = BCM_## __cpu ##_ENET1_IRQ, \ [IRQ_ENET_PHY] = BCM_## __cpu ##_ENET_PHY_IRQ, \ + [IRQ_HSSPI] = BCM_## __cpu ##_HSSPI_IRQ, \ [IRQ_OHCI0] = BCM_## __cpu ##_OHCI0_IRQ, \ [IRQ_EHCI0] = BCM_## __cpu ##_EHCI0_IRQ, \ [IRQ_USBD] = BCM_## __cpu ##_USBD_IRQ, \ diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_hsspi.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_hsspi.h new file mode 100644 index 00000000000000..1b1acafb3d7945 --- /dev/null +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_hsspi.h @@ -0,0 +1,8 @@ +#ifndef BCM63XX_DEV_HSSPI_H +#define BCM63XX_DEV_HSSPI_H + +#include + +int bcm63xx_hsspi_register(void); + +#endif /* BCM63XX_DEV_HSSPI_H */ diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h index 9875db31d883af..ab427f8814e6b2 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h @@ -462,126 +462,6 @@ /* Watchdog soft reset register (BCM6328 only) */ #define WDT_SOFTRESET_REG 0xc -/************************************************************************* - * _REG relative to RSET_UARTx - *************************************************************************/ - -/* UART Control Register */ -#define UART_CTL_REG 0x0 -#define UART_CTL_RXTMOUTCNT_SHIFT 0 -#define UART_CTL_RXTMOUTCNT_MASK (0x1f << UART_CTL_RXTMOUTCNT_SHIFT) -#define UART_CTL_RSTTXDN_SHIFT 5 -#define UART_CTL_RSTTXDN_MASK (1 << UART_CTL_RSTTXDN_SHIFT) -#define UART_CTL_RSTRXFIFO_SHIFT 6 -#define UART_CTL_RSTRXFIFO_MASK (1 << UART_CTL_RSTRXFIFO_SHIFT) -#define UART_CTL_RSTTXFIFO_SHIFT 7 -#define UART_CTL_RSTTXFIFO_MASK (1 << UART_CTL_RSTTXFIFO_SHIFT) -#define UART_CTL_STOPBITS_SHIFT 8 -#define UART_CTL_STOPBITS_MASK (0xf << UART_CTL_STOPBITS_SHIFT) -#define UART_CTL_STOPBITS_1 (0x7 << UART_CTL_STOPBITS_SHIFT) -#define UART_CTL_STOPBITS_2 (0xf << UART_CTL_STOPBITS_SHIFT) -#define UART_CTL_BITSPERSYM_SHIFT 12 -#define UART_CTL_BITSPERSYM_MASK (0x3 << UART_CTL_BITSPERSYM_SHIFT) -#define UART_CTL_XMITBRK_SHIFT 14 -#define UART_CTL_XMITBRK_MASK (1 << UART_CTL_XMITBRK_SHIFT) -#define UART_CTL_RSVD_SHIFT 15 -#define UART_CTL_RSVD_MASK (1 << UART_CTL_RSVD_SHIFT) -#define UART_CTL_RXPAREVEN_SHIFT 16 -#define UART_CTL_RXPAREVEN_MASK (1 << UART_CTL_RXPAREVEN_SHIFT) -#define UART_CTL_RXPAREN_SHIFT 17 -#define UART_CTL_RXPAREN_MASK (1 << UART_CTL_RXPAREN_SHIFT) -#define UART_CTL_TXPAREVEN_SHIFT 18 -#define UART_CTL_TXPAREVEN_MASK (1 << UART_CTL_TXPAREVEN_SHIFT) -#define UART_CTL_TXPAREN_SHIFT 18 -#define UART_CTL_TXPAREN_MASK (1 << UART_CTL_TXPAREN_SHIFT) -#define UART_CTL_LOOPBACK_SHIFT 20 -#define UART_CTL_LOOPBACK_MASK (1 << UART_CTL_LOOPBACK_SHIFT) -#define UART_CTL_RXEN_SHIFT 21 -#define UART_CTL_RXEN_MASK (1 << UART_CTL_RXEN_SHIFT) -#define UART_CTL_TXEN_SHIFT 22 -#define UART_CTL_TXEN_MASK (1 << UART_CTL_TXEN_SHIFT) -#define UART_CTL_BRGEN_SHIFT 23 -#define UART_CTL_BRGEN_MASK (1 << UART_CTL_BRGEN_SHIFT) - -/* UART Baudword register */ -#define UART_BAUD_REG 0x4 - -/* UART Misc Control register */ -#define UART_MCTL_REG 0x8 -#define UART_MCTL_DTR_SHIFT 0 -#define UART_MCTL_DTR_MASK (1 << UART_MCTL_DTR_SHIFT) -#define UART_MCTL_RTS_SHIFT 1 -#define UART_MCTL_RTS_MASK (1 << UART_MCTL_RTS_SHIFT) -#define UART_MCTL_RXFIFOTHRESH_SHIFT 8 -#define UART_MCTL_RXFIFOTHRESH_MASK (0xf << UART_MCTL_RXFIFOTHRESH_SHIFT) -#define UART_MCTL_TXFIFOTHRESH_SHIFT 12 -#define UART_MCTL_TXFIFOTHRESH_MASK (0xf << UART_MCTL_TXFIFOTHRESH_SHIFT) -#define UART_MCTL_RXFIFOFILL_SHIFT 16 -#define UART_MCTL_RXFIFOFILL_MASK (0x1f << UART_MCTL_RXFIFOFILL_SHIFT) -#define UART_MCTL_TXFIFOFILL_SHIFT 24 -#define UART_MCTL_TXFIFOFILL_MASK (0x1f << UART_MCTL_TXFIFOFILL_SHIFT) - -/* UART External Input Configuration register */ -#define UART_EXTINP_REG 0xc -#define UART_EXTINP_RI_SHIFT 0 -#define UART_EXTINP_RI_MASK (1 << UART_EXTINP_RI_SHIFT) -#define UART_EXTINP_CTS_SHIFT 1 -#define UART_EXTINP_CTS_MASK (1 << UART_EXTINP_CTS_SHIFT) -#define UART_EXTINP_DCD_SHIFT 2 -#define UART_EXTINP_DCD_MASK (1 << UART_EXTINP_DCD_SHIFT) -#define UART_EXTINP_DSR_SHIFT 3 -#define UART_EXTINP_DSR_MASK (1 << UART_EXTINP_DSR_SHIFT) -#define UART_EXTINP_IRSTAT(x) (1 << (x + 4)) -#define UART_EXTINP_IRMASK(x) (1 << (x + 8)) -#define UART_EXTINP_IR_RI 0 -#define UART_EXTINP_IR_CTS 1 -#define UART_EXTINP_IR_DCD 2 -#define UART_EXTINP_IR_DSR 3 -#define UART_EXTINP_RI_NOSENSE_SHIFT 16 -#define UART_EXTINP_RI_NOSENSE_MASK (1 << UART_EXTINP_RI_NOSENSE_SHIFT) -#define UART_EXTINP_CTS_NOSENSE_SHIFT 17 -#define UART_EXTINP_CTS_NOSENSE_MASK (1 << UART_EXTINP_CTS_NOSENSE_SHIFT) -#define UART_EXTINP_DCD_NOSENSE_SHIFT 18 -#define UART_EXTINP_DCD_NOSENSE_MASK (1 << UART_EXTINP_DCD_NOSENSE_SHIFT) -#define UART_EXTINP_DSR_NOSENSE_SHIFT 19 -#define UART_EXTINP_DSR_NOSENSE_MASK (1 << UART_EXTINP_DSR_NOSENSE_SHIFT) - -/* UART Interrupt register */ -#define UART_IR_REG 0x10 -#define UART_IR_MASK(x) (1 << (x + 16)) -#define UART_IR_STAT(x) (1 << (x)) -#define UART_IR_EXTIP 0 -#define UART_IR_TXUNDER 1 -#define UART_IR_TXOVER 2 -#define UART_IR_TXTRESH 3 -#define UART_IR_TXRDLATCH 4 -#define UART_IR_TXEMPTY 5 -#define UART_IR_RXUNDER 6 -#define UART_IR_RXOVER 7 -#define UART_IR_RXTIMEOUT 8 -#define UART_IR_RXFULL 9 -#define UART_IR_RXTHRESH 10 -#define UART_IR_RXNOTEMPTY 11 -#define UART_IR_RXFRAMEERR 12 -#define UART_IR_RXPARERR 13 -#define UART_IR_RXBRK 14 -#define UART_IR_TXDONE 15 - -/* UART Fifo register */ -#define UART_FIFO_REG 0x14 -#define UART_FIFO_VALID_SHIFT 0 -#define UART_FIFO_VALID_MASK 0xff -#define UART_FIFO_FRAMEERR_SHIFT 8 -#define UART_FIFO_FRAMEERR_MASK (1 << UART_FIFO_FRAMEERR_SHIFT) -#define UART_FIFO_PARERR_SHIFT 9 -#define UART_FIFO_PARERR_MASK (1 << UART_FIFO_PARERR_SHIFT) -#define UART_FIFO_BRKDET_SHIFT 10 -#define UART_FIFO_BRKDET_MASK (1 << UART_FIFO_BRKDET_SHIFT) -#define UART_FIFO_ANYERR_MASK (UART_FIFO_FRAMEERR_MASK | \ - UART_FIFO_PARERR_MASK | \ - UART_FIFO_BRKDET_MASK) - - /************************************************************************* * _REG relative to RSET_GPIO *************************************************************************/ diff --git a/arch/mips/include/asm/mach-generic/dma-coherence.h b/arch/mips/include/asm/mach-generic/dma-coherence.h index a9e8f6b62b0b9c..7629c35986f713 100644 --- a/arch/mips/include/asm/mach-generic/dma-coherence.h +++ b/arch/mips/include/asm/mach-generic/dma-coherence.h @@ -49,11 +49,7 @@ static inline int plat_dma_supported(struct device *dev, u64 mask) static inline int plat_device_is_coherent(struct device *dev) { -#ifdef CONFIG_DMA_COHERENT - return 1; -#else return coherentio; -#endif } #ifdef CONFIG_SWIOTLB diff --git a/arch/mips/include/asm/mach-generic/floppy.h b/arch/mips/include/asm/mach-generic/floppy.h index 5b5cd689a2f7a0..e2561d99a3feaf 100644 --- a/arch/mips/include/asm/mach-generic/floppy.h +++ b/arch/mips/include/asm/mach-generic/floppy.h @@ -9,7 +9,6 @@ #define __ASM_MACH_GENERIC_FLOPPY_H #include -#include #include #include #include diff --git a/arch/mips/include/asm/mach-generic/ide.h b/arch/mips/include/asm/mach-generic/ide.h index affa66f5c2dab0..4ae5fbcb15a5a7 100644 --- a/arch/mips/include/asm/mach-generic/ide.h +++ b/arch/mips/include/asm/mach-generic/ide.h @@ -23,7 +23,7 @@ static inline void __ide_flush_prologue(void) { #ifdef CONFIG_SMP - if (cpu_has_dc_aliases) + if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) preempt_disable(); #endif } @@ -31,14 +31,14 @@ static inline void __ide_flush_prologue(void) static inline void __ide_flush_epilogue(void) { #ifdef CONFIG_SMP - if (cpu_has_dc_aliases) + if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) preempt_enable(); #endif } static inline void __ide_flush_dcache_range(unsigned long addr, unsigned long size) { - if (cpu_has_dc_aliases) { + if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) { unsigned long end = addr + size; while (addr < end) { diff --git a/arch/mips/include/asm/mach-jazz/floppy.h b/arch/mips/include/asm/mach-jazz/floppy.h index 62aa1e287fba17..4b86c88a03b773 100644 --- a/arch/mips/include/asm/mach-jazz/floppy.h +++ b/arch/mips/include/asm/mach-jazz/floppy.h @@ -9,7 +9,6 @@ #define __ASM_MACH_JAZZ_FLOPPY_H #include -#include #include #include #include diff --git a/arch/mips/include/asm/mach-jz4740/platform.h b/arch/mips/include/asm/mach-jz4740/platform.h index 05988c2d656509..069b43a9da6f0e 100644 --- a/arch/mips/include/asm/mach-jz4740/platform.h +++ b/arch/mips/include/asm/mach-jz4740/platform.h @@ -21,6 +21,7 @@ extern struct platform_device jz4740_usb_ohci_device; extern struct platform_device jz4740_udc_device; +extern struct platform_device jz4740_udc_xceiv_device; extern struct platform_device jz4740_mmc_device; extern struct platform_device jz4740_rtc_device; extern struct platform_device jz4740_i2c_device; diff --git a/arch/mips/include/asm/mach-netlogic/irq.h b/arch/mips/include/asm/mach-netlogic/irq.h index 868ed8a2ed5c02..c0dbd530cca612 100644 --- a/arch/mips/include/asm/mach-netlogic/irq.h +++ b/arch/mips/include/asm/mach-netlogic/irq.h @@ -9,7 +9,8 @@ #define __ASM_NETLOGIC_IRQ_H #include -#define NR_IRQS (64 * NLM_NR_NODES) +#define NLM_IRQS_PER_NODE 1024 +#define NR_IRQS (NLM_IRQS_PER_NODE * NLM_NR_NODES) #define MIPS_CPU_IRQ_BASE 0 diff --git a/arch/mips/include/asm/mach-netlogic/multi-node.h b/arch/mips/include/asm/mach-netlogic/multi-node.h index d62fc773f4d7a9..9ed8dacdc37c5a 100644 --- a/arch/mips/include/asm/mach-netlogic/multi-node.h +++ b/arch/mips/include/asm/mach-netlogic/multi-node.h @@ -47,8 +47,37 @@ #endif #endif -#define NLM_CORES_PER_NODE 8 #define NLM_THREADS_PER_CORE 4 -#define NLM_CPUS_PER_NODE (NLM_CORES_PER_NODE * NLM_THREADS_PER_CORE) +#ifdef CONFIG_CPU_XLR +#define nlm_cores_per_node() 8 +#else +extern unsigned int xlp_cores_per_node; +#define nlm_cores_per_node() xlp_cores_per_node +#endif + +#define nlm_threads_per_node() (nlm_cores_per_node() * NLM_THREADS_PER_CORE) +#define nlm_cpuid_to_node(c) ((c) / nlm_threads_per_node()) + +struct nlm_soc_info { + unsigned long coremask; /* cores enabled on the soc */ + unsigned long ebase; /* not used now */ + uint64_t irqmask; /* EIMR for the node */ + uint64_t sysbase; /* only for XLP - sys block base */ + uint64_t picbase; /* PIC block base */ + spinlock_t piclock; /* lock for PIC access */ + cpumask_t cpumask; /* logical cpu mask for node */ + unsigned int socbus; +}; + +extern struct nlm_soc_info nlm_nodes[NLM_NR_NODES]; +#define nlm_get_node(i) (&nlm_nodes[i]) +#define nlm_node_present(n) ((n) >= 0 && (n) < NLM_NR_NODES && \ + nlm_get_node(n)->coremask != 0) +#ifdef CONFIG_CPU_XLR +#define nlm_current_node() (&nlm_nodes[0]) +#else +#define nlm_current_node() (&nlm_nodes[nlm_nodeid()]) +#endif +void nlm_node_init(int node); #endif diff --git a/arch/mips/include/asm/mach-netlogic/topology.h b/arch/mips/include/asm/mach-netlogic/topology.h new file mode 100644 index 00000000000000..0da99fa11c3830 --- /dev/null +++ b/arch/mips/include/asm/mach-netlogic/topology.h @@ -0,0 +1,20 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2013 Broadcom Corporation + */ +#ifndef _ASM_MACH_NETLOGIC_TOPOLOGY_H +#define _ASM_MACH_NETLOGIC_TOPOLOGY_H + +#include + +#define topology_physical_package_id(cpu) cpu_to_node(cpu) +#define topology_core_id(cpu) (cpu_logical_map(cpu) / NLM_THREADS_PER_CORE) +#define topology_thread_cpumask(cpu) (&cpu_sibling_map[cpu]) +#define topology_core_cpumask(cpu) cpumask_of_node(cpu_to_node(cpu)) + +#include + +#endif /* _ASM_MACH_NETLOGIC_TOPOLOGY_H */ diff --git a/arch/mips/include/asm/mips-boards/piix4.h b/arch/mips/include/asm/mips-boards/piix4.h index e33227998713e6..836e2ede24de11 100644 --- a/arch/mips/include/asm/mips-boards/piix4.h +++ b/arch/mips/include/asm/mips-boards/piix4.h @@ -26,6 +26,10 @@ #define PIIX4_FUNC0_PIRQRC_IRQ_ROUTING_DISABLE (1 << 7) #define PIIX4_FUNC0_PIRQRC_IRQ_ROUTING_MASK 0xf #define PIIX4_FUNC0_PIRQRC_IRQ_ROUTING_MAX 16 +/* SERIRQ Control */ +#define PIIX4_FUNC0_SERIRQC 0x64 +#define PIIX4_FUNC0_SERIRQC_EN (1 << 7) +#define PIIX4_FUNC0_SERIRQC_CONT (1 << 6) /* Top Of Memory */ #define PIIX4_FUNC0_TOM 0x69 #define PIIX4_FUNC0_TOM_TOP_OF_MEMORY_MASK 0xf0 @@ -34,6 +38,9 @@ #define PIIX4_FUNC0_DLC_USBPR_EN (1 << 2) #define PIIX4_FUNC0_DLC_PASSIVE_RELEASE_EN (1 << 1) #define PIIX4_FUNC0_DLC_DELAYED_TRANSACTION_EN (1 << 0) +/* General Configuration */ +#define PIIX4_FUNC0_GENCFG 0xb0 +#define PIIX4_FUNC0_GENCFG_SERIRQ (1 << 16) /* IDE Timing */ #define PIIX4_FUNC1_IDETIM_PRIMARY_LO 0x40 diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index e0331414c7d60f..bbc3dd4294bc31 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -14,6 +14,7 @@ #define _ASM_MIPSREGS_H #include +#include #include #include @@ -573,7 +574,9 @@ #define MIPS_CONF1_IA (_ULCAST_(7) << 16) #define MIPS_CONF1_IL (_ULCAST_(7) << 19) #define MIPS_CONF1_IS (_ULCAST_(7) << 22) -#define MIPS_CONF1_TLBS (_ULCAST_(63)<< 25) +#define MIPS_CONF1_TLBS_SHIFT (25) +#define MIPS_CONF1_TLBS_SIZE (6) +#define MIPS_CONF1_TLBS (_ULCAST_(63) << MIPS_CONF1_TLBS_SHIFT) #define MIPS_CONF2_SA (_ULCAST_(15)<< 0) #define MIPS_CONF2_SL (_ULCAST_(15)<< 4) @@ -587,21 +590,53 @@ #define MIPS_CONF3_TL (_ULCAST_(1) << 0) #define MIPS_CONF3_SM (_ULCAST_(1) << 1) #define MIPS_CONF3_MT (_ULCAST_(1) << 2) +#define MIPS_CONF3_CDMM (_ULCAST_(1) << 3) #define MIPS_CONF3_SP (_ULCAST_(1) << 4) #define MIPS_CONF3_VINT (_ULCAST_(1) << 5) #define MIPS_CONF3_VEIC (_ULCAST_(1) << 6) #define MIPS_CONF3_LPA (_ULCAST_(1) << 7) +#define MIPS_CONF3_ITL (_ULCAST_(1) << 8) +#define MIPS_CONF3_CTXTC (_ULCAST_(1) << 9) #define MIPS_CONF3_DSP (_ULCAST_(1) << 10) #define MIPS_CONF3_DSP2P (_ULCAST_(1) << 11) #define MIPS_CONF3_RXI (_ULCAST_(1) << 12) #define MIPS_CONF3_ULRI (_ULCAST_(1) << 13) #define MIPS_CONF3_ISA (_ULCAST_(3) << 14) #define MIPS_CONF3_ISA_OE (_ULCAST_(1) << 16) +#define MIPS_CONF3_MCU (_ULCAST_(1) << 17) +#define MIPS_CONF3_MMAR (_ULCAST_(7) << 18) +#define MIPS_CONF3_IPLW (_ULCAST_(3) << 21) #define MIPS_CONF3_VZ (_ULCAST_(1) << 23) - +#define MIPS_CONF3_PW (_ULCAST_(1) << 24) +#define MIPS_CONF3_SC (_ULCAST_(1) << 25) +#define MIPS_CONF3_BI (_ULCAST_(1) << 26) +#define MIPS_CONF3_BP (_ULCAST_(1) << 27) +#define MIPS_CONF3_MSA (_ULCAST_(1) << 28) +#define MIPS_CONF3_CMGCR (_ULCAST_(1) << 29) +#define MIPS_CONF3_BPG (_ULCAST_(1) << 30) + +#define MIPS_CONF4_MMUSIZEEXT_SHIFT (0) #define MIPS_CONF4_MMUSIZEEXT (_ULCAST_(255) << 0) +#define MIPS_CONF4_FTLBSETS_SHIFT (0) +#define MIPS_CONF4_FTLBSETS_SHIFT (0) +#define MIPS_CONF4_FTLBSETS (_ULCAST_(15) << MIPS_CONF4_FTLBSETS_SHIFT) +#define MIPS_CONF4_FTLBWAYS_SHIFT (4) +#define MIPS_CONF4_FTLBWAYS (_ULCAST_(15) << MIPS_CONF4_FTLBWAYS_SHIFT) +#define MIPS_CONF4_FTLBPAGESIZE_SHIFT (8) +/* bits 10:8 in FTLB-only configurations */ +#define MIPS_CONF4_FTLBPAGESIZE (_ULCAST_(7) << MIPS_CONF4_FTLBPAGESIZE_SHIFT) +/* bits 12:8 in VTLB-FTLB only configurations */ +#define MIPS_CONF4_VFTLBPAGESIZE (_ULCAST_(31) << MIPS_CONF4_FTLBPAGESIZE_SHIFT) #define MIPS_CONF4_MMUEXTDEF (_ULCAST_(3) << 14) #define MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT (_ULCAST_(1) << 14) +#define MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT (_ULCAST_(2) << 14) +#define MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT (_ULCAST_(3) << 14) +#define MIPS_CONF4_KSCREXIST (_ULCAST_(255) << 16) +#define MIPS_CONF4_VTLBSIZEEXT_SHIFT (24) +#define MIPS_CONF4_VTLBSIZEEXT (_ULCAST_(15) << MIPS_CONF4_VTLBSIZEEXT_SHIFT) +#define MIPS_CONF4_AE (_ULCAST_(1) << 28) +#define MIPS_CONF4_IE (_ULCAST_(3) << 29) +#define MIPS_CONF4_TLBINV (_ULCAST_(2) << 29) #define MIPS_CONF5_NF (_ULCAST_(1) << 0) #define MIPS_CONF5_UFR (_ULCAST_(1) << 2) @@ -611,11 +646,15 @@ #define MIPS_CONF5_K (_ULCAST_(1) << 30) #define MIPS_CONF6_SYND (_ULCAST_(1) << 13) +/* proAptiv FTLB on/off bit */ +#define MIPS_CONF6_FTLBEN (_ULCAST_(1) << 15) #define MIPS_CONF7_WII (_ULCAST_(1) << 31) #define MIPS_CONF7_RPS (_ULCAST_(1) << 2) +/* EntryHI bit definition */ +#define MIPS_ENTRYHI_EHINV (_ULCAST_(1) << 10) /* * Bits in the MIPS32/64 coprocessor 1 (FPU) revision register. @@ -628,6 +667,26 @@ #define MIPS_FPIR_L (_ULCAST_(1) << 21) #define MIPS_FPIR_F64 (_ULCAST_(1) << 22) +/* + * Bits in the MIPS32 Memory Segmentation registers. + */ +#define MIPS_SEGCFG_PA_SHIFT 9 +#define MIPS_SEGCFG_PA (_ULCAST_(127) << MIPS_SEGCFG_PA_SHIFT) +#define MIPS_SEGCFG_AM_SHIFT 4 +#define MIPS_SEGCFG_AM (_ULCAST_(7) << MIPS_SEGCFG_AM_SHIFT) +#define MIPS_SEGCFG_EU_SHIFT 3 +#define MIPS_SEGCFG_EU (_ULCAST_(1) << MIPS_SEGCFG_EU_SHIFT) +#define MIPS_SEGCFG_C_SHIFT 0 +#define MIPS_SEGCFG_C (_ULCAST_(7) << MIPS_SEGCFG_C_SHIFT) + +#define MIPS_SEGCFG_UUSK _ULCAST_(7) +#define MIPS_SEGCFG_USK _ULCAST_(5) +#define MIPS_SEGCFG_MUSUK _ULCAST_(4) +#define MIPS_SEGCFG_MUSK _ULCAST_(3) +#define MIPS_SEGCFG_MSK _ULCAST_(2) +#define MIPS_SEGCFG_MK _ULCAST_(1) +#define MIPS_SEGCFG_UK _ULCAST_(0) + #ifndef __ASSEMBLY__ /* @@ -648,6 +707,19 @@ static inline int mm_insn_16bit(u16 insn) return (opcode >= 1 && opcode <= 3) ? 1 : 0; } +/* + * TLB Invalidate Flush + */ +static inline void tlbinvf(void) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + ".word 0x42000004\n\t" /* tlbinvf */ + ".set pop"); +} + + /* * Functions to access the R10000 performance counters. These are basically * mfc0 and mtc0 instructions from and to coprocessor register with a 5-bit @@ -1102,6 +1174,15 @@ do { \ #define read_c0_ebase() __read_32bit_c0_register($15, 1) #define write_c0_ebase(val) __write_32bit_c0_register($15, 1, val) +/* MIPSR3 */ +#define read_c0_segctl0() __read_32bit_c0_register($5, 2) +#define write_c0_segctl0(val) __write_32bit_c0_register($5, 2, val) + +#define read_c0_segctl1() __read_32bit_c0_register($5, 3) +#define write_c0_segctl1(val) __write_32bit_c0_register($5, 3, val) + +#define read_c0_segctl2() __read_32bit_c0_register($5, 4) +#define write_c0_segctl2(val) __write_32bit_c0_register($5, 4, val) /* Cavium OCTEON (cnMIPS) */ #define read_c0_cvmcount() __read_ulong_c0_register($9, 6) diff --git a/arch/mips/include/asm/netlogic/common.h b/arch/mips/include/asm/netlogic/common.h index bb68c3398c8085..c281f03eb31263 100644 --- a/arch/mips/include/asm/netlogic/common.h +++ b/arch/mips/include/asm/netlogic/common.h @@ -84,7 +84,6 @@ nlm_set_nmi_handler(void *handler) */ void nlm_init_boot_cpu(void); unsigned int nlm_get_cpu_frequency(void); -void nlm_node_init(int node); extern struct plat_smp_ops nlm_smp_ops; extern char nlm_reset_entry[], nlm_reset_entry_end[]; @@ -94,26 +93,16 @@ extern struct dma_map_ops nlm_swiotlb_dma_ops; extern unsigned int nlm_threads_per_core; extern cpumask_t nlm_cpumask; -struct nlm_soc_info { - unsigned long coremask; /* cores enabled on the soc */ - unsigned long ebase; - uint64_t irqmask; - uint64_t sysbase; /* only for XLP */ - uint64_t picbase; - spinlock_t piclock; -}; - -#define nlm_get_node(i) (&nlm_nodes[i]) -#ifdef CONFIG_CPU_XLR -#define nlm_current_node() (&nlm_nodes[0]) -#else -#define nlm_current_node() (&nlm_nodes[nlm_nodeid()]) -#endif - struct irq_data; uint64_t nlm_pci_irqmask(int node); +void nlm_setup_pic_irq(int node, int picirq, int irq, int irt); void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *)); +#ifdef CONFIG_PCI_MSI +void nlm_dispatch_msi(int node, int lirq); +void nlm_dispatch_msix(int node, int msixirq); +#endif + /* * The NR_IRQs is divided between nodes, each of them has a separate irq space */ @@ -122,7 +111,6 @@ static inline int nlm_irq_to_xirq(int node, int irq) return node * NR_IRQS / NLM_NR_NODES + irq; } -extern struct nlm_soc_info nlm_nodes[NLM_NR_NODES]; extern int nlm_cpu_ready[]; #endif #endif /* _NETLOGIC_COMMON_H_ */ diff --git a/arch/mips/include/asm/netlogic/mips-extns.h b/arch/mips/include/asm/netlogic/mips-extns.h index f299d31d7c1a3f..de9aada6f4c1cb 100644 --- a/arch/mips/include/asm/netlogic/mips-extns.h +++ b/arch/mips/include/asm/netlogic/mips-extns.h @@ -146,7 +146,12 @@ static inline int hard_smp_processor_id(void) static inline int nlm_nodeid(void) { - return (__read_32bit_c0_register($15, 1) >> 5) & 0x3; + uint32_t prid = read_c0_prid(); + + if ((prid & 0xff00) == PRID_IMP_NETLOGIC_XLP9XX) + return (__read_32bit_c0_register($15, 1) >> 7) & 0x7; + else + return (__read_32bit_c0_register($15, 1) >> 5) & 0x3; } static inline unsigned int nlm_core_id(void) diff --git a/arch/mips/include/asm/netlogic/xlp-hal/bridge.h b/arch/mips/include/asm/netlogic/xlp-hal/bridge.h index 4e8eacb9588a2b..3067f983495d7e 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/bridge.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/bridge.h @@ -69,44 +69,9 @@ #define BRIDGE_FLASH_LIMIT3 0x13 #define BRIDGE_DRAM_BAR(i) (0x14 + (i)) -#define BRIDGE_DRAM_BAR0 0x14 -#define BRIDGE_DRAM_BAR1 0x15 -#define BRIDGE_DRAM_BAR2 0x16 -#define BRIDGE_DRAM_BAR3 0x17 -#define BRIDGE_DRAM_BAR4 0x18 -#define BRIDGE_DRAM_BAR5 0x19 -#define BRIDGE_DRAM_BAR6 0x1a -#define BRIDGE_DRAM_BAR7 0x1b - #define BRIDGE_DRAM_LIMIT(i) (0x1c + (i)) -#define BRIDGE_DRAM_LIMIT0 0x1c -#define BRIDGE_DRAM_LIMIT1 0x1d -#define BRIDGE_DRAM_LIMIT2 0x1e -#define BRIDGE_DRAM_LIMIT3 0x1f -#define BRIDGE_DRAM_LIMIT4 0x20 -#define BRIDGE_DRAM_LIMIT5 0x21 -#define BRIDGE_DRAM_LIMIT6 0x22 -#define BRIDGE_DRAM_LIMIT7 0x23 - #define BRIDGE_DRAM_NODE_TRANSLN(i) (0x24 + (i)) -#define BRIDGE_DRAM_NODE_TRANSLN0 0x24 -#define BRIDGE_DRAM_NODE_TRANSLN1 0x25 -#define BRIDGE_DRAM_NODE_TRANSLN2 0x26 -#define BRIDGE_DRAM_NODE_TRANSLN3 0x27 -#define BRIDGE_DRAM_NODE_TRANSLN4 0x28 -#define BRIDGE_DRAM_NODE_TRANSLN5 0x29 -#define BRIDGE_DRAM_NODE_TRANSLN6 0x2a -#define BRIDGE_DRAM_NODE_TRANSLN7 0x2b - #define BRIDGE_DRAM_CHNL_TRANSLN(i) (0x2c + (i)) -#define BRIDGE_DRAM_CHNL_TRANSLN0 0x2c -#define BRIDGE_DRAM_CHNL_TRANSLN1 0x2d -#define BRIDGE_DRAM_CHNL_TRANSLN2 0x2e -#define BRIDGE_DRAM_CHNL_TRANSLN3 0x2f -#define BRIDGE_DRAM_CHNL_TRANSLN4 0x30 -#define BRIDGE_DRAM_CHNL_TRANSLN5 0x31 -#define BRIDGE_DRAM_CHNL_TRANSLN6 0x32 -#define BRIDGE_DRAM_CHNL_TRANSLN7 0x33 #define BRIDGE_PCIEMEM_BASE0 0x34 #define BRIDGE_PCIEMEM_BASE1 0x35 @@ -178,12 +143,42 @@ #define BRIDGE_GIO_WEIGHT 0x2cb #define BRIDGE_FLASH_WEIGHT 0x2cc +/* FIXME verify */ +#define BRIDGE_9XX_FLASH_BAR(i) (0x11 + (i)) +#define BRIDGE_9XX_FLASH_BAR_LIMIT(i) (0x15 + (i)) + +#define BRIDGE_9XX_DRAM_BAR(i) (0x19 + (i)) +#define BRIDGE_9XX_DRAM_LIMIT(i) (0x29 + (i)) +#define BRIDGE_9XX_DRAM_NODE_TRANSLN(i) (0x39 + (i)) +#define BRIDGE_9XX_DRAM_CHNL_TRANSLN(i) (0x49 + (i)) + +#define BRIDGE_9XX_ADDRESS_ERROR0 0x9d +#define BRIDGE_9XX_ADDRESS_ERROR1 0x9e +#define BRIDGE_9XX_ADDRESS_ERROR2 0x9f + +#define BRIDGE_9XX_PCIEMEM_BASE0 0x59 +#define BRIDGE_9XX_PCIEMEM_BASE1 0x5a +#define BRIDGE_9XX_PCIEMEM_BASE2 0x5b +#define BRIDGE_9XX_PCIEMEM_BASE3 0x5c +#define BRIDGE_9XX_PCIEMEM_LIMIT0 0x5d +#define BRIDGE_9XX_PCIEMEM_LIMIT1 0x5e +#define BRIDGE_9XX_PCIEMEM_LIMIT2 0x5f +#define BRIDGE_9XX_PCIEMEM_LIMIT3 0x60 +#define BRIDGE_9XX_PCIEIO_BASE0 0x61 +#define BRIDGE_9XX_PCIEIO_BASE1 0x62 +#define BRIDGE_9XX_PCIEIO_BASE2 0x63 +#define BRIDGE_9XX_PCIEIO_BASE3 0x64 +#define BRIDGE_9XX_PCIEIO_LIMIT0 0x65 +#define BRIDGE_9XX_PCIEIO_LIMIT1 0x66 +#define BRIDGE_9XX_PCIEIO_LIMIT2 0x67 +#define BRIDGE_9XX_PCIEIO_LIMIT3 0x68 + #ifndef __ASSEMBLY__ #define nlm_read_bridge_reg(b, r) nlm_read_reg(b, r) #define nlm_write_bridge_reg(b, r, v) nlm_write_reg(b, r, v) -#define nlm_get_bridge_pcibase(node) \ - nlm_pcicfg_base(XLP_IO_BRIDGE_OFFSET(node)) +#define nlm_get_bridge_pcibase(node) nlm_pcicfg_base(cpu_is_xlp9xx() ? \ + XLP9XX_IO_BRIDGE_OFFSET(node) : XLP_IO_BRIDGE_OFFSET(node)) #define nlm_get_bridge_regbase(node) \ (nlm_get_bridge_pcibase(node) + XLP_IO_PCI_HDRSZ) diff --git a/arch/mips/include/asm/netlogic/xlp-hal/iomap.h b/arch/mips/include/asm/netlogic/xlp-hal/iomap.h index 55eee77adaca5d..1f23dfaa7167bc 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/iomap.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/iomap.h @@ -48,8 +48,10 @@ #define XLP_IO_SIZE (64 << 20) /* ECFG space size */ #define XLP_IO_PCI_HDRSZ 0x100 #define XLP_IO_DEV(node, dev) ((dev) + (node) * 8) -#define XLP_HDR_OFFSET(node, bus, dev, fn) (((bus) << 20) | \ - ((XLP_IO_DEV(node, dev)) << 15) | ((fn) << 12)) +#define XLP_IO_PCI_OFFSET(b, d, f) (((b) << 20) | ((d) << 15) | ((f) << 12)) + +#define XLP_HDR_OFFSET(node, bus, dev, fn) \ + XLP_IO_PCI_OFFSET(bus, XLP_IO_DEV(node, dev), fn) #define XLP_IO_BRIDGE_OFFSET(node) XLP_HDR_OFFSET(node, 0, 0, 0) /* coherent inter chip */ @@ -109,6 +111,36 @@ #define XLP_IO_MMC_OFFSET(node, slot) \ ((XLP_IO_SD_OFFSET(node))+(slot*0x100)+XLP_IO_PCI_HDRSZ) +/* Things have changed drastically in XLP 9XX */ +#define XLP9XX_HDR_OFFSET(n, d, f) \ + XLP_IO_PCI_OFFSET(xlp9xx_get_socbus(n), d, f) + +#define XLP9XX_IO_BRIDGE_OFFSET(node) XLP_IO_PCI_OFFSET(0, 0, node) +#define XLP9XX_IO_PIC_OFFSET(node) XLP9XX_HDR_OFFSET(node, 2, 0) +#define XLP9XX_IO_UART_OFFSET(node) XLP9XX_HDR_OFFSET(node, 2, 2) +#define XLP9XX_IO_SYS_OFFSET(node) XLP9XX_HDR_OFFSET(node, 6, 0) +#define XLP9XX_IO_FUSE_OFFSET(node) XLP9XX_HDR_OFFSET(node, 6, 1) +#define XLP9XX_IO_JTAG_OFFSET(node) XLP9XX_HDR_OFFSET(node, 6, 4) + +#define XLP9XX_IO_PCIE_OFFSET(node, i) XLP9XX_HDR_OFFSET(node, 1, i) +#define XLP9XX_IO_PCIE0_OFFSET(node) XLP9XX_HDR_OFFSET(node, 1, 0) +#define XLP9XX_IO_PCIE2_OFFSET(node) XLP9XX_HDR_OFFSET(node, 1, 2) +#define XLP9XX_IO_PCIE3_OFFSET(node) XLP9XX_HDR_OFFSET(node, 1, 3) + +/* XLP9xx USB block */ +#define XLP9XX_IO_USB_OFFSET(node, i) XLP9XX_HDR_OFFSET(node, 4, i) +#define XLP9XX_IO_USB_XHCI0_OFFSET(node) XLP9XX_HDR_OFFSET(node, 4, 1) +#define XLP9XX_IO_USB_XHCI1_OFFSET(node) XLP9XX_HDR_OFFSET(node, 4, 2) + +/* XLP9XX on-chip SATA controller */ +#define XLP9XX_IO_SATA_OFFSET(node) XLP9XX_HDR_OFFSET(node, 3, 2) + +#define XLP9XX_IO_NOR_OFFSET(node) XLP9XX_HDR_OFFSET(node, 7, 0) +#define XLP9XX_IO_NAND_OFFSET(node) XLP9XX_HDR_OFFSET(node, 7, 1) +#define XLP9XX_IO_SPI_OFFSET(node) XLP9XX_HDR_OFFSET(node, 7, 2) +/* SD flash */ +#define XLP9XX_IO_MMCSD_OFFSET(node) XLP9XX_HDR_OFFSET(node, 7, 3) + /* PCI config header register id's */ #define XLP_PCI_CFGREG0 0x00 #define XLP_PCI_CFGREG1 0x01 @@ -156,11 +188,23 @@ #define PCI_DEVICE_ID_NLM_MMC 0x1018 #define PCI_DEVICE_ID_NLM_XHCI 0x101d +#define PCI_DEVICE_ID_XLP9XX_SATA 0x901A +#define PCI_DEVICE_ID_XLP9XX_XHCI 0x901D + #ifndef __ASSEMBLY__ #define nlm_read_pci_reg(b, r) nlm_read_reg(b, r) #define nlm_write_pci_reg(b, r, v) nlm_write_reg(b, r, v) +static inline int xlp9xx_get_socbus(int node) +{ + uint64_t socbridge; + + if (node == 0) + return 1; + socbridge = nlm_pcicfg_base(XLP9XX_IO_BRIDGE_OFFSET(node)); + return (nlm_read_pci_reg(socbridge, 0x6) >> 8) & 0xff; +} #endif /* !__ASSEMBLY */ #endif /* __NLM_HAL_IOMAP_H__ */ diff --git a/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h b/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h index b559cb9f56ea78..d4deb87ad06991 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h @@ -52,25 +52,48 @@ #define PCIE_BYTE_SWAP_MEM_LIM 0x248 #define PCIE_BYTE_SWAP_IO_BASE 0x249 #define PCIE_BYTE_SWAP_IO_LIM 0x24A + +#define PCIE_BRIDGE_MSIX_ADDR_BASE 0x24F +#define PCIE_BRIDGE_MSIX_ADDR_LIMIT 0x250 #define PCIE_MSI_STATUS 0x25A #define PCIE_MSI_EN 0x25B +#define PCIE_MSIX_STATUS 0x25D +#define PCIE_INT_STATUS0 0x25F +#define PCIE_INT_STATUS1 0x260 #define PCIE_INT_EN0 0x261 +#define PCIE_INT_EN1 0x262 -/* PCIE_MSI_EN */ -#define PCIE_MSI_VECTOR_INT_EN 0xFFFFFFFF +/* XLP9XX has basic changes */ +#define PCIE_9XX_BYTE_SWAP_MEM_BASE 0x25c +#define PCIE_9XX_BYTE_SWAP_MEM_LIM 0x25d +#define PCIE_9XX_BYTE_SWAP_IO_BASE 0x25e +#define PCIE_9XX_BYTE_SWAP_IO_LIM 0x25f -/* PCIE_INT_EN0 */ -#define PCIE_MSI_INT_EN (1 << 9) +/* other */ +#define PCIE_NLINKS 4 +/* MSI addresses */ +#define MSI_ADDR_BASE 0xfffee00000ULL +#define MSI_ADDR_SZ 0x10000 +#define MSI_LINK_ADDR(n, l) (MSI_ADDR_BASE + \ + (PCIE_NLINKS * (n) + (l)) * MSI_ADDR_SZ) +#define MSIX_ADDR_BASE 0xfffef00000ULL +#define MSIX_LINK_ADDR(n, l) (MSIX_ADDR_BASE + \ + (PCIE_NLINKS * (n) + (l)) * MSI_ADDR_SZ) #ifndef __ASSEMBLY__ #define nlm_read_pcie_reg(b, r) nlm_read_reg(b, r) #define nlm_write_pcie_reg(b, r, v) nlm_write_reg(b, r, v) -#define nlm_get_pcie_base(node, inst) \ - nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, inst)) -#define nlm_get_pcie_regbase(node, inst) \ - (nlm_get_pcie_base(node, inst) + XLP_IO_PCI_HDRSZ) +#define nlm_get_pcie_base(node, inst) nlm_pcicfg_base(cpu_is_xlp9xx() ? \ + XLP9XX_IO_PCIE_OFFSET(node, inst) : XLP_IO_PCIE_OFFSET(node, inst)) + +#ifdef CONFIG_PCI_MSI +void xlp_init_node_msi_irqs(int node, int link); +#else +static inline void xlp_init_node_msi_irqs(int node, int link) {} +#endif + +struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev); -int xlp_pcie_link_irt(int link); #endif #endif /* __NLM_HAL_PCIBUS_H__ */ diff --git a/arch/mips/include/asm/netlogic/xlp-hal/pic.h b/arch/mips/include/asm/netlogic/xlp-hal/pic.h index 105389b79f0939..f10bf3bba58fc5 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/pic.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/pic.h @@ -150,12 +150,19 @@ #define PIC_IRT0 0x74 #define PIC_IRT(i) (PIC_IRT0 + ((i) * 2)) -#define TIMER_CYCLES_MAXVAL 0xffffffffffffffffULL +#define PIC_9XX_PENDING_0 0x6 +#define PIC_9XX_PENDING_1 0x8 +#define PIC_9XX_PENDING_2 0xa +#define PIC_9XX_PENDING_3 0xc + +#define PIC_9XX_IRT0 0x1c0 +#define PIC_9XX_IRT(i) (PIC_9XX_IRT0 + ((i) * 2)) /* * IRT Map */ #define PIC_NUM_IRTS 160 +#define PIC_9XX_NUM_IRTS 256 #define PIC_IRT_WD_0_INDEX 0 #define PIC_IRT_WD_1_INDEX 1 @@ -193,14 +200,9 @@ #define PIC_IRT_PCIE_LINK_INDEX(num) ((num) + PIC_IRT_PCIE_LINK_0_INDEX) #define PIC_CLOCK_TIMER 7 -#define PIC_IRQ_BASE 8 #if !defined(LOCORE) && !defined(__ASSEMBLY__) -#define PIC_IRT_FIRST_IRQ (PIC_IRQ_BASE) -#define PIC_IRT_LAST_IRQ 63 -#define PIC_IRQ_IS_IRT(irq) ((irq) >= PIC_IRT_FIRST_IRQ) - /* * Misc */ @@ -210,30 +212,26 @@ #define nlm_read_pic_reg(b, r) nlm_read_reg64(b, r) #define nlm_write_pic_reg(b, r, v) nlm_write_reg64(b, r, v) -#define nlm_get_pic_pcibase(node) nlm_pcicfg_base(XLP_IO_PIC_OFFSET(node)) +#define nlm_get_pic_pcibase(node) nlm_pcicfg_base(cpu_is_xlp9xx() ? \ + XLP9XX_IO_PIC_OFFSET(node) : XLP_IO_PIC_OFFSET(node)) #define nlm_get_pic_regbase(node) (nlm_get_pic_pcibase(node) + XLP_IO_PCI_HDRSZ) /* We use PIC on node 0 as a timer */ #define pic_timer_freq() nlm_get_pic_frequency(0) /* IRT and h/w interrupt routines */ -static inline int -nlm_pic_read_irt(uint64_t base, int irt_index) -{ - return nlm_read_pic_reg(base, PIC_IRT(irt_index)); -} - static inline void -nlm_set_irt_to_cpu(uint64_t base, int irt, int cpu) +nlm_9xx_pic_write_irt(uint64_t base, int irt_num, int en, int nmi, + int sch, int vec, int dt, int db, int cpu) { uint64_t val; - val = nlm_read_pic_reg(base, PIC_IRT(irt)); - /* clear cpuset and mask */ - val &= ~((0x7ull << 16) | 0xffff); - /* set DB, cpuset and cpumask */ - val |= (1 << 19) | ((cpu >> 4) << 16) | (1 << (cpu & 0xf)); - nlm_write_pic_reg(base, PIC_IRT(irt), val); + val = (((uint64_t)en & 0x1) << 22) | ((nmi & 0x1) << 23) | + ((0 /*mc*/) << 20) | ((vec & 0x3f) << 24) | + ((dt & 0x1) << 21) | (0 /*ptr*/ << 16) | + (cpu & 0x3ff); + + nlm_write_pic_reg(base, PIC_9XX_IRT(irt_num), val); } static inline void @@ -254,9 +252,13 @@ static inline void nlm_pic_write_irt_direct(uint64_t base, int irt_num, int en, int nmi, int sch, int vec, int cpu) { - nlm_pic_write_irt(base, irt_num, en, nmi, sch, vec, 1, - (cpu >> 4), /* thread group */ - 1 << (cpu & 0xf)); /* thread mask */ + if (cpu_is_xlp9xx()) + nlm_9xx_pic_write_irt(base, irt_num, en, nmi, sch, vec, + 1, 0, cpu); + else + nlm_pic_write_irt(base, irt_num, en, nmi, sch, vec, 1, + (cpu >> 4), /* thread group */ + 1 << (cpu & 0xf)); /* thread mask */ } static inline uint64_t @@ -298,8 +300,13 @@ nlm_pic_enable_irt(uint64_t base, int irt) { uint64_t reg; - reg = nlm_read_pic_reg(base, PIC_IRT(irt)); - nlm_write_pic_reg(base, PIC_IRT(irt), reg | (1u << 31)); + if (cpu_is_xlp9xx()) { + reg = nlm_read_pic_reg(base, PIC_9XX_IRT(irt)); + nlm_write_pic_reg(base, PIC_9XX_IRT(irt), reg | (1 << 22)); + } else { + reg = nlm_read_pic_reg(base, PIC_IRT(irt)); + nlm_write_pic_reg(base, PIC_IRT(irt), reg | (1u << 31)); + } } static inline void @@ -307,8 +314,15 @@ nlm_pic_disable_irt(uint64_t base, int irt) { uint64_t reg; - reg = nlm_read_pic_reg(base, PIC_IRT(irt)); - nlm_write_pic_reg(base, PIC_IRT(irt), reg & ~((uint64_t)1 << 31)); + if (cpu_is_xlp9xx()) { + reg = nlm_read_pic_reg(base, PIC_9XX_IRT(irt)); + reg &= ~((uint64_t)1 << 22); + nlm_write_pic_reg(base, PIC_9XX_IRT(irt), reg); + } else { + reg = nlm_read_pic_reg(base, PIC_IRT(irt)); + reg &= ~((uint64_t)1 << 31); + nlm_write_pic_reg(base, PIC_IRT(irt), reg); + } } static inline void @@ -316,8 +330,13 @@ nlm_pic_send_ipi(uint64_t base, int hwt, int irq, int nmi) { uint64_t ipi; - ipi = ((uint64_t)nmi << 31) | (irq << 20); - ipi |= ((hwt >> 4) << 16) | (1 << (hwt & 0xf)); /* cpuset and mask */ + if (cpu_is_xlp9xx()) + ipi = (nmi << 23) | (irq << 24) | + (0/*mcm*/ << 20) | (0/*ptr*/ << 16) | hwt; + else + ipi = ((uint64_t)nmi << 31) | (irq << 20) | + ((hwt >> 4) << 16) | (1 << (hwt & 0xf)); + nlm_write_pic_reg(base, PIC_IPI_CTL, ipi); } diff --git a/arch/mips/include/asm/netlogic/xlp-hal/sys.h b/arch/mips/include/asm/netlogic/xlp-hal/sys.h index fcf2833c16ca9d..d9b107ffca933c 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/sys.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/sys.h @@ -147,13 +147,29 @@ #define SYS_SYS_PLL_MEM_REQ 0x2a3 #define SYS_PLL_MEM_STAT 0x2a4 +/* Registers changed on 9XX */ +#define SYS_9XX_POWER_ON_RESET_CFG 0x00 +#define SYS_9XX_CHIP_RESET 0x01 +#define SYS_9XX_CPU_RESET 0x02 +#define SYS_9XX_CPU_NONCOHERENT_MODE 0x03 + +/* XLP 9XX fuse block registers */ +#define FUSE_9XX_DEVCFG6 0xc6 + #ifndef __ASSEMBLY__ #define nlm_read_sys_reg(b, r) nlm_read_reg(b, r) #define nlm_write_sys_reg(b, r, v) nlm_write_reg(b, r, v) -#define nlm_get_sys_pcibase(node) nlm_pcicfg_base(XLP_IO_SYS_OFFSET(node)) +#define nlm_get_sys_pcibase(node) nlm_pcicfg_base(cpu_is_xlp9xx() ? \ + XLP9XX_IO_SYS_OFFSET(node) : XLP_IO_SYS_OFFSET(node)) #define nlm_get_sys_regbase(node) (nlm_get_sys_pcibase(node) + XLP_IO_PCI_HDRSZ) +/* XLP9XX fuse block */ +#define nlm_get_fuse_pcibase(node) \ + nlm_pcicfg_base(XLP9XX_IO_FUSE_OFFSET(node)) +#define nlm_get_fuse_regbase(node) \ + (nlm_get_fuse_pcibase(node) + XLP_IO_PCI_HDRSZ) + unsigned int nlm_get_pic_frequency(int node); #endif #endif diff --git a/arch/mips/include/asm/netlogic/xlp-hal/uart.h b/arch/mips/include/asm/netlogic/xlp-hal/uart.h index 86d16e1e60720c..a6c54424dd95ca 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/uart.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/uart.h @@ -94,7 +94,8 @@ #define nlm_read_uart_reg(b, r) nlm_read_reg(b, r) #define nlm_write_uart_reg(b, r, v) nlm_write_reg(b, r, v) #define nlm_get_uart_pcibase(node, inst) \ - nlm_pcicfg_base(XLP_IO_UART_OFFSET(node, inst)) + nlm_pcicfg_base(cpu_is_xlp9xx() ? XLP9XX_IO_UART_OFFSET(node) : \ + XLP_IO_UART_OFFSET(node, inst)) #define nlm_get_uart_regbase(node, inst) \ (nlm_get_uart_pcibase(node, inst) + XLP_IO_PCI_HDRSZ) diff --git a/arch/mips/include/asm/netlogic/xlp-hal/xlp.h b/arch/mips/include/asm/netlogic/xlp-hal/xlp.h index 470f2095b34613..2b0c9599ebe595 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/xlp.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/xlp.h @@ -37,10 +37,9 @@ #define PIC_UART_0_IRQ 17 #define PIC_UART_1_IRQ 18 -#define PIC_PCIE_LINK_0_IRQ 19 -#define PIC_PCIE_LINK_1_IRQ 20 -#define PIC_PCIE_LINK_2_IRQ 21 -#define PIC_PCIE_LINK_3_IRQ 22 + +#define PIC_PCIE_LINK_LEGACY_IRQ_BASE 19 +#define PIC_PCIE_LINK_LEGACY_IRQ(i) (19 + (i)) #define PIC_EHCI_0_IRQ 23 #define PIC_EHCI_1_IRQ 24 @@ -51,6 +50,8 @@ #define PIC_2XX_XHCI_0_IRQ 23 #define PIC_2XX_XHCI_1_IRQ 24 #define PIC_2XX_XHCI_2_IRQ 25 +#define PIC_9XX_XHCI_0_IRQ 23 +#define PIC_9XX_XHCI_1_IRQ 24 #define PIC_MMC_IRQ 29 #define PIC_I2C_0_IRQ 30 @@ -58,6 +59,23 @@ #define PIC_I2C_2_IRQ 32 #define PIC_I2C_3_IRQ 33 +#define PIC_PCIE_LINK_MSI_IRQ_BASE 44 /* 44 - 47 MSI IRQ */ +#define PIC_PCIE_LINK_MSI_IRQ(i) (44 + (i)) + +/* MSI-X with second link-level dispatch */ +#define PIC_PCIE_MSIX_IRQ_BASE 48 /* 48 - 51 MSI-X IRQ */ +#define PIC_PCIE_MSIX_IRQ(i) (48 + (i)) + +#define NLM_MSIX_VEC_BASE 96 /* 96 - 127 - MSIX mapped */ +#define NLM_MSI_VEC_BASE 128 /* 128 -255 - MSI mapped */ + +#define NLM_PIC_INDIRECT_VEC_BASE 512 +#define NLM_GPIO_VEC_BASE 768 + +#define PIC_IRQ_BASE 8 +#define PIC_IRT_FIRST_IRQ PIC_IRQ_BASE +#define PIC_IRT_LAST_IRQ 63 + #ifndef __ASSEMBLY__ /* SMP support functions */ @@ -68,6 +86,9 @@ void xlp_mmu_init(void); void nlm_hal_init(void); int xlp_get_dram_map(int n, uint64_t *dram_map); +struct pci_dev; +int xlp_socdev_to_node(const struct pci_dev *dev); + /* Device tree related */ void xlp_early_init_devtree(void); void *xlp_dt_init(void *fdtp); @@ -76,8 +97,15 @@ static inline int cpu_is_xlpii(void) { int chip = read_c0_prid() & 0xff00; - return chip == PRID_IMP_NETLOGIC_XLP2XX; + return chip == PRID_IMP_NETLOGIC_XLP2XX || + chip == PRID_IMP_NETLOGIC_XLP9XX; } +static inline int cpu_is_xlp9xx(void) +{ + int chip = read_c0_prid() & 0xff00; + + return chip == PRID_IMP_NETLOGIC_XLP9XX; +} #endif /* !__ASSEMBLY__ */ #endif /* _ASM_NLM_XLP_H */ diff --git a/arch/mips/include/asm/netlogic/xlr/xlr.h b/arch/mips/include/asm/netlogic/xlr/xlr.h index c1667e0c272a4d..ceb991ca843697 100644 --- a/arch/mips/include/asm/netlogic/xlr/xlr.h +++ b/arch/mips/include/asm/netlogic/xlr/xlr.h @@ -35,11 +35,6 @@ #ifndef _ASM_NLM_XLR_H #define _ASM_NLM_XLR_H -/* Platform UART functions */ -struct uart_port; -unsigned int nlm_xlr_uart_in(struct uart_port *, int); -void nlm_xlr_uart_out(struct uart_port *, int, int); - /* SMP helpers */ void xlr_wakeup_secondary_cpus(void); diff --git a/arch/mips/include/asm/octeon/cvmx-helper-board.h b/arch/mips/include/asm/octeon/cvmx-helper-board.h index 41785dd0ddd0a0..893320375aefaf 100644 --- a/arch/mips/include/asm/octeon/cvmx-helper-board.h +++ b/arch/mips/include/asm/octeon/cvmx-helper-board.h @@ -36,6 +36,13 @@ #include +enum cvmx_helper_board_usb_clock_types { + USB_CLOCK_TYPE_REF_12, + USB_CLOCK_TYPE_REF_24, + USB_CLOCK_TYPE_REF_48, + USB_CLOCK_TYPE_CRYSTAL_12, +}; + typedef enum { set_phy_link_flags_autoneg = 0x1, set_phy_link_flags_flow_control_dont_touch = 0x0 << 1, @@ -154,4 +161,6 @@ extern int __cvmx_helper_board_interface_probe(int interface, */ extern int __cvmx_helper_board_hardware_enable(int interface); +enum cvmx_helper_board_usb_clock_types __cvmx_helper_board_usb_get_clock_type(void); + #endif /* __CVMX_HELPER_BOARD_H__ */ diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h index f6be4741f7e839..5e08bcc74897ab 100644 --- a/arch/mips/include/asm/page.h +++ b/arch/mips/include/asm/page.h @@ -11,6 +11,8 @@ #include #include +#include +#include /* * PAGE_SHIFT determines the page size @@ -33,6 +35,29 @@ #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) #define PAGE_MASK (~((1 << PAGE_SHIFT) - 1)) +/* + * This is used for calculating the real page sizes + * for FTLB or VTLB + FTLB confugrations. + */ +static inline unsigned int page_size_ftlb(unsigned int mmuextdef) +{ + switch (mmuextdef) { + case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT: + if (PAGE_SIZE == (1 << 30)) + return 5; + if (PAGE_SIZE == (1llu << 32)) + return 6; + if (PAGE_SIZE > (256 << 10)) + return 7; /* reserved */ + /* fall through */ + case MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT: + return (PAGE_SHIFT - 10) / 2; + default: + panic("Invalid FTLB configuration with Conf4_mmuextdef=%d value\n", + mmuextdef >> 14); + } +} + #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT #define HPAGE_SHIFT (PAGE_SHIFT + PAGE_SHIFT - 3) #define HPAGE_SIZE (_AC(1,UL) << HPAGE_SHIFT) diff --git a/arch/mips/include/asm/rtlx.h b/arch/mips/include/asm/rtlx.h index 90985b61dbd9a2..c1020654876e82 100644 --- a/arch/mips/include/asm/rtlx.h +++ b/arch/mips/include/asm/rtlx.h @@ -1,13 +1,18 @@ /* - * Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved. + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. * + * Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2013 Imagination Technologies Ltd. */ - #ifndef __ASM_RTLX_H_ #define __ASM_RTLX_H_ #include +#define RTLX_MODULE_NAME "rtlx" + #define LX_NODE_BASE 10 #define MIPS_CPU_RTLX_IRQ 0 @@ -15,18 +20,31 @@ #define RTLX_VERSION 2 #define RTLX_xID 0x12345600 #define RTLX_ID (RTLX_xID | RTLX_VERSION) +#define RTLX_BUFFER_SIZE 2048 #define RTLX_CHANNELS 8 #define RTLX_CHANNEL_STDIO 0 #define RTLX_CHANNEL_DBG 1 #define RTLX_CHANNEL_SYSIO 2 -extern int rtlx_open(int index, int can_sleep); -extern int rtlx_release(int index); -extern ssize_t rtlx_read(int index, void __user *buff, size_t count); -extern ssize_t rtlx_write(int index, const void __user *buffer, size_t count); -extern unsigned int rtlx_read_poll(int index, int can_sleep); -extern unsigned int rtlx_write_poll(int index); +void rtlx_starting(int vpe); +void rtlx_stopping(int vpe); + +int rtlx_open(int index, int can_sleep); +int rtlx_release(int index); +ssize_t rtlx_read(int index, void __user *buff, size_t count); +ssize_t rtlx_write(int index, const void __user *buffer, size_t count); +unsigned int rtlx_read_poll(int index, int can_sleep); +unsigned int rtlx_write_poll(int index); + +int __init rtlx_module_init(void); +void __exit rtlx_module_exit(void); + +void _interrupt_sp(void); + +extern struct vpe_notifications rtlx_notify; +extern const struct file_operations rtlx_fops; +extern void (*aprp_hook)(void); enum rtlx_state { RTLX_STATE_UNUSED = 0, @@ -35,10 +53,15 @@ enum rtlx_state { RTLX_STATE_OPENED }; -#define RTLX_BUFFER_SIZE 2048 +extern struct chan_waitqueues { + wait_queue_head_t rt_queue; + wait_queue_head_t lx_queue; + atomic_t in_open; + struct mutex mutex; +} channel_wqs[RTLX_CHANNELS]; /* each channel supports read and write. - linux (vpe0) reads lx_buffer and writes rt_buffer + linux (vpe0) reads lx_buffer and writes rt_buffer SP (vpe1) reads rt_buffer and writes lx_buffer */ struct rtlx_channel { @@ -55,11 +78,11 @@ struct rtlx_channel { char *lx_buffer; }; -struct rtlx_info { +extern struct rtlx_info { unsigned long id; enum rtlx_state state; + int ap_int_pending; /* Status of 0 or 1 for CONFIG_MIPS_CMP only */ struct rtlx_channel channel[RTLX_CHANNELS]; -}; - +} *rtlx; #endif /* __ASM_RTLX_H_ */ diff --git a/arch/mips/include/asm/switch_to.h b/arch/mips/include/asm/switch_to.h index eb0af15ac656b5..278d45a0972860 100644 --- a/arch/mips/include/asm/switch_to.h +++ b/arch/mips/include/asm/switch_to.h @@ -19,11 +19,19 @@ struct task_struct; -/* - * switch_to(n) should switch tasks to task nr n, first - * checking that n isn't the current task, in which case it does nothing. +/** + * resume - resume execution of a task + * @prev: The task previously executed. + * @next: The task to begin executing. + * @next_ti: task_thread_info(next). + * @usedfpu: Non-zero if prev's FP context should be saved. + * + * This function is used whilst scheduling to save the context of prev & load + * the context of next. Returns prev. */ -extern asmlinkage void *resume(void *last, void *next, void *next_ti, u32 __usedfpu); +extern asmlinkage struct task_struct *resume(struct task_struct *prev, + struct task_struct *next, struct thread_info *next_ti, + u32 usedfpu); extern unsigned int ll_bit; extern struct task_struct *ll_task; diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h index 81c89132c59d87..33e8dbfc1b6316 100644 --- a/arch/mips/include/asm/syscall.h +++ b/arch/mips/include/asm/syscall.h @@ -29,7 +29,7 @@ static inline long syscall_get_nr(struct task_struct *task, static inline unsigned long mips_get_syscall_arg(unsigned long *arg, struct task_struct *task, struct pt_regs *regs, unsigned int n) { - unsigned long usp = regs->regs[29]; + unsigned long usp __maybe_unused = regs->regs[29]; switch (n) { case 0: case 1: case 2: case 3: diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index 4f58ef6d0eed5c..24846f9053fe9a 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h @@ -110,11 +110,12 @@ static inline struct thread_info *current_thread_info(void) #define TIF_NOHZ 19 /* in adaptive nohz mode */ #define TIF_FIXADE 20 /* Fix address errors in software */ #define TIF_LOGADE 21 /* Log address errors to syslog */ -#define TIF_32BIT_REGS 22 /* also implies 16/32 fprs */ +#define TIF_32BIT_REGS 22 /* 32-bit general purpose registers */ #define TIF_32BIT_ADDR 23 /* 32-bit address space (o32/n32) */ #define TIF_FPUBOUND 24 /* thread bound to FPU-full CPU set */ #define TIF_LOAD_WATCH 25 /* If set, load watch registers */ #define TIF_SYSCALL_TRACEPOINT 26 /* syscall tracepoint instrumentation */ +#define TIF_32BIT_FPREGS 27 /* 32-bit floating point registers */ #define TIF_SYSCALL_TRACE 31 /* syscall trace active */ #define _TIF_SYSCALL_TRACE (1<mm) +#define UNIQUE_ENTRYHI(idx) \ + ((CKSEG0 + ((idx) << (PAGE_SHIFT + 1))) | \ + (cpu_has_tlbinv ? MIPS_ENTRYHI_EHINV : 0)) + #include #endif /* __ASM_TLB_H */ diff --git a/arch/mips/include/asm/vpe.h b/arch/mips/include/asm/vpe.h index 0880fe8809b198..7849f3978feafe 100644 --- a/arch/mips/include/asm/vpe.h +++ b/arch/mips/include/asm/vpe.h @@ -1,24 +1,95 @@ /* - * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. - * - * This program is free software; you can distribute 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 it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. * + * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2013 Imagination Technologies Ltd. */ - #ifndef _ASM_VPE_H #define _ASM_VPE_H +#include +#include +#include +#include + +#define VPE_MODULE_NAME "vpe" +#define VPE_MODULE_MINOR 1 + +/* grab the likely amount of memory we will need. */ +#ifdef CONFIG_MIPS_VPE_LOADER_TOM +#define P_SIZE (2 * 1024 * 1024) +#else +/* add an overhead to the max kmalloc size for non-striped symbols/etc */ +#define P_SIZE (256 * 1024) +#endif + +#define MAX_VPES 16 +#define VPE_PATH_MAX 256 + +static inline int aprp_cpu_index(void) +{ +#ifdef CONFIG_MIPS_CMP + return setup_max_cpus; +#else + extern int tclimit; + return tclimit; +#endif +} + +enum vpe_state { + VPE_STATE_UNUSED = 0, + VPE_STATE_INUSE, + VPE_STATE_RUNNING +}; + +enum tc_state { + TC_STATE_UNUSED = 0, + TC_STATE_INUSE, + TC_STATE_RUNNING, + TC_STATE_DYNAMIC +}; + +struct vpe { + enum vpe_state state; + + /* (device) minor associated with this vpe */ + int minor; + + /* elfloader stuff */ + void *load_addr; + unsigned long len; + char *pbuffer; + unsigned long plen; + char cwd[VPE_PATH_MAX]; + + unsigned long __start; + + /* tc's associated with this vpe */ + struct list_head tc; + + /* The list of vpe's */ + struct list_head list; + + /* shared symbol address */ + void *shared_ptr; + + /* the list of who wants to know when something major happens */ + struct list_head notify; + + unsigned int ntcs; +}; + +struct tc { + enum tc_state state; + int index; + + struct vpe *pvpe; /* parent VPE */ + struct list_head tc; /* The list of TC's with this VPE */ + struct list_head list; /* The global list of tc's */ +}; + struct vpe_notifications { void (*start)(int vpe); void (*stop)(int vpe); @@ -26,10 +97,34 @@ struct vpe_notifications { struct list_head list; }; +struct vpe_control { + spinlock_t vpe_list_lock; + struct list_head vpe_list; /* Virtual processing elements */ + spinlock_t tc_list_lock; + struct list_head tc_list; /* Thread contexts */ +}; + +extern unsigned long physical_memsize; +extern struct vpe_control vpecontrol; +extern const struct file_operations vpe_fops; + +int vpe_notify(int index, struct vpe_notifications *notify); + +void *vpe_get_shared(int index); +char *vpe_getcwd(int index); + +struct vpe *get_vpe(int minor); +struct tc *get_tc(int index); +struct vpe *alloc_vpe(int minor); +struct tc *alloc_tc(int index); +void release_vpe(struct vpe *v); -extern int vpe_notify(int index, struct vpe_notifications *notify); +void *alloc_progmem(unsigned long len); +void release_progmem(void *ptr); -extern void *vpe_get_shared(int index); -extern char *vpe_getcwd(int index); +int __weak vpe_run(struct vpe *v); +void cleanup_tc(struct tc *tc); +int __init vpe_module_init(void); +void __exit vpe_module_exit(void); #endif /* _ASM_VPE_H */ diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h index e5a676e3d3c04c..b39ba25b41ccd2 100644 --- a/arch/mips/include/uapi/asm/inst.h +++ b/arch/mips/include/uapi/asm/inst.h @@ -98,8 +98,9 @@ enum rt_op { */ enum cop_op { mfc_op = 0x00, dmfc_op = 0x01, - cfc_op = 0x02, mtc_op = 0x04, - dmtc_op = 0x05, ctc_op = 0x06, + cfc_op = 0x02, mfhc_op = 0x03, + mtc_op = 0x04, dmtc_op = 0x05, + ctc_op = 0x06, mthc_op = 0x07, bc_op = 0x08, cop_op = 0x10, copm_op = 0x18 }; @@ -397,8 +398,10 @@ enum mm_32f_73_minor_op { mm_movt1_op = 0xa5, mm_ftruncw_op = 0xac, mm_fneg1_op = 0xad, + mm_mfhc1_op = 0xc0, mm_froundl_op = 0xcc, mm_fcvtd1_op = 0xcd, + mm_mthc1_op = 0xe0, mm_froundw_op = 0xec, mm_fcvts1_op = 0xed, }; diff --git a/arch/mips/include/uapi/asm/unistd.h b/arch/mips/include/uapi/asm/unistd.h index 1dee279f96659c..d6e154a9e6a55e 100644 --- a/arch/mips/include/uapi/asm/unistd.h +++ b/arch/mips/include/uapi/asm/unistd.h @@ -369,16 +369,18 @@ #define __NR_process_vm_writev (__NR_Linux + 346) #define __NR_kcmp (__NR_Linux + 347) #define __NR_finit_module (__NR_Linux + 348) +#define __NR_sched_setattr (__NR_Linux + 349) +#define __NR_sched_getattr (__NR_Linux + 350) /* * Offset of the last Linux o32 flavoured syscall */ -#define __NR_Linux_syscalls 348 +#define __NR_Linux_syscalls 350 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ #define __NR_O32_Linux 4000 -#define __NR_O32_Linux_syscalls 348 +#define __NR_O32_Linux_syscalls 350 #if _MIPS_SIM == _MIPS_SIM_ABI64 @@ -695,16 +697,18 @@ #define __NR_kcmp (__NR_Linux + 306) #define __NR_finit_module (__NR_Linux + 307) #define __NR_getdents64 (__NR_Linux + 308) +#define __NR_sched_setattr (__NR_Linux + 309) +#define __NR_sched_getattr (__NR_Linux + 310) /* * Offset of the last Linux 64-bit flavoured syscall */ -#define __NR_Linux_syscalls 308 +#define __NR_Linux_syscalls 310 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ #define __NR_64_Linux 5000 -#define __NR_64_Linux_syscalls 308 +#define __NR_64_Linux_syscalls 310 #if _MIPS_SIM == _MIPS_SIM_NABI32 @@ -1025,15 +1029,17 @@ #define __NR_process_vm_writev (__NR_Linux + 310) #define __NR_kcmp (__NR_Linux + 311) #define __NR_finit_module (__NR_Linux + 312) +#define __NR_sched_setattr (__NR_Linux + 313) +#define __NR_sched_getattr (__NR_Linux + 314) /* * Offset of the last N32 flavoured syscall */ -#define __NR_Linux_syscalls 312 +#define __NR_Linux_syscalls 314 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */ #define __NR_N32_Linux 6000 -#define __NR_N32_Linux_syscalls 312 +#define __NR_N32_Linux_syscalls 314 #endif /* _UAPI_ASM_UNISTD_H */ diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c index 8a5ec0eedeb064..c01900e5d07886 100644 --- a/arch/mips/jz4740/board-qi_lb60.c +++ b/arch/mips/jz4740/board-qi_lb60.c @@ -427,6 +427,7 @@ static struct platform_device qi_lb60_audio_device = { static struct platform_device *jz_platform_devices[] __initdata = { &jz4740_udc_device, + &jz4740_udc_xceiv_device, &jz4740_mmc_device, &jz4740_nand_device, &qi_lb60_keypad, diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c index df65677f3d0b20..a447101cf9f114 100644 --- a/arch/mips/jz4740/platform.c +++ b/arch/mips/jz4740/platform.c @@ -14,13 +14,14 @@ */ #include -#include #include #include #include #include +#include + #include #include #include @@ -56,29 +57,35 @@ struct platform_device jz4740_usb_ohci_device = { .resource = jz4740_usb_ohci_resources, }; -/* UDC (USB gadget controller) */ -static struct resource jz4740_usb_gdt_resources[] = { - { - .start = JZ4740_UDC_BASE_ADDR, - .end = JZ4740_UDC_BASE_ADDR + 0x1000 - 1, - .flags = IORESOURCE_MEM, +/* USB Device Controller */ +struct platform_device jz4740_udc_xceiv_device = { + .name = "usb_phy_gen_xceiv", + .id = 0, +}; + +static struct resource jz4740_udc_resources[] = { + [0] = { + .start = JZ4740_UDC_BASE_ADDR, + .end = JZ4740_UDC_BASE_ADDR + 0x10000 - 1, + .flags = IORESOURCE_MEM, }, - { - .start = JZ4740_IRQ_UDC, - .end = JZ4740_IRQ_UDC, - .flags = IORESOURCE_IRQ, + [1] = { + .start = JZ4740_IRQ_UDC, + .end = JZ4740_IRQ_UDC, + .flags = IORESOURCE_IRQ, + .name = "mc", }, }; struct platform_device jz4740_udc_device = { - .name = "jz-udc", - .id = -1, - .dev = { - .dma_mask = &jz4740_udc_device.dev.coherent_dma_mask, + .name = "musb-jz4740", + .id = -1, + .dev = { + .dma_mask = &jz4740_udc_device.dev.coherent_dma_mask, .coherent_dma_mask = DMA_BIT_MASK(32), }, - .num_resources = ARRAY_SIZE(jz4740_usb_gdt_resources), - .resource = jz4740_usb_gdt_resources, + .num_resources = ARRAY_SIZE(jz4740_udc_resources), + .resource = jz4740_udc_resources, }; /* MMC/SD controller */ diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 1c1b71752c84cb..26c6175e137962 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o obj-$(CONFIG_SYNC_R4K) += sync-r4k.o +obj-$(CONFIG_DEBUG_FS) += segment.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_MODULES) += mips_ksyms.o module.o obj-$(CONFIG_MODULES_USE_ELF_RELA) += module-rela.o @@ -55,7 +56,11 @@ obj-$(CONFIG_MIPS_CMP) += smp-cmp.o obj-$(CONFIG_CPU_MIPSR2) += spram.o obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o +obj-$(CONFIG_MIPS_VPE_LOADER_CMP) += vpe-cmp.o +obj-$(CONFIG_MIPS_VPE_LOADER_MT) += vpe-mt.o obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o +obj-$(CONFIG_MIPS_VPE_APSP_API_CMP) += rtlx-cmp.o +obj-$(CONFIG_MIPS_VPE_APSP_API_MT) += rtlx-mt.o obj-$(CONFIG_I8259) += i8259.o obj-$(CONFIG_IRQ_CPU) += irq_cpu.o diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c index 202e581e609653..7faf5f2bee25d7 100644 --- a/arch/mips/kernel/binfmt_elfo32.c +++ b/arch/mips/kernel/binfmt_elfo32.c @@ -27,6 +27,18 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; typedef double elf_fpreg_t; typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; +/* + * In order to be sure that we don't attempt to execute an O32 binary which + * requires 64 bit FP (FR=1) on a system which does not support it we refuse + * to execute any binary which has bits specified by the following macro set + * in its ELF header flags. + */ +#ifdef CONFIG_MIPS_O32_FP64_SUPPORT +# define __MIPS_O32_FP64_MUST_BE_ZERO 0 +#else +# define __MIPS_O32_FP64_MUST_BE_ZERO EF_MIPS_FP64 +#endif + /* * This is used to ensure we don't load something for the wrong architecture. */ @@ -43,6 +55,8 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; __res = 0; \ if (((__h->e_flags & EF_MIPS_ABI) != 0) && \ ((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \ + __res = 0; \ + if (__h->e_flags & __MIPS_O32_FP64_MUST_BE_ZERO) \ __res = 0; \ \ __res; \ diff --git a/arch/mips/kernel/bmips_vec.S b/arch/mips/kernel/bmips_vec.S index bd79c4f9bff403..a5bf73d22fcc37 100644 --- a/arch/mips/kernel/bmips_vec.S +++ b/arch/mips/kernel/bmips_vec.S @@ -8,11 +8,11 @@ * Reset/NMI/re-entry vectors for BMIPS processors */ -#include #include #include #include +#include #include #include #include @@ -91,12 +91,18 @@ NESTED(bmips_reset_nmi_vec, PT_SIZE, sp) beqz k0, bmips_smp_entry #if defined(CONFIG_CPU_BMIPS5000) + mfc0 k0, CP0_PRID + li k1, PRID_IMP_BMIPS5000 + andi k0, 0xff00 + bne k0, k1, 1f + /* if we're not on core 0, this must be the SMP boot signal */ li k1, (3 << 25) mfc0 k0, $22 and k0, k1 bnez k0, bmips_smp_entry -#endif +1: +#endif /* CONFIG_CPU_BMIPS5000 */ #endif /* CONFIG_SMP */ /* nope, it's just a regular NMI */ @@ -139,7 +145,12 @@ bmips_smp_entry: xori k0, 0x04 mtc0 k0, CP0_CONFIG + mfc0 k0, CP0_PRID + andi k0, 0xff00 #if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380) + li k1, PRID_IMP_BMIPS43XX + bne k0, k1, 2f + /* initialize CPU1's local I-cache */ li k0, 0x80000000 li k1, 0x80010000 @@ -150,14 +161,21 @@ bmips_smp_entry: 1: cache Index_Store_Tag_I, 0(k0) addiu k0, 16 bne k0, k1, 1b -#elif defined(CONFIG_CPU_BMIPS5000) + + b 3f +2: +#endif /* CONFIG_CPU_BMIPS4350 || CONFIG_CPU_BMIPS4380 */ +#if defined(CONFIG_CPU_BMIPS5000) /* set exception vector base */ + li k1, PRID_IMP_BMIPS5000 + bne k0, k1, 3f + la k0, ebase lw k0, 0(k0) mtc0 k0, $15, 1 BARRIER -#endif - +#endif /* CONFIG_CPU_BMIPS5000 */ +3: /* jump back to kseg0 in case we need to remap the kseg1 area */ la k0, 1f jr k0 @@ -221,8 +239,18 @@ END(bmips_smp_int_vec) LEAF(bmips_enable_xks01) #if defined(CONFIG_XKS01) - + mfc0 t0, CP0_PRID + andi t2, t0, 0xff00 #if defined(CONFIG_CPU_BMIPS4380) + li t1, PRID_IMP_BMIPS43XX + bne t2, t1, 1f + + andi t0, 0xff + addiu t1, t0, -PRID_REV_BMIPS4380_HI + bgtz t1, 2f + addiu t0, -PRID_REV_BMIPS4380_LO + bltz t0, 2f + mfc0 t0, $22, 3 li t1, 0x1ff0 li t2, (1 << 12) | (1 << 9) @@ -231,7 +259,13 @@ LEAF(bmips_enable_xks01) or t0, t2 mtc0 t0, $22, 3 BARRIER -#elif defined(CONFIG_CPU_BMIPS5000) + b 2f +1: +#endif /* CONFIG_CPU_BMIPS4380 */ +#if defined(CONFIG_CPU_BMIPS5000) + li t1, PRID_IMP_BMIPS5000 + bne t2, t1, 2f + mfc0 t0, $22, 5 li t1, 0x01ff li t2, (1 << 8) | (1 << 5) @@ -240,12 +274,8 @@ LEAF(bmips_enable_xks01) or t0, t2 mtc0 t0, $22, 5 BARRIER -#else - -#error Missing XKS01 setup - -#endif - +#endif /* CONFIG_CPU_BMIPS5000 */ +2: #endif /* defined(CONFIG_XKS01) */ jr ra diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index c814287bdf5d10..530f832de02c20 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -112,7 +112,7 @@ static inline unsigned long cpu_get_fpu_id(void) unsigned long tmp, fpu_id; tmp = read_c0_status(); - __enable_fpu(); + __enable_fpu(FPU_AS_IS); fpu_id = read_32bit_cp1_register(CP1_REVISION); write_c0_status(tmp); return fpu_id; @@ -163,6 +163,25 @@ static void set_isa(struct cpuinfo_mips *c, unsigned int isa) static char unknown_isa[] = KERN_ERR \ "Unsupported ISA type, c0.config0: %d."; +static void set_ftlb_enable(struct cpuinfo_mips *c, int enable) +{ + unsigned int config6; + /* + * Config6 is implementation dependent and it's currently only + * used by proAptiv + */ + if (c->cputype == CPU_PROAPTIV) { + config6 = read_c0_config6(); + if (enable) + /* Enable FTLB */ + write_c0_config6(config6 | MIPS_CONF6_FTLBEN); + else + /* Disable FTLB */ + write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN); + back_to_back_c0_hazard(); + } +} + static inline unsigned int decode_config0(struct cpuinfo_mips *c) { unsigned int config0; @@ -170,8 +189,13 @@ static inline unsigned int decode_config0(struct cpuinfo_mips *c) config0 = read_c0_config(); - if (((config0 & MIPS_CONF_MT) >> 7) == 1) + /* + * Look for Standard TLB or Dual VTLB and FTLB + */ + if ((((config0 & MIPS_CONF_MT) >> 7) == 1) || + (((config0 & MIPS_CONF_MT) >> 7) == 4)) c->options |= MIPS_CPU_TLB; + isa = (config0 & MIPS_CONF_AT) >> 13; switch (isa) { case 0: @@ -226,8 +250,11 @@ static inline unsigned int decode_config1(struct cpuinfo_mips *c) c->options |= MIPS_CPU_FPU; c->options |= MIPS_CPU_32FPR; } - if (cpu_has_tlb) + if (cpu_has_tlb) { c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1; + c->tlbsizevtlb = c->tlbsize; + c->tlbsizeftlbsets = 0; + } return config1 & MIPS_CONF_M; } @@ -272,6 +299,8 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) c->options |= MIPS_CPU_MICROMIPS; if (config3 & MIPS_CONF3_VZ) c->ases |= MIPS_ASE_VZ; + if (config3 & MIPS_CONF3_SC) + c->options |= MIPS_CPU_SEGMENTS; return config3 & MIPS_CONF_M; } @@ -279,12 +308,51 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) static inline unsigned int decode_config4(struct cpuinfo_mips *c) { unsigned int config4; + unsigned int newcf4; + unsigned int mmuextdef; + unsigned int ftlb_page = MIPS_CONF4_FTLBPAGESIZE; config4 = read_c0_config4(); - if ((config4 & MIPS_CONF4_MMUEXTDEF) == MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT - && cpu_has_tlb) - c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40; + if (cpu_has_tlb) { + if (((config4 & MIPS_CONF4_IE) >> 29) == 2) + c->options |= MIPS_CPU_TLBINV; + mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF; + switch (mmuextdef) { + case MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT: + c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40; + c->tlbsizevtlb = c->tlbsize; + break; + case MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT: + c->tlbsizevtlb += + ((config4 & MIPS_CONF4_VTLBSIZEEXT) >> + MIPS_CONF4_VTLBSIZEEXT_SHIFT) * 0x40; + c->tlbsize = c->tlbsizevtlb; + ftlb_page = MIPS_CONF4_VFTLBPAGESIZE; + /* fall through */ + case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT: + newcf4 = (config4 & ~ftlb_page) | + (page_size_ftlb(mmuextdef) << + MIPS_CONF4_FTLBPAGESIZE_SHIFT); + write_c0_config4(newcf4); + back_to_back_c0_hazard(); + config4 = read_c0_config4(); + if (config4 != newcf4) { + pr_err("PAGE_SIZE 0x%lx is not supported by FTLB (config4=0x%x)\n", + PAGE_SIZE, config4); + /* Switch FTLB off */ + set_ftlb_enable(c, 0); + break; + } + c->tlbsizeftlbsets = 1 << + ((config4 & MIPS_CONF4_FTLBSETS) >> + MIPS_CONF4_FTLBSETS_SHIFT); + c->tlbsizeftlbways = ((config4 & MIPS_CONF4_FTLBWAYS) >> + MIPS_CONF4_FTLBWAYS_SHIFT) + 2; + c->tlbsize += c->tlbsizeftlbways * c->tlbsizeftlbsets; + break; + } + } c->kscratch_mask = (config4 >> 16) & 0xff; @@ -312,6 +380,9 @@ static void decode_configs(struct cpuinfo_mips *c) c->scache.flags = MIPS_CACHE_NOT_PRESENT; + /* Enable FTLB if present */ + set_ftlb_enable(c, 1); + ok = decode_config0(c); /* Read Config registers. */ BUG_ON(!ok); /* Arch spec violation! */ if (ok) @@ -675,7 +746,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) { - decode_configs(c); switch (c->processor_id & PRID_IMP_MASK) { case PRID_IMP_4KC: c->cputype = CPU_4KC; @@ -739,8 +809,26 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) c->cputype = CPU_74K; __cpu_name[cpu] = "MIPS 1074Kc"; break; + case PRID_IMP_INTERAPTIV_UP: + c->cputype = CPU_INTERAPTIV; + __cpu_name[cpu] = "MIPS interAptiv"; + break; + case PRID_IMP_INTERAPTIV_MP: + c->cputype = CPU_INTERAPTIV; + __cpu_name[cpu] = "MIPS interAptiv (multi)"; + break; + case PRID_IMP_PROAPTIV_UP: + c->cputype = CPU_PROAPTIV; + __cpu_name[cpu] = "MIPS proAptiv"; + break; + case PRID_IMP_PROAPTIV_MP: + c->cputype = CPU_PROAPTIV; + __cpu_name[cpu] = "MIPS proAptiv (multi)"; + break; } + decode_configs(c); + spram_config(); } @@ -943,6 +1031,7 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu) switch (c->processor_id & PRID_IMP_MASK) { case PRID_IMP_NETLOGIC_XLP2XX: + case PRID_IMP_NETLOGIC_XLP9XX: c->cputype = CPU_XLP; __cpu_name[cpu] = "Broadcom XLPII"; break; diff --git a/arch/mips/kernel/crash.c b/arch/mips/kernel/crash.c index 93aa302948d723..d21264681e97d8 100644 --- a/arch/mips/kernel/crash.c +++ b/arch/mips/kernel/crash.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index 47d7583cd67ff7..d84f6a5095023e 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -476,6 +476,7 @@ NESTED(nmi_handler, PT_SIZE, sp) BUILD_HANDLER ov ov sti silent /* #12 */ BUILD_HANDLER tr tr sti silent /* #13 */ BUILD_HANDLER fpe fpe fpe silent /* #15 */ + BUILD_HANDLER ftlb ftlb none silent /* #16 */ BUILD_HANDLER mdmx mdmx sti silent /* #22 */ #ifdef CONFIG_HARDWARE_WATCHPOINTS /* diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c index f7991d95bff9a6..3553243bf9d660 100644 --- a/arch/mips/kernel/idle.c +++ b/arch/mips/kernel/idle.c @@ -184,6 +184,8 @@ void __init check_wait(void) case CPU_24K: case CPU_34K: case CPU_1004K: + case CPU_INTERAPTIV: + case CPU_PROAPTIV: cpu_wait = r4k_wait; if (read_c0_config7() & MIPS_CONF7_WII) cpu_wait = r4k_wait_irqoff; diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 8c58d8a84bf30d..00d20974b3e7b2 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -65,26 +65,25 @@ static int show_cpuinfo(struct seq_file *m, void *v) cpu_data[n].watch_reg_masks[i]); seq_printf(m, "]\n"); } - if (cpu_has_mips_r) { - seq_printf(m, "isa\t\t\t: mips1"); - if (cpu_has_mips_2) - seq_printf(m, "%s", " mips2"); - if (cpu_has_mips_3) - seq_printf(m, "%s", " mips3"); - if (cpu_has_mips_4) - seq_printf(m, "%s", " mips4"); - if (cpu_has_mips_5) - seq_printf(m, "%s", " mips5"); - if (cpu_has_mips32r1) - seq_printf(m, "%s", " mips32r1"); - if (cpu_has_mips32r2) - seq_printf(m, "%s", " mips32r2"); - if (cpu_has_mips64r1) - seq_printf(m, "%s", " mips64r1"); - if (cpu_has_mips64r2) - seq_printf(m, "%s", " mips64r2"); - seq_printf(m, "\n"); - } + + seq_printf(m, "isa\t\t\t: mips1"); + if (cpu_has_mips_2) + seq_printf(m, "%s", " mips2"); + if (cpu_has_mips_3) + seq_printf(m, "%s", " mips3"); + if (cpu_has_mips_4) + seq_printf(m, "%s", " mips4"); + if (cpu_has_mips_5) + seq_printf(m, "%s", " mips5"); + if (cpu_has_mips32r1) + seq_printf(m, "%s", " mips32r1"); + if (cpu_has_mips32r2) + seq_printf(m, "%s", " mips32r2"); + if (cpu_has_mips64r1) + seq_printf(m, "%s", " mips64r1"); + if (cpu_has_mips64r2) + seq_printf(m, "%s", " mips64r2"); + seq_printf(m, "\n"); seq_printf(m, "ASEs implemented\t:"); if (cpu_has_mips16) seq_printf(m, "%s", " mips16"); @@ -107,7 +106,14 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "kscratch registers\t: %d\n", hweight8(cpu_data[n].kscratch_mask)); seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core); - +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) + if (cpu_has_mipsmt) { + seq_printf(m, "VPE\t\t\t: %d\n", cpu_data[n].vpe_id); +#if defined(CONFIG_MIPS_MT_SMTC) + seq_printf(m, "TC\t\t\t: %d\n", cpu_data[n].tc_id); +#endif + } +#endif sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", cpu_has_vce ? "%u" : "not available"); seq_printf(m, fmt, 'D', vced_count); diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index ddc76103e78c14..6ae540e133b2aa 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -60,15 +60,11 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) /* New thread loses kernel privileges. */ status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|ST0_FR|KU_MASK); -#ifdef CONFIG_64BIT - status |= test_thread_flag(TIF_32BIT_REGS) ? 0 : ST0_FR; -#endif status |= KU_USER; regs->cp0_status = status; clear_used_math(); clear_fpu_owner(); - if (cpu_has_dsp) - __init_dsp(); + init_dsp(); regs->cp0_epc = pc; regs->regs[29] = sp; } diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index b52e1d2b33e038..7da9b76db4d971 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -137,13 +137,13 @@ int ptrace_getfpregs(struct task_struct *child, __u32 __user *data) if (cpu_has_mipsmt) { unsigned int vpflags = dvpe(); flags = read_c0_status(); - __enable_fpu(); + __enable_fpu(FPU_AS_IS); __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp)); write_c0_status(flags); evpe(vpflags); } else { flags = read_c0_status(); - __enable_fpu(); + __enable_fpu(FPU_AS_IS); __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp)); write_c0_status(flags); } @@ -408,6 +408,7 @@ long arch_ptrace(struct task_struct *child, long request, /* Read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { struct pt_regs *regs; + fpureg_t *fregs; unsigned long tmp = 0; regs = task_pt_regs(child); @@ -418,26 +419,28 @@ long arch_ptrace(struct task_struct *child, long request, tmp = regs->regs[addr]; break; case FPR_BASE ... FPR_BASE + 31: - if (tsk_used_math(child)) { - fpureg_t *fregs = get_fpu_regs(child); + if (!tsk_used_math(child)) { + /* FP not yet used */ + tmp = -1; + break; + } + fregs = get_fpu_regs(child); #ifdef CONFIG_32BIT + if (test_thread_flag(TIF_32BIT_FPREGS)) { /* * The odd registers are actually the high * order bits of the values stored in the even * registers - unless we're using r2k_switch.S. */ if (addr & 1) - tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32); + tmp = fregs[(addr & ~1) - 32] >> 32; else - tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff); -#endif -#ifdef CONFIG_64BIT - tmp = fregs[addr - FPR_BASE]; -#endif - } else { - tmp = -1; /* FP not yet used */ + tmp = fregs[addr - 32]; + break; } +#endif + tmp = fregs[addr - FPR_BASE]; break; case PC: tmp = regs->cp0_epc; @@ -483,13 +486,13 @@ long arch_ptrace(struct task_struct *child, long request, if (cpu_has_mipsmt) { unsigned int vpflags = dvpe(); flags = read_c0_status(); - __enable_fpu(); + __enable_fpu(FPU_AS_IS); __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); write_c0_status(flags); evpe(vpflags); } else { flags = read_c0_status(); - __enable_fpu(); + __enable_fpu(FPU_AS_IS); __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); write_c0_status(flags); } @@ -554,22 +557,25 @@ long arch_ptrace(struct task_struct *child, long request, child->thread.fpu.fcr31 = 0; } #ifdef CONFIG_32BIT - /* - * The odd registers are actually the high order bits - * of the values stored in the even registers - unless - * we're using r2k_switch.S. - */ - if (addr & 1) { - fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff; - fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32; - } else { - fregs[addr - FPR_BASE] &= ~0xffffffffLL; - fregs[addr - FPR_BASE] |= data; + if (test_thread_flag(TIF_32BIT_FPREGS)) { + /* + * The odd registers are actually the high + * order bits of the values stored in the even + * registers - unless we're using r2k_switch.S. + */ + if (addr & 1) { + fregs[(addr & ~1) - FPR_BASE] &= + 0xffffffff; + fregs[(addr & ~1) - FPR_BASE] |= + ((u64)data) << 32; + } else { + fregs[addr - FPR_BASE] &= ~0xffffffffLL; + fregs[addr - FPR_BASE] |= data; + } + break; } #endif -#ifdef CONFIG_64BIT fregs[addr - FPR_BASE] = data; -#endif break; } case PC: diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index 9486055ba66031..b8aa2dd5b00bc1 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -80,6 +80,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, /* Read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { struct pt_regs *regs; + fpureg_t *fregs; unsigned int tmp; regs = task_pt_regs(child); @@ -90,21 +91,25 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, tmp = regs->regs[addr]; break; case FPR_BASE ... FPR_BASE + 31: - if (tsk_used_math(child)) { - fpureg_t *fregs = get_fpu_regs(child); - + if (!tsk_used_math(child)) { + /* FP not yet used */ + tmp = -1; + break; + } + fregs = get_fpu_regs(child); + if (test_thread_flag(TIF_32BIT_FPREGS)) { /* * The odd registers are actually the high * order bits of the values stored in the even * registers - unless we're using r2k_switch.S. */ if (addr & 1) - tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32); + tmp = fregs[(addr & ~1) - 32] >> 32; else - tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff); - } else { - tmp = -1; /* FP not yet used */ + tmp = fregs[addr - 32]; + break; } + tmp = fregs[addr - FPR_BASE]; break; case PC: tmp = regs->cp0_epc; @@ -147,13 +152,13 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, if (cpu_has_mipsmt) { unsigned int vpflags = dvpe(); flags = read_c0_status(); - __enable_fpu(); + __enable_fpu(FPU_AS_IS); __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); write_c0_status(flags); evpe(vpflags); } else { flags = read_c0_status(); - __enable_fpu(); + __enable_fpu(FPU_AS_IS); __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); write_c0_status(flags); } @@ -236,20 +241,24 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, sizeof(child->thread.fpu)); child->thread.fpu.fcr31 = 0; } - /* - * The odd registers are actually the high order bits - * of the values stored in the even registers - unless - * we're using r2k_switch.S. - */ - if (addr & 1) { - fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff; - fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32; - } else { - fregs[addr - FPR_BASE] &= ~0xffffffffLL; - /* Must cast, lest sign extension fill upper - bits! */ - fregs[addr - FPR_BASE] |= (unsigned int)data; + if (test_thread_flag(TIF_32BIT_FPREGS)) { + /* + * The odd registers are actually the high + * order bits of the values stored in the even + * registers - unless we're using r2k_switch.S. + */ + if (addr & 1) { + fregs[(addr & ~1) - FPR_BASE] &= + 0xffffffff; + fregs[(addr & ~1) - FPR_BASE] |= + ((u64)data) << 32; + } else { + fregs[addr - FPR_BASE] &= ~0xffffffffLL; + fregs[addr - FPR_BASE] |= data; + } + break; } + fregs[addr - FPR_BASE] = data; break; } case PC: diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 55ffe149dae905..253b2fb520267f 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -35,7 +35,15 @@ LEAF(_save_fp_context) cfc1 t1, fcr31 -#ifdef CONFIG_64BIT +#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2) + .set push +#ifdef CONFIG_MIPS32_R2 + .set mips64r2 + mfc0 t0, CP0_STATUS + sll t0, t0, 5 + bgez t0, 1f # skip storing odd if FR=0 + nop +#endif /* Store the 16 odd double precision registers */ EX sdc1 $f1, SC_FPREGS+8(a0) EX sdc1 $f3, SC_FPREGS+24(a0) @@ -53,6 +61,7 @@ LEAF(_save_fp_context) EX sdc1 $f27, SC_FPREGS+216(a0) EX sdc1 $f29, SC_FPREGS+232(a0) EX sdc1 $f31, SC_FPREGS+248(a0) +1: .set pop #endif /* Store the 16 even double precision registers */ @@ -82,7 +91,31 @@ LEAF(_save_fp_context) LEAF(_save_fp_context32) cfc1 t1, fcr31 - EX sdc1 $f0, SC32_FPREGS+0(a0) + mfc0 t0, CP0_STATUS + sll t0, t0, 5 + bgez t0, 1f # skip storing odd if FR=0 + nop + + /* Store the 16 odd double precision registers */ + EX sdc1 $f1, SC32_FPREGS+8(a0) + EX sdc1 $f3, SC32_FPREGS+24(a0) + EX sdc1 $f5, SC32_FPREGS+40(a0) + EX sdc1 $f7, SC32_FPREGS+56(a0) + EX sdc1 $f9, SC32_FPREGS+72(a0) + EX sdc1 $f11, SC32_FPREGS+88(a0) + EX sdc1 $f13, SC32_FPREGS+104(a0) + EX sdc1 $f15, SC32_FPREGS+120(a0) + EX sdc1 $f17, SC32_FPREGS+136(a0) + EX sdc1 $f19, SC32_FPREGS+152(a0) + EX sdc1 $f21, SC32_FPREGS+168(a0) + EX sdc1 $f23, SC32_FPREGS+184(a0) + EX sdc1 $f25, SC32_FPREGS+200(a0) + EX sdc1 $f27, SC32_FPREGS+216(a0) + EX sdc1 $f29, SC32_FPREGS+232(a0) + EX sdc1 $f31, SC32_FPREGS+248(a0) + + /* Store the 16 even double precision registers */ +1: EX sdc1 $f0, SC32_FPREGS+0(a0) EX sdc1 $f2, SC32_FPREGS+16(a0) EX sdc1 $f4, SC32_FPREGS+32(a0) EX sdc1 $f6, SC32_FPREGS+48(a0) @@ -114,7 +147,16 @@ LEAF(_save_fp_context32) */ LEAF(_restore_fp_context) EX lw t0, SC_FPC_CSR(a0) -#ifdef CONFIG_64BIT + +#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2) + .set push +#ifdef CONFIG_MIPS32_R2 + .set mips64r2 + mfc0 t0, CP0_STATUS + sll t0, t0, 5 + bgez t0, 1f # skip loading odd if FR=0 + nop +#endif EX ldc1 $f1, SC_FPREGS+8(a0) EX ldc1 $f3, SC_FPREGS+24(a0) EX ldc1 $f5, SC_FPREGS+40(a0) @@ -131,6 +173,7 @@ LEAF(_restore_fp_context) EX ldc1 $f27, SC_FPREGS+216(a0) EX ldc1 $f29, SC_FPREGS+232(a0) EX ldc1 $f31, SC_FPREGS+248(a0) +1: .set pop #endif EX ldc1 $f0, SC_FPREGS+0(a0) EX ldc1 $f2, SC_FPREGS+16(a0) @@ -157,7 +200,30 @@ LEAF(_restore_fp_context) LEAF(_restore_fp_context32) /* Restore an o32 sigcontext. */ EX lw t0, SC32_FPC_CSR(a0) - EX ldc1 $f0, SC32_FPREGS+0(a0) + + mfc0 t0, CP0_STATUS + sll t0, t0, 5 + bgez t0, 1f # skip loading odd if FR=0 + nop + + EX ldc1 $f1, SC32_FPREGS+8(a0) + EX ldc1 $f3, SC32_FPREGS+24(a0) + EX ldc1 $f5, SC32_FPREGS+40(a0) + EX ldc1 $f7, SC32_FPREGS+56(a0) + EX ldc1 $f9, SC32_FPREGS+72(a0) + EX ldc1 $f11, SC32_FPREGS+88(a0) + EX ldc1 $f13, SC32_FPREGS+104(a0) + EX ldc1 $f15, SC32_FPREGS+120(a0) + EX ldc1 $f17, SC32_FPREGS+136(a0) + EX ldc1 $f19, SC32_FPREGS+152(a0) + EX ldc1 $f21, SC32_FPREGS+168(a0) + EX ldc1 $f23, SC32_FPREGS+184(a0) + EX ldc1 $f25, SC32_FPREGS+200(a0) + EX ldc1 $f27, SC32_FPREGS+216(a0) + EX ldc1 $f29, SC32_FPREGS+232(a0) + EX ldc1 $f31, SC32_FPREGS+248(a0) + +1: EX ldc1 $f0, SC32_FPREGS+0(a0) EX ldc1 $f2, SC32_FPREGS+16(a0) EX ldc1 $f4, SC32_FPREGS+32(a0) EX ldc1 $f6, SC32_FPREGS+48(a0) diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index 078de5eaca8fd9..cc78dd9a17c788 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -123,7 +123,7 @@ * Save a thread's fp context. */ LEAF(_save_fp) -#ifdef CONFIG_64BIT +#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) mfc0 t0, CP0_STATUS #endif fpu_save_double a0 t0 t1 # clobbers t1 @@ -134,7 +134,7 @@ LEAF(_save_fp) * Restore a thread's fp context. */ LEAF(_restore_fp) -#ifdef CONFIG_64BIT +#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) mfc0 t0, CP0_STATUS #endif fpu_restore_double a0 t0 t1 # clobbers t1 @@ -228,6 +228,47 @@ LEAF(_init_fpu) mtc1 t1, $f29 mtc1 t1, $f30 mtc1 t1, $f31 + +#ifdef CONFIG_CPU_MIPS32_R2 + .set push + .set mips64r2 + sll t0, t0, 5 # is Status.FR set? + bgez t0, 1f # no: skip setting upper 32b + + mthc1 t1, $f0 + mthc1 t1, $f1 + mthc1 t1, $f2 + mthc1 t1, $f3 + mthc1 t1, $f4 + mthc1 t1, $f5 + mthc1 t1, $f6 + mthc1 t1, $f7 + mthc1 t1, $f8 + mthc1 t1, $f9 + mthc1 t1, $f10 + mthc1 t1, $f11 + mthc1 t1, $f12 + mthc1 t1, $f13 + mthc1 t1, $f14 + mthc1 t1, $f15 + mthc1 t1, $f16 + mthc1 t1, $f17 + mthc1 t1, $f18 + mthc1 t1, $f19 + mthc1 t1, $f20 + mthc1 t1, $f21 + mthc1 t1, $f22 + mthc1 t1, $f23 + mthc1 t1, $f24 + mthc1 t1, $f25 + mthc1 t1, $f26 + mthc1 t1, $f27 + mthc1 t1, $f28 + mthc1 t1, $f29 + mthc1 t1, $f30 + mthc1 t1, $f31 +1: .set pop +#endif /* CONFIG_CPU_MIPS32_R2 */ #else .set mips3 dmtc1 t1, $f0 diff --git a/arch/mips/kernel/rtlx-cmp.c b/arch/mips/kernel/rtlx-cmp.c new file mode 100644 index 00000000000000..56dc6963515314 --- /dev/null +++ b/arch/mips/kernel/rtlx-cmp.c @@ -0,0 +1,116 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2013 Imagination Technologies Ltd. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static int major; + +static void rtlx_interrupt(void) +{ + int i; + struct rtlx_info *info; + struct rtlx_info **p = vpe_get_shared(aprp_cpu_index()); + + if (p == NULL || *p == NULL) + return; + + info = *p; + + if (info->ap_int_pending == 1 && smp_processor_id() == 0) { + for (i = 0; i < RTLX_CHANNELS; i++) { + wake_up(&channel_wqs[i].lx_queue); + wake_up(&channel_wqs[i].rt_queue); + } + info->ap_int_pending = 0; + } +} + +void _interrupt_sp(void) +{ + smp_send_reschedule(aprp_cpu_index()); +} + +int __init rtlx_module_init(void) +{ + struct device *dev; + int i, err; + + if (!cpu_has_mipsmt) { + pr_warn("VPE loader: not a MIPS MT capable processor\n"); + return -ENODEV; + } + + if (num_possible_cpus() - aprp_cpu_index() < 1) { + pr_warn("No TCs reserved for AP/SP, not initializing RTLX.\n" + "Pass maxcpus= argument as kernel argument\n"); + + return -ENODEV; + } + + major = register_chrdev(0, RTLX_MODULE_NAME, &rtlx_fops); + if (major < 0) { + pr_err("rtlx_module_init: unable to register device\n"); + return major; + } + + /* initialise the wait queues */ + for (i = 0; i < RTLX_CHANNELS; i++) { + init_waitqueue_head(&channel_wqs[i].rt_queue); + init_waitqueue_head(&channel_wqs[i].lx_queue); + atomic_set(&channel_wqs[i].in_open, 0); + mutex_init(&channel_wqs[i].mutex); + + dev = device_create(mt_class, NULL, MKDEV(major, i), NULL, + "%s%d", RTLX_MODULE_NAME, i); + if (IS_ERR(dev)) { + err = PTR_ERR(dev); + goto out_chrdev; + } + } + + /* set up notifiers */ + rtlx_notify.start = rtlx_starting; + rtlx_notify.stop = rtlx_stopping; + vpe_notify(aprp_cpu_index(), &rtlx_notify); + + if (cpu_has_vint) { + aprp_hook = rtlx_interrupt; + } else { + pr_err("APRP RTLX init on non-vectored-interrupt processor\n"); + err = -ENODEV; + goto out_class; + } + + return 0; + +out_class: + for (i = 0; i < RTLX_CHANNELS; i++) + device_destroy(mt_class, MKDEV(major, i)); +out_chrdev: + unregister_chrdev(major, RTLX_MODULE_NAME); + + return err; +} + +void __exit rtlx_module_exit(void) +{ + int i; + + for (i = 0; i < RTLX_CHANNELS; i++) + device_destroy(mt_class, MKDEV(major, i)); + unregister_chrdev(major, RTLX_MODULE_NAME); +} diff --git a/arch/mips/kernel/rtlx-mt.c b/arch/mips/kernel/rtlx-mt.c new file mode 100644 index 00000000000000..91d61ba422b467 --- /dev/null +++ b/arch/mips/kernel/rtlx-mt.c @@ -0,0 +1,148 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2013 Imagination Technologies Ltd. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static int major; + +static void rtlx_dispatch(void) +{ + if (read_c0_cause() & read_c0_status() & C_SW0) + do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ); +} + +/* + * Interrupt handler may be called before rtlx_init has otherwise had + * a chance to run. + */ +static irqreturn_t rtlx_interrupt(int irq, void *dev_id) +{ + unsigned int vpeflags; + unsigned long flags; + int i; + + /* Ought not to be strictly necessary for SMTC builds */ + local_irq_save(flags); + vpeflags = dvpe(); + set_c0_status(0x100 << MIPS_CPU_RTLX_IRQ); + irq_enable_hazard(); + evpe(vpeflags); + local_irq_restore(flags); + + for (i = 0; i < RTLX_CHANNELS; i++) { + wake_up(&channel_wqs[i].lx_queue); + wake_up(&channel_wqs[i].rt_queue); + } + + return IRQ_HANDLED; +} + +static struct irqaction rtlx_irq = { + .handler = rtlx_interrupt, + .name = "RTLX", +}; + +static int rtlx_irq_num = MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ; + +void _interrupt_sp(void) +{ + unsigned long flags; + + local_irq_save(flags); + dvpe(); + settc(1); + write_vpe_c0_cause(read_vpe_c0_cause() | C_SW0); + evpe(EVPE_ENABLE); + local_irq_restore(flags); +} + +int __init rtlx_module_init(void) +{ + struct device *dev; + int i, err; + + if (!cpu_has_mipsmt) { + pr_warn("VPE loader: not a MIPS MT capable processor\n"); + return -ENODEV; + } + + if (aprp_cpu_index() == 0) { + pr_warn("No TCs reserved for AP/SP, not initializing RTLX.\n" + "Pass maxtcs= argument as kernel argument\n"); + + return -ENODEV; + } + + major = register_chrdev(0, RTLX_MODULE_NAME, &rtlx_fops); + if (major < 0) { + pr_err("rtlx_module_init: unable to register device\n"); + return major; + } + + /* initialise the wait queues */ + for (i = 0; i < RTLX_CHANNELS; i++) { + init_waitqueue_head(&channel_wqs[i].rt_queue); + init_waitqueue_head(&channel_wqs[i].lx_queue); + atomic_set(&channel_wqs[i].in_open, 0); + mutex_init(&channel_wqs[i].mutex); + + dev = device_create(mt_class, NULL, MKDEV(major, i), NULL, + "%s%d", RTLX_MODULE_NAME, i); + if (IS_ERR(dev)) { + err = PTR_ERR(dev); + goto out_chrdev; + } + } + + /* set up notifiers */ + rtlx_notify.start = rtlx_starting; + rtlx_notify.stop = rtlx_stopping; + vpe_notify(aprp_cpu_index(), &rtlx_notify); + + if (cpu_has_vint) { + aprp_hook = rtlx_dispatch; + } else { + pr_err("APRP RTLX init on non-vectored-interrupt processor\n"); + err = -ENODEV; + goto out_class; + } + + rtlx_irq.dev_id = rtlx; + err = setup_irq(rtlx_irq_num, &rtlx_irq); + if (err) + goto out_class; + + return 0; + +out_class: + for (i = 0; i < RTLX_CHANNELS; i++) + device_destroy(mt_class, MKDEV(major, i)); +out_chrdev: + unregister_chrdev(major, RTLX_MODULE_NAME); + + return err; +} + +void __exit rtlx_module_exit(void) +{ + int i; + + for (i = 0; i < RTLX_CHANNELS; i++) + device_destroy(mt_class, MKDEV(major, i)); + unregister_chrdev(major, RTLX_MODULE_NAME); +} diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index 2c12ea1668d13d..31b1b763cb2988 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c @@ -1,114 +1,51 @@ /* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. * Copyright (C) 2005, 06 Ralf Baechle (ralf@linux-mips.org) - * - * This program is free software; you can distribute 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 it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * + * Copyright (C) 2013 Imagination Technologies Ltd. */ - -#include #include #include -#include -#include -#include -#include -#include -#include #include #include -#include -#include -#include -#include +#include #include #include -#include -#include -#include #include -#include #include #include +#include -static struct rtlx_info *rtlx; -static int major; -static char module_name[] = "rtlx"; - -static struct chan_waitqueues { - wait_queue_head_t rt_queue; - wait_queue_head_t lx_queue; - atomic_t in_open; - struct mutex mutex; -} channel_wqs[RTLX_CHANNELS]; - -static struct vpe_notifications notify; static int sp_stopping; - -extern void *vpe_get_shared(int index); - -static void rtlx_dispatch(void) -{ - do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ); -} - - -/* Interrupt handler may be called before rtlx_init has otherwise had - a chance to run. -*/ -static irqreturn_t rtlx_interrupt(int irq, void *dev_id) -{ - unsigned int vpeflags; - unsigned long flags; - int i; - - /* Ought not to be strictly necessary for SMTC builds */ - local_irq_save(flags); - vpeflags = dvpe(); - set_c0_status(0x100 << MIPS_CPU_RTLX_IRQ); - irq_enable_hazard(); - evpe(vpeflags); - local_irq_restore(flags); - - for (i = 0; i < RTLX_CHANNELS; i++) { - wake_up(&channel_wqs[i].lx_queue); - wake_up(&channel_wqs[i].rt_queue); - } - - return IRQ_HANDLED; -} +struct rtlx_info *rtlx; +struct chan_waitqueues channel_wqs[RTLX_CHANNELS]; +struct vpe_notifications rtlx_notify; +void (*aprp_hook)(void) = NULL; +EXPORT_SYMBOL(aprp_hook); static void __used dump_rtlx(void) { int i; - printk("id 0x%lx state %d\n", rtlx->id, rtlx->state); + pr_info("id 0x%lx state %d\n", rtlx->id, rtlx->state); for (i = 0; i < RTLX_CHANNELS; i++) { struct rtlx_channel *chan = &rtlx->channel[i]; - printk(" rt_state %d lx_state %d buffer_size %d\n", - chan->rt_state, chan->lx_state, chan->buffer_size); + pr_info(" rt_state %d lx_state %d buffer_size %d\n", + chan->rt_state, chan->lx_state, chan->buffer_size); - printk(" rt_read %d rt_write %d\n", - chan->rt_read, chan->rt_write); + pr_info(" rt_read %d rt_write %d\n", + chan->rt_read, chan->rt_write); - printk(" lx_read %d lx_write %d\n", - chan->lx_read, chan->lx_write); + pr_info(" lx_read %d lx_write %d\n", + chan->lx_read, chan->lx_write); - printk(" rt_buffer <%s>\n", chan->rt_buffer); - printk(" lx_buffer <%s>\n", chan->lx_buffer); + pr_info(" rt_buffer <%s>\n", chan->rt_buffer); + pr_info(" lx_buffer <%s>\n", chan->lx_buffer); } } @@ -116,8 +53,7 @@ static void __used dump_rtlx(void) static int rtlx_init(struct rtlx_info *rtlxi) { if (rtlxi->id != RTLX_ID) { - printk(KERN_ERR "no valid RTLX id at 0x%p 0x%lx\n", - rtlxi, rtlxi->id); + pr_err("no valid RTLX id at 0x%p 0x%lx\n", rtlxi, rtlxi->id); return -ENOEXEC; } @@ -127,20 +63,20 @@ static int rtlx_init(struct rtlx_info *rtlxi) } /* notifications */ -static void starting(int vpe) +void rtlx_starting(int vpe) { int i; sp_stopping = 0; /* force a reload of rtlx */ - rtlx=NULL; + rtlx = NULL; /* wake up any sleeping rtlx_open's */ for (i = 0; i < RTLX_CHANNELS; i++) wake_up_interruptible(&channel_wqs[i].lx_queue); } -static void stopping(int vpe) +void rtlx_stopping(int vpe) { int i; @@ -158,31 +94,30 @@ int rtlx_open(int index, int can_sleep) int ret = 0; if (index >= RTLX_CHANNELS) { - printk(KERN_DEBUG "rtlx_open index out of range\n"); + pr_debug(KERN_DEBUG "rtlx_open index out of range\n"); return -ENOSYS; } if (atomic_inc_return(&channel_wqs[index].in_open) > 1) { - printk(KERN_DEBUG "rtlx_open channel %d already opened\n", - index); + pr_debug(KERN_DEBUG "rtlx_open channel %d already opened\n", index); ret = -EBUSY; goto out_fail; } if (rtlx == NULL) { - if( (p = vpe_get_shared(tclimit)) == NULL) { - if (can_sleep) { - ret = __wait_event_interruptible( + p = vpe_get_shared(aprp_cpu_index()); + if (p == NULL) { + if (can_sleep) { + ret = __wait_event_interruptible( channel_wqs[index].lx_queue, - (p = vpe_get_shared(tclimit))); - if (ret) + (p = vpe_get_shared(aprp_cpu_index()))); + if (ret) + goto out_fail; + } else { + pr_debug("No SP program loaded, and device opened with O_NONBLOCK\n"); + ret = -ENOSYS; goto out_fail; - } else { - printk(KERN_DEBUG "No SP program loaded, and device " - "opened with O_NONBLOCK\n"); - ret = -ENOSYS; - goto out_fail; - } + } } smp_rmb(); @@ -204,24 +139,24 @@ int rtlx_open(int index, int can_sleep) ret = -ERESTARTSYS; goto out_fail; } - finish_wait(&channel_wqs[index].lx_queue, &wait); + finish_wait(&channel_wqs[index].lx_queue, + &wait); } else { - pr_err(" *vpe_get_shared is NULL. " - "Has an SP program been loaded?\n"); + pr_err(" *vpe_get_shared is NULL. Has an SP program been loaded?\n"); ret = -ENOSYS; goto out_fail; } } if ((unsigned int)*p < KSEG0) { - printk(KERN_WARNING "vpe_get_shared returned an " - "invalid pointer maybe an error code %d\n", - (int)*p); + pr_warn("vpe_get_shared returned an invalid pointer maybe an error code %d\n", + (int)*p); ret = -ENOSYS; goto out_fail; } - if ((ret = rtlx_init(*p)) < 0) + ret = rtlx_init(*p); + if (ret < 0) goto out_ret; } @@ -352,7 +287,7 @@ ssize_t rtlx_write(int index, const void __user *buffer, size_t count) size_t fl; if (rtlx == NULL) - return(-ENOSYS); + return -ENOSYS; rt = &rtlx->channel[index]; @@ -361,8 +296,8 @@ ssize_t rtlx_write(int index, const void __user *buffer, size_t count) rt_read = rt->rt_read; /* total number of bytes to copy */ - count = min(count, (size_t)write_spacefree(rt_read, rt->rt_write, - rt->buffer_size)); + count = min_t(size_t, count, write_spacefree(rt_read, rt->rt_write, + rt->buffer_size)); /* first bit from write pointer to the end of the buffer, or count */ fl = min(count, (size_t) rt->buffer_size - rt->rt_write); @@ -372,9 +307,8 @@ ssize_t rtlx_write(int index, const void __user *buffer, size_t count) goto out; /* if there's any left copy to the beginning of the buffer */ - if (count - fl) { + if (count - fl) failed = copy_from_user(rt->rt_buffer, buffer + fl, count - fl); - } out: count -= failed; @@ -384,6 +318,8 @@ ssize_t rtlx_write(int index, const void __user *buffer, size_t count) smp_wmb(); mutex_unlock(&channel_wqs[index].mutex); + _interrupt_sp(); + return count; } @@ -398,7 +334,7 @@ static int file_release(struct inode *inode, struct file *filp) return rtlx_release(iminor(inode)); } -static unsigned int file_poll(struct file *file, poll_table * wait) +static unsigned int file_poll(struct file *file, poll_table *wait) { int minor = iminor(file_inode(file)); unsigned int mask = 0; @@ -420,21 +356,20 @@ static unsigned int file_poll(struct file *file, poll_table * wait) return mask; } -static ssize_t file_read(struct file *file, char __user * buffer, size_t count, - loff_t * ppos) +static ssize_t file_read(struct file *file, char __user *buffer, size_t count, + loff_t *ppos) { int minor = iminor(file_inode(file)); /* data available? */ - if (!rtlx_read_poll(minor, (file->f_flags & O_NONBLOCK) ? 0 : 1)) { - return 0; // -EAGAIN makes cat whinge - } + if (!rtlx_read_poll(minor, (file->f_flags & O_NONBLOCK) ? 0 : 1)) + return 0; /* -EAGAIN makes 'cat' whine */ return rtlx_read(minor, buffer, count); } -static ssize_t file_write(struct file *file, const char __user * buffer, - size_t count, loff_t * ppos) +static ssize_t file_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) { int minor = iminor(file_inode(file)); @@ -454,100 +389,16 @@ static ssize_t file_write(struct file *file, const char __user * buffer, return rtlx_write(minor, buffer, count); } -static const struct file_operations rtlx_fops = { +const struct file_operations rtlx_fops = { .owner = THIS_MODULE, - .open = file_open, + .open = file_open, .release = file_release, .write = file_write, - .read = file_read, - .poll = file_poll, + .read = file_read, + .poll = file_poll, .llseek = noop_llseek, }; -static struct irqaction rtlx_irq = { - .handler = rtlx_interrupt, - .name = "RTLX", -}; - -static int rtlx_irq_num = MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ; - -static char register_chrdev_failed[] __initdata = - KERN_ERR "rtlx_module_init: unable to register device\n"; - -static int __init rtlx_module_init(void) -{ - struct device *dev; - int i, err; - - if (!cpu_has_mipsmt) { - printk("VPE loader: not a MIPS MT capable processor\n"); - return -ENODEV; - } - - if (tclimit == 0) { - printk(KERN_WARNING "No TCs reserved for AP/SP, not " - "initializing RTLX.\nPass maxtcs= argument as kernel " - "argument\n"); - - return -ENODEV; - } - - major = register_chrdev(0, module_name, &rtlx_fops); - if (major < 0) { - printk(register_chrdev_failed); - return major; - } - - /* initialise the wait queues */ - for (i = 0; i < RTLX_CHANNELS; i++) { - init_waitqueue_head(&channel_wqs[i].rt_queue); - init_waitqueue_head(&channel_wqs[i].lx_queue); - atomic_set(&channel_wqs[i].in_open, 0); - mutex_init(&channel_wqs[i].mutex); - - dev = device_create(mt_class, NULL, MKDEV(major, i), NULL, - "%s%d", module_name, i); - if (IS_ERR(dev)) { - err = PTR_ERR(dev); - goto out_chrdev; - } - } - - /* set up notifiers */ - notify.start = starting; - notify.stop = stopping; - vpe_notify(tclimit, ¬ify); - - if (cpu_has_vint) - set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch); - else { - pr_err("APRP RTLX init on non-vectored-interrupt processor\n"); - err = -ENODEV; - goto out_chrdev; - } - - rtlx_irq.dev_id = rtlx; - setup_irq(rtlx_irq_num, &rtlx_irq); - - return 0; - -out_chrdev: - for (i = 0; i < RTLX_CHANNELS; i++) - device_destroy(mt_class, MKDEV(major, i)); - - return err; -} - -static void __exit rtlx_module_exit(void) -{ - int i; - - for (i = 0; i < RTLX_CHANNELS; i++) - device_destroy(mt_class, MKDEV(major, i)); - - unregister_chrdev(major, module_name); -} - module_init(rtlx_module_init); module_exit(rtlx_module_exit); diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index e8e541b40d86be..a5b14f48e1af80 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -563,3 +563,5 @@ EXPORT(sys_call_table) PTR sys_process_vm_writev PTR sys_kcmp PTR sys_finit_module + PTR sys_sched_setattr + PTR sys_sched_getattr /* 4350 */ diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 57e3742fec59a1..b56e254beb15b6 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -425,4 +425,6 @@ EXPORT(sys_call_table) PTR sys_kcmp PTR sys_finit_module PTR sys_getdents64 + PTR sys_sched_setattr + PTR sys_sched_getattr /* 5310 */ .size sys_call_table,.-sys_call_table diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 2f48f5934399e3..f7e5b72cf48125 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -418,4 +418,6 @@ EXPORT(sysn32_call_table) PTR compat_sys_process_vm_writev /* 6310 */ PTR sys_kcmp PTR sys_finit_module + PTR sys_sched_setattr + PTR sys_sched_getattr .size sysn32_call_table,.-sysn32_call_table diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index f1acdb429f4fa1..6788727d91af1f 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -541,4 +541,6 @@ EXPORT(sys32_call_table) PTR compat_sys_process_vm_writev PTR sys_kcmp PTR sys_finit_module + PTR sys_sched_setattr + PTR sys_sched_getattr /* 4350 */ .size sys32_call_table,.-sys32_call_table diff --git a/arch/mips/kernel/segment.c b/arch/mips/kernel/segment.c new file mode 100644 index 00000000000000..076ead2a985948 --- /dev/null +++ b/arch/mips/kernel/segment.c @@ -0,0 +1,110 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2013 Imagination Technologies Ltd. + */ + +#include +#include +#include +#include +#include + +static void build_segment_config(char *str, unsigned int cfg) +{ + unsigned int am; + static const char * const am_str[] = { + "UK", "MK", "MSK", "MUSK", "MUSUK", "USK", + "RSRVD", "UUSK"}; + + /* Segment access mode. */ + am = (cfg & MIPS_SEGCFG_AM) >> MIPS_SEGCFG_AM_SHIFT; + str += sprintf(str, "%-5s", am_str[am]); + + /* + * Access modes MK, MSK and MUSK are mapped segments. Therefore + * there is no direct physical address mapping. + */ + if ((am == 0) || (am > 3)) { + str += sprintf(str, " %03lx", + ((cfg & MIPS_SEGCFG_PA) >> MIPS_SEGCFG_PA_SHIFT)); + str += sprintf(str, " %01ld", + ((cfg & MIPS_SEGCFG_C) >> MIPS_SEGCFG_C_SHIFT)); + } else { + str += sprintf(str, " UND"); + str += sprintf(str, " U"); + } + + /* Exception configuration. */ + str += sprintf(str, " %01ld\n", + ((cfg & MIPS_SEGCFG_EU) >> MIPS_SEGCFG_EU_SHIFT)); +} + +static int show_segments(struct seq_file *m, void *v) +{ + unsigned int segcfg; + char str[42]; + + seq_puts(m, "Segment Virtual Size Access Mode Physical Caching EU\n"); + seq_puts(m, "------- ------- ---- ----------- -------- ------- --\n"); + + segcfg = read_c0_segctl0(); + build_segment_config(str, segcfg); + seq_printf(m, " 0 e0000000 512M %s", str); + + segcfg >>= 16; + build_segment_config(str, segcfg); + seq_printf(m, " 1 c0000000 512M %s", str); + + segcfg = read_c0_segctl1(); + build_segment_config(str, segcfg); + seq_printf(m, " 2 a0000000 512M %s", str); + + segcfg >>= 16; + build_segment_config(str, segcfg); + seq_printf(m, " 3 80000000 512M %s", str); + + segcfg = read_c0_segctl2(); + build_segment_config(str, segcfg); + seq_printf(m, " 4 40000000 1G %s", str); + + segcfg >>= 16; + build_segment_config(str, segcfg); + seq_printf(m, " 5 00000000 1G %s\n", str); + + return 0; +} + +static int segments_open(struct inode *inode, struct file *file) +{ + return single_open(file, show_segments, NULL); +} + +static const struct file_operations segments_fops = { + .open = segments_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init segments_info(void) +{ + extern struct dentry *mips_debugfs_dir; + struct dentry *segments; + + if (cpu_has_segments) { + if (!mips_debugfs_dir) + return -ENODEV; + + segments = debugfs_create_file("segments", S_IRUGO, + mips_debugfs_dir, NULL, + &segments_fops); + if (!segments) + return -ENOMEM; + } + return 0; +} + +device_initcall(segments_info); diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 2f285abc76d5b9..5199563c4403a5 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -71,8 +71,9 @@ static int protected_save_fp_context(struct sigcontext __user *sc) int err; while (1) { lock_fpu_owner(); - own_fpu_inatomic(1); - err = save_fp_context(sc); /* this might fail */ + err = own_fpu_inatomic(1); + if (!err) + err = save_fp_context(sc); /* this might fail */ unlock_fpu_owner(); if (likely(!err)) break; @@ -91,8 +92,9 @@ static int protected_restore_fp_context(struct sigcontext __user *sc) int err, tmp __maybe_unused; while (1) { lock_fpu_owner(); - own_fpu_inatomic(0); - err = restore_fp_context(sc); /* this might fail */ + err = own_fpu_inatomic(0); + if (!err) + err = restore_fp_context(sc); /* this might fail */ unlock_fpu_owner(); if (likely(!err)) break; diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 1905a419aa46f9..3d60f7750fa8d8 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -85,8 +85,9 @@ static int protected_save_fp_context32(struct sigcontext32 __user *sc) int err; while (1) { lock_fpu_owner(); - own_fpu_inatomic(1); - err = save_fp_context32(sc); /* this might fail */ + err = own_fpu_inatomic(1); + if (!err) + err = save_fp_context32(sc); /* this might fail */ unlock_fpu_owner(); if (likely(!err)) break; @@ -105,8 +106,9 @@ static int protected_restore_fp_context32(struct sigcontext32 __user *sc) int err, tmp __maybe_unused; while (1) { lock_fpu_owner(); - own_fpu_inatomic(0); - err = restore_fp_context32(sc); /* this might fail */ + err = own_fpu_inatomic(0); + if (!err) + err = restore_fp_context32(sc); /* this might fail */ unlock_fpu_owner(); if (likely(!err)) break; diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index 2362665ba4965f..ea4c2dc3169274 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -49,8 +49,10 @@ cpumask_t bmips_booted_mask; unsigned long bmips_smp_boot_sp; unsigned long bmips_smp_boot_gp; -static void bmips_send_ipi_single(int cpu, unsigned int action); -static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id); +static void bmips43xx_send_ipi_single(int cpu, unsigned int action); +static void bmips5000_send_ipi_single(int cpu, unsigned int action); +static irqreturn_t bmips43xx_ipi_interrupt(int irq, void *dev_id); +static irqreturn_t bmips5000_ipi_interrupt(int irq, void *dev_id); /* SW interrupts 0,1 are used for interprocessor signaling */ #define IPI0_IRQ (MIPS_CPU_IRQ_BASE + 0) @@ -64,49 +66,58 @@ static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id); static void __init bmips_smp_setup(void) { int i, cpu = 1, boot_cpu = 0; - -#if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380) int cpu_hw_intr; - /* arbitration priority */ - clear_c0_brcm_cmt_ctrl(0x30); - - /* NBK and weak order flags */ - set_c0_brcm_config_0(0x30000); - - /* Find out if we are running on TP0 or TP1 */ - boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31)); - - /* - * MIPS interrupts 0,1 (SW INT 0,1) cross over to the other thread - * MIPS interrupt 2 (HW INT 0) is the CPU0 L1 controller output - * MIPS interrupt 3 (HW INT 1) is the CPU1 L1 controller output - */ - if (boot_cpu == 0) - cpu_hw_intr = 0x02; - else - cpu_hw_intr = 0x1d; - - change_c0_brcm_cmt_intr(0xf8018000, (cpu_hw_intr << 27) | (0x03 << 15)); - - /* single core, 2 threads (2 pipelines) */ - max_cpus = 2; -#elif defined(CONFIG_CPU_BMIPS5000) - /* enable raceless SW interrupts */ - set_c0_brcm_config(0x03 << 22); - - /* route HW interrupt 0 to CPU0, HW interrupt 1 to CPU1 */ - change_c0_brcm_mode(0x1f << 27, 0x02 << 27); - - /* N cores, 2 threads per core */ - max_cpus = (((read_c0_brcm_config() >> 6) & 0x03) + 1) << 1; + switch (current_cpu_type()) { + case CPU_BMIPS4350: + case CPU_BMIPS4380: + /* arbitration priority */ + clear_c0_brcm_cmt_ctrl(0x30); + + /* NBK and weak order flags */ + set_c0_brcm_config_0(0x30000); + + /* Find out if we are running on TP0 or TP1 */ + boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31)); + + /* + * MIPS interrupts 0,1 (SW INT 0,1) cross over to the other + * thread + * MIPS interrupt 2 (HW INT 0) is the CPU0 L1 controller output + * MIPS interrupt 3 (HW INT 1) is the CPU1 L1 controller output + */ + if (boot_cpu == 0) + cpu_hw_intr = 0x02; + else + cpu_hw_intr = 0x1d; + + change_c0_brcm_cmt_intr(0xf8018000, + (cpu_hw_intr << 27) | (0x03 << 15)); + + /* single core, 2 threads (2 pipelines) */ + max_cpus = 2; + + break; + case CPU_BMIPS5000: + /* enable raceless SW interrupts */ + set_c0_brcm_config(0x03 << 22); + + /* route HW interrupt 0 to CPU0, HW interrupt 1 to CPU1 */ + change_c0_brcm_mode(0x1f << 27, 0x02 << 27); + + /* N cores, 2 threads per core */ + max_cpus = (((read_c0_brcm_config() >> 6) & 0x03) + 1) << 1; + + /* clear any pending SW interrupts */ + for (i = 0; i < max_cpus; i++) { + write_c0_brcm_action(ACTION_CLR_IPI(i, 0)); + write_c0_brcm_action(ACTION_CLR_IPI(i, 1)); + } - /* clear any pending SW interrupts */ - for (i = 0; i < max_cpus; i++) { - write_c0_brcm_action(ACTION_CLR_IPI(i, 0)); - write_c0_brcm_action(ACTION_CLR_IPI(i, 1)); + break; + default: + max_cpus = 1; } -#endif if (!bmips_smp_enabled) max_cpus = 1; @@ -134,6 +145,20 @@ static void __init bmips_smp_setup(void) */ static void bmips_prepare_cpus(unsigned int max_cpus) { + irqreturn_t (*bmips_ipi_interrupt)(int irq, void *dev_id); + + switch (current_cpu_type()) { + case CPU_BMIPS4350: + case CPU_BMIPS4380: + bmips_ipi_interrupt = bmips43xx_ipi_interrupt; + break; + case CPU_BMIPS5000: + bmips_ipi_interrupt = bmips5000_ipi_interrupt; + break; + default: + return; + } + if (request_irq(IPI0_IRQ, bmips_ipi_interrupt, IRQF_PERCPU, "smp_ipi0", NULL)) panic("Can't request IPI0 interrupt"); @@ -168,26 +193,39 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle) pr_info("SMP: Booting CPU%d...\n", cpu); - if (cpumask_test_cpu(cpu, &bmips_booted_mask)) - bmips_send_ipi_single(cpu, 0); + if (cpumask_test_cpu(cpu, &bmips_booted_mask)) { + switch (current_cpu_type()) { + case CPU_BMIPS4350: + case CPU_BMIPS4380: + bmips43xx_send_ipi_single(cpu, 0); + break; + case CPU_BMIPS5000: + bmips5000_send_ipi_single(cpu, 0); + break; + } + } else { -#if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380) - /* Reset slave TP1 if booting from TP0 */ - if (cpu_logical_map(cpu) == 1) - set_c0_brcm_cmt_ctrl(0x01); -#elif defined(CONFIG_CPU_BMIPS5000) - if (cpu & 0x01) - write_c0_brcm_action(ACTION_BOOT_THREAD(cpu)); - else { - /* - * core N thread 0 was already booted; just - * pulse the NMI line - */ - bmips_write_zscm_reg(0x210, 0xc0000000); - udelay(10); - bmips_write_zscm_reg(0x210, 0x00); + switch (current_cpu_type()) { + case CPU_BMIPS4350: + case CPU_BMIPS4380: + /* Reset slave TP1 if booting from TP0 */ + if (cpu_logical_map(cpu) == 1) + set_c0_brcm_cmt_ctrl(0x01); + break; + case CPU_BMIPS5000: + if (cpu & 0x01) + write_c0_brcm_action(ACTION_BOOT_THREAD(cpu)); + else { + /* + * core N thread 0 was already booted; just + * pulse the NMI line + */ + bmips_write_zscm_reg(0x210, 0xc0000000); + udelay(10); + bmips_write_zscm_reg(0x210, 0x00); + } + break; } -#endif cpumask_set_cpu(cpu, &bmips_booted_mask); } } @@ -199,26 +237,32 @@ static void bmips_init_secondary(void) { /* move NMI vector to kseg0, in case XKS01 is enabled */ -#if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380) - void __iomem *cbr = BMIPS_GET_CBR(); + void __iomem *cbr; unsigned long old_vec; unsigned long relo_vector; int boot_cpu; - boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31)); - relo_vector = boot_cpu ? BMIPS_RELO_VECTOR_CONTROL_0 : - BMIPS_RELO_VECTOR_CONTROL_1; + switch (current_cpu_type()) { + case CPU_BMIPS4350: + case CPU_BMIPS4380: + cbr = BMIPS_GET_CBR(); - old_vec = __raw_readl(cbr + relo_vector); - __raw_writel(old_vec & ~0x20000000, cbr + relo_vector); + boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31)); + relo_vector = boot_cpu ? BMIPS_RELO_VECTOR_CONTROL_0 : + BMIPS_RELO_VECTOR_CONTROL_1; - clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0); -#elif defined(CONFIG_CPU_BMIPS5000) - write_c0_brcm_bootvec(read_c0_brcm_bootvec() & - (smp_processor_id() & 0x01 ? ~0x20000000 : ~0x2000)); + old_vec = __raw_readl(cbr + relo_vector); + __raw_writel(old_vec & ~0x20000000, cbr + relo_vector); - write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0)); -#endif + clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0); + break; + case CPU_BMIPS5000: + write_c0_brcm_bootvec(read_c0_brcm_bootvec() & + (smp_processor_id() & 0x01 ? ~0x20000000 : ~0x2000)); + + write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0)); + break; + } } /* @@ -243,8 +287,6 @@ static void bmips_cpus_done(void) { } -#if defined(CONFIG_CPU_BMIPS5000) - /* * BMIPS5000 raceless IPIs * @@ -253,12 +295,12 @@ static void bmips_cpus_done(void) * IPI1 is used for SMP_CALL_FUNCTION */ -static void bmips_send_ipi_single(int cpu, unsigned int action) +static void bmips5000_send_ipi_single(int cpu, unsigned int action) { write_c0_brcm_action(ACTION_SET_IPI(cpu, action == SMP_CALL_FUNCTION)); } -static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id) +static irqreturn_t bmips5000_ipi_interrupt(int irq, void *dev_id) { int action = irq - IPI0_IRQ; @@ -272,7 +314,14 @@ static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -#else +static void bmips5000_send_ipi_mask(const struct cpumask *mask, + unsigned int action) +{ + unsigned int i; + + for_each_cpu(i, mask) + bmips5000_send_ipi_single(i, action); +} /* * BMIPS43xx racey IPIs @@ -287,7 +336,7 @@ static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id) static DEFINE_SPINLOCK(ipi_lock); static DEFINE_PER_CPU(int, ipi_action_mask); -static void bmips_send_ipi_single(int cpu, unsigned int action) +static void bmips43xx_send_ipi_single(int cpu, unsigned int action) { unsigned long flags; @@ -298,7 +347,7 @@ static void bmips_send_ipi_single(int cpu, unsigned int action) spin_unlock_irqrestore(&ipi_lock, flags); } -static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id) +static irqreturn_t bmips43xx_ipi_interrupt(int irq, void *dev_id) { unsigned long flags; int action, cpu = irq - IPI0_IRQ; @@ -317,15 +366,13 @@ static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -#endif /* BMIPS type */ - -static void bmips_send_ipi_mask(const struct cpumask *mask, +static void bmips43xx_send_ipi_mask(const struct cpumask *mask, unsigned int action) { unsigned int i; for_each_cpu(i, mask) - bmips_send_ipi_single(i, action); + bmips43xx_send_ipi_single(i, action); } #ifdef CONFIG_HOTPLUG_CPU @@ -381,15 +428,30 @@ void __ref play_dead(void) #endif /* CONFIG_HOTPLUG_CPU */ -struct plat_smp_ops bmips_smp_ops = { +struct plat_smp_ops bmips43xx_smp_ops = { + .smp_setup = bmips_smp_setup, + .prepare_cpus = bmips_prepare_cpus, + .boot_secondary = bmips_boot_secondary, + .smp_finish = bmips_smp_finish, + .init_secondary = bmips_init_secondary, + .cpus_done = bmips_cpus_done, + .send_ipi_single = bmips43xx_send_ipi_single, + .send_ipi_mask = bmips43xx_send_ipi_mask, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_disable = bmips_cpu_disable, + .cpu_die = bmips_cpu_die, +#endif +}; + +struct plat_smp_ops bmips5000_smp_ops = { .smp_setup = bmips_smp_setup, .prepare_cpus = bmips_prepare_cpus, .boot_secondary = bmips_boot_secondary, .smp_finish = bmips_smp_finish, .init_secondary = bmips_init_secondary, .cpus_done = bmips_cpus_done, - .send_ipi_single = bmips_send_ipi_single, - .send_ipi_mask = bmips_send_ipi_mask, + .send_ipi_single = bmips5000_send_ipi_single, + .send_ipi_mask = bmips5000_send_ipi_mask, #ifdef CONFIG_HOTPLUG_CPU .cpu_disable = bmips_cpu_disable, .cpu_die = bmips_cpu_die, @@ -427,43 +489,47 @@ void bmips_ebase_setup(void) BUG_ON(ebase != CKSEG0); -#if defined(CONFIG_CPU_BMIPS4350) - /* - * BMIPS4350 cannot relocate the normal vectors, but it - * can relocate the BEV=1 vectors. So CPU1 starts up at - * the relocated BEV=1, IV=0 general exception vector @ - * 0xa000_0380. - * - * set_uncached_handler() is used here because: - * - CPU1 will run this from uncached space - * - None of the cacheflush functions are set up yet - */ - set_uncached_handler(BMIPS_WARM_RESTART_VEC - CKSEG0, - &bmips_smp_int_vec, 0x80); - __sync(); - return; -#elif defined(CONFIG_CPU_BMIPS4380) - /* - * 0x8000_0000: reset/NMI (initially in kseg1) - * 0x8000_0400: normal vectors - */ - new_ebase = 0x80000400; - cbr = BMIPS_GET_CBR(); - __raw_writel(0x80080800, cbr + BMIPS_RELO_VECTOR_CONTROL_0); - __raw_writel(0xa0080800, cbr + BMIPS_RELO_VECTOR_CONTROL_1); -#elif defined(CONFIG_CPU_BMIPS5000) - /* - * 0x8000_0000: reset/NMI (initially in kseg1) - * 0x8000_1000: normal vectors - */ - new_ebase = 0x80001000; - write_c0_brcm_bootvec(0xa0088008); - write_c0_ebase(new_ebase); - if (max_cpus > 2) - bmips_write_zscm_reg(0xa0, 0xa008a008); -#else - return; -#endif + switch (current_cpu_type()) { + case CPU_BMIPS4350: + /* + * BMIPS4350 cannot relocate the normal vectors, but it + * can relocate the BEV=1 vectors. So CPU1 starts up at + * the relocated BEV=1, IV=0 general exception vector @ + * 0xa000_0380. + * + * set_uncached_handler() is used here because: + * - CPU1 will run this from uncached space + * - None of the cacheflush functions are set up yet + */ + set_uncached_handler(BMIPS_WARM_RESTART_VEC - CKSEG0, + &bmips_smp_int_vec, 0x80); + __sync(); + return; + case CPU_BMIPS4380: + /* + * 0x8000_0000: reset/NMI (initially in kseg1) + * 0x8000_0400: normal vectors + */ + new_ebase = 0x80000400; + cbr = BMIPS_GET_CBR(); + __raw_writel(0x80080800, cbr + BMIPS_RELO_VECTOR_CONTROL_0); + __raw_writel(0xa0080800, cbr + BMIPS_RELO_VECTOR_CONTROL_1); + break; + case CPU_BMIPS5000: + /* + * 0x8000_0000: reset/NMI (initially in kseg1) + * 0x8000_1000: normal vectors + */ + new_ebase = 0x80001000; + write_c0_brcm_bootvec(0xa0088008); + write_c0_ebase(new_ebase); + if (max_cpus > 2) + bmips_write_zscm_reg(0xa0, 0xa008a008); + break; + default: + return; + } + board_nmi_handler_setup = &bmips_nmi_handler_setup; ebase = new_ebase; } diff --git a/arch/mips/kernel/smp-cmp.c b/arch/mips/kernel/smp-cmp.c index 5969f1e9b62a5c..1b925d8a610cdc 100644 --- a/arch/mips/kernel/smp-cmp.c +++ b/arch/mips/kernel/smp-cmp.c @@ -199,11 +199,14 @@ void __init cmp_prepare_cpus(unsigned int max_cpus) pr_debug("SMPCMP: CPU%d: %s max_cpus=%d\n", smp_processor_id(), __func__, max_cpus); +#ifdef CONFIG_MIPS_MT /* * FIXME: some of these options are per-system, some per-core and * some per-cpu */ mips_mt_set_cpuoptions(); +#endif + } struct plat_smp_ops cmp_smp_ops = { diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index 57a3f7a2b370c1..0fb8cefc9114b2 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c @@ -71,6 +71,7 @@ static unsigned int __init smvp_vpe_init(unsigned int tc, unsigned int mvpconf0, /* Record this as available CPU */ set_cpu_possible(tc, true); + set_cpu_present(tc, true); __cpu_number_map[tc] = ++ncpu; __cpu_logical_map[ncpu] = tc; } @@ -112,12 +113,39 @@ static void __init smvp_tc_init(unsigned int tc, unsigned int mvpconf0) write_tc_c0_tchalt(TCHALT_H); } +#ifdef CONFIG_IRQ_GIC +static void mp_send_ipi_single(int cpu, unsigned int action) +{ + unsigned long flags; + + local_irq_save(flags); + + switch (action) { + case SMP_CALL_FUNCTION: + gic_send_ipi(plat_ipi_call_int_xlate(cpu)); + break; + + case SMP_RESCHEDULE_YOURSELF: + gic_send_ipi(plat_ipi_resched_int_xlate(cpu)); + break; + } + + local_irq_restore(flags); +} +#endif + static void vsmp_send_ipi_single(int cpu, unsigned int action) { int i; unsigned long flags; int vpflags; +#ifdef CONFIG_IRQ_GIC + if (gic_present) { + mp_send_ipi_single(cpu, action); + return; + } +#endif local_irq_save(flags); vpflags = dvpe(); /* can't access the other CPU's registers whilst MVPE enabled */ diff --git a/arch/mips/kernel/spram.c b/arch/mips/kernel/spram.c index 93f86817f20a64..b242e2c10ea0b6 100644 --- a/arch/mips/kernel/spram.c +++ b/arch/mips/kernel/spram.c @@ -8,7 +8,6 @@ * * Copyright (C) 2007, 2008 MIPS Technologies, Inc. */ -#include #include #include #include @@ -206,6 +205,8 @@ void spram_config(void) case CPU_34K: case CPU_74K: case CPU_1004K: + case CPU_INTERAPTIV: + case CPU_PROAPTIV: config0 = read_c0_config(); /* FIXME: addresses are Malta specific */ if (config0 & (1<<24)) { diff --git a/arch/mips/kernel/sync-r4k.c b/arch/mips/kernel/sync-r4k.c index 84536bf4a15403..c24ad5f4b32459 100644 --- a/arch/mips/kernel/sync-r4k.c +++ b/arch/mips/kernel/sync-r4k.c @@ -11,7 +11,6 @@ */ #include -#include #include #include diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index f9c8746be8d66d..e0b499694d180a 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -78,6 +78,7 @@ extern asmlinkage void handle_cpu(void); extern asmlinkage void handle_ov(void); extern asmlinkage void handle_tr(void); extern asmlinkage void handle_fpe(void); +extern asmlinkage void handle_ftlb(void); extern asmlinkage void handle_mdmx(void); extern asmlinkage void handle_watch(void); extern asmlinkage void handle_mt(void); @@ -1080,7 +1081,7 @@ asmlinkage void do_cpu(struct pt_regs *regs) unsigned long old_epc, old31; unsigned int opcode; unsigned int cpid; - int status; + int status, err; unsigned long __maybe_unused flags; prev_state = exception_enter(); @@ -1153,19 +1154,19 @@ asmlinkage void do_cpu(struct pt_regs *regs) case 1: if (used_math()) /* Using the FPU again. */ - own_fpu(1); + err = own_fpu(1); else { /* First time FPU user. */ - init_fpu(); + err = init_fpu(); set_used_math(); } - if (!raw_cpu_has_fpu) { + if (!raw_cpu_has_fpu || err) { int sig; void __user *fault_addr = NULL; sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 0, &fault_addr); - if (!process_fpemu_return(sig, fault_addr)) + if (!process_fpemu_return(sig, fault_addr) && !err) mt_ase_fp_affinity(); } @@ -1336,6 +1337,8 @@ static inline void parity_protection_init(void) case CPU_34K: case CPU_74K: case CPU_1004K: + case CPU_INTERAPTIV: + case CPU_PROAPTIV: { #define ERRCTL_PE 0x80000000 #define ERRCTL_L2P 0x00800000 @@ -1425,14 +1428,27 @@ asmlinkage void cache_parity_error(void) printk("Decoded c0_cacheerr: %s cache fault in %s reference.\n", reg_val & (1<<30) ? "secondary" : "primary", reg_val & (1<<31) ? "data" : "insn"); - printk("Error bits: %s%s%s%s%s%s%s\n", - reg_val & (1<<29) ? "ED " : "", - reg_val & (1<<28) ? "ET " : "", - reg_val & (1<<26) ? "EE " : "", - reg_val & (1<<25) ? "EB " : "", - reg_val & (1<<24) ? "EI " : "", - reg_val & (1<<23) ? "E1 " : "", - reg_val & (1<<22) ? "E0 " : ""); + if (cpu_has_mips_r2 && + ((current_cpu_data.processor_id && 0xff0000) == PRID_COMP_MIPS)) { + pr_err("Error bits: %s%s%s%s%s%s%s%s\n", + reg_val & (1<<29) ? "ED " : "", + reg_val & (1<<28) ? "ET " : "", + reg_val & (1<<27) ? "ES " : "", + reg_val & (1<<26) ? "EE " : "", + reg_val & (1<<25) ? "EB " : "", + reg_val & (1<<24) ? "EI " : "", + reg_val & (1<<23) ? "E1 " : "", + reg_val & (1<<22) ? "E0 " : ""); + } else { + pr_err("Error bits: %s%s%s%s%s%s%s\n", + reg_val & (1<<29) ? "ED " : "", + reg_val & (1<<28) ? "ET " : "", + reg_val & (1<<26) ? "EE " : "", + reg_val & (1<<25) ? "EB " : "", + reg_val & (1<<24) ? "EI " : "", + reg_val & (1<<23) ? "E1 " : "", + reg_val & (1<<22) ? "E0 " : ""); + } printk("IDX: 0x%08x\n", reg_val & ((1<<22)-1)); #if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) @@ -1446,6 +1462,34 @@ asmlinkage void cache_parity_error(void) panic("Can't handle the cache error!"); } +asmlinkage void do_ftlb(void) +{ + const int field = 2 * sizeof(unsigned long); + unsigned int reg_val; + + /* For the moment, report the problem and hang. */ + if (cpu_has_mips_r2 && + ((current_cpu_data.processor_id && 0xff0000) == PRID_COMP_MIPS)) { + pr_err("FTLB error exception, cp0_ecc=0x%08x:\n", + read_c0_ecc()); + pr_err("cp0_errorepc == %0*lx\n", field, read_c0_errorepc()); + reg_val = read_c0_cacheerr(); + pr_err("c0_cacheerr == %08x\n", reg_val); + + if ((reg_val & 0xc0000000) == 0xc0000000) { + pr_err("Decoded c0_cacheerr: FTLB parity error\n"); + } else { + pr_err("Decoded c0_cacheerr: %s cache fault in %s reference.\n", + reg_val & (1<<30) ? "secondary" : "primary", + reg_val & (1<<31) ? "data" : "insn"); + } + } else { + pr_err("FTLB error exception\n"); + } + /* Just print the cacheerr bits for now */ + cache_parity_error(); +} + /* * SDBBP EJTAG debug exception handler. * We skip the instruction and return to the next instruction. @@ -1995,6 +2039,7 @@ void __init trap_init(void) if (cpu_has_fpu && !cpu_has_nofpuex) set_except_vector(15, handle_fpe); + set_except_vector(16, handle_ftlb); set_except_vector(22, handle_mdmx); if (cpu_has_mcheck) diff --git a/arch/mips/kernel/vpe-cmp.c b/arch/mips/kernel/vpe-cmp.c new file mode 100644 index 00000000000000..9268ebc0f61e6e --- /dev/null +++ b/arch/mips/kernel/vpe-cmp.c @@ -0,0 +1,180 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2013 Imagination Technologies Ltd. + */ +#include +#include +#include +#include +#include + +#include + +static int major; + +void cleanup_tc(struct tc *tc) +{ + +} + +static ssize_t store_kill(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) +{ + struct vpe *vpe = get_vpe(aprp_cpu_index()); + struct vpe_notifications *notifier; + + list_for_each_entry(notifier, &vpe->notify, list) + notifier->stop(aprp_cpu_index()); + + release_progmem(vpe->load_addr); + vpe->state = VPE_STATE_UNUSED; + + return len; +} +static DEVICE_ATTR(kill, S_IWUSR, NULL, store_kill); + +static ssize_t ntcs_show(struct device *cd, struct device_attribute *attr, + char *buf) +{ + struct vpe *vpe = get_vpe(aprp_cpu_index()); + + return sprintf(buf, "%d\n", vpe->ntcs); +} + +static ssize_t ntcs_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) +{ + struct vpe *vpe = get_vpe(aprp_cpu_index()); + unsigned long new; + int ret; + + ret = kstrtoul(buf, 0, &new); + if (ret < 0) + return ret; + + /* APRP can only reserve one TC in a VPE and no more. */ + if (new != 1) + return -EINVAL; + + vpe->ntcs = new; + + return len; +} +static DEVICE_ATTR_RW(ntcs); + +static struct attribute *vpe_attrs[] = { + &dev_attr_kill.attr, + &dev_attr_ntcs.attr, + NULL, +}; +ATTRIBUTE_GROUPS(vpe); + +static void vpe_device_release(struct device *cd) +{ + kfree(cd); +} + +static struct class vpe_class = { + .name = "vpe", + .owner = THIS_MODULE, + .dev_release = vpe_device_release, + .dev_groups = vpe_groups, +}; + +static struct device vpe_device; + +int __init vpe_module_init(void) +{ + struct vpe *v = NULL; + struct tc *t; + int err; + + if (!cpu_has_mipsmt) { + pr_warn("VPE loader: not a MIPS MT capable processor\n"); + return -ENODEV; + } + + if (num_possible_cpus() - aprp_cpu_index() < 1) { + pr_warn("No VPEs reserved for AP/SP, not initialize VPE loader\n" + "Pass maxcpus= argument as kernel argument\n"); + return -ENODEV; + } + + major = register_chrdev(0, VPE_MODULE_NAME, &vpe_fops); + if (major < 0) { + pr_warn("VPE loader: unable to register character device\n"); + return major; + } + + err = class_register(&vpe_class); + if (err) { + pr_err("vpe_class registration failed\n"); + goto out_chrdev; + } + + device_initialize(&vpe_device); + vpe_device.class = &vpe_class, + vpe_device.parent = NULL, + dev_set_name(&vpe_device, "vpe_sp"); + vpe_device.devt = MKDEV(major, VPE_MODULE_MINOR); + err = device_add(&vpe_device); + if (err) { + pr_err("Adding vpe_device failed\n"); + goto out_class; + } + + t = alloc_tc(aprp_cpu_index()); + if (!t) { + pr_warn("VPE: unable to allocate TC\n"); + err = -ENOMEM; + goto out_dev; + } + + /* VPE */ + v = alloc_vpe(aprp_cpu_index()); + if (v == NULL) { + pr_warn("VPE: unable to allocate VPE\n"); + kfree(t); + err = -ENOMEM; + goto out_dev; + } + + v->ntcs = 1; + + /* add the tc to the list of this vpe's tc's. */ + list_add(&t->tc, &v->tc); + + /* TC */ + t->pvpe = v; /* set the parent vpe */ + + return 0; + +out_dev: + device_del(&vpe_device); + +out_class: + class_unregister(&vpe_class); + +out_chrdev: + unregister_chrdev(major, VPE_MODULE_NAME); + + return err; +} + +void __exit vpe_module_exit(void) +{ + struct vpe *v, *n; + + device_del(&vpe_device); + class_unregister(&vpe_class); + unregister_chrdev(major, VPE_MODULE_NAME); + + /* No locking needed here */ + list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) + if (v->state != VPE_STATE_UNUSED) + release_vpe(v); +} diff --git a/arch/mips/kernel/vpe-mt.c b/arch/mips/kernel/vpe-mt.c new file mode 100644 index 00000000000000..949ae0e1701816 --- /dev/null +++ b/arch/mips/kernel/vpe-mt.c @@ -0,0 +1,523 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2013 Imagination Technologies Ltd. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static int major; + +/* The number of TCs and VPEs physically available on the core */ +static int hw_tcs, hw_vpes; + +/* We are prepared so configure and start the VPE... */ +int vpe_run(struct vpe *v) +{ + unsigned long flags, val, dmt_flag; + struct vpe_notifications *notifier; + unsigned int vpeflags; + struct tc *t; + + /* check we are the Master VPE */ + local_irq_save(flags); + val = read_c0_vpeconf0(); + if (!(val & VPECONF0_MVP)) { + pr_warn("VPE loader: only Master VPE's are able to config MT\n"); + local_irq_restore(flags); + + return -1; + } + + dmt_flag = dmt(); + vpeflags = dvpe(); + + if (list_empty(&v->tc)) { + evpe(vpeflags); + emt(dmt_flag); + local_irq_restore(flags); + + pr_warn("VPE loader: No TC's associated with VPE %d\n", + v->minor); + + return -ENOEXEC; + } + + t = list_first_entry(&v->tc, struct tc, tc); + + /* Put MVPE's into 'configuration state' */ + set_c0_mvpcontrol(MVPCONTROL_VPC); + + settc(t->index); + + /* should check it is halted, and not activated */ + if ((read_tc_c0_tcstatus() & TCSTATUS_A) || + !(read_tc_c0_tchalt() & TCHALT_H)) { + evpe(vpeflags); + emt(dmt_flag); + local_irq_restore(flags); + + pr_warn("VPE loader: TC %d is already active!\n", + t->index); + + return -ENOEXEC; + } + + /* + * Write the address we want it to start running from in the TCPC + * register. + */ + write_tc_c0_tcrestart((unsigned long)v->__start); + write_tc_c0_tccontext((unsigned long)0); + + /* + * Mark the TC as activated, not interrupt exempt and not dynamically + * allocatable + */ + val = read_tc_c0_tcstatus(); + val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A; + write_tc_c0_tcstatus(val); + + write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H); + + /* + * The sde-kit passes 'memsize' to __start in $a3, so set something + * here... Or set $a3 to zero and define DFLT_STACK_SIZE and + * DFLT_HEAP_SIZE when you compile your program + */ + mttgpr(6, v->ntcs); + mttgpr(7, physical_memsize); + + /* set up VPE1 */ + /* + * bind the TC to VPE 1 as late as possible so we only have the final + * VPE registers to set up, and so an EJTAG probe can trigger on it + */ + write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1); + + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA)); + + back_to_back_c0_hazard(); + + /* Set up the XTC bit in vpeconf0 to point at our tc */ + write_vpe_c0_vpeconf0((read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC)) + | (t->index << VPECONF0_XTC_SHIFT)); + + back_to_back_c0_hazard(); + + /* enable this VPE */ + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); + + /* clear out any left overs from a previous program */ + write_vpe_c0_status(0); + write_vpe_c0_cause(0); + + /* take system out of configuration state */ + clear_c0_mvpcontrol(MVPCONTROL_VPC); + + /* + * SMTC/SMVP kernels manage VPE enable independently, + * but uniprocessor kernels need to turn it on, even + * if that wasn't the pre-dvpe() state. + */ +#ifdef CONFIG_SMP + evpe(vpeflags); +#else + evpe(EVPE_ENABLE); +#endif + emt(dmt_flag); + local_irq_restore(flags); + + list_for_each_entry(notifier, &v->notify, list) + notifier->start(VPE_MODULE_MINOR); + + return 0; +} + +void cleanup_tc(struct tc *tc) +{ + unsigned long flags; + unsigned int mtflags, vpflags; + int tmp; + + local_irq_save(flags); + mtflags = dmt(); + vpflags = dvpe(); + /* Put MVPE's into 'configuration state' */ + set_c0_mvpcontrol(MVPCONTROL_VPC); + + settc(tc->index); + tmp = read_tc_c0_tcstatus(); + + /* mark not allocated and not dynamically allocatable */ + tmp &= ~(TCSTATUS_A | TCSTATUS_DA); + tmp |= TCSTATUS_IXMT; /* interrupt exempt */ + write_tc_c0_tcstatus(tmp); + + write_tc_c0_tchalt(TCHALT_H); + mips_ihb(); + + clear_c0_mvpcontrol(MVPCONTROL_VPC); + evpe(vpflags); + emt(mtflags); + local_irq_restore(flags); +} + +/* module wrapper entry points */ +/* give me a vpe */ +void *vpe_alloc(void) +{ + int i; + struct vpe *v; + + /* find a vpe */ + for (i = 1; i < MAX_VPES; i++) { + v = get_vpe(i); + if (v != NULL) { + v->state = VPE_STATE_INUSE; + return v; + } + } + return NULL; +} +EXPORT_SYMBOL(vpe_alloc); + +/* start running from here */ +int vpe_start(void *vpe, unsigned long start) +{ + struct vpe *v = vpe; + + v->__start = start; + return vpe_run(v); +} +EXPORT_SYMBOL(vpe_start); + +/* halt it for now */ +int vpe_stop(void *vpe) +{ + struct vpe *v = vpe; + struct tc *t; + unsigned int evpe_flags; + + evpe_flags = dvpe(); + + t = list_entry(v->tc.next, struct tc, tc); + if (t != NULL) { + settc(t->index); + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA); + } + + evpe(evpe_flags); + + return 0; +} +EXPORT_SYMBOL(vpe_stop); + +/* I've done with it thank you */ +int vpe_free(void *vpe) +{ + struct vpe *v = vpe; + struct tc *t; + unsigned int evpe_flags; + + t = list_entry(v->tc.next, struct tc, tc); + if (t == NULL) + return -ENOEXEC; + + evpe_flags = dvpe(); + + /* Put MVPE's into 'configuration state' */ + set_c0_mvpcontrol(MVPCONTROL_VPC); + + settc(t->index); + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA); + + /* halt the TC */ + write_tc_c0_tchalt(TCHALT_H); + mips_ihb(); + + /* mark the TC unallocated */ + write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A); + + v->state = VPE_STATE_UNUSED; + + clear_c0_mvpcontrol(MVPCONTROL_VPC); + evpe(evpe_flags); + + return 0; +} +EXPORT_SYMBOL(vpe_free); + +static ssize_t store_kill(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) +{ + struct vpe *vpe = get_vpe(aprp_cpu_index()); + struct vpe_notifications *notifier; + + list_for_each_entry(notifier, &vpe->notify, list) + notifier->stop(aprp_cpu_index()); + + release_progmem(vpe->load_addr); + cleanup_tc(get_tc(aprp_cpu_index())); + vpe_stop(vpe); + vpe_free(vpe); + + return len; +} +static DEVICE_ATTR(kill, S_IWUSR, NULL, store_kill); + +static ssize_t ntcs_show(struct device *cd, struct device_attribute *attr, + char *buf) +{ + struct vpe *vpe = get_vpe(aprp_cpu_index()); + + return sprintf(buf, "%d\n", vpe->ntcs); +} + +static ssize_t ntcs_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) +{ + struct vpe *vpe = get_vpe(aprp_cpu_index()); + unsigned long new; + int ret; + + ret = kstrtoul(buf, 0, &new); + if (ret < 0) + return ret; + + if (new == 0 || new > (hw_tcs - aprp_cpu_index())) + return -EINVAL; + + vpe->ntcs = new; + + return len; +} +static DEVICE_ATTR_RW(ntcs); + +static struct attribute *vpe_attrs[] = { + &dev_attr_kill.attr, + &dev_attr_ntcs.attr, + NULL, +}; +ATTRIBUTE_GROUPS(vpe); + +static void vpe_device_release(struct device *cd) +{ + kfree(cd); +} + +static struct class vpe_class = { + .name = "vpe", + .owner = THIS_MODULE, + .dev_release = vpe_device_release, + .dev_groups = vpe_groups, +}; + +static struct device vpe_device; + +int __init vpe_module_init(void) +{ + unsigned int mtflags, vpflags; + unsigned long flags, val; + struct vpe *v = NULL; + struct tc *t; + int tc, err; + + if (!cpu_has_mipsmt) { + pr_warn("VPE loader: not a MIPS MT capable processor\n"); + return -ENODEV; + } + + if (vpelimit == 0) { + pr_warn("No VPEs reserved for AP/SP, not initialize VPE loader\n" + "Pass maxvpes= argument as kernel argument\n"); + + return -ENODEV; + } + + if (aprp_cpu_index() == 0) { + pr_warn("No TCs reserved for AP/SP, not initialize VPE loader\n" + "Pass maxtcs= argument as kernel argument\n"); + + return -ENODEV; + } + + major = register_chrdev(0, VPE_MODULE_NAME, &vpe_fops); + if (major < 0) { + pr_warn("VPE loader: unable to register character device\n"); + return major; + } + + err = class_register(&vpe_class); + if (err) { + pr_err("vpe_class registration failed\n"); + goto out_chrdev; + } + + device_initialize(&vpe_device); + vpe_device.class = &vpe_class, + vpe_device.parent = NULL, + dev_set_name(&vpe_device, "vpe1"); + vpe_device.devt = MKDEV(major, VPE_MODULE_MINOR); + err = device_add(&vpe_device); + if (err) { + pr_err("Adding vpe_device failed\n"); + goto out_class; + } + + local_irq_save(flags); + mtflags = dmt(); + vpflags = dvpe(); + + /* Put MVPE's into 'configuration state' */ + set_c0_mvpcontrol(MVPCONTROL_VPC); + + val = read_c0_mvpconf0(); + hw_tcs = (val & MVPCONF0_PTC) + 1; + hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; + + for (tc = aprp_cpu_index(); tc < hw_tcs; tc++) { + /* + * Must re-enable multithreading temporarily or in case we + * reschedule send IPIs or similar we might hang. + */ + clear_c0_mvpcontrol(MVPCONTROL_VPC); + evpe(vpflags); + emt(mtflags); + local_irq_restore(flags); + t = alloc_tc(tc); + if (!t) { + err = -ENOMEM; + goto out_dev; + } + + local_irq_save(flags); + mtflags = dmt(); + vpflags = dvpe(); + set_c0_mvpcontrol(MVPCONTROL_VPC); + + /* VPE's */ + if (tc < hw_tcs) { + settc(tc); + + v = alloc_vpe(tc); + if (v == NULL) { + pr_warn("VPE: unable to allocate VPE\n"); + goto out_reenable; + } + + v->ntcs = hw_tcs - aprp_cpu_index(); + + /* add the tc to the list of this vpe's tc's. */ + list_add(&t->tc, &v->tc); + + /* deactivate all but vpe0 */ + if (tc >= aprp_cpu_index()) { + unsigned long tmp = read_vpe_c0_vpeconf0(); + + tmp &= ~VPECONF0_VPA; + + /* master VPE */ + tmp |= VPECONF0_MVP; + write_vpe_c0_vpeconf0(tmp); + } + + /* disable multi-threading with TC's */ + write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & + ~VPECONTROL_TE); + + if (tc >= vpelimit) { + /* + * Set config to be the same as vpe0, + * particularly kseg0 coherency alg + */ + write_vpe_c0_config(read_c0_config()); + } + } + + /* TC's */ + t->pvpe = v; /* set the parent vpe */ + + if (tc >= aprp_cpu_index()) { + unsigned long tmp; + + settc(tc); + + /* Any TC that is bound to VPE0 gets left as is - in + * case we are running SMTC on VPE0. A TC that is bound + * to any other VPE gets bound to VPE0, ideally I'd like + * to make it homeless but it doesn't appear to let me + * bind a TC to a non-existent VPE. Which is perfectly + * reasonable. + * + * The (un)bound state is visible to an EJTAG probe so + * may notify GDB... + */ + tmp = read_tc_c0_tcbind(); + if (tmp & TCBIND_CURVPE) { + /* tc is bound >vpe0 */ + write_tc_c0_tcbind(tmp & ~TCBIND_CURVPE); + + t->pvpe = get_vpe(0); /* set the parent vpe */ + } + + /* halt the TC */ + write_tc_c0_tchalt(TCHALT_H); + mips_ihb(); + + tmp = read_tc_c0_tcstatus(); + + /* mark not activated and not dynamically allocatable */ + tmp &= ~(TCSTATUS_A | TCSTATUS_DA); + tmp |= TCSTATUS_IXMT; /* interrupt exempt */ + write_tc_c0_tcstatus(tmp); + } + } + +out_reenable: + /* release config state */ + clear_c0_mvpcontrol(MVPCONTROL_VPC); + + evpe(vpflags); + emt(mtflags); + local_irq_restore(flags); + + return 0; + +out_dev: + device_del(&vpe_device); + +out_class: + class_unregister(&vpe_class); + +out_chrdev: + unregister_chrdev(major, VPE_MODULE_NAME); + + return err; +} + +void __exit vpe_module_exit(void) +{ + struct vpe *v, *n; + + device_del(&vpe_device); + class_unregister(&vpe_class); + unregister_chrdev(major, VPE_MODULE_NAME); + + /* No locking needed here */ + list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) { + if (v->state != VPE_STATE_UNUSED) + release_vpe(v); + } +} diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 2d5c142bad67b0..11da314565cc33 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -1,37 +1,22 @@ /* - * Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved. - * - * This program is free software; you can distribute 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 it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - */ - -/* - * VPE support module + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. * - * Provides support for loading a MIPS SP program on VPE1. - * The SP environment is rather simple, no tlb's. It needs to be relocatable - * (or partially linked). You should initialise your stack in the startup - * code. This loader looks for the symbol __start and sets up - * execution to resume from there. The MIPS SDE kit contains suitable examples. + * Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2013 Imagination Technologies Ltd. * - * To load and run, simply cat a SP 'program file' to /dev/vpe1. - * i.e cat spapp >/dev/vpe1. + * VPE spport module for loading a MIPS SP program into VPE1. The SP + * environment is rather simple since there are no TLBs. It needs + * to be relocatable (or partiall linked). Initialize your stack in + * the startup-code. The loader looks for the symbol __start and sets + * up the execution to resume from there. To load and run, simply do + * a cat SP 'binary' to the /dev/vpe1 device. */ #include #include #include #include -#include #include #include #include @@ -46,13 +31,10 @@ #include #include #include -#include #include #include #include -typedef void *vpe_handle; - #ifndef ARCH_SHF_SMALL #define ARCH_SHF_SMALL 0 #endif @@ -60,95 +42,15 @@ typedef void *vpe_handle; /* If this is set, the section belongs in the init part of the module */ #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) -/* - * The number of TCs and VPEs physically available on the core - */ -static int hw_tcs, hw_vpes; -static char module_name[] = "vpe"; -static int major; -static const int minor = 1; /* fixed for now */ - -/* grab the likely amount of memory we will need. */ -#ifdef CONFIG_MIPS_VPE_LOADER_TOM -#define P_SIZE (2 * 1024 * 1024) -#else -/* add an overhead to the max kmalloc size for non-striped symbols/etc */ -#define P_SIZE (256 * 1024) -#endif - -extern unsigned long physical_memsize; - -#define MAX_VPES 16 -#define VPE_PATH_MAX 256 - -enum vpe_state { - VPE_STATE_UNUSED = 0, - VPE_STATE_INUSE, - VPE_STATE_RUNNING -}; - -enum tc_state { - TC_STATE_UNUSED = 0, - TC_STATE_INUSE, - TC_STATE_RUNNING, - TC_STATE_DYNAMIC -}; - -struct vpe { - enum vpe_state state; - - /* (device) minor associated with this vpe */ - int minor; - - /* elfloader stuff */ - void *load_addr; - unsigned long len; - char *pbuffer; - unsigned long plen; - char cwd[VPE_PATH_MAX]; - - unsigned long __start; - - /* tc's associated with this vpe */ - struct list_head tc; - - /* The list of vpe's */ - struct list_head list; - - /* shared symbol address */ - void *shared_ptr; - - /* the list of who wants to know when something major happens */ - struct list_head notify; - - unsigned int ntcs; -}; - -struct tc { - enum tc_state state; - int index; - - struct vpe *pvpe; /* parent VPE */ - struct list_head tc; /* The list of TC's with this VPE */ - struct list_head list; /* The global list of tc's */ -}; - -struct { - spinlock_t vpe_list_lock; - struct list_head vpe_list; /* Virtual processing elements */ - spinlock_t tc_list_lock; - struct list_head tc_list; /* Thread contexts */ -} vpecontrol = { +struct vpe_control vpecontrol = { .vpe_list_lock = __SPIN_LOCK_UNLOCKED(vpe_list_lock), .vpe_list = LIST_HEAD_INIT(vpecontrol.vpe_list), .tc_list_lock = __SPIN_LOCK_UNLOCKED(tc_list_lock), .tc_list = LIST_HEAD_INIT(vpecontrol.tc_list) }; -static void release_progmem(void *ptr); - /* get the vpe associated with this minor */ -static struct vpe *get_vpe(int minor) +struct vpe *get_vpe(int minor) { struct vpe *res, *v; @@ -158,7 +60,7 @@ static struct vpe *get_vpe(int minor) res = NULL; spin_lock(&vpecontrol.vpe_list_lock); list_for_each_entry(v, &vpecontrol.vpe_list, list) { - if (v->minor == minor) { + if (v->minor == VPE_MODULE_MINOR) { res = v; break; } @@ -169,7 +71,7 @@ static struct vpe *get_vpe(int minor) } /* get the vpe associated with this minor */ -static struct tc *get_tc(int index) +struct tc *get_tc(int index) { struct tc *res, *t; @@ -187,12 +89,13 @@ static struct tc *get_tc(int index) } /* allocate a vpe and associate it with this minor (or index) */ -static struct vpe *alloc_vpe(int minor) +struct vpe *alloc_vpe(int minor) { struct vpe *v; - if ((v = kzalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL) - return NULL; + v = kzalloc(sizeof(struct vpe), GFP_KERNEL); + if (v == NULL) + goto out; INIT_LIST_HEAD(&v->tc); spin_lock(&vpecontrol.vpe_list_lock); @@ -200,17 +103,19 @@ static struct vpe *alloc_vpe(int minor) spin_unlock(&vpecontrol.vpe_list_lock); INIT_LIST_HEAD(&v->notify); - v->minor = minor; + v->minor = VPE_MODULE_MINOR; +out: return v; } /* allocate a tc. At startup only tc0 is running, all other can be halted. */ -static struct tc *alloc_tc(int index) +struct tc *alloc_tc(int index) { struct tc *tc; - if ((tc = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) + tc = kzalloc(sizeof(struct tc), GFP_KERNEL); + if (tc == NULL) goto out; INIT_LIST_HEAD(&tc->tc); @@ -225,7 +130,7 @@ static struct tc *alloc_tc(int index) } /* clean up and free everything */ -static void release_vpe(struct vpe *v) +void release_vpe(struct vpe *v) { list_del(&v->list); if (v->load_addr) @@ -233,28 +138,8 @@ static void release_vpe(struct vpe *v) kfree(v); } -static void __maybe_unused dump_mtregs(void) -{ - unsigned long val; - - val = read_c0_config3(); - printk("config3 0x%lx MT %ld\n", val, - (val & CONFIG3_MT) >> CONFIG3_MT_SHIFT); - - val = read_c0_mvpcontrol(); - printk("MVPControl 0x%lx, STLB %ld VPC %ld EVP %ld\n", val, - (val & MVPCONTROL_STLB) >> MVPCONTROL_STLB_SHIFT, - (val & MVPCONTROL_VPC) >> MVPCONTROL_VPC_SHIFT, - (val & MVPCONTROL_EVP)); - - val = read_c0_mvpconf0(); - printk("mvpconf0 0x%lx, PVPE %ld PTC %ld M %ld\n", val, - (val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT, - val & MVPCONF0_PTC, (val & MVPCONF0_M) >> MVPCONF0_M_SHIFT); -} - -/* Find some VPE program space */ -static void *alloc_progmem(unsigned long len) +/* Find some VPE program space */ +void *alloc_progmem(unsigned long len) { void *addr; @@ -273,7 +158,7 @@ static void *alloc_progmem(unsigned long len) return addr; } -static void release_progmem(void *ptr) +void release_progmem(void *ptr) { #ifndef CONFIG_MIPS_VPE_LOADER_TOM kfree(ptr); @@ -281,7 +166,7 @@ static void release_progmem(void *ptr) } /* Update size with this section: return offset. */ -static long get_offset(unsigned long *size, Elf_Shdr * sechdr) +static long get_offset(unsigned long *size, Elf_Shdr *sechdr) { long ret; @@ -294,8 +179,8 @@ static long get_offset(unsigned long *size, Elf_Shdr * sechdr) might -- code, read-only data, read-write data, small data. Tally sizes, and place the offsets into sh_entsize fields: high bit means it belongs in init. */ -static void layout_sections(struct module *mod, const Elf_Ehdr * hdr, - Elf_Shdr * sechdrs, const char *secstrings) +static void layout_sections(struct module *mod, const Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, const char *secstrings) { static unsigned long const masks[][2] = { /* NOTE: all executable code must be the first section @@ -315,7 +200,6 @@ static void layout_sections(struct module *mod, const Elf_Ehdr * hdr, for (i = 0; i < hdr->e_shnum; ++i) { Elf_Shdr *s = &sechdrs[i]; - // || strncmp(secstrings + s->sh_name, ".init", 5) == 0) if ((s->sh_flags & masks[m][0]) != masks[m][0] || (s->sh_flags & masks[m][1]) || s->sh_entsize != ~0UL) @@ -330,7 +214,6 @@ static void layout_sections(struct module *mod, const Elf_Ehdr * hdr, } } - /* from module-elf32.c, but subverted a little */ struct mips_hi16 { @@ -353,20 +236,18 @@ static int apply_r_mips_gprel16(struct module *me, uint32_t *location, { int rel; - if( !(*location & 0xffff) ) { + if (!(*location & 0xffff)) { rel = (int)v - gp_addr; - } - else { + } else { /* .sbss + gp(relative) + offset */ /* kludge! */ rel = (int)(short)((int)v + gp_offs + (int)(short)(*location & 0xffff) - gp_addr); } - if( (rel > 32768) || (rel < -32768) ) { - printk(KERN_DEBUG "VPE loader: apply_r_mips_gprel16: " - "relative address 0x%x out of range of gp register\n", - rel); + if ((rel > 32768) || (rel < -32768)) { + pr_debug("VPE loader: apply_r_mips_gprel16: relative address 0x%x out of range of gp register\n", + rel); return -ENOEXEC; } @@ -380,12 +261,12 @@ static int apply_r_mips_pc16(struct module *me, uint32_t *location, { int rel; rel = (((unsigned int)v - (unsigned int)location)); - rel >>= 2; // because the offset is in _instructions_ not bytes. - rel -= 1; // and one instruction less due to the branch delay slot. + rel >>= 2; /* because the offset is in _instructions_ not bytes. */ + rel -= 1; /* and one instruction less due to the branch delay slot. */ - if( (rel > 32768) || (rel < -32768) ) { - printk(KERN_DEBUG "VPE loader: " - "apply_r_mips_pc16: relative address out of range 0x%x\n", rel); + if ((rel > 32768) || (rel < -32768)) { + pr_debug("VPE loader: apply_r_mips_pc16: relative address out of range 0x%x\n", + rel); return -ENOEXEC; } @@ -406,8 +287,7 @@ static int apply_r_mips_26(struct module *me, uint32_t *location, Elf32_Addr v) { if (v % 4) { - printk(KERN_DEBUG "VPE loader: apply_r_mips_26 " - " unaligned relocation\n"); + pr_debug("VPE loader: apply_r_mips_26: unaligned relocation\n"); return -ENOEXEC; } @@ -438,7 +318,7 @@ static int apply_r_mips_hi16(struct module *me, uint32_t *location, * the carry we need to add. Save the information, and let LO16 do the * actual relocation. */ - n = kmalloc(sizeof *n, GFP_KERNEL); + n = kmalloc(sizeof(*n), GFP_KERNEL); if (!n) return -ENOMEM; @@ -470,9 +350,7 @@ static int apply_r_mips_lo16(struct module *me, uint32_t *location, * The value for the HI16 had best be the same. */ if (v != l->value) { - printk(KERN_DEBUG "VPE loader: " - "apply_r_mips_lo16/hi16: \t" - "inconsistent value information\n"); + pr_debug("VPE loader: apply_r_mips_lo16/hi16: inconsistent value information\n"); goto out_free; } @@ -568,20 +446,19 @@ static int apply_relocations(Elf32_Shdr *sechdrs, + ELF32_R_SYM(r_info); if (!sym->st_value) { - printk(KERN_DEBUG "%s: undefined weak symbol %s\n", - me->name, strtab + sym->st_name); + pr_debug("%s: undefined weak symbol %s\n", + me->name, strtab + sym->st_name); /* just print the warning, dont barf */ } v = sym->st_value; res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v); - if( res ) { + if (res) { char *r = rstrs[ELF32_R_TYPE(r_info)]; - printk(KERN_WARNING "VPE loader: .text+0x%x " - "relocation type %s for symbol \"%s\" failed\n", - rel[i].r_offset, r ? r : "UNKNOWN", - strtab + sym->st_name); + pr_warn("VPE loader: .text+0x%x relocation type %s for symbol \"%s\" failed\n", + rel[i].r_offset, r ? r : "UNKNOWN", + strtab + sym->st_name); return res; } } @@ -596,10 +473,8 @@ static inline void save_gp_address(unsigned int secbase, unsigned int rel) } /* end module-elf32.c */ - - /* Change all symbols so that sh_value encodes the pointer directly. */ -static void simplify_symbols(Elf_Shdr * sechdrs, +static void simplify_symbols(Elf_Shdr *sechdrs, unsigned int symindex, const char *strtab, const char *secstrings, @@ -640,18 +515,16 @@ static void simplify_symbols(Elf_Shdr * sechdrs, break; case SHN_MIPS_SCOMMON: - printk(KERN_DEBUG "simplify_symbols: ignoring SHN_MIPS_SCOMMON " - "symbol <%s> st_shndx %d\n", strtab + sym[i].st_name, - sym[i].st_shndx); - // .sbss section + pr_debug("simplify_symbols: ignoring SHN_MIPS_SCOMMON symbol <%s> st_shndx %d\n", + strtab + sym[i].st_name, sym[i].st_shndx); + /* .sbss section */ break; default: secbase = sechdrs[sym[i].st_shndx].sh_addr; - if (strncmp(strtab + sym[i].st_name, "_gp", 3) == 0) { + if (strncmp(strtab + sym[i].st_name, "_gp", 3) == 0) save_gp_address(secbase, sym[i].st_value); - } sym[i].st_value += secbase; break; @@ -660,142 +533,21 @@ static void simplify_symbols(Elf_Shdr * sechdrs, } #ifdef DEBUG_ELFLOADER -static void dump_elfsymbols(Elf_Shdr * sechdrs, unsigned int symindex, +static void dump_elfsymbols(Elf_Shdr *sechdrs, unsigned int symindex, const char *strtab, struct module *mod) { Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); - printk(KERN_DEBUG "dump_elfsymbols: n %d\n", n); + pr_debug("dump_elfsymbols: n %d\n", n); for (i = 1; i < n; i++) { - printk(KERN_DEBUG " i %d name <%s> 0x%x\n", i, - strtab + sym[i].st_name, sym[i].st_value); + pr_debug(" i %d name <%s> 0x%x\n", i, strtab + sym[i].st_name, + sym[i].st_value); } } #endif -/* We are prepared so configure and start the VPE... */ -static int vpe_run(struct vpe * v) -{ - unsigned long flags, val, dmt_flag; - struct vpe_notifications *n; - unsigned int vpeflags; - struct tc *t; - - /* check we are the Master VPE */ - local_irq_save(flags); - val = read_c0_vpeconf0(); - if (!(val & VPECONF0_MVP)) { - printk(KERN_WARNING - "VPE loader: only Master VPE's are allowed to configure MT\n"); - local_irq_restore(flags); - - return -1; - } - - dmt_flag = dmt(); - vpeflags = dvpe(); - - if (list_empty(&v->tc)) { - evpe(vpeflags); - emt(dmt_flag); - local_irq_restore(flags); - - printk(KERN_WARNING - "VPE loader: No TC's associated with VPE %d\n", - v->minor); - - return -ENOEXEC; - } - - t = list_first_entry(&v->tc, struct tc, tc); - - /* Put MVPE's into 'configuration state' */ - set_c0_mvpcontrol(MVPCONTROL_VPC); - - settc(t->index); - - /* should check it is halted, and not activated */ - if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) { - evpe(vpeflags); - emt(dmt_flag); - local_irq_restore(flags); - - printk(KERN_WARNING "VPE loader: TC %d is already active!\n", - t->index); - - return -ENOEXEC; - } - - /* Write the address we want it to start running from in the TCPC register. */ - write_tc_c0_tcrestart((unsigned long)v->__start); - write_tc_c0_tccontext((unsigned long)0); - - /* - * Mark the TC as activated, not interrupt exempt and not dynamically - * allocatable - */ - val = read_tc_c0_tcstatus(); - val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A; - write_tc_c0_tcstatus(val); - - write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H); - - /* - * The sde-kit passes 'memsize' to __start in $a3, so set something - * here... Or set $a3 to zero and define DFLT_STACK_SIZE and - * DFLT_HEAP_SIZE when you compile your program - */ - mttgpr(6, v->ntcs); - mttgpr(7, physical_memsize); - - /* set up VPE1 */ - /* - * bind the TC to VPE 1 as late as possible so we only have the final - * VPE registers to set up, and so an EJTAG probe can trigger on it - */ - write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1); - - write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA)); - - back_to_back_c0_hazard(); - - /* Set up the XTC bit in vpeconf0 to point at our tc */ - write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC)) - | (t->index << VPECONF0_XTC_SHIFT)); - - back_to_back_c0_hazard(); - - /* enable this VPE */ - write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); - - /* clear out any left overs from a previous program */ - write_vpe_c0_status(0); - write_vpe_c0_cause(0); - - /* take system out of configuration state */ - clear_c0_mvpcontrol(MVPCONTROL_VPC); - - /* - * SMTC/SMVP kernels manage VPE enable independently, - * but uniprocessor kernels need to turn it on, even - * if that wasn't the pre-dvpe() state. - */ -#ifdef CONFIG_SMP - evpe(vpeflags); -#else - evpe(EVPE_ENABLE); -#endif - emt(dmt_flag); - local_irq_restore(flags); - - list_for_each_entry(n, &v->notify, list) - n->start(minor); - - return 0; -} - -static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs, +static int find_vpe_symbols(struct vpe *v, Elf_Shdr *sechdrs, unsigned int symindex, const char *strtab, struct module *mod) { @@ -803,16 +555,14 @@ static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs, unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); for (i = 1; i < n; i++) { - if (strcmp(strtab + sym[i].st_name, "__start") == 0) { + if (strcmp(strtab + sym[i].st_name, "__start") == 0) v->__start = sym[i].st_value; - } - if (strcmp(strtab + sym[i].st_name, "vpe_shared") == 0) { + if (strcmp(strtab + sym[i].st_name, "vpe_shared") == 0) v->shared_ptr = (void *)sym[i].st_value; - } } - if ( (v->__start == 0) || (v->shared_ptr == NULL)) + if ((v->__start == 0) || (v->shared_ptr == NULL)) return -1; return 0; @@ -823,14 +573,14 @@ static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs, * contents of the program (p)buffer performing relocatations/etc, free's it * when finished. */ -static int vpe_elfload(struct vpe * v) +static int vpe_elfload(struct vpe *v) { Elf_Ehdr *hdr; Elf_Shdr *sechdrs; long err = 0; char *secstrings, *strtab = NULL; unsigned int len, i, symindex = 0, strindex = 0, relocate = 0; - struct module mod; // so we can re-use the relocations code + struct module mod; /* so we can re-use the relocations code */ memset(&mod, 0, sizeof(struct module)); strcpy(mod.name, "VPE loader"); @@ -844,8 +594,7 @@ static int vpe_elfload(struct vpe * v) || (hdr->e_type != ET_REL && hdr->e_type != ET_EXEC) || !elf_check_arch(hdr) || hdr->e_shentsize != sizeof(*sechdrs)) { - printk(KERN_WARNING - "VPE loader: program wrong arch or weird elf version\n"); + pr_warn("VPE loader: program wrong arch or weird elf version\n"); return -ENOEXEC; } @@ -854,8 +603,7 @@ static int vpe_elfload(struct vpe * v) relocate = 1; if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) { - printk(KERN_ERR "VPE loader: program length %u truncated\n", - len); + pr_err("VPE loader: program length %u truncated\n", len); return -ENOEXEC; } @@ -870,22 +618,24 @@ static int vpe_elfload(struct vpe * v) if (relocate) { for (i = 1; i < hdr->e_shnum; i++) { - if (sechdrs[i].sh_type != SHT_NOBITS - && len < sechdrs[i].sh_offset + sechdrs[i].sh_size) { - printk(KERN_ERR "VPE program length %u truncated\n", + if ((sechdrs[i].sh_type != SHT_NOBITS) && + (len < sechdrs[i].sh_offset + sechdrs[i].sh_size)) { + pr_err("VPE program length %u truncated\n", len); return -ENOEXEC; } /* Mark all sections sh_addr with their address in the temporary image. */ - sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset; + sechdrs[i].sh_addr = (size_t) hdr + + sechdrs[i].sh_offset; /* Internal symbols and strings. */ if (sechdrs[i].sh_type == SHT_SYMTAB) { symindex = i; strindex = sechdrs[i].sh_link; - strtab = (char *)hdr + sechdrs[strindex].sh_offset; + strtab = (char *)hdr + + sechdrs[strindex].sh_offset; } } layout_sections(&mod, hdr, sechdrs, secstrings); @@ -912,8 +662,9 @@ static int vpe_elfload(struct vpe * v) /* Update sh_addr to point to copy in image. */ sechdrs[i].sh_addr = (unsigned long)dest; - printk(KERN_DEBUG " section sh_name %s sh_addr 0x%x\n", - secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr); + pr_debug(" section sh_name %s sh_addr 0x%x\n", + secstrings + sechdrs[i].sh_name, + sechdrs[i].sh_addr); } /* Fix up syms, so that st_value is a pointer to location. */ @@ -934,17 +685,18 @@ static int vpe_elfload(struct vpe * v) continue; if (sechdrs[i].sh_type == SHT_REL) - err = apply_relocations(sechdrs, strtab, symindex, i, - &mod); + err = apply_relocations(sechdrs, strtab, + symindex, i, &mod); else if (sechdrs[i].sh_type == SHT_RELA) - err = apply_relocate_add(sechdrs, strtab, symindex, i, - &mod); + err = apply_relocate_add(sechdrs, strtab, + symindex, i, &mod); if (err < 0) return err; } } else { - struct elf_phdr *phdr = (struct elf_phdr *) ((char *)hdr + hdr->e_phoff); + struct elf_phdr *phdr = (struct elf_phdr *) + ((char *)hdr + hdr->e_phoff); for (i = 0; i < hdr->e_phnum; i++) { if (phdr->p_type == PT_LOAD) { @@ -962,11 +714,15 @@ static int vpe_elfload(struct vpe * v) if (sechdrs[i].sh_type == SHT_SYMTAB) { symindex = i; strindex = sechdrs[i].sh_link; - strtab = (char *)hdr + sechdrs[strindex].sh_offset; + strtab = (char *)hdr + + sechdrs[strindex].sh_offset; - /* mark the symtab's address for when we try to find the - magic symbols */ - sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset; + /* + * mark symtab's address for when we try + * to find the magic symbols + */ + sechdrs[i].sh_addr = (size_t) hdr + + sechdrs[i].sh_offset; } } } @@ -977,53 +733,19 @@ static int vpe_elfload(struct vpe * v) if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) { if (v->__start == 0) { - printk(KERN_WARNING "VPE loader: program does not contain " - "a __start symbol\n"); + pr_warn("VPE loader: program does not contain a __start symbol\n"); return -ENOEXEC; } if (v->shared_ptr == NULL) - printk(KERN_WARNING "VPE loader: " - "program does not contain vpe_shared symbol.\n" - " Unable to use AMVP (AP/SP) facilities.\n"); + pr_warn("VPE loader: program does not contain vpe_shared symbol.\n" + " Unable to use AMVP (AP/SP) facilities.\n"); } - printk(" elf loaded\n"); + pr_info(" elf loaded\n"); return 0; } -static void cleanup_tc(struct tc *tc) -{ - unsigned long flags; - unsigned int mtflags, vpflags; - int tmp; - - local_irq_save(flags); - mtflags = dmt(); - vpflags = dvpe(); - /* Put MVPE's into 'configuration state' */ - set_c0_mvpcontrol(MVPCONTROL_VPC); - - settc(tc->index); - tmp = read_tc_c0_tcstatus(); - - /* mark not allocated and not dynamically allocatable */ - tmp &= ~(TCSTATUS_A | TCSTATUS_DA); - tmp |= TCSTATUS_IXMT; /* interrupt exempt */ - write_tc_c0_tcstatus(tmp); - - write_tc_c0_tchalt(TCHALT_H); - mips_ihb(); - - /* bind it to anything other than VPE1 */ -// write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE - - clear_c0_mvpcontrol(MVPCONTROL_VPC); - evpe(vpflags); - emt(mtflags); - local_irq_restore(flags); -} - static int getcwd(char *buff, int size) { mm_segment_t old_fs; @@ -1043,39 +765,39 @@ static int getcwd(char *buff, int size) static int vpe_open(struct inode *inode, struct file *filp) { enum vpe_state state; - struct vpe_notifications *not; + struct vpe_notifications *notifier; struct vpe *v; int ret; - if (minor != iminor(inode)) { + if (VPE_MODULE_MINOR != iminor(inode)) { /* assume only 1 device at the moment. */ - pr_warning("VPE loader: only vpe1 is supported\n"); + pr_warn("VPE loader: only vpe1 is supported\n"); return -ENODEV; } - if ((v = get_vpe(tclimit)) == NULL) { - pr_warning("VPE loader: unable to get vpe\n"); + v = get_vpe(aprp_cpu_index()); + if (v == NULL) { + pr_warn("VPE loader: unable to get vpe\n"); return -ENODEV; } state = xchg(&v->state, VPE_STATE_INUSE); if (state != VPE_STATE_UNUSED) { - printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n"); + pr_debug("VPE loader: tc in use dumping regs\n"); - list_for_each_entry(not, &v->notify, list) { - not->stop(tclimit); - } + list_for_each_entry(notifier, &v->notify, list) + notifier->stop(aprp_cpu_index()); release_progmem(v->load_addr); - cleanup_tc(get_tc(tclimit)); + cleanup_tc(get_tc(aprp_cpu_index())); } /* this of-course trashes what was there before... */ v->pbuffer = vmalloc(P_SIZE); if (!v->pbuffer) { - pr_warning("VPE loader: unable to allocate memory\n"); + pr_warn("VPE loader: unable to allocate memory\n"); return -ENOMEM; } v->plen = P_SIZE; @@ -1085,7 +807,7 @@ static int vpe_open(struct inode *inode, struct file *filp) v->cwd[0] = 0; ret = getcwd(v->cwd, VPE_PATH_MAX); if (ret < 0) - printk(KERN_WARNING "VPE loader: open, getcwd returned %d\n", ret); + pr_warn("VPE loader: open, getcwd returned %d\n", ret); v->shared_ptr = NULL; v->__start = 0; @@ -1099,20 +821,20 @@ static int vpe_release(struct inode *inode, struct file *filp) Elf_Ehdr *hdr; int ret = 0; - v = get_vpe(tclimit); + v = get_vpe(aprp_cpu_index()); if (v == NULL) return -ENODEV; hdr = (Elf_Ehdr *) v->pbuffer; if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) == 0) { - if (vpe_elfload(v) >= 0) { + if ((vpe_elfload(v) >= 0) && vpe_run) { vpe_run(v); } else { - printk(KERN_WARNING "VPE loader: ELF load failed.\n"); + pr_warn("VPE loader: ELF load failed.\n"); ret = -ENOEXEC; } } else { - printk(KERN_WARNING "VPE loader: only elf files are supported\n"); + pr_warn("VPE loader: only elf files are supported\n"); ret = -ENOEXEC; } @@ -1130,22 +852,22 @@ static int vpe_release(struct inode *inode, struct file *filp) return ret; } -static ssize_t vpe_write(struct file *file, const char __user * buffer, - size_t count, loff_t * ppos) +static ssize_t vpe_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) { size_t ret = count; struct vpe *v; - if (iminor(file_inode(file)) != minor) + if (iminor(file_inode(file)) != VPE_MODULE_MINOR) return -ENODEV; - v = get_vpe(tclimit); + v = get_vpe(aprp_cpu_index()); + if (v == NULL) return -ENODEV; if ((count + v->len) > v->plen) { - printk(KERN_WARNING - "VPE loader: elf size too big. Perhaps strip uneeded symbols\n"); + pr_warn("VPE loader: elf size too big. Perhaps strip uneeded symbols\n"); return -ENOMEM; } @@ -1157,7 +879,7 @@ static ssize_t vpe_write(struct file *file, const char __user * buffer, return ret; } -static const struct file_operations vpe_fops = { +const struct file_operations vpe_fops = { .owner = THIS_MODULE, .open = vpe_open, .release = vpe_release, @@ -1165,396 +887,40 @@ static const struct file_operations vpe_fops = { .llseek = noop_llseek, }; -/* module wrapper entry points */ -/* give me a vpe */ -vpe_handle vpe_alloc(void) -{ - int i; - struct vpe *v; - - /* find a vpe */ - for (i = 1; i < MAX_VPES; i++) { - if ((v = get_vpe(i)) != NULL) { - v->state = VPE_STATE_INUSE; - return v; - } - } - return NULL; -} - -EXPORT_SYMBOL(vpe_alloc); - -/* start running from here */ -int vpe_start(vpe_handle vpe, unsigned long start) -{ - struct vpe *v = vpe; - - v->__start = start; - return vpe_run(v); -} - -EXPORT_SYMBOL(vpe_start); - -/* halt it for now */ -int vpe_stop(vpe_handle vpe) -{ - struct vpe *v = vpe; - struct tc *t; - unsigned int evpe_flags; - - evpe_flags = dvpe(); - - if ((t = list_entry(v->tc.next, struct tc, tc)) != NULL) { - - settc(t->index); - write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA); - } - - evpe(evpe_flags); - - return 0; -} - -EXPORT_SYMBOL(vpe_stop); - -/* I've done with it thank you */ -int vpe_free(vpe_handle vpe) -{ - struct vpe *v = vpe; - struct tc *t; - unsigned int evpe_flags; - - if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { - return -ENOEXEC; - } - - evpe_flags = dvpe(); - - /* Put MVPE's into 'configuration state' */ - set_c0_mvpcontrol(MVPCONTROL_VPC); - - settc(t->index); - write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA); - - /* halt the TC */ - write_tc_c0_tchalt(TCHALT_H); - mips_ihb(); - - /* mark the TC unallocated */ - write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A); - - v->state = VPE_STATE_UNUSED; - - clear_c0_mvpcontrol(MVPCONTROL_VPC); - evpe(evpe_flags); - - return 0; -} - -EXPORT_SYMBOL(vpe_free); - void *vpe_get_shared(int index) { - struct vpe *v; + struct vpe *v = get_vpe(index); - if ((v = get_vpe(index)) == NULL) + if (v == NULL) return NULL; return v->shared_ptr; } - EXPORT_SYMBOL(vpe_get_shared); int vpe_notify(int index, struct vpe_notifications *notify) { - struct vpe *v; + struct vpe *v = get_vpe(index); - if ((v = get_vpe(index)) == NULL) + if (v == NULL) return -1; list_add(¬ify->list, &v->notify); return 0; } - EXPORT_SYMBOL(vpe_notify); char *vpe_getcwd(int index) { - struct vpe *v; + struct vpe *v = get_vpe(index); - if ((v = get_vpe(index)) == NULL) + if (v == NULL) return NULL; return v->cwd; } - EXPORT_SYMBOL(vpe_getcwd); -static ssize_t store_kill(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - struct vpe *vpe = get_vpe(tclimit); - struct vpe_notifications *not; - - list_for_each_entry(not, &vpe->notify, list) { - not->stop(tclimit); - } - - release_progmem(vpe->load_addr); - cleanup_tc(get_tc(tclimit)); - vpe_stop(vpe); - vpe_free(vpe); - - return len; -} -static DEVICE_ATTR(kill, S_IWUSR, NULL, store_kill); - -static ssize_t ntcs_show(struct device *cd, struct device_attribute *attr, - char *buf) -{ - struct vpe *vpe = get_vpe(tclimit); - - return sprintf(buf, "%d\n", vpe->ntcs); -} - -static ssize_t ntcs_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - struct vpe *vpe = get_vpe(tclimit); - unsigned long new; - char *endp; - - new = simple_strtoul(buf, &endp, 0); - if (endp == buf) - goto out_einval; - - if (new == 0 || new > (hw_tcs - tclimit)) - goto out_einval; - - vpe->ntcs = new; - - return len; - -out_einval: - return -EINVAL; -} -static DEVICE_ATTR_RW(ntcs); - -static struct attribute *vpe_attrs[] = { - &dev_attr_kill.attr, - &dev_attr_ntcs.attr, - NULL, -}; -ATTRIBUTE_GROUPS(vpe); - -static void vpe_device_release(struct device *cd) -{ - kfree(cd); -} - -struct class vpe_class = { - .name = "vpe", - .owner = THIS_MODULE, - .dev_release = vpe_device_release, - .dev_groups = vpe_groups, -}; - -struct device vpe_device; - -static int __init vpe_module_init(void) -{ - unsigned int mtflags, vpflags; - unsigned long flags, val; - struct vpe *v = NULL; - struct tc *t; - int tc, err; - - if (!cpu_has_mipsmt) { - printk("VPE loader: not a MIPS MT capable processor\n"); - return -ENODEV; - } - - if (vpelimit == 0) { - printk(KERN_WARNING "No VPEs reserved for AP/SP, not " - "initializing VPE loader.\nPass maxvpes= argument as " - "kernel argument\n"); - - return -ENODEV; - } - - if (tclimit == 0) { - printk(KERN_WARNING "No TCs reserved for AP/SP, not " - "initializing VPE loader.\nPass maxtcs= argument as " - "kernel argument\n"); - - return -ENODEV; - } - - major = register_chrdev(0, module_name, &vpe_fops); - if (major < 0) { - printk("VPE loader: unable to register character device\n"); - return major; - } - - err = class_register(&vpe_class); - if (err) { - printk(KERN_ERR "vpe_class registration failed\n"); - goto out_chrdev; - } - - device_initialize(&vpe_device); - vpe_device.class = &vpe_class, - vpe_device.parent = NULL, - dev_set_name(&vpe_device, "vpe1"); - vpe_device.devt = MKDEV(major, minor); - err = device_add(&vpe_device); - if (err) { - printk(KERN_ERR "Adding vpe_device failed\n"); - goto out_class; - } - - local_irq_save(flags); - mtflags = dmt(); - vpflags = dvpe(); - - /* Put MVPE's into 'configuration state' */ - set_c0_mvpcontrol(MVPCONTROL_VPC); - - /* dump_mtregs(); */ - - val = read_c0_mvpconf0(); - hw_tcs = (val & MVPCONF0_PTC) + 1; - hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; - - for (tc = tclimit; tc < hw_tcs; tc++) { - /* - * Must re-enable multithreading temporarily or in case we - * reschedule send IPIs or similar we might hang. - */ - clear_c0_mvpcontrol(MVPCONTROL_VPC); - evpe(vpflags); - emt(mtflags); - local_irq_restore(flags); - t = alloc_tc(tc); - if (!t) { - err = -ENOMEM; - goto out; - } - - local_irq_save(flags); - mtflags = dmt(); - vpflags = dvpe(); - set_c0_mvpcontrol(MVPCONTROL_VPC); - - /* VPE's */ - if (tc < hw_tcs) { - settc(tc); - - if ((v = alloc_vpe(tc)) == NULL) { - printk(KERN_WARNING "VPE: unable to allocate VPE\n"); - - goto out_reenable; - } - - v->ntcs = hw_tcs - tclimit; - - /* add the tc to the list of this vpe's tc's. */ - list_add(&t->tc, &v->tc); - - /* deactivate all but vpe0 */ - if (tc >= tclimit) { - unsigned long tmp = read_vpe_c0_vpeconf0(); - - tmp &= ~VPECONF0_VPA; - - /* master VPE */ - tmp |= VPECONF0_MVP; - write_vpe_c0_vpeconf0(tmp); - } - - /* disable multi-threading with TC's */ - write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); - - if (tc >= vpelimit) { - /* - * Set config to be the same as vpe0, - * particularly kseg0 coherency alg - */ - write_vpe_c0_config(read_c0_config()); - } - } - - /* TC's */ - t->pvpe = v; /* set the parent vpe */ - - if (tc >= tclimit) { - unsigned long tmp; - - settc(tc); - - /* Any TC that is bound to VPE0 gets left as is - in case - we are running SMTC on VPE0. A TC that is bound to any - other VPE gets bound to VPE0, ideally I'd like to make - it homeless but it doesn't appear to let me bind a TC - to a non-existent VPE. Which is perfectly reasonable. - - The (un)bound state is visible to an EJTAG probe so may - notify GDB... - */ - - if (((tmp = read_tc_c0_tcbind()) & TCBIND_CURVPE)) { - /* tc is bound >vpe0 */ - write_tc_c0_tcbind(tmp & ~TCBIND_CURVPE); - - t->pvpe = get_vpe(0); /* set the parent vpe */ - } - - /* halt the TC */ - write_tc_c0_tchalt(TCHALT_H); - mips_ihb(); - - tmp = read_tc_c0_tcstatus(); - - /* mark not activated and not dynamically allocatable */ - tmp &= ~(TCSTATUS_A | TCSTATUS_DA); - tmp |= TCSTATUS_IXMT; /* interrupt exempt */ - write_tc_c0_tcstatus(tmp); - } - } - -out_reenable: - /* release config state */ - clear_c0_mvpcontrol(MVPCONTROL_VPC); - - evpe(vpflags); - emt(mtflags); - local_irq_restore(flags); - - return 0; - -out_class: - class_unregister(&vpe_class); -out_chrdev: - unregister_chrdev(major, module_name); - -out: - return err; -} - -static void __exit vpe_module_exit(void) -{ - struct vpe *v, *n; - - device_del(&vpe_device); - unregister_chrdev(major, module_name); - - /* No locking needed here */ - list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) { - if (v->state != VPE_STATE_UNUSED) - release_vpe(v); - } -} - module_init(vpe_module_init); module_exit(vpe_module_exit); MODULE_DESCRIPTION("MIPS VPE Loader"); diff --git a/arch/mips/kvm/kvm_mips.c b/arch/mips/kvm/kvm_mips.c index 73b34827826c20..da5186fbd77a3a 100644 --- a/arch/mips/kvm/kvm_mips.c +++ b/arch/mips/kvm/kvm_mips.c @@ -1001,7 +1001,6 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) hrtimer_init(&vcpu->arch.comparecount_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); vcpu->arch.comparecount_timer.function = kvm_mips_comparecount_wakeup; - kvm_mips_init_shadow_tlb(vcpu); return 0; } diff --git a/arch/mips/kvm/kvm_tlb.c b/arch/mips/kvm/kvm_tlb.c index c777dd36d4a8bf..50ab9c4d4a5dc6 100644 --- a/arch/mips/kvm/kvm_tlb.c +++ b/arch/mips/kvm/kvm_tlb.c @@ -10,7 +10,6 @@ * Authors: Sanjay Lal */ -#include #include #include #include @@ -25,6 +24,7 @@ #include #include #include +#include #undef CONFIG_MIPS_MT #include @@ -35,9 +35,6 @@ #define PRIx64 "llx" -/* Use VZ EntryHi.EHINV to invalidate TLB entries */ -#define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1))) - atomic_t kvm_mips_instance; EXPORT_SYMBOL(kvm_mips_instance); @@ -147,30 +144,6 @@ void kvm_mips_dump_guest_tlbs(struct kvm_vcpu *vcpu) } } -void kvm_mips_dump_shadow_tlbs(struct kvm_vcpu *vcpu) -{ - int i; - volatile struct kvm_mips_tlb tlb; - - printk("Shadow TLBs:\n"); - for (i = 0; i < KVM_MIPS_GUEST_TLB_SIZE; i++) { - tlb = vcpu->arch.shadow_tlb[smp_processor_id()][i]; - printk("TLB%c%3d Hi 0x%08lx ", - (tlb.tlb_lo0 | tlb.tlb_lo1) & MIPS3_PG_V ? ' ' : '*', - i, tlb.tlb_hi); - printk("Lo0=0x%09" PRIx64 " %c%c attr %lx ", - (uint64_t) mips3_tlbpfn_to_paddr(tlb.tlb_lo0), - (tlb.tlb_lo0 & MIPS3_PG_D) ? 'D' : ' ', - (tlb.tlb_lo0 & MIPS3_PG_G) ? 'G' : ' ', - (tlb.tlb_lo0 >> 3) & 7); - printk("Lo1=0x%09" PRIx64 " %c%c attr %lx sz=%lx\n", - (uint64_t) mips3_tlbpfn_to_paddr(tlb.tlb_lo1), - (tlb.tlb_lo1 & MIPS3_PG_D) ? 'D' : ' ', - (tlb.tlb_lo1 & MIPS3_PG_G) ? 'G' : ' ', - (tlb.tlb_lo1 >> 3) & 7, tlb.tlb_mask); - } -} - static int kvm_mips_map_page(struct kvm *kvm, gfn_t gfn) { int srcu_idx, err = 0; @@ -657,70 +630,6 @@ kvm_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu, cpu_context(cpu, mm) = asid_cache(cpu) = asid; } -void kvm_shadow_tlb_put(struct kvm_vcpu *vcpu) -{ - unsigned long flags; - unsigned long old_entryhi; - unsigned long old_pagemask; - int entry = 0; - int cpu = smp_processor_id(); - - local_irq_save(flags); - - old_entryhi = read_c0_entryhi(); - old_pagemask = read_c0_pagemask(); - - for (entry = 0; entry < current_cpu_data.tlbsize; entry++) { - write_c0_index(entry); - mtc0_tlbw_hazard(); - tlb_read(); - tlbw_use_hazard(); - - vcpu->arch.shadow_tlb[cpu][entry].tlb_hi = read_c0_entryhi(); - vcpu->arch.shadow_tlb[cpu][entry].tlb_lo0 = read_c0_entrylo0(); - vcpu->arch.shadow_tlb[cpu][entry].tlb_lo1 = read_c0_entrylo1(); - vcpu->arch.shadow_tlb[cpu][entry].tlb_mask = read_c0_pagemask(); - } - - write_c0_entryhi(old_entryhi); - write_c0_pagemask(old_pagemask); - mtc0_tlbw_hazard(); - - local_irq_restore(flags); - -} - -void kvm_shadow_tlb_load(struct kvm_vcpu *vcpu) -{ - unsigned long flags; - unsigned long old_ctx; - int entry; - int cpu = smp_processor_id(); - - local_irq_save(flags); - - old_ctx = read_c0_entryhi(); - - for (entry = 0; entry < current_cpu_data.tlbsize; entry++) { - write_c0_entryhi(vcpu->arch.shadow_tlb[cpu][entry].tlb_hi); - mtc0_tlbw_hazard(); - write_c0_entrylo0(vcpu->arch.shadow_tlb[cpu][entry].tlb_lo0); - write_c0_entrylo1(vcpu->arch.shadow_tlb[cpu][entry].tlb_lo1); - - write_c0_index(entry); - mtc0_tlbw_hazard(); - - tlb_write_indexed(); - tlbw_use_hazard(); - } - - tlbw_use_hazard(); - write_c0_entryhi(old_ctx); - mtc0_tlbw_hazard(); - local_irq_restore(flags); -} - - void kvm_local_flush_tlb_all(void) { unsigned long flags; @@ -749,30 +658,6 @@ void kvm_local_flush_tlb_all(void) local_irq_restore(flags); } -void kvm_mips_init_shadow_tlb(struct kvm_vcpu *vcpu) -{ - int cpu, entry; - - for_each_possible_cpu(cpu) { - for (entry = 0; entry < current_cpu_data.tlbsize; entry++) { - vcpu->arch.shadow_tlb[cpu][entry].tlb_hi = - UNIQUE_ENTRYHI(entry); - vcpu->arch.shadow_tlb[cpu][entry].tlb_lo0 = 0x0; - vcpu->arch.shadow_tlb[cpu][entry].tlb_lo1 = 0x0; - vcpu->arch.shadow_tlb[cpu][entry].tlb_mask = - read_c0_pagemask(); -#ifdef DEBUG - kvm_debug - ("shadow_tlb[%d][%d]: tlb_hi: %#lx, lo0: %#lx, lo1: %#lx\n", - cpu, entry, - vcpu->arch.shadow_tlb[cpu][entry].tlb_hi, - vcpu->arch.shadow_tlb[cpu][entry].tlb_lo0, - vcpu->arch.shadow_tlb[cpu][entry].tlb_lo1); -#endif - } - } -} - /* Restore ASID once we are scheduled back after preemption */ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { @@ -810,14 +695,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) vcpu->arch.last_sched_cpu, cpu, vcpu->vcpu_id); } - /* Only reload shadow host TLB if new ASIDs haven't been allocated */ -#if 0 - if ((atomic_read(&kvm_mips_instance) > 1) && !newasid) { - kvm_mips_flush_host_tlb(0); - kvm_shadow_tlb_load(vcpu); - } -#endif - if (!newasid) { /* If we preempted while the guest was executing, then reload the pre-empted ASID */ if (current->flags & PF_VCPU) { @@ -863,12 +740,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) vcpu->arch.preempt_entryhi = read_c0_entryhi(); vcpu->arch.last_sched_cpu = cpu; -#if 0 - if ((atomic_read(&kvm_mips_instance) > 1)) { - kvm_shadow_tlb_put(vcpu); - } -#endif - if (((cpu_context(cpu, current->mm) ^ asid_cache(cpu)) & ASID_VERSION_MASK)) { kvm_debug("%s: Dropping MMU Context: %#lx\n", __func__, @@ -930,10 +801,8 @@ uint32_t kvm_get_inst(uint32_t *opc, struct kvm_vcpu *vcpu) } EXPORT_SYMBOL(kvm_local_flush_tlb_all); -EXPORT_SYMBOL(kvm_shadow_tlb_put); EXPORT_SYMBOL(kvm_mips_handle_mapped_seg_tlb_fault); EXPORT_SYMBOL(kvm_mips_handle_commpage_tlb_fault); -EXPORT_SYMBOL(kvm_mips_init_shadow_tlb); EXPORT_SYMBOL(kvm_mips_dump_host_tlbs); EXPORT_SYMBOL(kvm_mips_handle_kseg0_tlb_fault); EXPORT_SYMBOL(kvm_mips_host_tlb_lookup); @@ -941,8 +810,6 @@ EXPORT_SYMBOL(kvm_mips_flush_host_tlb); EXPORT_SYMBOL(kvm_mips_guest_tlb_lookup); EXPORT_SYMBOL(kvm_mips_host_tlb_inv); EXPORT_SYMBOL(kvm_mips_translate_guest_kseg0_to_hpa); -EXPORT_SYMBOL(kvm_shadow_tlb_load); -EXPORT_SYMBOL(kvm_mips_dump_shadow_tlbs); EXPORT_SYMBOL(kvm_mips_dump_guest_tlbs); EXPORT_SYMBOL(kvm_get_inst); EXPORT_SYMBOL(kvm_arch_vcpu_load); diff --git a/arch/mips/lantiq/xway/clk.c b/arch/mips/lantiq/xway/clk.c index 1ab576dc9bd1ad..8750dc0a1bf678 100644 --- a/arch/mips/lantiq/xway/clk.c +++ b/arch/mips/lantiq/xway/clk.c @@ -8,7 +8,6 @@ #include #include -#include #include #include diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c index 08f7ebd9c7746c..78a91fa41944d3 100644 --- a/arch/mips/lantiq/xway/dma.c +++ b/arch/mips/lantiq/xway/dma.c @@ -220,10 +220,6 @@ ltq_dma_init(struct platform_device *pdev) int i; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - panic("Failed to get dma resource"); - - /* remap dma register range */ ltq_dma_membase = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(ltq_dma_membase)) panic("Failed to remap dma resource"); diff --git a/arch/mips/lasat/at93c.c b/arch/mips/lasat/at93c.c index 793e234719a66c..942f32b91d12da 100644 --- a/arch/mips/lasat/at93c.c +++ b/arch/mips/lasat/at93c.c @@ -8,7 +8,6 @@ #include #include #include -#include #include "at93c.h" diff --git a/arch/mips/lasat/picvue.c b/arch/mips/lasat/picvue.c index 7eb334892693db..d613b97cd513be 100644 --- a/arch/mips/lasat/picvue.c +++ b/arch/mips/lasat/picvue.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/arch/mips/lib/uncached.c b/arch/mips/lib/uncached.c index d8522f8e842a29..09d5deea747f2f 100644 --- a/arch/mips/lib/uncached.c +++ b/arch/mips/lib/uncached.c @@ -8,7 +8,6 @@ * Author: Maciej W. Rozycki */ -#include #include #include diff --git a/arch/mips/loongson/lemote-2f/clock.c b/arch/mips/loongson/lemote-2f/clock.c index 4dc2f5fa3f6737..aed32b88576cbe 100644 --- a/arch/mips/loongson/lemote-2f/clock.c +++ b/arch/mips/loongson/lemote-2f/clock.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index efe008846ed056..506925b2c3f366 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -417,14 +417,20 @@ static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr) case mm_mtc1_op: case mm_cfc1_op: case mm_ctc1_op: + case mm_mfhc1_op: + case mm_mthc1_op: if (insn.mm_fp1_format.op == mm_mfc1_op) op = mfc_op; else if (insn.mm_fp1_format.op == mm_mtc1_op) op = mtc_op; else if (insn.mm_fp1_format.op == mm_cfc1_op) op = cfc_op; - else + else if (insn.mm_fp1_format.op == mm_ctc1_op) op = ctc_op; + else if (insn.mm_fp1_format.op == mm_mfhc1_op) + op = mfhc_op; + else + op = mthc_op; mips32_insn.fp1_format.opcode = cop1_op; mips32_insn.fp1_format.op = op; mips32_insn.fp1_format.rt = @@ -853,20 +859,20 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, * In the Linux kernel, we support selection of FPR format on the * basis of the Status.FR bit. If an FPU is not present, the FR bit * is hardwired to zero, which would imply a 32-bit FPU even for - * 64-bit CPUs so we rather look at TIF_32BIT_REGS. + * 64-bit CPUs so we rather look at TIF_32BIT_FPREGS. * FPU emu is slow and bulky and optimizing this function offers fairly * sizeable benefits so we try to be clever and make this function return * a constant whenever possible, that is on 64-bit kernels without O32 - * compatibility enabled and on 32-bit kernels. + * compatibility enabled and on 32-bit without 64-bit FPU support. */ static inline int cop1_64bit(struct pt_regs *xcp) { #if defined(CONFIG_64BIT) && !defined(CONFIG_MIPS32_O32) return 1; -#elif defined(CONFIG_64BIT) && defined(CONFIG_MIPS32_O32) - return !test_thread_flag(TIF_32BIT_REGS); -#else +#elif defined(CONFIG_32BIT) && !defined(CONFIG_MIPS_O32_FP64_SUPPORT) return 0; +#else + return !test_thread_flag(TIF_32BIT_FPREGS); #endif } @@ -878,6 +884,10 @@ static inline int cop1_64bit(struct pt_regs *xcp) ctx->fpr[x & ~1] >> 32 << 32 | (u32)(si) : \ ctx->fpr[x & ~1] << 32 >> 32 | (u64)(si) << 32) +#define SIFROMHREG(si, x) ((si) = (int)(ctx->fpr[x] >> 32)) +#define SITOHREG(si, x) (ctx->fpr[x] = \ + ctx->fpr[x] << 32 >> 32 | (u64)(si) << 32) + #define DIFROMREG(di, x) ((di) = ctx->fpr[x & ~(cop1_64bit(xcp) == 0)]) #define DITOREG(di, x) (ctx->fpr[x & ~(cop1_64bit(xcp) == 0)] = (di)) @@ -1055,6 +1065,25 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; #endif + case mfhc_op: + if (!cpu_has_mips_r2) + goto sigill; + + /* copregister rd -> gpr[rt] */ + if (MIPSInst_RT(ir) != 0) { + SIFROMHREG(xcp->regs[MIPSInst_RT(ir)], + MIPSInst_RD(ir)); + } + break; + + case mthc_op: + if (!cpu_has_mips_r2) + goto sigill; + + /* copregister rd <- gpr[rt] */ + SITOHREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); + break; + case mfc_op: /* copregister rd -> gpr[rt] */ if (MIPSInst_RT(ir) != 0) { @@ -1263,6 +1292,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, #endif default: +sigill: return SIGILL; } diff --git a/arch/mips/math-emu/kernel_linkage.c b/arch/mips/math-emu/kernel_linkage.c index 1c586575fe172c..3aeae07ed5b8db 100644 --- a/arch/mips/math-emu/kernel_linkage.c +++ b/arch/mips/math-emu/kernel_linkage.c @@ -89,8 +89,9 @@ int fpu_emulator_save_context32(struct sigcontext32 __user *sc) { int i; int err = 0; + int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; - for (i = 0; i < 32; i+=2) { + for (i = 0; i < 32; i += inc) { err |= __put_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]); } @@ -103,8 +104,9 @@ int fpu_emulator_restore_context32(struct sigcontext32 __user *sc) { int i; int err = 0; + int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; - for (i = 0; i < 32; i+=2) { + for (i = 0; i < 32; i += inc) { err |= __get_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]); } diff --git a/arch/mips/mm/c-octeon.c b/arch/mips/mm/c-octeon.c index c8efdb5b6ee029..f41a5c5b0865ec 100644 --- a/arch/mips/mm/c-octeon.c +++ b/arch/mips/mm/c-octeon.c @@ -6,7 +6,6 @@ * Copyright (C) 2005-2007 Cavium Networks */ #include -#include #include #include #include diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c index 2fcde0c8ea029c..135ec313c1f659 100644 --- a/arch/mips/mm/c-r3k.c +++ b/arch/mips/mm/c-r3k.c @@ -9,7 +9,6 @@ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov * Copyright (C) 2001, 2004, 2007 Maciej W. Rozycki */ -#include #include #include #include diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 49e572d879e134..c14259edd53f40 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1020,10 +1020,14 @@ static void probe_pcache(void) */ config1 = read_c0_config1(); - if ((lsize = ((config1 >> 19) & 7))) - c->icache.linesz = 2 << lsize; - else - c->icache.linesz = lsize; + lsize = (config1 >> 19) & 7; + + /* IL == 7 is reserved */ + if (lsize == 7) + panic("Invalid icache line size"); + + c->icache.linesz = lsize ? 2 << lsize : 0; + c->icache.sets = 32 << (((config1 >> 22) + 1) & 7); c->icache.ways = 1 + ((config1 >> 16) & 7); @@ -1040,10 +1044,14 @@ static void probe_pcache(void) */ c->dcache.flags = 0; - if ((lsize = ((config1 >> 10) & 7))) - c->dcache.linesz = 2 << lsize; - else - c->dcache.linesz= lsize; + lsize = (config1 >> 10) & 7; + + /* DL == 7 is reserved */ + if (lsize == 7) + panic("Invalid dcache line size"); + + c->dcache.linesz = lsize ? 2 << lsize : 0; + c->dcache.sets = 32 << (((config1 >> 13) + 1) & 7); c->dcache.ways = 1 + ((config1 >> 7) & 7); @@ -1105,6 +1113,8 @@ static void probe_pcache(void) case CPU_34K: case CPU_74K: case CPU_1004K: + case CPU_INTERAPTIV: + case CPU_PROAPTIV: if (current_cpu_type() == CPU_74K) alias_74k_erratum(c); if ((read_c0_config7() & (1 << 16))) { diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 15f813c303b45b..fde7e56d13fe3c 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -8,7 +8,6 @@ */ #include #include -#include #include #include #include diff --git a/arch/mips/mm/cex-sb1.S b/arch/mips/mm/cex-sb1.S index 191cf6e0c7258b..5d5f29681a21c0 100644 --- a/arch/mips/mm/cex-sb1.S +++ b/arch/mips/mm/cex-sb1.S @@ -15,7 +15,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include #include #include diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index 2e941856225875..44b6dff5aba2a0 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -23,6 +23,7 @@ #include +#ifdef CONFIG_DMA_MAYBE_COHERENT int coherentio = 0; /* User defined DMA coherency from command line. */ EXPORT_SYMBOL_GPL(coherentio); int hw_coherentio = 0; /* Actual hardware supported DMA coherency setting. */ @@ -42,6 +43,7 @@ static int __init setnocoherentio(char *str) return 0; } early_param("nocoherentio", setnocoherentio); +#endif static inline struct page *dma_addr_to_page(struct device *dev, dma_addr_t dma_addr) diff --git a/arch/mips/mm/hugetlbpage.c b/arch/mips/mm/hugetlbpage.c index 01fda4419ed09d..77e0ae036e7c9e 100644 --- a/arch/mips/mm/hugetlbpage.c +++ b/arch/mips/mm/hugetlbpage.c @@ -11,7 +11,6 @@ * Copyright (C) 2008, 2009 Cavium Networks, Inc. */ -#include #include #include #include diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 12156176c7caa9..6b59617760c193 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -171,8 +171,6 @@ void *kmap_coherent(struct page *page, unsigned long addr) return (void*) vaddr; } -#define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1))) - void kunmap_coherent(void) { #ifndef CONFIG_MIPS_MT_SMTC diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c index cbd81d17793a71..58033c44690d75 100644 --- a/arch/mips/mm/page.c +++ b/arch/mips/mm/page.c @@ -8,7 +8,6 @@ * Copyright (C) 2008 Thiemo Seufer * Copyright (C) 2012 MIPS Technologies, Inc. */ -#include #include #include #include diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c index 08d05aee8788be..7a56aee5fce70e 100644 --- a/arch/mips/mm/sc-mips.c +++ b/arch/mips/mm/sc-mips.c @@ -76,6 +76,8 @@ static inline int mips_sc_is_activated(struct cpuinfo_mips *c) case CPU_34K: case CPU_74K: case CPU_1004K: + case CPU_INTERAPTIV: + case CPU_PROAPTIV: case CPU_BMIPS5000: if (config2 & (1 << 12)) return 0; diff --git a/arch/mips/mm/sc-rm7k.c b/arch/mips/mm/sc-rm7k.c index aaffbba3370640..9ac1efcfbcc7f7 100644 --- a/arch/mips/mm/sc-rm7k.c +++ b/arch/mips/mm/sc-rm7k.c @@ -6,7 +6,6 @@ #undef DEBUG -#include #include #include #include diff --git a/arch/mips/mm/tlb-r3k.c b/arch/mips/mm/tlb-r3k.c index 9aca10994cd22b..d657493ef561ef 100644 --- a/arch/mips/mm/tlb-r3k.c +++ b/arch/mips/mm/tlb-r3k.c @@ -10,7 +10,6 @@ * Copyright (C) 2002 Ralf Baechle * Copyright (C) 2002 Maciej W. Rozycki */ -#include #include #include #include diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index da3b0b9c9eae0a..ae4ca24507072f 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -20,16 +20,11 @@ #include #include #include +#include #include extern void build_tlb_refill_handler(void); -/* - * Make sure all entries differ. If they're not different - * MIPS32 will take revenge ... - */ -#define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1))) - /* Atomicity and interruptability */ #ifdef CONFIG_MIPS_MT_SMTC @@ -77,7 +72,7 @@ void local_flush_tlb_all(void) { unsigned long flags; unsigned long old_ctx; - int entry; + int entry, ftlbhighset; ENTER_CRITICAL(flags); /* Save old context and create impossible VPN2 value */ @@ -88,13 +83,30 @@ void local_flush_tlb_all(void) entry = read_c0_wired(); /* Blast 'em all away. */ - while (entry < current_cpu_data.tlbsize) { - /* Make sure all entries differ. */ - write_c0_entryhi(UNIQUE_ENTRYHI(entry)); - write_c0_index(entry); - mtc0_tlbw_hazard(); - tlb_write_indexed(); - entry++; + if (cpu_has_tlbinv) { + if (current_cpu_data.tlbsizevtlb) { + write_c0_index(0); + mtc0_tlbw_hazard(); + tlbinvf(); /* invalidate VTLB */ + } + ftlbhighset = current_cpu_data.tlbsizevtlb + + current_cpu_data.tlbsizeftlbsets; + for (entry = current_cpu_data.tlbsizevtlb; + entry < ftlbhighset; + entry++) { + write_c0_index(entry); + mtc0_tlbw_hazard(); + tlbinvf(); /* invalidate one FTLB set */ + } + } else { + while (entry < current_cpu_data.tlbsize) { + /* Make sure all entries differ. */ + write_c0_entryhi(UNIQUE_ENTRYHI(entry)); + write_c0_index(entry); + mtc0_tlbw_hazard(); + tlb_write_indexed(); + entry++; + } } tlbw_use_hazard(); write_c0_entryhi(old_ctx); @@ -133,7 +145,9 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, start = round_down(start, PAGE_SIZE << 1); end = round_up(end, PAGE_SIZE << 1); size = (end - start) >> (PAGE_SHIFT + 1); - if (size <= current_cpu_data.tlbsize/2) { + if (size <= (current_cpu_data.tlbsizeftlbsets ? + current_cpu_data.tlbsize / 8 : + current_cpu_data.tlbsize / 2)) { int oldpid = read_c0_entryhi(); int newpid = cpu_asid(cpu, mm); @@ -172,7 +186,9 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) ENTER_CRITICAL(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; size = (size + 1) >> 1; - if (size <= current_cpu_data.tlbsize / 2) { + if (size <= (current_cpu_data.tlbsizeftlbsets ? + current_cpu_data.tlbsize / 8 : + current_cpu_data.tlbsize / 2)) { int pid = read_c0_entryhi(); start &= (PAGE_MASK << 1); diff --git a/arch/mips/mm/tlb-r8k.c b/arch/mips/mm/tlb-r8k.c index 6a99733a44402b..138a2ec7cc6b77 100644 --- a/arch/mips/mm/tlb-r8k.c +++ b/arch/mips/mm/tlb-r8k.c @@ -8,7 +8,6 @@ * Carsten Langgaard, carstenl@mips.com * Copyright (C) 2002 MIPS Technologies, Inc. All rights reserved. */ -#include #include #include #include diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 183f2b583e4dbc..b234b1b5ccada6 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -510,6 +509,7 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l, switch (current_cpu_type()) { case CPU_M14KC: case CPU_74K: + case CPU_PROAPTIV: break; default: diff --git a/arch/mips/mm/uasm-micromips.c b/arch/mips/mm/uasm-micromips.c index 060000fa653c3c..b8d580ca02e53f 100644 --- a/arch/mips/mm/uasm-micromips.c +++ b/arch/mips/mm/uasm-micromips.c @@ -15,7 +15,6 @@ #include #include -#include #include #include diff --git a/arch/mips/mm/uasm-mips.c b/arch/mips/mm/uasm-mips.c index 0c724589854e72..3abd609518c970 100644 --- a/arch/mips/mm/uasm-mips.c +++ b/arch/mips/mm/uasm-mips.c @@ -15,7 +15,6 @@ #include #include -#include #include #include diff --git a/arch/mips/mti-malta/Makefile b/arch/mips/mti-malta/Makefile index 72fdedbf76db8b..eae0ba3876d922 100644 --- a/arch/mips/mti-malta/Makefile +++ b/arch/mips/mti-malta/Makefile @@ -9,7 +9,5 @@ obj-y := malta-amon.o malta-display.o malta-init.o \ malta-int.o malta-memory.o malta-platform.o \ malta-reset.o malta-setup.o malta-time.o -obj-$(CONFIG_EARLY_PRINTK) += malta-console.o - # FIXME FIXME FIXME obj-$(CONFIG_MIPS_MT_SMTC) += malta-smtc.o diff --git a/arch/mips/mti-malta/malta-amon.c b/arch/mips/mti-malta/malta-amon.c index 1e4784458016eb..592ac0427426ac 100644 --- a/arch/mips/mti-malta/malta-amon.c +++ b/arch/mips/mti-malta/malta-amon.c @@ -1,30 +1,20 @@ /* - * Copyright (C) 2007 MIPS Technologies, Inc. - * All rights reserved. - - * This program is free software; you can distribute 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 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. + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * Copyright (C) 2007 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2013 Imagination Technologies Ltd. * - * Arbitrary Monitor interface + * Arbitrary Monitor Interface */ - #include -#include #include #include -#include #include +#include +#include int amon_cpu_avail(int cpu) { @@ -48,7 +38,7 @@ int amon_cpu_avail(int cpu) return 1; } -void amon_cpu_start(int cpu, +int amon_cpu_start(int cpu, unsigned long pc, unsigned long sp, unsigned long gp, unsigned long a0) { @@ -56,10 +46,10 @@ void amon_cpu_start(int cpu, (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH); if (!amon_cpu_avail(cpu)) - return; + return -1; if (cpu == smp_processor_id()) { pr_debug("launch: I am cpu%d!\n", cpu); - return; + return -1; } launch += cpu; @@ -78,4 +68,21 @@ void amon_cpu_start(int cpu, ; smp_rmb(); /* Target will be updating flags soon */ pr_debug("launch: cpu%d gone!\n", cpu); + + return 0; +} + +#ifdef CONFIG_MIPS_VPE_LOADER +int vpe_run(struct vpe *v) +{ + struct vpe_notifications *n; + + if (amon_cpu_start(aprp_cpu_index(), v->__start, 0, 0, 0) < 0) + return -1; + + list_for_each_entry(n, &v->notify, list) + n->start(VPE_MODULE_MINOR); + + return 0; } +#endif diff --git a/arch/mips/mti-malta/malta-console.c b/arch/mips/mti-malta/malta-console.c deleted file mode 100644 index 43bcfb4f816700..00000000000000 --- a/arch/mips/mti-malta/malta-console.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. - * - * This program is free software; you can distribute 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 it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Putting things on the screen/serial line using YAMONs facilities. - */ -#include -#include -#include -#include - - -#define PORT(offset) (0x3f8 + (offset)) - - -static inline unsigned int serial_in(int offset) -{ - return inb(PORT(offset)); -} - -static inline void serial_out(int offset, int value) -{ - outb(value, PORT(offset)); -} - -int prom_putchar(char c) -{ - while ((serial_in(UART_LSR) & UART_LSR_THRE) == 0) - ; - - serial_out(UART_TX, c); - - return 1; -} diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c index ff8caffd3266ea..fcebfced26d0c9 100644 --- a/arch/mips/mti-malta/malta-init.c +++ b/arch/mips/mti-malta/malta-init.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -44,32 +45,39 @@ static void __init console_config(void) char parity = '\0', bits = '\0', flow = '\0'; char *s; - if ((strstr(fw_getcmdline(), "console=")) == NULL) { - s = fw_getenv("modetty0"); - if (s) { - while (*s >= '0' && *s <= '9') - baud = baud*10 + *s++ - '0'; - if (*s == ',') - s++; - if (*s) - parity = *s++; - if (*s == ',') - s++; - if (*s) - bits = *s++; - if (*s == ',') - s++; - if (*s == 'h') - flow = 'r'; - } - if (baud == 0) - baud = 38400; - if (parity != 'n' && parity != 'o' && parity != 'e') - parity = 'n'; - if (bits != '7' && bits != '8') - bits = '8'; - if (flow == '\0') + s = fw_getenv("modetty0"); + if (s) { + while (*s >= '0' && *s <= '9') + baud = baud*10 + *s++ - '0'; + if (*s == ',') + s++; + if (*s) + parity = *s++; + if (*s == ',') + s++; + if (*s) + bits = *s++; + if (*s == ',') + s++; + if (*s == 'h') flow = 'r'; + } + if (baud == 0) + baud = 38400; + if (parity != 'n' && parity != 'o' && parity != 'e') + parity = 'n'; + if (bits != '7' && bits != '8') + bits = '8'; + if (flow == '\0') + flow = 'r'; + + if ((strstr(fw_getcmdline(), "earlycon=")) == NULL) { + sprintf(console_string, "uart8250,io,0x3f8,%d%c%c", baud, + parity, bits); + setup_early_serial8250_console(console_string); + } + + if ((strstr(fw_getcmdline(), "console=")) == NULL) { sprintf(console_string, " console=ttyS0,%d%c%c%c", baud, parity, bits, flow); strcat(fw_getcmdline(), console_string); diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c index 0892575f829da5..ca3e3a46a42f90 100644 --- a/arch/mips/mti-malta/malta-int.c +++ b/arch/mips/mti-malta/malta-int.c @@ -1,25 +1,16 @@ /* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * * Carsten Langgaard, carstenl@mips.com * Copyright (C) 2000, 2001, 2004 MIPS Technologies, Inc. * Copyright (C) 2001 Ralf Baechle - * - * This program is free software; you can distribute 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 it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * Copyright (C) 2013 Imagination Technologies Ltd. * * Routines for generic manipulation of the interrupts found on the MIPS - * Malta board. - * The interrupt controller is located in the South Bridge a PIIX4 device - * with two internal 82C95 interrupt controllers. + * Malta board. The interrupt controller is located in the South Bridge + * a PIIX4 device with two internal 82C95 interrupt controllers. */ #include #include @@ -44,6 +35,7 @@ #include #include #include +#include int gcmp_present = -1; static unsigned long _msc01_biu_base; @@ -90,7 +82,7 @@ static inline int mips_pcibios_iack(void) BONITO_PCIMAP_CFG = 0; break; default: - printk(KERN_WARNING "Unknown system controller.\n"); + pr_emerg("Unknown system controller.\n"); return -1; } return irq; @@ -126,6 +118,11 @@ static void malta_hw0_irqdispatch(void) } do_IRQ(MALTA_INT_BASE + irq); + +#ifdef MIPS_VPE_APSP_API + if (aprp_hook) + aprp_hook(); +#endif } static void malta_ipi_irqdispatch(void) @@ -149,11 +146,11 @@ static void corehi_irqdispatch(void) unsigned int intrcause, datalo, datahi; struct pt_regs *regs = get_irq_regs(); - printk(KERN_EMERG "CoreHI interrupt, shouldn't happen, we die here!\n"); - printk(KERN_EMERG "epc : %08lx\nStatus: %08lx\n" - "Cause : %08lx\nbadVaddr : %08lx\n", - regs->cp0_epc, regs->cp0_status, - regs->cp0_cause, regs->cp0_badvaddr); + pr_emerg("CoreHI interrupt, shouldn't happen, we die here!\n"); + pr_emerg("epc : %08lx\nStatus: %08lx\n" + "Cause : %08lx\nbadVaddr : %08lx\n", + regs->cp0_epc, regs->cp0_status, + regs->cp0_cause, regs->cp0_badvaddr); /* Read all the registers and then print them as there is a problem with interspersed printk's upsetting the Bonito controller. @@ -171,8 +168,8 @@ static void corehi_irqdispatch(void) intrcause = GT_READ(GT_INTRCAUSE_OFS); datalo = GT_READ(GT_CPUERR_ADDRLO_OFS); datahi = GT_READ(GT_CPUERR_ADDRHI_OFS); - printk(KERN_EMERG "GT_INTRCAUSE = %08x\n", intrcause); - printk(KERN_EMERG "GT_CPUERR_ADDR = %02x%08x\n", + pr_emerg("GT_INTRCAUSE = %08x\n", intrcause); + pr_emerg("GT_CPUERR_ADDR = %02x%08x\n", datahi, datalo); break; case MIPS_REVISION_SCON_BONITO: @@ -184,14 +181,14 @@ static void corehi_irqdispatch(void) intedge = BONITO_INTEDGE; intsteer = BONITO_INTSTEER; pcicmd = BONITO_PCICMD; - printk(KERN_EMERG "BONITO_INTISR = %08x\n", intisr); - printk(KERN_EMERG "BONITO_INTEN = %08x\n", inten); - printk(KERN_EMERG "BONITO_INTPOL = %08x\n", intpol); - printk(KERN_EMERG "BONITO_INTEDGE = %08x\n", intedge); - printk(KERN_EMERG "BONITO_INTSTEER = %08x\n", intsteer); - printk(KERN_EMERG "BONITO_PCICMD = %08x\n", pcicmd); - printk(KERN_EMERG "BONITO_PCIBADADDR = %08x\n", pcibadaddr); - printk(KERN_EMERG "BONITO_PCIMSTAT = %08x\n", pcimstat); + pr_emerg("BONITO_INTISR = %08x\n", intisr); + pr_emerg("BONITO_INTEN = %08x\n", inten); + pr_emerg("BONITO_INTPOL = %08x\n", intpol); + pr_emerg("BONITO_INTEDGE = %08x\n", intedge); + pr_emerg("BONITO_INTSTEER = %08x\n", intsteer); + pr_emerg("BONITO_PCICMD = %08x\n", pcicmd); + pr_emerg("BONITO_PCIBADADDR = %08x\n", pcibadaddr); + pr_emerg("BONITO_PCIMSTAT = %08x\n", pcimstat); break; } @@ -313,6 +310,11 @@ static void ipi_call_dispatch(void) static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) { +#ifdef MIPS_VPE_APSP_API + if (aprp_hook) + aprp_hook(); +#endif + scheduler_ipi(); return IRQ_HANDLED; @@ -365,13 +367,13 @@ static struct irqaction corehi_irqaction = { .flags = IRQF_NO_THREAD, }; -static msc_irqmap_t __initdata msc_irqmap[] = { +static msc_irqmap_t msc_irqmap[] __initdata = { {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0}, {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0}, }; -static int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap); +static int msc_nr_irqs __initdata = ARRAY_SIZE(msc_irqmap); -static msc_irqmap_t __initdata msc_eicirqmap[] = { +static msc_irqmap_t msc_eicirqmap[] __initdata = { {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0}, {MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0}, {MSC01E_INT_I8259A, MSC01_IRQ_LEVEL, 0}, @@ -384,7 +386,7 @@ static msc_irqmap_t __initdata msc_eicirqmap[] = { {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0} }; -static int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap); +static int msc_nr_eicirqs __initdata = ARRAY_SIZE(msc_eicirqmap); /* * This GIC specific tabular array defines the association between External @@ -431,9 +433,12 @@ int __init gcmp_probe(unsigned long addr, unsigned long size) if (gcmp_present >= 0) return gcmp_present; - _gcmp_base = (unsigned long) ioremap_nocache(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ); - _msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE, MSC01_BIU_ADDRSPACE_SZ); - gcmp_present = (GCMPGCB(GCMPB) & GCMP_GCB_GCMPB_GCMPBASE_MSK) == GCMP_BASE_ADDR; + _gcmp_base = (unsigned long) ioremap_nocache(GCMP_BASE_ADDR, + GCMP_ADDRSPACE_SZ); + _msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE, + MSC01_BIU_ADDRSPACE_SZ); + gcmp_present = ((GCMPGCB(GCMPB) & GCMP_GCB_GCMPB_GCMPBASE_MSK) == + GCMP_BASE_ADDR); if (gcmp_present) pr_debug("GCMP present\n"); @@ -443,9 +448,8 @@ int __init gcmp_probe(unsigned long addr, unsigned long size) /* Return the number of IOCU's present */ int __init gcmp_niocu(void) { - return gcmp_present ? - (GCMPGCB(GC) & GCMP_GCB_GC_NUMIOCU_MSK) >> GCMP_GCB_GC_NUMIOCU_SHF : - 0; + return gcmp_present ? ((GCMPGCB(GC) & GCMP_GCB_GC_NUMIOCU_MSK) >> + GCMP_GCB_GC_NUMIOCU_SHF) : 0; } /* Set GCMP region attributes */ @@ -594,11 +598,14 @@ void __init arch_init_irq(void) set_vi_handler(MIPSCPU_INT_IPI1, malta_ipi_irqdispatch); } /* Argh.. this really needs sorting out.. */ - printk("CPU%d: status register was %08x\n", smp_processor_id(), read_c0_status()); + pr_info("CPU%d: status register was %08x\n", + smp_processor_id(), read_c0_status()); write_c0_status(read_c0_status() | STATUSF_IP3 | STATUSF_IP4); - printk("CPU%d: status register now %08x\n", smp_processor_id(), read_c0_status()); + pr_info("CPU%d: status register now %08x\n", + smp_processor_id(), read_c0_status()); write_c0_status(0x1100dc00); - printk("CPU%d: status register frc %08x\n", smp_processor_id(), read_c0_status()); + pr_info("CPU%d: status register frc %08x\n", + smp_processor_id(), read_c0_status()); for (i = 0; i < nr_cpu_ids; i++) { arch_init_ipiirq(MIPS_GIC_IRQ_BASE + GIC_RESCHED_INT(i), &irq_resched); @@ -616,11 +623,15 @@ void __init arch_init_irq(void) cpu_ipi_call_irq = MSC01E_INT_SW1; } else { if (cpu_has_vint) { - set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch); - set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch); + set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, + ipi_resched_dispatch); + set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, + ipi_call_dispatch); } - cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ; - cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ; + cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + + MIPS_CPU_IPI_RESCHED_IRQ; + cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + + MIPS_CPU_IPI_CALL_IRQ; } arch_init_ipiirq(cpu_ipi_resched_irq, &irq_resched); arch_init_ipiirq(cpu_ipi_call_irq, &irq_call); @@ -630,9 +641,7 @@ void __init arch_init_irq(void) void malta_be_init(void) { - if (gcmp_present) { - /* Could change CM error mask register */ - } + /* Could change CM error mask register. */ } @@ -712,14 +721,14 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup) if (cause < 16) { unsigned long cca_bits = (cm_error >> 15) & 7; unsigned long tr_bits = (cm_error >> 12) & 7; - unsigned long mcmd_bits = (cm_error >> 7) & 0x1f; + unsigned long cmd_bits = (cm_error >> 7) & 0x1f; unsigned long stag_bits = (cm_error >> 3) & 15; unsigned long sport_bits = (cm_error >> 0) & 7; snprintf(buf, sizeof(buf), "CCA=%lu TR=%s MCmd=%s STag=%lu " "SPort=%lu\n", - cca_bits, tr[tr_bits], mcmd[mcmd_bits], + cca_bits, tr[tr_bits], mcmd[cmd_bits], stag_bits, sport_bits); } else { /* glob state & sresp together */ @@ -728,7 +737,7 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup) unsigned long c1_bits = (cm_error >> 12) & 7; unsigned long c0_bits = (cm_error >> 9) & 7; unsigned long sc_bit = (cm_error >> 8) & 1; - unsigned long mcmd_bits = (cm_error >> 3) & 0x1f; + unsigned long cmd_bits = (cm_error >> 3) & 0x1f; unsigned long sport_bits = (cm_error >> 0) & 7; snprintf(buf, sizeof(buf), "C3=%s C2=%s C1=%s C0=%s SC=%s " @@ -736,16 +745,16 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup) core[c3_bits], core[c2_bits], core[c1_bits], core[c0_bits], sc_bit ? "True" : "False", - mcmd[mcmd_bits], sport_bits); + mcmd[cmd_bits], sport_bits); } ocause = (cm_other & GCMP_GCB_GMEO_ERROR_2ND_MSK) >> GCMP_GCB_GMEO_ERROR_2ND_SHF; - printk("CM_ERROR=%08lx %s <%s>\n", cm_error, + pr_err("CM_ERROR=%08lx %s <%s>\n", cm_error, causes[cause], buf); - printk("CM_ADDR =%08lx\n", cm_addr); - printk("CM_OTHER=%08lx %s\n", cm_other, causes[ocause]); + pr_err("CM_ADDR =%08lx\n", cm_addr); + pr_err("CM_OTHER=%08lx %s\n", cm_other, causes[ocause]); /* reprime cause register */ GCMPGCB(GCMEC) = 0; diff --git a/arch/mips/mti-malta/malta-platform.c b/arch/mips/mti-malta/malta-platform.c index 132f8663825e4b..e1dd1c1d3fdeed 100644 --- a/arch/mips/mti-malta/malta-platform.c +++ b/arch/mips/mti-malta/malta-platform.c @@ -47,6 +47,7 @@ static struct plat_serial8250_port uart8250_data[] = { SMC_PORT(0x3F8, 4), SMC_PORT(0x2F8, 3), +#ifndef CONFIG_MIPS_CMP { .mapbase = 0x1f000900, /* The CBUS UART */ .irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB2, @@ -55,6 +56,7 @@ static struct plat_serial8250_port uart8250_data[] = { .flags = CBUS_UART_FLAGS, .regshift = 3, }, +#endif { }, }; diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c index a18af5fce67eb7..31900991214241 100644 --- a/arch/mips/mti-malta/malta-time.c +++ b/arch/mips/mti-malta/malta-time.c @@ -42,8 +42,6 @@ #include #include -unsigned long cpu_khz; - static int mips_cpu_timer_irq; static int mips_cpu_perf_irq; extern int cp0_perfcount_irq; @@ -168,11 +166,24 @@ unsigned int get_c0_compare_int(void) return mips_cpu_timer_irq; } +static void __init init_rtc(void) +{ + /* stop the clock whilst setting it up */ + CMOS_WRITE(RTC_SET | RTC_24H, RTC_CONTROL); + + /* 32KHz time base */ + CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT); + + /* start the clock */ + CMOS_WRITE(RTC_24H, RTC_CONTROL); +} + void __init plat_time_init(void) { unsigned int prid = read_c0_prid() & (PRID_COMP_MASK | PRID_IMP_MASK); unsigned int freq; + init_rtc(); estimate_frequencies(); freq = mips_hpt_frequency; @@ -182,7 +193,6 @@ void __init plat_time_init(void) freq = freqround(freq, 5000); printk("CPU frequency %d.%02d MHz\n", freq/1000000, (freq%1000000)*100/1000000); - cpu_khz = freq / 1000; mips_scroll_message(); diff --git a/arch/mips/mti-sead3/Makefile b/arch/mips/mti-sead3/Makefile index be114209217cc5..071786fa234ba5 100644 --- a/arch/mips/mti-sead3/Makefile +++ b/arch/mips/mti-sead3/Makefile @@ -21,5 +21,7 @@ obj-$(CONFIG_EARLY_PRINTK) += sead3-console.o obj-$(CONFIG_USB_EHCI_HCD) += sead3-ehci.o obj-$(CONFIG_OF) += sead3.dtb.o +CFLAGS_sead3-setup.o = -I$(src)/../../../scripts/dtc/libfdt + $(obj)/%.dtb: $(obj)/%.dts $(call if_changed,dtc) diff --git a/arch/mips/mti-sead3/sead3-pic32-bus.c b/arch/mips/mti-sead3/sead3-pic32-bus.c index eb2bf936d102b3..3b12aa5a7c88f3 100644 --- a/arch/mips/mti-sead3/sead3-pic32-bus.c +++ b/arch/mips/mti-sead3/sead3-pic32-bus.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/arch/mips/mti-sead3/sead3-setup.c b/arch/mips/mti-sead3/sead3-setup.c index 928ba84c8a7859..bf7fe48bf2f927 100644 --- a/arch/mips/mti-sead3/sead3-setup.c +++ b/arch/mips/mti-sead3/sead3-setup.c @@ -4,13 +4,15 @@ * for more details. * * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2013 Imagination Technologies Ltd. */ #include +#include #include #include -#include #include +#include #include @@ -19,8 +21,73 @@ const char *get_system_type(void) return "MIPS SEAD3"; } +static uint32_t get_memsize_from_cmdline(void) +{ + int memsize = 0; + char *p = arcs_cmdline; + char *s = "memsize="; + + p = strstr(p, s); + if (p) { + p += strlen(s); + memsize = memparse(p, NULL); + } + + return memsize; +} + +static uint32_t get_memsize_from_env(void) +{ + int memsize = 0; + char *p; + + p = fw_getenv("memsize"); + if (p) + memsize = memparse(p, NULL); + + return memsize; +} + +static uint32_t get_memsize(void) +{ + uint32_t memsize; + + memsize = get_memsize_from_cmdline(); + if (memsize) + return memsize; + + return get_memsize_from_env(); +} + +static void __init parse_memsize_param(void) +{ + int offset; + const uint64_t *prop_value; + int prop_len; + uint32_t memsize = get_memsize(); + + if (!memsize) + return; + + offset = fdt_path_offset(&__dtb_start, "/memory"); + if (offset > 0) { + uint64_t new_value; + /* + * reg contains 2 32-bits BE values, offset and size. We just + * want to replace the size value without affecting the offset + */ + prop_value = fdt_getprop(&__dtb_start, offset, "reg", &prop_len); + new_value = be64_to_cpu(*prop_value); + new_value = (new_value & ~0xffffffffllu) | memsize; + fdt_setprop_inplace_u64(&__dtb_start, offset, "reg", new_value); + } +} + void __init plat_mem_setup(void) { + /* allow command line/bootloader env to override memory size in DT */ + parse_memsize_param(); + /* * Load the builtin devicetree. This causes the chosen node to be * parsed resulting in our memory appearing @@ -30,16 +97,15 @@ void __init plat_mem_setup(void) void __init device_tree_init(void) { - unsigned long base, size; - if (!initial_boot_params) return; - base = virt_to_phys((void *)initial_boot_params); - size = be32_to_cpu(initial_boot_params->totalsize); - - /* Before we do anything, lets reserve the dt blob */ - reserve_bootmem(base, size, BOOTMEM_DEFAULT); + unflatten_and_copy_device_tree(); +} - unflatten_device_tree(); +static int __init customize_machine(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + return 0; } +arch_initcall(customize_machine); diff --git a/arch/mips/mti-sead3/sead3-time.c b/arch/mips/mti-sead3/sead3-time.c index 552d26c343869f..678d03d53c60cc 100644 --- a/arch/mips/mti-sead3/sead3-time.c +++ b/arch/mips/mti-sead3/sead3-time.c @@ -13,8 +13,6 @@ #include #include -unsigned long cpu_khz; - static int mips_cpu_timer_irq; static int mips_cpu_perf_irq; @@ -109,8 +107,6 @@ void __init plat_time_init(void) pr_debug("CPU frequency %d.%02d MHz\n", (est_freq / 1000000), (est_freq % 1000000) * 100 / 1000000); - cpu_khz = est_freq / 1000; - mips_scroll_message(); plat_perf_setup(); diff --git a/arch/mips/mti-sead3/sead3.dts b/arch/mips/mti-sead3/sead3.dts index 658f4378705629..e4b317d414f112 100644 --- a/arch/mips/mti-sead3/sead3.dts +++ b/arch/mips/mti-sead3/sead3.dts @@ -15,10 +15,6 @@ }; }; - chosen { - bootargs = "console=ttyS1,38400 rootdelay=10 root=/dev/sda3"; - }; - memory { device_type = "memory"; reg = <0x0 0x08000000>; diff --git a/arch/mips/netlogic/Kconfig b/arch/mips/netlogic/Kconfig index 852a4ee09954da..4eb683aef7d766 100644 --- a/arch/mips/netlogic/Kconfig +++ b/arch/mips/netlogic/Kconfig @@ -28,6 +28,15 @@ config DT_XLP_FVP pointer to the kernel. The corresponding DTS file is at arch/mips/netlogic/dts/xlp_fvp.dts +config DT_XLP_GVP + bool "Built-in device tree for XLP GVP boards" + default y + help + Add an FDT blob for XLP GVP board into the kernel. + This DTB will be used if the firmware does not pass in a DTB + pointer to the kernel. The corresponding DTS file is at + arch/mips/netlogic/dts/xlp_gvp.dts + config NLM_MULTINODE bool "Support for multi-chip boards" depends on NLM_XLP_BOARD diff --git a/arch/mips/netlogic/common/earlycons.c b/arch/mips/netlogic/common/earlycons.c index 1902fa22d277dc..769f93032c5331 100644 --- a/arch/mips/netlogic/common/earlycons.c +++ b/arch/mips/netlogic/common/earlycons.c @@ -37,9 +37,11 @@ #include #include +#include #if defined(CONFIG_CPU_XLP) #include +#include #include #elif defined(CONFIG_CPU_XLR) #include diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index 1c7e3a1b81abd6..5afc4b7fce0f12 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c @@ -180,6 +180,7 @@ static void __init nlm_init_percpu_irqs(void) #endif } + void nlm_setup_pic_irq(int node, int picirq, int irq, int irt) { struct nlm_pic_irq *pic_data; @@ -207,32 +208,32 @@ void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *)) static void nlm_init_node_irqs(int node) { - int i, irt; - uint64_t irqmask; struct nlm_soc_info *nodep; + int i, irt; pr_info("Init IRQ for node %d\n", node); nodep = nlm_get_node(node); - irqmask = PERCPU_IRQ_MASK; + nodep->irqmask = PERCPU_IRQ_MASK; for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ; i++) { irt = nlm_irq_to_irt(i); - if (irt == -1) + if (irt == -1) /* unused irq */ continue; - nlm_setup_pic_irq(node, i, i, irt); - /* set interrupts to first cpu in node */ + nodep->irqmask |= 1ull << i; + if (irt == -2) /* not a direct PIC irq */ + continue; + nlm_pic_init_irt(nodep->picbase, irt, i, - node * NLM_CPUS_PER_NODE, 0); - irqmask |= (1ull << i); + node * nlm_threads_per_node(), 0); + nlm_setup_pic_irq(node, i, i, irt); } - nodep->irqmask = irqmask; } void nlm_smp_irq_init(int hwcpuid) { int node, cpu; - node = hwcpuid / NLM_CPUS_PER_NODE; - cpu = hwcpuid % NLM_CPUS_PER_NODE; + node = nlm_cpuid_to_node(hwcpuid); + cpu = hwcpuid % nlm_threads_per_node(); if (cpu == 0 && node != 0) nlm_init_node_irqs(node); @@ -256,13 +257,23 @@ asmlinkage void plat_irq_dispatch(void) return; } +#if defined(CONFIG_PCI_MSI) && defined(CONFIG_CPU_XLP) + /* PCI interrupts need a second level dispatch for MSI bits */ + if (i >= PIC_PCIE_LINK_MSI_IRQ(0) && i <= PIC_PCIE_LINK_MSI_IRQ(3)) { + nlm_dispatch_msi(node, i); + return; + } + if (i >= PIC_PCIE_MSIX_IRQ(0) && i <= PIC_PCIE_MSIX_IRQ(3)) { + nlm_dispatch_msix(node, i); + return; + } + +#endif /* top level irq handling */ do_IRQ(nlm_irq_to_xirq(node, i)); } #ifdef CONFIG_OF -static struct irq_domain *xlp_pic_domain; - static const struct irq_domain_ops xlp_pic_irq_domain_ops = { .xlate = irq_domain_xlate_onetwocell, }; @@ -271,8 +282,9 @@ static int __init xlp_of_pic_init(struct device_node *node, struct device_node *parent) { const int n_picirqs = PIC_IRT_LAST_IRQ - PIC_IRQ_BASE + 1; + struct irq_domain *xlp_pic_domain; struct resource res; - int socid, ret; + int socid, ret, bus; /* we need a hack to get the PIC's SoC chip id */ ret = of_address_to_resource(node, 0, &res); @@ -280,7 +292,34 @@ static int __init xlp_of_pic_init(struct device_node *node, pr_err("PIC %s: reg property not found!\n", node->name); return -EINVAL; } - socid = (res.start >> 18) & 0x3; + + if (cpu_is_xlp9xx()) { + bus = (res.start >> 20) & 0xf; + for (socid = 0; socid < NLM_NR_NODES; socid++) { + if (!nlm_node_present(socid)) + continue; + if (nlm_get_node(socid)->socbus == bus) + break; + } + if (socid == NLM_NR_NODES) { + pr_err("PIC %s: Node mapping for bus %d not found!\n", + node->name, bus); + return -EINVAL; + } + } else { + socid = (res.start >> 18) & 0x3; + if (!nlm_node_present(socid)) { + pr_err("PIC %s: node %d does not exist!\n", + node->name, socid); + return -EINVAL; + } + } + + if (!nlm_node_present(socid)) { + pr_err("PIC %s: node %d does not exist!\n", node->name, socid); + return -EINVAL; + } + xlp_pic_domain = irq_domain_add_legacy(node, n_picirqs, nlm_irq_to_xirq(socid, PIC_IRQ_BASE), PIC_IRQ_BASE, &xlp_pic_irq_domain_ops, NULL); @@ -288,8 +327,7 @@ static int __init xlp_of_pic_init(struct device_node *node, pr_err("PIC %s: Creating legacy domain failed!\n", node->name); return -EINVAL; } - pr_info("Node %d: IRQ domain created for PIC@%pa\n", socid, - &res.start); + pr_info("Node %d: IRQ domain created for PIC@%pR\n", socid, &res); return 0; } diff --git a/arch/mips/netlogic/common/reset.S b/arch/mips/netlogic/common/reset.S index adb18288a6c0d5..b231fe1e7a093c 100644 --- a/arch/mips/netlogic/common/reset.S +++ b/arch/mips/netlogic/common/reset.S @@ -32,10 +32,10 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include #include +#include #include #include #include @@ -50,8 +50,8 @@ #include #define CP0_EBASE $15 -#define SYS_CPU_COHERENT_BASE(node) CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \ - XLP_IO_SYS_OFFSET(node) + XLP_IO_PCI_HDRSZ + \ +#define SYS_CPU_COHERENT_BASE CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \ + XLP_IO_SYS_OFFSET(0) + XLP_IO_PCI_HDRSZ + \ SYS_CPU_NONCOHERENT_MODE * 4 /* Enable XLP features and workarounds in the LSU */ @@ -74,35 +74,55 @@ .endm /* - * Low level flush for L1D cache on XLP, the normal cache ops does - * not do the complete and correct cache flush. + * L1D cache has to be flushed before enabling threads in XLP. + * On XLP8xx/XLP3xx, we do a low level flush using processor control + * registers. On XLPII CPUs, usual cache instructions work. */ .macro xlp_flush_l1_dcache + mfc0 t0, CP0_EBASE, 0 + andi t0, t0, 0xff00 + slt t1, t0, 0x1200 + beqz t1, 15f + nop + + /* XLP8xx low level cache flush */ li t0, LSU_DEBUG_DATA0 li t1, LSU_DEBUG_ADDR li t2, 0 /* index */ li t3, 0x1000 /* loop count */ -1: +11: sll v0, t2, 5 mtcr zero, t0 ori v1, v0, 0x3 /* way0 | write_enable | write_active */ mtcr v1, t1 -2: +12: mfcr v1, t1 andi v1, 0x1 /* wait for write_active == 0 */ - bnez v1, 2b + bnez v1, 12b nop mtcr zero, t0 ori v1, v0, 0x7 /* way1 | write_enable | write_active */ mtcr v1, t1 -3: +13: mfcr v1, t1 andi v1, 0x1 /* wait for write_active == 0 */ - bnez v1, 3b + bnez v1, 13b nop addi t2, 1 - bne t3, t2, 1b + bne t3, t2, 11b + nop + b 17f + nop + + /* XLPII CPUs, Invalidate all 64k of L1 D-cache */ +15: + li t0, 0x80000000 + li t1, 0x80010000 +16: cache Index_Writeback_Inv_D, 0(t0) + addiu t0, t0, 32 + bne t0, t1, 16b nop +17: .endm /* @@ -138,6 +158,13 @@ FEXPORT(nlm_reset_entry) nop 1: /* Entry point on core wakeup */ + mfc0 t0, CP0_EBASE, 0 /* processor ID */ + andi t0, 0xff00 + li t1, 0x1500 /* XLP 9xx */ + beq t0, t1, 2f /* does not need to set coherent */ + nop + + /* set bit in SYS coherent register for the core */ mfc0 t0, CP0_EBASE, 1 mfc0 t1, CP0_EBASE, 1 srl t1, 5 @@ -149,7 +176,7 @@ FEXPORT(nlm_reset_entry) li t1, 0x1 sll t0, t1, t0 nor t0, t0, zero /* t0 <- ~(1 << core) */ - li t2, SYS_CPU_COHERENT_BASE(0) + li t2, SYS_CPU_COHERENT_BASE add t2, t2, t3 /* t2 <- SYS offset for node */ lw t1, 0(t2) and t1, t1, t0 @@ -159,13 +186,13 @@ FEXPORT(nlm_reset_entry) lw t1, 0(t2) sync +2: /* Configure LSU on Non-0 Cores. */ xlp_config_lsu /* FALL THROUGH */ /* - * Wake up sibling threads from the initial thread in - * a core. + * Wake up sibling threads from the initial thread in a core. */ EXPORT(nlm_boot_siblings) /* core L1D flush before enable threads */ @@ -181,8 +208,10 @@ EXPORT(nlm_boot_siblings) /* * The new hardware thread starts at the next instruction * For all the cases other than core 0 thread 0, we will - * jump to the secondary wait function. - */ + * jump to the secondary wait function. + + * NOTE: All GPR contents are lost after the mtcr above! + */ mfc0 v0, CP0_EBASE, 1 andi v0, 0x3ff /* v0 <- node/core */ @@ -196,7 +225,7 @@ EXPORT(nlm_boot_siblings) #endif mtc0 t1, CP0_STATUS - /* mark CPU ready, careful here, previous mtcr trashed registers */ + /* mark CPU ready */ li t3, CKSEG1ADDR(RESET_DATA_PHYS) ADDIU t1, t3, BOOT_CPU_READY sll v1, v0, 2 diff --git a/arch/mips/netlogic/common/smp.c b/arch/mips/netlogic/common/smp.c index c0eded01fde96e..6baae15cc7b182 100644 --- a/arch/mips/netlogic/common/smp.c +++ b/arch/mips/netlogic/common/smp.c @@ -63,7 +63,7 @@ void nlm_send_ipi_single(int logical_cpu, unsigned int action) uint64_t picbase; cpu = cpu_logical_map(logical_cpu); - node = cpu / NLM_CPUS_PER_NODE; + node = nlm_cpuid_to_node(cpu); picbase = nlm_get_node(node)->picbase; if (action & SMP_CALL_FUNCTION) @@ -152,7 +152,7 @@ void nlm_boot_secondary(int logical_cpu, struct task_struct *idle) int cpu, node; cpu = cpu_logical_map(logical_cpu); - node = cpu / NLM_CPUS_PER_NODE; + node = nlm_cpuid_to_node(logical_cpu); nlm_next_sp = (unsigned long)__KSTK_TOS(idle); nlm_next_gp = (unsigned long)task_thread_info(idle); @@ -164,7 +164,7 @@ void nlm_boot_secondary(int logical_cpu, struct task_struct *idle) void __init nlm_smp_setup(void) { unsigned int boot_cpu; - int num_cpus, i, ncore; + int num_cpus, i, ncore, node; volatile u32 *cpu_ready = nlm_get_boot_data(BOOT_CPU_READY); char buf[64]; @@ -187,6 +187,8 @@ void __init nlm_smp_setup(void) __cpu_number_map[i] = num_cpus; __cpu_logical_map[num_cpus] = i; set_cpu_possible(num_cpus, true); + node = nlm_cpuid_to_node(i); + cpumask_set_cpu(num_cpus, &nlm_get_node(node)->cpumask); ++num_cpus; } } diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S index aa6cff0a229b0c..8597657c27fcc0 100644 --- a/arch/mips/netlogic/common/smpboot.S +++ b/arch/mips/netlogic/common/smpboot.S @@ -32,7 +32,6 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include #include @@ -98,7 +97,7 @@ END(nlm_boot_secondary_cpus) * In case of RMIboot bootloader which is used on XLR boards, the CPUs * be already woken up and waiting in bootloader code. * This will get them out of the bootloader code and into linux. Needed - * because the bootloader area will be taken and initialized by linux. + * because the bootloader area will be taken and initialized by linux. */ NESTED(nlm_rmiboot_preboot, 16, sp) mfc0 t0, $15, 1 /* read ebase */ @@ -133,6 +132,7 @@ NESTED(nlm_rmiboot_preboot, 16, sp) or t1, t2, v1 /* put in new value */ mtcr t1, t0 /* update core control */ + /* wait for NMI to hit */ 1: wait b 1b nop diff --git a/arch/mips/netlogic/dts/Makefile b/arch/mips/netlogic/dts/Makefile index 0b9be5fd2e466e..25c8e873ee2577 100644 --- a/arch/mips/netlogic/dts/Makefile +++ b/arch/mips/netlogic/dts/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_DT_XLP_EVP) := xlp_evp.dtb.o obj-$(CONFIG_DT_XLP_SVP) += xlp_svp.dtb.o obj-$(CONFIG_DT_XLP_FVP) += xlp_fvp.dtb.o +obj-$(CONFIG_DT_XLP_GVP) += xlp_gvp.dtb.o diff --git a/arch/mips/netlogic/dts/xlp_gvp.dts b/arch/mips/netlogic/dts/xlp_gvp.dts new file mode 100644 index 00000000000000..047d27f54487f2 --- /dev/null +++ b/arch/mips/netlogic/dts/xlp_gvp.dts @@ -0,0 +1,76 @@ +/* + * XLP9XX Device Tree Source for GVP boards + */ + +/dts-v1/; +/ { + model = "netlogic,XLP-GVP"; + compatible = "netlogic,xlp"; + #address-cells = <2>; + #size-cells = <2>; + + soc { + #address-cells = <2>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0 0 0 0x18000000 0x04000000 // PCIe CFG + 1 0 0 0x16000000 0x02000000>; // GBU chipselects + + serial0: serial@30000 { + device_type = "serial"; + compatible = "ns16550"; + reg = <0 0x112100 0xa00>; + reg-shift = <2>; + reg-io-width = <4>; + clock-frequency = <125000000>; + interrupt-parent = <&pic>; + interrupts = <17>; + }; + pic: pic@4000 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + reg = <0 0x110000 0x200>; + }; + + nor_flash@1,0 { + compatible = "cfi-flash"; + #address-cells = <1>; + #size-cells = <1>; + bank-width = <2>; + reg = <1 0 0x1000000>; + + partition@0 { + label = "x-loader"; + reg = <0x0 0x100000>; /* 1M */ + read-only; + }; + + partition@100000 { + label = "u-boot"; + reg = <0x100000 0x100000>; /* 1M */ + }; + + partition@200000 { + label = "kernel"; + reg = <0x200000 0x500000>; /* 5M */ + }; + + partition@700000 { + label = "rootfs"; + reg = <0x700000 0x800000>; /* 8M */ + }; + + partition@f00000 { + label = "env"; + reg = <0xf00000 0x100000>; /* 1M */ + read-only; + }; + }; + + }; + + chosen { + bootargs = "console=ttyS0,115200 rdinit=/sbin/init"; + }; +}; diff --git a/arch/mips/netlogic/xlp/dt.c b/arch/mips/netlogic/xlp/dt.c index 8316d5454b1751..5754097b9cde83 100644 --- a/arch/mips/netlogic/xlp/dt.c +++ b/arch/mips/netlogic/xlp/dt.c @@ -42,13 +42,18 @@ #include extern u32 __dtb_xlp_evp_begin[], __dtb_xlp_svp_begin[], - __dtb_xlp_fvp_begin[], __dtb_start[]; + __dtb_xlp_fvp_begin[], __dtb_xlp_gvp_begin[], __dtb_start[]; static void *xlp_fdt_blob; void __init *xlp_dt_init(void *fdtp) { if (!fdtp) { switch (current_cpu_data.processor_id & 0xff00) { +#ifdef CONFIG_DT_XLP_GVP + case PRID_IMP_NETLOGIC_XLP9XX: + fdtp = __dtb_xlp_gvp_begin; + break; +#endif #ifdef CONFIG_DT_XLP_FVP case PRID_IMP_NETLOGIC_XLP2XX: fdtp = __dtb_xlp_fvp_begin; diff --git a/arch/mips/netlogic/xlp/nlm_hal.c b/arch/mips/netlogic/xlp/nlm_hal.c index 56c50ba43c9b0b..997cd9ee10de66 100644 --- a/arch/mips/netlogic/xlp/nlm_hal.c +++ b/arch/mips/netlogic/xlp/nlm_hal.c @@ -57,6 +57,10 @@ void nlm_node_init(int node) nodep->sysbase = nlm_get_sys_regbase(node); nodep->picbase = nlm_get_pic_regbase(node); nodep->ebase = read_c0_ebase() & (~((1 << 12) - 1)); + if (cpu_is_xlp9xx()) + nodep->socbus = xlp9xx_get_socbus(node); + else + nodep->socbus = 0; spin_lock_init(&nodep->piclock); } @@ -65,6 +69,26 @@ int nlm_irq_to_irt(int irq) uint64_t pcibase; int devoff, irt; + /* bypass for 9xx */ + if (cpu_is_xlp9xx()) { + switch (irq) { + case PIC_9XX_XHCI_0_IRQ: + return 114; + case PIC_9XX_XHCI_1_IRQ: + return 115; + case PIC_UART_0_IRQ: + return 133; + case PIC_UART_1_IRQ: + return 134; + case PIC_PCIE_LINK_LEGACY_IRQ(0): + case PIC_PCIE_LINK_LEGACY_IRQ(1): + case PIC_PCIE_LINK_LEGACY_IRQ(2): + case PIC_PCIE_LINK_LEGACY_IRQ(3): + return 191 + irq - PIC_PCIE_LINK_LEGACY_IRQ_BASE; + } + return -1; + } + devoff = 0; switch (irq) { case PIC_UART_0_IRQ: @@ -135,9 +159,17 @@ int nlm_irq_to_irt(int irq) case PIC_I2C_3_IRQ: irt = irt + 3; break; } - } else if (irq >= PIC_PCIE_LINK_0_IRQ && irq <= PIC_PCIE_LINK_3_IRQ) { + } else if (irq >= PIC_PCIE_LINK_LEGACY_IRQ(0) && + irq <= PIC_PCIE_LINK_LEGACY_IRQ(3)) { /* HW bug, PCI IRT entries are bad on early silicon, fix */ - irt = PIC_IRT_PCIE_LINK_INDEX(irq - PIC_PCIE_LINK_0_IRQ); + irt = PIC_IRT_PCIE_LINK_INDEX(irq - + PIC_PCIE_LINK_LEGACY_IRQ_BASE); + } else if (irq >= PIC_PCIE_LINK_MSI_IRQ(0) && + irq <= PIC_PCIE_LINK_MSI_IRQ(3)) { + irt = -2; + } else if (irq >= PIC_PCIE_MSIX_IRQ(0) && + irq <= PIC_PCIE_MSIX_IRQ(3)) { + irt = -2; } else { irt = -1; } @@ -151,7 +183,10 @@ unsigned int nlm_get_core_frequency(int node, int core) uint64_t num, sysbase; sysbase = nlm_get_node(node)->sysbase; - rstval = nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG); + if (cpu_is_xlp9xx()) + rstval = nlm_read_sys_reg(sysbase, SYS_9XX_POWER_ON_RESET_CFG); + else + rstval = nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG); if (cpu_is_xlpii()) { num = 1000000ULL * (400 * 3 + 100 * (rstval >> 26)); denom = 3; @@ -265,6 +300,10 @@ static unsigned int nlm_2xx_get_pic_frequency(int node) unsigned int nlm_get_pic_frequency(int node) { + /* TODO Has to calculate freq as like 2xx */ + if (cpu_is_xlp9xx()) + return 250000000; + if (cpu_is_xlpii()) return nlm_2xx_get_pic_frequency(node); else @@ -284,21 +323,33 @@ int xlp_get_dram_map(int n, uint64_t *dram_map) { uint64_t bridgebase, base, lim; uint32_t val; + unsigned int barreg, limreg, xlatreg; int i, node, rv; /* Look only at mapping on Node 0, we don't handle crazy configs */ bridgebase = nlm_get_bridge_regbase(0); rv = 0; for (i = 0; i < 8; i++) { - val = nlm_read_bridge_reg(bridgebase, - BRIDGE_DRAM_NODE_TRANSLN(i)); - node = (val >> 1) & 0x3; - if (n >= 0 && n != node) - continue; - val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_BAR(i)); + if (cpu_is_xlp9xx()) { + barreg = BRIDGE_9XX_DRAM_BAR(i); + limreg = BRIDGE_9XX_DRAM_LIMIT(i); + xlatreg = BRIDGE_9XX_DRAM_NODE_TRANSLN(i); + } else { + barreg = BRIDGE_DRAM_BAR(i); + limreg = BRIDGE_DRAM_LIMIT(i); + xlatreg = BRIDGE_DRAM_NODE_TRANSLN(i); + } + if (n >= 0) { + /* node specified, get node mapping of BAR */ + val = nlm_read_bridge_reg(bridgebase, xlatreg); + node = (val >> 1) & 0x3; + if (n != node) + continue; + } + val = nlm_read_bridge_reg(bridgebase, barreg); val = (val >> 12) & 0xfffff; base = (uint64_t) val << 20; - val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_LIMIT(i)); + val = nlm_read_bridge_reg(bridgebase, limreg); val = (val >> 12) & 0xfffff; if (val == 0) /* BAR not used */ continue; diff --git a/arch/mips/netlogic/xlp/setup.c b/arch/mips/netlogic/xlp/setup.c index 54e75c77184b88..8c60a2dd9ef6bd 100644 --- a/arch/mips/netlogic/xlp/setup.c +++ b/arch/mips/netlogic/xlp/setup.c @@ -51,12 +51,16 @@ uint64_t nlm_io_base; struct nlm_soc_info nlm_nodes[NLM_NR_NODES]; cpumask_t nlm_cpumask = CPU_MASK_CPU0; unsigned int nlm_threads_per_core; +unsigned int xlp_cores_per_node; static void nlm_linux_exit(void) { uint64_t sysbase = nlm_get_node(0)->sysbase; - nlm_write_sys_reg(sysbase, SYS_CHIP_RESET, 1); + if (cpu_is_xlp9xx()) + nlm_write_sys_reg(sysbase, SYS_9XX_CHIP_RESET, 1); + else + nlm_write_sys_reg(sysbase, SYS_CHIP_RESET, 1); for ( ; ; ) cpu_wait(); } @@ -92,6 +96,14 @@ static void __init xlp_init_mem_from_bars(void) void __init plat_mem_setup(void) { +#ifdef CONFIG_SMP + nlm_wakeup_secondary_cpus(); + + /* update TLB size after waking up threads */ + current_cpu_data.tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1; + + register_smp_ops(&nlm_smp_ops); +#endif _machine_restart = (void (*)(char *))nlm_linux_exit; _machine_halt = nlm_linux_exit; pm_power_off = nlm_linux_exit; @@ -110,6 +122,7 @@ void __init plat_mem_setup(void) const char *get_system_type(void) { switch (read_c0_prid() & 0xff00) { + case PRID_IMP_NETLOGIC_XLP9XX: case PRID_IMP_NETLOGIC_XLP2XX: return "Broadcom XLPII Series"; default: @@ -149,6 +162,10 @@ void __init prom_init(void) void *reset_vec; nlm_io_base = CKSEG1ADDR(XLP_DEFAULT_IO_BASE); + if (cpu_is_xlp9xx()) + xlp_cores_per_node = 32; + else + xlp_cores_per_node = 8; nlm_init_boot_cpu(); xlp_mmu_init(); nlm_node_init(0); @@ -162,11 +179,5 @@ void __init prom_init(void) #ifdef CONFIG_SMP cpumask_setall(&nlm_cpumask); - nlm_wakeup_secondary_cpus(); - - /* update TLB size after waking up threads */ - current_cpu_data.tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1; - - register_smp_ops(&nlm_smp_ops); #endif } diff --git a/arch/mips/netlogic/xlp/usb-init-xlp2.c b/arch/mips/netlogic/xlp/usb-init-xlp2.c index 36e9c22afc467f..17ade1ce5dfd87 100644 --- a/arch/mips/netlogic/xlp/usb-init-xlp2.c +++ b/arch/mips/netlogic/xlp/usb-init-xlp2.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -83,12 +84,14 @@ #define nlm_read_usb_reg(b, r) nlm_read_reg(b, r) #define nlm_write_usb_reg(b, r, v) nlm_write_reg(b, r, v) -#define nlm_xlpii_get_usb_pcibase(node, inst) \ - nlm_pcicfg_base(XLP2XX_IO_USB_OFFSET(node, inst)) +#define nlm_xlpii_get_usb_pcibase(node, inst) \ + nlm_pcicfg_base(cpu_is_xlp9xx() ? \ + XLP9XX_IO_USB_OFFSET(node, inst) : \ + XLP2XX_IO_USB_OFFSET(node, inst)) #define nlm_xlpii_get_usb_regbase(node, inst) \ (nlm_xlpii_get_usb_pcibase(node, inst) + XLP_IO_PCI_HDRSZ) -static void xlpii_usb_ack(struct irq_data *data) +static void xlp2xx_usb_ack(struct irq_data *data) { u64 port_addr; @@ -109,6 +112,29 @@ static void xlpii_usb_ack(struct irq_data *data) nlm_write_usb_reg(port_addr, XLPII_USB3_INT_REG, 0xffffffff); } +static void xlp9xx_usb_ack(struct irq_data *data) +{ + u64 port_addr; + int node, irq; + + /* Find the node and irq on the node */ + irq = data->irq % NLM_IRQS_PER_NODE; + node = data->irq / NLM_IRQS_PER_NODE; + + switch (irq) { + case PIC_9XX_XHCI_0_IRQ: + port_addr = nlm_xlpii_get_usb_regbase(node, 1); + break; + case PIC_9XX_XHCI_1_IRQ: + port_addr = nlm_xlpii_get_usb_regbase(node, 2); + break; + default: + pr_err("No matching USB irq %d node %d!\n", irq, node); + return; + } + nlm_write_usb_reg(port_addr, XLPII_USB3_INT_REG, 0xffffffff); +} + static void nlm_xlpii_usb_hw_reset(int node, int port) { u64 port_addr, xhci_base, pci_base; @@ -178,17 +204,33 @@ static void nlm_xlpii_usb_hw_reset(int node, int port) static int __init nlm_platform_xlpii_usb_init(void) { + int node; + if (!cpu_is_xlpii()) return 0; - pr_info("Initializing 2XX USB Interface\n"); - nlm_xlpii_usb_hw_reset(0, 1); - nlm_xlpii_usb_hw_reset(0, 2); - nlm_xlpii_usb_hw_reset(0, 3); - nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_0_IRQ, xlpii_usb_ack); - nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_1_IRQ, xlpii_usb_ack); - nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_2_IRQ, xlpii_usb_ack); + if (!cpu_is_xlp9xx()) { + /* XLP 2XX single node */ + pr_info("Initializing 2XX USB Interface\n"); + nlm_xlpii_usb_hw_reset(0, 1); + nlm_xlpii_usb_hw_reset(0, 2); + nlm_xlpii_usb_hw_reset(0, 3); + nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_0_IRQ, xlp2xx_usb_ack); + nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_1_IRQ, xlp2xx_usb_ack); + nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_2_IRQ, xlp2xx_usb_ack); + return 0; + } + /* XLP 9XX, multi-node */ + pr_info("Initializing 9XX USB Interface\n"); + for (node = 0; node < NLM_NR_NODES; node++) { + if (!nlm_node_present(node)) + continue; + nlm_xlpii_usb_hw_reset(node, 1); + nlm_xlpii_usb_hw_reset(node, 2); + nlm_set_pic_extra_ack(node, PIC_9XX_XHCI_0_IRQ, xlp9xx_usb_ack); + nlm_set_pic_extra_ack(node, PIC_9XX_XHCI_1_IRQ, xlp9xx_usb_ack); + } return 0; } @@ -196,8 +238,26 @@ arch_initcall(nlm_platform_xlpii_usb_init); static u64 xlp_usb_dmamask = ~(u32)0; -/* Fixup IRQ for USB devices on XLP the SoC PCIe bus */ -static void nlm_usb_fixup_final(struct pci_dev *dev) +/* Fixup the IRQ for USB devices which is exist on XLP9XX SOC PCIE bus */ +static void nlm_xlp9xx_usb_fixup_final(struct pci_dev *dev) +{ + int node; + + node = xlp_socdev_to_node(dev); + dev->dev.dma_mask = &xlp_usb_dmamask; + dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + switch (dev->devfn) { + case 0x21: + dev->irq = nlm_irq_to_xirq(node, PIC_9XX_XHCI_0_IRQ); + break; + case 0x22: + dev->irq = nlm_irq_to_xirq(node, PIC_9XX_XHCI_1_IRQ); + break; + } +} + +/* Fixup the IRQ for USB devices which is exist on XLP2XX SOC PCIE bus */ +static void nlm_xlp2xx_usb_fixup_final(struct pci_dev *dev) { dev->dev.dma_mask = &xlp_usb_dmamask; dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); @@ -214,5 +274,7 @@ static void nlm_usb_fixup_final(struct pci_dev *dev) } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_XLP9XX_XHCI, + nlm_xlp9xx_usb_fixup_final); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_XHCI, - nlm_usb_fixup_final); + nlm_xlp2xx_usb_fixup_final); diff --git a/arch/mips/netlogic/xlp/wakeup.c b/arch/mips/netlogic/xlp/wakeup.c index 682d5638dc01ca..9a92617a2af592 100644 --- a/arch/mips/netlogic/xlp/wakeup.c +++ b/arch/mips/netlogic/xlp/wakeup.c @@ -32,7 +32,6 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include #include @@ -47,14 +46,14 @@ #include #include -#include #include +#include #include static int xlp_wakeup_core(uint64_t sysbase, int node, int core) { uint32_t coremask, value; - int count; + int count, resetreg; coremask = (1 << core); @@ -65,12 +64,24 @@ static int xlp_wakeup_core(uint64_t sysbase, int node, int core) nlm_write_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL, value); } + /* On 9XX, mark coherent first */ + if (cpu_is_xlp9xx()) { + value = nlm_read_sys_reg(sysbase, SYS_9XX_CPU_NONCOHERENT_MODE); + value &= ~coremask; + nlm_write_sys_reg(sysbase, SYS_9XX_CPU_NONCOHERENT_MODE, value); + } + /* Remove CPU Reset */ - value = nlm_read_sys_reg(sysbase, SYS_CPU_RESET); + resetreg = cpu_is_xlp9xx() ? SYS_9XX_CPU_RESET : SYS_CPU_RESET; + value = nlm_read_sys_reg(sysbase, resetreg); value &= ~coremask; - nlm_write_sys_reg(sysbase, SYS_CPU_RESET, value); + nlm_write_sys_reg(sysbase, resetreg, value); + + /* We are done on 9XX */ + if (cpu_is_xlp9xx()) + return 1; - /* Poll for CPU to mark itself coherent */ + /* Poll for CPU to mark itself coherent on other type of XLP */ count = 100000; do { value = nlm_read_sys_reg(sysbase, SYS_CPU_NONCOHERENT_MODE); @@ -84,7 +95,7 @@ static int wait_for_cpus(int cpu, int bootcpu) volatile uint32_t *cpu_ready = nlm_get_boot_data(BOOT_CPU_READY); int i, count, notready; - count = 0x20000000; + count = 0x800000; do { notready = nlm_threads_per_core; for (i = 0; i < nlm_threads_per_core; i++) @@ -98,27 +109,62 @@ static int wait_for_cpus(int cpu, int bootcpu) static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask) { struct nlm_soc_info *nodep; - uint64_t syspcibase; - uint32_t syscoremask; + uint64_t syspcibase, fusebase; + uint32_t syscoremask, mask, fusemask; int core, n, cpu; for (n = 0; n < NLM_NR_NODES; n++) { - syspcibase = nlm_get_sys_pcibase(n); - if (nlm_read_reg(syspcibase, 0) == 0xffffffff) - break; + if (n != 0) { + /* check if node exists and is online */ + if (cpu_is_xlp9xx()) { + int b = xlp9xx_get_socbus(n); + pr_info("Node %d SoC PCI bus %d.\n", n, b); + if (b == 0) + break; + } else { + syspcibase = nlm_get_sys_pcibase(n); + if (nlm_read_reg(syspcibase, 0) == 0xffffffff) + break; + } + nlm_node_init(n); + } /* read cores in reset from SYS */ - if (n != 0) - nlm_node_init(n); nodep = nlm_get_node(n); - syscoremask = nlm_read_sys_reg(nodep->sysbase, SYS_CPU_RESET); + + if (cpu_is_xlp9xx()) { + fusebase = nlm_get_fuse_regbase(n); + fusemask = nlm_read_reg(fusebase, FUSE_9XX_DEVCFG6); + mask = 0xfffff; + } else { + fusemask = nlm_read_sys_reg(nodep->sysbase, + SYS_EFUSE_DEVICE_CFG_STATUS0); + switch (read_c0_prid() & 0xff00) { + case PRID_IMP_NETLOGIC_XLP3XX: + mask = 0xf; + break; + case PRID_IMP_NETLOGIC_XLP2XX: + mask = 0x3; + break; + case PRID_IMP_NETLOGIC_XLP8XX: + default: + mask = 0xff; + break; + } + } + + /* + * Fused out cores are set in the fusemask, and the remaining + * cores are renumbered to range 0 .. nactive-1 + */ + syscoremask = (1 << hweight32(~fusemask & mask)) - 1; + /* The boot cpu */ - if (n == 0) { - syscoremask |= 1; + if (n == 0) nodep->coremask = 1; - } - for (core = 0; core < NLM_CORES_PER_NODE; core++) { + pr_info("Node %d - SYS/FUSE coremask %x\n", n, syscoremask); + for (core = 0; core < nlm_cores_per_node(); core++) { /* we will be on node 0 core 0 */ if (n == 0 && core == 0) continue; @@ -128,7 +174,7 @@ static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask) continue; /* see if at least the first hw thread is enabled */ - cpu = (n * NLM_CORES_PER_NODE + core) + cpu = (n * nlm_cores_per_node() + core) * NLM_THREADS_PER_CORE; if (!cpumask_test_cpu(cpu, wakeup_mask)) continue; @@ -141,7 +187,8 @@ static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask) nodep->coremask |= 1u << core; /* spin until the hw threads sets their ready */ - wait_for_cpus(cpu, 0); + if (!wait_for_cpus(cpu, 0)) + pr_err("Node %d : timeout core %d\n", n, core); } } } @@ -153,7 +200,8 @@ void xlp_wakeup_secondary_cpus() * first wakeup core 0 threads */ xlp_boot_core0_siblings(); - wait_for_cpus(0, 0); + if (!wait_for_cpus(0, 0)) + pr_err("Node 0 : timeout core 0\n"); /* now get other cores out of reset */ xlp_enable_secondary_cores(&nlm_cpumask); diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c index 7b96a91f47731a..4785932af248de 100644 --- a/arch/mips/netlogic/xlr/platform.c +++ b/arch/mips/netlogic/xlr/platform.c @@ -23,7 +23,7 @@ #include #include -unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset) +static unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset) { uint64_t uartbase; unsigned int value; @@ -41,7 +41,7 @@ unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset) return value; } -void nlm_xlr_uart_out(struct uart_port *p, int offset, int value) +static void nlm_xlr_uart_out(struct uart_port *p, int offset, int value) { uint64_t uartbase; diff --git a/arch/mips/netlogic/xlr/setup.c b/arch/mips/netlogic/xlr/setup.c index 921be5f7779770..d118b9aa764740 100644 --- a/arch/mips/netlogic/xlr/setup.c +++ b/arch/mips/netlogic/xlr/setup.c @@ -60,25 +60,6 @@ unsigned int nlm_threads_per_core = 1; struct nlm_soc_info nlm_nodes[NLM_NR_NODES]; cpumask_t nlm_cpumask = CPU_MASK_CPU0; -static void __init nlm_early_serial_setup(void) -{ - struct uart_port s; - unsigned long uart_base; - - uart_base = (unsigned long)nlm_mmio_base(NETLOGIC_IO_UART_0_OFFSET); - memset(&s, 0, sizeof(s)); - s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; - s.iotype = UPIO_MEM32; - s.regshift = 2; - s.irq = PIC_UART_0_IRQ; - s.uartclk = PIC_CLK_HZ; - s.serial_in = nlm_xlr_uart_in; - s.serial_out = nlm_xlr_uart_out; - s.mapbase = uart_base; - s.membase = (unsigned char __iomem *)uart_base; - early_serial_setup(&s); -} - static void nlm_linux_exit(void) { uint64_t gpiobase; @@ -214,7 +195,6 @@ void __init prom_init(void) memcpy(reset_vec, (void *)nlm_reset_entry, (nlm_reset_entry_end - nlm_reset_entry)); - nlm_early_serial_setup(); build_arcs_cmdline(argv); prom_add_memory(); diff --git a/arch/mips/netlogic/xlr/wakeup.c b/arch/mips/netlogic/xlr/wakeup.c index 9fb81fa6272a75..d61cba1e9c6592 100644 --- a/arch/mips/netlogic/xlr/wakeup.c +++ b/arch/mips/netlogic/xlr/wakeup.c @@ -32,7 +32,6 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include #include @@ -70,7 +69,7 @@ int xlr_wakeup_secondary_cpus(void) /* Fill up the coremask early */ nodep->coremask = 1; - for (i = 1; i < NLM_CORES_PER_NODE; i++) { + for (i = 1; i < nlm_cores_per_node(); i++) { for (j = 1000000; j > 0; j--) { if (cpu_ready[i * NLM_THREADS_PER_CORE]) break; diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c index 4d1736fc19557b..2a86e38872a725 100644 --- a/arch/mips/oprofile/common.c +++ b/arch/mips/oprofile/common.c @@ -86,6 +86,8 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) case CPU_34K: case CPU_1004K: case CPU_74K: + case CPU_INTERAPTIV: + case CPU_PROAPTIV: case CPU_LOONGSON1: case CPU_SB1: case CPU_SB1A: diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c index 3a2b6e9f25cfb9..4d94d75ec6f98f 100644 --- a/arch/mips/oprofile/op_model_mipsxx.c +++ b/arch/mips/oprofile/op_model_mipsxx.c @@ -376,6 +376,14 @@ static int __init mipsxx_init(void) op_model_mipsxx_ops.cpu_type = "mips/74K"; break; + case CPU_INTERAPTIV: + op_model_mipsxx_ops.cpu_type = "mips/interAptiv"; + break; + + case CPU_PROAPTIV: + op_model_mipsxx_ops.cpu_type = "mips/proAptiv"; + break; + case CPU_5KC: op_model_mipsxx_ops.cpu_type = "mips/5K"; break; diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 719e4557e22e55..137f2a6feb257a 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -60,4 +60,5 @@ obj-$(CONFIG_CPU_XLP) += pci-xlp.o ifdef CONFIG_PCI_MSI obj-$(CONFIG_CAVIUM_OCTEON_SOC) += msi-octeon.o +obj-$(CONFIG_CPU_XLP) += msi-xlp.o endif diff --git a/arch/mips/pci/fixup-malta.c b/arch/mips/pci/fixup-malta.c index df36e2327c5457..7a0eda782e35cf 100644 --- a/arch/mips/pci/fixup-malta.c +++ b/arch/mips/pci/fixup-malta.c @@ -54,6 +54,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev) static void malta_piix_func0_fixup(struct pci_dev *pdev) { unsigned char reg_val; + u32 reg_val32; /* PIIX PIRQC[A:D] irq mappings */ static int piixirqmap[PIIX4_FUNC0_PIRQRC_IRQ_ROUTING_MAX] = { 0, 0, 0, 3, @@ -83,6 +84,16 @@ static void malta_piix_func0_fixup(struct pci_dev *pdev) pci_write_config_byte(pdev, PIIX4_FUNC0_TOM, reg_val | PIIX4_FUNC0_TOM_TOP_OF_MEMORY_MASK); } + + /* Mux SERIRQ to its pin */ + pci_read_config_dword(pdev, PIIX4_FUNC0_GENCFG, ®_val32); + pci_write_config_dword(pdev, PIIX4_FUNC0_GENCFG, + reg_val32 | PIIX4_FUNC0_GENCFG_SERIRQ); + + /* Enable SERIRQ */ + pci_read_config_byte(pdev, PIIX4_FUNC0_SERIRQC, ®_val); + reg_val |= PIIX4_FUNC0_SERIRQC_EN | PIIX4_FUNC0_SERIRQC_CONT; + pci_write_config_byte(pdev, PIIX4_FUNC0_SERIRQC, reg_val); } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, diff --git a/arch/mips/pci/fixup-rc32434.c b/arch/mips/pci/fixup-rc32434.c index d0f6ecbf35f748..7fcafd5da7da65 100644 --- a/arch/mips/pci/fixup-rc32434.c +++ b/arch/mips/pci/fixup-rc32434.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include diff --git a/arch/mips/pci/fixup-sb1250.c b/arch/mips/pci/fixup-sb1250.c index 1441becdcb6c1c..8feae9154bafb7 100644 --- a/arch/mips/pci/fixup-sb1250.c +++ b/arch/mips/pci/fixup-sb1250.c @@ -8,7 +8,6 @@ * 2 of the License, or (at your option) any later version. */ -#include #include /* diff --git a/arch/mips/pci/msi-xlp.c b/arch/mips/pci/msi-xlp.c new file mode 100644 index 00000000000000..afd8405e018824 --- /dev/null +++ b/arch/mips/pci/msi-xlp.c @@ -0,0 +1,494 @@ +/* + * Copyright (c) 2003-2012 Broadcom Corporation + * All Rights Reserved + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the Broadcom + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define XLP_MSIVEC_PER_LINK 32 +#define XLP_MSIXVEC_TOTAL 32 +#define XLP_MSIXVEC_PER_LINK 8 + +/* 128 MSI irqs per node, mapped starting at NLM_MSI_VEC_BASE */ +static inline int nlm_link_msiirq(int link, int msivec) +{ + return NLM_MSI_VEC_BASE + link * XLP_MSIVEC_PER_LINK + msivec; +} + +static inline int nlm_irq_msivec(int irq) +{ + return irq % XLP_MSIVEC_PER_LINK; +} + +static inline int nlm_irq_msilink(int irq) +{ + return (irq % (XLP_MSIVEC_PER_LINK * PCIE_NLINKS)) / + XLP_MSIVEC_PER_LINK; +} + +/* + * Only 32 MSI-X vectors are possible because there are only 32 PIC + * interrupts for MSI. We split them statically and use 8 MSI-X vectors + * per link - this keeps the allocation and lookup simple. + */ +static inline int nlm_link_msixirq(int link, int bit) +{ + return NLM_MSIX_VEC_BASE + link * XLP_MSIXVEC_PER_LINK + bit; +} + +static inline int nlm_irq_msixvec(int irq) +{ + return irq % XLP_MSIXVEC_TOTAL; /* works when given xirq */ +} + +static inline int nlm_irq_msixlink(int irq) +{ + return nlm_irq_msixvec(irq) / XLP_MSIXVEC_PER_LINK; +} + +/* + * Per link MSI and MSI-X information, set as IRQ handler data for + * MSI and MSI-X interrupts. + */ +struct xlp_msi_data { + struct nlm_soc_info *node; + uint64_t lnkbase; + uint32_t msi_enabled_mask; + uint32_t msi_alloc_mask; + uint32_t msix_alloc_mask; + spinlock_t msi_lock; +}; + +/* + * MSI Chip definitions + * + * On XLP, there is a PIC interrupt associated with each PCIe link on the + * chip (which appears as a PCI bridge to us). This gives us 32 MSI irqa + * per link and 128 overall. + * + * When a device connected to the link raises a MSI interrupt, we get a + * link interrupt and we then have to look at PCIE_MSI_STATUS register at + * the bridge to map it to the IRQ + */ +static void xlp_msi_enable(struct irq_data *d) +{ + struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); + unsigned long flags; + int vec; + + vec = nlm_irq_msivec(d->irq); + spin_lock_irqsave(&md->msi_lock, flags); + md->msi_enabled_mask |= 1u << vec; + nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask); + spin_unlock_irqrestore(&md->msi_lock, flags); +} + +static void xlp_msi_disable(struct irq_data *d) +{ + struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); + unsigned long flags; + int vec; + + vec = nlm_irq_msivec(d->irq); + spin_lock_irqsave(&md->msi_lock, flags); + md->msi_enabled_mask &= ~(1u << vec); + nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask); + spin_unlock_irqrestore(&md->msi_lock, flags); +} + +static void xlp_msi_mask_ack(struct irq_data *d) +{ + struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); + int link, vec; + + link = nlm_irq_msilink(d->irq); + vec = nlm_irq_msivec(d->irq); + xlp_msi_disable(d); + + /* Ack MSI on bridge */ + nlm_write_reg(md->lnkbase, PCIE_MSI_STATUS, 1u << vec); + + /* Ack at eirr and PIC */ + ack_c0_eirr(PIC_PCIE_LINK_MSI_IRQ(link)); + nlm_pic_ack(md->node->picbase, PIC_IRT_PCIE_LINK_INDEX(link)); +} + +static struct irq_chip xlp_msi_chip = { + .name = "XLP-MSI", + .irq_enable = xlp_msi_enable, + .irq_disable = xlp_msi_disable, + .irq_mask_ack = xlp_msi_mask_ack, + .irq_unmask = xlp_msi_enable, +}; + +/* + * The MSI-X interrupt handling is different from MSI, there are 32 + * MSI-X interrupts generated by the PIC and each of these correspond + * to a MSI-X vector (0-31) that can be assigned. + * + * We divide the MSI-X vectors to 8 per link and do a per-link + * allocation + * + * Enable and disable done using standard MSI functions. + */ +static void xlp_msix_mask_ack(struct irq_data *d) +{ + struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); + int link, msixvec; + + msixvec = nlm_irq_msixvec(d->irq); + link = nlm_irq_msixlink(d->irq); + mask_msi_irq(d); + + /* Ack MSI on bridge */ + nlm_write_reg(md->lnkbase, PCIE_MSIX_STATUS, 1u << msixvec); + + /* Ack at eirr and PIC */ + ack_c0_eirr(PIC_PCIE_MSIX_IRQ(link)); + nlm_pic_ack(md->node->picbase, PIC_IRT_PCIE_MSIX_INDEX(msixvec)); +} + +static struct irq_chip xlp_msix_chip = { + .name = "XLP-MSIX", + .irq_enable = unmask_msi_irq, + .irq_disable = mask_msi_irq, + .irq_mask_ack = xlp_msix_mask_ack, + .irq_unmask = unmask_msi_irq, +}; + +void destroy_irq(unsigned int irq) +{ + /* nothing to do yet */ +} + +void arch_teardown_msi_irq(unsigned int irq) +{ + destroy_irq(irq); +} + +/* + * Setup a PCIe link for MSI. By default, the links are in + * legacy interrupt mode. We will switch them to MSI mode + * at the first MSI request. + */ +static void xlp_config_link_msi(uint64_t lnkbase, int lirq, uint64_t msiaddr) +{ + u32 val; + + val = nlm_read_reg(lnkbase, PCIE_INT_EN0); + if ((val & 0x200) == 0) { + val |= 0x200; /* MSI Interrupt enable */ + nlm_write_reg(lnkbase, PCIE_INT_EN0, val); + } + + val = nlm_read_reg(lnkbase, 0x1); /* CMD */ + if ((val & 0x0400) == 0) { + val |= 0x0400; + nlm_write_reg(lnkbase, 0x1, val); + } + + /* Update IRQ in the PCI irq reg */ + val = nlm_read_pci_reg(lnkbase, 0xf); + val &= ~0x1fu; + val |= (1 << 8) | lirq; + nlm_write_pci_reg(lnkbase, 0xf, val); + + /* MSI addr */ + nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_ADDRH, msiaddr >> 32); + nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_ADDRL, msiaddr & 0xffffffff); + + /* MSI cap for bridge */ + val = nlm_read_reg(lnkbase, PCIE_BRIDGE_MSI_CAP); + if ((val & (1 << 16)) == 0) { + val |= 0xb << 16; /* mmc32, msi enable */ + nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_CAP, val); + } +} + +/* + * Allocate a MSI vector on a link + */ +static int xlp_setup_msi(uint64_t lnkbase, int node, int link, + struct msi_desc *desc) +{ + struct xlp_msi_data *md; + struct msi_msg msg; + unsigned long flags; + int msivec, irt, lirq, xirq, ret; + uint64_t msiaddr; + + /* Get MSI data for the link */ + lirq = PIC_PCIE_LINK_MSI_IRQ(link); + xirq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); + md = irq_get_handler_data(xirq); + msiaddr = MSI_LINK_ADDR(node, link); + + spin_lock_irqsave(&md->msi_lock, flags); + if (md->msi_alloc_mask == 0) { + /* switch the link IRQ to MSI range */ + xlp_config_link_msi(lnkbase, lirq, msiaddr); + irt = PIC_IRT_PCIE_LINK_INDEX(link); + nlm_setup_pic_irq(node, lirq, lirq, irt); + nlm_pic_init_irt(nlm_get_node(node)->picbase, irt, lirq, + node * nlm_threads_per_node(), 1 /*en */); + } + + /* allocate a MSI vec, and tell the bridge about it */ + msivec = fls(md->msi_alloc_mask); + if (msivec == XLP_MSIVEC_PER_LINK) { + spin_unlock_irqrestore(&md->msi_lock, flags); + return -ENOMEM; + } + md->msi_alloc_mask |= (1u << msivec); + spin_unlock_irqrestore(&md->msi_lock, flags); + + msg.address_hi = msiaddr >> 32; + msg.address_lo = msiaddr & 0xffffffff; + msg.data = 0xc00 | msivec; + + xirq = xirq + msivec; /* msi mapped to global irq space */ + ret = irq_set_msi_desc(xirq, desc); + if (ret < 0) { + destroy_irq(xirq); + return ret; + } + + write_msi_msg(xirq, &msg); + return 0; +} + +/* + * Switch a link to MSI-X mode + */ +static void xlp_config_link_msix(uint64_t lnkbase, int lirq, uint64_t msixaddr) +{ + u32 val; + + val = nlm_read_reg(lnkbase, 0x2C); + if ((val & 0x80000000U) == 0) { + val |= 0x80000000U; + nlm_write_reg(lnkbase, 0x2C, val); + } + val = nlm_read_reg(lnkbase, PCIE_INT_EN0); + if ((val & 0x200) == 0) { + val |= 0x200; /* MSI Interrupt enable */ + nlm_write_reg(lnkbase, PCIE_INT_EN0, val); + } + + val = nlm_read_reg(lnkbase, 0x1); /* CMD */ + if ((val & 0x0400) == 0) { + val |= 0x0400; + nlm_write_reg(lnkbase, 0x1, val); + } + + /* Update IRQ in the PCI irq reg */ + val = nlm_read_pci_reg(lnkbase, 0xf); + val &= ~0x1fu; + val |= (1 << 8) | lirq; + nlm_write_pci_reg(lnkbase, 0xf, val); + + /* MSI-X addresses */ + nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_BASE, msixaddr >> 8); + nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_LIMIT, + (msixaddr + MSI_ADDR_SZ) >> 8); +} + +/* + * Allocate a MSI-X vector + */ +static int xlp_setup_msix(uint64_t lnkbase, int node, int link, + struct msi_desc *desc) +{ + struct xlp_msi_data *md; + struct msi_msg msg; + unsigned long flags; + int t, msixvec, lirq, xirq, ret; + uint64_t msixaddr; + + /* Get MSI data for the link */ + lirq = PIC_PCIE_MSIX_IRQ(link); + xirq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); + md = irq_get_handler_data(xirq); + msixaddr = MSIX_LINK_ADDR(node, link); + + spin_lock_irqsave(&md->msi_lock, flags); + /* switch the PCIe link to MSI-X mode at the first alloc */ + if (md->msix_alloc_mask == 0) + xlp_config_link_msix(lnkbase, lirq, msixaddr); + + /* allocate a MSI-X vec, and tell the bridge about it */ + t = fls(md->msix_alloc_mask); + if (t == XLP_MSIXVEC_PER_LINK) { + spin_unlock_irqrestore(&md->msi_lock, flags); + return -ENOMEM; + } + md->msix_alloc_mask |= (1u << t); + spin_unlock_irqrestore(&md->msi_lock, flags); + + xirq += t; + msixvec = nlm_irq_msixvec(xirq); + msg.address_hi = msixaddr >> 32; + msg.address_lo = msixaddr & 0xffffffff; + msg.data = 0xc00 | msixvec; + + ret = irq_set_msi_desc(xirq, desc); + if (ret < 0) { + destroy_irq(xirq); + return ret; + } + + write_msi_msg(xirq, &msg); + return 0; +} + +int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) +{ + struct pci_dev *lnkdev; + uint64_t lnkbase; + int node, link, slot; + + lnkdev = xlp_get_pcie_link(dev); + if (lnkdev == NULL) { + dev_err(&dev->dev, "Could not find bridge\n"); + return 1; + } + slot = PCI_SLOT(lnkdev->devfn); + link = PCI_FUNC(lnkdev->devfn); + node = slot / 8; + lnkbase = nlm_get_pcie_base(node, link); + + if (desc->msi_attrib.is_msix) + return xlp_setup_msix(lnkbase, node, link, desc); + else + return xlp_setup_msi(lnkbase, node, link, desc); +} + +void __init xlp_init_node_msi_irqs(int node, int link) +{ + struct nlm_soc_info *nodep; + struct xlp_msi_data *md; + int irq, i, irt, msixvec; + + pr_info("[%d %d] Init node PCI IRT\n", node, link); + nodep = nlm_get_node(node); + + /* Alloc an MSI block for the link */ + md = kzalloc(sizeof(*md), GFP_KERNEL); + spin_lock_init(&md->msi_lock); + md->msi_enabled_mask = 0; + md->msi_alloc_mask = 0; + md->msix_alloc_mask = 0; + md->node = nodep; + md->lnkbase = nlm_get_pcie_base(node, link); + + /* extended space for MSI interrupts */ + irq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); + for (i = irq; i < irq + XLP_MSIVEC_PER_LINK; i++) { + irq_set_chip_and_handler(i, &xlp_msi_chip, handle_level_irq); + irq_set_handler_data(i, md); + } + + for (i = 0; i < XLP_MSIXVEC_PER_LINK; i++) { + /* Initialize MSI-X irts to generate one interrupt per link */ + msixvec = link * XLP_MSIXVEC_PER_LINK + i; + irt = PIC_IRT_PCIE_MSIX_INDEX(msixvec); + nlm_pic_init_irt(nodep->picbase, irt, PIC_PCIE_MSIX_IRQ(link), + node * nlm_threads_per_node(), 1 /* enable */); + + /* Initialize MSI-X extended irq space for the link */ + irq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, i)); + irq_set_chip_and_handler(irq, &xlp_msix_chip, handle_level_irq); + irq_set_handler_data(irq, md); + } + +} + +void nlm_dispatch_msi(int node, int lirq) +{ + struct xlp_msi_data *md; + int link, i, irqbase; + u32 status; + + link = lirq - PIC_PCIE_LINK_MSI_IRQ_BASE; + irqbase = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); + md = irq_get_handler_data(irqbase); + status = nlm_read_reg(md->lnkbase, PCIE_MSI_STATUS) & + md->msi_enabled_mask; + while (status) { + i = __ffs(status); + do_IRQ(irqbase + i); + status &= status - 1; + } +} + +void nlm_dispatch_msix(int node, int lirq) +{ + struct xlp_msi_data *md; + int link, i, irqbase; + u32 status; + + link = lirq - PIC_PCIE_MSIX_IRQ_BASE; + irqbase = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); + md = irq_get_handler_data(irqbase); + status = nlm_read_reg(md->lnkbase, PCIE_MSIX_STATUS); + + /* narrow it down to the MSI-x vectors for our link */ + status = (status >> (link * XLP_MSIXVEC_PER_LINK)) & + ((1 << XLP_MSIXVEC_PER_LINK) - 1); + + while (status) { + i = __ffs(status); + do_IRQ(irqbase + i); + status &= status - 1; + } +} diff --git a/arch/mips/pci/ops-bcm63xx.c b/arch/mips/pci/ops-bcm63xx.c index 6144bb337e4466..13eea696bbe718 100644 --- a/arch/mips/pci/ops-bcm63xx.c +++ b/arch/mips/pci/ops-bcm63xx.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/arch/mips/pci/ops-bonito64.c b/arch/mips/pci/ops-bonito64.c index 830352e3aeda71..c06205a87348d0 100644 --- a/arch/mips/pci/ops-bonito64.c +++ b/arch/mips/pci/ops-bonito64.c @@ -22,7 +22,6 @@ #include #include #include -#include #include diff --git a/arch/mips/pci/ops-lantiq.c b/arch/mips/pci/ops-lantiq.c index 16e7c2526d7756..e5738ee26f4f1e 100644 --- a/arch/mips/pci/ops-lantiq.c +++ b/arch/mips/pci/ops-lantiq.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/pci/ops-loongson2.c b/arch/mips/pci/ops-loongson2.c index 98254afa0287f6..24138bb0cbe150 100644 --- a/arch/mips/pci/ops-loongson2.c +++ b/arch/mips/pci/ops-loongson2.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/arch/mips/pci/ops-mace.c b/arch/mips/pci/ops-mace.c index 1cfb5588699fb6..6b5821febc38fb 100644 --- a/arch/mips/pci/ops-mace.c +++ b/arch/mips/pci/ops-mace.c @@ -6,7 +6,6 @@ * Copyright (C) 2000, 2001 Keith M Wesolowski */ #include -#include #include #include #include diff --git a/arch/mips/pci/ops-msc.c b/arch/mips/pci/ops-msc.c index 92a8543361bb86..dbbf3657896c58 100644 --- a/arch/mips/pci/ops-msc.c +++ b/arch/mips/pci/ops-msc.c @@ -24,7 +24,6 @@ #include #include #include -#include #include diff --git a/arch/mips/pci/ops-nile4.c b/arch/mips/pci/ops-nile4.c index 499e35c3eb3575..a1a7c9f4096e3f 100644 --- a/arch/mips/pci/ops-nile4.c +++ b/arch/mips/pci/ops-nile4.c @@ -1,5 +1,4 @@ #include -#include #include #include diff --git a/arch/mips/pci/ops-rc32434.c b/arch/mips/pci/ops-rc32434.c index 7c7182e2350a36..874ed6df97683a 100644 --- a/arch/mips/pci/ops-rc32434.c +++ b/arch/mips/pci/ops-rc32434.c @@ -26,7 +26,6 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ #include -#include #include #include #include diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c index 162b4cb29dbaa3..0f09eafa5e3abb 100644 --- a/arch/mips/pci/pci-ip27.c +++ b/arch/mips/pci/pci-ip27.c @@ -7,7 +7,6 @@ * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org) * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ -#include #include #include #include diff --git a/arch/mips/pci/pci-malta.c b/arch/mips/pci/pci-malta.c index 37134ddfeaa5d4..f1a73890dd4f10 100644 --- a/arch/mips/pci/pci-malta.c +++ b/arch/mips/pci/pci-malta.c @@ -241,9 +241,9 @@ void __init mips_pcibios_init(void) return; } - /* Change start address to avoid conflicts with ACPI and SMB devices */ - if (controller->io_resource->start < 0x00002000UL) - controller->io_resource->start = 0x00002000UL; + /* PIIX4 ACPI starts at 0x1000 */ + if (controller->io_resource->start < 0x00001000UL) + controller->io_resource->start = 0x00001000UL; iomem_resource.end &= 0xfffffffffULL; /* 64 GB */ ioport_resource.end = controller->io_resource->end; diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c index adeff2bfe4cdd3..72919aeef42b31 100644 --- a/arch/mips/pci/pci-rt3883.c +++ b/arch/mips/pci/pci-rt3883.c @@ -436,9 +436,6 @@ static int rt3883_pci_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; - rpc->base = devm_ioremap_resource(dev, res); if (IS_ERR(rpc->base)) return PTR_ERR(rpc->base); diff --git a/arch/mips/pci/pci-xlp.c b/arch/mips/pci/pci-xlp.c index 653d2db9e0c518..7babf01600cb0f 100644 --- a/arch/mips/pci/pci-xlp.c +++ b/arch/mips/pci/pci-xlp.c @@ -47,10 +47,11 @@ #include #include #include +#include #include -#include #include +#include #include #include @@ -66,9 +67,22 @@ static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn, u32 *cfgaddr; where &= ~3; - if (bus->number == 0 && PCI_SLOT(devfn) == 1 && where == 0x954) + if (cpu_is_xlp9xx()) { + /* be very careful on SoC buses */ + if (bus->number == 0) { + /* Scan only existing nodes - uboot bug? */ + if (PCI_SLOT(devfn) != 0 || + !nlm_node_present(PCI_FUNC(devfn))) + return 0xffffffff; + } else if (bus->parent->number == 0) { /* SoC bus */ + if (PCI_SLOT(devfn) == 0) /* b.0.0 hangs */ + return 0xffffffff; + if (devfn == 44) /* b.5.4 hangs */ + return 0xffffffff; + } + } else if (bus->number == 0 && PCI_SLOT(devfn) == 1 && where == 0x954) { return 0xffffffff; - + } cfgaddr = (u32 *)(pci_config_base + pci_cfg_addr(bus->number, devfn, where)); data = *cfgaddr; @@ -162,27 +176,39 @@ struct pci_controller nlm_pci_controller = { .io_offset = 0x00000000UL, }; -static struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev) +struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev) { struct pci_bus *bus, *p; - /* Find the bridge on bus 0 */ bus = dev->bus; - for (p = bus->parent; p && p->number != 0; p = p->parent) - bus = p; - return p ? bus->self : NULL; + if (cpu_is_xlp9xx()) { + /* find bus with grand parent number == 0 */ + for (p = bus->parent; p && p->parent && p->parent->number != 0; + p = p->parent) + bus = p; + return (p && p->parent) ? bus->self : NULL; + } else { + /* Find the bridge on bus 0 */ + for (p = bus->parent; p && p->number != 0; p = p->parent) + bus = p; + + return p ? bus->self : NULL; + } } -static inline int nlm_pci_link_to_irq(int link) +int xlp_socdev_to_node(const struct pci_dev *lnkdev) { - return PIC_PCIE_LINK_0_IRQ + link; + if (cpu_is_xlp9xx()) + return PCI_FUNC(lnkdev->bus->self->devfn); + else + return PCI_SLOT(lnkdev->devfn) / 8; } int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { struct pci_dev *lnkdev; - int lnkslot, lnkfunc; + int lnkfunc, node; /* * For XLP PCIe, there is an IRQ per Link, find out which @@ -191,9 +217,11 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) lnkdev = xlp_get_pcie_link(dev); if (lnkdev == NULL) return 0; + lnkfunc = PCI_FUNC(lnkdev->devfn); - lnkslot = PCI_SLOT(lnkdev->devfn); - return nlm_irq_to_xirq(lnkslot / 8, nlm_pci_link_to_irq(lnkfunc)); + node = xlp_socdev_to_node(lnkdev); + + return nlm_irq_to_xirq(node, PIC_PCIE_LINK_LEGACY_IRQ(lnkfunc)); } /* Do platform specific device initialization at pci_enable_device() time */ @@ -220,17 +248,38 @@ static void xlp_config_pci_bswap(int node, int link) * Enable byte swap in hardware. Program each link's PCIe SWAP regions * from the link's address ranges. */ - reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link); - nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg); - - reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_LIMIT0 + link); - nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff); - - reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link); - nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg); - - reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link); - nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff); + if (cpu_is_xlp9xx()) { + reg = nlm_read_bridge_reg(nbubase, + BRIDGE_9XX_PCIEMEM_BASE0 + link); + nlm_write_pci_reg(lnkbase, PCIE_9XX_BYTE_SWAP_MEM_BASE, reg); + + reg = nlm_read_bridge_reg(nbubase, + BRIDGE_9XX_PCIEMEM_LIMIT0 + link); + nlm_write_pci_reg(lnkbase, + PCIE_9XX_BYTE_SWAP_MEM_LIM, reg | 0xfff); + + reg = nlm_read_bridge_reg(nbubase, + BRIDGE_9XX_PCIEIO_BASE0 + link); + nlm_write_pci_reg(lnkbase, PCIE_9XX_BYTE_SWAP_IO_BASE, reg); + + reg = nlm_read_bridge_reg(nbubase, + BRIDGE_9XX_PCIEIO_LIMIT0 + link); + nlm_write_pci_reg(lnkbase, + PCIE_9XX_BYTE_SWAP_IO_LIM, reg | 0xfff); + } else { + reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link); + nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg); + + reg = nlm_read_bridge_reg(nbubase, + BRIDGE_PCIEMEM_LIMIT0 + link); + nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff); + + reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link); + nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg); + + reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link); + nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff); + } } #else /* Swap configuration not needed in little-endian mode */ @@ -239,7 +288,6 @@ static inline void xlp_config_pci_bswap(int node, int link) {} static int __init pcibios_init(void) { - struct nlm_soc_info *nodep; uint64_t pciebase; int link, n; u32 reg; @@ -253,20 +301,20 @@ static int __init pcibios_init(void) ioport_resource.end = ~0; for (n = 0; n < NLM_NR_NODES; n++) { - nodep = nlm_get_node(n); - if (!nodep->coremask) - continue; /* node does not exist */ + if (!nlm_node_present(n)) + continue; - for (link = 0; link < 4; link++) { + for (link = 0; link < PCIE_NLINKS; link++) { pciebase = nlm_get_pcie_base(n, link); if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff) continue; xlp_config_pci_bswap(n, link); + xlp_init_node_msi_irqs(n, link); /* put in intpin and irq - u-boot does not */ reg = nlm_read_pci_reg(pciebase, 0xf); - reg &= ~0x1fu; - reg |= (1 << 8) | nlm_pci_link_to_irq(link); + reg &= ~0x1ffu; + reg |= (1 << 8) | PIC_PCIE_LINK_LEGACY_IRQ(link); nlm_write_pci_reg(pciebase, 0xf, reg); pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link); } diff --git a/arch/mips/pmcs-msp71xx/Kconfig b/arch/mips/pmcs-msp71xx/Kconfig index 3482b8c8640cfa..6073ca456d110c 100644 --- a/arch/mips/pmcs-msp71xx/Kconfig +++ b/arch/mips/pmcs-msp71xx/Kconfig @@ -6,6 +6,7 @@ config PMC_MSP4200_EVAL bool "PMC-Sierra MSP4200 Eval Board" select IRQ_MSP_SLP select HW_HAS_PCI + select MIPS_L1_CACHE_SHIFT_4 config PMC_MSP4200_GW bool "PMC-Sierra MSP4200 VoIP Gateway" diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig index 424f03496d14ad..1bfd1c17b3c223 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -15,6 +15,7 @@ choice config SOC_RT288X bool "RT288x" + select MIPS_L1_CACHE_SHIFT_4 config SOC_RT305X bool "RT305x" diff --git a/arch/mips/sgi-ip27/ip27-console.c b/arch/mips/sgi-ip27/ip27-console.c index b952d5b1af862a..45fdfbcbd4c612 100644 --- a/arch/mips/sgi-ip27/ip27-console.c +++ b/arch/mips/sgi-ip27/ip27-console.c @@ -5,7 +5,6 @@ * * Copyright (C) 2001, 2002 Ralf Baechle */ -#include #include #include diff --git a/arch/mips/sgi-ip27/ip27-irq-pci.c b/arch/mips/sgi-ip27/ip27-irq-pci.c index ec22ec5600f3bf..2a1c40784bd9e3 100644 --- a/arch/mips/sgi-ip27/ip27-irq-pci.c +++ b/arch/mips/sgi-ip27/ip27-irq-pci.c @@ -8,7 +8,6 @@ #undef DEBUG -#include #include #include #include diff --git a/arch/mips/sgi-ip27/ip27-klconfig.c b/arch/mips/sgi-ip27/ip27-klconfig.c index 7afe14688003a2..c873d62ff08355 100644 --- a/arch/mips/sgi-ip27/ip27-klconfig.c +++ b/arch/mips/sgi-ip27/ip27-klconfig.c @@ -2,7 +2,6 @@ * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org) * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ -#include #include #include #include diff --git a/arch/mips/sgi-ip27/ip27-xtalk.c b/arch/mips/sgi-ip27/ip27-xtalk.c index d59b820f528d1b..20f582a2137a3f 100644 --- a/arch/mips/sgi-ip27/ip27-xtalk.c +++ b/arch/mips/sgi-ip27/ip27-xtalk.c @@ -7,7 +7,6 @@ * Generic XTALK initialization code */ -#include #include #include #include diff --git a/arch/mn10300/Makefile b/arch/mn10300/Makefile index a3d0fef3b126ba..3f1ea5ddc40264 100644 --- a/arch/mn10300/Makefile +++ b/arch/mn10300/Makefile @@ -92,14 +92,6 @@ define archhelp echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage)' endef -# If you make sure the .S files get compiled with debug info, -# uncomment the following to disable optimisations -# that are unhelpful whilst debugging. -ifdef CONFIG_DEBUG_INFO -#KBUILD_CFLAGS += -O1 -KBUILD_AFLAGS += -Wa,--gdwarf2 -endif - # # include the appropriate processor- and unit-specific headers # diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S index d8a455ede5a751..fec8bf97d80642 100644 --- a/arch/openrisc/kernel/entry.S +++ b/arch/openrisc/kernel/entry.S @@ -853,37 +853,44 @@ UNHANDLED_EXCEPTION(_vector_0x1f00,0x1f00) /* ========================================================[ return ] === */ +_resume_userspace: + DISABLE_INTERRUPTS(r3,r4) + l.lwz r4,TI_FLAGS(r10) + l.andi r13,r4,_TIF_WORK_MASK + l.sfeqi r13,0 + l.bf _restore_all + l.nop + _work_pending: - /* - * if (current_thread_info->flags & _TIF_NEED_RESCHED) - * schedule(); - */ - l.lwz r5,TI_FLAGS(r10) - l.andi r3,r5,_TIF_NEED_RESCHED - l.sfnei r3,0 - l.bnf _work_notifysig + l.lwz r5,PT_ORIG_GPR11(r1) + l.sfltsi r5,0 + l.bnf 1f l.nop - l.jal schedule + l.andi r5,r5,0 +1: + l.jal do_work_pending + l.ori r3,r1,0 /* pt_regs */ + + l.sfeqi r11,0 + l.bf _restore_all l.nop - l.j _resume_userspace + l.sfltsi r11,0 + l.bnf 1f l.nop - -/* Handle pending signals and notify-resume requests. - * do_notify_resume must be passed the latest pushed pt_regs, not - * necessarily the "userspace" ones. Also, pt_regs->syscallno - * must be set so that the syscall restart functionality works. - */ -_work_notifysig: - l.jal do_notify_resume - l.ori r3,r1,0 /* pt_regs */ - -_resume_userspace: - DISABLE_INTERRUPTS(r3,r4) - l.lwz r3,TI_FLAGS(r10) - l.andi r3,r3,_TIF_WORK_MASK - l.sfnei r3,0 - l.bf _work_pending + l.and r11,r11,r0 + l.ori r11,r11,__NR_restart_syscall + l.j _syscall_check_trace_enter l.nop +1: + l.lwz r11,PT_ORIG_GPR11(r1) + /* Restore arg registers */ + l.lwz r3,PT_GPR3(r1) + l.lwz r4,PT_GPR4(r1) + l.lwz r5,PT_GPR5(r1) + l.lwz r6,PT_GPR6(r1) + l.lwz r7,PT_GPR7(r1) + l.j _syscall_check_trace_enter + l.lwz r8,PT_GPR8(r1) _restore_all: RESTORE_ALL diff --git a/arch/openrisc/kernel/signal.c b/arch/openrisc/kernel/signal.c index ae167f7e081aa0..66775bc07a8eeb 100644 --- a/arch/openrisc/kernel/signal.c +++ b/arch/openrisc/kernel/signal.c @@ -28,24 +28,24 @@ #include #include +#include #include #include #define DEBUG_SIG 0 struct rt_sigframe { - struct siginfo *pinfo; - void *puc; struct siginfo info; struct ucontext uc; unsigned char retcode[16]; /* trampoline code */ }; -static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +static int restore_sigcontext(struct pt_regs *regs, + struct sigcontext __user *sc) { - unsigned int err = 0; + int err = 0; - /* Alwys make any pending restarted system call return -EINTR */ + /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; /* @@ -53,25 +53,21 @@ static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) * (sc is already checked for VERIFY_READ since the sigframe was * checked in sys_sigreturn previously) */ - if (__copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long))) - goto badframe; - if (__copy_from_user(®s->pc, &sc->regs.pc, sizeof(unsigned long))) - goto badframe; - if (__copy_from_user(®s->sr, &sc->regs.sr, sizeof(unsigned long))) - goto badframe; + err |= __copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long)); + err |= __copy_from_user(®s->pc, &sc->regs.pc, sizeof(unsigned long)); + err |= __copy_from_user(®s->sr, &sc->regs.sr, sizeof(unsigned long)); /* make sure the SM-bit is cleared so user-mode cannot fool us */ regs->sr &= ~SPR_SR_SM; + regs->orig_gpr11 = -1; /* Avoid syscall restart checks */ + /* TODO: the other ports use regs->orig_XX to disable syscall checks * after this completes, but we don't use that mechanism. maybe we can * use it now ? */ return err; - -badframe: - return 1; } asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs) @@ -111,21 +107,18 @@ asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs) * Set up a signal frame. */ -static int setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, - unsigned long mask) +static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { int err = 0; /* copy the regs */ - + /* There should be no need to save callee-saved registers here... + * ...but we save them anyway. Revisit this + */ err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long)); err |= __copy_to_user(&sc->regs.pc, ®s->pc, sizeof(unsigned long)); err |= __copy_to_user(&sc->regs.sr, ®s->sr, sizeof(unsigned long)); - /* then some other stuff */ - - err |= __put_user(mask, &sc->oldmask); - return err; } @@ -173,55 +166,53 @@ static inline void __user *get_sigframe(struct k_sigaction *ka, * trampoline which performs the syscall sigreturn, or a provided * user-mode trampoline. */ -static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs *regs) +static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, + struct pt_regs *regs) { struct rt_sigframe *frame; unsigned long return_ip; int err = 0; - frame = get_sigframe(ka, regs, sizeof(*frame)); + frame = get_sigframe(&ksig->ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto give_sigsegv; + return -EFAULT; - err |= __put_user(&frame->info, &frame->pinfo); - err |= __put_user(&frame->uc, &frame->puc); + /* Create siginfo. */ + if (ksig->ka.sa.sa_flags & SA_SIGINFO) + err |= copy_siginfo_to_user(&frame->info, &ksig->info); - if (ka->sa.sa_flags & SA_SIGINFO) - err |= copy_siginfo_to_user(&frame->info, info); - if (err) - goto give_sigsegv; - - /* Clear all the bits of the ucontext we don't use. */ - err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); + /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(NULL, &frame->uc.uc_link); err |= __save_altstack(&frame->uc.uc_stack, regs->sp); - err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); + err |= setup_sigcontext(regs, &frame->uc.uc_mcontext); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); if (err) - goto give_sigsegv; + return -EFAULT; /* trampoline - the desired return ip is the retcode itself */ return_ip = (unsigned long)&frame->retcode; - /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */ - err |= __put_user(0xa960, (short *)(frame->retcode + 0)); - err |= __put_user(__NR_rt_sigreturn, (short *)(frame->retcode + 2)); + /* This is: + l.ori r11,r0,__NR_sigreturn + l.sys 1 + */ + err |= __put_user(0xa960, (short *)(frame->retcode + 0)); + err |= __put_user(__NR_rt_sigreturn, (short *)(frame->retcode + 2)); err |= __put_user(0x20000001, (unsigned long *)(frame->retcode + 4)); err |= __put_user(0x15000000, (unsigned long *)(frame->retcode + 8)); if (err) - goto give_sigsegv; + return -EFAULT; /* TODO what is the current->exec_domain stuff and invmap ? */ /* Set up registers for signal handler */ - regs->pc = (unsigned long)ka->sa.sa_handler; /* what we enter NOW */ + regs->pc = (unsigned long)ksig->ka.sa.sa_handler; /* what we enter NOW */ regs->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */ - regs->gpr[3] = (unsigned long)sig; /* arg 1: signo */ + regs->gpr[3] = (unsigned long)ksig->sig; /* arg 1: signo */ regs->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */ regs->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */ @@ -229,25 +220,16 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, regs->sp = (unsigned long)frame; return 0; - -give_sigsegv: - force_sigsegv(sig, current); - return -EFAULT; } static inline void -handle_signal(unsigned long sig, - siginfo_t *info, struct k_sigaction *ka, - struct pt_regs *regs) +handle_signal(struct ksignal *ksig, struct pt_regs *regs) { int ret; - ret = setup_rt_frame(sig, ka, info, sigmask_to_save(), regs); - if (ret) - return; + ret = setup_rt_frame(ksig, sigmask_to_save(), regs); - signal_delivered(sig, info, ka, regs, - test_thread_flag(TIF_SINGLESTEP)); + signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP)); } /* @@ -262,82 +244,99 @@ handle_signal(unsigned long sig, * mode below. */ -void do_signal(struct pt_regs *regs) +int do_signal(struct pt_regs *regs, int syscall) { - siginfo_t info; - int signr; - struct k_sigaction ka; - - /* - * We want the common case to go fast, which - * is why we may in certain cases get here from - * kernel mode. Just return without doing anything - * if so. - */ - if (!user_mode(regs)) - return; - - signr = get_signal_to_deliver(&info, &ka, regs, NULL); - - /* If we are coming out of a syscall then we need - * to check if the syscall was interrupted and wants to be - * restarted after handling the signal. If so, the original - * syscall number is put back into r11 and the PC rewound to - * point at the l.sys instruction that resulted in the - * original syscall. Syscall results other than the four - * below mean that the syscall executed to completion and no - * restart is necessary. - */ - if (regs->orig_gpr11) { - int restart = 0; - - switch (regs->gpr[11]) { + struct ksignal ksig; + unsigned long continue_addr = 0; + unsigned long restart_addr = 0; + unsigned long retval = 0; + int restart = 0; + + if (syscall) { + continue_addr = regs->pc; + restart_addr = continue_addr - 4; + retval = regs->gpr[11]; + + /* + * Setup syscall restart here so that a debugger will + * see the already changed PC. + */ + switch (retval) { case -ERESTART_RESTARTBLOCK: + restart = -2; + /* Fall through */ case -ERESTARTNOHAND: - /* Restart if there is no signal handler */ - restart = (signr <= 0); - break; case -ERESTARTSYS: - /* Restart if there no signal handler or - * SA_RESTART flag is set */ - restart = (signr <= 0 || (ka.sa.sa_flags & SA_RESTART)); - break; case -ERESTARTNOINTR: - /* Always restart */ - restart = 1; + restart++; + regs->gpr[11] = regs->orig_gpr11; + regs->pc = restart_addr; break; } - - if (restart) { - if (regs->gpr[11] == -ERESTART_RESTARTBLOCK) - regs->gpr[11] = __NR_restart_syscall; - else - regs->gpr[11] = regs->orig_gpr11; - regs->pc -= 4; - } else { - regs->gpr[11] = -EINTR; - } } - if (signr <= 0) { - /* no signal to deliver so we just put the saved sigmask - * back */ + /* + * Get the signal to deliver. During the call to get_signal the + * debugger may change all our registers so we may need to revert + * the decision to restart the syscall; specifically, if the PC is + * changed, don't restart the syscall. + */ + if (get_signal(&ksig)) { + if (unlikely(restart) && regs->pc == restart_addr) { + if (retval == -ERESTARTNOHAND || + retval == -ERESTART_RESTARTBLOCK + || (retval == -ERESTARTSYS + && !(ksig.ka.sa.sa_flags & SA_RESTART))) { + /* No automatic restart */ + regs->gpr[11] = -EINTR; + regs->pc = continue_addr; + } + } + handle_signal(&ksig, regs); + } else { + /* no handler */ restore_saved_sigmask(); - } else { /* signr > 0 */ - /* Whee! Actually deliver the signal. */ - handle_signal(signr, &info, &ka, regs); + /* + * Restore pt_regs PC as syscall restart will be handled by + * kernel without return to userspace + */ + if (unlikely(restart) && regs->pc == restart_addr) { + regs->pc = continue_addr; + return restart; + } } - return; + return 0; } -asmlinkage void do_notify_resume(struct pt_regs *regs) +asmlinkage int +do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) { - if (current_thread_info()->flags & _TIF_SIGPENDING) - do_signal(regs); - - if (current_thread_info()->flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); - } + do { + if (likely(thread_flags & _TIF_NEED_RESCHED)) { + schedule(); + } else { + if (unlikely(!user_mode(regs))) + return 0; + local_irq_enable(); + if (thread_flags & _TIF_SIGPENDING) { + int restart = do_signal(regs, syscall); + if (unlikely(restart)) { + /* + * Restart without handlers. + * Deal with it without leaving + * the kernel space. + */ + return restart; + } + syscall = 0; + } else { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + } + } + local_irq_disable(); + thread_flags = current_thread_info()->flags; + } while (thread_flags & _TIF_WORK_MASK); + return 0; } diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c index 88d0962de65a8c..2bedafea3d94c1 100644 --- a/arch/parisc/hpux/fs.c +++ b/arch/parisc/hpux/fs.c @@ -33,22 +33,9 @@ int hpux_execve(struct pt_regs *regs) { - int error; - struct filename *filename; - - filename = getname((const char __user *) regs->gr[26]); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - goto out; - - error = do_execve(filename->name, + return do_execve(getname((const char __user *) regs->gr[26]), (const char __user *const __user *) regs->gr[25], (const char __user *const __user *) regs->gr[24]); - - putname(filename); - -out: - return error; } struct hpux_dirent { diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h index 2f9b751878ba86..de65f66ea64e75 100644 --- a/arch/parisc/include/asm/cacheflush.h +++ b/arch/parisc/include/asm/cacheflush.h @@ -132,7 +132,6 @@ void mark_rodata_ro(void); static inline void *kmap(struct page *page) { might_sleep(); - flush_dcache_page(page); return page_address(page); } @@ -144,7 +143,6 @@ static inline void kunmap(struct page *page) static inline void *kmap_atomic(struct page *page) { pagefault_disable(); - flush_dcache_page(page); return page_address(page); } diff --git a/arch/parisc/include/asm/elf.h b/arch/parisc/include/asm/elf.h index ad2b5039789420..3391d061eccc02 100644 --- a/arch/parisc/include/asm/elf.h +++ b/arch/parisc/include/asm/elf.h @@ -348,4 +348,8 @@ struct pt_regs; /* forward declaration... */ #define ELF_HWCAP 0 +struct mm_struct; +extern unsigned long arch_randomize_brk(struct mm_struct *); +#define arch_randomize_brk arch_randomize_brk + #endif diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h index c53fc63149e831..637fe031aa8476 100644 --- a/arch/parisc/include/asm/page.h +++ b/arch/parisc/include/asm/page.h @@ -29,7 +29,8 @@ struct page; void clear_page_asm(void *page); void copy_page_asm(void *to, void *from); #define clear_user_page(vto, vaddr, page) clear_page_asm(vto) -#define copy_user_page(vto, vfrom, vaddr, page) copy_page_asm(vto, vfrom) +void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, + struct page *pg); /* #define CONFIG_PARISC_TMPALIAS */ diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h index 34899b5d959aa5..22b89d1edba7a9 100644 --- a/arch/parisc/include/asm/pgtable.h +++ b/arch/parisc/include/asm/pgtable.h @@ -511,6 +511,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, /* We provide our own get_unmapped_area to provide cache coherency */ #define HAVE_ARCH_UNMAPPED_AREA +#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG #define __HAVE_ARCH_PTEP_GET_AND_CLEAR diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h index cc2290a3cace1e..198a86feb5748f 100644 --- a/arch/parisc/include/asm/processor.h +++ b/arch/parisc/include/asm/processor.h @@ -30,6 +30,8 @@ #endif #define current_text_addr() ({ void *pc; current_ia(pc); pc; }) +#define HAVE_ARCH_PICK_MMAP_LAYOUT + #define TASK_SIZE_OF(tsk) ((tsk)->thread.task_size) #define TASK_SIZE TASK_SIZE_OF(current) #define TASK_UNMAPPED_BASE (current->thread.map_base) diff --git a/arch/parisc/include/asm/thread_info.h b/arch/parisc/include/asm/thread_info.h index d5f97ea3a4e1ab..4b9b10ce1f9d09 100644 --- a/arch/parisc/include/asm/thread_info.h +++ b/arch/parisc/include/asm/thread_info.h @@ -76,6 +76,16 @@ struct thread_info { #define _TIF_SYSCALL_TRACE_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \ _TIF_BLOCKSTEP | _TIF_SYSCALL_AUDIT) +#ifdef CONFIG_64BIT +# ifdef CONFIG_COMPAT +# define is_32bit_task() (test_thread_flag(TIF_32BIT)) +# else +# define is_32bit_task() (0) +# endif +#else +# define is_32bit_task() (1) +#endif + #endif /* __KERNEL__ */ #endif /* _ASM_PARISC_THREAD_INFO_H */ diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h index f3a8aa554841c1..c0ae62520d1575 100644 --- a/arch/parisc/include/uapi/asm/errno.h +++ b/arch/parisc/include/uapi/asm/errno.h @@ -106,7 +106,7 @@ #define EALREADY 244 /* Operation already in progress */ #define EINPROGRESS 245 /* Operation now in progress */ -#define EWOULDBLOCK 246 /* Operation would block (Linux returns EAGAIN) */ +#define EWOULDBLOCK EAGAIN /* Operation would block (Not HPUX compliant) */ #define ENOTEMPTY 247 /* Directory not empty */ #define ENAMETOOLONG 248 /* File name too long */ #define ELOOP 249 /* Too many symbolic links encountered */ diff --git a/arch/parisc/include/uapi/asm/stat.h b/arch/parisc/include/uapi/asm/stat.h index d76fbda5d62c04..b606b366d0a743 100644 --- a/arch/parisc/include/uapi/asm/stat.h +++ b/arch/parisc/include/uapi/asm/stat.h @@ -5,67 +5,65 @@ struct stat { unsigned int st_dev; /* dev_t is 32 bits on parisc */ - ino_t st_ino; /* 32 bits */ - mode_t st_mode; /* 16 bits */ + unsigned int st_ino; /* 32 bits */ + unsigned short st_mode; /* 16 bits */ unsigned short st_nlink; /* 16 bits */ unsigned short st_reserved1; /* old st_uid */ unsigned short st_reserved2; /* old st_gid */ unsigned int st_rdev; - off_t st_size; - time_t st_atime; + signed int st_size; + signed int st_atime; unsigned int st_atime_nsec; - time_t st_mtime; + signed int st_mtime; unsigned int st_mtime_nsec; - time_t st_ctime; + signed int st_ctime; unsigned int st_ctime_nsec; int st_blksize; int st_blocks; unsigned int __unused1; /* ACL stuff */ unsigned int __unused2; /* network */ - ino_t __unused3; /* network */ + unsigned int __unused3; /* network */ unsigned int __unused4; /* cnodes */ unsigned short __unused5; /* netsite */ short st_fstype; unsigned int st_realdev; unsigned short st_basemode; unsigned short st_spareshort; - uid_t st_uid; - gid_t st_gid; + unsigned int st_uid; + unsigned int st_gid; unsigned int st_spare4[3]; }; #define STAT_HAVE_NSEC -typedef __kernel_off64_t off64_t; - struct hpux_stat64 { unsigned int st_dev; /* dev_t is 32 bits on parisc */ - ino_t st_ino; /* 32 bits */ - mode_t st_mode; /* 16 bits */ + unsigned int st_ino; /* 32 bits */ + unsigned short st_mode; /* 16 bits */ unsigned short st_nlink; /* 16 bits */ unsigned short st_reserved1; /* old st_uid */ unsigned short st_reserved2; /* old st_gid */ unsigned int st_rdev; - off64_t st_size; - time_t st_atime; + signed long long st_size; + signed int st_atime; unsigned int st_spare1; - time_t st_mtime; + signed int st_mtime; unsigned int st_spare2; - time_t st_ctime; + signed int st_ctime; unsigned int st_spare3; int st_blksize; - __u64 st_blocks; + unsigned long long st_blocks; unsigned int __unused1; /* ACL stuff */ unsigned int __unused2; /* network */ - ino_t __unused3; /* network */ + unsigned int __unused3; /* network */ unsigned int __unused4; /* cnodes */ unsigned short __unused5; /* netsite */ short st_fstype; unsigned int st_realdev; unsigned short st_basemode; unsigned short st_spareshort; - uid_t st_uid; - gid_t st_gid; + unsigned int st_uid; + unsigned int st_gid; unsigned int st_spare4[3]; }; diff --git a/arch/parisc/include/uapi/asm/unistd.h b/arch/parisc/include/uapi/asm/unistd.h index 2c8b9bde18ebf7..42706794a36f34 100644 --- a/arch/parisc/include/uapi/asm/unistd.h +++ b/arch/parisc/include/uapi/asm/unistd.h @@ -826,8 +826,10 @@ #define __NR_process_vm_writev (__NR_Linux + 331) #define __NR_kcmp (__NR_Linux + 332) #define __NR_finit_module (__NR_Linux + 333) +#define __NR_sched_setattr (__NR_Linux + 334) +#define __NR_sched_getattr (__NR_Linux + 335) -#define __NR_Linux_syscalls (__NR_finit_module + 1) +#define __NR_Linux_syscalls (__NR_sched_getattr + 1) #define __IGNORE_select /* newselect */ diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index a72545554a3154..ac87a40502e6f6 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -388,6 +388,20 @@ void flush_kernel_dcache_page_addr(void *addr) } EXPORT_SYMBOL(flush_kernel_dcache_page_addr); +void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, + struct page *pg) +{ + /* Copy using kernel mapping. No coherency is needed (all in + kunmap) for the `to' page. However, the `from' page needs to + be flushed through a mapping equivalent to the user mapping + before it can be accessed through the kernel mapping. */ + preempt_disable(); + flush_dcache_page_asm(__pa(vfrom), vaddr); + preempt_enable(); + copy_page_asm(vto, vfrom); +} +EXPORT_SYMBOL(copy_user_page); + void purge_tlb_entries(struct mm_struct *mm, unsigned long addr) { unsigned long flags; diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 55f92b61418287..0bbbf0d3f6081b 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -13,7 +13,7 @@ * Copyright (C) 2000 Grant Grundler * Copyright (C) 2001 Alan Modra * Copyright (C) 2001-2002 Ryan Bradetich - * Copyright (C) 2001-2007 Helge Deller + * Copyright (C) 2001-2014 Helge Deller * Copyright (C) 2002 Randolph Chung * * @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -286,3 +287,21 @@ void *dereference_function_descriptor(void *ptr) return ptr; } #endif + +static inline unsigned long brk_rnd(void) +{ + /* 8MB for 32bit, 1GB for 64bit */ + if (is_32bit_task()) + return (get_random_int() & 0x7ffUL) << PAGE_SHIFT; + else + return (get_random_int() & 0x3ffffUL) << PAGE_SHIFT; +} + +unsigned long arch_randomize_brk(struct mm_struct *mm) +{ + unsigned long ret = PAGE_ALIGN(mm->brk + brk_rnd()); + + if (ret < mm->brk) + return mm->brk; + return ret; +} diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index 0d3a9d4927b580..b7cadc4a06cdf4 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -5,6 +5,7 @@ * Copyright (C) 1999-2003 Matthew Wilcox * Copyright (C) 2000-2003 Paul Bame * Copyright (C) 2001 Thomas Bogendoerfer + * Copyright (C) 1999-2014 Helge Deller * * * This program is free software; you can redistribute it and/or modify @@ -23,6 +24,7 @@ */ #include +#include #include #include #include @@ -32,78 +34,230 @@ #include #include #include +#include -static unsigned long get_unshared_area(unsigned long addr, unsigned long len) +/* we construct an artificial offset for the mapping based on the physical + * address of the kernel mapping variable */ +#define GET_LAST_MMAP(filp) \ + (filp ? ((unsigned long) filp->f_mapping) >> 8 : 0UL) +#define SET_LAST_MMAP(filp, val) \ + { /* nothing */ } + +static int get_offset(unsigned int last_mmap) { - struct vm_unmapped_area_info info; + return (last_mmap & (SHMLBA-1)) >> PAGE_SHIFT; +} - info.flags = 0; - info.length = len; - info.low_limit = PAGE_ALIGN(addr); - info.high_limit = TASK_SIZE; - info.align_mask = 0; - info.align_offset = 0; - return vm_unmapped_area(&info); +static unsigned long shared_align_offset(unsigned int last_mmap, + unsigned long pgoff) +{ + return (get_offset(last_mmap) + pgoff) << PAGE_SHIFT; } -/* - * We need to know the offset to use. Old scheme was to look for - * existing mapping and use the same offset. New scheme is to use the - * address of the kernel data structure as the seed for the offset. - * We'll see how that works... - * - * The mapping is cacheline aligned, so there's no information in the bottom - * few bits of the address. We're looking for 10 bits (4MB / 4k), so let's - * drop the bottom 8 bits and use bits 8-17. - */ -static int get_offset(struct address_space *mapping) +static inline unsigned long COLOR_ALIGN(unsigned long addr, + unsigned int last_mmap, unsigned long pgoff) { - return (unsigned long) mapping >> 8; + unsigned long base = (addr+SHMLBA-1) & ~(SHMLBA-1); + unsigned long off = (SHMLBA-1) & + (shared_align_offset(last_mmap, pgoff) << PAGE_SHIFT); + + return base + off; } -static unsigned long shared_align_offset(struct file *filp, unsigned long pgoff) +/* + * Top of mmap area (just below the process stack). + */ + +static unsigned long mmap_upper_limit(void) { - struct address_space *mapping = filp ? filp->f_mapping : NULL; + unsigned long stack_base; - return (get_offset(mapping) + pgoff) << PAGE_SHIFT; + /* Limit stack size to 1GB - see setup_arg_pages() in fs/exec.c */ + stack_base = rlimit_max(RLIMIT_STACK); + if (stack_base > (1 << 30)) + stack_base = 1 << 30; + + return PAGE_ALIGN(STACK_TOP - stack_base); } -static unsigned long get_shared_area(struct file *filp, unsigned long addr, - unsigned long len, unsigned long pgoff) + +unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags) { + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long task_size = TASK_SIZE; + int do_color_align, last_mmap; struct vm_unmapped_area_info info; + if (len > task_size) + return -ENOMEM; + + do_color_align = 0; + if (filp || (flags & MAP_SHARED)) + do_color_align = 1; + last_mmap = GET_LAST_MMAP(filp); + + if (flags & MAP_FIXED) { + if ((flags & MAP_SHARED) && last_mmap && + (addr - shared_align_offset(last_mmap, pgoff)) + & (SHMLBA - 1)) + return -EINVAL; + goto found_addr; + } + + if (addr) { + if (do_color_align && last_mmap) + addr = COLOR_ALIGN(addr, last_mmap, pgoff); + else + addr = PAGE_ALIGN(addr); + + vma = find_vma(mm, addr); + if (task_size - len >= addr && + (!vma || addr + len <= vma->vm_start)) + goto found_addr; + } + info.flags = 0; info.length = len; - info.low_limit = PAGE_ALIGN(addr); - info.high_limit = TASK_SIZE; - info.align_mask = PAGE_MASK & (SHMLBA - 1); - info.align_offset = shared_align_offset(filp, pgoff); - return vm_unmapped_area(&info); + info.low_limit = mm->mmap_legacy_base; + info.high_limit = mmap_upper_limit(); + info.align_mask = last_mmap ? (PAGE_MASK & (SHMLBA - 1)) : 0; + info.align_offset = shared_align_offset(last_mmap, pgoff); + addr = vm_unmapped_area(&info); + +found_addr: + if (do_color_align && !last_mmap && !(addr & ~PAGE_MASK)) + SET_LAST_MMAP(filp, addr - (pgoff << PAGE_SHIFT)); + + return addr; } -unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, - unsigned long len, unsigned long pgoff, unsigned long flags) +unsigned long +arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, + const unsigned long len, const unsigned long pgoff, + const unsigned long flags) { + struct vm_area_struct *vma; + struct mm_struct *mm = current->mm; + unsigned long addr = addr0; + int do_color_align, last_mmap; + struct vm_unmapped_area_info info; + +#ifdef CONFIG_64BIT + /* This should only ever run for 32-bit processes. */ + BUG_ON(!test_thread_flag(TIF_32BIT)); +#endif + + /* requested length too big for entire address space */ if (len > TASK_SIZE) return -ENOMEM; + + do_color_align = 0; + if (filp || (flags & MAP_SHARED)) + do_color_align = 1; + last_mmap = GET_LAST_MMAP(filp); + if (flags & MAP_FIXED) { - if ((flags & MAP_SHARED) && - (addr - shared_align_offset(filp, pgoff)) & (SHMLBA - 1)) + if ((flags & MAP_SHARED) && last_mmap && + (addr - shared_align_offset(last_mmap, pgoff)) + & (SHMLBA - 1)) return -EINVAL; - return addr; + goto found_addr; } - if (!addr) - addr = TASK_UNMAPPED_BASE; - if (filp || (flags & MAP_SHARED)) - addr = get_shared_area(filp, addr, len, pgoff); - else - addr = get_unshared_area(addr, len); + /* requesting a specific address */ + if (addr) { + if (do_color_align && last_mmap) + addr = COLOR_ALIGN(addr, last_mmap, pgoff); + else + addr = PAGE_ALIGN(addr); + vma = find_vma(mm, addr); + if (TASK_SIZE - len >= addr && + (!vma || addr + len <= vma->vm_start)) + goto found_addr; + } + + info.flags = VM_UNMAPPED_AREA_TOPDOWN; + info.length = len; + info.low_limit = PAGE_SIZE; + info.high_limit = mm->mmap_base; + info.align_mask = last_mmap ? (PAGE_MASK & (SHMLBA - 1)) : 0; + info.align_offset = shared_align_offset(last_mmap, pgoff); + addr = vm_unmapped_area(&info); + if (!(addr & ~PAGE_MASK)) + goto found_addr; + VM_BUG_ON(addr != -ENOMEM); + + /* + * A failed mmap() very likely causes application failure, + * so fall back to the bottom-up function here. This scenario + * can happen with large stack limits and large mmap() + * allocations. + */ + return arch_get_unmapped_area(filp, addr0, len, pgoff, flags); + +found_addr: + if (do_color_align && !last_mmap && !(addr & ~PAGE_MASK)) + SET_LAST_MMAP(filp, addr - (pgoff << PAGE_SHIFT)); return addr; } +static int mmap_is_legacy(void) +{ + if (current->personality & ADDR_COMPAT_LAYOUT) + return 1; + + /* parisc stack always grows up - so a unlimited stack should + * not be an indicator to use the legacy memory layout. + * if (rlimit(RLIMIT_STACK) == RLIM_INFINITY) + * return 1; + */ + + return sysctl_legacy_va_layout; +} + +static unsigned long mmap_rnd(void) +{ + unsigned long rnd = 0; + + /* + * 8 bits of randomness in 32bit mmaps, 20 address space bits + * 28 bits of randomness in 64bit mmaps, 40 address space bits + */ + if (current->flags & PF_RANDOMIZE) { + if (is_32bit_task()) + rnd = get_random_int() % (1<<8); + else + rnd = get_random_int() % (1<<28); + } + return rnd << PAGE_SHIFT; +} + +static unsigned long mmap_legacy_base(void) +{ + return TASK_UNMAPPED_BASE + mmap_rnd(); +} + +/* + * This function, called very early during the creation of a new + * process VM image, sets up which VM layout function to use: + */ +void arch_pick_mmap_layout(struct mm_struct *mm) +{ + mm->mmap_legacy_base = mmap_legacy_base(); + mm->mmap_base = mmap_upper_limit(); + + if (mmap_is_legacy()) { + mm->mmap_base = mm->mmap_legacy_base; + mm->get_unmapped_area = arch_get_unmapped_area; + } else { + mm->get_unmapped_area = arch_get_unmapped_area_topdown; + } +} + + asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 0c9107285e6687..8fa3fbb3e4d380 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -429,6 +429,8 @@ ENTRY_COMP(process_vm_writev) ENTRY_SAME(kcmp) ENTRY_SAME(finit_module) + ENTRY_SAME(sched_setattr) + ENTRY_SAME(sched_getattr) /* 335 */ /* Nothing yet */ diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 1695b6ab503d8e..957bf344c0f533 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -140,6 +140,7 @@ config PPC select OLD_SIGACTION if PPC32 select HAVE_DEBUG_STACKOVERFLOW select HAVE_IRQ_EXIT_ON_IRQ_STACK + select ARCH_USE_CMPXCHG_LOCKREF if PPC64 config GENERIC_CSUM def_bool CPU_LITTLE_ENDIAN @@ -214,9 +215,6 @@ config DEFAULT_UIMAGE Used to allow a board to specify it wants a uImage built by default default n -config REDBOOT - bool - config ARCH_HIBERNATION_POSSIBLE bool default y @@ -344,6 +342,8 @@ config PPC_TRANSACTIONAL_MEM bool "Transactional Memory support for POWERPC" depends on PPC_BOOK3S_64 depends on SMP + select ALTIVEC + select VSX default n ---help--- Support user-mode Transactional Memory on POWERPC. @@ -384,6 +384,12 @@ config ARCH_HAS_WALK_MEMORY config ARCH_ENABLE_MEMORY_HOTREMOVE def_bool y +config PPC64_SUPPORTS_MEMORY_FAILURE + bool "Add support for memory hwpoison" + depends on PPC_BOOK3S_64 + default "y" if PPC_POWERNV + select ARCH_SUPPORTS_MEMORY_FAILURE + config KEXEC bool "kexec system call" depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP)) @@ -404,8 +410,7 @@ config KEXEC config CRASH_DUMP bool "Build a kdump crash kernel" depends on PPC64 || 6xx || FSL_BOOKE || (44x && !SMP) - select RELOCATABLE if PPC64 || 44x - select DYNAMIC_MEMSTART if FSL_BOOKE + select RELOCATABLE if PPC64 || 44x || FSL_BOOKE help Build a kernel suitable for use as a kdump capture kernel. The same kernel binary can be used as production kernel and dump @@ -529,6 +534,7 @@ config PPC_16K_PAGES config PPC_64K_PAGES bool "64k page size" if 44x || PPC_STD_MMU_64 || PPC_BOOK3E_64 + depends on !PPC_FSL_BOOK3E select PPC_HAS_HASH_64K if PPC_STD_MMU_64 config PPC_256K_PAGES @@ -886,7 +892,7 @@ config DYNAMIC_MEMSTART config RELOCATABLE bool "Build a relocatable kernel" - depends on ADVANCED_OPTIONS && FLATMEM && 44x + depends on ADVANCED_OPTIONS && FLATMEM && (44x || FSL_BOOKE) select NONSTATIC_KERNEL help This builds a kernel image that is capable of running at the @@ -1042,11 +1048,6 @@ config KEYS_COMPAT source "crypto/Kconfig" -config PPC_CLOCK - bool - default n - select HAVE_CLK - config PPC_LIB_RHEAP bool diff --git a/arch/powerpc/boot/.gitignore b/arch/powerpc/boot/.gitignore index 554734ff302e89..d61c03525777ce 100644 --- a/arch/powerpc/boot/.gitignore +++ b/arch/powerpc/boot/.gitignore @@ -16,6 +16,7 @@ mktree uImage cuImage.* dtbImage.* +*.dtb treeImage.* zImage zImage.initrd diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index ca7f08cc4afd77..90e9d954866032 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -71,9 +71,9 @@ src-wlib-y := string.S crt0.S crtsavres.S stdio.c main.c \ uartlite.c mpc52xx-psc.c src-wlib-$(CONFIG_40x) += 4xx.c planetcore.c src-wlib-$(CONFIG_44x) += 4xx.c ebony.c bamboo.c -src-wlib-$(CONFIG_8xx) += mpc8xx.c planetcore.c +src-wlib-$(CONFIG_8xx) += mpc8xx.c planetcore.c fsl-soc.c src-wlib-$(CONFIG_PPC_82xx) += pq2.c fsl-soc.c planetcore.c -src-wlib-$(CONFIG_EMBEDDED6xx) += mv64x60.c mv64x60_i2c.c ugecon.c +src-wlib-$(CONFIG_EMBEDDED6xx) += mv64x60.c mv64x60_i2c.c ugecon.c fsl-soc.c src-plat-y := of.c epapr.c src-plat-$(CONFIG_40x) += fixed-head.S ep405.c cuboot-hotfoot.c \ @@ -95,7 +95,7 @@ src-plat-$(CONFIG_FSL_SOC_BOOKE) += cuboot-85xx.c cuboot-85xx-cpm2.c src-plat-$(CONFIG_EMBEDDED6xx) += cuboot-pq2.c cuboot-mpc7448hpc2.c \ cuboot-c2k.c gamecube-head.S \ gamecube.c wii-head.S wii.c holly.c \ - prpmc2800.c + prpmc2800.c fixed-head.S mvme5100.c src-plat-$(CONFIG_AMIGAONE) += cuboot-amigaone.c src-plat-$(CONFIG_PPC_PS3) += ps3-head.S ps3-hvcall.S ps3.c src-plat-$(CONFIG_EPAPR_BOOT) += epapr.c epapr-wrapper.c @@ -286,6 +286,7 @@ image-$(CONFIG_MPC7448HPC2) += cuImage.mpc7448hpc2 image-$(CONFIG_PPC_C2K) += cuImage.c2k image-$(CONFIG_GAMECUBE) += dtbImage.gamecube image-$(CONFIG_WII) += dtbImage.wii +image-$(CONFIG_MVME5100) += dtbImage.mvme5100 # Board port in arch/powerpc/platform/amigaone/Kconfig image-$(CONFIG_AMIGAONE) += cuImage.amigaone diff --git a/arch/powerpc/boot/dts/ac14xx.dts b/arch/powerpc/boot/dts/ac14xx.dts index a543c4088cba1e..a1b883730b3169 100644 --- a/arch/powerpc/boot/dts/ac14xx.dts +++ b/arch/powerpc/boot/dts/ac14xx.dts @@ -139,7 +139,14 @@ }; }; + clocks { + osc { + clock-frequency = <25000000>; + }; + }; + soc@80000000 { + bus-frequency = <80000000>; /* 80 MHz ips bus */ clock@f00 { compatible = "fsl,mpc5121rev2-clock", "fsl,mpc5121-clock"; diff --git a/arch/powerpc/boot/dts/fsl/elo3-dma-2.dtsi b/arch/powerpc/boot/dts/fsl/elo3-dma-2.dtsi new file mode 100644 index 00000000000000..d3cc8d0f7c254f --- /dev/null +++ b/arch/powerpc/boot/dts/fsl/elo3-dma-2.dtsi @@ -0,0 +1,82 @@ +/* + * QorIQ Elo3 DMA device tree stub [ controller @ offset 0x102300 ] + * + * Copyright 2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +dma2: dma@102300 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,elo3-dma"; + reg = <0x102300 0x4>, + <0x102600 0x4>; + ranges = <0x0 0x102100 0x500>; + dma-channel@0 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x0 0x80>; + interrupts = <464 2 0 0>; + }; + dma-channel@80 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x80 0x80>; + interrupts = <465 2 0 0>; + }; + dma-channel@100 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x100 0x80>; + interrupts = <466 2 0 0>; + }; + dma-channel@180 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x180 0x80>; + interrupts = <467 2 0 0>; + }; + dma-channel@300 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x300 0x80>; + interrupts = <468 2 0 0>; + }; + dma-channel@380 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x380 0x80>; + interrupts = <469 2 0 0>; + }; + dma-channel@400 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x400 0x80>; + interrupts = <470 2 0 0>; + }; + dma-channel@480 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x480 0x80>; + interrupts = <471 2 0 0>; + }; +}; diff --git a/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi index 68cc5e7f64777c..642dc3a83d0e35 100644 --- a/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi @@ -36,7 +36,8 @@ #address-cells = <2>; #size-cells = <1>; compatible = "fsl,p1020-elbc", "fsl,elbc", "simple-bus"; - interrupts = <19 2 0 0>; + interrupts = <19 2 0 0>, + <16 2 0 0>; }; /* controller at 0x9000 */ diff --git a/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi index adb82fd9057f3d..407cb5fd0f5bad 100644 --- a/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi @@ -36,7 +36,8 @@ #address-cells = <2>; #size-cells = <1>; compatible = "fsl,p1021-elbc", "fsl,elbc", "simple-bus"; - interrupts = <19 2 0 0>; + interrupts = <19 2 0 0>, + <16 2 0 0>; }; /* controller at 0x9000 */ diff --git a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi index e179803a81ef88..ebf20223454986 100644 --- a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi @@ -40,7 +40,8 @@ * pin muxing when the DIU is enabled. */ compatible = "fsl,p1022-elbc", "fsl,elbc"; - interrupts = <19 2 0 0>; + interrupts = <19 2 0 0>, + <16 2 0 0>; }; /* controller at 0x9000 */ diff --git a/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi index f1105bffa91567..81437fdf1db4f0 100644 --- a/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi @@ -36,7 +36,8 @@ #address-cells = <2>; #size-cells = <1>; compatible = "fsl,p1023-elbc", "fsl,elbc", "simple-bus"; - interrupts = <19 2 0 0>; + interrupts = <19 2 0 0>, + <16 2 0 0>; }; /* controller at 0xa000 */ diff --git a/arch/powerpc/boot/dts/kilauea.dts b/arch/powerpc/boot/dts/kilauea.dts index 1613d6e4049eb2..5ba7f01e2a2978 100644 --- a/arch/powerpc/boot/dts/kilauea.dts +++ b/arch/powerpc/boot/dts/kilauea.dts @@ -406,7 +406,7 @@ MSI: ppc4xx-msi@C10000000 { compatible = "amcc,ppc4xx-msi", "ppc4xx-msi"; - reg = < 0x0 0xEF620000 0x100>; + reg = <0xEF620000 0x100>; sdr-base = <0x4B0>; msi-data = <0x00000000>; msi-mask = <0x44440000>; diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/mpc5121.dtsi index 2d7cb04ac962ba..2c0e1552d20bb9 100644 --- a/arch/powerpc/boot/dts/mpc5121.dtsi +++ b/arch/powerpc/boot/dts/mpc5121.dtsi @@ -9,6 +9,8 @@ * option) any later version. */ +#include + /dts-v1/; / { @@ -49,6 +51,10 @@ compatible = "fsl,mpc5121-mbx"; reg = <0x20000000 0x4000>; interrupts = <66 0x8>; + clocks = <&clks MPC512x_CLK_MBX_BUS>, + <&clks MPC512x_CLK_MBX_3D>, + <&clks MPC512x_CLK_MBX>; + clock-names = "mbx-bus", "mbx-3d", "mbx"; }; sram@30000000 { @@ -62,6 +68,8 @@ interrupts = <6 8>; #address-cells = <1>; #size-cells = <1>; + clocks = <&clks MPC512x_CLK_NFC>; + clock-names = "ipg"; }; localbus@80000020 { @@ -73,6 +81,17 @@ ranges = <0x0 0x0 0xfc000000 0x04000000>; }; + clocks { + #address-cells = <1>; + #size-cells = <0>; + + osc: osc { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <33000000>; + }; + }; + soc@80000000 { compatible = "fsl,mpc5121-immr"; #address-cells = <1>; @@ -117,9 +136,12 @@ }; /* Clock control */ - clock@f00 { + clks: clock@f00 { compatible = "fsl,mpc5121-clock"; reg = <0xf00 0x100>; + #clock-cells = <1>; + clocks = <&osc>; + clock-names = "osc"; }; /* Power Management Controller */ @@ -139,12 +161,24 @@ compatible = "fsl,mpc5121-mscan"; reg = <0x1300 0x80>; interrupts = <12 0x8>; + clocks = <&clks MPC512x_CLK_BDLC>, + <&clks MPC512x_CLK_IPS>, + <&clks MPC512x_CLK_SYS>, + <&clks MPC512x_CLK_REF>, + <&clks MPC512x_CLK_MSCAN0_MCLK>; + clock-names = "ipg", "ips", "sys", "ref", "mclk"; }; can@1380 { compatible = "fsl,mpc5121-mscan"; reg = <0x1380 0x80>; interrupts = <13 0x8>; + clocks = <&clks MPC512x_CLK_BDLC>, + <&clks MPC512x_CLK_IPS>, + <&clks MPC512x_CLK_SYS>, + <&clks MPC512x_CLK_REF>, + <&clks MPC512x_CLK_MSCAN1_MCLK>; + clock-names = "ipg", "ips", "sys", "ref", "mclk"; }; sdhc@1500 { @@ -153,6 +187,9 @@ interrupts = <8 0x8>; dmas = <&dma0 30>; dma-names = "rx-tx"; + clocks = <&clks MPC512x_CLK_IPS>, + <&clks MPC512x_CLK_SDHC>; + clock-names = "ipg", "per"; }; i2c@1700 { @@ -161,6 +198,8 @@ compatible = "fsl,mpc5121-i2c", "fsl-i2c"; reg = <0x1700 0x20>; interrupts = <9 0x8>; + clocks = <&clks MPC512x_CLK_I2C>; + clock-names = "ipg"; }; i2c@1720 { @@ -169,6 +208,8 @@ compatible = "fsl,mpc5121-i2c", "fsl-i2c"; reg = <0x1720 0x20>; interrupts = <10 0x8>; + clocks = <&clks MPC512x_CLK_I2C>; + clock-names = "ipg"; }; i2c@1740 { @@ -177,6 +218,8 @@ compatible = "fsl,mpc5121-i2c", "fsl-i2c"; reg = <0x1740 0x20>; interrupts = <11 0x8>; + clocks = <&clks MPC512x_CLK_I2C>; + clock-names = "ipg"; }; i2ccontrol@1760 { @@ -188,30 +231,48 @@ compatible = "fsl,mpc5121-axe"; reg = <0x2000 0x100>; interrupts = <42 0x8>; + clocks = <&clks MPC512x_CLK_AXE>; + clock-names = "ipg"; }; display@2100 { compatible = "fsl,mpc5121-diu"; reg = <0x2100 0x100>; interrupts = <64 0x8>; + clocks = <&clks MPC512x_CLK_DIU>; + clock-names = "ipg"; }; can@2300 { compatible = "fsl,mpc5121-mscan"; reg = <0x2300 0x80>; interrupts = <90 0x8>; + clocks = <&clks MPC512x_CLK_BDLC>, + <&clks MPC512x_CLK_IPS>, + <&clks MPC512x_CLK_SYS>, + <&clks MPC512x_CLK_REF>, + <&clks MPC512x_CLK_MSCAN2_MCLK>; + clock-names = "ipg", "ips", "sys", "ref", "mclk"; }; can@2380 { compatible = "fsl,mpc5121-mscan"; reg = <0x2380 0x80>; interrupts = <91 0x8>; + clocks = <&clks MPC512x_CLK_BDLC>, + <&clks MPC512x_CLK_IPS>, + <&clks MPC512x_CLK_SYS>, + <&clks MPC512x_CLK_REF>, + <&clks MPC512x_CLK_MSCAN3_MCLK>; + clock-names = "ipg", "ips", "sys", "ref", "mclk"; }; viu@2400 { compatible = "fsl,mpc5121-viu"; reg = <0x2400 0x400>; interrupts = <67 0x8>; + clocks = <&clks MPC512x_CLK_VIU>; + clock-names = "ipg"; }; mdio@2800 { @@ -219,6 +280,8 @@ reg = <0x2800 0x800>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clks MPC512x_CLK_FEC>; + clock-names = "per"; }; eth0: ethernet@2800 { @@ -227,6 +290,8 @@ reg = <0x2800 0x800>; local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <4 0x8>; + clocks = <&clks MPC512x_CLK_FEC>; + clock-names = "per"; }; /* USB1 using external ULPI PHY */ @@ -238,6 +303,8 @@ interrupts = <43 0x8>; dr_mode = "otg"; phy_type = "ulpi"; + clocks = <&clks MPC512x_CLK_USB1>; + clock-names = "ipg"; }; /* USB0 using internal UTMI PHY */ @@ -249,6 +316,8 @@ interrupts = <44 0x8>; dr_mode = "otg"; phy_type = "utmi_wide"; + clocks = <&clks MPC512x_CLK_USB2>; + clock-names = "ipg"; }; /* IO control */ @@ -267,6 +336,8 @@ compatible = "fsl,mpc5121-pata"; reg = <0x10200 0x100>; interrupts = <5 0x8>; + clocks = <&clks MPC512x_CLK_PATA>; + clock-names = "ipg"; }; /* 512x PSCs are not 52xx PSC compatible */ @@ -278,6 +349,9 @@ interrupts = <40 0x8>; fsl,rx-fifo-size = <16>; fsl,tx-fifo-size = <16>; + clocks = <&clks MPC512x_CLK_PSC0>, + <&clks MPC512x_CLK_PSC0_MCLK>; + clock-names = "ipg", "mclk"; }; /* PSC1 */ @@ -287,6 +361,9 @@ interrupts = <40 0x8>; fsl,rx-fifo-size = <16>; fsl,tx-fifo-size = <16>; + clocks = <&clks MPC512x_CLK_PSC1>, + <&clks MPC512x_CLK_PSC1_MCLK>; + clock-names = "ipg", "mclk"; }; /* PSC2 */ @@ -296,6 +373,9 @@ interrupts = <40 0x8>; fsl,rx-fifo-size = <16>; fsl,tx-fifo-size = <16>; + clocks = <&clks MPC512x_CLK_PSC2>, + <&clks MPC512x_CLK_PSC2_MCLK>; + clock-names = "ipg", "mclk"; }; /* PSC3 */ @@ -305,6 +385,9 @@ interrupts = <40 0x8>; fsl,rx-fifo-size = <16>; fsl,tx-fifo-size = <16>; + clocks = <&clks MPC512x_CLK_PSC3>, + <&clks MPC512x_CLK_PSC3_MCLK>; + clock-names = "ipg", "mclk"; }; /* PSC4 */ @@ -314,6 +397,9 @@ interrupts = <40 0x8>; fsl,rx-fifo-size = <16>; fsl,tx-fifo-size = <16>; + clocks = <&clks MPC512x_CLK_PSC4>, + <&clks MPC512x_CLK_PSC4_MCLK>; + clock-names = "ipg", "mclk"; }; /* PSC5 */ @@ -323,6 +409,9 @@ interrupts = <40 0x8>; fsl,rx-fifo-size = <16>; fsl,tx-fifo-size = <16>; + clocks = <&clks MPC512x_CLK_PSC5>, + <&clks MPC512x_CLK_PSC5_MCLK>; + clock-names = "ipg", "mclk"; }; /* PSC6 */ @@ -332,6 +421,9 @@ interrupts = <40 0x8>; fsl,rx-fifo-size = <16>; fsl,tx-fifo-size = <16>; + clocks = <&clks MPC512x_CLK_PSC6>, + <&clks MPC512x_CLK_PSC6_MCLK>; + clock-names = "ipg", "mclk"; }; /* PSC7 */ @@ -341,6 +433,9 @@ interrupts = <40 0x8>; fsl,rx-fifo-size = <16>; fsl,tx-fifo-size = <16>; + clocks = <&clks MPC512x_CLK_PSC7>, + <&clks MPC512x_CLK_PSC7_MCLK>; + clock-names = "ipg", "mclk"; }; /* PSC8 */ @@ -350,6 +445,9 @@ interrupts = <40 0x8>; fsl,rx-fifo-size = <16>; fsl,tx-fifo-size = <16>; + clocks = <&clks MPC512x_CLK_PSC8>, + <&clks MPC512x_CLK_PSC8_MCLK>; + clock-names = "ipg", "mclk"; }; /* PSC9 */ @@ -359,6 +457,9 @@ interrupts = <40 0x8>; fsl,rx-fifo-size = <16>; fsl,tx-fifo-size = <16>; + clocks = <&clks MPC512x_CLK_PSC9>, + <&clks MPC512x_CLK_PSC9_MCLK>; + clock-names = "ipg", "mclk"; }; /* PSC10 */ @@ -368,6 +469,9 @@ interrupts = <40 0x8>; fsl,rx-fifo-size = <16>; fsl,tx-fifo-size = <16>; + clocks = <&clks MPC512x_CLK_PSC10>, + <&clks MPC512x_CLK_PSC10_MCLK>; + clock-names = "ipg", "mclk"; }; /* PSC11 */ @@ -377,12 +481,17 @@ interrupts = <40 0x8>; fsl,rx-fifo-size = <16>; fsl,tx-fifo-size = <16>; + clocks = <&clks MPC512x_CLK_PSC11>, + <&clks MPC512x_CLK_PSC11_MCLK>; + clock-names = "ipg", "mclk"; }; pscfifo@11f00 { compatible = "fsl,mpc5121-psc-fifo"; reg = <0x11f00 0x100>; interrupts = <40 0x8>; + clocks = <&clks MPC512x_CLK_PSC_FIFO>; + clock-names = "ipg"; }; dma0: dma@14000 { @@ -400,6 +509,8 @@ #address-cells = <3>; #size-cells = <2>; #interrupt-cells = <1>; + clocks = <&clks MPC512x_CLK_PCI>; + clock-names = "ipg"; reg = <0x80008500 0x100 /* internal registers */ 0x80008300 0x8>; /* config space access registers */ diff --git a/arch/powerpc/boot/dts/mpc5125twr.dts b/arch/powerpc/boot/dts/mpc5125twr.dts index a618dfc13e4c8f..e4f297471748ec 100644 --- a/arch/powerpc/boot/dts/mpc5125twr.dts +++ b/arch/powerpc/boot/dts/mpc5125twr.dts @@ -12,6 +12,8 @@ * option) any later version. */ +#include + /dts-v1/; / { @@ -54,6 +56,17 @@ reg = <0x30000000 0x08000>; // 32K at 0x30000000 }; + clocks { + #address-cells = <1>; + #size-cells = <0>; + + osc: osc { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <33000000>; + }; + }; + soc@80000000 { compatible = "fsl,mpc5121-immr"; #address-cells = <1>; @@ -87,9 +100,12 @@ reg = <0xe00 0x100>; }; - clock@f00 { // Clock control + clks: clock@f00 { // Clock control compatible = "fsl,mpc5121-clock"; reg = <0xf00 0x100>; + #clock-cells = <1>; + clocks = <&osc>; + clock-names = "osc"; }; pmc@1000{ // Power Management Controller @@ -114,18 +130,33 @@ compatible = "fsl,mpc5121-mscan"; interrupts = <12 0x8>; reg = <0x1300 0x80>; + clocks = <&clks MPC512x_CLK_BDLC>, + <&clks MPC512x_CLK_IPS>, + <&clks MPC512x_CLK_SYS>, + <&clks MPC512x_CLK_REF>, + <&clks MPC512x_CLK_MSCAN0_MCLK>; + clock-names = "ipg", "ips", "sys", "ref", "mclk"; }; can@1380 { compatible = "fsl,mpc5121-mscan"; interrupts = <13 0x8>; reg = <0x1380 0x80>; + clocks = <&clks MPC512x_CLK_BDLC>, + <&clks MPC512x_CLK_IPS>, + <&clks MPC512x_CLK_SYS>, + <&clks MPC512x_CLK_REF>, + <&clks MPC512x_CLK_MSCAN1_MCLK>; + clock-names = "ipg", "ips", "sys", "ref", "mclk"; }; sdhc@1500 { compatible = "fsl,mpc5121-sdhc"; interrupts = <8 0x8>; reg = <0x1500 0x100>; + clocks = <&clks MPC512x_CLK_IPS>, + <&clks MPC512x_CLK_SDHC>; + clock-names = "ipg", "per"; }; i2c@1700 { @@ -134,6 +165,8 @@ compatible = "fsl,mpc5121-i2c", "fsl-i2c"; reg = <0x1700 0x20>; interrupts = <0x9 0x8>; + clocks = <&clks MPC512x_CLK_I2C>; + clock-names = "ipg"; }; i2c@1720 { @@ -142,6 +175,8 @@ compatible = "fsl,mpc5121-i2c", "fsl-i2c"; reg = <0x1720 0x20>; interrupts = <0xa 0x8>; + clocks = <&clks MPC512x_CLK_I2C>; + clock-names = "ipg"; }; i2c@1740 { @@ -150,6 +185,8 @@ compatible = "fsl,mpc5121-i2c", "fsl-i2c"; reg = <0x1740 0x20>; interrupts = <0xb 0x8>; + clocks = <&clks MPC512x_CLK_I2C>; + clock-names = "ipg"; }; i2ccontrol@1760 { @@ -161,6 +198,8 @@ compatible = "fsl,mpc5121-diu"; reg = <0x2100 0x100>; interrupts = <64 0x8>; + clocks = <&clks MPC512x_CLK_DIU>; + clock-names = "ipg"; }; mdio@2800 { @@ -180,6 +219,8 @@ interrupts = <4 0x8>; phy-handle = < &phy0 >; phy-connection-type = "rmii"; + clocks = <&clks MPC512x_CLK_FEC>; + clock-names = "per"; }; // IO control @@ -200,6 +241,8 @@ interrupts = <43 0x8>; dr_mode = "host"; phy_type = "ulpi"; + clocks = <&clks MPC512x_CLK_USB1>; + clock-names = "ipg"; status = "disabled"; }; @@ -211,6 +254,9 @@ interrupts = <40 0x8>; fsl,rx-fifo-size = <16>; fsl,tx-fifo-size = <16>; + clocks = <&clks MPC512x_CLK_PSC1>, + <&clks MPC512x_CLK_PSC1_MCLK>; + clock-names = "ipg", "mclk"; }; // PSC9 uart1 aka ttyPSC1 @@ -220,12 +266,17 @@ interrupts = <40 0x8>; fsl,rx-fifo-size = <16>; fsl,tx-fifo-size = <16>; + clocks = <&clks MPC512x_CLK_PSC9>, + <&clks MPC512x_CLK_PSC9_MCLK>; + clock-names = "ipg", "mclk"; }; pscfifo@11f00 { compatible = "fsl,mpc5121-psc-fifo"; reg = <0x11f00 0x100>; interrupts = <40 0x8>; + clocks = <&clks MPC512x_CLK_PSC_FIFO>; + clock-names = "ipg"; }; dma@14000 { diff --git a/arch/powerpc/boot/dts/mvme5100.dts b/arch/powerpc/boot/dts/mvme5100.dts new file mode 100644 index 00000000000000..1ecb341a232a50 --- /dev/null +++ b/arch/powerpc/boot/dts/mvme5100.dts @@ -0,0 +1,185 @@ +/* + * Device Tree Source for Motorola/Emerson MVME5100. + * + * Copyright 2013 CSC Australia Pty. Ltd. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without + * any warranty of any kind, whether express or implied. + */ + +/dts-v1/; + +/ { + model = "MVME5100"; + compatible = "MVME5100"; + #address-cells = <1>; + #size-cells = <1>; + + aliases { + serial0 = &serial0; + pci0 = &pci0; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,7410 { + device_type = "cpu"; + reg = <0x0>; + /* Following required by dtc but not used */ + d-cache-line-size = <32>; + i-cache-line-size = <32>; + i-cache-size = <32768>; + d-cache-size = <32768>; + timebase-frequency = <25000000>; + clock-frequency = <500000000>; + bus-frequency = <100000000>; + }; + }; + + memory { + device_type = "memory"; + reg = <0x0 0x20000000>; + }; + + hawk@fef80000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "hawk-bridge", "simple-bus"; + ranges = <0x0 0xfef80000 0x10000>; + reg = <0xfef80000 0x10000>; + + serial0: serial@8000 { + device_type = "serial"; + compatible = "ns16550"; + reg = <0x8000 0x80>; + reg-shift = <4>; + clock-frequency = <1843200>; + current-speed = <9600>; + interrupts = <1 1>; // IRQ1 Level Active Low. + interrupt-parent = <&mpic>; + }; + + serial1: serial@8200 { + device_type = "serial"; + compatible = "ns16550"; + reg = <0x8200 0x80>; + reg-shift = <4>; + clock-frequency = <1843200>; + current-speed = <9600>; + interrupts = <1 1>; // IRQ1 Level Active Low. + interrupt-parent = <&mpic>; + }; + + mpic: interrupt-controller@f3f80000 { + #interrupt-cells = <2>; + #address-cells = <0>; + device_type = "open-pic"; + compatible = "chrp,open-pic"; + interrupt-controller; + reg = <0xf3f80000 0x40000>; + }; + }; + + pci0: pci@feff0000 { + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + device_type = "pci"; + compatible = "hawk-pci"; + reg = <0xfec00000 0x400000>; + 8259-interrupt-acknowledge = <0xfeff0030>; + ranges = <0x1000000 0x0 0x0 0xfe000000 0x0 0x800000 + 0x2000000 0x0 0x80000000 0x80000000 0x0 0x74000000>; + bus-range = <0 255>; + clock-frequency = <33333333>; + interrupt-parent = <&mpic>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + + /* + * This definition (IDSEL 11) duplicates the + * interrupts definition in the i8259 + * interrupt controller below. + * + * Do not change the interrupt sense/polarity from + * 0x2 to anything else, doing so will cause endless + * "spurious" i8259 interrupts to be fielded. + */ + // IDSEL 11 - iPMC712 PCI/ISA Bridge + 0x5800 0x0 0x0 0x1 &mpic 0x0 0x2 + 0x5800 0x0 0x0 0x2 &mpic 0x0 0x2 + 0x5800 0x0 0x0 0x3 &mpic 0x0 0x2 + 0x5800 0x0 0x0 0x4 &mpic 0x0 0x2 + + /* IDSEL 12 - Not Used */ + + /* IDSEL 13 - Universe VME Bridge */ + 0x6800 0x0 0x0 0x1 &mpic 0x5 0x1 + 0x6800 0x0 0x0 0x2 &mpic 0x6 0x1 + 0x6800 0x0 0x0 0x3 &mpic 0x7 0x1 + 0x6800 0x0 0x0 0x4 &mpic 0x8 0x1 + + /* IDSEL 14 - ENET 1 */ + 0x7000 0x0 0x0 0x1 &mpic 0x2 0x1 + + /* IDSEL 15 - Not Used */ + + /* IDSEL 16 - PMC Slot 1 */ + 0x8000 0x0 0x0 0x1 &mpic 0x9 0x1 + 0x8000 0x0 0x0 0x2 &mpic 0xa 0x1 + 0x8000 0x0 0x0 0x3 &mpic 0xb 0x1 + 0x8000 0x0 0x0 0x4 &mpic 0xc 0x1 + + /* IDSEL 17 - PMC Slot 2 */ + 0x8800 0x0 0x0 0x1 &mpic 0xc 0x1 + 0x8800 0x0 0x0 0x2 &mpic 0x9 0x1 + 0x8800 0x0 0x0 0x3 &mpic 0xa 0x1 + 0x8800 0x0 0x0 0x4 &mpic 0xb 0x1 + + /* IDSEL 18 - Not Used */ + + /* IDSEL 19 - ENET 2 */ + 0x9800 0x0 0x0 0x1 &mpic 0xd 0x1 + + /* IDSEL 20 - PMCSPAN (PCI-X) */ + 0xa000 0x0 0x0 0x1 &mpic 0x9 0x1 + 0xa000 0x0 0x0 0x2 &mpic 0xa 0x1 + 0xa000 0x0 0x0 0x3 &mpic 0xb 0x1 + 0xa000 0x0 0x0 0x4 &mpic 0xc 0x1 + + >; + + isa { + #address-cells = <2>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "isa"; + compatible = "isa"; + ranges = <0x00000001 0 0x01000000 0 0x00000000 0x00001000>; + interrupt-parent = <&i8259>; + + i8259: interrupt-controller@20 { + #interrupt-cells = <2>; + #address-cells = <0>; + interrupts = <0 2>; + device_type = "interrupt-controller"; + compatible = "chrp,iic"; + interrupt-controller; + reg = <1 0x00000020 0x00000002 + 1 0x000000a0 0x00000002 + 1 0x000004d0 0x00000002>; + interrupt-parent = <&mpic>; + }; + + }; + + }; + + chosen { + linux,stdout-path = &serial0; + }; + +}; diff --git a/arch/powerpc/boot/dts/p1010rdb-pa.dts b/arch/powerpc/boot/dts/p1010rdb-pa.dts new file mode 100644 index 00000000000000..767d4c03285789 --- /dev/null +++ b/arch/powerpc/boot/dts/p1010rdb-pa.dts @@ -0,0 +1,23 @@ +/* + * P1010 RDB Device Tree Source + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/include/ "fsl/p1010si-pre.dtsi" + +/ { + model = "fsl,P1010RDB"; + compatible = "fsl,P1010RDB"; + + /include/ "p1010rdb_32b.dtsi" +}; + +/include/ "p1010rdb.dtsi" +/include/ "p1010rdb-pa.dtsi" +/include/ "fsl/p1010si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1010rdb-pa.dtsi b/arch/powerpc/boot/dts/p1010rdb-pa.dtsi new file mode 100644 index 00000000000000..434fb2d58575b9 --- /dev/null +++ b/arch/powerpc/boot/dts/p1010rdb-pa.dtsi @@ -0,0 +1,85 @@ +/* + * P1010 RDB Device Tree Source stub (no addresses or top-level ranges) + * + * Copyright 2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +&ifc_nand { + partition@0 { + /* This location must not be altered */ + /* 1MB for u-boot Bootloader Image */ + reg = <0x0 0x00100000>; + label = "NAND U-Boot Image"; + read-only; + }; + + partition@100000 { + /* 1MB for DTB Image */ + reg = <0x00100000 0x00100000>; + label = "NAND DTB Image"; + }; + + partition@200000 { + /* 4MB for Linux Kernel Image */ + reg = <0x00200000 0x00400000>; + label = "NAND Linux Kernel Image"; + }; + + partition@600000 { + /* 4MB for Compressed Root file System Image */ + reg = <0x00600000 0x00400000>; + label = "NAND Compressed RFS Image"; + }; + + partition@a00000 { + /* 15MB for JFFS2 based Root file System */ + reg = <0x00a00000 0x00f00000>; + label = "NAND JFFS2 Root File System"; + }; + + partition@1900000 { + /* 7MB for User Area */ + reg = <0x01900000 0x00700000>; + label = "NAND User area"; + }; +}; + +&phy0 { + interrupts = <1 1 0 0>; +}; + +&phy1 { + interrupts = <2 1 0 0>; +}; + +&phy2 { + interrupts = <4 1 0 0>; +}; diff --git a/arch/powerpc/boot/dts/p1010rdb_36b.dts b/arch/powerpc/boot/dts/p1010rdb-pa_36b.dts similarity index 64% rename from arch/powerpc/boot/dts/p1010rdb_36b.dts rename to arch/powerpc/boot/dts/p1010rdb-pa_36b.dts index 64776f4a4651cc..3033371bc007ec 100644 --- a/arch/powerpc/boot/dts/p1010rdb_36b.dts +++ b/arch/powerpc/boot/dts/p1010rdb-pa_36b.dts @@ -38,52 +38,9 @@ model = "fsl,P1010RDB"; compatible = "fsl,P1010RDB"; - memory { - device_type = "memory"; - }; - - board_ifc: ifc: ifc@fffe1e000 { - /* NOR, NAND Flashes and CPLD on board */ - ranges = <0x0 0x0 0xf 0xee000000 0x02000000 - 0x1 0x0 0xf 0xff800000 0x00010000 - 0x3 0x0 0xf 0xffb00000 0x00000020>; - reg = <0xf 0xffe1e000 0 0x2000>; - }; - - board_soc: soc: soc@fffe00000 { - ranges = <0x0 0xf 0xffe00000 0x100000>; - }; - - pci0: pcie@fffe09000 { - reg = <0xf 0xffe09000 0 0x1000>; - ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0xc0000000 - 0x2000000 0x0 0xc0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci1: pcie@fffe0a000 { - reg = <0xf 0xffe0a000 0 0x1000>; - ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0xc0000000 - 0x2000000 0x0 0xc0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; + /include/ "p1010rdb_36b.dtsi" }; /include/ "p1010rdb.dtsi" +/include/ "p1010rdb-pa.dtsi" /include/ "fsl/p1010si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1010rdb-pb.dts b/arch/powerpc/boot/dts/p1010rdb-pb.dts new file mode 100644 index 00000000000000..6eeb7d3185beff --- /dev/null +++ b/arch/powerpc/boot/dts/p1010rdb-pb.dts @@ -0,0 +1,35 @@ +/* + * P1010 RDB Device Tree Source + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/include/ "fsl/p1010si-pre.dtsi" + +/ { + model = "fsl,P1010RDB-PB"; + compatible = "fsl,P1010RDB-PB"; + + /include/ "p1010rdb_32b.dtsi" +}; + +/include/ "p1010rdb.dtsi" + +&phy0 { + interrupts = <0 1 0 0>; +}; + +&phy1 { + interrupts = <2 1 0 0>; +}; + +&phy2 { + interrupts = <1 1 0 0>; +}; + +/include/ "fsl/p1010si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1010rdb-pb_36b.dts b/arch/powerpc/boot/dts/p1010rdb-pb_36b.dts new file mode 100644 index 00000000000000..7ab3c907b326ec --- /dev/null +++ b/arch/powerpc/boot/dts/p1010rdb-pb_36b.dts @@ -0,0 +1,58 @@ +/* + * P1010 RDB Device Tree Source (36-bit address map) + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/include/ "fsl/p1010si-pre.dtsi" + +/ { + model = "fsl,P1010RDB-PB"; + compatible = "fsl,P1010RDB-PB"; + + /include/ "p1010rdb_36b.dtsi" +}; + +/include/ "p1010rdb.dtsi" + +&phy0 { + interrupts = <0 1 0 0>; +}; + +&phy1 { + interrupts = <2 1 0 0>; +}; + +&phy2 { + interrupts = <1 1 0 0>; +}; + +/include/ "fsl/p1010si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1010rdb.dts b/arch/powerpc/boot/dts/p1010rdb.dts deleted file mode 100644 index b868d22984e961..00000000000000 --- a/arch/powerpc/boot/dts/p1010rdb.dts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * P1010 RDB Device Tree Source - * - * Copyright 2011 Freescale Semiconductor Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -/include/ "fsl/p1010si-pre.dtsi" - -/ { - model = "fsl,P1010RDB"; - compatible = "fsl,P1010RDB"; - - memory { - device_type = "memory"; - }; - - board_ifc: ifc: ifc@ffe1e000 { - /* NOR, NAND Flashes and CPLD on board */ - ranges = <0x0 0x0 0x0 0xee000000 0x02000000 - 0x1 0x0 0x0 0xff800000 0x00010000 - 0x3 0x0 0x0 0xffb00000 0x00000020>; - reg = <0x0 0xffe1e000 0 0x2000>; - }; - - board_soc: soc: soc@ffe00000 { - ranges = <0x0 0x0 0xffe00000 0x100000>; - }; - - pci0: pcie@ffe09000 { - reg = <0 0xffe09000 0 0x1000>; - ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0xa0000000 - 0x2000000 0x0 0xa0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci1: pcie@ffe0a000 { - reg = <0 0xffe0a000 0 0x1000>; - ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0x80000000 - 0x2000000 0x0 0x80000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; -}; - -/include/ "p1010rdb.dtsi" -/include/ "fsl/p1010si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1010rdb.dtsi b/arch/powerpc/boot/dts/p1010rdb.dtsi index ec7c27a646711c..ea534efa790d36 100644 --- a/arch/powerpc/boot/dts/p1010rdb.dtsi +++ b/arch/powerpc/boot/dts/p1010rdb.dtsi @@ -69,49 +69,11 @@ }; }; - nand@1,0 { + ifc_nand: nand@1,0 { #address-cells = <1>; #size-cells = <1>; compatible = "fsl,ifc-nand"; reg = <0x1 0x0 0x10000>; - - partition@0 { - /* This location must not be altered */ - /* 1MB for u-boot Bootloader Image */ - reg = <0x0 0x00100000>; - label = "NAND U-Boot Image"; - read-only; - }; - - partition@100000 { - /* 1MB for DTB Image */ - reg = <0x00100000 0x00100000>; - label = "NAND DTB Image"; - }; - - partition@200000 { - /* 4MB for Linux Kernel Image */ - reg = <0x00200000 0x00400000>; - label = "NAND Linux Kernel Image"; - }; - - partition@600000 { - /* 4MB for Compressed Root file System Image */ - reg = <0x00600000 0x00400000>; - label = "NAND Compressed RFS Image"; - }; - - partition@a00000 { - /* 15MB for JFFS2 based Root file System */ - reg = <0x00a00000 0x00f00000>; - label = "NAND JFFS2 Root File System"; - }; - - partition@1900000 { - /* 7MB for User Area */ - reg = <0x01900000 0x00700000>; - label = "NAND User area"; - }; }; cpld@3,0 { @@ -193,17 +155,14 @@ mdio@24000 { phy0: ethernet-phy@0 { - interrupts = <3 1 0 0>; reg = <0x1>; }; phy1: ethernet-phy@1 { - interrupts = <2 1 0 0>; reg = <0x0>; }; phy2: ethernet-phy@2 { - interrupts = <2 1 0 0>; reg = <0x2>; }; diff --git a/arch/powerpc/boot/dts/p1010rdb_32b.dtsi b/arch/powerpc/boot/dts/p1010rdb_32b.dtsi new file mode 100644 index 00000000000000..fdc19aab2f7067 --- /dev/null +++ b/arch/powerpc/boot/dts/p1010rdb_32b.dtsi @@ -0,0 +1,79 @@ +/* + * P1010 RDB Device Tree Source stub (no addresses or top-level ranges) + * + * Copyright 2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +memory { + device_type = "memory"; +}; + +board_ifc: ifc: ifc@ffe1e000 { + /* NOR, NAND Flashes and CPLD on board */ + ranges = <0x0 0x0 0x0 0xee000000 0x02000000 + 0x1 0x0 0x0 0xff800000 0x00010000 + 0x3 0x0 0x0 0xffb00000 0x00000020>; + reg = <0x0 0xffe1e000 0 0x2000>; +}; + +board_soc: soc: soc@ffe00000 { + ranges = <0x0 0x0 0xffe00000 0x100000>; +}; + +pci0: pcie@ffe09000 { + reg = <0 0xffe09000 0 0x1000>; + ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xa0000000 + 0x2000000 0x0 0xa0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; +}; + +pci1: pcie@ffe0a000 { + reg = <0 0xffe0a000 0 0x1000>; + ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0x80000000 + 0x2000000 0x0 0x80000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; +}; diff --git a/arch/powerpc/boot/dts/p1010rdb_36b.dtsi b/arch/powerpc/boot/dts/p1010rdb_36b.dtsi new file mode 100644 index 00000000000000..de2fceed4f7990 --- /dev/null +++ b/arch/powerpc/boot/dts/p1010rdb_36b.dtsi @@ -0,0 +1,79 @@ +/* + * P1010 RDB Device Tree Source stub (no addresses or top-level ranges) + * + * Copyright 2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +memory { + device_type = "memory"; +}; + +board_ifc: ifc: ifc@fffe1e000 { + /* NOR, NAND Flashes and CPLD on board */ + ranges = <0x0 0x0 0xf 0xee000000 0x02000000 + 0x1 0x0 0xf 0xff800000 0x00010000 + 0x3 0x0 0xf 0xffb00000 0x00000020>; + reg = <0xf 0xffe1e000 0 0x2000>; +}; + +board_soc: soc: soc@fffe00000 { + ranges = <0x0 0xf 0xffe00000 0x100000>; +}; + +pci0: pcie@fffe09000 { + reg = <0xf 0xffe09000 0 0x1000>; + ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xc0000000 + 0x2000000 0x0 0xc0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; +}; + +pci1: pcie@fffe0a000 { + reg = <0xf 0xffe0a000 0 0x1000>; + ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xc0000000 + 0x2000000 0x0 0xc0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; +}; diff --git a/arch/powerpc/boot/dts/p1022ds.dtsi b/arch/powerpc/boot/dts/p1022ds.dtsi index 873da350d01ba6..957e0dc1dc0f62 100644 --- a/arch/powerpc/boot/dts/p1022ds.dtsi +++ b/arch/powerpc/boot/dts/p1022ds.dtsi @@ -146,8 +146,9 @@ */ }; rtc@68 { - compatible = "dallas,ds1339"; + compatible = "dallas,ds3232"; reg = <0x68>; + interrupts = <0x1 0x1 0 0>; }; adt7461@4c { compatible = "adi,adt7461"; diff --git a/arch/powerpc/boot/dts/p1025twr.dts b/arch/powerpc/boot/dts/p1025twr.dts new file mode 100644 index 00000000000000..9036a4987905f1 --- /dev/null +++ b/arch/powerpc/boot/dts/p1025twr.dts @@ -0,0 +1,95 @@ +/* + * P1025 TWR Device Tree Source (32-bit address map) + * + * Copyright 2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/include/ "fsl/p1021si-pre.dtsi" +/ { + model = "fsl,P1025"; + compatible = "fsl,TWR-P1025"; + + memory { + device_type = "memory"; + }; + + lbc: localbus@ffe05000 { + reg = <0 0xffe05000 0 0x1000>; + + /* NOR Flash and SSD1289 */ + ranges = <0x0 0x0 0x0 0xec000000 0x04000000 + 0x2 0x0 0x0 0xe0000000 0x00020000>; + }; + + soc: soc@ffe00000 { + ranges = <0x0 0x0 0xffe00000 0x100000>; + }; + + pci0: pcie@ffe09000 { + ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; + reg = <0 0xffe09000 0 0x1000>; + pcie@0 { + ranges = <0x2000000 0x0 0xa0000000 + 0x2000000 0x0 0xa0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci1: pcie@ffe0a000 { + reg = <0 0xffe0a000 0 0x1000>; + ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0x80000000 + 0x2000000 0x0 0x80000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + qe: qe@ffe80000 { + ranges = <0x0 0x0 0xffe80000 0x40000>; + reg = <0 0xffe80000 0 0x480>; + brg-frequency = <0>; + bus-frequency = <0>; + }; +}; + +/include/ "p1025twr.dtsi" +/include/ "fsl/p1021si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1025twr.dtsi b/arch/powerpc/boot/dts/p1025twr.dtsi new file mode 100644 index 00000000000000..8453501c256ebd --- /dev/null +++ b/arch/powerpc/boot/dts/p1025twr.dtsi @@ -0,0 +1,280 @@ +/* + * P1025 TWR Device Tree Source stub (no addresses or top-level ranges) + * + * Copyright 2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/{ + aliases { + ethernet3 = &enet3; + ethernet4 = &enet4; + }; +}; + +&lbc { + nor@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x4000000>; + bank-width = <2>; + device-width = <1>; + + partition@0 { + /* This location must not be altered */ + /* 256KB for Vitesse 7385 Switch firmware */ + reg = <0x0 0x00040000>; + label = "NOR Vitesse-7385 Firmware"; + read-only; + }; + + partition@40000 { + /* 256KB for DTB Image */ + reg = <0x00040000 0x00040000>; + label = "NOR DTB Image"; + }; + + partition@80000 { + /* 5.5 MB for Linux Kernel Image */ + reg = <0x00080000 0x00580000>; + label = "NOR Linux Kernel Image"; + }; + + partition@400000 { + /* 56.75MB for Root file System */ + reg = <0x00600000 0x038c0000>; + label = "NOR Root File System"; + }; + + partition@ec0000 { + /* This location must not be altered */ + /* 256KB for QE ucode firmware*/ + reg = <0x03ec0000 0x00040000>; + label = "NOR QE microcode firmware"; + read-only; + }; + + partition@f00000 { + /* This location must not be altered */ + /* 512KB for u-boot Bootloader Image */ + /* 512KB for u-boot Environment Variables */ + reg = <0x03f00000 0x00100000>; + label = "NOR U-Boot Image"; + read-only; + }; + }; + + /* CS2 for Display */ + display@2,0 { + compatible = "solomon,ssd1289fb"; + reg = <0x2 0x0000 0x0004>; + }; + +}; + +&soc { + usb@22000 { + phy_type = "ulpi"; + }; + + mdio@24000 { + phy0: ethernet-phy@2 { + interrupt-parent = <&mpic>; + interrupts = <1 1 0 0>; + reg = <0x2>; + }; + + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; + interrupts = <2 1 0 0>; + reg = <0x1>; + }; + + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25000 { + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26000 { + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet0: ethernet@b0000 { + phy-handle = <&phy0>; + phy-connection-type = "rgmii-id"; + + }; + + enet1: ethernet@b1000 { + status = "disabled"; + }; + + enet2: ethernet@b2000 { + phy-handle = <&phy1>; + phy-connection-type = "rgmii-id"; + }; + + par_io@e0100 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xe0100 0x60>; + ranges = <0x0 0xe0100 0x60>; + device_type = "par_io"; + num-ports = <3>; + pio1: ucc_pin@01 { + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 0x1 0x13 0x1 0x0 0x1 0x0 /* QE_MUX_MDC */ + 0x1 0x14 0x3 0x0 0x1 0x0 /* QE_MUX_MDIO */ + 0x0 0x17 0x2 0x0 0x2 0x0 /* CLK12 */ + 0x0 0x18 0x2 0x0 0x1 0x0 /* CLK9 */ + 0x0 0x7 0x1 0x0 0x2 0x0 /* ENET1_TXD0_SER1_TXD0 */ + 0x0 0x9 0x1 0x0 0x2 0x0 /* ENET1_TXD1_SER1_TXD1 */ + 0x0 0xb 0x1 0x0 0x2 0x0 /* ENET1_TXD2_SER1_TXD2 */ + 0x0 0xc 0x1 0x0 0x2 0x0 /* ENET1_TXD3_SER1_TXD3 */ + 0x0 0x6 0x2 0x0 0x2 0x0 /* ENET1_RXD0_SER1_RXD0 */ + 0x0 0xa 0x2 0x0 0x2 0x0 /* ENET1_RXD1_SER1_RXD1 */ + 0x0 0xe 0x2 0x0 0x2 0x0 /* ENET1_RXD2_SER1_RXD2 */ + 0x0 0xf 0x2 0x0 0x2 0x0 /* ENET1_RXD3_SER1_RXD3 */ + 0x0 0x5 0x1 0x0 0x2 0x0 /* ENET1_TX_EN_SER1_RTS_B */ + 0x0 0xd 0x1 0x0 0x2 0x0 /* ENET1_TX_ER */ + 0x0 0x4 0x2 0x0 0x2 0x0 /* ENET1_RX_DV_SER1_CTS_B */ + 0x0 0x8 0x2 0x0 0x2 0x0 /* ENET1_RX_ER_SER1_CD_B */ + 0x0 0x11 0x2 0x0 0x2 0x0 /* ENET1_CRS */ + 0x0 0x10 0x2 0x0 0x2 0x0>; /* ENET1_COL */ + }; + + pio2: ucc_pin@02 { + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 0x1 0x13 0x1 0x0 0x1 0x0 /* QE_MUX_MDC */ + 0x1 0x14 0x3 0x0 0x1 0x0 /* QE_MUX_MDIO */ + 0x1 0xb 0x2 0x0 0x1 0x0 /* CLK13 */ + 0x1 0x7 0x1 0x0 0x2 0x0 /* ENET5_TXD0_SER5_TXD0 */ + 0x1 0xa 0x1 0x0 0x2 0x0 /* ENET5_TXD1_SER5_TXD1 */ + 0x1 0x6 0x2 0x0 0x2 0x0 /* ENET5_RXD0_SER5_RXD0 */ + 0x1 0x9 0x2 0x0 0x2 0x0 /* ENET5_RXD1_SER5_RXD1 */ + 0x1 0x5 0x1 0x0 0x2 0x0 /* ENET5_TX_EN_SER5_RTS_B */ + 0x1 0x4 0x2 0x0 0x2 0x0 /* ENET5_RX_DV_SER5_CTS_B */ + 0x1 0x8 0x2 0x0 0x2 0x0>; /* ENET5_RX_ER_SER5_CD_B */ + }; + + pio3: ucc_pin@03 { + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 0x0 0x16 0x2 0x0 0x2 0x0 /* SER7_CD_B*/ + 0x0 0x12 0x2 0x0 0x2 0x0 /* SER7_CTS_B*/ + 0x0 0x13 0x1 0x0 0x2 0x0 /* SER7_RTS_B*/ + 0x0 0x14 0x2 0x0 0x2 0x0 /* SER7_RXD0*/ + 0x0 0x15 0x1 0x0 0x2 0x0>; /* SER7_TXD0*/ + }; + + pio4: ucc_pin@04 { + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 0x1 0x0 0x2 0x0 0x2 0x0 /* SER3_CD_B*/ + 0x0 0x1c 0x2 0x0 0x2 0x0 /* SER3_CTS_B*/ + 0x0 0x1d 0x1 0x0 0x2 0x0 /* SER3_RTS_B*/ + 0x0 0x1e 0x2 0x0 0x2 0x0 /* SER3_RXD0*/ + 0x0 0x1f 0x1 0x0 0x2 0x0>; /* SER3_TXD0*/ + }; + }; +}; + +&qe { + enet3: ucc@2000 { + device_type = "network"; + compatible = "ucc_geth"; + rx-clock-name = "clk12"; + tx-clock-name = "clk9"; + pio-handle = <&pio1>; + phy-handle = <&qe_phy0>; + phy-connection-type = "mii"; + }; + + mdio@2120 { + qe_phy0: ethernet-phy@18 { + interrupt-parent = <&mpic>; + interrupts = <4 1 0 0>; + reg = <0x18>; + device_type = "ethernet-phy"; + }; + qe_phy1: ethernet-phy@19 { + interrupt-parent = <&mpic>; + interrupts = <5 1 0 0>; + reg = <0x19>; + device_type = "ethernet-phy"; + }; + tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet4: ucc@2400 { + device_type = "network"; + compatible = "ucc_geth"; + rx-clock-name = "none"; + tx-clock-name = "clk13"; + pio-handle = <&pio2>; + phy-handle = <&qe_phy1>; + phy-connection-type = "rmii"; + }; + + serial2: ucc@2600 { + device_type = "serial"; + compatible = "ucc_uart"; + port-number = <0>; + rx-clock-name = "brg6"; + tx-clock-name = "brg6"; + pio-handle = <&pio3>; + }; + + serial3: ucc@2200 { + device_type = "serial"; + compatible = "ucc_uart"; + port-number = <1>; + rx-clock-name = "brg2"; + tx-clock-name = "brg2"; + pio-handle = <&pio4>; + }; +}; diff --git a/arch/powerpc/boot/dts/virtex440-ml507.dts b/arch/powerpc/boot/dts/virtex440-ml507.dts index fc7073bc547efa..391a4e299783d8 100644 --- a/arch/powerpc/boot/dts/virtex440-ml507.dts +++ b/arch/powerpc/boot/dts/virtex440-ml507.dts @@ -257,6 +257,8 @@ #size-cells = <1>; compatible = "xlnx,compound"; ethernet@81c00000 { + #address-cells = <1>; + #size-cells = <0>; compatible = "xlnx,xps-ll-temac-1.01.b"; device_type = "network"; interrupt-parent = <&xps_intc_0>; diff --git a/arch/powerpc/boot/mvme5100.c b/arch/powerpc/boot/mvme5100.c new file mode 100644 index 00000000000000..cb865f83c60b55 --- /dev/null +++ b/arch/powerpc/boot/mvme5100.c @@ -0,0 +1,27 @@ +/* + * Motorola/Emerson MVME5100 with PPCBug firmware. + * + * Author: Stephen Chivers + * + * Copyright 2013 CSC Australia Pty. Ltd. + * + * 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. + * + */ +#include "types.h" +#include "ops.h" +#include "io.h" + +BSS_STACK(4096); + +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5) +{ + u32 heapsize; + + heapsize = 0x8000000 - (u32)_end; /* 128M */ + simple_alloc_init(_end, heapsize, 32, 64); + fdt_init(_dtb_start); + serial_console_init(); +} diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index 2e1af74a64bec5..d27a25518b018b 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -265,6 +265,10 @@ epapr) link_address='0x20000000' pie=-pie ;; +mvme5100) + platformo="$object/fixed-head.o $object/mvme5100.o" + binary=y + ;; esac vmz="$tmpdir/`basename \"$kernel\"`.$ext" diff --git a/arch/powerpc/configs/85xx/p1023_defconfig b/arch/powerpc/configs/85xx/p1023_defconfig deleted file mode 100644 index b06d37da44f454..00000000000000 --- a/arch/powerpc/configs/85xx/p1023_defconfig +++ /dev/null @@ -1,188 +0,0 @@ -CONFIG_PPC_85xx=y -CONFIG_SMP=y -CONFIG_NR_CPUS=2 -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_AUDIT=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_RCU_FANOUT=32 -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_KALLSYMS_ALL=y -CONFIG_EMBEDDED=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y -CONFIG_MODVERSIONS=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAC_PARTITION=y -CONFIG_PHYSICAL_START=0x00000000 -CONFIG_P1023_RDB=y -CONFIG_P1023_RDS=y -CONFIG_QUICC_ENGINE=y -CONFIG_QE_GPIO=y -CONFIG_CPM2=y -CONFIG_HIGHMEM=y -# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_BINFMT_MISC=m -CONFIG_MATH_EMULATION=y -CONFIG_SWIOTLB=y -CONFIG_PCI=y -CONFIG_PCIEPORTBUS=y -# CONFIG_PCIEAER is not set -# CONFIG_PCIEASPM is not set -CONFIG_PCI_MSI=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_NET_KEY=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_MULTIPATH=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_IP_PNP_RARP=y -CONFIG_NET_IPIP=y -CONFIG_IP_MROUTE=y -CONFIG_IP_PIMSM_V1=y -CONFIG_IP_PIMSM_V2=y -CONFIG_ARPD=y -CONFIG_INET_ESP=y -# CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_INET_LRO is not set -CONFIG_IPV6=y -CONFIG_IP_SCTP=m -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_DEVTMPFS=y -CONFIG_DEVTMPFS_MOUNT=y -CONFIG_MTD=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND=y -CONFIG_MTD_NAND_FSL_ELBC=y -CONFIG_PROC_DEVICETREE=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=131072 -CONFIG_EEPROM_AT24=y -CONFIG_EEPROM_LEGACY=y -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=y -CONFIG_BLK_DEV_SR=y -CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_LOGGING=y -CONFIG_ATA=y -CONFIG_SATA_FSL=y -CONFIG_SATA_SIL24=y -CONFIG_NETDEVICES=y -CONFIG_DUMMY=y -CONFIG_FS_ENET=y -CONFIG_FSL_PQ_MDIO=y -CONFIG_E1000E=y -CONFIG_PHYLIB=y -CONFIG_AT803X_PHY=y -CONFIG_MARVELL_PHY=y -CONFIG_DAVICOM_PHY=y -CONFIG_CICADA_PHY=y -CONFIG_VITESSE_PHY=y -CONFIG_FIXED_PHY=y -CONFIG_INPUT_FF_MEMLESS=m -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -CONFIG_SERIO_LIBPS2=y -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=2 -CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -CONFIG_SERIAL_8250_EXTENDED=y -CONFIG_SERIAL_8250_MANY_PORTS=y -CONFIG_SERIAL_8250_SHARE_IRQ=y -CONFIG_SERIAL_8250_DETECT_IRQ=y -CONFIG_SERIAL_8250_RSA=y -CONFIG_HW_RANDOM=y -CONFIG_NVRAM=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_CPM=m -CONFIG_I2C_MPC=y -CONFIG_GPIO_MPC8XXX=y -# CONFIG_HWMON is not set -CONFIG_VIDEO_OUTPUT_CONTROL=y -CONFIG_SOUND=y -CONFIG_SND=y -CONFIG_SND_MIXER_OSS=y -CONFIG_SND_PCM_OSS=y -# CONFIG_SND_SUPPORT_OLD_API is not set -CONFIG_USB=y -CONFIG_USB_DEVICEFS=y -CONFIG_USB_MON=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_FSL=y -CONFIG_USB_STORAGE=y -CONFIG_EDAC=y -CONFIG_EDAC_MM_EDAC=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_DS1307=y -CONFIG_RTC_DRV_CMOS=y -CONFIG_DMADEVICES=y -CONFIG_FSL_DMA=y -# CONFIG_NET_DMA is not set -CONFIG_STAGING=y -CONFIG_EXT2_FS=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_ISO9660_FS=m -CONFIG_JOLIET=y -CONFIG_ZISOFS=y -CONFIG_UDF_FS=m -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=y -CONFIG_NTFS_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_ADFS_FS=m -CONFIG_AFFS_FS=m -CONFIG_HFS_FS=m -CONFIG_HFSPLUS_FS=m -CONFIG_BEFS_FS=m -CONFIG_BFS_FS=m -CONFIG_EFS_FS=m -CONFIG_CRAMFS=y -CONFIG_VXFS_FS=m -CONFIG_HPFS_FS=m -CONFIG_QNX4FS_FS=m -CONFIG_SYSV_FS=m -CONFIG_UFS_FS=m -CONFIG_NFS_FS=y -CONFIG_NFS_V4=y -CONFIG_ROOT_NFS=y -CONFIG_NFSD=y -CONFIG_CRC_T10DIF=y -CONFIG_FRAME_WARN=8092 -CONFIG_DEBUG_FS=y -CONFIG_DETECT_HUNG_TASK=y -# CONFIG_DEBUG_BUGVERBOSE is not set -CONFIG_DEBUG_INFO=y -CONFIG_STRICT_DEVMEM=y -CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_SHA256=y -CONFIG_CRYPTO_SHA512=y -CONFIG_CRYPTO_AES=y -# CONFIG_CRYPTO_ANSI_CPRNG is not set -CONFIG_CRYPTO_DEV_FSL_CAAM=y diff --git a/arch/powerpc/configs/adder875_defconfig b/arch/powerpc/configs/adder875_defconfig index 69128740c14dcd..15b1ff5d96e763 100644 --- a/arch/powerpc/configs/adder875_defconfig +++ b/arch/powerpc/configs/adder875_defconfig @@ -70,3 +70,4 @@ CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set +CONFIG_CRC32_SLICEBY4=y diff --git a/arch/powerpc/configs/ep88xc_defconfig b/arch/powerpc/configs/ep88xc_defconfig index 219fd470ed22d4..b8a79d7ee89fae 100644 --- a/arch/powerpc/configs/ep88xc_defconfig +++ b/arch/powerpc/configs/ep88xc_defconfig @@ -72,3 +72,4 @@ CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set +CONFIG_CRC32_SLICEBY4=y diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig index d2e0fab5ee5b3e..83d3550fdb5400 100644 --- a/arch/powerpc/configs/mpc85xx_defconfig +++ b/arch/powerpc/configs/mpc85xx_defconfig @@ -31,6 +31,7 @@ CONFIG_C293_PCIE=y CONFIG_P1010_RDB=y CONFIG_P1022_DS=y CONFIG_P1022_RDK=y +CONFIG_P1023_RDB=y CONFIG_P1023_RDS=y CONFIG_SOCRATES=y CONFIG_KSI8560=y @@ -113,6 +114,7 @@ CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 +CONFIG_EEPROM_AT24=y CONFIG_EEPROM_LEGACY=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y @@ -211,6 +213,7 @@ CONFIG_EDAC=y CONFIG_EDAC_MM_EDAC=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_CMOS=y +CONFIG_RTC_DRV_DS1307=y CONFIG_DMADEVICES=y CONFIG_FSL_DMA=y # CONFIG_NET_DMA is not set diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig index 4cb7b59e98bd84..4b686294feb495 100644 --- a/arch/powerpc/configs/mpc85xx_smp_defconfig +++ b/arch/powerpc/configs/mpc85xx_smp_defconfig @@ -34,6 +34,7 @@ CONFIG_C293_PCIE=y CONFIG_P1010_RDB=y CONFIG_P1022_DS=y CONFIG_P1022_RDK=y +CONFIG_P1023_RDB=y CONFIG_P1023_RDS=y CONFIG_SOCRATES=y CONFIG_KSI8560=y @@ -116,6 +117,7 @@ CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 +CONFIG_EEPROM_AT24=y CONFIG_EEPROM_LEGACY=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y @@ -212,6 +214,7 @@ CONFIG_EDAC=y CONFIG_EDAC_MM_EDAC=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_CMOS=y +CONFIG_RTC_DRV_DS1307=y CONFIG_DMADEVICES=y CONFIG_FSL_DMA=y # CONFIG_NET_DMA is not set diff --git a/arch/powerpc/configs/mpc866_ads_defconfig b/arch/powerpc/configs/mpc866_ads_defconfig index 5c258823e69481..d954e80c286a92 100644 --- a/arch/powerpc/configs/mpc866_ads_defconfig +++ b/arch/powerpc/configs/mpc866_ads_defconfig @@ -55,3 +55,4 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_CRC_CCITT=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set # CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRC32_SLICEBY4=y diff --git a/arch/powerpc/configs/mpc885_ads_defconfig b/arch/powerpc/configs/mpc885_ads_defconfig index 9e146cdf63ded0..3f47d00a10c0d9 100644 --- a/arch/powerpc/configs/mpc885_ads_defconfig +++ b/arch/powerpc/configs/mpc885_ads_defconfig @@ -78,3 +78,4 @@ CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set +CONFIG_CRC32_SLICEBY4=y diff --git a/arch/powerpc/configs/mvme5100_defconfig b/arch/powerpc/configs/mvme5100_defconfig new file mode 100644 index 00000000000000..93c7752e2dbbdf --- /dev/null +++ b/arch/powerpc/configs/mvme5100_defconfig @@ -0,0 +1,144 @@ +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_NET_NS is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +# CONFIG_COMPAT_BRK is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_PPC_CHRP is not set +# CONFIG_PPC_PMAC is not set +CONFIG_EMBEDDED6xx=y +CONFIG_MVME5100=y +CONFIG_KVM_GUEST=y +CONFIG_HZ_100=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_COMPACTION is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttyS0,9600 ip=dhcp root=/dev/nfs" +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_INET_LRO is not set +# CONFIG_IPV6 is not set +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_LAPB=m +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_PROC_DEVICETREE=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=2 +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_EEPROM_LEGACY=m +CONFIG_NETDEVICES=y +CONFIG_TUN=m +# CONFIG_NET_VENDOR_3COM is not set +CONFIG_E100=y +# CONFIG_WLAN is not set +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=10 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_HW_RANDOM=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MPC=y +# CONFIG_HWMON is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +# CONFIG_VGA_CONSOLE is not set +# CONFIG_HID is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_VME_BUS=m +CONFIG_VME_CA91CX42=m +CONFIG_EXT2_FS=m +CONFIG_EXT3_FS=m +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_XFS_FS=m +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_CIFS=m +CONFIG_NLS=y +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_UTF8=m +CONFIG_CRC_CCITT=m +CONFIG_CRC_T10DIF=y +CONFIG_XZ_DEC=y +CONFIG_XZ_DEC_X86=y +CONFIG_XZ_DEC_IA64=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_ARMTHUMB=y +CONFIG_XZ_DEC_SPARC=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=20 +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_DEFLATE=m +# CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index 581a3bcae72836..e015896b7e5ceb 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -186,6 +186,7 @@ CONFIG_SCSI_DH_RDAC=m CONFIG_SCSI_DH_ALUA=m CONFIG_ATA=y CONFIG_SATA_SIL24=y +CONFIG_SATA_MV=y CONFIG_SATA_SVW=y CONFIG_MD=y CONFIG_BLK_DEV_MD=y diff --git a/arch/powerpc/configs/tqm8xx_defconfig b/arch/powerpc/configs/tqm8xx_defconfig index 8616fde0896f41..4b6f8bf104e068 100644 --- a/arch/powerpc/configs/tqm8xx_defconfig +++ b/arch/powerpc/configs/tqm8xx_defconfig @@ -84,3 +84,4 @@ CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set +CONFIG_CRC32_SLICEBY4=y diff --git a/arch/powerpc/include/asm/bitops.h b/arch/powerpc/include/asm/bitops.h index 910194e9a1e2a2..a5e9a7d494d8bd 100644 --- a/arch/powerpc/include/asm/bitops.h +++ b/arch/powerpc/include/asm/bitops.h @@ -46,6 +46,11 @@ #include #include +/* PPC bit number conversion */ +#define PPC_BITLSHIFT(be) (BITS_PER_LONG - 1 - (be)) +#define PPC_BIT(bit) (1UL << PPC_BITLSHIFT(bit)) +#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs)) + /* * clear_bit doesn't imply a memory barrier */ diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h index 9e495c9a6a889d..ed0afc1e44a433 100644 --- a/arch/powerpc/include/asm/cache.h +++ b/arch/powerpc/include/asm/cache.h @@ -41,8 +41,20 @@ struct ppc64_caches { extern struct ppc64_caches ppc64_caches; #endif /* __powerpc64__ && ! __ASSEMBLY__ */ -#if !defined(__ASSEMBLY__) +#if defined(__ASSEMBLY__) +/* + * For a snooping icache, we still need a dummy icbi to purge all the + * prefetched instructions from the ifetch buffers. We also need a sync + * before the icbi to order the the actual stores to memory that might + * have modified instructions with the icbi. + */ +#define PURGE_PREFETCHED_INS \ + sync; \ + icbi 0,r3; \ + sync; \ + isync +#else #define __read_mostly __attribute__((__section__(".data..read_mostly"))) #ifdef CONFIG_6xx diff --git a/arch/powerpc/include/asm/clk_interface.h b/arch/powerpc/include/asm/clk_interface.h deleted file mode 100644 index ab1882c1e1762b..00000000000000 --- a/arch/powerpc/include/asm/clk_interface.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __ASM_POWERPC_CLK_INTERFACE_H -#define __ASM_POWERPC_CLK_INTERFACE_H - -#include - -struct clk_interface { - struct clk* (*clk_get) (struct device *dev, const char *id); - int (*clk_enable) (struct clk *clk); - void (*clk_disable) (struct clk *clk); - unsigned long (*clk_get_rate) (struct clk *clk); - void (*clk_put) (struct clk *clk); - long (*clk_round_rate) (struct clk *clk, unsigned long rate); - int (*clk_set_rate) (struct clk *clk, unsigned long rate); - int (*clk_set_parent) (struct clk *clk, struct clk *parent); - struct clk* (*clk_get_parent) (struct clk *clk); -}; - -extern struct clk_interface clk_functions; - -#endif /* __ASM_POWERPC_CLK_INTERFACE_H */ diff --git a/arch/powerpc/include/asm/cmpxchg.h b/arch/powerpc/include/asm/cmpxchg.h index e245aab7f191cc..d463c68fe7f05f 100644 --- a/arch/powerpc/include/asm/cmpxchg.h +++ b/arch/powerpc/include/asm/cmpxchg.h @@ -300,6 +300,7 @@ __cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new, BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ cmpxchg_local((ptr), (o), (n)); \ }) +#define cmpxchg64_relaxed cmpxchg64_local #else #include #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) diff --git a/arch/powerpc/include/asm/code-patching.h b/arch/powerpc/include/asm/code-patching.h index a6f8c7a5cbb74f..97e02f985df8e4 100644 --- a/arch/powerpc/include/asm/code-patching.h +++ b/arch/powerpc/include/asm/code-patching.h @@ -34,6 +34,13 @@ int instr_is_branch_to_addr(const unsigned int *instr, unsigned long addr); unsigned long branch_target(const unsigned int *instr); unsigned int translate_branch(const unsigned int *dest, const unsigned int *src); +#ifdef CONFIG_PPC_BOOK3E_64 +void __patch_exception(int exc, unsigned long addr); +#define patch_exception(exc, name) do { \ + extern unsigned int name; \ + __patch_exception((exc), (unsigned long)&name); \ +} while (0) +#endif static inline unsigned long ppc_function_entry(void *func) { diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 0d4939ba48e721..617cc767c07681 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -90,6 +90,18 @@ struct cpu_spec { * if the error is fatal, 1 if it was fully recovered and 0 to * pass up (not CPU originated) */ int (*machine_check)(struct pt_regs *regs); + + /* + * Processor specific early machine check handler which is + * called in real mode to handle SLB and TLB errors. + */ + long (*machine_check_early)(struct pt_regs *regs); + + /* + * Processor specific routine to flush tlbs. + */ + void (*flush_tlb)(unsigned long inval_selector); + }; extern struct cpu_spec *cur_cpu_spec; diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index e27e9ad6818ea8..150866b2a3fe07 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h @@ -134,6 +134,7 @@ static inline int dma_supported(struct device *dev, u64 mask) } extern int dma_set_mask(struct device *dev, u64 dma_mask); +extern int __dma_set_mask(struct device *dev, u64 dma_mask); #define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL) diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index d3e5e9bc8f946f..d4dd41fb951b34 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h @@ -90,7 +90,8 @@ struct eeh_pe { #define EEH_DEV_IRQ_DISABLED (1 << 3) /* Interrupt disabled */ #define EEH_DEV_DISCONNECTED (1 << 4) /* Removing from PE */ -#define EEH_DEV_SYSFS (1 << 8) /* Sysfs created */ +#define EEH_DEV_NO_HANDLER (1 << 8) /* No error handler */ +#define EEH_DEV_SYSFS (1 << 9) /* Sysfs created */ struct eeh_dev { int mode; /* EEH mode */ @@ -117,6 +118,16 @@ static inline struct pci_dev *eeh_dev_to_pci_dev(struct eeh_dev *edev) return edev ? edev->pdev : NULL; } +/* Return values from eeh_ops::next_error */ +enum { + EEH_NEXT_ERR_NONE = 0, + EEH_NEXT_ERR_INF, + EEH_NEXT_ERR_FROZEN_PE, + EEH_NEXT_ERR_FENCED_PHB, + EEH_NEXT_ERR_DEAD_PHB, + EEH_NEXT_ERR_DEAD_IOC +}; + /* * The struct is used to trace the registered EEH operation * callback functions. Actually, those operation callback @@ -157,13 +168,24 @@ struct eeh_ops { int (*read_config)(struct device_node *dn, int where, int size, u32 *val); int (*write_config)(struct device_node *dn, int where, int size, u32 val); int (*next_error)(struct eeh_pe **pe); + int (*restore_config)(struct device_node *dn); }; extern struct eeh_ops *eeh_ops; -extern int eeh_subsystem_enabled; +extern bool eeh_subsystem_enabled; extern raw_spinlock_t confirm_error_lock; extern int eeh_probe_mode; +static inline bool eeh_enabled(void) +{ + return eeh_subsystem_enabled; +} + +static inline void eeh_set_enable(bool mode) +{ + eeh_subsystem_enabled = mode; +} + #define EEH_PROBE_MODE_DEV (1<<0) /* From PCI device */ #define EEH_PROBE_MODE_DEVTREE (1<<1) /* From device tree */ @@ -234,7 +256,7 @@ void eeh_remove_device(struct pci_dev *); * If this macro yields TRUE, the caller relays to eeh_check_failure() * which does further tests out of line. */ -#define EEH_POSSIBLE_ERROR(val, type) ((val) == (type)~0 && eeh_subsystem_enabled) +#define EEH_POSSIBLE_ERROR(val, type) ((val) == (type)~0 && eeh_enabled()) /* * Reads from a device which has been isolated by EEH will return @@ -245,6 +267,13 @@ void eeh_remove_device(struct pci_dev *); #else /* !CONFIG_EEH */ +static inline bool eeh_enabled(void) +{ + return false; +} + +static inline void eeh_set_enable(bool mode) { } + static inline int eeh_init(void) { return 0; diff --git a/arch/powerpc/include/asm/epapr_hcalls.h b/arch/powerpc/include/asm/epapr_hcalls.h index 86b0ac79990ca4..334459ad145b4e 100644 --- a/arch/powerpc/include/asm/epapr_hcalls.h +++ b/arch/powerpc/include/asm/epapr_hcalls.h @@ -460,5 +460,116 @@ static inline unsigned int ev_idle(void) return r3; } + +#ifdef CONFIG_EPAPR_PARAVIRT +static inline unsigned long epapr_hypercall(unsigned long *in, + unsigned long *out, + unsigned long nr) +{ + unsigned long register r0 asm("r0"); + unsigned long register r3 asm("r3") = in[0]; + unsigned long register r4 asm("r4") = in[1]; + unsigned long register r5 asm("r5") = in[2]; + unsigned long register r6 asm("r6") = in[3]; + unsigned long register r7 asm("r7") = in[4]; + unsigned long register r8 asm("r8") = in[5]; + unsigned long register r9 asm("r9") = in[6]; + unsigned long register r10 asm("r10") = in[7]; + unsigned long register r11 asm("r11") = nr; + unsigned long register r12 asm("r12"); + + asm volatile("bl epapr_hypercall_start" + : "=r"(r0), "=r"(r3), "=r"(r4), "=r"(r5), "=r"(r6), + "=r"(r7), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11), + "=r"(r12) + : "r"(r3), "r"(r4), "r"(r5), "r"(r6), "r"(r7), "r"(r8), + "r"(r9), "r"(r10), "r"(r11) + : "memory", "cc", "xer", "ctr", "lr"); + + out[0] = r4; + out[1] = r5; + out[2] = r6; + out[3] = r7; + out[4] = r8; + out[5] = r9; + out[6] = r10; + out[7] = r11; + + return r3; +} +#else +static unsigned long epapr_hypercall(unsigned long *in, + unsigned long *out, + unsigned long nr) +{ + return EV_UNIMPLEMENTED; +} +#endif + +static inline long epapr_hypercall0_1(unsigned int nr, unsigned long *r2) +{ + unsigned long in[8]; + unsigned long out[8]; + unsigned long r; + + r = epapr_hypercall(in, out, nr); + *r2 = out[0]; + + return r; +} + +static inline long epapr_hypercall0(unsigned int nr) +{ + unsigned long in[8]; + unsigned long out[8]; + + return epapr_hypercall(in, out, nr); +} + +static inline long epapr_hypercall1(unsigned int nr, unsigned long p1) +{ + unsigned long in[8]; + unsigned long out[8]; + + in[0] = p1; + return epapr_hypercall(in, out, nr); +} + +static inline long epapr_hypercall2(unsigned int nr, unsigned long p1, + unsigned long p2) +{ + unsigned long in[8]; + unsigned long out[8]; + + in[0] = p1; + in[1] = p2; + return epapr_hypercall(in, out, nr); +} + +static inline long epapr_hypercall3(unsigned int nr, unsigned long p1, + unsigned long p2, unsigned long p3) +{ + unsigned long in[8]; + unsigned long out[8]; + + in[0] = p1; + in[1] = p2; + in[2] = p3; + return epapr_hypercall(in, out, nr); +} + +static inline long epapr_hypercall4(unsigned int nr, unsigned long p1, + unsigned long p2, unsigned long p3, + unsigned long p4) +{ + unsigned long in[8]; + unsigned long out[8]; + + in[0] = p1; + in[1] = p2; + in[2] = p3; + in[3] = p4; + return epapr_hypercall(in, out, nr); +} #endif /* !__ASSEMBLY__ */ #endif /* _EPAPR_HCALLS_H */ diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 243ce69ad685ff..66830618cc19b2 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -301,9 +301,12 @@ do_kvm_##n: \ beq 4f; /* if from kernel mode */ \ ACCOUNT_CPU_USER_ENTRY(r9, r10); \ SAVE_PPR(area, r9, r10); \ -4: std r2,GPR2(r1); /* save r2 in stackframe */ \ - SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ - SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \ +4: EXCEPTION_PROLOG_COMMON_2(area) \ + EXCEPTION_PROLOG_COMMON_3(n) \ + ACCOUNT_STOLEN_TIME + +/* Save original regs values from save area to stack frame. */ +#define EXCEPTION_PROLOG_COMMON_2(area) \ ld r9,area+EX_R9(r13); /* move r9, r10 to stackframe */ \ ld r10,area+EX_R10(r13); \ std r9,GPR9(r1); \ @@ -318,11 +321,16 @@ do_kvm_##n: \ ld r10,area+EX_CFAR(r13); \ std r10,ORIG_GPR3(r1); \ END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66); \ + GET_CTR(r10, area); \ + std r10,_CTR(r1); + +#define EXCEPTION_PROLOG_COMMON_3(n) \ + std r2,GPR2(r1); /* save r2 in stackframe */ \ + SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ + SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \ mflr r9; /* Get LR, later save to stack */ \ ld r2,PACATOC(r13); /* get kernel TOC into r2 */ \ std r9,_LINK(r1); \ - GET_CTR(r10, area); \ - std r10,_CTR(r1); \ lbz r10,PACASOFTIRQEN(r13); \ mfspr r11,SPRN_XER; /* save XER in stackframe */ \ std r10,SOFTE(r1); \ @@ -332,8 +340,7 @@ do_kvm_##n: \ li r10,0; \ ld r11,exception_marker@toc(r2); \ std r10,RESULT(r1); /* clear regs->result */ \ - std r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */ \ - ACCOUNT_STOLEN_TIME + std r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */ /* * Exception vectors. diff --git a/arch/powerpc/include/asm/fsl_lbc.h b/arch/powerpc/include/asm/fsl_lbc.h index 420b45368fcff0..067fb0dca549b8 100644 --- a/arch/powerpc/include/asm/fsl_lbc.h +++ b/arch/powerpc/include/asm/fsl_lbc.h @@ -285,7 +285,7 @@ struct fsl_lbc_ctrl { /* device info */ struct device *dev; struct fsl_lbc_regs __iomem *regs; - int irq; + int irq[2]; wait_queue_head_t irq_wait; spinlock_t lock; void *nand; diff --git a/arch/powerpc/include/asm/hardirq.h b/arch/powerpc/include/asm/hardirq.h index 3bdcfce2c42a92..418fb654370d09 100644 --- a/arch/powerpc/include/asm/hardirq.h +++ b/arch/powerpc/include/asm/hardirq.h @@ -6,7 +6,8 @@ typedef struct { unsigned int __softirq_pending; - unsigned int timer_irqs; + unsigned int timer_irqs_event; + unsigned int timer_irqs_others; unsigned int pmu_irqs; unsigned int mce_exceptions; unsigned int spurious_irqs; diff --git a/arch/powerpc/include/asm/hugetlb.h b/arch/powerpc/include/asm/hugetlb.h index d750336b171db4..623f2971ce0ed8 100644 --- a/arch/powerpc/include/asm/hugetlb.h +++ b/arch/powerpc/include/asm/hugetlb.h @@ -127,7 +127,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { #ifdef CONFIG_PPC64 - return __pte(pte_update(mm, addr, ptep, ~0UL, 1)); + return __pte(pte_update(mm, addr, ptep, ~0UL, 0, 1)); #else return __pte(pte_update(ptep, ~0UL, 0)); #endif diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index 575fbf81fad02d..97d3869991ca69 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -191,8 +191,24 @@ DEF_MMIO_OUT_D(out_le32, 32, stw); #endif /* __BIG_ENDIAN */ +/* + * Cache inhibitied accessors for use in real mode, you don't want to use these + * unless you know what you're doing. + * + * NB. These use the cpu byte ordering. + */ +DEF_MMIO_OUT_X(out_rm8, 8, stbcix); +DEF_MMIO_OUT_X(out_rm16, 16, sthcix); +DEF_MMIO_OUT_X(out_rm32, 32, stwcix); +DEF_MMIO_IN_X(in_rm8, 8, lbzcix); +DEF_MMIO_IN_X(in_rm16, 16, lhzcix); +DEF_MMIO_IN_X(in_rm32, 32, lwzcix); + #ifdef __powerpc64__ +DEF_MMIO_OUT_X(out_rm64, 64, stdcix); +DEF_MMIO_IN_X(in_rm64, 64, ldcix); + #ifdef __BIG_ENDIAN__ DEF_MMIO_OUT_D(out_be64, 64, std); DEF_MMIO_IN_D(in_be64, 64, ld); diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h index c34656a8925e2f..42632c7a2a4e77 100644 --- a/arch/powerpc/include/asm/iommu.h +++ b/arch/powerpc/include/asm/iommu.h @@ -30,22 +30,19 @@ #include #include -#define IOMMU_PAGE_SHIFT 12 -#define IOMMU_PAGE_SIZE (ASM_CONST(1) << IOMMU_PAGE_SHIFT) -#define IOMMU_PAGE_MASK (~((1 << IOMMU_PAGE_SHIFT) - 1)) -#define IOMMU_PAGE_ALIGN(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE) +#define IOMMU_PAGE_SHIFT_4K 12 +#define IOMMU_PAGE_SIZE_4K (ASM_CONST(1) << IOMMU_PAGE_SHIFT_4K) +#define IOMMU_PAGE_MASK_4K (~((1 << IOMMU_PAGE_SHIFT_4K) - 1)) +#define IOMMU_PAGE_ALIGN_4K(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE_4K) + +#define IOMMU_PAGE_SIZE(tblptr) (ASM_CONST(1) << (tblptr)->it_page_shift) +#define IOMMU_PAGE_MASK(tblptr) (~((1 << (tblptr)->it_page_shift) - 1)) +#define IOMMU_PAGE_ALIGN(addr, tblptr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE(tblptr)) /* Boot time flags */ extern int iommu_is_off; extern int iommu_force_on; -/* Pure 2^n version of get_order */ -static __inline__ __attribute_const__ int get_iommu_order(unsigned long size) -{ - return __ilog2((size - 1) >> IOMMU_PAGE_SHIFT) + 1; -} - - /* * IOMAP_MAX_ORDER defines the largest contiguous block * of dma space we can get. IOMAP_MAX_ORDER = 13 @@ -76,11 +73,21 @@ struct iommu_table { struct iommu_pool large_pool; struct iommu_pool pools[IOMMU_NR_POOLS]; unsigned long *it_map; /* A simple allocation bitmap for now */ + unsigned long it_page_shift;/* table iommu page size */ #ifdef CONFIG_IOMMU_API struct iommu_group *it_group; #endif + void (*set_bypass)(struct iommu_table *tbl, bool enable); }; +/* Pure 2^n version of get_order */ +static inline __attribute_const__ +int get_iommu_order(unsigned long size, struct iommu_table *tbl) +{ + return __ilog2((size - 1) >> tbl->it_page_shift) + 1; +} + + struct scatterlist; static inline void set_iommu_table_base(struct device *dev, void *base) @@ -101,8 +108,34 @@ extern void iommu_free_table(struct iommu_table *tbl, const char *node_name); */ extern struct iommu_table *iommu_init_table(struct iommu_table * tbl, int nid); +#ifdef CONFIG_IOMMU_API extern void iommu_register_group(struct iommu_table *tbl, int pci_domain_number, unsigned long pe_num); +extern int iommu_add_device(struct device *dev); +extern void iommu_del_device(struct device *dev); +#else +static inline void iommu_register_group(struct iommu_table *tbl, + int pci_domain_number, + unsigned long pe_num) +{ +} + +static inline int iommu_add_device(struct device *dev) +{ + return 0; +} + +static inline void iommu_del_device(struct device *dev) +{ +} +#endif /* !CONFIG_IOMMU_API */ + +static inline void set_iommu_table_base_and_group(struct device *dev, + void *base) +{ + set_iommu_table_base(dev, base); + iommu_add_device(dev); +} extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl, struct scatterlist *sglist, int nelems, diff --git a/arch/powerpc/include/asm/kvm_asm.h b/arch/powerpc/include/asm/kvm_asm.h index 1bd92fd43cfb7f..19eb74a95b592f 100644 --- a/arch/powerpc/include/asm/kvm_asm.h +++ b/arch/powerpc/include/asm/kvm_asm.h @@ -74,6 +74,7 @@ #define BOOKE_INTERRUPT_GUEST_DBELL_CRIT 39 #define BOOKE_INTERRUPT_HV_SYSCALL 40 #define BOOKE_INTERRUPT_HV_PRIV 41 +#define BOOKE_INTERRUPT_LRAT_ERROR 42 /* book3s */ @@ -91,14 +92,17 @@ #define BOOK3S_INTERRUPT_FP_UNAVAIL 0x800 #define BOOK3S_INTERRUPT_DECREMENTER 0x900 #define BOOK3S_INTERRUPT_HV_DECREMENTER 0x980 +#define BOOK3S_INTERRUPT_DOORBELL 0xa00 #define BOOK3S_INTERRUPT_SYSCALL 0xc00 #define BOOK3S_INTERRUPT_TRACE 0xd00 #define BOOK3S_INTERRUPT_H_DATA_STORAGE 0xe00 #define BOOK3S_INTERRUPT_H_INST_STORAGE 0xe20 #define BOOK3S_INTERRUPT_H_EMUL_ASSIST 0xe40 +#define BOOK3S_INTERRUPT_H_DOORBELL 0xe80 #define BOOK3S_INTERRUPT_PERFMON 0xf00 #define BOOK3S_INTERRUPT_ALTIVEC 0xf20 #define BOOK3S_INTERRUPT_VSX 0xf40 +#define BOOK3S_INTERRUPT_H_FAC_UNAVAIL 0xf80 #define BOOK3S_IRQPRIO_SYSTEM_RESET 0 #define BOOK3S_IRQPRIO_DATA_SEGMENT 1 diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h index bc23b1ba798068..83851aabfdc869 100644 --- a/arch/powerpc/include/asm/kvm_book3s.h +++ b/arch/powerpc/include/asm/kvm_book3s.h @@ -186,9 +186,6 @@ extern void kvmppc_update_lpcr(struct kvm *kvm, unsigned long lpcr, extern void kvmppc_entry_trampoline(void); extern void kvmppc_hv_entry_trampoline(void); -extern void kvmppc_load_up_fpu(void); -extern void kvmppc_load_up_altivec(void); -extern void kvmppc_load_up_vsx(void); extern u32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst); extern ulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst); extern int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd); @@ -271,16 +268,25 @@ static inline ulong kvmppc_get_pc(struct kvm_vcpu *vcpu) return vcpu->arch.pc; } -static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu) +static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu) { - ulong pc = kvmppc_get_pc(vcpu); + return (vcpu->arch.shared->msr & MSR_LE) != (MSR_KERNEL & MSR_LE); +} +static inline u32 kvmppc_get_last_inst_internal(struct kvm_vcpu *vcpu, ulong pc) +{ /* Load the instruction manually if it failed to do so in the * exit path */ if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED) kvmppc_ld(vcpu, &pc, sizeof(u32), &vcpu->arch.last_inst, false); - return vcpu->arch.last_inst; + return kvmppc_need_byteswap(vcpu) ? swab32(vcpu->arch.last_inst) : + vcpu->arch.last_inst; +} + +static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu) +{ + return kvmppc_get_last_inst_internal(vcpu, kvmppc_get_pc(vcpu)); } /* @@ -290,14 +296,7 @@ static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu) */ static inline u32 kvmppc_get_last_sc(struct kvm_vcpu *vcpu) { - ulong pc = kvmppc_get_pc(vcpu) - 4; - - /* Load the instruction manually if it failed to do so in the - * exit path */ - if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED) - kvmppc_ld(vcpu, &pc, sizeof(u32), &vcpu->arch.last_inst, false); - - return vcpu->arch.last_inst; + return kvmppc_get_last_inst_internal(vcpu, kvmppc_get_pc(vcpu) - 4); } static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu) diff --git a/arch/powerpc/include/asm/kvm_book3s_asm.h b/arch/powerpc/include/asm/kvm_book3s_asm.h index 192917d2239c4e..f3a91dc02c981f 100644 --- a/arch/powerpc/include/asm/kvm_book3s_asm.h +++ b/arch/powerpc/include/asm/kvm_book3s_asm.h @@ -88,6 +88,7 @@ struct kvmppc_host_state { u8 hwthread_req; u8 hwthread_state; u8 host_ipi; + u8 ptid; struct kvm_vcpu *kvm_vcpu; struct kvmppc_vcore *kvm_vcore; unsigned long xics_phys; diff --git a/arch/powerpc/include/asm/kvm_booke.h b/arch/powerpc/include/asm/kvm_booke.h index dd8f61510dfd01..80d46b5a7efb49 100644 --- a/arch/powerpc/include/asm/kvm_booke.h +++ b/arch/powerpc/include/asm/kvm_booke.h @@ -63,6 +63,12 @@ static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu) return vcpu->arch.xer; } +static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu) +{ + /* XXX Would need to check TLB entry */ + return false; +} + static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu) { return vcpu->arch.last_inst; diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 237d1d25b44815..1eaea2dea1745e 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -288,6 +288,7 @@ struct kvmppc_vcore { int n_woken; int nap_count; int napping_threads; + int first_vcpuid; u16 pcpu; u16 last_cpu; u8 vcore_state; @@ -298,10 +299,12 @@ struct kvmppc_vcore { u64 stolen_tb; u64 preempt_tb; struct kvm_vcpu *runner; + struct kvm *kvm; u64 tb_offset; /* guest timebase - host timebase */ ulong lpcr; u32 arch_compat; ulong pcr; + ulong dpdes; /* doorbell state (POWER8) */ }; #define VCORE_ENTRY_COUNT(vc) ((vc)->entry_exit_count & 0xff) @@ -410,8 +413,7 @@ struct kvm_vcpu_arch { ulong gpr[32]; - u64 fpr[32]; - u64 fpscr; + struct thread_fp_state fp; #ifdef CONFIG_SPE ulong evr[32]; @@ -420,12 +422,7 @@ struct kvm_vcpu_arch { u64 acc; #endif #ifdef CONFIG_ALTIVEC - vector128 vr[32]; - vector128 vscr; -#endif - -#ifdef CONFIG_VSX - u64 vsr[64]; + struct thread_vr_state vr; #endif #ifdef CONFIG_KVM_BOOKE_HV @@ -452,6 +449,7 @@ struct kvm_vcpu_arch { ulong pc; ulong ctr; ulong lr; + ulong tar; ulong xer; u32 cr; @@ -461,13 +459,30 @@ struct kvm_vcpu_arch { ulong guest_owned_ext; ulong purr; ulong spurr; + ulong ic; + ulong vtb; ulong dscr; ulong amr; ulong uamor; + ulong iamr; u32 ctrl; + u32 dabrx; ulong dabr; + ulong dawr; + ulong dawrx; + ulong ciabr; ulong cfar; ulong ppr; + ulong pspb; + ulong fscr; + ulong ebbhr; + ulong ebbrr; + ulong bescr; + ulong csigr; + ulong tacr; + ulong tcscr; + ulong acop; + ulong wort; ulong shadow_srr1; #endif u32 vrsave; /* also USPRG0 */ @@ -502,10 +517,33 @@ struct kvm_vcpu_arch { u32 ccr1; u32 dbsr; - u64 mmcr[3]; + u64 mmcr[5]; u32 pmc[8]; + u32 spmc[2]; u64 siar; u64 sdar; + u64 sier; +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + u64 tfhar; + u64 texasr; + u64 tfiar; + + u32 cr_tm; + u64 lr_tm; + u64 ctr_tm; + u64 amr_tm; + u64 ppr_tm; + u64 dscr_tm; + u64 tar_tm; + + ulong gpr_tm[32]; + + struct thread_fp_state fp_tm; + + struct thread_vr_state vr_tm; + u32 vrsave_tm; /* also USPRG0 */ + +#endif #ifdef CONFIG_KVM_EXIT_TIMING struct mutex exit_timing_lock; @@ -546,6 +584,7 @@ struct kvm_vcpu_arch { #endif gpa_t paddr_accessed; gva_t vaddr_accessed; + pgd_t *pgdir; u8 io_gpr; /* GPR used as IO source/target */ u8 mmio_is_bigendian; @@ -603,7 +642,6 @@ struct kvm_vcpu_arch { struct list_head run_list; struct task_struct *run_task; struct kvm_run *kvm_run; - pgd_t *pgdir; spinlock_t vpa_update_lock; struct kvmppc_vpa vpa; @@ -616,9 +654,12 @@ struct kvm_vcpu_arch { spinlock_t tbacct_lock; u64 busy_stolen; u64 busy_preempt; + unsigned long intr_msr; #endif }; +#define VCPU_FPR(vcpu, i) (vcpu)->arch.fp.fpr[i][TS_FPROFFSET] + /* Values for vcpu->arch.state */ #define KVMPPC_VCPU_NOTREADY 0 #define KVMPPC_VCPU_RUNNABLE 1 diff --git a/arch/powerpc/include/asm/kvm_para.h b/arch/powerpc/include/asm/kvm_para.h index 2b119654b4c1a5..336a91acb8b1f3 100644 --- a/arch/powerpc/include/asm/kvm_para.h +++ b/arch/powerpc/include/asm/kvm_para.h @@ -39,10 +39,6 @@ static inline int kvm_para_available(void) return 1; } -extern unsigned long kvm_hypercall(unsigned long *in, - unsigned long *out, - unsigned long nr); - #else static inline int kvm_para_available(void) @@ -50,82 +46,8 @@ static inline int kvm_para_available(void) return 0; } -static unsigned long kvm_hypercall(unsigned long *in, - unsigned long *out, - unsigned long nr) -{ - return EV_UNIMPLEMENTED; -} - #endif -static inline long kvm_hypercall0_1(unsigned int nr, unsigned long *r2) -{ - unsigned long in[8]; - unsigned long out[8]; - unsigned long r; - - r = kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr)); - *r2 = out[0]; - - return r; -} - -static inline long kvm_hypercall0(unsigned int nr) -{ - unsigned long in[8]; - unsigned long out[8]; - - return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr)); -} - -static inline long kvm_hypercall1(unsigned int nr, unsigned long p1) -{ - unsigned long in[8]; - unsigned long out[8]; - - in[0] = p1; - return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr)); -} - -static inline long kvm_hypercall2(unsigned int nr, unsigned long p1, - unsigned long p2) -{ - unsigned long in[8]; - unsigned long out[8]; - - in[0] = p1; - in[1] = p2; - return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr)); -} - -static inline long kvm_hypercall3(unsigned int nr, unsigned long p1, - unsigned long p2, unsigned long p3) -{ - unsigned long in[8]; - unsigned long out[8]; - - in[0] = p1; - in[1] = p2; - in[2] = p3; - return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr)); -} - -static inline long kvm_hypercall4(unsigned int nr, unsigned long p1, - unsigned long p2, unsigned long p3, - unsigned long p4) -{ - unsigned long in[8]; - unsigned long out[8]; - - in[0] = p1; - in[1] = p2; - in[2] = p3; - in[3] = p4; - return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr)); -} - - static inline unsigned int kvm_arch_para_features(void) { unsigned long r; @@ -133,7 +55,7 @@ static inline unsigned int kvm_arch_para_features(void) if (!kvm_para_available()) return 0; - if(kvm_hypercall0_1(KVM_HC_FEATURES, &r)) + if(epapr_hypercall0_1(KVM_HCALL_TOKEN(KVM_HC_FEATURES), &r)) return 0; return r; diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index c8317fbf92c470..fcd53f0d34bad9 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -54,12 +54,13 @@ extern void kvmppc_handler_highmem(void); extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu); extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, unsigned int rt, unsigned int bytes, - int is_bigendian); + int is_default_endian); extern int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu, unsigned int rt, unsigned int bytes, - int is_bigendian); + int is_default_endian); extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, - u64 val, unsigned int bytes, int is_bigendian); + u64 val, unsigned int bytes, + int is_default_endian); extern int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu); @@ -455,6 +456,12 @@ static inline void kvmppc_fix_ee_before_entry(void) trace_hardirqs_on(); #ifdef CONFIG_PPC64 + /* + * To avoid races, the caller must have gone directly from having + * interrupts fully-enabled to hard-disabled. + */ + WARN_ON(local_paca->irq_happened != PACA_IRQ_HARD_DIS); + /* Only need to enable IRQs by hard enabling them after this */ local_paca->irq_happened = 0; local_paca->soft_enabled = 1; diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h index 844c28de7ec05e..d0a2a2f9956471 100644 --- a/arch/powerpc/include/asm/lppaca.h +++ b/arch/powerpc/include/asm/lppaca.h @@ -132,8 +132,6 @@ struct slb_shadow { } save_area[SLB_NUM_BOLTED]; } ____cacheline_aligned; -extern struct slb_shadow slb_shadow[]; - /* * Layout of entries in the hypervisor's dispatch trace log buffer. */ diff --git a/arch/powerpc/include/asm/mce.h b/arch/powerpc/include/asm/mce.h new file mode 100644 index 00000000000000..8e99edf6d966d8 --- /dev/null +++ b/arch/powerpc/include/asm/mce.h @@ -0,0 +1,197 @@ +/* + * Machine check exception header file. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright 2013 IBM Corporation + * Author: Mahesh Salgaonkar + */ + +#ifndef __ASM_PPC64_MCE_H__ +#define __ASM_PPC64_MCE_H__ + +#include + +/* + * Machine Check bits on power7 and power8 + */ +#define P7_SRR1_MC_LOADSTORE(srr1) ((srr1) & PPC_BIT(42)) /* P8 too */ + +/* SRR1 bits for machine check (On Power7 and Power8) */ +#define P7_SRR1_MC_IFETCH(srr1) ((srr1) & PPC_BITMASK(43, 45)) /* P8 too */ + +#define P7_SRR1_MC_IFETCH_UE (0x1 << PPC_BITLSHIFT(45)) /* P8 too */ +#define P7_SRR1_MC_IFETCH_SLB_PARITY (0x2 << PPC_BITLSHIFT(45)) /* P8 too */ +#define P7_SRR1_MC_IFETCH_SLB_MULTIHIT (0x3 << PPC_BITLSHIFT(45)) /* P8 too */ +#define P7_SRR1_MC_IFETCH_SLB_BOTH (0x4 << PPC_BITLSHIFT(45)) +#define P7_SRR1_MC_IFETCH_TLB_MULTIHIT (0x5 << PPC_BITLSHIFT(45)) /* P8 too */ +#define P7_SRR1_MC_IFETCH_UE_TLB_RELOAD (0x6 << PPC_BITLSHIFT(45)) /* P8 too */ +#define P7_SRR1_MC_IFETCH_UE_IFU_INTERNAL (0x7 << PPC_BITLSHIFT(45)) + +/* SRR1 bits for machine check (On Power8) */ +#define P8_SRR1_MC_IFETCH_ERAT_MULTIHIT (0x4 << PPC_BITLSHIFT(45)) + +/* DSISR bits for machine check (On Power7 and Power8) */ +#define P7_DSISR_MC_UE (PPC_BIT(48)) /* P8 too */ +#define P7_DSISR_MC_UE_TABLEWALK (PPC_BIT(49)) /* P8 too */ +#define P7_DSISR_MC_ERAT_MULTIHIT (PPC_BIT(52)) /* P8 too */ +#define P7_DSISR_MC_TLB_MULTIHIT_MFTLB (PPC_BIT(53)) /* P8 too */ +#define P7_DSISR_MC_SLB_PARITY_MFSLB (PPC_BIT(55)) /* P8 too */ +#define P7_DSISR_MC_SLB_MULTIHIT (PPC_BIT(56)) /* P8 too */ +#define P7_DSISR_MC_SLB_MULTIHIT_PARITY (PPC_BIT(57)) /* P8 too */ + +/* + * DSISR bits for machine check (Power8) in addition to above. + * Secondary DERAT Multihit + */ +#define P8_DSISR_MC_ERAT_MULTIHIT_SEC (PPC_BIT(54)) + +/* SLB error bits */ +#define P7_DSISR_MC_SLB_ERRORS (P7_DSISR_MC_ERAT_MULTIHIT | \ + P7_DSISR_MC_SLB_PARITY_MFSLB | \ + P7_DSISR_MC_SLB_MULTIHIT | \ + P7_DSISR_MC_SLB_MULTIHIT_PARITY) + +#define P8_DSISR_MC_SLB_ERRORS (P7_DSISR_MC_SLB_ERRORS | \ + P8_DSISR_MC_ERAT_MULTIHIT_SEC) +enum MCE_Version { + MCE_V1 = 1, +}; + +enum MCE_Severity { + MCE_SEV_NO_ERROR = 0, + MCE_SEV_WARNING = 1, + MCE_SEV_ERROR_SYNC = 2, + MCE_SEV_FATAL = 3, +}; + +enum MCE_Disposition { + MCE_DISPOSITION_RECOVERED = 0, + MCE_DISPOSITION_NOT_RECOVERED = 1, +}; + +enum MCE_Initiator { + MCE_INITIATOR_UNKNOWN = 0, + MCE_INITIATOR_CPU = 1, +}; + +enum MCE_ErrorType { + MCE_ERROR_TYPE_UNKNOWN = 0, + MCE_ERROR_TYPE_UE = 1, + MCE_ERROR_TYPE_SLB = 2, + MCE_ERROR_TYPE_ERAT = 3, + MCE_ERROR_TYPE_TLB = 4, +}; + +enum MCE_UeErrorType { + MCE_UE_ERROR_INDETERMINATE = 0, + MCE_UE_ERROR_IFETCH = 1, + MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH = 2, + MCE_UE_ERROR_LOAD_STORE = 3, + MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE = 4, +}; + +enum MCE_SlbErrorType { + MCE_SLB_ERROR_INDETERMINATE = 0, + MCE_SLB_ERROR_PARITY = 1, + MCE_SLB_ERROR_MULTIHIT = 2, +}; + +enum MCE_EratErrorType { + MCE_ERAT_ERROR_INDETERMINATE = 0, + MCE_ERAT_ERROR_PARITY = 1, + MCE_ERAT_ERROR_MULTIHIT = 2, +}; + +enum MCE_TlbErrorType { + MCE_TLB_ERROR_INDETERMINATE = 0, + MCE_TLB_ERROR_PARITY = 1, + MCE_TLB_ERROR_MULTIHIT = 2, +}; + +struct machine_check_event { + enum MCE_Version version:8; /* 0x00 */ + uint8_t in_use; /* 0x01 */ + enum MCE_Severity severity:8; /* 0x02 */ + enum MCE_Initiator initiator:8; /* 0x03 */ + enum MCE_ErrorType error_type:8; /* 0x04 */ + enum MCE_Disposition disposition:8; /* 0x05 */ + uint8_t reserved_1[2]; /* 0x06 */ + uint64_t gpr3; /* 0x08 */ + uint64_t srr0; /* 0x10 */ + uint64_t srr1; /* 0x18 */ + union { /* 0x20 */ + struct { + enum MCE_UeErrorType ue_error_type:8; + uint8_t effective_address_provided; + uint8_t physical_address_provided; + uint8_t reserved_1[5]; + uint64_t effective_address; + uint64_t physical_address; + uint8_t reserved_2[8]; + } ue_error; + + struct { + enum MCE_SlbErrorType slb_error_type:8; + uint8_t effective_address_provided; + uint8_t reserved_1[6]; + uint64_t effective_address; + uint8_t reserved_2[16]; + } slb_error; + + struct { + enum MCE_EratErrorType erat_error_type:8; + uint8_t effective_address_provided; + uint8_t reserved_1[6]; + uint64_t effective_address; + uint8_t reserved_2[16]; + } erat_error; + + struct { + enum MCE_TlbErrorType tlb_error_type:8; + uint8_t effective_address_provided; + uint8_t reserved_1[6]; + uint64_t effective_address; + uint8_t reserved_2[16]; + } tlb_error; + } u; +}; + +struct mce_error_info { + enum MCE_ErrorType error_type:8; + union { + enum MCE_UeErrorType ue_error_type:8; + enum MCE_SlbErrorType slb_error_type:8; + enum MCE_EratErrorType erat_error_type:8; + enum MCE_TlbErrorType tlb_error_type:8; + } u; + uint8_t reserved[2]; +}; + +#define MAX_MC_EVT 100 + +/* Release flags for get_mce_event() */ +#define MCE_EVENT_RELEASE true +#define MCE_EVENT_DONTRELEASE false + +extern void save_mce_event(struct pt_regs *regs, long handled, + struct mce_error_info *mce_err, uint64_t addr); +extern int get_mce_event(struct machine_check_event *mce, bool release); +extern void release_mce_event(void); +extern void machine_check_queue_event(void); +extern void machine_check_print_event_info(struct machine_check_event *evt); +extern uint64_t get_mce_fault_addr(struct machine_check_event *evt); + +#endif /* __ASM_PPC64_MCE_H__ */ diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h index 936db360790adc..89b785d1684673 100644 --- a/arch/powerpc/include/asm/mmu-book3e.h +++ b/arch/powerpc/include/asm/mmu-book3e.h @@ -286,8 +286,21 @@ static inline unsigned int mmu_psize_to_shift(unsigned int mmu_psize) extern int mmu_linear_psize; extern int mmu_vmemmap_psize; +struct tlb_core_data { + /* For software way selection, as on Freescale TLB1 */ + u8 esel_next, esel_max, esel_first; + + /* Per-core spinlock for e6500 TLB handlers (no tlbsrx.) */ + u8 lock; +}; + #ifdef CONFIG_PPC64 extern unsigned long linear_map_top; +extern int book3e_htw_mode; + +#define PPC_HTW_NONE 0 +#define PPC_HTW_IBM 1 +#define PPC_HTW_E6500 2 /* * 64-bit booke platforms don't load the tlb in the tlb miss handler code. diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index 691fd8aca939f8..f8d1d6dcf7db63 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -180,16 +180,17 @@ static inline void assert_pte_locked(struct mm_struct *mm, unsigned long addr) #define MMU_PAGE_64K_AP 3 /* "Admixed pages" (hash64 only) */ #define MMU_PAGE_256K 4 #define MMU_PAGE_1M 5 -#define MMU_PAGE_4M 6 -#define MMU_PAGE_8M 7 -#define MMU_PAGE_16M 8 -#define MMU_PAGE_64M 9 -#define MMU_PAGE_256M 10 -#define MMU_PAGE_1G 11 -#define MMU_PAGE_16G 12 -#define MMU_PAGE_64G 13 - -#define MMU_PAGE_COUNT 14 +#define MMU_PAGE_2M 6 +#define MMU_PAGE_4M 7 +#define MMU_PAGE_8M 8 +#define MMU_PAGE_16M 9 +#define MMU_PAGE_64M 10 +#define MMU_PAGE_256M 11 +#define MMU_PAGE_1G 12 +#define MMU_PAGE_16G 13 +#define MMU_PAGE_64G 14 + +#define MMU_PAGE_COUNT 15 #if defined(CONFIG_PPC_STD_MMU_64) /* 64-bit classic hash table MMU */ diff --git a/arch/powerpc/include/asm/mpc5121.h b/arch/powerpc/include/asm/mpc5121.h index 887d3d6133e351..4a69cd1d50410d 100644 --- a/arch/powerpc/include/asm/mpc5121.h +++ b/arch/powerpc/include/asm/mpc5121.h @@ -37,7 +37,12 @@ struct mpc512x_ccm { u32 cccr; /* CFM Clock Control Register */ u32 dccr; /* DIU Clock Control Register */ u32 mscan_ccr[4]; /* MSCAN Clock Control Registers */ - u8 res[0x98]; /* Reserved */ + u32 out_ccr[4]; /* OUT CLK Configure Registers */ + u32 rsv0[2]; /* Reserved */ + u32 scfr3; /* System Clock Frequency Register 3 */ + u32 rsv1[3]; /* Reserved */ + u32 spll_lock_cnt; /* System PLL Lock Counter */ + u8 res[0x6c]; /* Reserved */ }; /* diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 7bdcf340016c41..40157e2ca69144 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -33,6 +33,28 @@ struct opal_takeover_args { u64 rd_loc; /* r11 */ }; +/* + * SG entry + * + * WARNING: The current implementation requires each entry + * to represent a block that is 4k aligned *and* each block + * size except the last one in the list to be as well. + */ +struct opal_sg_entry { + void *data; + long length; +}; + +/* sg list */ +struct opal_sg_list { + unsigned long num_entries; + struct opal_sg_list *next; + struct opal_sg_entry entry[]; +}; + +/* We calculate number of sg entries based on PAGE_SIZE */ +#define SG_ENTRIES_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct opal_sg_entry)) + extern long opal_query_takeover(u64 *hal_size, u64 *hal_align); extern long opal_do_takeover(struct opal_takeover_args *args); @@ -132,6 +154,9 @@ extern int opal_enter_rtas(struct rtas_args *args, #define OPAL_FLASH_VALIDATE 76 #define OPAL_FLASH_MANAGE 77 #define OPAL_FLASH_UPDATE 78 +#define OPAL_GET_MSG 85 +#define OPAL_CHECK_ASYNC_COMPLETION 86 +#define OPAL_SYNC_HOST_REBOOT 87 #ifndef __ASSEMBLY__ @@ -211,7 +236,16 @@ enum OpalPendingState { OPAL_EVENT_ERROR_LOG = 0x40, OPAL_EVENT_EPOW = 0x80, OPAL_EVENT_LED_STATUS = 0x100, - OPAL_EVENT_PCI_ERROR = 0x200 + OPAL_EVENT_PCI_ERROR = 0x200, + OPAL_EVENT_MSG_PENDING = 0x800, +}; + +enum OpalMessageType { + OPAL_MSG_ASYNC_COMP = 0, + OPAL_MSG_MEM_ERR, + OPAL_MSG_EPOW, + OPAL_MSG_SHUTDOWN, + OPAL_MSG_TYPE_MAX, }; /* Machine check related definitions */ @@ -311,12 +345,16 @@ enum OpalMveEnableAction { OPAL_ENABLE_MVE = 1 }; -enum OpalPciResetAndReinitScope { +enum OpalPciResetScope { OPAL_PHB_COMPLETE = 1, OPAL_PCI_LINK = 2, OPAL_PHB_ERROR = 3, OPAL_PCI_HOT_RESET = 4, OPAL_PCI_FUNDAMENTAL_RESET = 5, OPAL_PCI_IODA_TABLE_RESET = 6, }; +enum OpalPciReinitScope { + OPAL_REINIT_PCI_DEV = 1000 +}; + enum OpalPciResetState { OPAL_DEASSERT_RESET = 0, OPAL_ASSERT_RESET = 1 @@ -356,6 +394,12 @@ enum OpalLPCAddressType { OPAL_LPC_FW = 2, }; +struct opal_msg { + uint32_t msg_type; + uint32_t reserved; + uint64_t params[8]; +}; + struct opal_machine_check_event { enum OpalMCE_Version version:8; /* 0x00 */ uint8_t in_use; /* 0x01 */ @@ -404,6 +448,58 @@ struct opal_machine_check_event { } u; }; +/* FSP memory errors handling */ +enum OpalMemErr_Version { + OpalMemErr_V1 = 1, +}; + +enum OpalMemErrType { + OPAL_MEM_ERR_TYPE_RESILIENCE = 0, + OPAL_MEM_ERR_TYPE_DYN_DALLOC, + OPAL_MEM_ERR_TYPE_SCRUB, +}; + +/* Memory Reilience error type */ +enum OpalMemErr_ResilErrType { + OPAL_MEM_RESILIENCE_CE = 0, + OPAL_MEM_RESILIENCE_UE, + OPAL_MEM_RESILIENCE_UE_SCRUB, +}; + +/* Dynamic Memory Deallocation type */ +enum OpalMemErr_DynErrType { + OPAL_MEM_DYNAMIC_DEALLOC = 0, +}; + +/* OpalMemoryErrorData->flags */ +#define OPAL_MEM_CORRECTED_ERROR 0x0001 +#define OPAL_MEM_THRESHOLD_EXCEEDED 0x0002 +#define OPAL_MEM_ACK_REQUIRED 0x8000 + +struct OpalMemoryErrorData { + enum OpalMemErr_Version version:8; /* 0x00 */ + enum OpalMemErrType type:8; /* 0x01 */ + uint16_t flags; /* 0x02 */ + uint8_t reserved_1[4]; /* 0x04 */ + + union { + /* Memory Resilience corrected/uncorrected error info */ + struct { + enum OpalMemErr_ResilErrType resil_err_type:8; + uint8_t reserved_1[7]; + uint64_t physical_address_start; + uint64_t physical_address_end; + } resilience; + /* Dynamic memory deallocation error info */ + struct { + enum OpalMemErr_DynErrType dyn_err_type:8; + uint8_t reserved_1[7]; + uint64_t physical_address_start; + uint64_t physical_address_end; + } dyn_dealloc; + } u; +}; + enum { OPAL_P7IOC_DIAG_TYPE_NONE = 0, OPAL_P7IOC_DIAG_TYPE_RGC = 1, @@ -710,7 +806,7 @@ int64_t opal_pci_get_phb_diag_data(uint64_t phb_id, void *diag_buffer, int64_t opal_pci_get_phb_diag_data2(uint64_t phb_id, void *diag_buffer, uint64_t diag_buffer_len); int64_t opal_pci_fence_phb(uint64_t phb_id); -int64_t opal_pci_reinit(uint64_t phb_id, uint8_t reinit_scope); +int64_t opal_pci_reinit(uint64_t phb_id, uint64_t reinit_scope, uint64_t data); int64_t opal_pci_mask_pe_error(uint64_t phb_id, uint16_t pe_number, uint8_t error_type, uint8_t mask_action); int64_t opal_set_slot_led_status(uint64_t phb_id, uint64_t slot_id, uint8_t led_type, uint8_t led_action); int64_t opal_get_epow_status(__be64 *status); @@ -731,6 +827,10 @@ int64_t opal_validate_flash(uint64_t buffer, uint32_t *size, uint32_t *result); int64_t opal_manage_flash(uint8_t op); int64_t opal_update_flash(uint64_t blk_list); +int64_t opal_get_msg(uint64_t buffer, size_t size); +int64_t opal_check_completion(uint64_t buffer, size_t size, uint64_t token); +int64_t opal_sync_host_reboot(void); + /* Internal functions */ extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data); @@ -744,6 +844,8 @@ extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data); extern int opal_notifier_register(struct notifier_block *nb); +extern int opal_message_notifier_register(enum OpalMessageType msg_type, + struct notifier_block *nb); extern void opal_notifier_enable(void); extern void opal_notifier_disable(void); extern void opal_notifier_update_evt(uint64_t evt_mask, uint64_t evt_val); diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index b6ea9e068c13dd..9c5dbc3833fbc6 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -16,7 +16,6 @@ #ifdef CONFIG_PPC64 -#include #include #include #include @@ -113,6 +112,10 @@ struct paca_struct { /* Keep pgd in the same cacheline as the start of extlb */ pgd_t *pgd __attribute__((aligned(0x80))); /* Current PGD */ pgd_t *kernel_pgd; /* Kernel PGD */ + + /* Shared by all threads of a core -- points to tcd of first thread */ + struct tlb_core_data *tcd_ptr; + /* We can have up to 3 levels of reentrancy in the TLB miss handler */ u64 extlb[3][EX_TLB_SIZE / sizeof(u64)]; u64 exmc[8]; /* used for machine checks */ @@ -123,6 +126,8 @@ struct paca_struct { void *mc_kstack; void *crit_kstack; void *dbg_kstack; + + struct tlb_core_data tcd; #endif /* CONFIG_PPC_BOOK3E */ mm_context_t context; @@ -152,6 +157,15 @@ struct paca_struct { */ struct opal_machine_check_event *opal_mc_evt; #endif +#ifdef CONFIG_PPC_BOOK3S_64 + /* Exclusive emergency stack pointer for machine check exception. */ + void *mc_emergency_sp; + /* + * Flag to check whether we are in machine check early handler + * and already using emergency stack. + */ + u16 in_mce; +#endif /* Stuff for accurate time accounting */ u64 user_time; /* accumulated usermode TB ticks */ diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h index 4a191c47286748..eb9261024f5192 100644 --- a/arch/powerpc/include/asm/pgtable-ppc64.h +++ b/arch/powerpc/include/asm/pgtable-ppc64.h @@ -195,6 +195,7 @@ extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr, static inline unsigned long pte_update(struct mm_struct *mm, unsigned long addr, pte_t *ptep, unsigned long clr, + unsigned long set, int huge) { #ifdef PTE_ATOMIC_UPDATES @@ -205,14 +206,15 @@ static inline unsigned long pte_update(struct mm_struct *mm, andi. %1,%0,%6\n\ bne- 1b \n\ andc %1,%0,%4 \n\ + or %1,%1,%7\n\ stdcx. %1,0,%3 \n\ bne- 1b" : "=&r" (old), "=&r" (tmp), "=m" (*ptep) - : "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY) + : "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY), "r" (set) : "cc" ); #else unsigned long old = pte_val(*ptep); - *ptep = __pte(old & ~clr); + *ptep = __pte((old & ~clr) | set); #endif /* huge pages use the old page table lock */ if (!huge) @@ -231,9 +233,9 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm, { unsigned long old; - if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0) + if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0) return 0; - old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0); + old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0, 0); return (old & _PAGE_ACCESSED) != 0; } #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG @@ -252,7 +254,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, if ((pte_val(*ptep) & _PAGE_RW) == 0) return; - pte_update(mm, addr, ptep, _PAGE_RW, 0); + pte_update(mm, addr, ptep, _PAGE_RW, 0, 0); } static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, @@ -261,7 +263,7 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, if ((pte_val(*ptep) & _PAGE_RW) == 0) return; - pte_update(mm, addr, ptep, _PAGE_RW, 1); + pte_update(mm, addr, ptep, _PAGE_RW, 0, 1); } /* @@ -284,14 +286,14 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0); + unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0, 0); return __pte(old); } static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t * ptep) { - pte_update(mm, addr, ptep, ~0UL, 0); + pte_update(mm, addr, ptep, ~0UL, 0, 0); } @@ -506,7 +508,9 @@ extern int pmdp_set_access_flags(struct vm_area_struct *vma, extern unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr, - pmd_t *pmdp, unsigned long clr); + pmd_t *pmdp, + unsigned long clr, + unsigned long set); static inline int __pmdp_test_and_clear_young(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp) @@ -515,7 +519,7 @@ static inline int __pmdp_test_and_clear_young(struct mm_struct *mm, if ((pmd_val(*pmdp) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0) return 0; - old = pmd_hugepage_update(mm, addr, pmdp, _PAGE_ACCESSED); + old = pmd_hugepage_update(mm, addr, pmdp, _PAGE_ACCESSED, 0); return ((old & _PAGE_ACCESSED) != 0); } @@ -542,7 +546,7 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, unsigned long addr, if ((pmd_val(*pmdp) & _PAGE_RW) == 0) return; - pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW); + pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW, 0); } #define __HAVE_ARCH_PMDP_SPLITTING_FLUSH @@ -558,5 +562,19 @@ extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp); #define __HAVE_ARCH_PMDP_INVALIDATE extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp); + +#define pmd_move_must_withdraw pmd_move_must_withdraw +struct spinlock; +static inline int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl, + struct spinlock *old_pmd_ptl) +{ + /* + * Archs like ppc64 use pgtable to store per pmd + * specific information. So when we switch the pmd, + * we should also withdraw and deposit the pgtable + */ + return true; +} + #endif /* __ASSEMBLY__ */ #endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */ diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h index 7d6eacf249cf42..3ebb188c3ff51a 100644 --- a/arch/powerpc/include/asm/pgtable.h +++ b/arch/powerpc/include/asm/pgtable.h @@ -3,6 +3,7 @@ #ifdef __KERNEL__ #ifndef __ASSEMBLY__ +#include #include /* For TASK_SIZE */ #include #include @@ -33,10 +34,95 @@ static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } static inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL; } -static inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; } static inline int pte_none(pte_t pte) { return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; } static inline pgprot_t pte_pgprot(pte_t pte) { return __pgprot(pte_val(pte) & PAGE_PROT_BITS); } +#ifdef CONFIG_NUMA_BALANCING + +static inline int pte_present(pte_t pte) +{ + return pte_val(pte) & (_PAGE_PRESENT | _PAGE_NUMA); +} + +#define pte_numa pte_numa +static inline int pte_numa(pte_t pte) +{ + return (pte_val(pte) & + (_PAGE_NUMA|_PAGE_PRESENT)) == _PAGE_NUMA; +} + +#define pte_mknonnuma pte_mknonnuma +static inline pte_t pte_mknonnuma(pte_t pte) +{ + pte_val(pte) &= ~_PAGE_NUMA; + pte_val(pte) |= _PAGE_PRESENT | _PAGE_ACCESSED; + return pte; +} + +#define pte_mknuma pte_mknuma +static inline pte_t pte_mknuma(pte_t pte) +{ + /* + * We should not set _PAGE_NUMA on non present ptes. Also clear the + * present bit so that hash_page will return 1 and we collect this + * as numa fault. + */ + if (pte_present(pte)) { + pte_val(pte) |= _PAGE_NUMA; + pte_val(pte) &= ~_PAGE_PRESENT; + } else + VM_BUG_ON(1); + return pte; +} + +#define ptep_set_numa ptep_set_numa +static inline void ptep_set_numa(struct mm_struct *mm, unsigned long addr, + pte_t *ptep) +{ + if ((pte_val(*ptep) & _PAGE_PRESENT) == 0) + VM_BUG_ON(1); + + pte_update(mm, addr, ptep, _PAGE_PRESENT, _PAGE_NUMA, 0); + return; +} + +#define pmd_numa pmd_numa +static inline int pmd_numa(pmd_t pmd) +{ + return pte_numa(pmd_pte(pmd)); +} + +#define pmdp_set_numa pmdp_set_numa +static inline void pmdp_set_numa(struct mm_struct *mm, unsigned long addr, + pmd_t *pmdp) +{ + if ((pmd_val(*pmdp) & _PAGE_PRESENT) == 0) + VM_BUG_ON(1); + + pmd_hugepage_update(mm, addr, pmdp, _PAGE_PRESENT, _PAGE_NUMA); + return; +} + +#define pmd_mknonnuma pmd_mknonnuma +static inline pmd_t pmd_mknonnuma(pmd_t pmd) +{ + return pte_pmd(pte_mknonnuma(pmd_pte(pmd))); +} + +#define pmd_mknuma pmd_mknuma +static inline pmd_t pmd_mknuma(pmd_t pmd) +{ + return pte_pmd(pte_mknuma(pmd_pte(pmd))); +} + +# else + +static inline int pte_present(pte_t pte) +{ + return pte_val(pte) & _PAGE_PRESENT; +} +#endif /* CONFIG_NUMA_BALANCING */ + /* Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. * @@ -223,6 +309,27 @@ extern int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr, #endif pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea, unsigned *shift); + +static inline pte_t *lookup_linux_ptep(pgd_t *pgdir, unsigned long hva, + unsigned long *pte_sizep) +{ + pte_t *ptep; + unsigned long ps = *pte_sizep; + unsigned int shift; + + ptep = find_linux_pte_or_hugepte(pgdir, hva, &shift); + if (!ptep) + return NULL; + if (shift) + *pte_sizep = 1ul << shift; + else + *pte_sizep = PAGE_SIZE; + + if (ps > *pte_sizep) + return NULL; + + return ptep; +} #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index f595b98079ee1e..6586a40a46ce16 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -4,7 +4,6 @@ #ifndef _ASM_POWERPC_PPC_ASM_H #define _ASM_POWERPC_PPC_ASM_H -#include #include #include #include @@ -295,6 +294,11 @@ GLUE(.,name): * you want to access various offsets within it). On ppc32 this is * identical to LOAD_REG_IMMEDIATE. * + * LOAD_REG_ADDR_PIC(rn, name) + * Loads the address of label 'name' into register 'run'. Use this when + * the kernel doesn't run at the linked or relocated address. Please + * note that this macro will clobber the lr register. + * * LOAD_REG_ADDRBASE(rn, name) * ADDROFF(name) * LOAD_REG_ADDRBASE loads part of the address of label 'name' into @@ -305,6 +309,14 @@ GLUE(.,name): * LOAD_REG_ADDRBASE(rX, name) * ld rY,ADDROFF(name)(rX) */ + +/* Be careful, this will clobber the lr register. */ +#define LOAD_REG_ADDR_PIC(reg, name) \ + bl 0f; \ +0: mflr reg; \ + addis reg,reg,(name - 0b)@ha; \ + addi reg,reg,(name - 0b)@l; + #ifdef __powerpc64__ #define LOAD_REG_IMMEDIATE(reg,expr) \ lis reg,(expr)@highest; \ diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index fc14a38c7ccffa..b62de43ae5f344 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -256,6 +256,8 @@ struct thread_struct { unsigned long evr[32]; /* upper 32-bits of SPE regs */ u64 acc; /* Accumulator */ unsigned long spefscr; /* SPE & eFP status */ + unsigned long spefscr_last; /* SPEFSCR value on last prctl + call or trap return */ int used_spe; /* set if process has used spe */ #endif /* CONFIG_SPE */ #ifdef CONFIG_PPC_TRANSACTIONAL_MEM @@ -317,7 +319,9 @@ struct thread_struct { (_ALIGN_UP(sizeof(init_thread_info), 16) + (unsigned long) &init_stack) #ifdef CONFIG_SPE -#define SPEFSCR_INIT .spefscr = SPEFSCR_FINVE | SPEFSCR_FDBZE | SPEFSCR_FUNFE | SPEFSCR_FOVFE, +#define SPEFSCR_INIT \ + .spefscr = SPEFSCR_FINVE | SPEFSCR_FDBZE | SPEFSCR_FUNFE | SPEFSCR_FOVFE, \ + .spefscr_last = SPEFSCR_FINVE | SPEFSCR_FDBZE | SPEFSCR_FUNFE | SPEFSCR_FOVFE, #else #define SPEFSCR_INIT #endif @@ -373,6 +377,8 @@ extern int set_endian(struct task_struct *tsk, unsigned int val); extern int get_unalign_ctl(struct task_struct *tsk, unsigned long adr); extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val); +extern void fp_enable(void); +extern void vec_enable(void); extern void load_fp_state(struct thread_fp_state *fp); extern void store_fp_state(struct thread_fp_state *fp); extern void load_vr_state(struct thread_vr_state *vr); @@ -444,13 +450,6 @@ enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF}; extern int powersave_nap; /* set if nap mode can be used in idle loop */ extern void power7_nap(void); - -#ifdef CONFIG_PSERIES_IDLE -extern void update_smt_snooze_delay(int cpu, int residency); -#else -static inline void update_smt_snooze_delay(int cpu, int residency) {} -#endif - extern void flush_instruction_cache(void); extern void hard_reset_now(void); extern void poweroff_now(void); diff --git a/arch/powerpc/include/asm/ps3.h b/arch/powerpc/include/asm/ps3.h index 678a7c1d9cb8ef..a1bc7e7584228a 100644 --- a/arch/powerpc/include/asm/ps3.h +++ b/arch/powerpc/include/asm/ps3.h @@ -21,7 +21,6 @@ #if !defined(_ASM_POWERPC_PS3_H) #define _ASM_POWERPC_PS3_H -#include #include #include #include diff --git a/arch/powerpc/include/asm/pte-hash64.h b/arch/powerpc/include/asm/pte-hash64.h index 0419eeb53274c6..2505d8eab15cb9 100644 --- a/arch/powerpc/include/asm/pte-hash64.h +++ b/arch/powerpc/include/asm/pte-hash64.h @@ -19,7 +19,7 @@ #define _PAGE_FILE 0x0002 /* (!present only) software: pte holds file offset */ #define _PAGE_EXEC 0x0004 /* No execute on POWER4 and newer (we invert) */ #define _PAGE_GUARDED 0x0008 -#define _PAGE_COHERENT 0x0010 /* M: enforce memory coherence (SMP systems) */ +/* We can derive Memory coherence from _PAGE_NO_CACHE */ #define _PAGE_NO_CACHE 0x0020 /* I: cache inhibit */ #define _PAGE_WRITETHRU 0x0040 /* W: cache write-through */ #define _PAGE_DIRTY 0x0080 /* C: page changed */ @@ -27,6 +27,12 @@ #define _PAGE_RW 0x0200 /* software: user write access allowed */ #define _PAGE_BUSY 0x0800 /* software: PTE & hash are busy */ +/* + * Used for tracking numa faults + */ +#define _PAGE_NUMA 0x00000010 /* Gather numa placement stats */ + + /* No separate kernel read-only */ #define _PAGE_KERNEL_RW (_PAGE_RW | _PAGE_DIRTY) /* user access blocked by key */ #define _PAGE_KERNEL_RO _PAGE_KERNEL_RW diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index fa8388ed94c52e..90c06ec6eff51d 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -223,17 +223,26 @@ #define CTRL_TE 0x00c00000 /* thread enable */ #define CTRL_RUNLATCH 0x1 #define SPRN_DAWR 0xB4 +#define SPRN_CIABR 0xBB +#define CIABR_PRIV 0x3 +#define CIABR_PRIV_USER 1 +#define CIABR_PRIV_SUPER 2 +#define CIABR_PRIV_HYPER 3 #define SPRN_DAWRX 0xBC -#define DAWRX_USER (1UL << 0) -#define DAWRX_KERNEL (1UL << 1) -#define DAWRX_HYP (1UL << 2) +#define DAWRX_USER __MASK(0) +#define DAWRX_KERNEL __MASK(1) +#define DAWRX_HYP __MASK(2) +#define DAWRX_WTI __MASK(3) +#define DAWRX_WT __MASK(4) +#define DAWRX_DR __MASK(5) +#define DAWRX_DW __MASK(6) #define SPRN_DABR 0x3F5 /* Data Address Breakpoint Register */ #define SPRN_DABR2 0x13D /* e300 */ #define SPRN_DABRX 0x3F7 /* Data Address Breakpoint Register Extension */ -#define DABRX_USER (1UL << 0) -#define DABRX_KERNEL (1UL << 1) -#define DABRX_HYP (1UL << 2) -#define DABRX_BTI (1UL << 3) +#define DABRX_USER __MASK(0) +#define DABRX_KERNEL __MASK(1) +#define DABRX_HYP __MASK(2) +#define DABRX_BTI __MASK(3) #define DABRX_ALL (DABRX_BTI | DABRX_HYP | DABRX_KERNEL | DABRX_USER) #define SPRN_DAR 0x013 /* Data Address Register */ #define SPRN_DBCR 0x136 /* e300 Data Breakpoint Control Reg */ @@ -260,6 +269,8 @@ #define SPRN_HRMOR 0x139 /* Real mode offset register */ #define SPRN_HSRR0 0x13A /* Hypervisor Save/Restore 0 */ #define SPRN_HSRR1 0x13B /* Hypervisor Save/Restore 1 */ +#define SPRN_IC 0x350 /* Virtual Instruction Count */ +#define SPRN_VTB 0x351 /* Virtual Time Base */ /* HFSCR and FSCR bit numbers are the same */ #define FSCR_TAR_LG 8 /* Enable Target Address Register */ #define FSCR_EBB_LG 7 /* Enable Event Based Branching */ @@ -298,9 +309,13 @@ #define LPCR_RMLS 0x1C000000 /* impl dependent rmo limit sel */ #define LPCR_RMLS_SH (63-37) #define LPCR_ILE 0x02000000 /* !HV irqs set MSR:LE */ +#define LPCR_AIL 0x01800000 /* Alternate interrupt location */ #define LPCR_AIL_0 0x00000000 /* MMU off exception offset 0x0 */ #define LPCR_AIL_3 0x01800000 /* MMU on exception offset 0xc00...4xxx */ -#define LPCR_PECE 0x00007000 /* powersave exit cause enable */ +#define LPCR_ONL 0x00040000 /* online - PURR/SPURR count */ +#define LPCR_PECE 0x0001f000 /* powersave exit cause enable */ +#define LPCR_PECEDP 0x00010000 /* directed priv dbells cause exit */ +#define LPCR_PECEDH 0x00008000 /* directed hyp dbells cause exit */ #define LPCR_PECE0 0x00004000 /* ext. exceptions can cause exit */ #define LPCR_PECE1 0x00002000 /* decrementer can cause exit */ #define LPCR_PECE2 0x00001000 /* machine check etc can cause exit */ @@ -322,6 +337,8 @@ #define SPRN_PCR 0x152 /* Processor compatibility register */ #define PCR_VEC_DIS (1ul << (63-0)) /* Vec. disable (bit NA since POWER8) */ #define PCR_VSX_DIS (1ul << (63-1)) /* VSX disable (bit NA since POWER8) */ +#define PCR_TM_DIS (1ul << (63-2)) /* Trans. memory disable (POWER8) */ +#define PCR_ARCH_206 0x4 /* Architecture 2.06 */ #define PCR_ARCH_205 0x2 /* Architecture 2.05 */ #define SPRN_HEIR 0x153 /* Hypervisor Emulated Instruction Register */ #define SPRN_TLBINDEXR 0x154 /* P7 TLB control register */ @@ -368,6 +385,8 @@ #define DER_EBRKE 0x00000002 /* External Breakpoint Interrupt */ #define DER_DPIE 0x00000001 /* Dev. Port Nonmaskable Request */ #define SPRN_DMISS 0x3D0 /* Data TLB Miss Register */ +#define SPRN_DHDES 0x0B1 /* Directed Hyp. Doorbell Exc. State */ +#define SPRN_DPDES 0x0B0 /* Directed Priv. Doorbell Exc. State */ #define SPRN_EAR 0x11A /* External Address Register */ #define SPRN_HASH1 0x3D2 /* Primary Hash Address Register */ #define SPRN_HASH2 0x3D3 /* Secondary Hash Address Resgister */ @@ -427,6 +446,7 @@ #define SPRN_IABR 0x3F2 /* Instruction Address Breakpoint Register */ #define SPRN_IABR2 0x3FA /* 83xx */ #define SPRN_IBCR 0x135 /* 83xx Insn Breakpoint Control Reg */ +#define SPRN_IAMR 0x03D /* Instr. Authority Mask Reg */ #define SPRN_HID4 0x3F4 /* 970 HID4 */ #define HID4_LPES0 (1ul << (63-0)) /* LPAR env. sel. bit 0 */ #define HID4_RMLS2_SH (63 - 2) /* Real mode limit bottom 2 bits */ @@ -541,6 +561,7 @@ #define SPRN_PIR 0x3FF /* Processor Identification Register */ #endif #define SPRN_TIR 0x1BE /* Thread Identification Register */ +#define SPRN_PSPB 0x09F /* Problem State Priority Boost reg */ #define SPRN_PTEHI 0x3D5 /* 981 7450 PTE HI word (S/W TLB load) */ #define SPRN_PTELO 0x3D6 /* 982 7450 PTE LO word (S/W TLB load) */ #define SPRN_PURR 0x135 /* Processor Utilization of Resources Reg */ @@ -682,6 +703,7 @@ #define SPRN_EBBHR 804 /* Event based branch handler register */ #define SPRN_EBBRR 805 /* Event based branch return register */ #define SPRN_BESCR 806 /* Branch event status and control register */ +#define SPRN_WORT 895 /* Workload optimization register - thread */ #define SPRN_PMC1 787 #define SPRN_PMC2 788 @@ -698,6 +720,11 @@ #define SIER_SIHV 0x1000000 /* Sampled MSR_HV */ #define SIER_SIAR_VALID 0x0400000 /* SIAR contents valid */ #define SIER_SDAR_VALID 0x0200000 /* SDAR contents valid */ +#define SPRN_TACR 888 +#define SPRN_TCSCR 889 +#define SPRN_CSIGR 890 +#define SPRN_SPMC1 892 +#define SPRN_SPMC2 893 /* When EBB is enabled, some of MMCR0/MMCR2/SIER are user accessible */ #define MMCR0_USER_MASK (MMCR0_FC | MMCR0_PMXE | MMCR0_PMAO) @@ -1075,6 +1102,8 @@ #define PVR_8560 0x80200000 #define PVR_VER_E500V1 0x8020 #define PVR_VER_E500V2 0x8021 +#define PVR_VER_E6500 0x8040 + /* * For the 8xx processors, all of them report the same PVR family for * the PowerPC core. The various versions of these processors must be diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h index 2e31aacd8accaf..163c3b05a76e9d 100644 --- a/arch/powerpc/include/asm/reg_booke.h +++ b/arch/powerpc/include/asm/reg_booke.h @@ -101,6 +101,7 @@ #define SPRN_IVOR39 0x1B1 /* Interrupt Vector Offset Register 39 */ #define SPRN_IVOR40 0x1B2 /* Interrupt Vector Offset Register 40 */ #define SPRN_IVOR41 0x1B3 /* Interrupt Vector Offset Register 41 */ +#define SPRN_IVOR42 0x1B4 /* Interrupt Vector Offset Register 42 */ #define SPRN_GIVOR2 0x1B8 /* Guest IVOR2 */ #define SPRN_GIVOR3 0x1B9 /* Guest IVOR3 */ #define SPRN_GIVOR4 0x1BA /* Guest IVOR4 */ @@ -170,6 +171,7 @@ #define SPRN_L2CSR1 0x3FA /* L2 Data Cache Control and Status Register 1 */ #define SPRN_DCCR 0x3FA /* Data Cache Cacheability Register */ #define SPRN_ICCR 0x3FB /* Instruction Cache Cacheability Register */ +#define SPRN_PWRMGTCR0 0x3FB /* Power management control register 0 */ #define SPRN_SVR 0x3FF /* System Version Register */ /* @@ -216,6 +218,14 @@ #define CCR1_DPC 0x00000100 /* Disable L1 I-Cache/D-Cache parity checking */ #define CCR1_TCS 0x00000080 /* Timer Clock Select */ +/* Bit definitions for PWRMGTCR0. */ +#define PWRMGTCR0_PW20_WAIT (1 << 14) /* PW20 state enable bit */ +#define PWRMGTCR0_PW20_ENT_SHIFT 8 +#define PWRMGTCR0_PW20_ENT 0x3F00 +#define PWRMGTCR0_AV_IDLE_PD_EN (1 << 22) /* Altivec idle enable */ +#define PWRMGTCR0_AV_IDLE_CNT_SHIFT 16 +#define PWRMGTCR0_AV_IDLE_CNT 0x3F0000 + /* Bit definitions for the MCSR. */ #define MCSR_MCS 0x80000000 /* Machine Check Summary */ #define MCSR_IB 0x40000000 /* Instruction PLB Error */ diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h index 4ee06fe15de41d..d0e784e0ff484f 100644 --- a/arch/powerpc/include/asm/sections.h +++ b/arch/powerpc/include/asm/sections.h @@ -8,6 +8,7 @@ #ifdef __powerpc64__ +extern char __start_interrupts[]; extern char __end_interrupts[]; extern char __prom_init_toc_start[]; @@ -21,6 +22,17 @@ static inline int in_kernel_text(unsigned long addr) return 0; } +static inline int overlaps_interrupt_vector_text(unsigned long start, + unsigned long end) +{ + unsigned long real_start, real_end; + real_start = __start_interrupts - _stext; + real_end = __end_interrupts - _stext; + + return start < (unsigned long)__va(real_end) && + (unsigned long)__va(real_start) < end; +} + static inline int overlaps_kernel_text(unsigned long start, unsigned long end) { return start < (unsigned long)__init_end && diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h index f6e78d63fb6acc..35aa339410bdae 100644 --- a/arch/powerpc/include/asm/spinlock.h +++ b/arch/powerpc/include/asm/spinlock.h @@ -30,8 +30,6 @@ #define smp_mb__after_unlock_lock() smp_mb() /* Full ordering for lock. */ -#define arch_spin_is_locked(x) ((x)->slock != 0) - #ifdef CONFIG_PPC64 /* use 0x800000yy when locked, where yy == CPU number */ #ifdef __BIG_ENDIAN__ @@ -56,6 +54,16 @@ #define SYNC_IO #endif +static __always_inline int arch_spin_value_unlocked(arch_spinlock_t lock) +{ + return lock.slock == 0; +} + +static inline int arch_spin_is_locked(arch_spinlock_t *lock) +{ + return !arch_spin_value_unlocked(*lock); +} + /* * This returns the old value in the lock, so we succeeded * in getting the lock if the return value is 0. diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h index aace90547614db..0e83e7d8c73f5d 100644 --- a/arch/powerpc/include/asm/switch_to.h +++ b/arch/powerpc/include/asm/switch_to.h @@ -25,10 +25,8 @@ static inline void save_tar(struct thread_struct *prev) static inline void save_tar(struct thread_struct *prev) {} #endif -extern void load_up_fpu(void); extern void enable_kernel_fp(void); extern void enable_kernel_altivec(void); -extern void load_up_altivec(struct task_struct *); extern int emulate_altivec(struct pt_regs *); extern void __giveup_vsx(struct task_struct *); extern void giveup_vsx(struct task_struct *); diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index 43523fe0d8b4c4..3ddf7027670642 100644 --- a/arch/powerpc/include/asm/systbl.h +++ b/arch/powerpc/include/asm/systbl.h @@ -359,3 +359,5 @@ COMPAT_SYS(process_vm_readv) COMPAT_SYS(process_vm_writev) SYSCALL(finit_module) SYSCALL(ni_syscall) /* sys_kcmp */ +SYSCALL_SPU(sched_setattr) +SYSCALL_SPU(sched_getattr) diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 9854c564ac525b..b034ecdb7c74f2 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -91,8 +91,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define TIF_32BIT 4 /* 32 bit binary */ -#define TIF_PERFMON_WORK 5 /* work for pfm_handle_work() */ -#define TIF_PERFMON_CTXSW 6 /* perfmon needs ctxsw calls */ +#define TIF_RESTORE_TM 5 /* need to restore TM FP/VEC/VSX */ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ #define TIF_SINGLESTEP 8 /* singlestepping active */ #define TIF_NOHZ 9 /* in adaptive nohz mode */ @@ -115,8 +114,7 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_NEED_RESCHED (1< -#define __NR_syscalls 355 +#define __NR_syscalls 357 #define __NR__exit __NR_exit #define NR_syscalls __NR_syscalls diff --git a/arch/powerpc/include/asm/vdso.h b/arch/powerpc/include/asm/vdso.h index 0d9cecddf8a4f5..c53f5f6d1761f7 100644 --- a/arch/powerpc/include/asm/vdso.h +++ b/arch/powerpc/include/asm/vdso.h @@ -4,11 +4,11 @@ #ifdef __KERNEL__ /* Default link addresses for the vDSOs */ -#define VDSO32_LBASE 0x100000 -#define VDSO64_LBASE 0x100000 +#define VDSO32_LBASE 0x0 +#define VDSO64_LBASE 0x0 /* Default map addresses for 32bit vDSO */ -#define VDSO32_MBASE VDSO32_LBASE +#define VDSO32_MBASE 0x100000 #define VDSO_VERSION_STRING LINUX_2.6.15 diff --git a/arch/powerpc/include/asm/vio.h b/arch/powerpc/include/asm/vio.h index 68d0cc998b1baa..4f9b7ca0710fc5 100644 --- a/arch/powerpc/include/asm/vio.h +++ b/arch/powerpc/include/asm/vio.h @@ -15,7 +15,6 @@ #define _ASM_POWERPC_VIO_H #ifdef __KERNEL__ -#include #include #include #include diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h index 6836ec79a8305a..a6665be4f3ab81 100644 --- a/arch/powerpc/include/uapi/asm/kvm.h +++ b/arch/powerpc/include/uapi/asm/kvm.h @@ -545,6 +545,7 @@ struct kvm_get_htab_header { #define KVM_REG_PPC_TCSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb1) #define KVM_REG_PPC_PID (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb2) #define KVM_REG_PPC_ACOP (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb3) +#define KVM_REG_PPC_WORT (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb4) #define KVM_REG_PPC_VRSAVE (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb4) #define KVM_REG_PPC_LPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb5) @@ -553,6 +554,8 @@ struct kvm_get_htab_header { /* Architecture compatibility level */ #define KVM_REG_PPC_ARCH_COMPAT (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb7) +#define KVM_REG_PPC_DABRX (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb8) + /* Transactional Memory checkpointed state: * This is all GPRs, all VSX regs and a subset of SPRs */ diff --git a/arch/powerpc/include/uapi/asm/tm.h b/arch/powerpc/include/uapi/asm/tm.h index 85059a00f560b1..5d836b7c117624 100644 --- a/arch/powerpc/include/uapi/asm/tm.h +++ b/arch/powerpc/include/uapi/asm/tm.h @@ -6,6 +6,8 @@ * the failure is persistent. PAPR saves 0xff-0xe0 for the hypervisor. */ #define TM_CAUSE_PERSISTENT 0x01 +#define TM_CAUSE_KVM_RESCHED 0xe0 /* From PAPR */ +#define TM_CAUSE_KVM_FAC_UNAV 0xe2 /* From PAPR */ #define TM_CAUSE_RESCHED 0xde #define TM_CAUSE_TLBI 0xdc #define TM_CAUSE_FAC_UNAV 0xda diff --git a/arch/powerpc/include/uapi/asm/unistd.h b/arch/powerpc/include/uapi/asm/unistd.h index 74cb4d72d6739b..881bf2e2560d40 100644 --- a/arch/powerpc/include/uapi/asm/unistd.h +++ b/arch/powerpc/include/uapi/asm/unistd.h @@ -377,6 +377,7 @@ #define __NR_process_vm_writev 352 #define __NR_finit_module 353 #define __NR_kcmp 354 - +#define __NR_sched_setattr 355 +#define __NR_sched_getattr 356 #endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 445cb6e39d5b0b..fcc9a89a469508 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \ obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power.o +obj-$(CONFIG_PPC_BOOK3S_64) += mce.o mce_power.o obj64-$(CONFIG_RELOCATABLE) += reloc_64.o obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o obj-$(CONFIG_PPC_A2) += cpu_setup_a2.o @@ -47,7 +48,6 @@ obj-$(CONFIG_ALTIVEC) += vecemu.o obj-$(CONFIG_PPC_970_NAP) += idle_power4.o obj-$(CONFIG_PPC_P7_NAP) += idle_power7.o obj-$(CONFIG_PPC_OF) += of_platform.o prom_parse.o -obj-$(CONFIG_PPC_CLOCK) += clock.o procfs-y := proc_powerpc.o obj-$(CONFIG_PROC_FS) += $(procfs-y) rtaspci-$(CONFIG_PPC64)-$(CONFIG_PCI) := rtas_pci.o diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index d3de01066f7dd7..b5aacf72ae6f5d 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -203,6 +203,15 @@ int main(void) DEFINE(PACA_MC_STACK, offsetof(struct paca_struct, mc_kstack)); DEFINE(PACA_CRIT_STACK, offsetof(struct paca_struct, crit_kstack)); DEFINE(PACA_DBG_STACK, offsetof(struct paca_struct, dbg_kstack)); + DEFINE(PACA_TCD_PTR, offsetof(struct paca_struct, tcd_ptr)); + + DEFINE(TCD_ESEL_NEXT, + offsetof(struct tlb_core_data, esel_next)); + DEFINE(TCD_ESEL_MAX, + offsetof(struct tlb_core_data, esel_max)); + DEFINE(TCD_ESEL_FIRST, + offsetof(struct tlb_core_data, esel_first)); + DEFINE(TCD_LOCK, offsetof(struct tlb_core_data, lock)); #endif /* CONFIG_PPC_BOOK3E */ #ifdef CONFIG_PPC_STD_MMU_64 @@ -232,6 +241,10 @@ int main(void) DEFINE(PACA_DTL_RIDX, offsetof(struct paca_struct, dtl_ridx)); #endif /* CONFIG_PPC_STD_MMU_64 */ DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp)); +#ifdef CONFIG_PPC_BOOK3S_64 + DEFINE(PACAMCEMERGSP, offsetof(struct paca_struct, mc_emergency_sp)); + DEFINE(PACA_IN_MCE, offsetof(struct paca_struct, in_mce)); +#endif DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id)); DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state)); DEFINE(PACA_STARTTIME, offsetof(struct paca_struct, starttime)); @@ -425,18 +438,14 @@ int main(void) DEFINE(VCPU_GUEST_PID, offsetof(struct kvm_vcpu, arch.pid)); DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr)); DEFINE(VCPU_VRSAVE, offsetof(struct kvm_vcpu, arch.vrsave)); - DEFINE(VCPU_FPRS, offsetof(struct kvm_vcpu, arch.fpr)); - DEFINE(VCPU_FPSCR, offsetof(struct kvm_vcpu, arch.fpscr)); + DEFINE(VCPU_FPRS, offsetof(struct kvm_vcpu, arch.fp.fpr)); #ifdef CONFIG_ALTIVEC - DEFINE(VCPU_VRS, offsetof(struct kvm_vcpu, arch.vr)); - DEFINE(VCPU_VSCR, offsetof(struct kvm_vcpu, arch.vscr)); -#endif -#ifdef CONFIG_VSX - DEFINE(VCPU_VSRS, offsetof(struct kvm_vcpu, arch.vsr)); + DEFINE(VCPU_VRS, offsetof(struct kvm_vcpu, arch.vr.vr)); #endif DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.xer)); DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.ctr)); DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr)); + DEFINE(VCPU_TAR, offsetof(struct kvm_vcpu, arch.tar)); DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr)); DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.pc)); #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE @@ -484,16 +493,24 @@ int main(void) DEFINE(VCPU_DAR, offsetof(struct kvm_vcpu, arch.shregs.dar)); DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa.pinned_addr)); DEFINE(VCPU_VPA_DIRTY, offsetof(struct kvm_vcpu, arch.vpa.dirty)); + DEFINE(VCPU_INTR_MSR, offsetof(struct kvm_vcpu, arch.intr_msr)); #endif #ifdef CONFIG_PPC_BOOK3S DEFINE(VCPU_VCPUID, offsetof(struct kvm_vcpu, vcpu_id)); DEFINE(VCPU_PURR, offsetof(struct kvm_vcpu, arch.purr)); DEFINE(VCPU_SPURR, offsetof(struct kvm_vcpu, arch.spurr)); + DEFINE(VCPU_IC, offsetof(struct kvm_vcpu, arch.ic)); + DEFINE(VCPU_VTB, offsetof(struct kvm_vcpu, arch.vtb)); DEFINE(VCPU_DSCR, offsetof(struct kvm_vcpu, arch.dscr)); DEFINE(VCPU_AMR, offsetof(struct kvm_vcpu, arch.amr)); DEFINE(VCPU_UAMOR, offsetof(struct kvm_vcpu, arch.uamor)); + DEFINE(VCPU_IAMR, offsetof(struct kvm_vcpu, arch.iamr)); DEFINE(VCPU_CTRL, offsetof(struct kvm_vcpu, arch.ctrl)); DEFINE(VCPU_DABR, offsetof(struct kvm_vcpu, arch.dabr)); + DEFINE(VCPU_DABRX, offsetof(struct kvm_vcpu, arch.dabrx)); + DEFINE(VCPU_DAWR, offsetof(struct kvm_vcpu, arch.dawr)); + DEFINE(VCPU_DAWRX, offsetof(struct kvm_vcpu, arch.dawrx)); + DEFINE(VCPU_CIABR, offsetof(struct kvm_vcpu, arch.ciabr)); DEFINE(VCPU_HFLAGS, offsetof(struct kvm_vcpu, arch.hflags)); DEFINE(VCPU_DEC, offsetof(struct kvm_vcpu, arch.dec)); DEFINE(VCPU_DEC_EXPIRES, offsetof(struct kvm_vcpu, arch.dec_expires)); @@ -502,8 +519,10 @@ int main(void) DEFINE(VCPU_PRODDED, offsetof(struct kvm_vcpu, arch.prodded)); DEFINE(VCPU_MMCR, offsetof(struct kvm_vcpu, arch.mmcr)); DEFINE(VCPU_PMC, offsetof(struct kvm_vcpu, arch.pmc)); + DEFINE(VCPU_SPMC, offsetof(struct kvm_vcpu, arch.spmc)); DEFINE(VCPU_SIAR, offsetof(struct kvm_vcpu, arch.siar)); DEFINE(VCPU_SDAR, offsetof(struct kvm_vcpu, arch.sdar)); + DEFINE(VCPU_SIER, offsetof(struct kvm_vcpu, arch.sier)); DEFINE(VCPU_SLB, offsetof(struct kvm_vcpu, arch.slb)); DEFINE(VCPU_SLB_MAX, offsetof(struct kvm_vcpu, arch.slb_max)); DEFINE(VCPU_SLB_NR, offsetof(struct kvm_vcpu, arch.slb_nr)); @@ -511,20 +530,47 @@ int main(void) DEFINE(VCPU_FAULT_DAR, offsetof(struct kvm_vcpu, arch.fault_dar)); DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst)); DEFINE(VCPU_TRAP, offsetof(struct kvm_vcpu, arch.trap)); - DEFINE(VCPU_PTID, offsetof(struct kvm_vcpu, arch.ptid)); DEFINE(VCPU_CFAR, offsetof(struct kvm_vcpu, arch.cfar)); DEFINE(VCPU_PPR, offsetof(struct kvm_vcpu, arch.ppr)); + DEFINE(VCPU_FSCR, offsetof(struct kvm_vcpu, arch.fscr)); + DEFINE(VCPU_PSPB, offsetof(struct kvm_vcpu, arch.pspb)); + DEFINE(VCPU_EBBHR, offsetof(struct kvm_vcpu, arch.ebbhr)); + DEFINE(VCPU_EBBRR, offsetof(struct kvm_vcpu, arch.ebbrr)); + DEFINE(VCPU_BESCR, offsetof(struct kvm_vcpu, arch.bescr)); + DEFINE(VCPU_CSIGR, offsetof(struct kvm_vcpu, arch.csigr)); + DEFINE(VCPU_TACR, offsetof(struct kvm_vcpu, arch.tacr)); + DEFINE(VCPU_TCSCR, offsetof(struct kvm_vcpu, arch.tcscr)); + DEFINE(VCPU_ACOP, offsetof(struct kvm_vcpu, arch.acop)); + DEFINE(VCPU_WORT, offsetof(struct kvm_vcpu, arch.wort)); DEFINE(VCPU_SHADOW_SRR1, offsetof(struct kvm_vcpu, arch.shadow_srr1)); DEFINE(VCORE_ENTRY_EXIT, offsetof(struct kvmppc_vcore, entry_exit_count)); DEFINE(VCORE_NAP_COUNT, offsetof(struct kvmppc_vcore, nap_count)); DEFINE(VCORE_IN_GUEST, offsetof(struct kvmppc_vcore, in_guest)); DEFINE(VCORE_NAPPING_THREADS, offsetof(struct kvmppc_vcore, napping_threads)); + DEFINE(VCORE_KVM, offsetof(struct kvmppc_vcore, kvm)); DEFINE(VCORE_TB_OFFSET, offsetof(struct kvmppc_vcore, tb_offset)); DEFINE(VCORE_LPCR, offsetof(struct kvmppc_vcore, lpcr)); DEFINE(VCORE_PCR, offsetof(struct kvmppc_vcore, pcr)); + DEFINE(VCORE_DPDES, offsetof(struct kvmppc_vcore, dpdes)); DEFINE(VCPU_SLB_E, offsetof(struct kvmppc_slb, orige)); DEFINE(VCPU_SLB_V, offsetof(struct kvmppc_slb, origv)); DEFINE(VCPU_SLB_SIZE, sizeof(struct kvmppc_slb)); +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + DEFINE(VCPU_TFHAR, offsetof(struct kvm_vcpu, arch.tfhar)); + DEFINE(VCPU_TFIAR, offsetof(struct kvm_vcpu, arch.tfiar)); + DEFINE(VCPU_TEXASR, offsetof(struct kvm_vcpu, arch.texasr)); + DEFINE(VCPU_GPR_TM, offsetof(struct kvm_vcpu, arch.gpr_tm)); + DEFINE(VCPU_FPRS_TM, offsetof(struct kvm_vcpu, arch.fp_tm.fpr)); + DEFINE(VCPU_VRS_TM, offsetof(struct kvm_vcpu, arch.vr_tm.vr)); + DEFINE(VCPU_VRSAVE_TM, offsetof(struct kvm_vcpu, arch.vrsave_tm)); + DEFINE(VCPU_CR_TM, offsetof(struct kvm_vcpu, arch.cr_tm)); + DEFINE(VCPU_LR_TM, offsetof(struct kvm_vcpu, arch.lr_tm)); + DEFINE(VCPU_CTR_TM, offsetof(struct kvm_vcpu, arch.ctr_tm)); + DEFINE(VCPU_AMR_TM, offsetof(struct kvm_vcpu, arch.amr_tm)); + DEFINE(VCPU_PPR_TM, offsetof(struct kvm_vcpu, arch.ppr_tm)); + DEFINE(VCPU_DSCR_TM, offsetof(struct kvm_vcpu, arch.dscr_tm)); + DEFINE(VCPU_TAR_TM, offsetof(struct kvm_vcpu, arch.tar_tm)); +#endif #ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE @@ -589,6 +635,7 @@ int main(void) HSTATE_FIELD(HSTATE_XICS_PHYS, xics_phys); HSTATE_FIELD(HSTATE_SAVED_XIRR, saved_xirr); HSTATE_FIELD(HSTATE_HOST_IPI, host_ipi); + HSTATE_FIELD(HSTATE_PTID, ptid); HSTATE_FIELD(HSTATE_MMCR, host_mmcr); HSTATE_FIELD(HSTATE_PMC, host_pmc); HSTATE_FIELD(HSTATE_PURR, host_purr); diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c index 654932727873da..2912b8787aa46b 100644 --- a/arch/powerpc/kernel/cacheinfo.c +++ b/arch/powerpc/kernel/cacheinfo.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -794,6 +793,9 @@ static void remove_cache_dir(struct cache_dir *cache_dir) { remove_index_dirs(cache_dir); + /* Remove cache dir from sysfs */ + kobject_del(cache_dir->kobj); + kobject_put(cache_dir->kobj); kfree(cache_dir); diff --git a/arch/powerpc/kernel/clock.c b/arch/powerpc/kernel/clock.c deleted file mode 100644 index a764b47791e858..00000000000000 --- a/arch/powerpc/kernel/clock.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Dummy clk implementations for powerpc. - * These need to be overridden in platform code. - */ - -#include -#include -#include -#include -#include - -struct clk_interface clk_functions; - -struct clk *clk_get(struct device *dev, const char *id) -{ - if (clk_functions.clk_get) - return clk_functions.clk_get(dev, id); - return ERR_PTR(-ENOSYS); -} -EXPORT_SYMBOL(clk_get); - -void clk_put(struct clk *clk) -{ - if (clk_functions.clk_put) - clk_functions.clk_put(clk); -} -EXPORT_SYMBOL(clk_put); - -int clk_enable(struct clk *clk) -{ - if (clk_functions.clk_enable) - return clk_functions.clk_enable(clk); - return -ENOSYS; -} -EXPORT_SYMBOL(clk_enable); - -void clk_disable(struct clk *clk) -{ - if (clk_functions.clk_disable) - clk_functions.clk_disable(clk); -} -EXPORT_SYMBOL(clk_disable); - -unsigned long clk_get_rate(struct clk *clk) -{ - if (clk_functions.clk_get_rate) - return clk_functions.clk_get_rate(clk); - return 0; -} -EXPORT_SYMBOL(clk_get_rate); - -long clk_round_rate(struct clk *clk, unsigned long rate) -{ - if (clk_functions.clk_round_rate) - return clk_functions.clk_round_rate(clk, rate); - return -ENOSYS; -} -EXPORT_SYMBOL(clk_round_rate); - -int clk_set_rate(struct clk *clk, unsigned long rate) -{ - if (clk_functions.clk_set_rate) - return clk_functions.clk_set_rate(clk, rate); - return -ENOSYS; -} -EXPORT_SYMBOL(clk_set_rate); - -struct clk *clk_get_parent(struct clk *clk) -{ - if (clk_functions.clk_get_parent) - return clk_functions.clk_get_parent(clk); - return ERR_PTR(-ENOSYS); -} -EXPORT_SYMBOL(clk_get_parent); - -int clk_set_parent(struct clk *clk, struct clk *parent) -{ - if (clk_functions.clk_set_parent) - return clk_functions.clk_set_parent(clk, parent); - return -ENOSYS; -} -EXPORT_SYMBOL(clk_set_parent); diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S index bfb18c7290b7a1..cc2d8962e0906b 100644 --- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S @@ -53,11 +53,57 @@ _GLOBAL(__e500_dcache_setup) isync blr +/* + * FIXME - we haven't yet done testing to determine a reasonable default + * value for PW20_WAIT_IDLE_BIT. + */ +#define PW20_WAIT_IDLE_BIT 50 /* 1ms, TB frequency is 41.66MHZ */ +_GLOBAL(setup_pw20_idle) + mfspr r3, SPRN_PWRMGTCR0 + + /* Set PW20_WAIT bit, enable pw20 state*/ + ori r3, r3, PWRMGTCR0_PW20_WAIT + li r11, PW20_WAIT_IDLE_BIT + + /* Set Automatic PW20 Core Idle Count */ + rlwimi r3, r11, PWRMGTCR0_PW20_ENT_SHIFT, PWRMGTCR0_PW20_ENT + + mtspr SPRN_PWRMGTCR0, r3 + + blr + +/* + * FIXME - we haven't yet done testing to determine a reasonable default + * value for AV_WAIT_IDLE_BIT. + */ +#define AV_WAIT_IDLE_BIT 50 /* 1ms, TB frequency is 41.66MHZ */ +_GLOBAL(setup_altivec_idle) + mfspr r3, SPRN_PWRMGTCR0 + + /* Enable Altivec Idle */ + oris r3, r3, PWRMGTCR0_AV_IDLE_PD_EN@h + li r11, AV_WAIT_IDLE_BIT + + /* Set Automatic AltiVec Idle Count */ + rlwimi r3, r11, PWRMGTCR0_AV_IDLE_CNT_SHIFT, PWRMGTCR0_AV_IDLE_CNT + + mtspr SPRN_PWRMGTCR0, r3 + + blr + _GLOBAL(__setup_cpu_e6500) mflr r6 #ifdef CONFIG_PPC64 bl .setup_altivec_ivors + /* Touch IVOR42 only if the CPU supports E.HV category */ + mfspr r10,SPRN_MMUCFG + rlwinm. r10,r10,0,MMUCFG_LPIDSIZE + beq 1f + bl .setup_lrat_ivor +1: #endif + bl setup_pw20_idle + bl setup_altivec_idle bl __setup_cpu_e5500 mtlr r6 blr @@ -119,6 +165,14 @@ _GLOBAL(__setup_cpu_e5500) _GLOBAL(__restore_cpu_e6500) mflr r5 bl .setup_altivec_ivors + /* Touch IVOR42 only if the CPU supports E.HV category */ + mfspr r10,SPRN_MMUCFG + rlwinm. r10,r10,0,MMUCFG_LPIDSIZE + beq 1f + bl .setup_lrat_ivor +1: + bl .setup_pw20_idle + bl .setup_altivec_idle bl __restore_cpu_e5500 mtlr r5 blr diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S index 18b5b9cf8e3730..37d1bb002aa97b 100644 --- a/arch/powerpc/kernel/cpu_setup_power.S +++ b/arch/powerpc/kernel/cpu_setup_power.S @@ -29,7 +29,7 @@ _GLOBAL(__setup_cpu_power7) mtspr SPRN_LPID,r0 mfspr r3,SPRN_LPCR bl __init_LPCR - bl __init_TLB + bl __init_tlb_power7 mtlr r11 blr @@ -42,7 +42,7 @@ _GLOBAL(__restore_cpu_power7) mtspr SPRN_LPID,r0 mfspr r3,SPRN_LPCR bl __init_LPCR - bl __init_TLB + bl __init_tlb_power7 mtlr r11 blr @@ -59,7 +59,7 @@ _GLOBAL(__setup_cpu_power8) oris r3, r3, LPCR_AIL_3@h bl __init_LPCR bl __init_HFSCR - bl __init_TLB + bl __init_tlb_power8 bl __init_PMU_HV mtlr r11 blr @@ -78,7 +78,7 @@ _GLOBAL(__restore_cpu_power8) oris r3, r3, LPCR_AIL_3@h bl __init_LPCR bl __init_HFSCR - bl __init_TLB + bl __init_tlb_power8 bl __init_PMU_HV mtlr r11 blr @@ -134,15 +134,31 @@ __init_HFSCR: mtspr SPRN_HFSCR,r3 blr -__init_TLB: - /* - * Clear the TLB using the "IS 3" form of tlbiel instruction - * (invalidate by congruence class). P7 has 128 CCs, P8 has 512 - * so we just always do 512 - */ +/* + * Clear the TLB using the specified IS form of tlbiel instruction + * (invalidate by congruence class). P7 has 128 CCs., P8 has 512. + * + * r3 = IS field + */ +__init_tlb_power7: + li r3,0xc00 /* IS field = 0b11 */ +_GLOBAL(__flush_tlb_power7) + li r6,128 + mtctr r6 + mr r7,r3 /* IS field */ + ptesync +2: tlbiel r7 + addi r7,r7,0x1000 + bdnz 2b + ptesync +1: blr + +__init_tlb_power8: + li r3,0xc00 /* IS field = 0b11 */ +_GLOBAL(__flush_tlb_power8) li r6,512 mtctr r6 - li r7,0xc00 /* IS field = 0b11 */ + mr r7,r3 /* IS field */ ptesync 2: tlbiel r7 addi r7,r7,0x1000 diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 597d954e58601b..6c8dd5da4de5ea 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -71,6 +71,10 @@ extern void __restore_cpu_power7(void); extern void __setup_cpu_power8(unsigned long offset, struct cpu_spec* spec); extern void __restore_cpu_power8(void); extern void __restore_cpu_a2(void); +extern void __flush_tlb_power7(unsigned long inval_selector); +extern void __flush_tlb_power8(unsigned long inval_selector); +extern long __machine_check_early_realmode_p7(struct pt_regs *regs); +extern long __machine_check_early_realmode_p8(struct pt_regs *regs); #endif /* CONFIG_PPC64 */ #if defined(CONFIG_E500) extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec); @@ -440,6 +444,8 @@ static struct cpu_spec __initdata cpu_specs[] = { .oprofile_cpu_type = "ppc64/ibm-compat-v1", .cpu_setup = __setup_cpu_power7, .cpu_restore = __restore_cpu_power7, + .flush_tlb = __flush_tlb_power7, + .machine_check_early = __machine_check_early_realmode_p7, .platform = "power7", }, { /* 2.07-compliant processor, i.e. Power8 "architected" mode */ @@ -456,6 +462,8 @@ static struct cpu_spec __initdata cpu_specs[] = { .oprofile_cpu_type = "ppc64/ibm-compat-v1", .cpu_setup = __setup_cpu_power8, .cpu_restore = __restore_cpu_power8, + .flush_tlb = __flush_tlb_power8, + .machine_check_early = __machine_check_early_realmode_p8, .platform = "power8", }, { /* Power7 */ @@ -474,6 +482,8 @@ static struct cpu_spec __initdata cpu_specs[] = { .oprofile_type = PPC_OPROFILE_POWER4, .cpu_setup = __setup_cpu_power7, .cpu_restore = __restore_cpu_power7, + .flush_tlb = __flush_tlb_power7, + .machine_check_early = __machine_check_early_realmode_p7, .platform = "power7", }, { /* Power7+ */ @@ -492,6 +502,8 @@ static struct cpu_spec __initdata cpu_specs[] = { .oprofile_type = PPC_OPROFILE_POWER4, .cpu_setup = __setup_cpu_power7, .cpu_restore = __restore_cpu_power7, + .flush_tlb = __flush_tlb_power7, + .machine_check_early = __machine_check_early_realmode_p7, .platform = "power7+", }, { /* Power8E */ @@ -510,6 +522,8 @@ static struct cpu_spec __initdata cpu_specs[] = { .oprofile_type = PPC_OPROFILE_INVALID, .cpu_setup = __setup_cpu_power8, .cpu_restore = __restore_cpu_power8, + .flush_tlb = __flush_tlb_power8, + .machine_check_early = __machine_check_early_realmode_p8, .platform = "power8", }, { /* Power8 */ @@ -528,6 +542,8 @@ static struct cpu_spec __initdata cpu_specs[] = { .oprofile_type = PPC_OPROFILE_INVALID, .cpu_setup = __setup_cpu_power8, .cpu_restore = __restore_cpu_power8, + .flush_tlb = __flush_tlb_power8, + .machine_check_early = __machine_check_early_realmode_p8, .platform = "power8", }, { /* Cell Broadband Engine */ diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index fdcd8f551affe3..18d7c80ddeb98c 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c index e4897523de41e4..54d0116256f752 100644 --- a/arch/powerpc/kernel/dma-iommu.c +++ b/arch/powerpc/kernel/dma-iommu.c @@ -83,10 +83,10 @@ static int dma_iommu_dma_supported(struct device *dev, u64 mask) return 0; } - if (tbl->it_offset > (mask >> IOMMU_PAGE_SHIFT)) { + if (tbl->it_offset > (mask >> tbl->it_page_shift)) { dev_info(dev, "Warning: IOMMU offset too big for device mask\n"); dev_info(dev, "mask: 0x%08llx, table offset: 0x%08lx\n", - mask, tbl->it_offset << IOMMU_PAGE_SHIFT); + mask, tbl->it_offset << tbl->it_page_shift); return 0; } else return 1; diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c index 8032b97ccdcb66..ee78f6e49d64bd 100644 --- a/arch/powerpc/kernel/dma.c +++ b/arch/powerpc/kernel/dma.c @@ -191,12 +191,10 @@ EXPORT_SYMBOL(dma_direct_ops); #define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16) -int dma_set_mask(struct device *dev, u64 dma_mask) +int __dma_set_mask(struct device *dev, u64 dma_mask) { struct dma_map_ops *dma_ops = get_dma_ops(dev); - if (ppc_md.dma_set_mask) - return ppc_md.dma_set_mask(dev, dma_mask); if ((dma_ops != NULL) && (dma_ops->set_dma_mask != NULL)) return dma_ops->set_dma_mask(dev, dma_mask); if (!dev->dma_mask || !dma_supported(dev, dma_mask)) @@ -204,6 +202,12 @@ int dma_set_mask(struct device *dev, u64 dma_mask) *dev->dma_mask = dma_mask; return 0; } +int dma_set_mask(struct device *dev, u64 dma_mask) +{ + if (ppc_md.dma_set_mask) + return ppc_md.dma_set_mask(dev, dma_mask); + return __dma_set_mask(dev, dma_mask); +} EXPORT_SYMBOL(dma_set_mask); u64 dma_get_required_mask(struct device *dev) diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 4bd687d5e7aa3f..e7b76a6bf15083 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -84,12 +85,12 @@ #define EEH_MAX_FAILS 2100000 /* Time to wait for a PCI slot to report status, in milliseconds */ -#define PCI_BUS_RESET_WAIT_MSEC (60*1000) +#define PCI_BUS_RESET_WAIT_MSEC (5*60*1000) /* Platform dependent EEH operations */ struct eeh_ops *eeh_ops = NULL; -int eeh_subsystem_enabled; +bool eeh_subsystem_enabled = false; EXPORT_SYMBOL(eeh_subsystem_enabled); /* @@ -364,7 +365,7 @@ int eeh_dev_check_failure(struct eeh_dev *edev) eeh_stats.total_mmio_ffs++; - if (!eeh_subsystem_enabled) + if (!eeh_enabled()) return 0; if (!edev) { @@ -747,6 +748,17 @@ int __exit eeh_ops_unregister(const char *name) return -EEXIST; } +static int eeh_reboot_notifier(struct notifier_block *nb, + unsigned long action, void *unused) +{ + eeh_set_enable(false); + return NOTIFY_DONE; +} + +static struct notifier_block eeh_reboot_nb = { + .notifier_call = eeh_reboot_notifier, +}; + /** * eeh_init - EEH initialization * @@ -778,6 +790,14 @@ int eeh_init(void) if (machine_is(powernv) && cnt++ <= 0) return ret; + /* Register reboot notifier */ + ret = register_reboot_notifier(&eeh_reboot_nb); + if (ret) { + pr_warn("%s: Failed to register notifier (%d)\n", + __func__, ret); + return ret; + } + /* call platform initialization function */ if (!eeh_ops) { pr_warning("%s: Platform EEH operation not found\n", @@ -822,7 +842,7 @@ int eeh_init(void) return ret; } - if (eeh_subsystem_enabled) + if (eeh_enabled()) pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n"); else pr_warning("EEH: No capable adapters found\n"); @@ -897,7 +917,7 @@ void eeh_add_device_late(struct pci_dev *dev) struct device_node *dn; struct eeh_dev *edev; - if (!dev || !eeh_subsystem_enabled) + if (!dev || !eeh_enabled()) return; pr_debug("EEH: Adding device %s\n", pci_name(dev)); @@ -921,6 +941,13 @@ void eeh_add_device_late(struct pci_dev *dev) eeh_sysfs_remove_device(edev->pdev); edev->mode &= ~EEH_DEV_SYSFS; + /* + * We definitely should have the PCI device removed + * though it wasn't correctly. So we needn't call + * into error handler afterwards. + */ + edev->mode |= EEH_DEV_NO_HANDLER; + edev->pdev = NULL; dev->dev.archdata.edev = NULL; } @@ -998,7 +1025,7 @@ void eeh_remove_device(struct pci_dev *dev) { struct eeh_dev *edev; - if (!dev || !eeh_subsystem_enabled) + if (!dev || !eeh_enabled()) return; edev = pci_dev_to_eeh_dev(dev); @@ -1023,6 +1050,14 @@ void eeh_remove_device(struct pci_dev *dev) else edev->mode |= EEH_DEV_DISCONNECTED; + /* + * We're removing from the PCI subsystem, that means + * the PCI device driver can't support EEH or not + * well. So we rely on hotplug completely to do recovery + * for the specific PCI device. + */ + edev->mode |= EEH_DEV_NO_HANDLER; + eeh_addr_cache_rmv_dev(dev); eeh_sysfs_remove_device(dev); edev->mode &= ~EEH_DEV_SYSFS; @@ -1030,7 +1065,7 @@ void eeh_remove_device(struct pci_dev *dev) static int proc_eeh_show(struct seq_file *m, void *v) { - if (0 == eeh_subsystem_enabled) { + if (!eeh_enabled()) { seq_printf(m, "EEH Subsystem is globally disabled\n"); seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs); } else { diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index c17f90d0f73c62..fdc679d309ec4c 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -217,7 +217,8 @@ static void *eeh_report_mmio_enabled(void *data, void *userdata) if (!driver) return NULL; if (!driver->err_handler || - !driver->err_handler->mmio_enabled) { + !driver->err_handler->mmio_enabled || + (edev->mode & EEH_DEV_NO_HANDLER)) { eeh_pcid_put(dev); return NULL; } @@ -258,7 +259,8 @@ static void *eeh_report_reset(void *data, void *userdata) eeh_enable_irq(dev); if (!driver->err_handler || - !driver->err_handler->slot_reset) { + !driver->err_handler->slot_reset || + (edev->mode & EEH_DEV_NO_HANDLER)) { eeh_pcid_put(dev); return NULL; } @@ -297,7 +299,9 @@ static void *eeh_report_resume(void *data, void *userdata) eeh_enable_irq(dev); if (!driver->err_handler || - !driver->err_handler->resume) { + !driver->err_handler->resume || + (edev->mode & EEH_DEV_NO_HANDLER)) { + edev->mode &= ~EEH_DEV_NO_HANDLER; eeh_pcid_put(dev); return NULL; } @@ -358,9 +362,13 @@ static void *eeh_rmv_device(void *data, void *userdata) */ if (!dev || (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)) return NULL; + driver = eeh_pcid_get(dev); - if (driver && driver->err_handler) - return NULL; + if (driver) { + eeh_pcid_put(dev); + if (driver->err_handler) + return NULL; + } /* Remove it from PCI subsystem */ pr_debug("EEH: Removing %s without EEH sensitive driver\n", @@ -476,7 +484,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) /* The longest amount of time to wait for a pci device * to come back on line, in seconds. */ -#define MAX_WAIT_FOR_RECOVERY 150 +#define MAX_WAIT_FOR_RECOVERY 300 static void eeh_handle_normal_event(struct eeh_pe *pe) { @@ -637,86 +645,92 @@ static void eeh_handle_special_event(void) { struct eeh_pe *pe, *phb_pe; struct pci_bus *bus; - struct pci_controller *hose, *tmp; + struct pci_controller *hose; unsigned long flags; - int rc = 0; + int rc; - /* - * The return value from next_error() has been classified as follows. - * It might be good to enumerate them. However, next_error() is only - * supported by PowerNV platform for now. So it would be fine to use - * integer directly: - * - * 4 - Dead IOC 3 - Dead PHB - * 2 - Fenced PHB 1 - Frozen PE - * 0 - No error found - * - */ - rc = eeh_ops->next_error(&pe); - if (rc <= 0) - return; - switch (rc) { - case 4: - /* Mark all PHBs in dead state */ - eeh_serialize_lock(&flags); - list_for_each_entry_safe(hose, tmp, - &hose_list, list_node) { - phb_pe = eeh_phb_pe_get(hose); - if (!phb_pe) continue; - - eeh_pe_state_mark(phb_pe, - EEH_PE_ISOLATED | EEH_PE_PHB_DEAD); + do { + rc = eeh_ops->next_error(&pe); + + switch (rc) { + case EEH_NEXT_ERR_DEAD_IOC: + /* Mark all PHBs in dead state */ + eeh_serialize_lock(&flags); + + /* Purge all events */ + eeh_remove_event(NULL); + + list_for_each_entry(hose, &hose_list, list_node) { + phb_pe = eeh_phb_pe_get(hose); + if (!phb_pe) continue; + + eeh_pe_state_mark(phb_pe, + EEH_PE_ISOLATED | EEH_PE_PHB_DEAD); + } + + eeh_serialize_unlock(flags); + + break; + case EEH_NEXT_ERR_FROZEN_PE: + case EEH_NEXT_ERR_FENCED_PHB: + case EEH_NEXT_ERR_DEAD_PHB: + /* Mark the PE in fenced state */ + eeh_serialize_lock(&flags); + + /* Purge all events of the PHB */ + eeh_remove_event(pe); + + if (rc == EEH_NEXT_ERR_DEAD_PHB) + eeh_pe_state_mark(pe, + EEH_PE_ISOLATED | EEH_PE_PHB_DEAD); + else + eeh_pe_state_mark(pe, + EEH_PE_ISOLATED | EEH_PE_RECOVERING); + + eeh_serialize_unlock(flags); + + break; + case EEH_NEXT_ERR_NONE: + return; + default: + pr_warn("%s: Invalid value %d from next_error()\n", + __func__, rc); + return; } - eeh_serialize_unlock(flags); - - /* Purge all events */ - eeh_remove_event(NULL); - break; - case 3: - case 2: - case 1: - /* Mark the PE in fenced state */ - eeh_serialize_lock(&flags); - if (rc == 3) - eeh_pe_state_mark(pe, - EEH_PE_ISOLATED | EEH_PE_PHB_DEAD); - else - eeh_pe_state_mark(pe, - EEH_PE_ISOLATED | EEH_PE_RECOVERING); - eeh_serialize_unlock(flags); - - /* Purge all events of the PHB */ - eeh_remove_event(pe); - break; - default: - pr_err("%s: Invalid value %d from next_error()\n", - __func__, rc); - return; - } - /* - * For fenced PHB and frozen PE, it's handled as normal - * event. We have to remove the affected PHBs for dead - * PHB and IOC - */ - if (rc == 2 || rc == 1) - eeh_handle_normal_event(pe); - else { - pci_lock_rescan_remove(); - list_for_each_entry_safe(hose, tmp, - &hose_list, list_node) { - phb_pe = eeh_phb_pe_get(hose); - if (!phb_pe || !(phb_pe->state & EEH_PE_PHB_DEAD)) - continue; - - bus = eeh_pe_bus_get(phb_pe); - /* Notify all devices that they're about to go down. */ - eeh_pe_dev_traverse(pe, eeh_report_failure, NULL); - pcibios_remove_pci_devices(bus); + /* + * For fenced PHB and frozen PE, it's handled as normal + * event. We have to remove the affected PHBs for dead + * PHB and IOC + */ + if (rc == EEH_NEXT_ERR_FROZEN_PE || + rc == EEH_NEXT_ERR_FENCED_PHB) { + eeh_handle_normal_event(pe); + } else { + pci_lock_rescan_remove(); + list_for_each_entry(hose, &hose_list, list_node) { + phb_pe = eeh_phb_pe_get(hose); + if (!phb_pe || + !(phb_pe->state & EEH_PE_PHB_DEAD)) + continue; + + /* Notify all devices to be down */ + bus = eeh_pe_bus_get(phb_pe); + eeh_pe_dev_traverse(pe, + eeh_report_failure, NULL); + pcibios_remove_pci_devices(bus); + } + pci_unlock_rescan_remove(); } - pci_unlock_rescan_remove(); - } + + /* + * If we have detected dead IOC, we needn't proceed + * any more since all PHBs would have been removed + */ + if (rc == EEH_NEXT_ERR_DEAD_IOC) + break; + } while (rc != EEH_NEXT_ERR_NONE); } /** diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c index f9450537e335a3..f0c353fa655a3a 100644 --- a/arch/powerpc/kernel/eeh_pe.c +++ b/arch/powerpc/kernel/eeh_pe.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -737,6 +736,9 @@ static void *eeh_restore_one_device_bars(void *data, void *flag) else eeh_restore_device_bars(edev, dn); + if (eeh_ops->restore_config) + eeh_ops->restore_config(dn); + return NULL; } diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index bbfb0294b35440..662c6dd98072e7 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -664,8 +664,16 @@ _GLOBAL(ret_from_except_lite) bl .restore_interrupts SCHEDULE_USER b .ret_from_except_lite - -2: bl .save_nvgprs +2: +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + andi. r0,r4,_TIF_USER_WORK_MASK & ~_TIF_RESTORE_TM + bne 3f /* only restore TM if nothing else to do */ + addi r3,r1,STACK_FRAME_OVERHEAD + bl .restore_tm_state + b restore +3: +#endif + bl .save_nvgprs bl .restore_interrupts addi r3,r1,STACK_FRAME_OVERHEAD bl .do_notify_resume diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index e7751561fd1d6c..063b65dd4f27a2 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -308,6 +308,7 @@ interrupt_base_book3e: /* fake trap */ EXCEPTION_STUB(0x2e0, guest_doorbell_crit) EXCEPTION_STUB(0x300, hypercall) EXCEPTION_STUB(0x320, ehpriv) + EXCEPTION_STUB(0x340, lrat_error) .globl interrupt_end_book3e interrupt_end_book3e: @@ -677,6 +678,17 @@ kernel_dbg_exc: bl .unknown_exception b .ret_from_except +/* LRAT Error interrupt */ + START_EXCEPTION(lrat_error); + NORMAL_EXCEPTION_PROLOG(0x340, BOOKE_INTERRUPT_LRAT_ERROR, + PROLOG_ADDITION_NONE) + EXCEPTION_COMMON(0x340, PACA_EXGEN, INTS_KEEP) + addi r3,r1,STACK_FRAME_OVERHEAD + bl .save_nvgprs + INTS_RESTORE_HARD + bl .unknown_exception + b .ret_from_except + /* * An interrupt came in while soft-disabled; We mark paca->irq_happened * accordingly and if the interrupt is level sensitive, we hard disable @@ -859,6 +871,7 @@ BAD_STACK_TRAMPOLINE(0x2e0) BAD_STACK_TRAMPOLINE(0x300) BAD_STACK_TRAMPOLINE(0x310) BAD_STACK_TRAMPOLINE(0x320) +BAD_STACK_TRAMPOLINE(0x340) BAD_STACK_TRAMPOLINE(0x400) BAD_STACK_TRAMPOLINE(0x500) BAD_STACK_TRAMPOLINE(0x600) @@ -1055,12 +1068,9 @@ skpinv: addi r6,r6,1 /* Increment */ mtspr SPRN_MAS0,r3 tlbre mfspr r6,SPRN_MAS1 - rlwinm r6,r6,0,2,0 /* clear IPROT */ + rlwinm r6,r6,0,2,31 /* clear IPROT and VALID */ mtspr SPRN_MAS1,r6 tlbwe - - /* Invalidate TLB1 */ - PPC_TLBILX_ALL(0,R0) sync isync @@ -1114,12 +1124,9 @@ skpinv: addi r6,r6,1 /* Increment */ mtspr SPRN_MAS0,r4 tlbre mfspr r5,SPRN_MAS1 - rlwinm r5,r5,0,2,0 /* clear IPROT */ + rlwinm r5,r5,0,2,31 /* clear IPROT and VALID */ mtspr SPRN_MAS1,r5 tlbwe - - /* Invalidate TLB1 */ - PPC_TLBILX_ALL(0,R0) sync isync @@ -1414,3 +1421,7 @@ _GLOBAL(setup_ehv_ivors) SET_IVOR(38, 0x2c0) /* Guest Processor Doorbell */ SET_IVOR(39, 0x2e0) /* Guest Processor Doorbell Crit/MC */ blr + +_GLOBAL(setup_lrat_ivor) + SET_IVOR(42, 0x340) /* LRAT Error */ + blr diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 9f905e40922e41..38d507306a111d 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -155,8 +155,30 @@ machine_check_pSeries_1: */ HMT_MEDIUM_PPR_DISCARD SET_SCRATCH0(r13) /* save r13 */ +#ifdef CONFIG_PPC_P7_NAP +BEGIN_FTR_SECTION + /* Running native on arch 2.06 or later, check if we are + * waking up from nap. We only handle no state loss and + * supervisor state loss. We do -not- handle hypervisor + * state loss at this time. + */ + mfspr r13,SPRN_SRR1 + rlwinm. r13,r13,47-31,30,31 + beq 9f + + /* waking up from powersave (nap) state */ + cmpwi cr1,r13,2 + /* Total loss of HV state is fatal. let's just stay stuck here */ + bgt cr1,. +9: +END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206) +#endif /* CONFIG_PPC_P7_NAP */ EXCEPTION_PROLOG_0(PACA_EXMC) +BEGIN_FTR_SECTION + b machine_check_pSeries_early +FTR_SECTION_ELSE b machine_check_pSeries_0 +ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE) . = 0x300 .globl data_access_pSeries @@ -405,6 +427,64 @@ denorm_exception_hv: .align 7 /* moved from 0x200 */ +machine_check_pSeries_early: +BEGIN_FTR_SECTION + EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200) + /* + * Register contents: + * R13 = PACA + * R9 = CR + * Original R9 to R13 is saved on PACA_EXMC + * + * Switch to mc_emergency stack and handle re-entrancy (though we + * currently don't test for overflow). Save MCE registers srr1, + * srr0, dar and dsisr and then set ME=1 + * + * We use paca->in_mce to check whether this is the first entry or + * nested machine check. We increment paca->in_mce to track nested + * machine checks. + * + * If this is the first entry then set stack pointer to + * paca->mc_emergency_sp, otherwise r1 is already pointing to + * stack frame on mc_emergency stack. + * + * NOTE: We are here with MSR_ME=0 (off), which means we risk a + * checkstop if we get another machine check exception before we do + * rfid with MSR_ME=1. + */ + mr r11,r1 /* Save r1 */ + lhz r10,PACA_IN_MCE(r13) + cmpwi r10,0 /* Are we in nested machine check */ + bne 0f /* Yes, we are. */ + /* First machine check entry */ + ld r1,PACAMCEMERGSP(r13) /* Use MC emergency stack */ +0: subi r1,r1,INT_FRAME_SIZE /* alloc stack frame */ + addi r10,r10,1 /* increment paca->in_mce */ + sth r10,PACA_IN_MCE(r13) + std r11,GPR1(r1) /* Save r1 on the stack. */ + std r11,0(r1) /* make stack chain pointer */ + mfspr r11,SPRN_SRR0 /* Save SRR0 */ + std r11,_NIP(r1) + mfspr r11,SPRN_SRR1 /* Save SRR1 */ + std r11,_MSR(r1) + mfspr r11,SPRN_DAR /* Save DAR */ + std r11,_DAR(r1) + mfspr r11,SPRN_DSISR /* Save DSISR */ + std r11,_DSISR(r1) + std r9,_CCR(r1) /* Save CR in stackframe */ + /* Save r9 through r13 from EXMC save area to stack frame. */ + EXCEPTION_PROLOG_COMMON_2(PACA_EXMC) + mfmsr r11 /* get MSR value */ + ori r11,r11,MSR_ME /* turn on ME bit */ + ori r11,r11,MSR_RI /* turn on RI bit */ + ld r12,PACAKBASE(r13) /* get high part of &label */ + LOAD_HANDLER(r12, machine_check_handle_early) + mtspr SPRN_SRR0,r12 + mtspr SPRN_SRR1,r11 + rfid + b . /* prevent speculative execution */ +END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) + machine_check_pSeries: .globl machine_check_fwnmi machine_check_fwnmi: @@ -688,30 +768,6 @@ kvmppc_skip_Hinterrupt: STD_EXCEPTION_COMMON(0x100, system_reset, .system_reset_exception) - /* - * Machine check is different because we use a different - * save area: PACA_EXMC instead of PACA_EXGEN. - */ - .align 7 - .globl machine_check_common -machine_check_common: - - mfspr r10,SPRN_DAR - std r10,PACA_EXGEN+EX_DAR(r13) - mfspr r10,SPRN_DSISR - stw r10,PACA_EXGEN+EX_DSISR(r13) - EXCEPTION_PROLOG_COMMON(0x200, PACA_EXMC) - FINISH_NAP - DISABLE_INTS - ld r3,PACA_EXGEN+EX_DAR(r13) - lwz r4,PACA_EXGEN+EX_DSISR(r13) - std r3,_DAR(r1) - std r4,_DSISR(r1) - bl .save_nvgprs - addi r3,r1,STACK_FRAME_OVERHEAD - bl .machine_check_exception - b .ret_from_except - STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ) STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, .timer_interrupt) STD_EXCEPTION_COMMON(0x980, hdecrementer, .hdec_interrupt) @@ -1080,6 +1136,30 @@ unrecov_user_slb: #endif /* __DISABLED__ */ + /* + * Machine check is different because we use a different + * save area: PACA_EXMC instead of PACA_EXGEN. + */ + .align 7 + .globl machine_check_common +machine_check_common: + + mfspr r10,SPRN_DAR + std r10,PACA_EXGEN+EX_DAR(r13) + mfspr r10,SPRN_DSISR + stw r10,PACA_EXGEN+EX_DSISR(r13) + EXCEPTION_PROLOG_COMMON(0x200, PACA_EXMC) + FINISH_NAP + DISABLE_INTS + ld r3,PACA_EXGEN+EX_DAR(r13) + lwz r4,PACA_EXGEN+EX_DSISR(r13) + std r3,_DAR(r1) + std r4,_DSISR(r1) + bl .save_nvgprs + addi r3,r1,STACK_FRAME_OVERHEAD + bl .machine_check_exception + b .ret_from_except + .align 7 .globl alignment_common alignment_common: @@ -1263,6 +1343,120 @@ _GLOBAL(opal_mc_secondary_handler) #endif /* CONFIG_PPC_POWERNV */ +#define MACHINE_CHECK_HANDLER_WINDUP \ + /* Clear MSR_RI before setting SRR0 and SRR1. */\ + li r0,MSR_RI; \ + mfmsr r9; /* get MSR value */ \ + andc r9,r9,r0; \ + mtmsrd r9,1; /* Clear MSR_RI */ \ + /* Move original SRR0 and SRR1 into the respective regs */ \ + ld r9,_MSR(r1); \ + mtspr SPRN_SRR1,r9; \ + ld r3,_NIP(r1); \ + mtspr SPRN_SRR0,r3; \ + ld r9,_CTR(r1); \ + mtctr r9; \ + ld r9,_XER(r1); \ + mtxer r9; \ + ld r9,_LINK(r1); \ + mtlr r9; \ + REST_GPR(0, r1); \ + REST_8GPRS(2, r1); \ + REST_GPR(10, r1); \ + ld r11,_CCR(r1); \ + mtcr r11; \ + /* Decrement paca->in_mce. */ \ + lhz r12,PACA_IN_MCE(r13); \ + subi r12,r12,1; \ + sth r12,PACA_IN_MCE(r13); \ + REST_GPR(11, r1); \ + REST_2GPRS(12, r1); \ + /* restore original r1. */ \ + ld r1,GPR1(r1) + + /* + * Handle machine check early in real mode. We come here with + * ME=1, MMU (IR=0 and DR=0) off and using MC emergency stack. + */ + .align 7 + .globl machine_check_handle_early +machine_check_handle_early: + std r0,GPR0(r1) /* Save r0 */ + EXCEPTION_PROLOG_COMMON_3(0x200) + bl .save_nvgprs + addi r3,r1,STACK_FRAME_OVERHEAD + bl .machine_check_early + ld r12,_MSR(r1) +#ifdef CONFIG_PPC_P7_NAP + /* + * Check if thread was in power saving mode. We come here when any + * of the following is true: + * a. thread wasn't in power saving mode + * b. thread was in power saving mode with no state loss or + * supervisor state loss + * + * Go back to nap again if (b) is true. + */ + rlwinm. r11,r12,47-31,30,31 /* Was it in power saving mode? */ + beq 4f /* No, it wasn;t */ + /* Thread was in power saving mode. Go back to nap again. */ + cmpwi r11,2 + bne 3f + /* Supervisor state loss */ + li r0,1 + stb r0,PACA_NAPSTATELOST(r13) +3: bl .machine_check_queue_event + MACHINE_CHECK_HANDLER_WINDUP + GET_PACA(r13) + ld r1,PACAR1(r13) + b .power7_enter_nap_mode +4: +#endif + /* + * Check if we are coming from hypervisor userspace. If yes then we + * continue in host kernel in V mode to deliver the MC event. + */ + rldicl. r11,r12,4,63 /* See if MC hit while in HV mode. */ + beq 5f + andi. r11,r12,MSR_PR /* See if coming from user. */ + bne 9f /* continue in V mode if we are. */ + +5: +#ifdef CONFIG_KVM_BOOK3S_64_HV + /* + * We are coming from kernel context. Check if we are coming from + * guest. if yes, then we can continue. We will fall through + * do_kvm_200->kvmppc_interrupt to deliver the MC event to guest. + */ + lbz r11,HSTATE_IN_GUEST(r13) + cmpwi r11,0 /* Check if coming from guest */ + bne 9f /* continue if we are. */ +#endif + /* + * At this point we are not sure about what context we come from. + * Queue up the MCE event and return from the interrupt. + * But before that, check if this is an un-recoverable exception. + * If yes, then stay on emergency stack and panic. + */ + andi. r11,r12,MSR_RI + bne 2f +1: addi r3,r1,STACK_FRAME_OVERHEAD + bl .unrecoverable_exception + b 1b +2: + /* + * Return from MC interrupt. + * Queue up the MCE event so that we can log it later, while + * returning from kernel or opal call. + */ + bl .machine_check_queue_event + MACHINE_CHECK_HANDLER_WINDUP + rfid +9: + /* Deliver the machine check to host kernel in V mode. */ + MACHINE_CHECK_HANDLER_WINDUP + b machine_check_pSeries + /* * r13 points to the PACA, r9 contains the saved CR, * r12 contain the saved SRR1, SRR0 is still ready for return diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S index f7f5b8bed68f59..9ad236e5d2c9d0 100644 --- a/arch/powerpc/kernel/fpu.S +++ b/arch/powerpc/kernel/fpu.S @@ -80,6 +80,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX) blr #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ +/* + * Enable use of the FPU, and VSX if possible, for the caller. + */ +_GLOBAL(fp_enable) + mfmsr r3 + ori r3,r3,MSR_FP +#ifdef CONFIG_VSX +BEGIN_FTR_SECTION + oris r3,r3,MSR_VSX@h +END_FTR_SECTION_IFSET(CPU_FTR_VSX) +#endif + SYNC + MTMSRD(r3) + isync /* (not necessary for arch 2.02 and later) */ + blr + /* * Load state from memory into FP registers including FPSCR. * Assumes the caller has enabled FP in the MSR. diff --git a/arch/powerpc/kernel/fsl_booke_entry_mapping.S b/arch/powerpc/kernel/fsl_booke_entry_mapping.S index a92c79be2728e9..f22e7e44fbf321 100644 --- a/arch/powerpc/kernel/fsl_booke_entry_mapping.S +++ b/arch/powerpc/kernel/fsl_booke_entry_mapping.S @@ -176,6 +176,8 @@ skpinv: addi r6,r6,1 /* Increment */ /* 7. Jump to KERNELBASE mapping */ lis r6,(KERNELBASE & ~0xfff)@h ori r6,r6,(KERNELBASE & ~0xfff)@l + rlwinm r7,r25,0,0x03ffffff + add r6,r7,r6 #elif defined(ENTRY_MAPPING_KEXEC_SETUP) /* diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 4f0946de2d5c91..b7363bd4245284 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -23,6 +23,7 @@ */ #include +#include #include #include #include diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index f45726a1d963dd..b497188a94a1e2 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -65,29 +65,78 @@ _ENTRY(_start); nop /* Translate device tree address to physical, save in r30/r31 */ - mfmsr r16 - mfspr r17,SPRN_PID - rlwinm r17,r17,16,0x3fff0000 /* turn PID into MAS6[SPID] */ - rlwimi r17,r16,28,0x00000001 /* turn MSR[DS] into MAS6[SAS] */ - mtspr SPRN_MAS6,r17 - - tlbsx 0,r3 /* must succeed */ - - mfspr r16,SPRN_MAS1 - mfspr r20,SPRN_MAS3 - rlwinm r17,r16,25,0x1f /* r17 = log2(page size) */ - li r18,1024 - slw r18,r18,r17 /* r18 = page size */ - addi r18,r18,-1 - and r19,r3,r18 /* r19 = page offset */ - andc r31,r20,r18 /* r31 = page base */ - or r31,r31,r19 /* r31 = devtree phys addr */ - mfspr r30,SPRN_MAS7 + bl get_phys_addr + mr r30,r3 + mr r31,r4 li r25,0 /* phys kernel start (low) */ li r24,0 /* CPU number */ li r23,0 /* phys kernel start (high) */ +#ifdef CONFIG_RELOCATABLE + LOAD_REG_ADDR_PIC(r3, _stext) /* Get our current runtime base */ + + /* Translate _stext address to physical, save in r23/r25 */ + bl get_phys_addr + mr r23,r3 + mr r25,r4 + + bl 0f +0: mflr r8 + addis r3,r8,(is_second_reloc - 0b)@ha + lwz r19,(is_second_reloc - 0b)@l(r3) + + /* Check if this is the second relocation. */ + cmpwi r19,1 + bne 1f + + /* + * For the second relocation, we already get the real memstart_addr + * from device tree. So we will map PAGE_OFFSET to memstart_addr, + * then the virtual address of start kernel should be: + * PAGE_OFFSET + (kernstart_addr - memstart_addr) + * Since the offset between kernstart_addr and memstart_addr should + * never be beyond 1G, so we can just use the lower 32bit of them + * for the calculation. + */ + lis r3,PAGE_OFFSET@h + + addis r4,r8,(kernstart_addr - 0b)@ha + addi r4,r4,(kernstart_addr - 0b)@l + lwz r5,4(r4) + + addis r6,r8,(memstart_addr - 0b)@ha + addi r6,r6,(memstart_addr - 0b)@l + lwz r7,4(r6) + + subf r5,r7,r5 + add r3,r3,r5 + b 2f + +1: + /* + * We have the runtime (virutal) address of our base. + * We calculate our shift of offset from a 64M page. + * We could map the 64M page we belong to at PAGE_OFFSET and + * get going from there. + */ + lis r4,KERNELBASE@h + ori r4,r4,KERNELBASE@l + rlwinm r6,r25,0,0x3ffffff /* r6 = PHYS_START % 64M */ + rlwinm r5,r4,0,0x3ffffff /* r5 = KERNELBASE % 64M */ + subf r3,r5,r6 /* r3 = r6 - r5 */ + add r3,r4,r3 /* Required Virtual Address */ + +2: bl relocate + + /* + * For the second relocation, we already set the right tlb entries + * for the kernel space, so skip the code in fsl_booke_entry_mapping.S + */ + cmpwi r19,1 + beq set_ivor +#endif + /* We try to not make any assumptions about how the boot loader * setup or used the TLBs. We invalidate all mappings from the * boot loader and load a single entry in TLB1[0] to map the @@ -113,6 +162,7 @@ _ENTRY(__early_start) #include "fsl_booke_entry_mapping.S" #undef ENTRY_MAPPING_BOOT_SETUP +set_ivor: /* Establish the interrupt vector offsets */ SET_IVOR(0, CriticalInput); SET_IVOR(1, MachineCheck); @@ -166,8 +216,7 @@ _ENTRY(__early_start) /* Check to see if we're the second processor, and jump * to the secondary_start code if so */ - lis r24, boot_cpuid@h - ori r24, r24, boot_cpuid@l + LOAD_REG_ADDR_PIC(r24, boot_cpuid) lwz r24, 0(r24) cmpwi r24, -1 mfspr r24,SPRN_PIR @@ -197,6 +246,18 @@ _ENTRY(__early_start) bl early_init +#ifdef CONFIG_RELOCATABLE + mr r3,r30 + mr r4,r31 +#ifdef CONFIG_PHYS_64BIT + mr r5,r23 + mr r6,r25 +#else + mr r5,r25 +#endif + bl relocate_init +#endif + #ifdef CONFIG_DYNAMIC_MEMSTART lis r3,kernstart_addr@ha la r3,kernstart_addr@l(r3) @@ -855,6 +916,33 @@ KernelSPE: #endif /* CONFIG_SPE */ +/* + * Translate the effec addr in r3 to phys addr. The phys addr will be put + * into r3(higher 32bit) and r4(lower 32bit) + */ +get_phys_addr: + mfmsr r8 + mfspr r9,SPRN_PID + rlwinm r9,r9,16,0x3fff0000 /* turn PID into MAS6[SPID] */ + rlwimi r9,r8,28,0x00000001 /* turn MSR[DS] into MAS6[SAS] */ + mtspr SPRN_MAS6,r9 + + tlbsx 0,r3 /* must succeed */ + + mfspr r8,SPRN_MAS1 + mfspr r12,SPRN_MAS3 + rlwinm r9,r8,25,0x1f /* r9 = log2(page size) */ + li r10,1024 + slw r10,r10,r9 /* r10 = page size */ + addi r10,r10,-1 + and r11,r3,r10 /* r11 = page offset */ + andc r4,r12,r10 /* r4 = page base */ + or r4,r4,r11 /* r4 = devtree phys addr */ +#ifdef CONFIG_PHYS_64BIT + mfspr r3,SPRN_MAS7 +#endif + blr + /* * Global functions */ @@ -1057,24 +1145,36 @@ _GLOBAL(__flush_disable_L1) /* When we get here, r24 needs to hold the CPU # */ .globl __secondary_start __secondary_start: - lis r3,__secondary_hold_acknowledge@h - ori r3,r3,__secondary_hold_acknowledge@l - stw r24,0(r3) - - li r3,0 - mr r4,r24 /* Why? */ - bl call_setup_cpu - - lis r3,tlbcam_index@ha - lwz r3,tlbcam_index@l(r3) + LOAD_REG_ADDR_PIC(r3, tlbcam_index) + lwz r3,0(r3) mtctr r3 li r26,0 /* r26 safe? */ + bl switch_to_as1 + mr r27,r3 /* tlb entry */ /* Load each CAM entry */ 1: mr r3,r26 bl loadcam_entry addi r26,r26,1 bdnz 1b + mr r3,r27 /* tlb entry */ + LOAD_REG_ADDR_PIC(r4, memstart_addr) + lwz r4,0(r4) + mr r5,r25 /* phys kernel start */ + rlwinm r5,r5,0,~0x3ffffff /* aligned 64M */ + subf r4,r5,r4 /* memstart_addr - phys kernel start */ + li r5,0 /* no device tree */ + li r6,0 /* not boot cpu */ + bl restore_to_as0 + + + lis r3,__secondary_hold_acknowledge@h + ori r3,r3,__secondary_hold_acknowledge@l + stw r24,0(r3) + + li r3,0 + mr r4,r24 /* Why? */ + bl call_setup_cpu /* get current_thread_info and current */ lis r1,secondary_ti@ha @@ -1110,6 +1210,112 @@ __secondary_hold_acknowledge: .long -1 #endif +/* + * Create a tlb entry with the same effective and physical address as + * the tlb entry used by the current running code. But set the TS to 1. + * Then switch to the address space 1. It will return with the r3 set to + * the ESEL of the new created tlb. + */ +_GLOBAL(switch_to_as1) + mflr r5 + + /* Find a entry not used */ + mfspr r3,SPRN_TLB1CFG + andi. r3,r3,0xfff + mfspr r4,SPRN_PID + rlwinm r4,r4,16,0x3fff0000 /* turn PID into MAS6[SPID] */ + mtspr SPRN_MAS6,r4 +1: lis r4,0x1000 /* Set MAS0(TLBSEL) = 1 */ + addi r3,r3,-1 + rlwimi r4,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ + mtspr SPRN_MAS0,r4 + tlbre + mfspr r4,SPRN_MAS1 + andis. r4,r4,MAS1_VALID@h + bne 1b + + /* Get the tlb entry used by the current running code */ + bl 0f +0: mflr r4 + tlbsx 0,r4 + + mfspr r4,SPRN_MAS1 + ori r4,r4,MAS1_TS /* Set the TS = 1 */ + mtspr SPRN_MAS1,r4 + + mfspr r4,SPRN_MAS0 + rlwinm r4,r4,0,~MAS0_ESEL_MASK + rlwimi r4,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ + mtspr SPRN_MAS0,r4 + tlbwe + isync + sync + + mfmsr r4 + ori r4,r4,MSR_IS | MSR_DS + mtspr SPRN_SRR0,r5 + mtspr SPRN_SRR1,r4 + sync + rfi + +/* + * Restore to the address space 0 and also invalidate the tlb entry created + * by switch_to_as1. + * r3 - the tlb entry which should be invalidated + * r4 - __pa(PAGE_OFFSET in AS1) - __pa(PAGE_OFFSET in AS0) + * r5 - device tree virtual address. If r4 is 0, r5 is ignored. + * r6 - boot cpu +*/ +_GLOBAL(restore_to_as0) + mflr r0 + + bl 0f +0: mflr r9 + addi r9,r9,1f - 0b + + /* + * We may map the PAGE_OFFSET in AS0 to a different physical address, + * so we need calculate the right jump and device tree address based + * on the offset passed by r4. + */ + add r9,r9,r4 + add r5,r5,r4 + add r0,r0,r4 + +2: mfmsr r7 + li r8,(MSR_IS | MSR_DS) + andc r7,r7,r8 + + mtspr SPRN_SRR0,r9 + mtspr SPRN_SRR1,r7 + sync + rfi + + /* Invalidate the temporary tlb entry for AS1 */ +1: lis r9,0x1000 /* Set MAS0(TLBSEL) = 1 */ + rlwimi r9,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ + mtspr SPRN_MAS0,r9 + tlbre + mfspr r9,SPRN_MAS1 + rlwinm r9,r9,0,2,31 /* Clear MAS1 Valid and IPPROT */ + mtspr SPRN_MAS1,r9 + tlbwe + isync + + cmpwi r4,0 + cmpwi cr1,r6,0 + cror eq,4*cr1+eq,eq + bne 3f /* offset != 0 && is_boot_cpu */ + mtlr r0 + blr + + /* + * The PAGE_OFFSET will map to a different physical address, + * jump to _start to do another relocation again. + */ +3: mr r3,r5 + bl _start + /* * We put a few things here that have to be page-aligned. This stuff * goes at the beginning of the data segment, which is page-aligned. diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index f0b47d1a6b0ebd..b0a1792279bbf3 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S index 847e40e62fcee8..3fdef0f0c67fa9 100644 --- a/arch/powerpc/kernel/idle_power7.S +++ b/arch/powerpc/kernel/idle_power7.S @@ -84,6 +84,7 @@ _GLOBAL(power7_nap) std r9,_MSR(r1) std r1,PACAR1(r13) +_GLOBAL(power7_enter_nap_mode) #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE /* Tell KVM we're napping */ li r4,KVM_HWTHREAD_IN_NAP diff --git a/arch/powerpc/kernel/iomap.c b/arch/powerpc/kernel/iomap.c index 97a3715ac8bd83..b82227e7e21bbb 100644 --- a/arch/powerpc/kernel/iomap.c +++ b/arch/powerpc/kernel/iomap.c @@ -3,7 +3,6 @@ * * (C) Copyright 2004 Linus Torvalds */ -#include #include #include #include diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index 572bb5b95f35d8..88e3ec6e1d965a 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -251,14 +251,13 @@ static unsigned long iommu_range_alloc(struct device *dev, if (dev) boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, - 1 << IOMMU_PAGE_SHIFT); + 1 << tbl->it_page_shift); else - boundary_size = ALIGN(1UL << 32, 1 << IOMMU_PAGE_SHIFT); + boundary_size = ALIGN(1UL << 32, 1 << tbl->it_page_shift); /* 4GB boundary for iseries_hv_alloc and iseries_hv_map */ - n = iommu_area_alloc(tbl->it_map, limit, start, npages, - tbl->it_offset, boundary_size >> IOMMU_PAGE_SHIFT, - align_mask); + n = iommu_area_alloc(tbl->it_map, limit, start, npages, tbl->it_offset, + boundary_size >> tbl->it_page_shift, align_mask); if (n == -1) { if (likely(pass == 0)) { /* First try the pool from the start */ @@ -320,12 +319,12 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl, return DMA_ERROR_CODE; entry += tbl->it_offset; /* Offset into real TCE table */ - ret = entry << IOMMU_PAGE_SHIFT; /* Set the return dma address */ + ret = entry << tbl->it_page_shift; /* Set the return dma address */ /* Put the TCEs in the HW table */ build_fail = ppc_md.tce_build(tbl, entry, npages, - (unsigned long)page & IOMMU_PAGE_MASK, - direction, attrs); + (unsigned long)page & + IOMMU_PAGE_MASK(tbl), direction, attrs); /* ppc_md.tce_build() only returns non-zero for transient errors. * Clean up the table bitmap in this case and return @@ -352,7 +351,7 @@ static bool iommu_free_check(struct iommu_table *tbl, dma_addr_t dma_addr, { unsigned long entry, free_entry; - entry = dma_addr >> IOMMU_PAGE_SHIFT; + entry = dma_addr >> tbl->it_page_shift; free_entry = entry - tbl->it_offset; if (((free_entry + npages) > tbl->it_size) || @@ -401,7 +400,7 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, unsigned long flags; struct iommu_pool *pool; - entry = dma_addr >> IOMMU_PAGE_SHIFT; + entry = dma_addr >> tbl->it_page_shift; free_entry = entry - tbl->it_offset; pool = get_pool(tbl, free_entry); @@ -468,13 +467,13 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, } /* Allocate iommu entries for that segment */ vaddr = (unsigned long) sg_virt(s); - npages = iommu_num_pages(vaddr, slen, IOMMU_PAGE_SIZE); + npages = iommu_num_pages(vaddr, slen, IOMMU_PAGE_SIZE(tbl)); align = 0; - if (IOMMU_PAGE_SHIFT < PAGE_SHIFT && slen >= PAGE_SIZE && + if (tbl->it_page_shift < PAGE_SHIFT && slen >= PAGE_SIZE && (vaddr & ~PAGE_MASK) == 0) - align = PAGE_SHIFT - IOMMU_PAGE_SHIFT; + align = PAGE_SHIFT - tbl->it_page_shift; entry = iommu_range_alloc(dev, tbl, npages, &handle, - mask >> IOMMU_PAGE_SHIFT, align); + mask >> tbl->it_page_shift, align); DBG(" - vaddr: %lx, size: %lx\n", vaddr, slen); @@ -489,16 +488,16 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, /* Convert entry to a dma_addr_t */ entry += tbl->it_offset; - dma_addr = entry << IOMMU_PAGE_SHIFT; - dma_addr |= (s->offset & ~IOMMU_PAGE_MASK); + dma_addr = entry << tbl->it_page_shift; + dma_addr |= (s->offset & ~IOMMU_PAGE_MASK(tbl)); DBG(" - %lu pages, entry: %lx, dma_addr: %lx\n", npages, entry, dma_addr); /* Insert into HW table */ build_fail = ppc_md.tce_build(tbl, entry, npages, - vaddr & IOMMU_PAGE_MASK, - direction, attrs); + vaddr & IOMMU_PAGE_MASK(tbl), + direction, attrs); if(unlikely(build_fail)) goto failure; @@ -559,9 +558,9 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, if (s->dma_length != 0) { unsigned long vaddr, npages; - vaddr = s->dma_address & IOMMU_PAGE_MASK; + vaddr = s->dma_address & IOMMU_PAGE_MASK(tbl); npages = iommu_num_pages(s->dma_address, s->dma_length, - IOMMU_PAGE_SIZE); + IOMMU_PAGE_SIZE(tbl)); __iommu_free(tbl, vaddr, npages); s->dma_address = DMA_ERROR_CODE; s->dma_length = 0; @@ -592,7 +591,7 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, if (sg->dma_length == 0) break; npages = iommu_num_pages(dma_handle, sg->dma_length, - IOMMU_PAGE_SIZE); + IOMMU_PAGE_SIZE(tbl)); __iommu_free(tbl, dma_handle, npages); sg = sg_next(sg); } @@ -676,7 +675,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) set_bit(0, tbl->it_map); /* We only split the IOMMU table if we have 1GB or more of space */ - if ((tbl->it_size << IOMMU_PAGE_SHIFT) >= (1UL * 1024 * 1024 * 1024)) + if ((tbl->it_size << tbl->it_page_shift) >= (1UL * 1024 * 1024 * 1024)) tbl->nr_pools = IOMMU_NR_POOLS; else tbl->nr_pools = 1; @@ -768,16 +767,16 @@ dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl, vaddr = page_address(page) + offset; uaddr = (unsigned long)vaddr; - npages = iommu_num_pages(uaddr, size, IOMMU_PAGE_SIZE); + npages = iommu_num_pages(uaddr, size, IOMMU_PAGE_SIZE(tbl)); if (tbl) { align = 0; - if (IOMMU_PAGE_SHIFT < PAGE_SHIFT && size >= PAGE_SIZE && + if (tbl->it_page_shift < PAGE_SHIFT && size >= PAGE_SIZE && ((unsigned long)vaddr & ~PAGE_MASK) == 0) - align = PAGE_SHIFT - IOMMU_PAGE_SHIFT; + align = PAGE_SHIFT - tbl->it_page_shift; dma_handle = iommu_alloc(dev, tbl, vaddr, npages, direction, - mask >> IOMMU_PAGE_SHIFT, align, + mask >> tbl->it_page_shift, align, attrs); if (dma_handle == DMA_ERROR_CODE) { if (printk_ratelimit()) { @@ -786,7 +785,7 @@ dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl, npages); } } else - dma_handle |= (uaddr & ~IOMMU_PAGE_MASK); + dma_handle |= (uaddr & ~IOMMU_PAGE_MASK(tbl)); } return dma_handle; @@ -801,7 +800,8 @@ void iommu_unmap_page(struct iommu_table *tbl, dma_addr_t dma_handle, BUG_ON(direction == DMA_NONE); if (tbl) { - npages = iommu_num_pages(dma_handle, size, IOMMU_PAGE_SIZE); + npages = iommu_num_pages(dma_handle, size, + IOMMU_PAGE_SIZE(tbl)); iommu_free(tbl, dma_handle, npages); } } @@ -845,10 +845,10 @@ void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl, memset(ret, 0, size); /* Set up tces to cover the allocated range */ - nio_pages = size >> IOMMU_PAGE_SHIFT; - io_order = get_iommu_order(size); + nio_pages = size >> tbl->it_page_shift; + io_order = get_iommu_order(size, tbl); mapping = iommu_alloc(dev, tbl, ret, nio_pages, DMA_BIDIRECTIONAL, - mask >> IOMMU_PAGE_SHIFT, io_order, NULL); + mask >> tbl->it_page_shift, io_order, NULL); if (mapping == DMA_ERROR_CODE) { free_pages((unsigned long)ret, order); return NULL; @@ -864,7 +864,7 @@ void iommu_free_coherent(struct iommu_table *tbl, size_t size, unsigned int nio_pages; size = PAGE_ALIGN(size); - nio_pages = size >> IOMMU_PAGE_SHIFT; + nio_pages = size >> tbl->it_page_shift; iommu_free(tbl, dma_handle, nio_pages); size = PAGE_ALIGN(size); free_pages((unsigned long)vaddr, get_order(size)); @@ -935,10 +935,10 @@ int iommu_tce_clear_param_check(struct iommu_table *tbl, if (tce_value) return -EINVAL; - if (ioba & ~IOMMU_PAGE_MASK) + if (ioba & ~IOMMU_PAGE_MASK(tbl)) return -EINVAL; - ioba >>= IOMMU_PAGE_SHIFT; + ioba >>= tbl->it_page_shift; if (ioba < tbl->it_offset) return -EINVAL; @@ -955,13 +955,13 @@ int iommu_tce_put_param_check(struct iommu_table *tbl, if (!(tce & (TCE_PCI_WRITE | TCE_PCI_READ))) return -EINVAL; - if (tce & ~(IOMMU_PAGE_MASK | TCE_PCI_WRITE | TCE_PCI_READ)) + if (tce & ~(IOMMU_PAGE_MASK(tbl) | TCE_PCI_WRITE | TCE_PCI_READ)) return -EINVAL; - if (ioba & ~IOMMU_PAGE_MASK) + if (ioba & ~IOMMU_PAGE_MASK(tbl)) return -EINVAL; - ioba >>= IOMMU_PAGE_SHIFT; + ioba >>= tbl->it_page_shift; if (ioba < tbl->it_offset) return -EINVAL; @@ -1037,7 +1037,7 @@ int iommu_tce_build(struct iommu_table *tbl, unsigned long entry, /* if (unlikely(ret)) pr_err("iommu_tce: %s failed on hwaddr=%lx ioba=%lx kva=%lx ret=%d\n", - __func__, hwaddr, entry << IOMMU_PAGE_SHIFT, + __func__, hwaddr, entry << IOMMU_PAGE_SHIFT(tbl), hwaddr, ret); */ return ret; @@ -1049,14 +1049,14 @@ int iommu_put_tce_user_mode(struct iommu_table *tbl, unsigned long entry, { int ret; struct page *page = NULL; - unsigned long hwaddr, offset = tce & IOMMU_PAGE_MASK & ~PAGE_MASK; + unsigned long hwaddr, offset = tce & IOMMU_PAGE_MASK(tbl) & ~PAGE_MASK; enum dma_data_direction direction = iommu_tce_direction(tce); ret = get_user_pages_fast(tce & PAGE_MASK, 1, direction != DMA_TO_DEVICE, &page); if (unlikely(ret != 1)) { /* pr_err("iommu_tce: get_user_pages_fast failed tce=%lx ioba=%lx ret=%d\n", - tce, entry << IOMMU_PAGE_SHIFT, ret); */ + tce, entry << IOMMU_PAGE_SHIFT(tbl), ret); */ return -EFAULT; } hwaddr = (unsigned long) page_address(page) + offset; @@ -1067,7 +1067,7 @@ int iommu_put_tce_user_mode(struct iommu_table *tbl, unsigned long entry, if (ret < 0) pr_err("iommu_tce: %s failed ioba=%lx, tce=%lx, ret=%d\n", - __func__, entry << IOMMU_PAGE_SHIFT, tce, ret); + __func__, entry << tbl->it_page_shift, tce, ret); return ret; } @@ -1088,6 +1088,14 @@ int iommu_take_ownership(struct iommu_table *tbl) memset(tbl->it_map, 0xff, sz); iommu_clear_tces_and_put_pages(tbl, tbl->it_offset, tbl->it_size); + /* + * Disable iommu bypass, otherwise the user can DMA to all of + * our physical memory via the bypass window instead of just + * the pages that has been explicitly mapped into the iommu + */ + if (tbl->set_bypass) + tbl->set_bypass(tbl, false); + return 0; } EXPORT_SYMBOL_GPL(iommu_take_ownership); @@ -1102,10 +1110,14 @@ void iommu_release_ownership(struct iommu_table *tbl) /* Restore bit#0 set by iommu_init_table() */ if (tbl->it_offset == 0) set_bit(0, tbl->it_map); + + /* The kernel owns the device now, we can restore the iommu bypass */ + if (tbl->set_bypass) + tbl->set_bypass(tbl, true); } EXPORT_SYMBOL_GPL(iommu_release_ownership); -static int iommu_add_device(struct device *dev) +int iommu_add_device(struct device *dev) { struct iommu_table *tbl; int ret = 0; @@ -1127,6 +1139,12 @@ static int iommu_add_device(struct device *dev) pr_debug("iommu_tce: adding %s to iommu group %d\n", dev_name(dev), iommu_group_id(tbl->it_group)); + if (PAGE_SIZE < IOMMU_PAGE_SIZE(tbl)) { + pr_err("iommu_tce: unsupported iommu page size."); + pr_err("%s has not been added\n", dev_name(dev)); + return -EINVAL; + } + ret = iommu_group_add_device(tbl->it_group, dev); if (ret < 0) pr_err("iommu_tce: %s has not been added, ret=%d\n", @@ -1134,52 +1152,23 @@ static int iommu_add_device(struct device *dev) return ret; } +EXPORT_SYMBOL_GPL(iommu_add_device); -static void iommu_del_device(struct device *dev) -{ - iommu_group_remove_device(dev); -} - -static int iommu_bus_notifier(struct notifier_block *nb, - unsigned long action, void *data) +void iommu_del_device(struct device *dev) { - struct device *dev = data; - - switch (action) { - case BUS_NOTIFY_ADD_DEVICE: - return iommu_add_device(dev); - case BUS_NOTIFY_DEL_DEVICE: - iommu_del_device(dev); - return 0; - default: - return 0; + /* + * Some devices might not have IOMMU table and group + * and we needn't detach them from the associated + * IOMMU groups + */ + if (!dev->iommu_group) { + pr_debug("iommu_tce: skipping device %s with no tbl\n", + dev_name(dev)); + return; } -} - -static struct notifier_block tce_iommu_bus_nb = { - .notifier_call = iommu_bus_notifier, -}; - -static int __init tce_iommu_init(void) -{ - struct pci_dev *pdev = NULL; - - BUILD_BUG_ON(PAGE_SIZE < IOMMU_PAGE_SIZE); - - for_each_pci_dev(pdev) - iommu_add_device(&pdev->dev); - - bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb); - return 0; -} - -subsys_initcall_sync(tce_iommu_init); - -#else -void iommu_register_group(struct iommu_table *tbl, - int pci_domain_number, unsigned long pe_num) -{ + iommu_group_remove_device(dev); } +EXPORT_SYMBOL_GPL(iommu_del_device); #endif /* CONFIG_IOMMU_API */ diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index ba016561521557..1d0848bba049bf 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -354,8 +354,13 @@ int arch_show_interrupts(struct seq_file *p, int prec) seq_printf(p, "%*s: ", prec, "LOC"); for_each_online_cpu(j) - seq_printf(p, "%10u ", per_cpu(irq_stat, j).timer_irqs); - seq_printf(p, " Local timer interrupts\n"); + seq_printf(p, "%10u ", per_cpu(irq_stat, j).timer_irqs_event); + seq_printf(p, " Local timer interrupts for timer event device\n"); + + seq_printf(p, "%*s: ", prec, "LOC"); + for_each_online_cpu(j) + seq_printf(p, "%10u ", per_cpu(irq_stat, j).timer_irqs_others); + seq_printf(p, " Local timer interrupts for others\n"); seq_printf(p, "%*s: ", prec, "SPU"); for_each_online_cpu(j) @@ -389,11 +394,12 @@ int arch_show_interrupts(struct seq_file *p, int prec) */ u64 arch_irq_stat_cpu(unsigned int cpu) { - u64 sum = per_cpu(irq_stat, cpu).timer_irqs; + u64 sum = per_cpu(irq_stat, cpu).timer_irqs_event; sum += per_cpu(irq_stat, cpu).pmu_irqs; sum += per_cpu(irq_stat, cpu).mce_exceptions; sum += per_cpu(irq_stat, cpu).spurious_irqs; + sum += per_cpu(irq_stat, cpu).timer_irqs_others; #ifdef CONFIG_PPC_DOORBELL sum += per_cpu(irq_stat, cpu).doorbell_irqs; #endif @@ -553,8 +559,13 @@ void exc_lvl_ctx_init(void) #ifdef CONFIG_PPC64 cpu_nr = i; #else +#ifdef CONFIG_SMP cpu_nr = get_hard_smp_processor_id(i); +#else + cpu_nr = 0; +#endif #endif + memset((void *)critirq_ctx[cpu_nr], 0, THREAD_SIZE); tp = critirq_ctx[cpu_nr]; tp->cpu = cpu_nr; diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 83e89d310734f6..8504657379f13f 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c index db28032e320e3e..6a0175297b0d8e 100644 --- a/arch/powerpc/kernel/kvm.c +++ b/arch/powerpc/kernel/kvm.c @@ -413,13 +413,13 @@ static void kvm_map_magic_page(void *data) { u32 *features = data; - ulong in[8]; + ulong in[8] = {0}; ulong out[8]; in[0] = KVM_MAGIC_PAGE; in[1] = KVM_MAGIC_PAGE; - kvm_hypercall(in, out, KVM_HCALL_TOKEN(KVM_HC_PPC_MAP_MAGIC_PAGE)); + epapr_hypercall(in, out, KVM_HCALL_TOKEN(KVM_HC_PPC_MAP_MAGIC_PAGE)); *features = out[0]; } @@ -711,43 +711,6 @@ static void kvm_use_magic_page(void) kvm_patching_worked ? "worked" : "failed"); } -unsigned long kvm_hypercall(unsigned long *in, - unsigned long *out, - unsigned long nr) -{ - unsigned long register r0 asm("r0"); - unsigned long register r3 asm("r3") = in[0]; - unsigned long register r4 asm("r4") = in[1]; - unsigned long register r5 asm("r5") = in[2]; - unsigned long register r6 asm("r6") = in[3]; - unsigned long register r7 asm("r7") = in[4]; - unsigned long register r8 asm("r8") = in[5]; - unsigned long register r9 asm("r9") = in[6]; - unsigned long register r10 asm("r10") = in[7]; - unsigned long register r11 asm("r11") = nr; - unsigned long register r12 asm("r12"); - - asm volatile("bl epapr_hypercall_start" - : "=r"(r0), "=r"(r3), "=r"(r4), "=r"(r5), "=r"(r6), - "=r"(r7), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11), - "=r"(r12) - : "r"(r3), "r"(r4), "r"(r5), "r"(r6), "r"(r7), "r"(r8), - "r"(r9), "r"(r10), "r"(r11) - : "memory", "cc", "xer", "ctr", "lr"); - - out[0] = r4; - out[1] = r5; - out[2] = r6; - out[3] = r7; - out[4] = r8; - out[5] = r9; - out[6] = r10; - out[7] = r11; - - return r3; -} -EXPORT_SYMBOL_GPL(kvm_hypercall); - static __init void kvm_free_tmp(void) { free_reserved_area(&kvm_tmp[kvm_tmp_index], diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c index 75d4f7340da893..015ae55c18686f 100644 --- a/arch/powerpc/kernel/machine_kexec.c +++ b/arch/powerpc/kernel/machine_kexec.c @@ -196,7 +196,9 @@ int overlaps_crashkernel(unsigned long start, unsigned long size) /* Values we need to export to the second kernel via the device tree. */ static phys_addr_t kernel_end; +static phys_addr_t crashk_base; static phys_addr_t crashk_size; +static unsigned long long mem_limit; static struct property kernel_end_prop = { .name = "linux,kernel-end", @@ -207,7 +209,7 @@ static struct property kernel_end_prop = { static struct property crashk_base_prop = { .name = "linux,crashkernel-base", .length = sizeof(phys_addr_t), - .value = &crashk_res.start, + .value = &crashk_base }; static struct property crashk_size_prop = { @@ -219,9 +221,11 @@ static struct property crashk_size_prop = { static struct property memory_limit_prop = { .name = "linux,memory-limit", .length = sizeof(unsigned long long), - .value = &memory_limit, + .value = &mem_limit, }; +#define cpu_to_be_ulong __PASTE(cpu_to_be, BITS_PER_LONG) + static void __init export_crashk_values(struct device_node *node) { struct property *prop; @@ -237,8 +241,9 @@ static void __init export_crashk_values(struct device_node *node) of_remove_property(node, prop); if (crashk_res.start != 0) { + crashk_base = cpu_to_be_ulong(crashk_res.start), of_add_property(node, &crashk_base_prop); - crashk_size = resource_size(&crashk_res); + crashk_size = cpu_to_be_ulong(resource_size(&crashk_res)); of_add_property(node, &crashk_size_prop); } @@ -246,6 +251,7 @@ static void __init export_crashk_values(struct device_node *node) * memory_limit is required by the kexec-tools to limit the * crash regions to the actual memory used. */ + mem_limit = cpu_to_be_ulong(memory_limit); of_update_property(node, &memory_limit_prop); } @@ -264,7 +270,7 @@ static int __init kexec_setup(void) of_remove_property(node, prop); /* information needed by userspace when using default_machine_kexec */ - kernel_end = __pa(_end); + kernel_end = cpu_to_be_ulong(__pa(_end)); of_add_property(node, &kernel_end_prop); export_crashk_values(node); diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index be4e6d648f6093..59d229a2a3e08d 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -369,6 +369,7 @@ void default_machine_kexec(struct kimage *image) /* Values we need to export to the second kernel via the device tree. */ static unsigned long htab_base; +static unsigned long htab_size; static struct property htab_base_prop = { .name = "linux,htab-base", @@ -379,7 +380,7 @@ static struct property htab_base_prop = { static struct property htab_size_prop = { .name = "linux,htab-size", .length = sizeof(unsigned long), - .value = &htab_size_bytes, + .value = &htab_size, }; static int __init export_htab_values(void) @@ -403,8 +404,9 @@ static int __init export_htab_values(void) if (prop) of_remove_property(node, prop); - htab_base = __pa(htab_address); + htab_base = cpu_to_be64(__pa(htab_address)); of_add_property(node, &htab_base_prop); + htab_size = cpu_to_be64(htab_size_bytes); of_add_property(node, &htab_size_prop); of_node_put(node); diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c new file mode 100644 index 00000000000000..cadef7e64e4245 --- /dev/null +++ b/arch/powerpc/kernel/mce.c @@ -0,0 +1,352 @@ +/* + * Machine check exception handling. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright 2013 IBM Corporation + * Author: Mahesh Salgaonkar + */ + +#undef DEBUG +#define pr_fmt(fmt) "mce: " fmt + +#include +#include +#include +#include +#include +#include + +static DEFINE_PER_CPU(int, mce_nest_count); +static DEFINE_PER_CPU(struct machine_check_event[MAX_MC_EVT], mce_event); + +/* Queue for delayed MCE events. */ +static DEFINE_PER_CPU(int, mce_queue_count); +static DEFINE_PER_CPU(struct machine_check_event[MAX_MC_EVT], mce_event_queue); + +static void machine_check_process_queued_event(struct irq_work *work); +struct irq_work mce_event_process_work = { + .func = machine_check_process_queued_event, +}; + +static void mce_set_error_info(struct machine_check_event *mce, + struct mce_error_info *mce_err) +{ + mce->error_type = mce_err->error_type; + switch (mce_err->error_type) { + case MCE_ERROR_TYPE_UE: + mce->u.ue_error.ue_error_type = mce_err->u.ue_error_type; + break; + case MCE_ERROR_TYPE_SLB: + mce->u.slb_error.slb_error_type = mce_err->u.slb_error_type; + break; + case MCE_ERROR_TYPE_ERAT: + mce->u.erat_error.erat_error_type = mce_err->u.erat_error_type; + break; + case MCE_ERROR_TYPE_TLB: + mce->u.tlb_error.tlb_error_type = mce_err->u.tlb_error_type; + break; + case MCE_ERROR_TYPE_UNKNOWN: + default: + break; + } +} + +/* + * Decode and save high level MCE information into per cpu buffer which + * is an array of machine_check_event structure. + */ +void save_mce_event(struct pt_regs *regs, long handled, + struct mce_error_info *mce_err, + uint64_t addr) +{ + uint64_t srr1; + int index = __get_cpu_var(mce_nest_count)++; + struct machine_check_event *mce = &__get_cpu_var(mce_event[index]); + + /* + * Return if we don't have enough space to log mce event. + * mce_nest_count may go beyond MAX_MC_EVT but that's ok, + * the check below will stop buffer overrun. + */ + if (index >= MAX_MC_EVT) + return; + + /* Populate generic machine check info */ + mce->version = MCE_V1; + mce->srr0 = regs->nip; + mce->srr1 = regs->msr; + mce->gpr3 = regs->gpr[3]; + mce->in_use = 1; + + mce->initiator = MCE_INITIATOR_CPU; + if (handled) + mce->disposition = MCE_DISPOSITION_RECOVERED; + else + mce->disposition = MCE_DISPOSITION_NOT_RECOVERED; + mce->severity = MCE_SEV_ERROR_SYNC; + + srr1 = regs->msr; + + /* + * Populate the mce error_type and type-specific error_type. + */ + mce_set_error_info(mce, mce_err); + + if (!addr) + return; + + if (mce->error_type == MCE_ERROR_TYPE_TLB) { + mce->u.tlb_error.effective_address_provided = true; + mce->u.tlb_error.effective_address = addr; + } else if (mce->error_type == MCE_ERROR_TYPE_SLB) { + mce->u.slb_error.effective_address_provided = true; + mce->u.slb_error.effective_address = addr; + } else if (mce->error_type == MCE_ERROR_TYPE_ERAT) { + mce->u.erat_error.effective_address_provided = true; + mce->u.erat_error.effective_address = addr; + } else if (mce->error_type == MCE_ERROR_TYPE_UE) { + mce->u.ue_error.effective_address_provided = true; + mce->u.ue_error.effective_address = addr; + } + return; +} + +/* + * get_mce_event: + * mce Pointer to machine_check_event structure to be filled. + * release Flag to indicate whether to free the event slot or not. + * 0 <= do not release the mce event. Caller will invoke + * release_mce_event() once event has been consumed. + * 1 <= release the slot. + * + * return 1 = success + * 0 = failure + * + * get_mce_event() will be called by platform specific machine check + * handle routine and in KVM. + * When we call get_mce_event(), we are still in interrupt context and + * preemption will not be scheduled until ret_from_expect() routine + * is called. + */ +int get_mce_event(struct machine_check_event *mce, bool release) +{ + int index = __get_cpu_var(mce_nest_count) - 1; + struct machine_check_event *mc_evt; + int ret = 0; + + /* Sanity check */ + if (index < 0) + return ret; + + /* Check if we have MCE info to process. */ + if (index < MAX_MC_EVT) { + mc_evt = &__get_cpu_var(mce_event[index]); + /* Copy the event structure and release the original */ + if (mce) + *mce = *mc_evt; + if (release) + mc_evt->in_use = 0; + ret = 1; + } + /* Decrement the count to free the slot. */ + if (release) + __get_cpu_var(mce_nest_count)--; + + return ret; +} + +void release_mce_event(void) +{ + get_mce_event(NULL, true); +} + +/* + * Queue up the MCE event which then can be handled later. + */ +void machine_check_queue_event(void) +{ + int index; + struct machine_check_event evt; + + if (!get_mce_event(&evt, MCE_EVENT_RELEASE)) + return; + + index = __get_cpu_var(mce_queue_count)++; + /* If queue is full, just return for now. */ + if (index >= MAX_MC_EVT) { + __get_cpu_var(mce_queue_count)--; + return; + } + __get_cpu_var(mce_event_queue[index]) = evt; + + /* Queue irq work to process this event later. */ + irq_work_queue(&mce_event_process_work); +} + +/* + * process pending MCE event from the mce event queue. This function will be + * called during syscall exit. + */ +static void machine_check_process_queued_event(struct irq_work *work) +{ + int index; + + /* + * For now just print it to console. + * TODO: log this error event to FSP or nvram. + */ + while (__get_cpu_var(mce_queue_count) > 0) { + index = __get_cpu_var(mce_queue_count) - 1; + machine_check_print_event_info( + &__get_cpu_var(mce_event_queue[index])); + __get_cpu_var(mce_queue_count)--; + } +} + +void machine_check_print_event_info(struct machine_check_event *evt) +{ + const char *level, *sevstr, *subtype; + static const char *mc_ue_types[] = { + "Indeterminate", + "Instruction fetch", + "Page table walk ifetch", + "Load/Store", + "Page table walk Load/Store", + }; + static const char *mc_slb_types[] = { + "Indeterminate", + "Parity", + "Multihit", + }; + static const char *mc_erat_types[] = { + "Indeterminate", + "Parity", + "Multihit", + }; + static const char *mc_tlb_types[] = { + "Indeterminate", + "Parity", + "Multihit", + }; + + /* Print things out */ + if (evt->version != MCE_V1) { + pr_err("Machine Check Exception, Unknown event version %d !\n", + evt->version); + return; + } + switch (evt->severity) { + case MCE_SEV_NO_ERROR: + level = KERN_INFO; + sevstr = "Harmless"; + break; + case MCE_SEV_WARNING: + level = KERN_WARNING; + sevstr = ""; + break; + case MCE_SEV_ERROR_SYNC: + level = KERN_ERR; + sevstr = "Severe"; + break; + case MCE_SEV_FATAL: + default: + level = KERN_ERR; + sevstr = "Fatal"; + break; + } + + printk("%s%s Machine check interrupt [%s]\n", level, sevstr, + evt->disposition == MCE_DISPOSITION_RECOVERED ? + "Recovered" : "[Not recovered"); + printk("%s Initiator: %s\n", level, + evt->initiator == MCE_INITIATOR_CPU ? "CPU" : "Unknown"); + switch (evt->error_type) { + case MCE_ERROR_TYPE_UE: + subtype = evt->u.ue_error.ue_error_type < + ARRAY_SIZE(mc_ue_types) ? + mc_ue_types[evt->u.ue_error.ue_error_type] + : "Unknown"; + printk("%s Error type: UE [%s]\n", level, subtype); + if (evt->u.ue_error.effective_address_provided) + printk("%s Effective address: %016llx\n", + level, evt->u.ue_error.effective_address); + if (evt->u.ue_error.physical_address_provided) + printk("%s Physial address: %016llx\n", + level, evt->u.ue_error.physical_address); + break; + case MCE_ERROR_TYPE_SLB: + subtype = evt->u.slb_error.slb_error_type < + ARRAY_SIZE(mc_slb_types) ? + mc_slb_types[evt->u.slb_error.slb_error_type] + : "Unknown"; + printk("%s Error type: SLB [%s]\n", level, subtype); + if (evt->u.slb_error.effective_address_provided) + printk("%s Effective address: %016llx\n", + level, evt->u.slb_error.effective_address); + break; + case MCE_ERROR_TYPE_ERAT: + subtype = evt->u.erat_error.erat_error_type < + ARRAY_SIZE(mc_erat_types) ? + mc_erat_types[evt->u.erat_error.erat_error_type] + : "Unknown"; + printk("%s Error type: ERAT [%s]\n", level, subtype); + if (evt->u.erat_error.effective_address_provided) + printk("%s Effective address: %016llx\n", + level, evt->u.erat_error.effective_address); + break; + case MCE_ERROR_TYPE_TLB: + subtype = evt->u.tlb_error.tlb_error_type < + ARRAY_SIZE(mc_tlb_types) ? + mc_tlb_types[evt->u.tlb_error.tlb_error_type] + : "Unknown"; + printk("%s Error type: TLB [%s]\n", level, subtype); + if (evt->u.tlb_error.effective_address_provided) + printk("%s Effective address: %016llx\n", + level, evt->u.tlb_error.effective_address); + break; + default: + case MCE_ERROR_TYPE_UNKNOWN: + printk("%s Error type: Unknown\n", level); + break; + } +} + +uint64_t get_mce_fault_addr(struct machine_check_event *evt) +{ + switch (evt->error_type) { + case MCE_ERROR_TYPE_UE: + if (evt->u.ue_error.effective_address_provided) + return evt->u.ue_error.effective_address; + break; + case MCE_ERROR_TYPE_SLB: + if (evt->u.slb_error.effective_address_provided) + return evt->u.slb_error.effective_address; + break; + case MCE_ERROR_TYPE_ERAT: + if (evt->u.erat_error.effective_address_provided) + return evt->u.erat_error.effective_address; + break; + case MCE_ERROR_TYPE_TLB: + if (evt->u.tlb_error.effective_address_provided) + return evt->u.tlb_error.effective_address; + break; + default: + case MCE_ERROR_TYPE_UNKNOWN: + break; + } + return 0; +} +EXPORT_SYMBOL(get_mce_fault_addr); diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c new file mode 100644 index 00000000000000..27c93f41166f42 --- /dev/null +++ b/arch/powerpc/kernel/mce_power.c @@ -0,0 +1,284 @@ +/* + * Machine check exception handling CPU-side for power7 and power8 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright 2013 IBM Corporation + * Author: Mahesh Salgaonkar + */ + +#undef DEBUG +#define pr_fmt(fmt) "mce_power: " fmt + +#include +#include +#include +#include + +/* flush SLBs and reload */ +static void flush_and_reload_slb(void) +{ + struct slb_shadow *slb; + unsigned long i, n; + + /* Invalidate all SLBs */ + asm volatile("slbmte %0,%0; slbia" : : "r" (0)); + +#ifdef CONFIG_KVM_BOOK3S_HANDLER + /* + * If machine check is hit when in guest or in transition, we will + * only flush the SLBs and continue. + */ + if (get_paca()->kvm_hstate.in_guest) + return; +#endif + + /* For host kernel, reload the SLBs from shadow SLB buffer. */ + slb = get_slb_shadow(); + if (!slb) + return; + + n = min_t(u32, be32_to_cpu(slb->persistent), SLB_MIN_SIZE); + + /* Load up the SLB entries from shadow SLB */ + for (i = 0; i < n; i++) { + unsigned long rb = be64_to_cpu(slb->save_area[i].esid); + unsigned long rs = be64_to_cpu(slb->save_area[i].vsid); + + rb = (rb & ~0xFFFul) | i; + asm volatile("slbmte %0,%1" : : "r" (rs), "r" (rb)); + } +} + +static long mce_handle_derror(uint64_t dsisr, uint64_t slb_error_bits) +{ + long handled = 1; + + /* + * flush and reload SLBs for SLB errors and flush TLBs for TLB errors. + * reset the error bits whenever we handle them so that at the end + * we can check whether we handled all of them or not. + * */ + if (dsisr & slb_error_bits) { + flush_and_reload_slb(); + /* reset error bits */ + dsisr &= ~(slb_error_bits); + } + if (dsisr & P7_DSISR_MC_TLB_MULTIHIT_MFTLB) { + if (cur_cpu_spec && cur_cpu_spec->flush_tlb) + cur_cpu_spec->flush_tlb(TLBIEL_INVAL_PAGE); + /* reset error bits */ + dsisr &= ~P7_DSISR_MC_TLB_MULTIHIT_MFTLB; + } + /* Any other errors we don't understand? */ + if (dsisr & 0xffffffffUL) + handled = 0; + + return handled; +} + +static long mce_handle_derror_p7(uint64_t dsisr) +{ + return mce_handle_derror(dsisr, P7_DSISR_MC_SLB_ERRORS); +} + +static long mce_handle_common_ierror(uint64_t srr1) +{ + long handled = 0; + + switch (P7_SRR1_MC_IFETCH(srr1)) { + case 0: + break; + case P7_SRR1_MC_IFETCH_SLB_PARITY: + case P7_SRR1_MC_IFETCH_SLB_MULTIHIT: + /* flush and reload SLBs for SLB errors. */ + flush_and_reload_slb(); + handled = 1; + break; + case P7_SRR1_MC_IFETCH_TLB_MULTIHIT: + if (cur_cpu_spec && cur_cpu_spec->flush_tlb) { + cur_cpu_spec->flush_tlb(TLBIEL_INVAL_PAGE); + handled = 1; + } + break; + default: + break; + } + + return handled; +} + +static long mce_handle_ierror_p7(uint64_t srr1) +{ + long handled = 0; + + handled = mce_handle_common_ierror(srr1); + + if (P7_SRR1_MC_IFETCH(srr1) == P7_SRR1_MC_IFETCH_SLB_BOTH) { + flush_and_reload_slb(); + handled = 1; + } + return handled; +} + +static void mce_get_common_ierror(struct mce_error_info *mce_err, uint64_t srr1) +{ + switch (P7_SRR1_MC_IFETCH(srr1)) { + case P7_SRR1_MC_IFETCH_SLB_PARITY: + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_PARITY; + break; + case P7_SRR1_MC_IFETCH_SLB_MULTIHIT: + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_MULTIHIT; + break; + case P7_SRR1_MC_IFETCH_TLB_MULTIHIT: + mce_err->error_type = MCE_ERROR_TYPE_TLB; + mce_err->u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT; + break; + case P7_SRR1_MC_IFETCH_UE: + case P7_SRR1_MC_IFETCH_UE_IFU_INTERNAL: + mce_err->error_type = MCE_ERROR_TYPE_UE; + mce_err->u.ue_error_type = MCE_UE_ERROR_IFETCH; + break; + case P7_SRR1_MC_IFETCH_UE_TLB_RELOAD: + mce_err->error_type = MCE_ERROR_TYPE_UE; + mce_err->u.ue_error_type = + MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH; + break; + } +} + +static void mce_get_ierror_p7(struct mce_error_info *mce_err, uint64_t srr1) +{ + mce_get_common_ierror(mce_err, srr1); + if (P7_SRR1_MC_IFETCH(srr1) == P7_SRR1_MC_IFETCH_SLB_BOTH) { + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_INDETERMINATE; + } +} + +static void mce_get_derror_p7(struct mce_error_info *mce_err, uint64_t dsisr) +{ + if (dsisr & P7_DSISR_MC_UE) { + mce_err->error_type = MCE_ERROR_TYPE_UE; + mce_err->u.ue_error_type = MCE_UE_ERROR_LOAD_STORE; + } else if (dsisr & P7_DSISR_MC_UE_TABLEWALK) { + mce_err->error_type = MCE_ERROR_TYPE_UE; + mce_err->u.ue_error_type = + MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE; + } else if (dsisr & P7_DSISR_MC_ERAT_MULTIHIT) { + mce_err->error_type = MCE_ERROR_TYPE_ERAT; + mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT; + } else if (dsisr & P7_DSISR_MC_SLB_MULTIHIT) { + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_MULTIHIT; + } else if (dsisr & P7_DSISR_MC_SLB_PARITY_MFSLB) { + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_PARITY; + } else if (dsisr & P7_DSISR_MC_TLB_MULTIHIT_MFTLB) { + mce_err->error_type = MCE_ERROR_TYPE_TLB; + mce_err->u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT; + } else if (dsisr & P7_DSISR_MC_SLB_MULTIHIT_PARITY) { + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_INDETERMINATE; + } +} + +long __machine_check_early_realmode_p7(struct pt_regs *regs) +{ + uint64_t srr1, addr; + long handled = 1; + struct mce_error_info mce_error_info = { 0 }; + + srr1 = regs->msr; + + /* + * Handle memory errors depending whether this was a load/store or + * ifetch exception. Also, populate the mce error_type and + * type-specific error_type from either SRR1 or DSISR, depending + * whether this was a load/store or ifetch exception + */ + if (P7_SRR1_MC_LOADSTORE(srr1)) { + handled = mce_handle_derror_p7(regs->dsisr); + mce_get_derror_p7(&mce_error_info, regs->dsisr); + addr = regs->dar; + } else { + handled = mce_handle_ierror_p7(srr1); + mce_get_ierror_p7(&mce_error_info, srr1); + addr = regs->nip; + } + + save_mce_event(regs, handled, &mce_error_info, addr); + return handled; +} + +static void mce_get_ierror_p8(struct mce_error_info *mce_err, uint64_t srr1) +{ + mce_get_common_ierror(mce_err, srr1); + if (P7_SRR1_MC_IFETCH(srr1) == P8_SRR1_MC_IFETCH_ERAT_MULTIHIT) { + mce_err->error_type = MCE_ERROR_TYPE_ERAT; + mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT; + } +} + +static void mce_get_derror_p8(struct mce_error_info *mce_err, uint64_t dsisr) +{ + mce_get_derror_p7(mce_err, dsisr); + if (dsisr & P8_DSISR_MC_ERAT_MULTIHIT_SEC) { + mce_err->error_type = MCE_ERROR_TYPE_ERAT; + mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT; + } +} + +static long mce_handle_ierror_p8(uint64_t srr1) +{ + long handled = 0; + + handled = mce_handle_common_ierror(srr1); + + if (P7_SRR1_MC_IFETCH(srr1) == P8_SRR1_MC_IFETCH_ERAT_MULTIHIT) { + flush_and_reload_slb(); + handled = 1; + } + return handled; +} + +static long mce_handle_derror_p8(uint64_t dsisr) +{ + return mce_handle_derror(dsisr, P8_DSISR_MC_SLB_ERRORS); +} + +long __machine_check_early_realmode_p8(struct pt_regs *regs) +{ + uint64_t srr1, addr; + long handled = 1; + struct mce_error_info mce_error_info = { 0 }; + + srr1 = regs->msr; + + if (P7_SRR1_MC_LOADSTORE(srr1)) { + handled = mce_handle_derror_p8(regs->dsisr); + mce_get_derror_p8(&mce_error_info, regs->dsisr); + addr = regs->dar; + } else { + handled = mce_handle_ierror_p8(srr1); + mce_get_ierror_p8(&mce_error_info, srr1); + addr = regs->nip; + } + + save_mce_event(regs, handled, &mce_error_info, addr); + return handled; +} diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index e47d268727a4a8..7c6bb4b17b4960 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -57,11 +57,14 @@ _GLOBAL(call_do_softirq) mtlr r0 blr +/* + * void call_do_irq(struct pt_regs *regs, struct thread_info *irqtp); + */ _GLOBAL(call_do_irq) mflr r0 stw r0,4(r1) lwz r10,THREAD+KSP_LIMIT(r2) - addi r11,r3,THREAD_INFO_GAP + addi r11,r4,THREAD_INFO_GAP stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4) mr r1,r4 stw r10,8(r1) @@ -344,7 +347,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_UNIFIED_ID_CACHE) */ _KPROBE(flush_icache_range) BEGIN_FTR_SECTION - isync + PURGE_PREFETCHED_INS blr /* for 601, do nothing */ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) li r5,L1_CACHE_BYTES-1 @@ -448,6 +451,7 @@ _GLOBAL(invalidate_dcache_range) */ _GLOBAL(__flush_dcache_icache) BEGIN_FTR_SECTION + PURGE_PREFETCHED_INS blr END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) rlwinm r3,r3,0,0,31-PAGE_SHIFT /* Get page base address */ @@ -489,6 +493,7 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_44x) */ _GLOBAL(__flush_dcache_icache_phys) BEGIN_FTR_SECTION + PURGE_PREFETCHED_INS blr /* for 601, do nothing */ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) mfmsr r10 diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 64bf8db12b15be..3d0249599d524a 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -67,6 +67,7 @@ PPC64_CACHES: _KPROBE(flush_icache_range) BEGIN_FTR_SECTION + PURGE_PREFETCHED_INS blr END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) /* @@ -211,6 +212,11 @@ _GLOBAL(__flush_dcache_icache) * Different systems have different cache line sizes */ +BEGIN_FTR_SECTION + PURGE_PREFETCHED_INS + blr +END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) + /* Flush the dcache */ ld r7,PPC64_CACHES@toc(r2) clrrdi r3,r3,PAGE_SHIFT /* Page align */ diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index 0620eaaaad45b4..bf0aada02fe479 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -99,12 +99,28 @@ static inline void free_lppacas(void) { } * 3 persistent SLBs are registered here. The buffer will be zero * initially, hence will all be invaild until we actually write them. */ -struct slb_shadow slb_shadow[] __cacheline_aligned = { - [0 ... (NR_CPUS-1)] = { - .persistent = cpu_to_be32(SLB_NUM_BOLTED), - .buffer_length = cpu_to_be32(sizeof(struct slb_shadow)), - }, -}; +static struct slb_shadow *slb_shadow; + +static void __init allocate_slb_shadows(int nr_cpus, int limit) +{ + int size = PAGE_ALIGN(sizeof(struct slb_shadow) * nr_cpus); + slb_shadow = __va(memblock_alloc_base(size, PAGE_SIZE, limit)); + memset(slb_shadow, 0, size); +} + +static struct slb_shadow * __init init_slb_shadow(int cpu) +{ + struct slb_shadow *s = &slb_shadow[cpu]; + + s->persistent = cpu_to_be32(SLB_NUM_BOLTED); + s->buffer_length = cpu_to_be32(sizeof(*s)); + + return s; +} + +#else /* CONFIG_PPC_STD_MMU_64 */ + +static void __init allocate_slb_shadows(int nr_cpus, int limit) { } #endif /* CONFIG_PPC_STD_MMU_64 */ @@ -142,8 +158,13 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu) new_paca->__current = &init_task; new_paca->data_offset = 0xfeeeeeeeeeeeeeeeULL; #ifdef CONFIG_PPC_STD_MMU_64 - new_paca->slb_shadow_ptr = &slb_shadow[cpu]; + new_paca->slb_shadow_ptr = init_slb_shadow(cpu); #endif /* CONFIG_PPC_STD_MMU_64 */ + +#ifdef CONFIG_PPC_BOOK3E + /* For now -- if we have threads this will be adjusted later */ + new_paca->tcd_ptr = &new_paca->tcd; +#endif } /* Put the paca pointer into r13 and SPRG_PACA */ @@ -190,6 +211,8 @@ void __init allocate_pacas(void) allocate_lppacas(nr_cpu_ids, limit); + allocate_slb_shadows(nr_cpu_ids, limit); + /* Can't use for_each_*_cpu, as they aren't functional yet */ for (cpu = 0; cpu < nr_cpu_ids; cpu++) initialise_paca(&paca[cpu], cpu); diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 4a96556fd2d49e..8d4c247f17389f 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -74,6 +73,48 @@ struct task_struct *last_task_used_vsx = NULL; struct task_struct *last_task_used_spe = NULL; #endif +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +void giveup_fpu_maybe_transactional(struct task_struct *tsk) +{ + /* + * If we are saving the current thread's registers, and the + * thread is in a transactional state, set the TIF_RESTORE_TM + * bit so that we know to restore the registers before + * returning to userspace. + */ + if (tsk == current && tsk->thread.regs && + MSR_TM_ACTIVE(tsk->thread.regs->msr) && + !test_thread_flag(TIF_RESTORE_TM)) { + tsk->thread.tm_orig_msr = tsk->thread.regs->msr; + set_thread_flag(TIF_RESTORE_TM); + } + + giveup_fpu(tsk); +} + +void giveup_altivec_maybe_transactional(struct task_struct *tsk) +{ + /* + * If we are saving the current thread's registers, and the + * thread is in a transactional state, set the TIF_RESTORE_TM + * bit so that we know to restore the registers before + * returning to userspace. + */ + if (tsk == current && tsk->thread.regs && + MSR_TM_ACTIVE(tsk->thread.regs->msr) && + !test_thread_flag(TIF_RESTORE_TM)) { + tsk->thread.tm_orig_msr = tsk->thread.regs->msr; + set_thread_flag(TIF_RESTORE_TM); + } + + giveup_altivec(tsk); +} + +#else +#define giveup_fpu_maybe_transactional(tsk) giveup_fpu(tsk) +#define giveup_altivec_maybe_transactional(tsk) giveup_altivec(tsk) +#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ + #ifdef CONFIG_PPC_FPU /* * Make sure the floating-point register state in the @@ -102,13 +143,13 @@ void flush_fp_to_thread(struct task_struct *tsk) */ BUG_ON(tsk != current); #endif - giveup_fpu(tsk); + giveup_fpu_maybe_transactional(tsk); } preempt_enable(); } } EXPORT_SYMBOL_GPL(flush_fp_to_thread); -#endif +#endif /* CONFIG_PPC_FPU */ void enable_kernel_fp(void) { @@ -116,11 +157,11 @@ void enable_kernel_fp(void) #ifdef CONFIG_SMP if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) - giveup_fpu(current); + giveup_fpu_maybe_transactional(current); else giveup_fpu(NULL); /* just enables FP for kernel */ #else - giveup_fpu(last_task_used_math); + giveup_fpu_maybe_transactional(last_task_used_math); #endif /* CONFIG_SMP */ } EXPORT_SYMBOL(enable_kernel_fp); @@ -132,11 +173,11 @@ void enable_kernel_altivec(void) #ifdef CONFIG_SMP if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) - giveup_altivec(current); + giveup_altivec_maybe_transactional(current); else giveup_altivec_notask(); #else - giveup_altivec(last_task_used_altivec); + giveup_altivec_maybe_transactional(last_task_used_altivec); #endif /* CONFIG_SMP */ } EXPORT_SYMBOL(enable_kernel_altivec); @@ -153,7 +194,7 @@ void flush_altivec_to_thread(struct task_struct *tsk) #ifdef CONFIG_SMP BUG_ON(tsk != current); #endif - giveup_altivec(tsk); + giveup_altivec_maybe_transactional(tsk); } preempt_enable(); } @@ -182,8 +223,8 @@ EXPORT_SYMBOL(enable_kernel_vsx); void giveup_vsx(struct task_struct *tsk) { - giveup_fpu(tsk); - giveup_altivec(tsk); + giveup_fpu_maybe_transactional(tsk); + giveup_altivec_maybe_transactional(tsk); __giveup_vsx(tsk); } @@ -479,7 +520,48 @@ static inline bool hw_brk_match(struct arch_hw_breakpoint *a, return false; return true; } + #ifdef CONFIG_PPC_TRANSACTIONAL_MEM +static void tm_reclaim_thread(struct thread_struct *thr, + struct thread_info *ti, uint8_t cause) +{ + unsigned long msr_diff = 0; + + /* + * If FP/VSX registers have been already saved to the + * thread_struct, move them to the transact_fp array. + * We clear the TIF_RESTORE_TM bit since after the reclaim + * the thread will no longer be transactional. + */ + if (test_ti_thread_flag(ti, TIF_RESTORE_TM)) { + msr_diff = thr->tm_orig_msr & ~thr->regs->msr; + if (msr_diff & MSR_FP) + memcpy(&thr->transact_fp, &thr->fp_state, + sizeof(struct thread_fp_state)); + if (msr_diff & MSR_VEC) + memcpy(&thr->transact_vr, &thr->vr_state, + sizeof(struct thread_vr_state)); + clear_ti_thread_flag(ti, TIF_RESTORE_TM); + msr_diff &= MSR_FP | MSR_VEC | MSR_VSX | MSR_FE0 | MSR_FE1; + } + + tm_reclaim(thr, thr->regs->msr, cause); + + /* Having done the reclaim, we now have the checkpointed + * FP/VSX values in the registers. These might be valid + * even if we have previously called enable_kernel_fp() or + * flush_fp_to_thread(), so update thr->regs->msr to + * indicate their current validity. + */ + thr->regs->msr |= msr_diff; +} + +void tm_reclaim_current(uint8_t cause) +{ + tm_enable(); + tm_reclaim_thread(¤t->thread, current_thread_info(), cause); +} + static inline void tm_reclaim_task(struct task_struct *tsk) { /* We have to work out if we're switching from/to a task that's in the @@ -502,9 +584,11 @@ static inline void tm_reclaim_task(struct task_struct *tsk) /* Stash the original thread MSR, as giveup_fpu et al will * modify it. We hold onto it to see whether the task used - * FP & vector regs. + * FP & vector regs. If the TIF_RESTORE_TM flag is set, + * tm_orig_msr is already set. */ - thr->tm_orig_msr = thr->regs->msr; + if (!test_ti_thread_flag(task_thread_info(tsk), TIF_RESTORE_TM)) + thr->tm_orig_msr = thr->regs->msr; TM_DEBUG("--- tm_reclaim on pid %d (NIP=%lx, " "ccr=%lx, msr=%lx, trap=%lx)\n", @@ -512,7 +596,7 @@ static inline void tm_reclaim_task(struct task_struct *tsk) thr->regs->ccr, thr->regs->msr, thr->regs->trap); - tm_reclaim(thr, thr->regs->msr, TM_CAUSE_RESCHED); + tm_reclaim_thread(thr, task_thread_info(tsk), TM_CAUSE_RESCHED); TM_DEBUG("--- tm_reclaim on pid %d complete\n", tsk->pid); @@ -588,6 +672,43 @@ static inline void __switch_to_tm(struct task_struct *prev) tm_reclaim_task(prev); } } + +/* + * This is called if we are on the way out to userspace and the + * TIF_RESTORE_TM flag is set. It checks if we need to reload + * FP and/or vector state and does so if necessary. + * If userspace is inside a transaction (whether active or + * suspended) and FP/VMX/VSX instructions have ever been enabled + * inside that transaction, then we have to keep them enabled + * and keep the FP/VMX/VSX state loaded while ever the transaction + * continues. The reason is that if we didn't, and subsequently + * got a FP/VMX/VSX unavailable interrupt inside a transaction, + * we don't know whether it's the same transaction, and thus we + * don't know which of the checkpointed state and the transactional + * state to use. + */ +void restore_tm_state(struct pt_regs *regs) +{ + unsigned long msr_diff; + + clear_thread_flag(TIF_RESTORE_TM); + if (!MSR_TM_ACTIVE(regs->msr)) + return; + + msr_diff = current->thread.tm_orig_msr & ~regs->msr; + msr_diff &= MSR_FP | MSR_VEC | MSR_VSX; + if (msr_diff & MSR_FP) { + fp_enable(); + load_fp_state(¤t->thread.fp_state); + regs->msr |= current->thread.fpexc_mode; + } + if (msr_diff & MSR_VEC) { + vec_enable(); + load_vr_state(¤t->thread.vr_state); + } + regs->msr |= msr_diff; +} + #else #define tm_recheckpoint_new_task(new) #define __switch_to_tm(prev) @@ -690,7 +811,7 @@ struct task_struct *__switch_to(struct task_struct *prev, * schedule DABR */ #ifndef CONFIG_HAVE_HW_BREAKPOINT - if (unlikely(hw_brk_match(&__get_cpu_var(current_brk), &new->thread.hw_brk))) + if (unlikely(!hw_brk_match(&__get_cpu_var(current_brk), &new->thread.hw_brk))) set_breakpoint(&new->thread.hw_brk); #endif /* CONFIG_HAVE_HW_BREAKPOINT */ #endif @@ -1175,6 +1296,19 @@ int set_fpexc_mode(struct task_struct *tsk, unsigned int val) if (val & PR_FP_EXC_SW_ENABLE) { #ifdef CONFIG_SPE if (cpu_has_feature(CPU_FTR_SPE)) { + /* + * When the sticky exception bits are set + * directly by userspace, it must call prctl + * with PR_GET_FPEXC (with PR_FP_EXC_SW_ENABLE + * in the existing prctl settings) or + * PR_SET_FPEXC (with PR_FP_EXC_SW_ENABLE in + * the bits being set). functions + * saving and restoring the whole + * floating-point environment need to do so + * anyway to restore the prctl settings from + * the saved environment. + */ + tsk->thread.spefscr_last = mfspr(SPRN_SPEFSCR); tsk->thread.fpexc_mode = val & (PR_FP_EXC_SW_ENABLE | PR_FP_ALL_EXCEPT); return 0; @@ -1206,9 +1340,22 @@ int get_fpexc_mode(struct task_struct *tsk, unsigned long adr) if (tsk->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE) #ifdef CONFIG_SPE - if (cpu_has_feature(CPU_FTR_SPE)) + if (cpu_has_feature(CPU_FTR_SPE)) { + /* + * When the sticky exception bits are set + * directly by userspace, it must call prctl + * with PR_GET_FPEXC (with PR_FP_EXC_SW_ENABLE + * in the existing prctl settings) or + * PR_SET_FPEXC (with PR_FP_EXC_SW_ENABLE in + * the bits being set). functions + * saving and restoring the whole + * floating-point environment need to do so + * anyway to restore the prctl settings from + * the saved environment. + */ + tsk->thread.spefscr_last = mfspr(SPRN_SPEFSCR); val = tsk->thread.fpexc_mode; - else + } else return -EINVAL; #else return -EINVAL; diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index fa0ad8aafbccf3..f58c0d3aaeb497 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -523,6 +523,20 @@ static int __init early_init_dt_scan_memory_ppc(unsigned long node, return early_init_dt_scan_memory(node, uname, depth, data); } +/* + * For a relocatable kernel, we need to get the memstart_addr first, + * then use it to calculate the virtual kernel start address. This has + * to happen at a very early stage (before machine_init). In this case, + * we just want to get the memstart_address and would not like to mess the + * memblock at this stage. So introduce a variable to skip the memblock_add() + * for this reason. + */ +#ifdef CONFIG_RELOCATABLE +static int add_mem_to_memblock = 1; +#else +#define add_mem_to_memblock 1 +#endif + void __init early_init_dt_add_memory_arch(u64 base, u64 size) { #ifdef CONFIG_PPC64 @@ -543,7 +557,8 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) } /* Add the chunk to the MEMBLOCK list */ - memblock_add(base, size); + if (add_mem_to_memblock) + memblock_add(base, size); } static void __init early_reserve_mem_dt(void) @@ -740,6 +755,30 @@ void __init early_init_devtree(void *params) DBG(" <- early_init_devtree()\n"); } +#ifdef CONFIG_RELOCATABLE +/* + * This function run before early_init_devtree, so we have to init + * initial_boot_params. + */ +void __init early_get_first_memblock_info(void *params, phys_addr_t *size) +{ + /* Setup flat device-tree pointer */ + initial_boot_params = params; + + /* + * Scan the memory nodes and set add_mem_to_memblock to 0 to avoid + * mess the memblock. + */ + add_mem_to_memblock = 0; + of_scan_flat_dt(early_init_dt_scan_root, NULL); + of_scan_flat_dt(early_init_dt_scan_memory_ppc, NULL); + add_mem_to_memblock = 1; + + if (size) + *size = first_memblock_size; +} +#endif + /******* * * New implementation of the OF "find" APIs, return a refcounted diff --git a/arch/powerpc/kernel/reloc_64.S b/arch/powerpc/kernel/reloc_64.S index b47a0e1ab00150..1482327cfeba9c 100644 --- a/arch/powerpc/kernel/reloc_64.S +++ b/arch/powerpc/kernel/reloc_64.S @@ -69,8 +69,8 @@ _GLOBAL(relocate) * R_PPC64_RELATIVE ones. */ mtctr r8 -5: lwz r0,12(9) /* ELF64_R_TYPE(reloc->r_info) */ - cmpwi r0,R_PPC64_RELATIVE +5: ld r0,8(9) /* ELF64_R_TYPE(reloc->r_info) */ + cmpdi r0,R_PPC64_RELATIVE bne 6f ld r6,0(r9) /* reloc->r_offset */ ld r0,16(r9) /* reloc->r_addend */ diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 2b0da27eaee424..04cc4fcca78b69 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -247,7 +247,12 @@ static void __init exc_lvl_early_init(void) /* interrupt stacks must be in lowmem, we get that for free on ppc32 * as the memblock is limited to lowmem by MEMBLOCK_REAL_LIMIT */ for_each_possible_cpu(i) { +#ifdef CONFIG_SMP hw_cpu = get_hard_smp_processor_id(i); +#else + hw_cpu = 0; +#endif + critirq_ctx[hw_cpu] = (struct thread_info *) __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); #ifdef CONFIG_BOOKE diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 856dd4e99bfe45..f5f11a7d30e550 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -97,6 +97,36 @@ int dcache_bsize; int icache_bsize; int ucache_bsize; +#if defined(CONFIG_PPC_BOOK3E) && defined(CONFIG_SMP) +static void setup_tlb_core_data(void) +{ + int cpu; + + for_each_possible_cpu(cpu) { + int first = cpu_first_thread_sibling(cpu); + + paca[cpu].tcd_ptr = &paca[first].tcd; + + /* + * If we have threads, we need either tlbsrx. + * or e6500 tablewalk mode, or else TLB handlers + * will be racy and could produce duplicate entries. + */ + if (smt_enabled_at_boot >= 2 && + !mmu_has_feature(MMU_FTR_USE_TLBRSRV) && + book3e_htw_mode != PPC_HTW_E6500) { + /* Should we panic instead? */ + WARN_ONCE("%s: unsupported MMU configuration -- expect problems\n", + __func__); + } + } +} +#else +static void setup_tlb_core_data(void) +{ +} +#endif + #ifdef CONFIG_SMP static char *smt_enabled_cmdline; @@ -445,6 +475,7 @@ void __init setup_system(void) smp_setup_cpu_maps(); check_smt_enabled(); + setup_tlb_core_data(); #ifdef CONFIG_SMP /* Release secondary cpus out of their spinloops at 0x60 now that @@ -520,9 +551,6 @@ static void __init irqstack_early_init(void) #ifdef CONFIG_PPC_BOOK3E static void __init exc_lvl_early_init(void) { - extern unsigned int interrupt_base_book3e; - extern unsigned int exc_debug_debug_book3e; - unsigned int i; for_each_possible_cpu(i) { @@ -535,8 +563,7 @@ static void __init exc_lvl_early_init(void) } if (cpu_has_feature(CPU_FTR_DEBUG_LVL_EXC)) - patch_branch(&interrupt_base_book3e + (0x040 / 4) + 1, - (unsigned long)&exc_debug_debug_book3e, 0); + patch_exception(0x040, exc_debug_debug_book3e); } #else #define exc_lvl_early_init() @@ -544,7 +571,8 @@ static void __init exc_lvl_early_init(void) /* * Stack space used when we detect a bad kernel stack pointer, and - * early in SMP boots before relocation is enabled. + * early in SMP boots before relocation is enabled. Exclusive emergency + * stack for machine checks. */ static void __init emergency_stack_init(void) { @@ -567,6 +595,13 @@ static void __init emergency_stack_init(void) sp = memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit); sp += THREAD_SIZE; paca[i].emergency_sp = __va(sp); + +#ifdef CONFIG_PPC_BOOK3S_64 + /* emergency stack for machine check exception handling. */ + sp = memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit); + sp += THREAD_SIZE; + paca[i].mc_emergency_sp = __va(sp); +#endif } } diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index 457e97aa29455e..8fc4177ed65acb 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -203,8 +203,7 @@ unsigned long get_tm_stackpointer(struct pt_regs *regs) #ifdef CONFIG_PPC_TRANSACTIONAL_MEM if (MSR_TM_ACTIVE(regs->msr)) { - tm_enable(); - tm_reclaim(¤t->thread, regs->msr, TM_CAUSE_SIGNAL); + tm_reclaim_current(TM_CAUSE_SIGNAL); if (MSR_TM_TRANSACTIONAL(regs->msr)) return current->thread.ckpt_regs.gpr[1]; } diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 68027bfa5f8e3c..a67e00aa3caad1 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -519,6 +519,13 @@ static int save_tm_user_regs(struct pt_regs *regs, { unsigned long msr = regs->msr; + /* Remove TM bits from thread's MSR. The MSR in the sigcontext + * just indicates to userland that we were doing a transaction, but we + * don't want to return in transactional state. This also ensures + * that flush_fp_to_thread won't set TIF_RESTORE_TM again. + */ + regs->msr &= ~MSR_TS_MASK; + /* Make sure floating point registers are stored in regs */ flush_fp_to_thread(current); @@ -1015,29 +1022,24 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, #ifdef CONFIG_PPC_TRANSACTIONAL_MEM tm_frame = &rt_sf->uc_transact.uc_mcontext; if (MSR_TM_ACTIVE(regs->msr)) { + if (__put_user((unsigned long)&rt_sf->uc_transact, + &rt_sf->uc.uc_link) || + __put_user((unsigned long)tm_frame, + &rt_sf->uc_transact.uc_regs)) + goto badframe; if (save_tm_user_regs(regs, frame, tm_frame, sigret)) goto badframe; } else #endif { + if (__put_user(0, &rt_sf->uc.uc_link)) + goto badframe; if (save_user_regs(regs, frame, tm_frame, sigret, 1)) goto badframe; } regs->link = tramp; -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - if (MSR_TM_ACTIVE(regs->msr)) { - if (__put_user((unsigned long)&rt_sf->uc_transact, - &rt_sf->uc.uc_link) - || __put_user((unsigned long)tm_frame, &rt_sf->uc_transact.uc_regs)) - goto badframe; - } - else -#endif - if (__put_user(0, &rt_sf->uc.uc_link)) - goto badframe; - current->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */ /* create a stack frame for the caller of the handler */ @@ -1056,13 +1058,6 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, /* enter the signal handler in native-endian mode */ regs->msr &= ~MSR_LE; regs->msr |= (MSR_KERNEL & MSR_LE); -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - /* Remove TM bits from thread's MSR. The MSR in the sigcontext - * just indicates to userland that we were doing a transaction, but we - * don't want to return in transactional state: - */ - regs->msr &= ~MSR_TS_MASK; -#endif return 1; badframe: @@ -1484,13 +1479,6 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka, regs->nip = (unsigned long) ka->sa.sa_handler; /* enter the signal handler in big-endian mode */ regs->msr &= ~MSR_LE; -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - /* Remove TM bits from thread's MSR. The MSR in the sigcontext - * just indicates to userland that we were doing a transaction, but we - * don't want to return in transactional state: - */ - regs->msr &= ~MSR_TS_MASK; -#endif return 1; badframe: diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 42991045349f81..e35bf773df7a8d 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -192,6 +192,13 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, BUG_ON(!MSR_TM_ACTIVE(regs->msr)); + /* Remove TM bits from thread's MSR. The MSR in the sigcontext + * just indicates to userland that we were doing a transaction, but we + * don't want to return in transactional state. This also ensures + * that flush_fp_to_thread won't set TIF_RESTORE_TM again. + */ + regs->msr &= ~MSR_TS_MASK; + flush_fp_to_thread(current); #ifdef CONFIG_ALTIVEC @@ -749,13 +756,6 @@ int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info, /* Make sure signal handler doesn't get spurious FP exceptions */ current->thread.fp_state.fpscr = 0; -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - /* Remove TM bits from thread's MSR. The MSR in the sigcontext - * just indicates to userland that we were doing a transaction, but we - * don't want to return in transactional state: - */ - regs->msr &= ~MSR_TS_MASK; -#endif /* Set up to return from userspace. */ if (vdso64_rt_sigtramp && current->mm->context.vdso_base) { diff --git a/arch/powerpc/kernel/smp-tbsync.c b/arch/powerpc/kernel/smp-tbsync.c index e68fd1ae727a56..7a37ecd3afa3b2 100644 --- a/arch/powerpc/kernel/smp-tbsync.c +++ b/arch/powerpc/kernel/smp-tbsync.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index c1cf4a1522d994..ac2621af31545b 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -369,13 +369,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus) cpumask_set_cpu(boot_cpuid, cpu_sibling_mask(boot_cpuid)); cpumask_set_cpu(boot_cpuid, cpu_core_mask(boot_cpuid)); - if (smp_ops) - if (smp_ops->probe) - max_cpus = smp_ops->probe(); - else - max_cpus = NR_CPUS; - else - max_cpus = 1; + if (smp_ops && smp_ops->probe) + smp_ops->probe(); } void smp_prepare_boot_cpu(void) diff --git a/arch/powerpc/kernel/swsusp_booke.S b/arch/powerpc/kernel/swsusp_booke.S index 0f204053e5b5a4..553c1405ee0577 100644 --- a/arch/powerpc/kernel/swsusp_booke.S +++ b/arch/powerpc/kernel/swsusp_booke.S @@ -74,21 +74,21 @@ _GLOBAL(swsusp_arch_suspend) bne 1b /* Save SPRGs */ - mfsprg r4,0 + mfspr r4,SPRN_SPRG0 stw r4,SL_SPRG0(r11) - mfsprg r4,1 + mfspr r4,SPRN_SPRG1 stw r4,SL_SPRG1(r11) - mfsprg r4,2 + mfspr r4,SPRN_SPRG2 stw r4,SL_SPRG2(r11) - mfsprg r4,3 + mfspr r4,SPRN_SPRG3 stw r4,SL_SPRG3(r11) - mfsprg r4,4 + mfspr r4,SPRN_SPRG4 stw r4,SL_SPRG4(r11) - mfsprg r4,5 + mfspr r4,SPRN_SPRG5 stw r4,SL_SPRG5(r11) - mfsprg r4,6 + mfspr r4,SPRN_SPRG6 stw r4,SL_SPRG6(r11) - mfsprg r4,7 + mfspr r4,SPRN_SPRG7 stw r4,SL_SPRG7(r11) /* Call the low level suspend stuff (we should probably have made @@ -150,21 +150,21 @@ _GLOBAL(swsusp_arch_resume) bl _tlbil_all lwz r4,SL_SPRG0(r11) - mtsprg 0,r4 + mtspr SPRN_SPRG0,r4 lwz r4,SL_SPRG1(r11) - mtsprg 1,r4 + mtspr SPRN_SPRG1,r4 lwz r4,SL_SPRG2(r11) - mtsprg 2,r4 + mtspr SPRN_SPRG2,r4 lwz r4,SL_SPRG3(r11) - mtsprg 3,r4 + mtspr SPRN_SPRG3,r4 lwz r4,SL_SPRG4(r11) - mtsprg 4,r4 + mtspr SPRN_SPRG4,r4 lwz r4,SL_SPRG5(r11) - mtsprg 5,r4 + mtspr SPRN_SPRG5,r4 lwz r4,SL_SPRG6(r11) - mtsprg 6,r4 + mtspr SPRN_SPRG6,r4 lwz r4,SL_SPRG7(r11) - mtsprg 7,r4 + mtspr SPRN_SPRG7,r4 /* restore the MSR */ lwz r3,SL_MSR(r11) diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c index 4e3cc47f26b90e..cd9be9aa016d18 100644 --- a/arch/powerpc/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index b4e667663d9bfc..97e1dc91768374 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -51,8 +51,6 @@ static ssize_t store_smt_snooze_delay(struct device *dev, return -EINVAL; per_cpu(smt_snooze_delay, cpu->dev.id) = snooze; - update_smt_snooze_delay(cpu->dev.id, snooze); - return count; } @@ -86,6 +84,304 @@ __setup("smt-snooze-delay=", setup_smt_snooze_delay); #endif /* CONFIG_PPC64 */ +#ifdef CONFIG_PPC_FSL_BOOK3E +#define MAX_BIT 63 + +static u64 pw20_wt; +static u64 altivec_idle_wt; + +static unsigned int get_idle_ticks_bit(u64 ns) +{ + u64 cycle; + + if (ns >= 10000) + cycle = div_u64(ns + 500, 1000) * tb_ticks_per_usec; + else + cycle = div_u64(ns * tb_ticks_per_usec, 1000); + + if (!cycle) + return 0; + + return ilog2(cycle); +} + +static void do_show_pwrmgtcr0(void *val) +{ + u32 *value = val; + + *value = mfspr(SPRN_PWRMGTCR0); +} + +static ssize_t show_pw20_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 value; + unsigned int cpu = dev->id; + + smp_call_function_single(cpu, do_show_pwrmgtcr0, &value, 1); + + value &= PWRMGTCR0_PW20_WAIT; + + return sprintf(buf, "%u\n", value ? 1 : 0); +} + +static void do_store_pw20_state(void *val) +{ + u32 *value = val; + u32 pw20_state; + + pw20_state = mfspr(SPRN_PWRMGTCR0); + + if (*value) + pw20_state |= PWRMGTCR0_PW20_WAIT; + else + pw20_state &= ~PWRMGTCR0_PW20_WAIT; + + mtspr(SPRN_PWRMGTCR0, pw20_state); +} + +static ssize_t store_pw20_state(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 value; + unsigned int cpu = dev->id; + + if (kstrtou32(buf, 0, &value)) + return -EINVAL; + + if (value > 1) + return -EINVAL; + + smp_call_function_single(cpu, do_store_pw20_state, &value, 1); + + return count; +} + +static ssize_t show_pw20_wait_time(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 value; + u64 tb_cycle = 1; + u64 time; + + unsigned int cpu = dev->id; + + if (!pw20_wt) { + smp_call_function_single(cpu, do_show_pwrmgtcr0, &value, 1); + value = (value & PWRMGTCR0_PW20_ENT) >> + PWRMGTCR0_PW20_ENT_SHIFT; + + tb_cycle = (tb_cycle << (MAX_BIT - value + 1)); + /* convert ms to ns */ + if (tb_ticks_per_usec > 1000) { + time = div_u64(tb_cycle, tb_ticks_per_usec / 1000); + } else { + u32 rem_us; + + time = div_u64_rem(tb_cycle, tb_ticks_per_usec, + &rem_us); + time = time * 1000 + rem_us * 1000 / tb_ticks_per_usec; + } + } else { + time = pw20_wt; + } + + return sprintf(buf, "%llu\n", time > 0 ? time : 0); +} + +static void set_pw20_wait_entry_bit(void *val) +{ + u32 *value = val; + u32 pw20_idle; + + pw20_idle = mfspr(SPRN_PWRMGTCR0); + + /* Set Automatic PW20 Core Idle Count */ + /* clear count */ + pw20_idle &= ~PWRMGTCR0_PW20_ENT; + + /* set count */ + pw20_idle |= ((MAX_BIT - *value) << PWRMGTCR0_PW20_ENT_SHIFT); + + mtspr(SPRN_PWRMGTCR0, pw20_idle); +} + +static ssize_t store_pw20_wait_time(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 entry_bit; + u64 value; + + unsigned int cpu = dev->id; + + if (kstrtou64(buf, 0, &value)) + return -EINVAL; + + if (!value) + return -EINVAL; + + entry_bit = get_idle_ticks_bit(value); + if (entry_bit > MAX_BIT) + return -EINVAL; + + pw20_wt = value; + + smp_call_function_single(cpu, set_pw20_wait_entry_bit, + &entry_bit, 1); + + return count; +} + +static ssize_t show_altivec_idle(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 value; + unsigned int cpu = dev->id; + + smp_call_function_single(cpu, do_show_pwrmgtcr0, &value, 1); + + value &= PWRMGTCR0_AV_IDLE_PD_EN; + + return sprintf(buf, "%u\n", value ? 1 : 0); +} + +static void do_store_altivec_idle(void *val) +{ + u32 *value = val; + u32 altivec_idle; + + altivec_idle = mfspr(SPRN_PWRMGTCR0); + + if (*value) + altivec_idle |= PWRMGTCR0_AV_IDLE_PD_EN; + else + altivec_idle &= ~PWRMGTCR0_AV_IDLE_PD_EN; + + mtspr(SPRN_PWRMGTCR0, altivec_idle); +} + +static ssize_t store_altivec_idle(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 value; + unsigned int cpu = dev->id; + + if (kstrtou32(buf, 0, &value)) + return -EINVAL; + + if (value > 1) + return -EINVAL; + + smp_call_function_single(cpu, do_store_altivec_idle, &value, 1); + + return count; +} + +static ssize_t show_altivec_idle_wait_time(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 value; + u64 tb_cycle = 1; + u64 time; + + unsigned int cpu = dev->id; + + if (!altivec_idle_wt) { + smp_call_function_single(cpu, do_show_pwrmgtcr0, &value, 1); + value = (value & PWRMGTCR0_AV_IDLE_CNT) >> + PWRMGTCR0_AV_IDLE_CNT_SHIFT; + + tb_cycle = (tb_cycle << (MAX_BIT - value + 1)); + /* convert ms to ns */ + if (tb_ticks_per_usec > 1000) { + time = div_u64(tb_cycle, tb_ticks_per_usec / 1000); + } else { + u32 rem_us; + + time = div_u64_rem(tb_cycle, tb_ticks_per_usec, + &rem_us); + time = time * 1000 + rem_us * 1000 / tb_ticks_per_usec; + } + } else { + time = altivec_idle_wt; + } + + return sprintf(buf, "%llu\n", time > 0 ? time : 0); +} + +static void set_altivec_idle_wait_entry_bit(void *val) +{ + u32 *value = val; + u32 altivec_idle; + + altivec_idle = mfspr(SPRN_PWRMGTCR0); + + /* Set Automatic AltiVec Idle Count */ + /* clear count */ + altivec_idle &= ~PWRMGTCR0_AV_IDLE_CNT; + + /* set count */ + altivec_idle |= ((MAX_BIT - *value) << PWRMGTCR0_AV_IDLE_CNT_SHIFT); + + mtspr(SPRN_PWRMGTCR0, altivec_idle); +} + +static ssize_t store_altivec_idle_wait_time(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 entry_bit; + u64 value; + + unsigned int cpu = dev->id; + + if (kstrtou64(buf, 0, &value)) + return -EINVAL; + + if (!value) + return -EINVAL; + + entry_bit = get_idle_ticks_bit(value); + if (entry_bit > MAX_BIT) + return -EINVAL; + + altivec_idle_wt = value; + + smp_call_function_single(cpu, set_altivec_idle_wait_entry_bit, + &entry_bit, 1); + + return count; +} + +/* + * Enable/Disable interface: + * 0, disable. 1, enable. + */ +static DEVICE_ATTR(pw20_state, 0600, show_pw20_state, store_pw20_state); +static DEVICE_ATTR(altivec_idle, 0600, show_altivec_idle, store_altivec_idle); + +/* + * Set wait time interface:(Nanosecond) + * Example: Base on TBfreq is 41MHZ. + * 1~48(ns): TB[63] + * 49~97(ns): TB[62] + * 98~195(ns): TB[61] + * 196~390(ns): TB[60] + * 391~780(ns): TB[59] + * 781~1560(ns): TB[58] + * ... + */ +static DEVICE_ATTR(pw20_wait_time, 0600, + show_pw20_wait_time, + store_pw20_wait_time); +static DEVICE_ATTR(altivec_idle_wait_time, 0600, + show_altivec_idle_wait_time, + store_altivec_idle_wait_time); +#endif + /* * Enabling PMCs will slow partition context switch times so we only do * it the first time we write to the PMCs. @@ -108,14 +404,14 @@ void ppc_enable_pmcs(void) } EXPORT_SYMBOL(ppc_enable_pmcs); -#define SYSFS_PMCSETUP(NAME, ADDRESS) \ +#define __SYSFS_SPRSETUP(NAME, ADDRESS, EXTRA) \ static void read_##NAME(void *val) \ { \ *(unsigned long *)val = mfspr(ADDRESS); \ } \ static void write_##NAME(void *val) \ { \ - ppc_enable_pmcs(); \ + EXTRA; \ mtspr(ADDRESS, *(unsigned long *)val); \ } \ static ssize_t show_##NAME(struct device *dev, \ @@ -140,6 +436,10 @@ static ssize_t __used \ return count; \ } +#define SYSFS_PMCSETUP(NAME, ADDRESS) \ + __SYSFS_SPRSETUP(NAME, ADDRESS, ppc_enable_pmcs()) +#define SYSFS_SPRSETUP(NAME, ADDRESS) \ + __SYSFS_SPRSETUP(NAME, ADDRESS, ) /* Let's define all possible registers, we'll only hook up the ones * that are implemented on the current processor @@ -175,10 +475,10 @@ SYSFS_PMCSETUP(pmc7, SPRN_PMC7); SYSFS_PMCSETUP(pmc8, SPRN_PMC8); SYSFS_PMCSETUP(mmcra, SPRN_MMCRA); -SYSFS_PMCSETUP(purr, SPRN_PURR); -SYSFS_PMCSETUP(spurr, SPRN_SPURR); -SYSFS_PMCSETUP(dscr, SPRN_DSCR); -SYSFS_PMCSETUP(pir, SPRN_PIR); +SYSFS_SPRSETUP(purr, SPRN_PURR); +SYSFS_SPRSETUP(spurr, SPRN_SPURR); +SYSFS_SPRSETUP(dscr, SPRN_DSCR); +SYSFS_SPRSETUP(pir, SPRN_PIR); /* Lets only enable read for phyp resources and @@ -249,34 +549,34 @@ SYSFS_PMCSETUP(pa6t_pmc3, SPRN_PA6T_PMC3); SYSFS_PMCSETUP(pa6t_pmc4, SPRN_PA6T_PMC4); SYSFS_PMCSETUP(pa6t_pmc5, SPRN_PA6T_PMC5); #ifdef CONFIG_DEBUG_KERNEL -SYSFS_PMCSETUP(hid0, SPRN_HID0); -SYSFS_PMCSETUP(hid1, SPRN_HID1); -SYSFS_PMCSETUP(hid4, SPRN_HID4); -SYSFS_PMCSETUP(hid5, SPRN_HID5); -SYSFS_PMCSETUP(ima0, SPRN_PA6T_IMA0); -SYSFS_PMCSETUP(ima1, SPRN_PA6T_IMA1); -SYSFS_PMCSETUP(ima2, SPRN_PA6T_IMA2); -SYSFS_PMCSETUP(ima3, SPRN_PA6T_IMA3); -SYSFS_PMCSETUP(ima4, SPRN_PA6T_IMA4); -SYSFS_PMCSETUP(ima5, SPRN_PA6T_IMA5); -SYSFS_PMCSETUP(ima6, SPRN_PA6T_IMA6); -SYSFS_PMCSETUP(ima7, SPRN_PA6T_IMA7); -SYSFS_PMCSETUP(ima8, SPRN_PA6T_IMA8); -SYSFS_PMCSETUP(ima9, SPRN_PA6T_IMA9); -SYSFS_PMCSETUP(imaat, SPRN_PA6T_IMAAT); -SYSFS_PMCSETUP(btcr, SPRN_PA6T_BTCR); -SYSFS_PMCSETUP(pccr, SPRN_PA6T_PCCR); -SYSFS_PMCSETUP(rpccr, SPRN_PA6T_RPCCR); -SYSFS_PMCSETUP(der, SPRN_PA6T_DER); -SYSFS_PMCSETUP(mer, SPRN_PA6T_MER); -SYSFS_PMCSETUP(ber, SPRN_PA6T_BER); -SYSFS_PMCSETUP(ier, SPRN_PA6T_IER); -SYSFS_PMCSETUP(sier, SPRN_PA6T_SIER); -SYSFS_PMCSETUP(siar, SPRN_PA6T_SIAR); -SYSFS_PMCSETUP(tsr0, SPRN_PA6T_TSR0); -SYSFS_PMCSETUP(tsr1, SPRN_PA6T_TSR1); -SYSFS_PMCSETUP(tsr2, SPRN_PA6T_TSR2); -SYSFS_PMCSETUP(tsr3, SPRN_PA6T_TSR3); +SYSFS_SPRSETUP(hid0, SPRN_HID0); +SYSFS_SPRSETUP(hid1, SPRN_HID1); +SYSFS_SPRSETUP(hid4, SPRN_HID4); +SYSFS_SPRSETUP(hid5, SPRN_HID5); +SYSFS_SPRSETUP(ima0, SPRN_PA6T_IMA0); +SYSFS_SPRSETUP(ima1, SPRN_PA6T_IMA1); +SYSFS_SPRSETUP(ima2, SPRN_PA6T_IMA2); +SYSFS_SPRSETUP(ima3, SPRN_PA6T_IMA3); +SYSFS_SPRSETUP(ima4, SPRN_PA6T_IMA4); +SYSFS_SPRSETUP(ima5, SPRN_PA6T_IMA5); +SYSFS_SPRSETUP(ima6, SPRN_PA6T_IMA6); +SYSFS_SPRSETUP(ima7, SPRN_PA6T_IMA7); +SYSFS_SPRSETUP(ima8, SPRN_PA6T_IMA8); +SYSFS_SPRSETUP(ima9, SPRN_PA6T_IMA9); +SYSFS_SPRSETUP(imaat, SPRN_PA6T_IMAAT); +SYSFS_SPRSETUP(btcr, SPRN_PA6T_BTCR); +SYSFS_SPRSETUP(pccr, SPRN_PA6T_PCCR); +SYSFS_SPRSETUP(rpccr, SPRN_PA6T_RPCCR); +SYSFS_SPRSETUP(der, SPRN_PA6T_DER); +SYSFS_SPRSETUP(mer, SPRN_PA6T_MER); +SYSFS_SPRSETUP(ber, SPRN_PA6T_BER); +SYSFS_SPRSETUP(ier, SPRN_PA6T_IER); +SYSFS_SPRSETUP(sier, SPRN_PA6T_SIER); +SYSFS_SPRSETUP(siar, SPRN_PA6T_SIAR); +SYSFS_SPRSETUP(tsr0, SPRN_PA6T_TSR0); +SYSFS_SPRSETUP(tsr1, SPRN_PA6T_TSR1); +SYSFS_SPRSETUP(tsr2, SPRN_PA6T_TSR2); +SYSFS_SPRSETUP(tsr3, SPRN_PA6T_TSR3); #endif /* CONFIG_DEBUG_KERNEL */ #endif /* HAS_PPC_PMC_PA6T */ @@ -421,6 +721,15 @@ static void register_cpu_online(unsigned int cpu) device_create_file(s, &dev_attr_pir); #endif /* CONFIG_PPC64 */ +#ifdef CONFIG_PPC_FSL_BOOK3E + if (PVR_VER(cur_cpu_spec->pvr_value) == PVR_VER_E6500) { + device_create_file(s, &dev_attr_pw20_state); + device_create_file(s, &dev_attr_pw20_wait_time); + + device_create_file(s, &dev_attr_altivec_idle); + device_create_file(s, &dev_attr_altivec_idle_wait_time); + } +#endif cacheinfo_cpu_online(cpu); } @@ -493,6 +802,15 @@ static void unregister_cpu_online(unsigned int cpu) device_remove_file(s, &dev_attr_pir); #endif /* CONFIG_PPC64 */ +#ifdef CONFIG_PPC_FSL_BOOK3E + if (PVR_VER(cur_cpu_spec->pvr_value) == PVR_VER_E6500) { + device_remove_file(s, &dev_attr_pw20_state); + device_remove_file(s, &dev_attr_pw20_wait_time); + + device_remove_file(s, &dev_attr_altivec_idle); + device_remove_file(s, &dev_attr_altivec_idle_wait_time); + } +#endif cacheinfo_cpu_offline(cpu); } diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index b3b144121cc99d..b3dab20acf34ab 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -510,7 +510,6 @@ void timer_interrupt(struct pt_regs * regs) */ may_hard_irq_enable(); - __get_cpu_var(irq_stat).timer_irqs++; #if defined(CONFIG_PPC32) && defined(CONFIG_PMAC) if (atomic_read(&ppc_n_lost_interrupts) != 0) @@ -532,10 +531,15 @@ void timer_interrupt(struct pt_regs * regs) *next_tb = ~(u64)0; if (evt->event_handler) evt->event_handler(evt); + __get_cpu_var(irq_stat).timer_irqs_event++; } else { now = *next_tb - now; if (now <= DECREMENTER_MAX) set_dec((int)now); + /* We may have raced with new irq work */ + if (test_irq_work_pending()) + set_dec(1); + __get_cpu_var(irq_stat).timer_irqs_others++; } #ifdef CONFIG_PPC64 @@ -801,8 +805,16 @@ static void __init clocksource_init(void) static int decrementer_set_next_event(unsigned long evt, struct clock_event_device *dev) { + /* Don't adjust the decrementer if some irq work is pending */ + if (test_irq_work_pending()) + return 0; __get_cpu_var(decrementers_next_tb) = get_tb_or_rtc() + evt; set_dec(evt); + + /* We may have raced with new irq work */ + if (test_irq_work_pending()) + set_dec(1); + return 0; } diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 907a472f9a9e4c..33cd7a0b8e730b 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -285,6 +285,21 @@ void system_reset_exception(struct pt_regs *regs) /* What should we do here? We could issue a shutdown or hard reset. */ } + +/* + * This function is called in real mode. Strictly no printk's please. + * + * regs->nip and regs->msr contains srr0 and ssr1. + */ +long machine_check_early(struct pt_regs *regs) +{ + long handled = 0; + + if (cur_cpu_spec && cur_cpu_spec->machine_check_early) + handled = cur_cpu_spec->machine_check_early(regs); + return handled; +} + #endif /* @@ -1384,7 +1399,6 @@ void fp_unavailable_tm(struct pt_regs *regs) TM_DEBUG("FP Unavailable trap whilst transactional at 0x%lx, MSR=%lx\n", regs->nip, regs->msr); - tm_enable(); /* We can only have got here if the task started using FP after * beginning the transaction. So, the transactional regs are just a @@ -1393,8 +1407,7 @@ void fp_unavailable_tm(struct pt_regs *regs) * transaction, and probably retry but now with FP enabled. So the * checkpointed FP registers need to be loaded. */ - tm_reclaim(¤t->thread, current->thread.regs->msr, - TM_CAUSE_FAC_UNAV); + tm_reclaim_current(TM_CAUSE_FAC_UNAV); /* Reclaim didn't save out any FPRs to transact_fprs. */ /* Enable FP for the task: */ @@ -1403,11 +1416,19 @@ void fp_unavailable_tm(struct pt_regs *regs) /* This loads and recheckpoints the FP registers from * thread.fpr[]. They will remain in registers after the * checkpoint so we don't need to reload them after. + * If VMX is in use, the VRs now hold checkpointed values, + * so we don't want to load the VRs from the thread_struct. */ - tm_recheckpoint(¤t->thread, regs->msr); + tm_recheckpoint(¤t->thread, MSR_FP); + + /* If VMX is in use, get the transactional values back */ + if (regs->msr & MSR_VEC) { + do_load_up_transact_altivec(¤t->thread); + /* At this point all the VSX state is loaded, so enable it */ + regs->msr |= MSR_VSX; + } } -#ifdef CONFIG_ALTIVEC void altivec_unavailable_tm(struct pt_regs *regs) { /* See the comments in fp_unavailable_tm(). This function operates @@ -1417,18 +1438,21 @@ void altivec_unavailable_tm(struct pt_regs *regs) TM_DEBUG("Vector Unavailable trap whilst transactional at 0x%lx," "MSR=%lx\n", regs->nip, regs->msr); - tm_enable(); - tm_reclaim(¤t->thread, current->thread.regs->msr, - TM_CAUSE_FAC_UNAV); + tm_reclaim_current(TM_CAUSE_FAC_UNAV); regs->msr |= MSR_VEC; - tm_recheckpoint(¤t->thread, regs->msr); + tm_recheckpoint(¤t->thread, MSR_VEC); current->thread.used_vr = 1; + + if (regs->msr & MSR_FP) { + do_load_up_transact_fpu(¤t->thread); + regs->msr |= MSR_VSX; + } } -#endif -#ifdef CONFIG_VSX void vsx_unavailable_tm(struct pt_regs *regs) { + unsigned long orig_msr = regs->msr; + /* See the comments in fp_unavailable_tm(). This works similarly, * though we're loading both FP and VEC registers in here. * @@ -1440,18 +1464,30 @@ void vsx_unavailable_tm(struct pt_regs *regs) "MSR=%lx\n", regs->nip, regs->msr); - tm_enable(); + current->thread.used_vsr = 1; + + /* If FP and VMX are already loaded, we have all the state we need */ + if ((orig_msr & (MSR_FP | MSR_VEC)) == (MSR_FP | MSR_VEC)) { + regs->msr |= MSR_VSX; + return; + } + /* This reclaims FP and/or VR regs if they're already enabled */ - tm_reclaim(¤t->thread, current->thread.regs->msr, - TM_CAUSE_FAC_UNAV); + tm_reclaim_current(TM_CAUSE_FAC_UNAV); regs->msr |= MSR_VEC | MSR_FP | current->thread.fpexc_mode | MSR_VSX; - /* This loads & recheckpoints FP and VRs. */ - tm_recheckpoint(¤t->thread, regs->msr); - current->thread.used_vsr = 1; + + /* This loads & recheckpoints FP and VRs; but we have + * to be sure not to overwrite previously-valid state. + */ + tm_recheckpoint(¤t->thread, regs->msr & ~orig_msr); + + if (orig_msr & MSR_FP) + do_load_up_transact_fpu(¤t->thread); + if (orig_msr & MSR_VEC) + do_load_up_transact_altivec(¤t->thread); } -#endif #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ void performance_monitor_exception(struct pt_regs *regs) diff --git a/arch/powerpc/kernel/vdso32/vdso32_wrapper.S b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S index 6e8f507ed32bb5..6ac107ac402a93 100644 --- a/arch/powerpc/kernel/vdso32/vdso32_wrapper.S +++ b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S @@ -1,4 +1,3 @@ -#include #include #include @@ -7,7 +6,7 @@ .globl vdso32_start, vdso32_end .balign PAGE_SIZE vdso32_start: - .incbin "arch/powerpc/kernel/vdso32/vdso32.so" + .incbin "arch/powerpc/kernel/vdso32/vdso32.so.dbg" .balign PAGE_SIZE vdso32_end: diff --git a/arch/powerpc/kernel/vdso64/vdso64_wrapper.S b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S index b8553d62b792ff..df60fca6a13d1e 100644 --- a/arch/powerpc/kernel/vdso64/vdso64_wrapper.S +++ b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S @@ -1,4 +1,3 @@ -#include #include #include @@ -7,7 +6,7 @@ .globl vdso64_start, vdso64_end .balign PAGE_SIZE vdso64_start: - .incbin "arch/powerpc/kernel/vdso64/vdso64.so" + .incbin "arch/powerpc/kernel/vdso64/vdso64.so.dbg" .balign PAGE_SIZE vdso64_end: diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S index 0458a9aaba9d13..74f8050518d690 100644 --- a/arch/powerpc/kernel/vector.S +++ b/arch/powerpc/kernel/vector.S @@ -36,6 +36,16 @@ _GLOBAL(do_load_up_transact_altivec) blr #endif +/* + * Enable use of VMX/Altivec for the caller. + */ +_GLOBAL(vec_enable) + mfmsr r3 + oris r3,r3,MSR_VEC@h + MTMSRD(r3) + isync + blr + /* * Load state from memory into VMX registers including VSCR. * Assumes the caller has enabled VMX in the MSR. diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 76a64821f4a236..826d8bd9e5223d 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -518,16 +518,18 @@ static dma_addr_t vio_dma_iommu_map_page(struct device *dev, struct page *page, struct dma_attrs *attrs) { struct vio_dev *viodev = to_vio_dev(dev); + struct iommu_table *tbl; dma_addr_t ret = DMA_ERROR_CODE; - if (vio_cmo_alloc(viodev, roundup(size, IOMMU_PAGE_SIZE))) { + tbl = get_iommu_table_base(dev); + if (vio_cmo_alloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl)))) { atomic_inc(&viodev->cmo.allocs_failed); return ret; } ret = dma_iommu_ops.map_page(dev, page, offset, size, direction, attrs); if (unlikely(dma_mapping_error(dev, ret))) { - vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE)); + vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl))); atomic_inc(&viodev->cmo.allocs_failed); } @@ -540,10 +542,12 @@ static void vio_dma_iommu_unmap_page(struct device *dev, dma_addr_t dma_handle, struct dma_attrs *attrs) { struct vio_dev *viodev = to_vio_dev(dev); + struct iommu_table *tbl; + tbl = get_iommu_table_base(dev); dma_iommu_ops.unmap_page(dev, dma_handle, size, direction, attrs); - vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE)); + vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl))); } static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist, @@ -551,12 +555,14 @@ static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist, struct dma_attrs *attrs) { struct vio_dev *viodev = to_vio_dev(dev); + struct iommu_table *tbl; struct scatterlist *sgl; int ret, count = 0; size_t alloc_size = 0; + tbl = get_iommu_table_base(dev); for (sgl = sglist; count < nelems; count++, sgl++) - alloc_size += roundup(sgl->length, IOMMU_PAGE_SIZE); + alloc_size += roundup(sgl->length, IOMMU_PAGE_SIZE(tbl)); if (vio_cmo_alloc(viodev, alloc_size)) { atomic_inc(&viodev->cmo.allocs_failed); @@ -572,7 +578,7 @@ static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist, } for (sgl = sglist, count = 0; count < ret; count++, sgl++) - alloc_size -= roundup(sgl->dma_length, IOMMU_PAGE_SIZE); + alloc_size -= roundup(sgl->dma_length, IOMMU_PAGE_SIZE(tbl)); if (alloc_size) vio_cmo_dealloc(viodev, alloc_size); @@ -585,12 +591,14 @@ static void vio_dma_iommu_unmap_sg(struct device *dev, struct dma_attrs *attrs) { struct vio_dev *viodev = to_vio_dev(dev); + struct iommu_table *tbl; struct scatterlist *sgl; size_t alloc_size = 0; int count = 0; + tbl = get_iommu_table_base(dev); for (sgl = sglist; count < nelems; count++, sgl++) - alloc_size += roundup(sgl->dma_length, IOMMU_PAGE_SIZE); + alloc_size += roundup(sgl->dma_length, IOMMU_PAGE_SIZE(tbl)); dma_iommu_ops.unmap_sg(dev, sglist, nelems, direction, attrs); @@ -706,11 +714,14 @@ static int vio_cmo_bus_probe(struct vio_dev *viodev) { struct vio_cmo_dev_entry *dev_ent; struct device *dev = &viodev->dev; + struct iommu_table *tbl; struct vio_driver *viodrv = to_vio_driver(dev->driver); unsigned long flags; size_t size; bool dma_capable = false; + tbl = get_iommu_table_base(dev); + /* A device requires entitlement if it has a DMA window property */ switch (viodev->family) { case VDEVICE: @@ -736,7 +747,8 @@ static int vio_cmo_bus_probe(struct vio_dev *viodev) return -EINVAL; } - viodev->cmo.desired = IOMMU_PAGE_ALIGN(viodrv->get_desired_dma(viodev)); + viodev->cmo.desired = + IOMMU_PAGE_ALIGN(viodrv->get_desired_dma(viodev), tbl); if (viodev->cmo.desired < VIO_CMO_MIN_ENT) viodev->cmo.desired = VIO_CMO_MIN_ENT; size = VIO_CMO_MIN_ENT; @@ -1176,9 +1188,10 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) &tbl->it_index, &offset, &size); /* TCE table size - measured in tce entries */ - tbl->it_size = size >> IOMMU_PAGE_SHIFT; + tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K; + tbl->it_size = size >> tbl->it_page_shift; /* offset for VIO should always be 0 */ - tbl->it_offset = offset >> IOMMU_PAGE_SHIFT; + tbl->it_offset = offset >> tbl->it_page_shift; tbl->it_busno = 0; tbl->it_type = TCE_VB; tbl->it_blocksize = 16; diff --git a/arch/powerpc/kvm/44x.c b/arch/powerpc/kvm/44x.c index 93221e87b91196..9cb4b0a3603183 100644 --- a/arch/powerpc/kvm/44x.c +++ b/arch/powerpc/kvm/44x.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -231,3 +233,5 @@ static void __exit kvmppc_44x_exit(void) module_init(kvmppc_44x_init); module_exit(kvmppc_44x_exit); +MODULE_ALIAS_MISCDEV(KVM_MINOR); +MODULE_ALIAS("devname:kvm"); diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index 8912608b7e1b34..94e597e6f15cd0 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -575,10 +577,10 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) break; case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31: i = reg->id - KVM_REG_PPC_FPR0; - val = get_reg_val(reg->id, vcpu->arch.fpr[i]); + val = get_reg_val(reg->id, VCPU_FPR(vcpu, i)); break; case KVM_REG_PPC_FPSCR: - val = get_reg_val(reg->id, vcpu->arch.fpscr); + val = get_reg_val(reg->id, vcpu->arch.fp.fpscr); break; #ifdef CONFIG_ALTIVEC case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31: @@ -586,19 +588,30 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) r = -ENXIO; break; } - val.vval = vcpu->arch.vr[reg->id - KVM_REG_PPC_VR0]; + val.vval = vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0]; break; case KVM_REG_PPC_VSCR: if (!cpu_has_feature(CPU_FTR_ALTIVEC)) { r = -ENXIO; break; } - val = get_reg_val(reg->id, vcpu->arch.vscr.u[3]); + val = get_reg_val(reg->id, vcpu->arch.vr.vscr.u[3]); break; case KVM_REG_PPC_VRSAVE: val = get_reg_val(reg->id, vcpu->arch.vrsave); break; #endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_VSX + case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: + if (cpu_has_feature(CPU_FTR_VSX)) { + long int i = reg->id - KVM_REG_PPC_VSR0; + val.vsxval[0] = vcpu->arch.fp.fpr[i][0]; + val.vsxval[1] = vcpu->arch.fp.fpr[i][1]; + } else { + r = -ENXIO; + } + break; +#endif /* CONFIG_VSX */ case KVM_REG_PPC_DEBUG_INST: { u32 opcode = INS_TW; r = copy_to_user((u32 __user *)(long)reg->addr, @@ -654,10 +667,10 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) break; case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31: i = reg->id - KVM_REG_PPC_FPR0; - vcpu->arch.fpr[i] = set_reg_val(reg->id, val); + VCPU_FPR(vcpu, i) = set_reg_val(reg->id, val); break; case KVM_REG_PPC_FPSCR: - vcpu->arch.fpscr = set_reg_val(reg->id, val); + vcpu->arch.fp.fpscr = set_reg_val(reg->id, val); break; #ifdef CONFIG_ALTIVEC case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31: @@ -665,14 +678,14 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) r = -ENXIO; break; } - vcpu->arch.vr[reg->id - KVM_REG_PPC_VR0] = val.vval; + vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0] = val.vval; break; case KVM_REG_PPC_VSCR: if (!cpu_has_feature(CPU_FTR_ALTIVEC)) { r = -ENXIO; break; } - vcpu->arch.vscr.u[3] = set_reg_val(reg->id, val); + vcpu->arch.vr.vscr.u[3] = set_reg_val(reg->id, val); break; case KVM_REG_PPC_VRSAVE: if (!cpu_has_feature(CPU_FTR_ALTIVEC)) { @@ -682,6 +695,17 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) vcpu->arch.vrsave = set_reg_val(reg->id, val); break; #endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_VSX + case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: + if (cpu_has_feature(CPU_FTR_VSX)) { + long int i = reg->id - KVM_REG_PPC_VSR0; + vcpu->arch.fp.fpr[i][0] = val.vsxval[0]; + vcpu->arch.fp.fpr[i][1] = val.vsxval[1]; + } else { + r = -ENXIO; + } + break; +#endif /* CONFIG_VSX */ #ifdef CONFIG_KVM_XICS case KVM_REG_PPC_ICP_STATE: if (!vcpu->arch.icp) { @@ -879,3 +903,9 @@ static void kvmppc_book3s_exit(void) module_init(kvmppc_book3s_init); module_exit(kvmppc_book3s_exit); + +/* On 32bit this is our one and only kernel module */ +#ifdef CONFIG_KVM_BOOK3S_32 +MODULE_ALIAS_MISCDEV(KVM_MINOR); +MODULE_ALIAS("devname:kvm"); +#endif diff --git a/arch/powerpc/kvm/book3s_32_mmu_host.c b/arch/powerpc/kvm/book3s_32_mmu_host.c index 3a0abd2e5a15a2..5fac89dfe4cdf2 100644 --- a/arch/powerpc/kvm/book3s_32_mmu_host.c +++ b/arch/powerpc/kvm/book3s_32_mmu_host.c @@ -243,6 +243,11 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte, /* Now tell our Shadow PTE code about the new page */ pte = kvmppc_mmu_hpte_cache_next(vcpu); + if (!pte) { + kvm_release_pfn_clean(hpaddr >> PAGE_SHIFT); + r = -EAGAIN; + goto out; + } dprintk_mmu("KVM: %c%c Map 0x%llx: [%lx] 0x%llx (0x%llx) -> %lx\n", orig_pte->may_write ? 'w' : '-', diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index c5d148434c0819..303ece75b8e4aa 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -262,7 +262,7 @@ int kvmppc_mmu_hv_init(void) static void kvmppc_mmu_book3s_64_hv_reset_msr(struct kvm_vcpu *vcpu) { - kvmppc_set_msr(vcpu, MSR_SF | MSR_ME); + kvmppc_set_msr(vcpu, vcpu->arch.intr_msr); } /* @@ -562,7 +562,7 @@ static int kvmppc_hv_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu, * we just return and retry the instruction. */ - if (instruction_is_store(vcpu->arch.last_inst) != !!is_store) + if (instruction_is_store(kvmppc_get_last_inst(vcpu)) != !!is_store) return RESUME_GUEST; /* diff --git a/arch/powerpc/kvm/book3s_exports.c b/arch/powerpc/kvm/book3s_exports.c index 852989a9bad304..20d4ea8e656d3e 100644 --- a/arch/powerpc/kvm/book3s_exports.c +++ b/arch/powerpc/kvm/book3s_exports.c @@ -25,9 +25,5 @@ EXPORT_SYMBOL_GPL(kvmppc_hv_entry_trampoline); #endif #ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE EXPORT_SYMBOL_GPL(kvmppc_entry_trampoline); -EXPORT_SYMBOL_GPL(kvmppc_load_up_fpu); -#ifdef CONFIG_ALTIVEC -EXPORT_SYMBOL_GPL(kvmppc_load_up_altivec); -#endif #endif diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 3818bd95327c5f..17fc9496b6aca0 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -85,10 +86,13 @@ static void kvmppc_fast_vcpu_kick_hv(struct kvm_vcpu *vcpu) /* CPU points to the first thread of the core */ if (cpu != me && cpu >= 0 && cpu < nr_cpu_ids) { +#ifdef CONFIG_KVM_XICS int real_cpu = cpu + vcpu->arch.ptid; if (paca[real_cpu].kvm_hstate.xics_phys) xics_wake_cpu(real_cpu); - else if (cpu_online(cpu)) + else +#endif + if (cpu_online(cpu)) smp_send_reschedule(cpu); } put_cpu(); @@ -182,14 +186,28 @@ int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat) switch (arch_compat) { case PVR_ARCH_205: - pcr = PCR_ARCH_205; + /* + * If an arch bit is set in PCR, all the defined + * higher-order arch bits also have to be set. + */ + pcr = PCR_ARCH_206 | PCR_ARCH_205; break; case PVR_ARCH_206: case PVR_ARCH_206p: + pcr = PCR_ARCH_206; + break; + case PVR_ARCH_207: break; default: return -EINVAL; } + + if (!cpu_has_feature(CPU_FTR_ARCH_207S)) { + /* POWER7 can't emulate POWER8 */ + if (!(pcr & PCR_ARCH_206)) + return -EINVAL; + pcr &= ~PCR_ARCH_206; + } } spin_lock(&vc->lock); @@ -637,6 +655,7 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu, r = RESUME_GUEST; break; case BOOK3S_INTERRUPT_EXTERNAL: + case BOOK3S_INTERRUPT_H_DOORBELL: vcpu->stat.ext_intr_exits++; r = RESUME_GUEST; break; @@ -673,12 +692,10 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu, /* hcall - punt to userspace */ int i; - if (vcpu->arch.shregs.msr & MSR_PR) { - /* sc 1 from userspace - reflect to guest syscall */ - kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_SYSCALL); - r = RESUME_GUEST; - break; - } + /* hypercall with MSR_PR has already been handled in rmode, + * and never reaches here. + */ + run->papr_hcall.nr = kvmppc_get_gpr(vcpu, 3); for (i = 0; i < 9; ++i) run->papr_hcall.args[i] = kvmppc_get_gpr(vcpu, 4 + i); @@ -708,7 +725,16 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu, * we don't emulate any guest instructions at this stage. */ case BOOK3S_INTERRUPT_H_EMUL_ASSIST: - kvmppc_core_queue_program(vcpu, 0x80000); + kvmppc_core_queue_program(vcpu, SRR1_PROGILL); + r = RESUME_GUEST; + break; + /* + * This occurs if the guest (kernel or userspace), does something that + * is prohibited by HFSCR. We just generate a program interrupt to + * the guest. + */ + case BOOK3S_INTERRUPT_H_FAC_UNAVAIL: + kvmppc_core_queue_program(vcpu, SRR1_PROGILL); r = RESUME_GUEST; break; default: @@ -765,11 +791,35 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr) u64 mask; spin_lock(&vc->lock); + /* + * If ILE (interrupt little-endian) has changed, update the + * MSR_LE bit in the intr_msr for each vcpu in this vcore. + */ + if ((new_lpcr & LPCR_ILE) != (vc->lpcr & LPCR_ILE)) { + struct kvm *kvm = vcpu->kvm; + struct kvm_vcpu *vcpu; + int i; + + mutex_lock(&kvm->lock); + kvm_for_each_vcpu(i, vcpu, kvm) { + if (vcpu->arch.vcore != vc) + continue; + if (new_lpcr & LPCR_ILE) + vcpu->arch.intr_msr |= MSR_LE; + else + vcpu->arch.intr_msr &= ~MSR_LE; + } + mutex_unlock(&kvm->lock); + } + /* * Userspace can only modify DPFD (default prefetch depth), * ILE (interrupt little-endian) and TC (translation control). + * On POWER8 userspace can also modify AIL (alt. interrupt loc.) */ mask = LPCR_DPFD | LPCR_ILE | LPCR_TC; + if (cpu_has_feature(CPU_FTR_ARCH_207S)) + mask |= LPCR_AIL; vc->lpcr = (vc->lpcr & ~mask) | (new_lpcr & mask); spin_unlock(&vc->lock); } @@ -787,6 +837,9 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, case KVM_REG_PPC_DABR: *val = get_reg_val(id, vcpu->arch.dabr); break; + case KVM_REG_PPC_DABRX: + *val = get_reg_val(id, vcpu->arch.dabrx); + break; case KVM_REG_PPC_DSCR: *val = get_reg_val(id, vcpu->arch.dscr); break; @@ -802,7 +855,7 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, case KVM_REG_PPC_UAMOR: *val = get_reg_val(id, vcpu->arch.uamor); break; - case KVM_REG_PPC_MMCR0 ... KVM_REG_PPC_MMCRA: + case KVM_REG_PPC_MMCR0 ... KVM_REG_PPC_MMCRS: i = id - KVM_REG_PPC_MMCR0; *val = get_reg_val(id, vcpu->arch.mmcr[i]); break; @@ -810,33 +863,87 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, i = id - KVM_REG_PPC_PMC1; *val = get_reg_val(id, vcpu->arch.pmc[i]); break; + case KVM_REG_PPC_SPMC1 ... KVM_REG_PPC_SPMC2: + i = id - KVM_REG_PPC_SPMC1; + *val = get_reg_val(id, vcpu->arch.spmc[i]); + break; case KVM_REG_PPC_SIAR: *val = get_reg_val(id, vcpu->arch.siar); break; case KVM_REG_PPC_SDAR: *val = get_reg_val(id, vcpu->arch.sdar); break; -#ifdef CONFIG_VSX - case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31: - if (cpu_has_feature(CPU_FTR_VSX)) { - /* VSX => FP reg i is stored in arch.vsr[2*i] */ - long int i = id - KVM_REG_PPC_FPR0; - *val = get_reg_val(id, vcpu->arch.vsr[2 * i]); - } else { - /* let generic code handle it */ - r = -EINVAL; - } + case KVM_REG_PPC_SIER: + *val = get_reg_val(id, vcpu->arch.sier); break; - case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: - if (cpu_has_feature(CPU_FTR_VSX)) { - long int i = id - KVM_REG_PPC_VSR0; - val->vsxval[0] = vcpu->arch.vsr[2 * i]; - val->vsxval[1] = vcpu->arch.vsr[2 * i + 1]; - } else { - r = -ENXIO; - } + case KVM_REG_PPC_IAMR: + *val = get_reg_val(id, vcpu->arch.iamr); + break; +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + case KVM_REG_PPC_TFHAR: + *val = get_reg_val(id, vcpu->arch.tfhar); + break; + case KVM_REG_PPC_TFIAR: + *val = get_reg_val(id, vcpu->arch.tfiar); + break; + case KVM_REG_PPC_TEXASR: + *val = get_reg_val(id, vcpu->arch.texasr); + break; +#endif + case KVM_REG_PPC_FSCR: + *val = get_reg_val(id, vcpu->arch.fscr); + break; + case KVM_REG_PPC_PSPB: + *val = get_reg_val(id, vcpu->arch.pspb); + break; + case KVM_REG_PPC_EBBHR: + *val = get_reg_val(id, vcpu->arch.ebbhr); + break; + case KVM_REG_PPC_EBBRR: + *val = get_reg_val(id, vcpu->arch.ebbrr); + break; + case KVM_REG_PPC_BESCR: + *val = get_reg_val(id, vcpu->arch.bescr); + break; + case KVM_REG_PPC_TAR: + *val = get_reg_val(id, vcpu->arch.tar); + break; + case KVM_REG_PPC_DPDES: + *val = get_reg_val(id, vcpu->arch.vcore->dpdes); + break; + case KVM_REG_PPC_DAWR: + *val = get_reg_val(id, vcpu->arch.dawr); + break; + case KVM_REG_PPC_DAWRX: + *val = get_reg_val(id, vcpu->arch.dawrx); + break; + case KVM_REG_PPC_CIABR: + *val = get_reg_val(id, vcpu->arch.ciabr); + break; + case KVM_REG_PPC_IC: + *val = get_reg_val(id, vcpu->arch.ic); + break; + case KVM_REG_PPC_VTB: + *val = get_reg_val(id, vcpu->arch.vtb); + break; + case KVM_REG_PPC_CSIGR: + *val = get_reg_val(id, vcpu->arch.csigr); + break; + case KVM_REG_PPC_TACR: + *val = get_reg_val(id, vcpu->arch.tacr); + break; + case KVM_REG_PPC_TCSCR: + *val = get_reg_val(id, vcpu->arch.tcscr); + break; + case KVM_REG_PPC_PID: + *val = get_reg_val(id, vcpu->arch.pid); + break; + case KVM_REG_PPC_ACOP: + *val = get_reg_val(id, vcpu->arch.acop); + break; + case KVM_REG_PPC_WORT: + *val = get_reg_val(id, vcpu->arch.wort); break; -#endif /* CONFIG_VSX */ case KVM_REG_PPC_VPA_ADDR: spin_lock(&vcpu->arch.vpa_update_lock); *val = get_reg_val(id, vcpu->arch.vpa.next_gpa); @@ -890,6 +997,9 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, case KVM_REG_PPC_DABR: vcpu->arch.dabr = set_reg_val(id, *val); break; + case KVM_REG_PPC_DABRX: + vcpu->arch.dabrx = set_reg_val(id, *val) & ~DABRX_HYP; + break; case KVM_REG_PPC_DSCR: vcpu->arch.dscr = set_reg_val(id, *val); break; @@ -905,7 +1015,7 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, case KVM_REG_PPC_UAMOR: vcpu->arch.uamor = set_reg_val(id, *val); break; - case KVM_REG_PPC_MMCR0 ... KVM_REG_PPC_MMCRA: + case KVM_REG_PPC_MMCR0 ... KVM_REG_PPC_MMCRS: i = id - KVM_REG_PPC_MMCR0; vcpu->arch.mmcr[i] = set_reg_val(id, *val); break; @@ -913,33 +1023,90 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, i = id - KVM_REG_PPC_PMC1; vcpu->arch.pmc[i] = set_reg_val(id, *val); break; + case KVM_REG_PPC_SPMC1 ... KVM_REG_PPC_SPMC2: + i = id - KVM_REG_PPC_SPMC1; + vcpu->arch.spmc[i] = set_reg_val(id, *val); + break; case KVM_REG_PPC_SIAR: vcpu->arch.siar = set_reg_val(id, *val); break; case KVM_REG_PPC_SDAR: vcpu->arch.sdar = set_reg_val(id, *val); break; -#ifdef CONFIG_VSX - case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31: - if (cpu_has_feature(CPU_FTR_VSX)) { - /* VSX => FP reg i is stored in arch.vsr[2*i] */ - long int i = id - KVM_REG_PPC_FPR0; - vcpu->arch.vsr[2 * i] = set_reg_val(id, *val); - } else { - /* let generic code handle it */ - r = -EINVAL; - } + case KVM_REG_PPC_SIER: + vcpu->arch.sier = set_reg_val(id, *val); break; - case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: - if (cpu_has_feature(CPU_FTR_VSX)) { - long int i = id - KVM_REG_PPC_VSR0; - vcpu->arch.vsr[2 * i] = val->vsxval[0]; - vcpu->arch.vsr[2 * i + 1] = val->vsxval[1]; - } else { - r = -ENXIO; - } + case KVM_REG_PPC_IAMR: + vcpu->arch.iamr = set_reg_val(id, *val); + break; +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + case KVM_REG_PPC_TFHAR: + vcpu->arch.tfhar = set_reg_val(id, *val); + break; + case KVM_REG_PPC_TFIAR: + vcpu->arch.tfiar = set_reg_val(id, *val); + break; + case KVM_REG_PPC_TEXASR: + vcpu->arch.texasr = set_reg_val(id, *val); + break; +#endif + case KVM_REG_PPC_FSCR: + vcpu->arch.fscr = set_reg_val(id, *val); + break; + case KVM_REG_PPC_PSPB: + vcpu->arch.pspb = set_reg_val(id, *val); + break; + case KVM_REG_PPC_EBBHR: + vcpu->arch.ebbhr = set_reg_val(id, *val); + break; + case KVM_REG_PPC_EBBRR: + vcpu->arch.ebbrr = set_reg_val(id, *val); + break; + case KVM_REG_PPC_BESCR: + vcpu->arch.bescr = set_reg_val(id, *val); + break; + case KVM_REG_PPC_TAR: + vcpu->arch.tar = set_reg_val(id, *val); + break; + case KVM_REG_PPC_DPDES: + vcpu->arch.vcore->dpdes = set_reg_val(id, *val); + break; + case KVM_REG_PPC_DAWR: + vcpu->arch.dawr = set_reg_val(id, *val); + break; + case KVM_REG_PPC_DAWRX: + vcpu->arch.dawrx = set_reg_val(id, *val) & ~DAWRX_HYP; + break; + case KVM_REG_PPC_CIABR: + vcpu->arch.ciabr = set_reg_val(id, *val); + /* Don't allow setting breakpoints in hypervisor code */ + if ((vcpu->arch.ciabr & CIABR_PRIV) == CIABR_PRIV_HYPER) + vcpu->arch.ciabr &= ~CIABR_PRIV; /* disable */ + break; + case KVM_REG_PPC_IC: + vcpu->arch.ic = set_reg_val(id, *val); + break; + case KVM_REG_PPC_VTB: + vcpu->arch.vtb = set_reg_val(id, *val); + break; + case KVM_REG_PPC_CSIGR: + vcpu->arch.csigr = set_reg_val(id, *val); + break; + case KVM_REG_PPC_TACR: + vcpu->arch.tacr = set_reg_val(id, *val); + break; + case KVM_REG_PPC_TCSCR: + vcpu->arch.tcscr = set_reg_val(id, *val); + break; + case KVM_REG_PPC_PID: + vcpu->arch.pid = set_reg_val(id, *val); + break; + case KVM_REG_PPC_ACOP: + vcpu->arch.acop = set_reg_val(id, *val); + break; + case KVM_REG_PPC_WORT: + vcpu->arch.wort = set_reg_val(id, *val); break; -#endif /* CONFIG_VSX */ case KVM_REG_PPC_VPA_ADDR: addr = set_reg_val(id, *val); r = -EINVAL; @@ -1017,6 +1184,7 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm, spin_lock_init(&vcpu->arch.vpa_update_lock); spin_lock_init(&vcpu->arch.tbacct_lock); vcpu->arch.busy_preempt = TB_NIL; + vcpu->arch.intr_msr = MSR_SF | MSR_ME; kvmppc_mmu_book3s_hv_init(vcpu); @@ -1034,6 +1202,8 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm, init_waitqueue_head(&vcore->wq); vcore->preempt_tb = TB_NIL; vcore->lpcr = kvm->arch.lpcr; + vcore->first_vcpuid = core * threads_per_core; + vcore->kvm = kvm; } kvm->arch.vcores[core] = vcore; kvm->arch.online_vcores++; @@ -1047,6 +1217,7 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm, ++vcore->num_threads; spin_unlock(&vcore->lock); vcpu->arch.vcore = vcore; + vcpu->arch.ptid = vcpu->vcpu_id - vcore->first_vcpuid; vcpu->arch.cpu_type = KVM_CPU_3S_64; kvmppc_sanity_check(vcpu); @@ -1110,7 +1281,7 @@ static void kvmppc_end_cede(struct kvm_vcpu *vcpu) } } -extern int __kvmppc_vcore_entry(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); +extern void __kvmppc_vcore_entry(void); static void kvmppc_remove_runnable(struct kvmppc_vcore *vc, struct kvm_vcpu *vcpu) @@ -1184,13 +1355,16 @@ static void kvmppc_start_thread(struct kvm_vcpu *vcpu) tpaca = &paca[cpu]; tpaca->kvm_hstate.kvm_vcpu = vcpu; tpaca->kvm_hstate.kvm_vcore = vc; - tpaca->kvm_hstate.napping = 0; + tpaca->kvm_hstate.ptid = vcpu->arch.ptid; vcpu->cpu = vc->pcpu; smp_wmb(); #if defined(CONFIG_PPC_ICP_NATIVE) && defined(CONFIG_SMP) - if (vcpu->arch.ptid) { + if (cpu != smp_processor_id()) { +#ifdef CONFIG_KVM_XICS xics_wake_cpu(cpu); - ++vc->n_woken; +#endif + if (vcpu->arch.ptid) + ++vc->n_woken; } #endif } @@ -1247,10 +1421,10 @@ static int on_primary_thread(void) */ static void kvmppc_run_core(struct kvmppc_vcore *vc) { - struct kvm_vcpu *vcpu, *vcpu0, *vnext; + struct kvm_vcpu *vcpu, *vnext; long ret; u64 now; - int ptid, i, need_vpa_update; + int i, need_vpa_update; int srcu_idx; struct kvm_vcpu *vcpus_to_update[threads_per_core]; @@ -1287,25 +1461,6 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc) spin_lock(&vc->lock); } - /* - * Assign physical thread IDs, first to non-ceded vcpus - * and then to ceded ones. - */ - ptid = 0; - vcpu0 = NULL; - list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) { - if (!vcpu->arch.ceded) { - if (!ptid) - vcpu0 = vcpu; - vcpu->arch.ptid = ptid++; - } - } - if (!vcpu0) - goto out; /* nothing to run; should never happen */ - list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) - if (vcpu->arch.ceded) - vcpu->arch.ptid = ptid++; - /* * Make sure we are running on thread 0, and that * secondary threads are offline. @@ -1322,15 +1477,19 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc) kvmppc_create_dtl_entry(vcpu, vc); } + /* Set this explicitly in case thread 0 doesn't have a vcpu */ + get_paca()->kvm_hstate.kvm_vcore = vc; + get_paca()->kvm_hstate.ptid = 0; + vc->vcore_state = VCORE_RUNNING; preempt_disable(); spin_unlock(&vc->lock); kvm_guest_enter(); - srcu_idx = srcu_read_lock(&vcpu0->kvm->srcu); + srcu_idx = srcu_read_lock(&vc->kvm->srcu); - __kvmppc_vcore_entry(NULL, vcpu0); + __kvmppc_vcore_entry(); spin_lock(&vc->lock); /* disable sending of IPIs on virtual external irqs */ @@ -1345,7 +1504,7 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc) vc->vcore_state = VCORE_EXITING; spin_unlock(&vc->lock); - srcu_read_unlock(&vcpu0->kvm->srcu, srcu_idx); + srcu_read_unlock(&vc->kvm->srcu, srcu_idx); /* make sure updates to secondary vcpu structs are visible now */ smp_mb(); @@ -1453,7 +1612,6 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) if (!signal_pending(current)) { if (vc->vcore_state == VCORE_RUNNING && VCORE_EXIT_COUNT(vc) == 0) { - vcpu->arch.ptid = vc->n_runnable - 1; kvmppc_create_dtl_entry(vcpu, vc); kvmppc_start_thread(vcpu); } else if (vc->vcore_state == VCORE_SLEEPING) { @@ -2048,6 +2206,9 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm) LPCR_VPM0 | LPCR_VPM1; kvm->arch.vrma_slb_v = SLB_VSID_B_1T | (VRMA_VSID << SLB_VSID_SHIFT_1T); + /* On POWER8 turn on online bit to enable PURR/SPURR */ + if (cpu_has_feature(CPU_FTR_ARCH_207S)) + lpcr |= LPCR_ONL; } kvm->arch.lpcr = lpcr; @@ -2222,3 +2383,5 @@ static void kvmppc_book3s_exit_hv(void) module_init(kvmppc_book3s_init_hv); module_exit(kvmppc_book3s_exit_hv); MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(KVM_MINOR); +MODULE_ALIAS("devname:kvm"); diff --git a/arch/powerpc/kvm/book3s_hv_interrupts.S b/arch/powerpc/kvm/book3s_hv_interrupts.S index 928142c64cb00e..e873796b1a2931 100644 --- a/arch/powerpc/kvm/book3s_hv_interrupts.S +++ b/arch/powerpc/kvm/book3s_hv_interrupts.S @@ -35,7 +35,7 @@ ****************************************************************************/ /* Registers: - * r4: vcpu pointer + * none */ _GLOBAL(__kvmppc_vcore_entry) @@ -57,9 +57,11 @@ BEGIN_FTR_SECTION std r3, HSTATE_DSCR(r13) END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) +BEGIN_FTR_SECTION /* Save host DABR */ mfspr r3, SPRN_DABR std r3, HSTATE_DABR(r13) +END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) /* Hard-disable interrupts */ mfmsr r10 @@ -69,7 +71,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) mtmsrd r10,1 /* Save host PMU registers */ - /* R4 is live here (vcpu pointer) but not r3 or r5 */ li r3, 1 sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ mfspr r7, SPRN_MMCR0 /* save MMCR0 */ @@ -134,16 +135,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) * enters the guest with interrupts enabled. */ BEGIN_FTR_SECTION + ld r4, HSTATE_KVM_VCPU(r13) ld r0, VCPU_PENDING_EXC(r4) li r7, (1 << BOOK3S_IRQPRIO_EXTERNAL) oris r7, r7, (1 << BOOK3S_IRQPRIO_EXTERNAL_LEVEL)@h and. r0, r0, r7 beq 32f - mr r31, r4 lhz r3, PACAPACAINDEX(r13) bl smp_send_reschedule nop - mr r4, r31 32: END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) #endif /* CONFIG_SMP */ diff --git a/arch/powerpc/kvm/book3s_hv_ras.c b/arch/powerpc/kvm/book3s_hv_ras.c index a353c485808c6e..768a9f977c001e 100644 --- a/arch/powerpc/kvm/book3s_hv_ras.c +++ b/arch/powerpc/kvm/book3s_hv_ras.c @@ -12,6 +12,7 @@ #include #include #include +#include /* SRR1 bits for machine check on POWER7 */ #define SRR1_MC_LDSTERR (1ul << (63-42)) @@ -58,18 +59,6 @@ static void reload_slb(struct kvm_vcpu *vcpu) } } -/* POWER7 TLB flush */ -static void flush_tlb_power7(struct kvm_vcpu *vcpu) -{ - unsigned long i, rb; - - rb = TLBIEL_INVAL_SET_LPID; - for (i = 0; i < POWER7_TLB_SETS; ++i) { - asm volatile("tlbiel %0" : : "r" (rb)); - rb += 1 << TLBIEL_INVAL_SET_SHIFT; - } -} - /* * On POWER7, see if we can handle a machine check that occurred inside * the guest in real mode, without switching to the host partition. @@ -79,9 +68,7 @@ static void flush_tlb_power7(struct kvm_vcpu *vcpu) static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) { unsigned long srr1 = vcpu->arch.shregs.msr; -#ifdef CONFIG_PPC_POWERNV - struct opal_machine_check_event *opal_evt; -#endif + struct machine_check_event mce_evt; long handled = 1; if (srr1 & SRR1_MC_LDSTERR) { @@ -96,7 +83,8 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) DSISR_MC_SLB_PARITY | DSISR_MC_DERAT_MULTI); } if (dsisr & DSISR_MC_TLB_MULTI) { - flush_tlb_power7(vcpu); + if (cur_cpu_spec && cur_cpu_spec->flush_tlb) + cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID); dsisr &= ~DSISR_MC_TLB_MULTI; } /* Any other errors we don't understand? */ @@ -113,28 +101,38 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) reload_slb(vcpu); break; case SRR1_MC_IFETCH_TLBMULTI: - flush_tlb_power7(vcpu); + if (cur_cpu_spec && cur_cpu_spec->flush_tlb) + cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID); break; default: handled = 0; } -#ifdef CONFIG_PPC_POWERNV /* - * See if OPAL has already handled the condition. - * We assume that if the condition is recovered then OPAL + * See if we have already handled the condition in the linux host. + * We assume that if the condition is recovered then linux host * will have generated an error log event that we will pick * up and log later. + * Don't release mce event now. In case if condition is not + * recovered we do guest exit and go back to linux host machine + * check handler. Hence we need make sure that current mce event + * is available for linux host to consume. */ - opal_evt = local_paca->opal_mc_evt; - if (opal_evt->version == OpalMCE_V1 && - (opal_evt->severity == OpalMCE_SEV_NO_ERROR || - opal_evt->disposition == OpalMCE_DISPOSITION_RECOVERED)) + if (!get_mce_event(&mce_evt, MCE_EVENT_DONTRELEASE)) + goto out; + + if (mce_evt.version == MCE_V1 && + (mce_evt.severity == MCE_SEV_NO_ERROR || + mce_evt.disposition == MCE_DISPOSITION_RECOVERED)) handled = 1; +out: + /* + * If we have handled the error, then release the mce event because + * we will be delivering machine check to guest. + */ if (handled) - opal_evt->in_use = 0; -#endif + release_mce_event(); return handled; } diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c index 8689e2e308573b..37fb3caa4c80a5 100644 --- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c +++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c @@ -134,7 +134,7 @@ static void remove_revmap_chain(struct kvm *kvm, long pte_index, unlock_rmap(rmap); } -static pte_t lookup_linux_pte(pgd_t *pgdir, unsigned long hva, +static pte_t lookup_linux_pte_and_update(pgd_t *pgdir, unsigned long hva, int writing, unsigned long *pte_sizep) { pte_t *ptep; @@ -232,7 +232,8 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags, /* Look up the Linux PTE for the backing page */ pte_size = psize; - pte = lookup_linux_pte(pgdir, hva, writing, &pte_size); + pte = lookup_linux_pte_and_update(pgdir, hva, writing, + &pte_size); if (pte_present(pte)) { if (writing && !pte_write(pte)) /* make the actual HPTE be read-only */ @@ -672,7 +673,8 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags, memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn); if (memslot) { hva = __gfn_to_hva_memslot(memslot, gfn); - pte = lookup_linux_pte(pgdir, hva, 1, &psize); + pte = lookup_linux_pte_and_update(pgdir, hva, + 1, &psize); if (pte_present(pte) && !pte_write(pte)) r = hpte_make_readonly(r); } diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index be4fa04a37c96d..e66d4ec04d953a 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -33,6 +33,10 @@ #error Need to fix lppaca and SLB shadow accesses in little endian mode #endif +/* Values in HSTATE_NAPPING(r13) */ +#define NAPPING_CEDE 1 +#define NAPPING_NOVCPU 2 + /* * Call kvmppc_hv_entry in real mode. * Must be called with interrupts hard-disabled. @@ -57,29 +61,23 @@ _GLOBAL(kvmppc_hv_entry_trampoline) RFI kvmppc_call_hv_entry: + ld r4, HSTATE_KVM_VCPU(r13) bl kvmppc_hv_entry /* Back from guest - restore host state and return to caller */ +BEGIN_FTR_SECTION /* Restore host DABR and DABRX */ ld r5,HSTATE_DABR(r13) li r6,7 mtspr SPRN_DABR,r5 mtspr SPRN_DABRX,r6 +END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) /* Restore SPRG3 */ ld r3,PACA_SPRG3(r13) mtspr SPRN_SPRG3,r3 - /* - * Reload DEC. HDEC interrupts were disabled when - * we reloaded the host's LPCR value. - */ - ld r3, HSTATE_DECEXP(r13) - mftb r4 - subf r4, r4, r3 - mtspr SPRN_DEC, r4 - /* Reload the host's PMU registers */ ld r3, PACALPPACAPTR(r13) /* is the host using the PMU? */ lbz r4, LPPACA_PMCINUSE(r3) @@ -114,6 +112,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) isync 23: + /* + * Reload DEC. HDEC interrupts were disabled when + * we reloaded the host's LPCR value. + */ + ld r3, HSTATE_DECEXP(r13) + mftb r4 + subf r4, r4, r3 + mtspr SPRN_DEC, r4 + /* * For external and machine check interrupts, we need * to call the Linux handler to process the interrupt. @@ -153,15 +160,75 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) 13: b machine_check_fwnmi +kvmppc_primary_no_guest: + /* We handle this much like a ceded vcpu */ + /* set our bit in napping_threads */ + ld r5, HSTATE_KVM_VCORE(r13) + lbz r7, HSTATE_PTID(r13) + li r0, 1 + sld r0, r0, r7 + addi r6, r5, VCORE_NAPPING_THREADS +1: lwarx r3, 0, r6 + or r3, r3, r0 + stwcx. r3, 0, r6 + bne 1b + /* order napping_threads update vs testing entry_exit_count */ + isync + li r12, 0 + lwz r7, VCORE_ENTRY_EXIT(r5) + cmpwi r7, 0x100 + bge kvm_novcpu_exit /* another thread already exiting */ + li r3, NAPPING_NOVCPU + stb r3, HSTATE_NAPPING(r13) + li r3, 1 + stb r3, HSTATE_HWTHREAD_REQ(r13) + + b kvm_do_nap + +kvm_novcpu_wakeup: + ld r1, HSTATE_HOST_R1(r13) + ld r5, HSTATE_KVM_VCORE(r13) + li r0, 0 + stb r0, HSTATE_NAPPING(r13) + stb r0, HSTATE_HWTHREAD_REQ(r13) + + /* check the wake reason */ + bl kvmppc_check_wake_reason + + /* see if any other thread is already exiting */ + lwz r0, VCORE_ENTRY_EXIT(r5) + cmpwi r0, 0x100 + bge kvm_novcpu_exit + + /* clear our bit in napping_threads */ + lbz r7, HSTATE_PTID(r13) + li r0, 1 + sld r0, r0, r7 + addi r6, r5, VCORE_NAPPING_THREADS +4: lwarx r7, 0, r6 + andc r7, r7, r0 + stwcx. r7, 0, r6 + bne 4b + + /* See if the wake reason means we need to exit */ + cmpdi r3, 0 + bge kvm_novcpu_exit + + /* Got an IPI but other vcpus aren't yet exiting, must be a latecomer */ + ld r4, HSTATE_KVM_VCPU(r13) + cmpdi r4, 0 + bne kvmppc_got_guest + +kvm_novcpu_exit: + b hdec_soon + /* - * We come in here when wakened from nap mode on a secondary hw thread. + * We come in here when wakened from nap mode. * Relocation is off and most register values are lost. * r13 points to the PACA. */ .globl kvm_start_guest kvm_start_guest: - ld r1,PACAEMERGSP(r13) - subi r1,r1,STACK_FRAME_OVERHEAD ld r2,PACATOC(r13) li r0,KVM_HWTHREAD_IN_KVM @@ -173,8 +240,13 @@ kvm_start_guest: /* were we napping due to cede? */ lbz r0,HSTATE_NAPPING(r13) - cmpwi r0,0 - bne kvm_end_cede + cmpwi r0,NAPPING_CEDE + beq kvm_end_cede + cmpwi r0,NAPPING_NOVCPU + beq kvm_novcpu_wakeup + + ld r1,PACAEMERGSP(r13) + subi r1,r1,STACK_FRAME_OVERHEAD /* * We weren't napping due to cede, so this must be a secondary @@ -184,40 +256,22 @@ kvm_start_guest: */ /* Check the wake reason in SRR1 to see why we got here */ - mfspr r3,SPRN_SRR1 - rlwinm r3,r3,44-31,0x7 /* extract wake reason field */ - cmpwi r3,4 /* was it an external interrupt? */ - bne 27f /* if not */ - ld r5,HSTATE_XICS_PHYS(r13) - li r7,XICS_XIRR /* if it was an external interrupt, */ - lwzcix r8,r5,r7 /* get and ack the interrupt */ - sync - clrldi. r9,r8,40 /* get interrupt source ID. */ - beq 28f /* none there? */ - cmpwi r9,XICS_IPI /* was it an IPI? */ - bne 29f - li r0,0xff - li r6,XICS_MFRR - stbcix r0,r5,r6 /* clear IPI */ - stwcix r8,r5,r7 /* EOI the interrupt */ - sync /* order loading of vcpu after that */ + bl kvmppc_check_wake_reason + cmpdi r3, 0 + bge kvm_no_guest /* get vcpu pointer, NULL if we have no vcpu to run */ ld r4,HSTATE_KVM_VCPU(r13) cmpdi r4,0 /* if we have no vcpu to run, go back to sleep */ beq kvm_no_guest - b 30f -27: /* XXX should handle hypervisor maintenance interrupts etc. here */ - b kvm_no_guest -28: /* SRR1 said external but ICP said nope?? */ - b kvm_no_guest -29: /* External non-IPI interrupt to offline secondary thread? help?? */ - stw r8,HSTATE_SAVED_XIRR(r13) - b kvm_no_guest + /* Set HSTATE_DSCR(r13) to something sensible */ + LOAD_REG_ADDR(r6, dscr_default) + ld r6, 0(r6) + std r6, HSTATE_DSCR(r13) -30: bl kvmppc_hv_entry + bl kvmppc_hv_entry /* Back from the guest, go back to nap */ /* Clear our vcpu pointer so we don't come back in early */ @@ -229,18 +283,6 @@ kvm_start_guest: * visible we could be given another vcpu. */ lwsync - /* Clear any pending IPI - we're an offline thread */ - ld r5, HSTATE_XICS_PHYS(r13) - li r7, XICS_XIRR - lwzcix r3, r5, r7 /* ack any pending interrupt */ - rlwinm. r0, r3, 0, 0xffffff /* any pending? */ - beq 37f - sync - li r0, 0xff - li r6, XICS_MFRR - stbcix r0, r5, r6 /* clear the IPI */ - stwcix r3, r5, r7 /* EOI it */ -37: sync /* increment the nap count and then go to nap mode */ ld r4, HSTATE_KVM_VCORE(r13) @@ -253,6 +295,7 @@ kvm_start_guest: kvm_no_guest: li r0, KVM_HWTHREAD_IN_NAP stb r0, HSTATE_HWTHREAD_STATE(r13) +kvm_do_nap: li r3, LPCR_PECE0 mfspr r4, SPRN_LPCR rlwimi r4, r3, 0, LPCR_PECE0 | LPCR_PECE1 @@ -277,7 +320,7 @@ kvmppc_hv_entry: /* Required state: * - * R4 = vcpu pointer + * R4 = vcpu pointer (or NULL) * MSR = ~IR|DR * R13 = PACA * R1 = host R1 @@ -287,122 +330,12 @@ kvmppc_hv_entry: std r0, PPC_LR_STKOFF(r1) stdu r1, -112(r1) - /* Set partition DABR */ - /* Do this before re-enabling PMU to avoid P7 DABR corruption bug */ - li r5,3 - ld r6,VCPU_DABR(r4) - mtspr SPRN_DABRX,r5 - mtspr SPRN_DABR,r6 -BEGIN_FTR_SECTION - isync -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) - - /* Load guest PMU registers */ - /* R4 is live here (vcpu pointer) */ - li r3, 1 - sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ - mtspr SPRN_MMCR0, r3 /* freeze all counters, disable ints */ - isync - lwz r3, VCPU_PMC(r4) /* always load up guest PMU registers */ - lwz r5, VCPU_PMC + 4(r4) /* to prevent information leak */ - lwz r6, VCPU_PMC + 8(r4) - lwz r7, VCPU_PMC + 12(r4) - lwz r8, VCPU_PMC + 16(r4) - lwz r9, VCPU_PMC + 20(r4) -BEGIN_FTR_SECTION - lwz r10, VCPU_PMC + 24(r4) - lwz r11, VCPU_PMC + 28(r4) -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) - mtspr SPRN_PMC1, r3 - mtspr SPRN_PMC2, r5 - mtspr SPRN_PMC3, r6 - mtspr SPRN_PMC4, r7 - mtspr SPRN_PMC5, r8 - mtspr SPRN_PMC6, r9 -BEGIN_FTR_SECTION - mtspr SPRN_PMC7, r10 - mtspr SPRN_PMC8, r11 -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) - ld r3, VCPU_MMCR(r4) - ld r5, VCPU_MMCR + 8(r4) - ld r6, VCPU_MMCR + 16(r4) - ld r7, VCPU_SIAR(r4) - ld r8, VCPU_SDAR(r4) - mtspr SPRN_MMCR1, r5 - mtspr SPRN_MMCRA, r6 - mtspr SPRN_SIAR, r7 - mtspr SPRN_SDAR, r8 - mtspr SPRN_MMCR0, r3 - isync - - /* Load up FP, VMX and VSX registers */ - bl kvmppc_load_fp - - ld r14, VCPU_GPR(R14)(r4) - ld r15, VCPU_GPR(R15)(r4) - ld r16, VCPU_GPR(R16)(r4) - ld r17, VCPU_GPR(R17)(r4) - ld r18, VCPU_GPR(R18)(r4) - ld r19, VCPU_GPR(R19)(r4) - ld r20, VCPU_GPR(R20)(r4) - ld r21, VCPU_GPR(R21)(r4) - ld r22, VCPU_GPR(R22)(r4) - ld r23, VCPU_GPR(R23)(r4) - ld r24, VCPU_GPR(R24)(r4) - ld r25, VCPU_GPR(R25)(r4) - ld r26, VCPU_GPR(R26)(r4) - ld r27, VCPU_GPR(R27)(r4) - ld r28, VCPU_GPR(R28)(r4) - ld r29, VCPU_GPR(R29)(r4) - ld r30, VCPU_GPR(R30)(r4) - ld r31, VCPU_GPR(R31)(r4) - -BEGIN_FTR_SECTION - /* Switch DSCR to guest value */ - ld r5, VCPU_DSCR(r4) - mtspr SPRN_DSCR, r5 -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) - - /* - * Set the decrementer to the guest decrementer. - */ - ld r8,VCPU_DEC_EXPIRES(r4) - mftb r7 - subf r3,r7,r8 - mtspr SPRN_DEC,r3 - stw r3,VCPU_DEC(r4) - - ld r5, VCPU_SPRG0(r4) - ld r6, VCPU_SPRG1(r4) - ld r7, VCPU_SPRG2(r4) - ld r8, VCPU_SPRG3(r4) - mtspr SPRN_SPRG0, r5 - mtspr SPRN_SPRG1, r6 - mtspr SPRN_SPRG2, r7 - mtspr SPRN_SPRG3, r8 - /* Save R1 in the PACA */ std r1, HSTATE_HOST_R1(r13) - /* Load up DAR and DSISR */ - ld r5, VCPU_DAR(r4) - lwz r6, VCPU_DSISR(r4) - mtspr SPRN_DAR, r5 - mtspr SPRN_DSISR, r6 - li r6, KVM_GUEST_MODE_HOST_HV stb r6, HSTATE_IN_GUEST(r13) -BEGIN_FTR_SECTION - /* Restore AMR and UAMOR, set AMOR to all 1s */ - ld r5,VCPU_AMR(r4) - ld r6,VCPU_UAMOR(r4) - li r7,-1 - mtspr SPRN_AMR,r5 - mtspr SPRN_UAMOR,r6 - mtspr SPRN_AMOR,r7 -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) - /* Clear out SLB */ li r6,0 slbmte r6,r6 @@ -428,8 +361,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) bne 21b /* Primary thread switches to guest partition. */ - ld r9,VCPU_KVM(r4) /* pointer to struct kvm */ - lwz r6,VCPU_PTID(r4) + ld r9,VCORE_KVM(r5) /* pointer to struct kvm */ + lbz r6,HSTATE_PTID(r13) cmpwi r6,0 bne 20f ld r6,KVM_SDR1(r9) @@ -457,7 +390,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) andc r7,r7,r0 stdcx. r7,0,r6 bne 23b - li r6,128 /* and flush the TLB */ + /* Flush the TLB of any entries for this LPID */ + /* use arch 2.07S as a proxy for POWER8 */ +BEGIN_FTR_SECTION + li r6,512 /* POWER8 has 512 sets */ +FTR_SECTION_ELSE + li r6,128 /* POWER7 has 128 sets */ +ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_207S) mtctr r6 li r7,0x800 /* IS field = 0b10 */ ptesync @@ -487,6 +426,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) beq 38f mtspr SPRN_PCR, r7 38: + +BEGIN_FTR_SECTION + /* DPDES is shared between threads */ + ld r8, VCORE_DPDES(r5) + mtspr SPRN_DPDES, r8 +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) + li r0,1 stb r0,VCORE_IN_GUEST(r5) /* signal secondaries to continue */ b 10f @@ -503,32 +449,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) mtspr SPRN_RMOR,r8 isync - /* Increment yield count if they have a VPA */ - ld r3, VCPU_VPA(r4) - cmpdi r3, 0 - beq 25f - lwz r5, LPPACA_YIELDCOUNT(r3) - addi r5, r5, 1 - stw r5, LPPACA_YIELDCOUNT(r3) - li r6, 1 - stb r6, VCPU_VPA_DIRTY(r4) -25: /* Check if HDEC expires soon */ mfspr r3,SPRN_HDEC - cmpwi r3,10 + cmpwi r3,512 /* 1 microsecond */ li r12,BOOK3S_INTERRUPT_HV_DECREMENTER - mr r9,r4 blt hdec_soon - - /* Save purr/spurr */ - mfspr r5,SPRN_PURR - mfspr r6,SPRN_SPURR - std r5,HSTATE_PURR(r13) - std r6,HSTATE_SPURR(r13) - ld r7,VCPU_PURR(r4) - ld r8,VCPU_SPURR(r4) - mtspr SPRN_PURR,r7 - mtspr SPRN_SPURR,r8 b 31f /* @@ -539,7 +464,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) * We also have to invalidate the TLB since its * entries aren't tagged with the LPID. */ -30: ld r9,VCPU_KVM(r4) /* pointer to struct kvm */ +30: ld r5,HSTATE_KVM_VCORE(r13) + ld r9,VCORE_KVM(r5) /* pointer to struct kvm */ /* first take native_tlbie_lock */ .section ".toc","aw" @@ -604,7 +530,6 @@ toc_tlbie_lock: mfspr r3,SPRN_HDEC cmpwi r3,10 li r12,BOOK3S_INTERRUPT_HV_DECREMENTER - mr r9,r4 blt hdec_soon /* Enable HDEC interrupts */ @@ -619,9 +544,14 @@ toc_tlbie_lock: mfspr r0,SPRN_HID0 mfspr r0,SPRN_HID0 mfspr r0,SPRN_HID0 +31: + /* Do we have a guest vcpu to run? */ + cmpdi r4, 0 + beq kvmppc_primary_no_guest +kvmppc_got_guest: /* Load up guest SLB entries */ -31: lwz r5,VCPU_SLB_MAX(r4) + lwz r5,VCPU_SLB_MAX(r4) cmpwi r5,0 beq 9f mtctr r5 @@ -632,6 +562,209 @@ toc_tlbie_lock: addi r6,r6,VCPU_SLB_SIZE bdnz 1b 9: + /* Increment yield count if they have a VPA */ + ld r3, VCPU_VPA(r4) + cmpdi r3, 0 + beq 25f + lwz r5, LPPACA_YIELDCOUNT(r3) + addi r5, r5, 1 + stw r5, LPPACA_YIELDCOUNT(r3) + li r6, 1 + stb r6, VCPU_VPA_DIRTY(r4) +25: + +BEGIN_FTR_SECTION + /* Save purr/spurr */ + mfspr r5,SPRN_PURR + mfspr r6,SPRN_SPURR + std r5,HSTATE_PURR(r13) + std r6,HSTATE_SPURR(r13) + ld r7,VCPU_PURR(r4) + ld r8,VCPU_SPURR(r4) + mtspr SPRN_PURR,r7 + mtspr SPRN_SPURR,r8 +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) + +BEGIN_FTR_SECTION + /* Set partition DABR */ + /* Do this before re-enabling PMU to avoid P7 DABR corruption bug */ + lwz r5,VCPU_DABRX(r4) + ld r6,VCPU_DABR(r4) + mtspr SPRN_DABRX,r5 + mtspr SPRN_DABR,r6 + BEGIN_FTR_SECTION_NESTED(89) + isync + END_FTR_SECTION_NESTED(CPU_FTR_ARCH_206, CPU_FTR_ARCH_206, 89) +END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) + + /* Load guest PMU registers */ + /* R4 is live here (vcpu pointer) */ + li r3, 1 + sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ + mtspr SPRN_MMCR0, r3 /* freeze all counters, disable ints */ + isync + lwz r3, VCPU_PMC(r4) /* always load up guest PMU registers */ + lwz r5, VCPU_PMC + 4(r4) /* to prevent information leak */ + lwz r6, VCPU_PMC + 8(r4) + lwz r7, VCPU_PMC + 12(r4) + lwz r8, VCPU_PMC + 16(r4) + lwz r9, VCPU_PMC + 20(r4) +BEGIN_FTR_SECTION + lwz r10, VCPU_PMC + 24(r4) + lwz r11, VCPU_PMC + 28(r4) +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) + mtspr SPRN_PMC1, r3 + mtspr SPRN_PMC2, r5 + mtspr SPRN_PMC3, r6 + mtspr SPRN_PMC4, r7 + mtspr SPRN_PMC5, r8 + mtspr SPRN_PMC6, r9 +BEGIN_FTR_SECTION + mtspr SPRN_PMC7, r10 + mtspr SPRN_PMC8, r11 +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) + ld r3, VCPU_MMCR(r4) + ld r5, VCPU_MMCR + 8(r4) + ld r6, VCPU_MMCR + 16(r4) + ld r7, VCPU_SIAR(r4) + ld r8, VCPU_SDAR(r4) + mtspr SPRN_MMCR1, r5 + mtspr SPRN_MMCRA, r6 + mtspr SPRN_SIAR, r7 + mtspr SPRN_SDAR, r8 +BEGIN_FTR_SECTION + ld r5, VCPU_MMCR + 24(r4) + ld r6, VCPU_SIER(r4) + lwz r7, VCPU_PMC + 24(r4) + lwz r8, VCPU_PMC + 28(r4) + ld r9, VCPU_MMCR + 32(r4) + mtspr SPRN_MMCR2, r5 + mtspr SPRN_SIER, r6 + mtspr SPRN_SPMC1, r7 + mtspr SPRN_SPMC2, r8 + mtspr SPRN_MMCRS, r9 +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) + mtspr SPRN_MMCR0, r3 + isync + + /* Load up FP, VMX and VSX registers */ + bl kvmppc_load_fp + + ld r14, VCPU_GPR(R14)(r4) + ld r15, VCPU_GPR(R15)(r4) + ld r16, VCPU_GPR(R16)(r4) + ld r17, VCPU_GPR(R17)(r4) + ld r18, VCPU_GPR(R18)(r4) + ld r19, VCPU_GPR(R19)(r4) + ld r20, VCPU_GPR(R20)(r4) + ld r21, VCPU_GPR(R21)(r4) + ld r22, VCPU_GPR(R22)(r4) + ld r23, VCPU_GPR(R23)(r4) + ld r24, VCPU_GPR(R24)(r4) + ld r25, VCPU_GPR(R25)(r4) + ld r26, VCPU_GPR(R26)(r4) + ld r27, VCPU_GPR(R27)(r4) + ld r28, VCPU_GPR(R28)(r4) + ld r29, VCPU_GPR(R29)(r4) + ld r30, VCPU_GPR(R30)(r4) + ld r31, VCPU_GPR(R31)(r4) + +BEGIN_FTR_SECTION + /* Switch DSCR to guest value */ + ld r5, VCPU_DSCR(r4) + mtspr SPRN_DSCR, r5 +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) + +BEGIN_FTR_SECTION + /* Skip next section on POWER7 or PPC970 */ + b 8f +END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) + /* Turn on TM so we can access TFHAR/TFIAR/TEXASR */ + mfmsr r8 + li r0, 1 + rldimi r8, r0, MSR_TM_LG, 63-MSR_TM_LG + mtmsrd r8 + + /* Load up POWER8-specific registers */ + ld r5, VCPU_IAMR(r4) + lwz r6, VCPU_PSPB(r4) + ld r7, VCPU_FSCR(r4) + mtspr SPRN_IAMR, r5 + mtspr SPRN_PSPB, r6 + mtspr SPRN_FSCR, r7 + ld r5, VCPU_DAWR(r4) + ld r6, VCPU_DAWRX(r4) + ld r7, VCPU_CIABR(r4) + ld r8, VCPU_TAR(r4) + mtspr SPRN_DAWR, r5 + mtspr SPRN_DAWRX, r6 + mtspr SPRN_CIABR, r7 + mtspr SPRN_TAR, r8 + ld r5, VCPU_IC(r4) + ld r6, VCPU_VTB(r4) + mtspr SPRN_IC, r5 + mtspr SPRN_VTB, r6 +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + ld r5, VCPU_TFHAR(r4) + ld r6, VCPU_TFIAR(r4) + ld r7, VCPU_TEXASR(r4) + mtspr SPRN_TFHAR, r5 + mtspr SPRN_TFIAR, r6 + mtspr SPRN_TEXASR, r7 +#endif + ld r8, VCPU_EBBHR(r4) + mtspr SPRN_EBBHR, r8 + ld r5, VCPU_EBBRR(r4) + ld r6, VCPU_BESCR(r4) + ld r7, VCPU_CSIGR(r4) + ld r8, VCPU_TACR(r4) + mtspr SPRN_EBBRR, r5 + mtspr SPRN_BESCR, r6 + mtspr SPRN_CSIGR, r7 + mtspr SPRN_TACR, r8 + ld r5, VCPU_TCSCR(r4) + ld r6, VCPU_ACOP(r4) + lwz r7, VCPU_GUEST_PID(r4) + ld r8, VCPU_WORT(r4) + mtspr SPRN_TCSCR, r5 + mtspr SPRN_ACOP, r6 + mtspr SPRN_PID, r7 + mtspr SPRN_WORT, r8 +8: + + /* + * Set the decrementer to the guest decrementer. + */ + ld r8,VCPU_DEC_EXPIRES(r4) + mftb r7 + subf r3,r7,r8 + mtspr SPRN_DEC,r3 + stw r3,VCPU_DEC(r4) + + ld r5, VCPU_SPRG0(r4) + ld r6, VCPU_SPRG1(r4) + ld r7, VCPU_SPRG2(r4) + ld r8, VCPU_SPRG3(r4) + mtspr SPRN_SPRG0, r5 + mtspr SPRN_SPRG1, r6 + mtspr SPRN_SPRG2, r7 + mtspr SPRN_SPRG3, r8 + + /* Load up DAR and DSISR */ + ld r5, VCPU_DAR(r4) + lwz r6, VCPU_DSISR(r4) + mtspr SPRN_DAR, r5 + mtspr SPRN_DSISR, r6 + +BEGIN_FTR_SECTION + /* Restore AMR and UAMOR, set AMOR to all 1s */ + ld r5,VCPU_AMR(r4) + ld r6,VCPU_UAMOR(r4) + li r7,-1 + mtspr SPRN_AMR,r5 + mtspr SPRN_UAMOR,r6 + mtspr SPRN_AMOR,r7 +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) /* Restore state of CTRL run bit; assume 1 on entry */ lwz r5,VCPU_CTRL(r4) @@ -647,48 +780,53 @@ toc_tlbie_lock: mtctr r6 mtxer r7 +kvmppc_cede_reentry: /* r4 = vcpu, r13 = paca */ ld r10, VCPU_PC(r4) ld r11, VCPU_MSR(r4) -kvmppc_cede_reentry: /* r4 = vcpu, r13 = paca */ ld r6, VCPU_SRR0(r4) ld r7, VCPU_SRR1(r4) + mtspr SPRN_SRR0, r6 + mtspr SPRN_SRR1, r7 +deliver_guest_interrupt: /* r11 = vcpu->arch.msr & ~MSR_HV */ rldicl r11, r11, 63 - MSR_HV_LG, 1 rotldi r11, r11, 1 + MSR_HV_LG ori r11, r11, MSR_ME /* Check if we can deliver an external or decrementer interrupt now */ - ld r0,VCPU_PENDING_EXC(r4) - lis r8,(1 << BOOK3S_IRQPRIO_EXTERNAL_LEVEL)@h - and r0,r0,r8 - cmpdi cr1,r0,0 - andi. r0,r11,MSR_EE - beq cr1,11f + ld r0, VCPU_PENDING_EXC(r4) + rldicl r0, r0, 64 - BOOK3S_IRQPRIO_EXTERNAL_LEVEL, 63 + cmpdi cr1, r0, 0 + andi. r8, r11, MSR_EE BEGIN_FTR_SECTION - mfspr r8,SPRN_LPCR - ori r8,r8,LPCR_MER - mtspr SPRN_LPCR,r8 + mfspr r8, SPRN_LPCR + /* Insert EXTERNAL_LEVEL bit into LPCR at the MER bit position */ + rldimi r8, r0, LPCR_MER_SH, 63 - LPCR_MER_SH + mtspr SPRN_LPCR, r8 isync END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) beq 5f - li r0,BOOK3S_INTERRUPT_EXTERNAL -12: mr r6,r10 - mr r10,r0 - mr r7,r11 - li r11,(MSR_ME << 1) | 1 /* synthesize MSR_SF | MSR_ME */ - rotldi r11,r11,63 - b 5f -11: beq 5f - mfspr r0,SPRN_DEC - cmpwi r0,0 - li r0,BOOK3S_INTERRUPT_DECREMENTER - blt 12b + li r0, BOOK3S_INTERRUPT_EXTERNAL + bne cr1, 12f + mfspr r0, SPRN_DEC + cmpwi r0, 0 + li r0, BOOK3S_INTERRUPT_DECREMENTER + bge 5f - /* Move SRR0 and SRR1 into the respective regs */ -5: mtspr SPRN_SRR0, r6 - mtspr SPRN_SRR1, r7 +12: mtspr SPRN_SRR0, r10 + mr r10,r0 + mtspr SPRN_SRR1, r11 + ld r11, VCPU_INTR_MSR(r4) +5: +/* + * Required state: + * R4 = vcpu + * R10: value for HSRR0 + * R11: value for HSRR1 + * R13 = PACA + */ fast_guest_return: li r0,0 stb r0,VCPU_CEDED(r4) /* cancel cede */ @@ -868,39 +1006,19 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206) /* External interrupt, first check for host_ipi. If this is * set, we know the host wants us out so let's do it now */ -do_ext_interrupt: bl kvmppc_read_intr cmpdi r3, 0 bgt ext_interrupt_to_host - /* Allright, looks like an IPI for the guest, we need to set MER */ /* Check if any CPU is heading out to the host, if so head out too */ ld r5, HSTATE_KVM_VCORE(r13) lwz r0, VCORE_ENTRY_EXIT(r5) cmpwi r0, 0x100 bge ext_interrupt_to_host - /* See if there is a pending interrupt for the guest */ - mfspr r8, SPRN_LPCR - ld r0, VCPU_PENDING_EXC(r9) - /* Insert EXTERNAL_LEVEL bit into LPCR at the MER bit position */ - rldicl. r0, r0, 64 - BOOK3S_IRQPRIO_EXTERNAL_LEVEL, 63 - rldimi r8, r0, LPCR_MER_SH, 63 - LPCR_MER_SH - beq 2f - - /* And if the guest EE is set, we can deliver immediately, else - * we return to the guest with MER set - */ - andi. r0, r11, MSR_EE - beq 2f - mtspr SPRN_SRR0, r10 - mtspr SPRN_SRR1, r11 - li r10, BOOK3S_INTERRUPT_EXTERNAL - li r11, (MSR_ME << 1) | 1 /* synthesize MSR_SF | MSR_ME */ - rotldi r11, r11, 63 -2: mr r4, r9 - mtspr SPRN_LPCR, r8 - b fast_guest_return + /* Return to guest after delivering any pending interrupt */ + mr r4, r9 + b deliver_guest_interrupt ext_interrupt_to_host: @@ -963,25 +1081,206 @@ BEGIN_FTR_SECTION subf r5,r7,r5 subf r6,r8,r6 - /* - * Restore host PURR/SPURR and add guest times - * so that the time in the guest gets accounted. - */ - ld r3,HSTATE_PURR(r13) - ld r4,HSTATE_SPURR(r13) - add r3,r3,r5 - add r4,r4,r6 - mtspr SPRN_PURR,r3 - mtspr SPRN_SPURR,r4 -END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_201) + /* + * Restore host PURR/SPURR and add guest times + * so that the time in the guest gets accounted. + */ + ld r3,HSTATE_PURR(r13) + ld r4,HSTATE_SPURR(r13) + add r3,r3,r5 + add r4,r4,r6 + mtspr SPRN_PURR,r3 + mtspr SPRN_SPURR,r4 +END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_201) + + /* Save DEC */ + mfspr r5,SPRN_DEC + mftb r6 + extsw r5,r5 + add r5,r5,r6 + std r5,VCPU_DEC_EXPIRES(r9) + +BEGIN_FTR_SECTION + b 8f +END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) + /* Turn on TM so we can access TFHAR/TFIAR/TEXASR */ + mfmsr r8 + li r0, 1 + rldimi r8, r0, MSR_TM_LG, 63-MSR_TM_LG + mtmsrd r8 + + /* Save POWER8-specific registers */ + mfspr r5, SPRN_IAMR + mfspr r6, SPRN_PSPB + mfspr r7, SPRN_FSCR + std r5, VCPU_IAMR(r9) + stw r6, VCPU_PSPB(r9) + std r7, VCPU_FSCR(r9) + mfspr r5, SPRN_IC + mfspr r6, SPRN_VTB + mfspr r7, SPRN_TAR + std r5, VCPU_IC(r9) + std r6, VCPU_VTB(r9) + std r7, VCPU_TAR(r9) +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + mfspr r5, SPRN_TFHAR + mfspr r6, SPRN_TFIAR + mfspr r7, SPRN_TEXASR + std r5, VCPU_TFHAR(r9) + std r6, VCPU_TFIAR(r9) + std r7, VCPU_TEXASR(r9) +#endif + mfspr r8, SPRN_EBBHR + std r8, VCPU_EBBHR(r9) + mfspr r5, SPRN_EBBRR + mfspr r6, SPRN_BESCR + mfspr r7, SPRN_CSIGR + mfspr r8, SPRN_TACR + std r5, VCPU_EBBRR(r9) + std r6, VCPU_BESCR(r9) + std r7, VCPU_CSIGR(r9) + std r8, VCPU_TACR(r9) + mfspr r5, SPRN_TCSCR + mfspr r6, SPRN_ACOP + mfspr r7, SPRN_PID + mfspr r8, SPRN_WORT + std r5, VCPU_TCSCR(r9) + std r6, VCPU_ACOP(r9) + stw r7, VCPU_GUEST_PID(r9) + std r8, VCPU_WORT(r9) +8: + + /* Save and reset AMR and UAMOR before turning on the MMU */ +BEGIN_FTR_SECTION + mfspr r5,SPRN_AMR + mfspr r6,SPRN_UAMOR + std r5,VCPU_AMR(r9) + std r6,VCPU_UAMOR(r9) + li r6,0 + mtspr SPRN_AMR,r6 +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) + + /* Switch DSCR back to host value */ +BEGIN_FTR_SECTION + mfspr r8, SPRN_DSCR + ld r7, HSTATE_DSCR(r13) + std r8, VCPU_DSCR(r9) + mtspr SPRN_DSCR, r7 +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) + + /* Save non-volatile GPRs */ + std r14, VCPU_GPR(R14)(r9) + std r15, VCPU_GPR(R15)(r9) + std r16, VCPU_GPR(R16)(r9) + std r17, VCPU_GPR(R17)(r9) + std r18, VCPU_GPR(R18)(r9) + std r19, VCPU_GPR(R19)(r9) + std r20, VCPU_GPR(R20)(r9) + std r21, VCPU_GPR(R21)(r9) + std r22, VCPU_GPR(R22)(r9) + std r23, VCPU_GPR(R23)(r9) + std r24, VCPU_GPR(R24)(r9) + std r25, VCPU_GPR(R25)(r9) + std r26, VCPU_GPR(R26)(r9) + std r27, VCPU_GPR(R27)(r9) + std r28, VCPU_GPR(R28)(r9) + std r29, VCPU_GPR(R29)(r9) + std r30, VCPU_GPR(R30)(r9) + std r31, VCPU_GPR(R31)(r9) + + /* Save SPRGs */ + mfspr r3, SPRN_SPRG0 + mfspr r4, SPRN_SPRG1 + mfspr r5, SPRN_SPRG2 + mfspr r6, SPRN_SPRG3 + std r3, VCPU_SPRG0(r9) + std r4, VCPU_SPRG1(r9) + std r5, VCPU_SPRG2(r9) + std r6, VCPU_SPRG3(r9) + + /* save FP state */ + mr r3, r9 + bl kvmppc_save_fp + /* Increment yield count if they have a VPA */ + ld r8, VCPU_VPA(r9) /* do they have a VPA? */ + cmpdi r8, 0 + beq 25f + lwz r3, LPPACA_YIELDCOUNT(r8) + addi r3, r3, 1 + stw r3, LPPACA_YIELDCOUNT(r8) + li r3, 1 + stb r3, VCPU_VPA_DIRTY(r9) +25: + /* Save PMU registers if requested */ + /* r8 and cr0.eq are live here */ + li r3, 1 + sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ + mfspr r4, SPRN_MMCR0 /* save MMCR0 */ + mtspr SPRN_MMCR0, r3 /* freeze all counters, disable ints */ + mfspr r6, SPRN_MMCRA +BEGIN_FTR_SECTION + /* On P7, clear MMCRA in order to disable SDAR updates */ + li r7, 0 + mtspr SPRN_MMCRA, r7 +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) + isync + beq 21f /* if no VPA, save PMU stuff anyway */ + lbz r7, LPPACA_PMCINUSE(r8) + cmpwi r7, 0 /* did they ask for PMU stuff to be saved? */ + bne 21f + std r3, VCPU_MMCR(r9) /* if not, set saved MMCR0 to FC */ + b 22f +21: mfspr r5, SPRN_MMCR1 + mfspr r7, SPRN_SIAR + mfspr r8, SPRN_SDAR + std r4, VCPU_MMCR(r9) + std r5, VCPU_MMCR + 8(r9) + std r6, VCPU_MMCR + 16(r9) + std r7, VCPU_SIAR(r9) + std r8, VCPU_SDAR(r9) + mfspr r3, SPRN_PMC1 + mfspr r4, SPRN_PMC2 + mfspr r5, SPRN_PMC3 + mfspr r6, SPRN_PMC4 + mfspr r7, SPRN_PMC5 + mfspr r8, SPRN_PMC6 +BEGIN_FTR_SECTION + mfspr r10, SPRN_PMC7 + mfspr r11, SPRN_PMC8 +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) + stw r3, VCPU_PMC(r9) + stw r4, VCPU_PMC + 4(r9) + stw r5, VCPU_PMC + 8(r9) + stw r6, VCPU_PMC + 12(r9) + stw r7, VCPU_PMC + 16(r9) + stw r8, VCPU_PMC + 20(r9) +BEGIN_FTR_SECTION + stw r10, VCPU_PMC + 24(r9) + stw r11, VCPU_PMC + 28(r9) +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) +BEGIN_FTR_SECTION + mfspr r4, SPRN_MMCR2 + mfspr r5, SPRN_SIER + mfspr r6, SPRN_SPMC1 + mfspr r7, SPRN_SPMC2 + mfspr r8, SPRN_MMCRS + std r4, VCPU_MMCR + 24(r9) + std r5, VCPU_SIER(r9) + stw r6, VCPU_PMC + 24(r9) + stw r7, VCPU_PMC + 28(r9) + std r8, VCPU_MMCR + 32(r9) + lis r4, 0x8000 + mtspr SPRN_MMCRS, r4 +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) +22: /* Clear out SLB */ li r5,0 slbmte r5,r5 slbia ptesync -hdec_soon: /* r9 = vcpu, r12 = trap, r13 = paca */ +hdec_soon: /* r12 = trap, r13 = paca */ BEGIN_FTR_SECTION b 32f END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) @@ -1014,8 +1313,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) */ cmpwi r3,0x100 /* Are we the first here? */ bge 43f - cmpwi r3,1 /* Are any other threads in the guest? */ - ble 43f cmpwi r12,BOOK3S_INTERRUPT_HV_DECREMENTER beq 40f li r0,0 @@ -1026,7 +1323,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) * doesn't wake CPUs up from nap. */ lwz r3,VCORE_NAPPING_THREADS(r5) - lwz r4,VCPU_PTID(r9) + lbz r4,HSTATE_PTID(r13) li r0,1 sld r0,r0,r4 andc. r3,r3,r0 /* no sense IPI'ing ourselves */ @@ -1045,10 +1342,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) addi r6,r6,PACA_SIZE bne 42b +secondary_too_late: /* Secondary threads wait for primary to do partition switch */ -43: ld r4,VCPU_KVM(r9) /* pointer to struct kvm */ - ld r5,HSTATE_KVM_VCORE(r13) - lwz r3,VCPU_PTID(r9) +43: ld r5,HSTATE_KVM_VCORE(r13) + ld r4,VCORE_KVM(r5) /* pointer to struct kvm */ + lbz r3,HSTATE_PTID(r13) cmpwi r3,0 beq 15f HMT_LOW @@ -1076,6 +1374,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) mtspr SPRN_LPID,r7 isync +BEGIN_FTR_SECTION + /* DPDES is shared between threads */ + mfspr r7, SPRN_DPDES + std r7, VCORE_DPDES(r5) + /* clear DPDES so we don't get guest doorbells in the host */ + li r8, 0 + mtspr SPRN_DPDES, r8 +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) + /* Subtract timebase offset from timebase */ ld r8,VCORE_TB_OFFSET(r5) cmpdi r8,0 @@ -1113,7 +1420,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) * We have to lock against concurrent tlbies, and * we have to flush the whole TLB. */ -32: ld r4,VCPU_KVM(r9) /* pointer to struct kvm */ +32: ld r5,HSTATE_KVM_VCORE(r13) + ld r4,VCORE_KVM(r5) /* pointer to struct kvm */ /* Take the guest's tlbie_lock */ #ifdef __BIG_ENDIAN__ @@ -1203,6 +1511,56 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) add r5,r5,r6 std r5,VCPU_DEC_EXPIRES(r9) +BEGIN_FTR_SECTION + b 8f +END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) + /* Turn on TM so we can access TFHAR/TFIAR/TEXASR */ + mfmsr r8 + li r0, 1 + rldimi r8, r0, MSR_TM_LG, 63-MSR_TM_LG + mtmsrd r8 + + /* Save POWER8-specific registers */ + mfspr r5, SPRN_IAMR + mfspr r6, SPRN_PSPB + mfspr r7, SPRN_FSCR + std r5, VCPU_IAMR(r9) + stw r6, VCPU_PSPB(r9) + std r7, VCPU_FSCR(r9) + mfspr r5, SPRN_IC + mfspr r6, SPRN_VTB + mfspr r7, SPRN_TAR + std r5, VCPU_IC(r9) + std r6, VCPU_VTB(r9) + std r7, VCPU_TAR(r9) +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + mfspr r5, SPRN_TFHAR + mfspr r6, SPRN_TFIAR + mfspr r7, SPRN_TEXASR + std r5, VCPU_TFHAR(r9) + std r6, VCPU_TFIAR(r9) + std r7, VCPU_TEXASR(r9) +#endif + mfspr r8, SPRN_EBBHR + std r8, VCPU_EBBHR(r9) + mfspr r5, SPRN_EBBRR + mfspr r6, SPRN_BESCR + mfspr r7, SPRN_CSIGR + mfspr r8, SPRN_TACR + std r5, VCPU_EBBRR(r9) + std r6, VCPU_BESCR(r9) + std r7, VCPU_CSIGR(r9) + std r8, VCPU_TACR(r9) + mfspr r5, SPRN_TCSCR + mfspr r6, SPRN_ACOP + mfspr r7, SPRN_PID + mfspr r8, SPRN_WORT + std r5, VCPU_TCSCR(r9) + std r6, VCPU_ACOP(r9) + stw r7, VCPU_GUEST_PID(r9) + std r8, VCPU_WORT(r9) +8: + /* Save and reset AMR and UAMOR before turning on the MMU */ BEGIN_FTR_SECTION mfspr r5,SPRN_AMR @@ -1217,130 +1575,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) li r0, KVM_GUEST_MODE_NONE stb r0, HSTATE_IN_GUEST(r13) - /* Switch DSCR back to host value */ -BEGIN_FTR_SECTION - mfspr r8, SPRN_DSCR - ld r7, HSTATE_DSCR(r13) - std r8, VCPU_DSCR(r9) - mtspr SPRN_DSCR, r7 -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) - - /* Save non-volatile GPRs */ - std r14, VCPU_GPR(R14)(r9) - std r15, VCPU_GPR(R15)(r9) - std r16, VCPU_GPR(R16)(r9) - std r17, VCPU_GPR(R17)(r9) - std r18, VCPU_GPR(R18)(r9) - std r19, VCPU_GPR(R19)(r9) - std r20, VCPU_GPR(R20)(r9) - std r21, VCPU_GPR(R21)(r9) - std r22, VCPU_GPR(R22)(r9) - std r23, VCPU_GPR(R23)(r9) - std r24, VCPU_GPR(R24)(r9) - std r25, VCPU_GPR(R25)(r9) - std r26, VCPU_GPR(R26)(r9) - std r27, VCPU_GPR(R27)(r9) - std r28, VCPU_GPR(R28)(r9) - std r29, VCPU_GPR(R29)(r9) - std r30, VCPU_GPR(R30)(r9) - std r31, VCPU_GPR(R31)(r9) - - /* Save SPRGs */ - mfspr r3, SPRN_SPRG0 - mfspr r4, SPRN_SPRG1 - mfspr r5, SPRN_SPRG2 - mfspr r6, SPRN_SPRG3 - std r3, VCPU_SPRG0(r9) - std r4, VCPU_SPRG1(r9) - std r5, VCPU_SPRG2(r9) - std r6, VCPU_SPRG3(r9) - - /* save FP state */ - mr r3, r9 - bl .kvmppc_save_fp - - /* Increment yield count if they have a VPA */ - ld r8, VCPU_VPA(r9) /* do they have a VPA? */ - cmpdi r8, 0 - beq 25f - lwz r3, LPPACA_YIELDCOUNT(r8) - addi r3, r3, 1 - stw r3, LPPACA_YIELDCOUNT(r8) - li r3, 1 - stb r3, VCPU_VPA_DIRTY(r9) -25: - /* Save PMU registers if requested */ - /* r8 and cr0.eq are live here */ - li r3, 1 - sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ - mfspr r4, SPRN_MMCR0 /* save MMCR0 */ - mtspr SPRN_MMCR0, r3 /* freeze all counters, disable ints */ - mfspr r6, SPRN_MMCRA -BEGIN_FTR_SECTION - /* On P7, clear MMCRA in order to disable SDAR updates */ - li r7, 0 - mtspr SPRN_MMCRA, r7 -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) - isync - beq 21f /* if no VPA, save PMU stuff anyway */ - lbz r7, LPPACA_PMCINUSE(r8) - cmpwi r7, 0 /* did they ask for PMU stuff to be saved? */ - bne 21f - std r3, VCPU_MMCR(r9) /* if not, set saved MMCR0 to FC */ - b 22f -21: mfspr r5, SPRN_MMCR1 - mfspr r7, SPRN_SIAR - mfspr r8, SPRN_SDAR - std r4, VCPU_MMCR(r9) - std r5, VCPU_MMCR + 8(r9) - std r6, VCPU_MMCR + 16(r9) - std r7, VCPU_SIAR(r9) - std r8, VCPU_SDAR(r9) - mfspr r3, SPRN_PMC1 - mfspr r4, SPRN_PMC2 - mfspr r5, SPRN_PMC3 - mfspr r6, SPRN_PMC4 - mfspr r7, SPRN_PMC5 - mfspr r8, SPRN_PMC6 -BEGIN_FTR_SECTION - mfspr r10, SPRN_PMC7 - mfspr r11, SPRN_PMC8 -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) - stw r3, VCPU_PMC(r9) - stw r4, VCPU_PMC + 4(r9) - stw r5, VCPU_PMC + 8(r9) - stw r6, VCPU_PMC + 12(r9) - stw r7, VCPU_PMC + 16(r9) - stw r8, VCPU_PMC + 20(r9) -BEGIN_FTR_SECTION - stw r10, VCPU_PMC + 24(r9) - stw r11, VCPU_PMC + 28(r9) -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) -22: ld r0, 112+PPC_LR_STKOFF(r1) addi r1, r1, 112 mtlr r0 blr -secondary_too_late: - ld r5,HSTATE_KVM_VCORE(r13) - HMT_LOW -13: lbz r3,VCORE_IN_GUEST(r5) - cmpwi r3,0 - bne 13b - HMT_MEDIUM - li r0, KVM_GUEST_MODE_NONE - stb r0, HSTATE_IN_GUEST(r13) - ld r11,PACA_SLBSHADOWPTR(r13) - - .rept SLB_NUM_BOLTED - ld r5,SLBSHADOW_SAVEAREA(r11) - ld r6,SLBSHADOW_SAVEAREA+8(r11) - andis. r7,r5,SLB_ESID_V@h - beq 1f - slbmte r6,r5 -1: addi r11,r11,16 - .endr - b 22b /* * Check whether an HDSI is an HPTE not found fault or something else. @@ -1386,8 +1624,7 @@ kvmppc_hdsi: mtspr SPRN_SRR0, r10 mtspr SPRN_SRR1, r11 li r10, BOOK3S_INTERRUPT_DATA_STORAGE - li r11, (MSR_ME << 1) | 1 /* synthesize MSR_SF | MSR_ME */ - rotldi r11, r11, 63 + ld r11, VCPU_INTR_MSR(r9) fast_interrupt_c_return: 6: ld r7, VCPU_CTR(r9) lwz r8, VCPU_XER(r9) @@ -1456,8 +1693,7 @@ kvmppc_hisi: 1: mtspr SPRN_SRR0, r10 mtspr SPRN_SRR1, r11 li r10, BOOK3S_INTERRUPT_INST_STORAGE - li r11, (MSR_ME << 1) | 1 /* synthesize MSR_SF | MSR_ME */ - rotldi r11, r11, 63 + ld r11, VCPU_INTR_MSR(r9) b fast_interrupt_c_return 3: ld r6, VCPU_KVM(r9) /* not relocated, use VRMA */ @@ -1474,7 +1710,8 @@ kvmppc_hisi: hcall_try_real_mode: ld r3,VCPU_GPR(R3)(r9) andi. r0,r11,MSR_PR - bne guest_exit_cont + /* sc 1 from userspace - reflect to guest syscall */ + bne sc_1_fast_return clrrdi r3,r3,2 cmpldi r3,hcall_real_table_end - hcall_real_table bge guest_exit_cont @@ -1495,6 +1732,14 @@ hcall_try_real_mode: ld r11,VCPU_MSR(r4) b fast_guest_return +sc_1_fast_return: + mtspr SPRN_SRR0,r10 + mtspr SPRN_SRR1,r11 + li r10, BOOK3S_INTERRUPT_SYSCALL + ld r11, VCPU_INTR_MSR(r9) + mr r4,r9 + b fast_guest_return + /* We've attempted a real mode hcall, but it's punted it back * to userspace. We need to restore some clobbered volatiles * before resuming the pass-it-to-qemu path */ @@ -1588,14 +1833,34 @@ hcall_real_table: .long 0 /* 0x11c */ .long 0 /* 0x120 */ .long .kvmppc_h_bulk_remove - hcall_real_table + .long 0 /* 0x128 */ + .long 0 /* 0x12c */ + .long 0 /* 0x130 */ + .long .kvmppc_h_set_xdabr - hcall_real_table hcall_real_table_end: ignore_hdec: mr r4,r9 b fast_guest_return +_GLOBAL(kvmppc_h_set_xdabr) + andi. r0, r5, DABRX_USER | DABRX_KERNEL + beq 6f + li r0, DABRX_USER | DABRX_KERNEL | DABRX_BTI + andc. r0, r5, r0 + beq 3f +6: li r3, H_PARAMETER + blr + _GLOBAL(kvmppc_h_set_dabr) + li r5, DABRX_USER | DABRX_KERNEL +3: +BEGIN_FTR_SECTION + b 2f +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) std r4,VCPU_DABR(r3) + stw r5, VCPU_DABRX(r3) + mtspr SPRN_DABRX, r5 /* Work around P7 bug where DABR can get corrupted on mtspr */ 1: mtspr SPRN_DABR,r4 mfspr r5, SPRN_DABR @@ -1605,6 +1870,17 @@ _GLOBAL(kvmppc_h_set_dabr) li r3,0 blr + /* Emulate H_SET_DABR/X on P8 for the sake of compat mode guests */ +2: rlwimi r5, r4, 5, DAWRX_DR | DAWRX_DW + rlwimi r5, r4, 1, DAWRX_WT + clrrdi r4, r4, 3 + std r4, VCPU_DAWR(r3) + std r5, VCPU_DAWRX(r3) + mtspr SPRN_DAWR, r4 + mtspr SPRN_DAWRX, r5 + li r3, 0 + blr + _GLOBAL(kvmppc_h_cede) ori r11,r11,MSR_EE std r11,VCPU_MSR(r3) @@ -1628,7 +1904,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206) * up to the host. */ ld r5,HSTATE_KVM_VCORE(r13) - lwz r6,VCPU_PTID(r3) + lbz r6,HSTATE_PTID(r13) lwz r8,VCORE_ENTRY_EXIT(r5) clrldi r8,r8,56 li r0,1 @@ -1643,9 +1919,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206) bne 31b /* order napping_threads update vs testing entry_exit_count */ isync - li r0,1 + li r0,NAPPING_CEDE stb r0,HSTATE_NAPPING(r13) - mr r4,r3 lwz r7,VCORE_ENTRY_EXIT(r5) cmpwi r7,0x100 bge 33f /* another thread already exiting */ @@ -1677,16 +1952,19 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206) std r31, VCPU_GPR(R31)(r3) /* save FP state */ - bl .kvmppc_save_fp + bl kvmppc_save_fp /* - * Take a nap until a decrementer or external interrupt occurs, - * with PECE1 (wake on decr) and PECE0 (wake on external) set in LPCR + * Take a nap until a decrementer or external or doobell interrupt + * occurs, with PECE1, PECE0 and PECEDP set in LPCR */ li r0,1 stb r0,HSTATE_HWTHREAD_REQ(r13) mfspr r5,SPRN_LPCR ori r5,r5,LPCR_PECE0 | LPCR_PECE1 +BEGIN_FTR_SECTION + oris r5,r5,LPCR_PECEDP@h +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) mtspr SPRN_LPCR,r5 isync li r0, 0 @@ -1698,6 +1976,11 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206) nap b . +33: mr r4, r3 + li r3, 0 + li r12, 0 + b 34f + kvm_end_cede: /* get vcpu pointer */ ld r4, HSTATE_KVM_VCPU(r13) @@ -1727,12 +2010,15 @@ kvm_end_cede: ld r29, VCPU_GPR(R29)(r4) ld r30, VCPU_GPR(R30)(r4) ld r31, VCPU_GPR(R31)(r4) + + /* Check the wake reason in SRR1 to see why we got here */ + bl kvmppc_check_wake_reason /* clear our bit in vcore->napping_threads */ -33: ld r5,HSTATE_KVM_VCORE(r13) - lwz r3,VCPU_PTID(r4) +34: ld r5,HSTATE_KVM_VCORE(r13) + lbz r7,HSTATE_PTID(r13) li r0,1 - sld r0,r0,r3 + sld r0,r0,r7 addi r6,r5,VCORE_NAPPING_THREADS 32: lwarx r7,0,r6 andc r7,r7,r0 @@ -1741,23 +2027,18 @@ kvm_end_cede: li r0,0 stb r0,HSTATE_NAPPING(r13) - /* Check the wake reason in SRR1 to see why we got here */ - mfspr r3, SPRN_SRR1 - rlwinm r3, r3, 44-31, 0x7 /* extract wake reason field */ - cmpwi r3, 4 /* was it an external interrupt? */ - li r12, BOOK3S_INTERRUPT_EXTERNAL + /* See if the wake reason means we need to exit */ + stw r12, VCPU_TRAP(r4) mr r9, r4 - ld r10, VCPU_PC(r9) - ld r11, VCPU_MSR(r9) - beq do_ext_interrupt /* if so */ + cmpdi r3, 0 + bgt guest_exit_cont /* see if any other thread is already exiting */ lwz r0,VCORE_ENTRY_EXIT(r5) cmpwi r0,0x100 - blt kvmppc_cede_reentry /* if not go back to guest */ + bge guest_exit_cont - /* some threads are exiting, so go to the guest exit path */ - b hcall_real_fallback + b kvmppc_cede_reentry /* if not go back to guest */ /* cede when already previously prodded case */ kvm_cede_prodded: @@ -1783,10 +2064,47 @@ machine_check_realmode: beq mc_cont /* If not, deliver a machine check. SRR0/1 are already set */ li r10, BOOK3S_INTERRUPT_MACHINE_CHECK - li r11, (MSR_ME << 1) | 1 /* synthesize MSR_SF | MSR_ME */ - rotldi r11, r11, 63 + ld r11, VCPU_INTR_MSR(r9) b fast_interrupt_c_return +/* + * Check the reason we woke from nap, and take appropriate action. + * Returns: + * 0 if nothing needs to be done + * 1 if something happened that needs to be handled by the host + * -1 if there was a guest wakeup (IPI) + * + * Also sets r12 to the interrupt vector for any interrupt that needs + * to be handled now by the host (0x500 for external interrupt), or zero. + */ +kvmppc_check_wake_reason: + mfspr r6, SPRN_SRR1 +BEGIN_FTR_SECTION + rlwinm r6, r6, 45-31, 0xf /* extract wake reason field (P8) */ +FTR_SECTION_ELSE + rlwinm r6, r6, 45-31, 0xe /* P7 wake reason field is 3 bits */ +ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_207S) + cmpwi r6, 8 /* was it an external interrupt? */ + li r12, BOOK3S_INTERRUPT_EXTERNAL + beq kvmppc_read_intr /* if so, see what it was */ + li r3, 0 + li r12, 0 + cmpwi r6, 6 /* was it the decrementer? */ + beq 0f +BEGIN_FTR_SECTION + cmpwi r6, 5 /* privileged doorbell? */ + beq 0f + cmpwi r6, 3 /* hypervisor doorbell? */ + beq 3f +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) + li r3, 1 /* anything else, return 1 */ +0: blr + + /* hypervisor doorbell */ +3: li r12, BOOK3S_INTERRUPT_H_DOORBELL + li r3, 1 + blr + /* * Determine what sort of external interrupt is pending (if any). * Returns: @@ -1818,7 +2136,6 @@ kvmppc_read_intr: * interrupts directly to the guest */ cmpwi r3, XICS_IPI /* if there is, is it an IPI? */ - li r3, 1 bne 42f /* It's an IPI, clear the MFRR and EOI it */ @@ -1844,19 +2161,25 @@ kvmppc_read_intr: * before exit, it will be picked up by the host ICP driver */ stw r0, HSTATE_SAVED_XIRR(r13) + li r3, 1 b 1b 43: /* We raced with the host, we need to resend that IPI, bummer */ li r0, IPI_PRIORITY stbcix r0, r6, r8 /* set the IPI */ sync + li r3, 1 b 1b /* * Save away FP, VMX and VSX registers. * r3 = vcpu pointer + * N.B. r30 and r31 are volatile across this function, + * thus it is not callable from C. */ -_GLOBAL(kvmppc_save_fp) +kvmppc_save_fp: + mflr r30 + mr r31,r3 mfmsr r5 ori r8,r5,MSR_FP #ifdef CONFIG_ALTIVEC @@ -1871,42 +2194,17 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX) #endif mtmsrd r8 isync -#ifdef CONFIG_VSX -BEGIN_FTR_SECTION - reg = 0 - .rept 32 - li r6,reg*16+VCPU_VSRS - STXVD2X(reg,R6,R3) - reg = reg + 1 - .endr -FTR_SECTION_ELSE -#endif - reg = 0 - .rept 32 - stfd reg,reg*8+VCPU_FPRS(r3) - reg = reg + 1 - .endr -#ifdef CONFIG_VSX -ALT_FTR_SECTION_END_IFSET(CPU_FTR_VSX) -#endif - mffs fr0 - stfd fr0,VCPU_FPSCR(r3) - + addi r3,r3,VCPU_FPRS + bl .store_fp_state #ifdef CONFIG_ALTIVEC BEGIN_FTR_SECTION - reg = 0 - .rept 32 - li r6,reg*16+VCPU_VRS - stvx reg,r6,r3 - reg = reg + 1 - .endr - mfvscr vr0 - li r6,VCPU_VSCR - stvx vr0,r6,r3 + addi r3,r31,VCPU_VRS + bl .store_vr_state END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif mfspr r6,SPRN_VRSAVE stw r6,VCPU_VRSAVE(r3) + mtlr r30 mtmsrd r5 isync blr @@ -1914,9 +2212,12 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) /* * Load up FP, VMX and VSX registers * r4 = vcpu pointer + * N.B. r30 and r31 are volatile across this function, + * thus it is not callable from C. */ - .globl kvmppc_load_fp kvmppc_load_fp: + mflr r30 + mr r31,r4 mfmsr r9 ori r8,r9,MSR_FP #ifdef CONFIG_ALTIVEC @@ -1931,42 +2232,18 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX) #endif mtmsrd r8 isync - lfd fr0,VCPU_FPSCR(r4) - MTFSF_L(fr0) -#ifdef CONFIG_VSX -BEGIN_FTR_SECTION - reg = 0 - .rept 32 - li r7,reg*16+VCPU_VSRS - LXVD2X(reg,R7,R4) - reg = reg + 1 - .endr -FTR_SECTION_ELSE -#endif - reg = 0 - .rept 32 - lfd reg,reg*8+VCPU_FPRS(r4) - reg = reg + 1 - .endr -#ifdef CONFIG_VSX -ALT_FTR_SECTION_END_IFSET(CPU_FTR_VSX) -#endif - + addi r3,r4,VCPU_FPRS + bl .load_fp_state #ifdef CONFIG_ALTIVEC BEGIN_FTR_SECTION - li r7,VCPU_VSCR - lvx vr0,r7,r4 - mtvscr vr0 - reg = 0 - .rept 32 - li r7,reg*16+VCPU_VRS - lvx reg,r7,r4 - reg = reg + 1 - .endr + addi r3,r31,VCPU_VRS + bl .load_vr_state END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif lwz r7,VCPU_VRSAVE(r4) mtspr SPRN_VRSAVE,r7 + mtlr r30 + mr r4,r31 blr /* diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c index a59a25a1321843..c1abd95063f47d 100644 --- a/arch/powerpc/kvm/book3s_paired_singles.c +++ b/arch/powerpc/kvm/book3s_paired_singles.c @@ -160,7 +160,7 @@ static inline void kvmppc_sync_qpr(struct kvm_vcpu *vcpu, int rt) { - kvm_cvt_df(&vcpu->arch.fpr[rt], &vcpu->arch.qpr[rt]); + kvm_cvt_df(&VCPU_FPR(vcpu, rt), &vcpu->arch.qpr[rt]); } static void kvmppc_inject_pf(struct kvm_vcpu *vcpu, ulong eaddr, bool is_store) @@ -207,11 +207,11 @@ static int kvmppc_emulate_fpr_load(struct kvm_run *run, struct kvm_vcpu *vcpu, /* put in registers */ switch (ls_type) { case FPU_LS_SINGLE: - kvm_cvt_fd((u32*)tmp, &vcpu->arch.fpr[rs]); + kvm_cvt_fd((u32*)tmp, &VCPU_FPR(vcpu, rs)); vcpu->arch.qpr[rs] = *((u32*)tmp); break; case FPU_LS_DOUBLE: - vcpu->arch.fpr[rs] = *((u64*)tmp); + VCPU_FPR(vcpu, rs) = *((u64*)tmp); break; } @@ -233,18 +233,18 @@ static int kvmppc_emulate_fpr_store(struct kvm_run *run, struct kvm_vcpu *vcpu, switch (ls_type) { case FPU_LS_SINGLE: - kvm_cvt_df(&vcpu->arch.fpr[rs], (u32*)tmp); + kvm_cvt_df(&VCPU_FPR(vcpu, rs), (u32*)tmp); val = *((u32*)tmp); len = sizeof(u32); break; case FPU_LS_SINGLE_LOW: - *((u32*)tmp) = vcpu->arch.fpr[rs]; - val = vcpu->arch.fpr[rs] & 0xffffffff; + *((u32*)tmp) = VCPU_FPR(vcpu, rs); + val = VCPU_FPR(vcpu, rs) & 0xffffffff; len = sizeof(u32); break; case FPU_LS_DOUBLE: - *((u64*)tmp) = vcpu->arch.fpr[rs]; - val = vcpu->arch.fpr[rs]; + *((u64*)tmp) = VCPU_FPR(vcpu, rs); + val = VCPU_FPR(vcpu, rs); len = sizeof(u64); break; default: @@ -301,7 +301,7 @@ static int kvmppc_emulate_psq_load(struct kvm_run *run, struct kvm_vcpu *vcpu, emulated = EMULATE_DONE; /* put in registers */ - kvm_cvt_fd(&tmp[0], &vcpu->arch.fpr[rs]); + kvm_cvt_fd(&tmp[0], &VCPU_FPR(vcpu, rs)); vcpu->arch.qpr[rs] = tmp[1]; dprintk(KERN_INFO "KVM: PSQ_LD [0x%x, 0x%x] at 0x%lx (%d)\n", tmp[0], @@ -319,7 +319,7 @@ static int kvmppc_emulate_psq_store(struct kvm_run *run, struct kvm_vcpu *vcpu, u32 tmp[2]; int len = w ? sizeof(u32) : sizeof(u64); - kvm_cvt_df(&vcpu->arch.fpr[rs], &tmp[0]); + kvm_cvt_df(&VCPU_FPR(vcpu, rs), &tmp[0]); tmp[1] = vcpu->arch.qpr[rs]; r = kvmppc_st(vcpu, &addr, len, tmp, true); @@ -512,7 +512,6 @@ static int kvmppc_ps_three_in(struct kvm_vcpu *vcpu, bool rc, u32 *src2, u32 *src3)) { u32 *qpr = vcpu->arch.qpr; - u64 *fpr = vcpu->arch.fpr; u32 ps0_out; u32 ps0_in1, ps0_in2, ps0_in3; u32 ps1_in1, ps1_in2, ps1_in3; @@ -521,20 +520,20 @@ static int kvmppc_ps_three_in(struct kvm_vcpu *vcpu, bool rc, WARN_ON(rc); /* PS0 */ - kvm_cvt_df(&fpr[reg_in1], &ps0_in1); - kvm_cvt_df(&fpr[reg_in2], &ps0_in2); - kvm_cvt_df(&fpr[reg_in3], &ps0_in3); + kvm_cvt_df(&VCPU_FPR(vcpu, reg_in1), &ps0_in1); + kvm_cvt_df(&VCPU_FPR(vcpu, reg_in2), &ps0_in2); + kvm_cvt_df(&VCPU_FPR(vcpu, reg_in3), &ps0_in3); if (scalar & SCALAR_LOW) ps0_in2 = qpr[reg_in2]; - func(&vcpu->arch.fpscr, &ps0_out, &ps0_in1, &ps0_in2, &ps0_in3); + func(&vcpu->arch.fp.fpscr, &ps0_out, &ps0_in1, &ps0_in2, &ps0_in3); dprintk(KERN_INFO "PS3 ps0 -> f(0x%x, 0x%x, 0x%x) = 0x%x\n", ps0_in1, ps0_in2, ps0_in3, ps0_out); if (!(scalar & SCALAR_NO_PS0)) - kvm_cvt_fd(&ps0_out, &fpr[reg_out]); + kvm_cvt_fd(&ps0_out, &VCPU_FPR(vcpu, reg_out)); /* PS1 */ ps1_in1 = qpr[reg_in1]; @@ -545,7 +544,7 @@ static int kvmppc_ps_three_in(struct kvm_vcpu *vcpu, bool rc, ps1_in2 = ps0_in2; if (!(scalar & SCALAR_NO_PS1)) - func(&vcpu->arch.fpscr, &qpr[reg_out], &ps1_in1, &ps1_in2, &ps1_in3); + func(&vcpu->arch.fp.fpscr, &qpr[reg_out], &ps1_in1, &ps1_in2, &ps1_in3); dprintk(KERN_INFO "PS3 ps1 -> f(0x%x, 0x%x, 0x%x) = 0x%x\n", ps1_in1, ps1_in2, ps1_in3, qpr[reg_out]); @@ -561,7 +560,6 @@ static int kvmppc_ps_two_in(struct kvm_vcpu *vcpu, bool rc, u32 *src2)) { u32 *qpr = vcpu->arch.qpr; - u64 *fpr = vcpu->arch.fpr; u32 ps0_out; u32 ps0_in1, ps0_in2; u32 ps1_out; @@ -571,20 +569,20 @@ static int kvmppc_ps_two_in(struct kvm_vcpu *vcpu, bool rc, WARN_ON(rc); /* PS0 */ - kvm_cvt_df(&fpr[reg_in1], &ps0_in1); + kvm_cvt_df(&VCPU_FPR(vcpu, reg_in1), &ps0_in1); if (scalar & SCALAR_LOW) ps0_in2 = qpr[reg_in2]; else - kvm_cvt_df(&fpr[reg_in2], &ps0_in2); + kvm_cvt_df(&VCPU_FPR(vcpu, reg_in2), &ps0_in2); - func(&vcpu->arch.fpscr, &ps0_out, &ps0_in1, &ps0_in2); + func(&vcpu->arch.fp.fpscr, &ps0_out, &ps0_in1, &ps0_in2); if (!(scalar & SCALAR_NO_PS0)) { dprintk(KERN_INFO "PS2 ps0 -> f(0x%x, 0x%x) = 0x%x\n", ps0_in1, ps0_in2, ps0_out); - kvm_cvt_fd(&ps0_out, &fpr[reg_out]); + kvm_cvt_fd(&ps0_out, &VCPU_FPR(vcpu, reg_out)); } /* PS1 */ @@ -594,7 +592,7 @@ static int kvmppc_ps_two_in(struct kvm_vcpu *vcpu, bool rc, if (scalar & SCALAR_HIGH) ps1_in2 = ps0_in2; - func(&vcpu->arch.fpscr, &ps1_out, &ps1_in1, &ps1_in2); + func(&vcpu->arch.fp.fpscr, &ps1_out, &ps1_in1, &ps1_in2); if (!(scalar & SCALAR_NO_PS1)) { qpr[reg_out] = ps1_out; @@ -612,7 +610,6 @@ static int kvmppc_ps_one_in(struct kvm_vcpu *vcpu, bool rc, u32 *dst, u32 *src1)) { u32 *qpr = vcpu->arch.qpr; - u64 *fpr = vcpu->arch.fpr; u32 ps0_out, ps0_in; u32 ps1_in; @@ -620,17 +617,17 @@ static int kvmppc_ps_one_in(struct kvm_vcpu *vcpu, bool rc, WARN_ON(rc); /* PS0 */ - kvm_cvt_df(&fpr[reg_in], &ps0_in); - func(&vcpu->arch.fpscr, &ps0_out, &ps0_in); + kvm_cvt_df(&VCPU_FPR(vcpu, reg_in), &ps0_in); + func(&vcpu->arch.fp.fpscr, &ps0_out, &ps0_in); dprintk(KERN_INFO "PS1 ps0 -> f(0x%x) = 0x%x\n", ps0_in, ps0_out); - kvm_cvt_fd(&ps0_out, &fpr[reg_out]); + kvm_cvt_fd(&ps0_out, &VCPU_FPR(vcpu, reg_out)); /* PS1 */ ps1_in = qpr[reg_in]; - func(&vcpu->arch.fpscr, &qpr[reg_out], &ps1_in); + func(&vcpu->arch.fp.fpscr, &qpr[reg_out], &ps1_in); dprintk(KERN_INFO "PS1 ps1 -> f(0x%x) = 0x%x\n", ps1_in, qpr[reg_out]); @@ -649,10 +646,10 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu) int ax_rc = inst_get_field(inst, 21, 25); short full_d = inst_get_field(inst, 16, 31); - u64 *fpr_d = &vcpu->arch.fpr[ax_rd]; - u64 *fpr_a = &vcpu->arch.fpr[ax_ra]; - u64 *fpr_b = &vcpu->arch.fpr[ax_rb]; - u64 *fpr_c = &vcpu->arch.fpr[ax_rc]; + u64 *fpr_d = &VCPU_FPR(vcpu, ax_rd); + u64 *fpr_a = &VCPU_FPR(vcpu, ax_ra); + u64 *fpr_b = &VCPU_FPR(vcpu, ax_rb); + u64 *fpr_c = &VCPU_FPR(vcpu, ax_rc); bool rcomp = (inst & 1) ? true : false; u32 cr = kvmppc_get_cr(vcpu); @@ -674,11 +671,11 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu) /* Do we need to clear FE0 / FE1 here? Don't think so. */ #ifdef DEBUG - for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) { + for (i = 0; i < ARRAY_SIZE(vcpu->arch.fp.fpr); i++) { u32 f; - kvm_cvt_df(&vcpu->arch.fpr[i], &f); + kvm_cvt_df(&VCPU_FPR(vcpu, i), &f); dprintk(KERN_INFO "FPR[%d] = 0x%x / 0x%llx QPR[%d] = 0x%x\n", - i, f, vcpu->arch.fpr[i], i, vcpu->arch.qpr[i]); + i, f, VCPU_FPR(vcpu, i), i, vcpu->arch.qpr[i]); } #endif @@ -764,8 +761,8 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu) break; } case OP_4X_PS_NEG: - vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_rb]; - vcpu->arch.fpr[ax_rd] ^= 0x8000000000000000ULL; + VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_rb); + VCPU_FPR(vcpu, ax_rd) ^= 0x8000000000000000ULL; vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb]; vcpu->arch.qpr[ax_rd] ^= 0x80000000; break; @@ -775,7 +772,7 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu) break; case OP_4X_PS_MR: WARN_ON(rcomp); - vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_rb]; + VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_rb); vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb]; break; case OP_4X_PS_CMPO1: @@ -784,44 +781,44 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu) break; case OP_4X_PS_NABS: WARN_ON(rcomp); - vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_rb]; - vcpu->arch.fpr[ax_rd] |= 0x8000000000000000ULL; + VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_rb); + VCPU_FPR(vcpu, ax_rd) |= 0x8000000000000000ULL; vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb]; vcpu->arch.qpr[ax_rd] |= 0x80000000; break; case OP_4X_PS_ABS: WARN_ON(rcomp); - vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_rb]; - vcpu->arch.fpr[ax_rd] &= ~0x8000000000000000ULL; + VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_rb); + VCPU_FPR(vcpu, ax_rd) &= ~0x8000000000000000ULL; vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb]; vcpu->arch.qpr[ax_rd] &= ~0x80000000; break; case OP_4X_PS_MERGE00: WARN_ON(rcomp); - vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_ra]; - /* vcpu->arch.qpr[ax_rd] = vcpu->arch.fpr[ax_rb]; */ - kvm_cvt_df(&vcpu->arch.fpr[ax_rb], + VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_ra); + /* vcpu->arch.qpr[ax_rd] = VCPU_FPR(vcpu, ax_rb); */ + kvm_cvt_df(&VCPU_FPR(vcpu, ax_rb), &vcpu->arch.qpr[ax_rd]); break; case OP_4X_PS_MERGE01: WARN_ON(rcomp); - vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_ra]; + VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_ra); vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb]; break; case OP_4X_PS_MERGE10: WARN_ON(rcomp); - /* vcpu->arch.fpr[ax_rd] = vcpu->arch.qpr[ax_ra]; */ + /* VCPU_FPR(vcpu, ax_rd) = vcpu->arch.qpr[ax_ra]; */ kvm_cvt_fd(&vcpu->arch.qpr[ax_ra], - &vcpu->arch.fpr[ax_rd]); - /* vcpu->arch.qpr[ax_rd] = vcpu->arch.fpr[ax_rb]; */ - kvm_cvt_df(&vcpu->arch.fpr[ax_rb], + &VCPU_FPR(vcpu, ax_rd)); + /* vcpu->arch.qpr[ax_rd] = VCPU_FPR(vcpu, ax_rb); */ + kvm_cvt_df(&VCPU_FPR(vcpu, ax_rb), &vcpu->arch.qpr[ax_rd]); break; case OP_4X_PS_MERGE11: WARN_ON(rcomp); - /* vcpu->arch.fpr[ax_rd] = vcpu->arch.qpr[ax_ra]; */ + /* VCPU_FPR(vcpu, ax_rd) = vcpu->arch.qpr[ax_ra]; */ kvm_cvt_fd(&vcpu->arch.qpr[ax_ra], - &vcpu->arch.fpr[ax_rd]); + &VCPU_FPR(vcpu, ax_rd)); vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb]; break; } @@ -856,7 +853,7 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu) case OP_4A_PS_SUM1: emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd, ax_rb, ax_ra, SCALAR_NO_PS0 | SCALAR_HIGH, fps_fadds); - vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_rc]; + VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_rc); break; case OP_4A_PS_SUM0: emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd, @@ -1106,45 +1103,45 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu) case 59: switch (inst_get_field(inst, 21, 30)) { case OP_59_FADDS: - fpd_fadds(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b); + fpd_fadds(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b); kvmppc_sync_qpr(vcpu, ax_rd); break; case OP_59_FSUBS: - fpd_fsubs(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b); + fpd_fsubs(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b); kvmppc_sync_qpr(vcpu, ax_rd); break; case OP_59_FDIVS: - fpd_fdivs(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b); + fpd_fdivs(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b); kvmppc_sync_qpr(vcpu, ax_rd); break; case OP_59_FRES: - fpd_fres(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b); + fpd_fres(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b); kvmppc_sync_qpr(vcpu, ax_rd); break; case OP_59_FRSQRTES: - fpd_frsqrtes(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b); + fpd_frsqrtes(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b); kvmppc_sync_qpr(vcpu, ax_rd); break; } switch (inst_get_field(inst, 26, 30)) { case OP_59_FMULS: - fpd_fmuls(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c); + fpd_fmuls(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c); kvmppc_sync_qpr(vcpu, ax_rd); break; case OP_59_FMSUBS: - fpd_fmsubs(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); + fpd_fmsubs(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); kvmppc_sync_qpr(vcpu, ax_rd); break; case OP_59_FMADDS: - fpd_fmadds(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); + fpd_fmadds(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); kvmppc_sync_qpr(vcpu, ax_rd); break; case OP_59_FNMSUBS: - fpd_fnmsubs(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); + fpd_fnmsubs(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); kvmppc_sync_qpr(vcpu, ax_rd); break; case OP_59_FNMADDS: - fpd_fnmadds(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); + fpd_fnmadds(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); kvmppc_sync_qpr(vcpu, ax_rd); break; } @@ -1159,12 +1156,12 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu) break; case OP_63_MFFS: /* XXX missing CR */ - *fpr_d = vcpu->arch.fpscr; + *fpr_d = vcpu->arch.fp.fpscr; break; case OP_63_MTFSF: /* XXX missing fm bits */ /* XXX missing CR */ - vcpu->arch.fpscr = *fpr_b; + vcpu->arch.fp.fpscr = *fpr_b; break; case OP_63_FCMPU: { @@ -1172,7 +1169,7 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu) u32 cr0_mask = 0xf0000000; u32 cr_shift = inst_get_field(inst, 6, 8) * 4; - fpd_fcmpu(&vcpu->arch.fpscr, &tmp_cr, fpr_a, fpr_b); + fpd_fcmpu(&vcpu->arch.fp.fpscr, &tmp_cr, fpr_a, fpr_b); cr &= ~(cr0_mask >> cr_shift); cr |= (cr & cr0_mask) >> cr_shift; break; @@ -1183,40 +1180,40 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu) u32 cr0_mask = 0xf0000000; u32 cr_shift = inst_get_field(inst, 6, 8) * 4; - fpd_fcmpo(&vcpu->arch.fpscr, &tmp_cr, fpr_a, fpr_b); + fpd_fcmpo(&vcpu->arch.fp.fpscr, &tmp_cr, fpr_a, fpr_b); cr &= ~(cr0_mask >> cr_shift); cr |= (cr & cr0_mask) >> cr_shift; break; } case OP_63_FNEG: - fpd_fneg(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b); + fpd_fneg(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b); break; case OP_63_FMR: *fpr_d = *fpr_b; break; case OP_63_FABS: - fpd_fabs(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b); + fpd_fabs(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b); break; case OP_63_FCPSGN: - fpd_fcpsgn(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b); + fpd_fcpsgn(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b); break; case OP_63_FDIV: - fpd_fdiv(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b); + fpd_fdiv(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b); break; case OP_63_FADD: - fpd_fadd(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b); + fpd_fadd(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b); break; case OP_63_FSUB: - fpd_fsub(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b); + fpd_fsub(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b); break; case OP_63_FCTIW: - fpd_fctiw(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b); + fpd_fctiw(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b); break; case OP_63_FCTIWZ: - fpd_fctiwz(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b); + fpd_fctiwz(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b); break; case OP_63_FRSP: - fpd_frsp(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b); + fpd_frsp(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b); kvmppc_sync_qpr(vcpu, ax_rd); break; case OP_63_FRSQRTE: @@ -1224,39 +1221,39 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu) double one = 1.0f; /* fD = sqrt(fB) */ - fpd_fsqrt(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b); + fpd_fsqrt(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b); /* fD = 1.0f / fD */ - fpd_fdiv(&vcpu->arch.fpscr, &cr, fpr_d, (u64*)&one, fpr_d); + fpd_fdiv(&vcpu->arch.fp.fpscr, &cr, fpr_d, (u64*)&one, fpr_d); break; } } switch (inst_get_field(inst, 26, 30)) { case OP_63_FMUL: - fpd_fmul(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c); + fpd_fmul(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c); break; case OP_63_FSEL: - fpd_fsel(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); + fpd_fsel(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); break; case OP_63_FMSUB: - fpd_fmsub(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); + fpd_fmsub(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); break; case OP_63_FMADD: - fpd_fmadd(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); + fpd_fmadd(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); break; case OP_63_FNMSUB: - fpd_fnmsub(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); + fpd_fnmsub(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); break; case OP_63_FNMADD: - fpd_fnmadd(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); + fpd_fnmadd(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b); break; } break; } #ifdef DEBUG - for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) { + for (i = 0; i < ARRAY_SIZE(vcpu->arch.fp.fpr); i++) { u32 f; - kvm_cvt_df(&vcpu->arch.fpr[i], &f); + kvm_cvt_df(&VCPU_FPR(vcpu, i), &f); dprintk(KERN_INFO "FPR[%d] = 0x%x\n", i, f); } #endif diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 5b9e9063cfaf0c..c5c052a9729c95 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "book3s.h" @@ -566,12 +567,6 @@ static inline int get_fpr_index(int i) void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr) { struct thread_struct *t = ¤t->thread; - u64 *vcpu_fpr = vcpu->arch.fpr; -#ifdef CONFIG_VSX - u64 *vcpu_vsx = vcpu->arch.vsr; -#endif - u64 *thread_fpr = &t->fp_state.fpr[0][0]; - int i; /* * VSX instructions can access FP and vector registers, so if @@ -594,26 +589,16 @@ void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr) * both the traditional FP registers and the added VSX * registers into thread.fp_state.fpr[]. */ - if (current->thread.regs->msr & MSR_FP) + if (t->regs->msr & MSR_FP) giveup_fpu(current); - for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) - vcpu_fpr[i] = thread_fpr[get_fpr_index(i)]; - - vcpu->arch.fpscr = t->fp_state.fpscr; - -#ifdef CONFIG_VSX - if (cpu_has_feature(CPU_FTR_VSX)) - for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr) / 2; i++) - vcpu_vsx[i] = thread_fpr[get_fpr_index(i) + 1]; -#endif + t->fp_save_area = NULL; } #ifdef CONFIG_ALTIVEC if (msr & MSR_VEC) { if (current->thread.regs->msr & MSR_VEC) giveup_altivec(current); - memcpy(vcpu->arch.vr, t->vr_state.vr, sizeof(vcpu->arch.vr)); - vcpu->arch.vscr = t->vr_state.vscr; + t->vr_save_area = NULL; } #endif @@ -661,12 +646,6 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr, ulong msr) { struct thread_struct *t = ¤t->thread; - u64 *vcpu_fpr = vcpu->arch.fpr; -#ifdef CONFIG_VSX - u64 *vcpu_vsx = vcpu->arch.vsr; -#endif - u64 *thread_fpr = &t->fp_state.fpr[0][0]; - int i; /* When we have paired singles, we emulate in software */ if (vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE) @@ -704,27 +683,20 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr, #endif if (msr & MSR_FP) { - for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) - thread_fpr[get_fpr_index(i)] = vcpu_fpr[i]; -#ifdef CONFIG_VSX - for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr) / 2; i++) - thread_fpr[get_fpr_index(i) + 1] = vcpu_vsx[i]; -#endif - t->fp_state.fpscr = vcpu->arch.fpscr; - t->fpexc_mode = 0; - kvmppc_load_up_fpu(); + enable_kernel_fp(); + load_fp_state(&vcpu->arch.fp); + t->fp_save_area = &vcpu->arch.fp; } if (msr & MSR_VEC) { #ifdef CONFIG_ALTIVEC - memcpy(t->vr_state.vr, vcpu->arch.vr, sizeof(vcpu->arch.vr)); - t->vr_state.vscr = vcpu->arch.vscr; - t->vrsave = -1; - kvmppc_load_up_altivec(); + enable_kernel_altivec(); + load_vr_state(&vcpu->arch.vr); + t->vr_save_area = &vcpu->arch.vr; #endif } - current->thread.regs->msr |= msr; + t->regs->msr |= msr; vcpu->arch.guest_owned_ext |= msr; kvmppc_recalc_shadow_msr(vcpu); @@ -743,11 +715,15 @@ static void kvmppc_handle_lost_ext(struct kvm_vcpu *vcpu) if (!lost_ext) return; - if (lost_ext & MSR_FP) - kvmppc_load_up_fpu(); + if (lost_ext & MSR_FP) { + enable_kernel_fp(); + load_fp_state(&vcpu->arch.fp); + } #ifdef CONFIG_ALTIVEC - if (lost_ext & MSR_VEC) - kvmppc_load_up_altivec(); + if (lost_ext & MSR_VEC) { + enable_kernel_altivec(); + load_vr_state(&vcpu->arch.vr); + } #endif current->thread.regs->msr |= lost_ext; } @@ -873,6 +849,7 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu, /* We're good on these - the host merely wanted to get our attention */ case BOOK3S_INTERRUPT_DECREMENTER: case BOOK3S_INTERRUPT_HV_DECREMENTER: + case BOOK3S_INTERRUPT_DOORBELL: vcpu->stat.dec_exits++; r = RESUME_GUEST; break; @@ -1045,14 +1022,14 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu, * and if we really did time things so badly, then we just exit * again due to a host external interrupt. */ - local_irq_disable(); s = kvmppc_prepare_to_enter(vcpu); - if (s <= 0) { - local_irq_enable(); + if (s <= 0) r = s; - } else { + else { + /* interrupts now hard-disabled */ kvmppc_fix_ee_before_entry(); } + kvmppc_handle_lost_ext(vcpu); } @@ -1133,19 +1110,6 @@ static int kvmppc_get_one_reg_pr(struct kvm_vcpu *vcpu, u64 id, case KVM_REG_PPC_HIOR: *val = get_reg_val(id, to_book3s(vcpu)->hior); break; -#ifdef CONFIG_VSX - case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: { - long int i = id - KVM_REG_PPC_VSR0; - - if (!cpu_has_feature(CPU_FTR_VSX)) { - r = -ENXIO; - break; - } - val->vsxval[0] = vcpu->arch.fpr[i]; - val->vsxval[1] = vcpu->arch.vsr[i]; - break; - } -#endif /* CONFIG_VSX */ default: r = -EINVAL; break; @@ -1164,19 +1128,6 @@ static int kvmppc_set_one_reg_pr(struct kvm_vcpu *vcpu, u64 id, to_book3s(vcpu)->hior = set_reg_val(id, *val); to_book3s(vcpu)->hior_explicit = true; break; -#ifdef CONFIG_VSX - case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: { - long int i = id - KVM_REG_PPC_VSR0; - - if (!cpu_has_feature(CPU_FTR_VSX)) { - r = -ENXIO; - break; - } - vcpu->arch.fpr[i] = val->vsxval[0]; - vcpu->arch.vsr[i] = val->vsxval[1]; - break; - } -#endif /* CONFIG_VSX */ default: r = -EINVAL; break; @@ -1274,17 +1225,9 @@ static void kvmppc_core_vcpu_free_pr(struct kvm_vcpu *vcpu) static int kvmppc_vcpu_run_pr(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) { int ret; - struct thread_fp_state fp; - int fpexc_mode; #ifdef CONFIG_ALTIVEC - struct thread_vr_state vr; unsigned long uninitialized_var(vrsave); - int used_vr; #endif -#ifdef CONFIG_VSX - int used_vsr; -#endif - ulong ext_msr; /* Check if we can run the vcpu at all */ if (!vcpu->arch.sane) { @@ -1299,40 +1242,27 @@ static int kvmppc_vcpu_run_pr(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) * really did time things so badly, then we just exit again due to * a host external interrupt. */ - local_irq_disable(); ret = kvmppc_prepare_to_enter(vcpu); - if (ret <= 0) { - local_irq_enable(); + if (ret <= 0) goto out; - } + /* interrupts now hard-disabled */ - /* Save FPU state in stack */ + /* Save FPU state in thread_struct */ if (current->thread.regs->msr & MSR_FP) giveup_fpu(current); - fp = current->thread.fp_state; - fpexc_mode = current->thread.fpexc_mode; #ifdef CONFIG_ALTIVEC - /* Save Altivec state in stack */ - used_vr = current->thread.used_vr; - if (used_vr) { - if (current->thread.regs->msr & MSR_VEC) - giveup_altivec(current); - vr = current->thread.vr_state; - vrsave = current->thread.vrsave; - } + /* Save Altivec state in thread_struct */ + if (current->thread.regs->msr & MSR_VEC) + giveup_altivec(current); #endif #ifdef CONFIG_VSX - /* Save VSX state in stack */ - used_vsr = current->thread.used_vsr; - if (used_vsr && (current->thread.regs->msr & MSR_VSX)) + /* Save VSX state in thread_struct */ + if (current->thread.regs->msr & MSR_VSX) __giveup_vsx(current); #endif - /* Remember the MSR with disabled extensions */ - ext_msr = current->thread.regs->msr; - /* Preload FPU if it's enabled */ if (vcpu->arch.shared->msr & MSR_FP) kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP); @@ -1347,25 +1277,6 @@ static int kvmppc_vcpu_run_pr(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) /* Make sure we save the guest FPU/Altivec/VSX state */ kvmppc_giveup_ext(vcpu, MSR_FP | MSR_VEC | MSR_VSX); - current->thread.regs->msr = ext_msr; - - /* Restore FPU/VSX state from stack */ - current->thread.fp_state = fp; - current->thread.fpexc_mode = fpexc_mode; - -#ifdef CONFIG_ALTIVEC - /* Restore Altivec state from stack */ - if (used_vr && current->thread.used_vr) { - current->thread.vr_state = vr; - current->thread.vrsave = vrsave; - } - current->thread.used_vr = used_vr; -#endif - -#ifdef CONFIG_VSX - current->thread.used_vsr = used_vsr; -#endif - out: vcpu->mode = OUTSIDE_GUEST_MODE; return ret; @@ -1606,4 +1517,6 @@ module_init(kvmppc_book3s_init_pr); module_exit(kvmppc_book3s_exit_pr); MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(KVM_MINOR); +MODULE_ALIAS("devname:kvm"); #endif diff --git a/arch/powerpc/kvm/book3s_rmhandlers.S b/arch/powerpc/kvm/book3s_rmhandlers.S index c3c5231adade6f..9eec675220e621 100644 --- a/arch/powerpc/kvm/book3s_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_rmhandlers.S @@ -162,51 +162,4 @@ _GLOBAL(kvmppc_entry_trampoline) mtsrr1 r6 RFI -#if defined(CONFIG_PPC_BOOK3S_32) -#define STACK_LR INT_FRAME_SIZE+4 - -/* load_up_xxx have to run with MSR_DR=0 on Book3S_32 */ -#define MSR_EXT_START \ - PPC_STL r20, _NIP(r1); \ - mfmsr r20; \ - LOAD_REG_IMMEDIATE(r3, MSR_DR|MSR_EE); \ - andc r3,r20,r3; /* Disable DR,EE */ \ - mtmsr r3; \ - sync - -#define MSR_EXT_END \ - mtmsr r20; /* Enable DR,EE */ \ - sync; \ - PPC_LL r20, _NIP(r1) - -#elif defined(CONFIG_PPC_BOOK3S_64) -#define STACK_LR _LINK -#define MSR_EXT_START -#define MSR_EXT_END -#endif - -/* - * Activate current's external feature (FPU/Altivec/VSX) - */ -#define define_load_up(what) \ - \ -_GLOBAL(kvmppc_load_up_ ## what); \ - PPC_STLU r1, -INT_FRAME_SIZE(r1); \ - mflr r3; \ - PPC_STL r3, STACK_LR(r1); \ - MSR_EXT_START; \ - \ - bl FUNC(load_up_ ## what); \ - \ - MSR_EXT_END; \ - PPC_LL r3, STACK_LR(r1); \ - mtlr r3; \ - addi r1, r1, INT_FRAME_SIZE; \ - blr - -define_load_up(fpu) -#ifdef CONFIG_ALTIVEC -define_load_up(altivec) -#endif - #include "book3s_segment.S" diff --git a/arch/powerpc/kvm/book3s_segment.S b/arch/powerpc/kvm/book3s_segment.S index bc50c97751d368..1e0cc2adfd40d9 100644 --- a/arch/powerpc/kvm/book3s_segment.S +++ b/arch/powerpc/kvm/book3s_segment.S @@ -361,6 +361,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) beqa BOOK3S_INTERRUPT_DECREMENTER cmpwi r12, BOOK3S_INTERRUPT_PERFMON beqa BOOK3S_INTERRUPT_PERFMON + cmpwi r12, BOOK3S_INTERRUPT_DOORBELL + beqa BOOK3S_INTERRUPT_DOORBELL RFI kvmppc_handler_trampoline_exit_end: diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c index 02a17dcf16107a..d1acd32a64c034 100644 --- a/arch/powerpc/kvm/book3s_xics.c +++ b/arch/powerpc/kvm/book3s_xics.c @@ -1246,8 +1246,10 @@ static int kvmppc_xics_create(struct kvm_device *dev, u32 type) kvm->arch.xics = xics; mutex_unlock(&kvm->lock); - if (ret) + if (ret) { + kfree(xics); return ret; + } xics_debugfs_init(xics); diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index 0591e05db74b1a..ab62109fdfa3f7 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c @@ -643,7 +643,7 @@ int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu) local_irq_enable(); kvm_vcpu_block(vcpu); clear_bit(KVM_REQ_UNHALT, &vcpu->requests); - local_irq_disable(); + hard_irq_disable(); kvmppc_set_exit_type(vcpu, EMULATED_MTMSRWE_EXITS); r = 1; @@ -682,34 +682,22 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) { int ret, s; struct debug_reg debug; -#ifdef CONFIG_PPC_FPU - struct thread_fp_state fp; - int fpexc_mode; -#endif if (!vcpu->arch.sane) { kvm_run->exit_reason = KVM_EXIT_INTERNAL_ERROR; return -EINVAL; } - local_irq_disable(); s = kvmppc_prepare_to_enter(vcpu); if (s <= 0) { - local_irq_enable(); ret = s; goto out; } + /* interrupts now hard-disabled */ #ifdef CONFIG_PPC_FPU /* Save userspace FPU state in stack */ enable_kernel_fp(); - fp = current->thread.fp_state; - fpexc_mode = current->thread.fpexc_mode; - - /* Restore guest FPU state to thread */ - memcpy(current->thread.fp_state.fpr, vcpu->arch.fpr, - sizeof(vcpu->arch.fpr)); - current->thread.fp_state.fpscr = vcpu->arch.fpscr; /* * Since we can't trap on MSR_FP in GS-mode, we consider the guest @@ -728,6 +716,7 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) debug = current->thread.debug; current->thread.debug = vcpu->arch.shadow_dbg_reg; + vcpu->arch.pgdir = current->mm->pgd; kvmppc_fix_ee_before_entry(); ret = __kvmppc_vcpu_run(kvm_run, vcpu); @@ -743,15 +732,6 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) kvmppc_save_guest_fp(vcpu); vcpu->fpu_active = 0; - - /* Save guest FPU state from thread */ - memcpy(vcpu->arch.fpr, current->thread.fp_state.fpr, - sizeof(vcpu->arch.fpr)); - vcpu->arch.fpscr = current->thread.fp_state.fpscr; - - /* Restore userspace FPU state from stack */ - current->thread.fp_state = fp; - current->thread.fpexc_mode = fpexc_mode; #endif out: @@ -898,17 +878,6 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, int s; int idx; -#ifdef CONFIG_PPC64 - WARN_ON(local_paca->irq_happened != 0); -#endif - - /* - * We enter with interrupts disabled in hardware, but - * we need to call hard_irq_disable anyway to ensure that - * the software state is kept in sync. - */ - hard_irq_disable(); - /* update before a new last_exit_type is rewritten */ kvmppc_update_timing_stats(vcpu); @@ -1217,12 +1186,11 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, * aren't already exiting to userspace for some other reason. */ if (!(r & RESUME_HOST)) { - local_irq_disable(); s = kvmppc_prepare_to_enter(vcpu); - if (s <= 0) { - local_irq_enable(); + if (s <= 0) r = (s << 2) | RESUME_HOST | (r & RESUME_FLAG_NV); - } else { + else { + /* interrupts now hard-disabled */ kvmppc_fix_ee_before_entry(); } } diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h index 09bfd9bc7cf8d9..b632cd35919b1b 100644 --- a/arch/powerpc/kvm/booke.h +++ b/arch/powerpc/kvm/booke.h @@ -136,7 +136,9 @@ static inline void kvmppc_load_guest_fp(struct kvm_vcpu *vcpu) { #ifdef CONFIG_PPC_FPU if (vcpu->fpu_active && !(current->thread.regs->msr & MSR_FP)) { - load_up_fpu(); + enable_kernel_fp(); + load_fp_state(&vcpu->arch.fp); + current->thread.fp_save_area = &vcpu->arch.fp; current->thread.regs->msr |= MSR_FP; } #endif @@ -151,6 +153,7 @@ static inline void kvmppc_save_guest_fp(struct kvm_vcpu *vcpu) #ifdef CONFIG_PPC_FPU if (vcpu->fpu_active && (current->thread.regs->msr & MSR_FP)) giveup_fpu(current); + current->thread.fp_save_area = NULL; #endif } diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S index e8ed7d659c55f8..e4185f6b3309af 100644 --- a/arch/powerpc/kvm/bookehv_interrupts.S +++ b/arch/powerpc/kvm/bookehv_interrupts.S @@ -33,6 +33,8 @@ #ifdef CONFIG_64BIT #include +#include +#include #else #include "../kernel/head_booke.h" /* for THREAD_NORMSAVE() */ #endif @@ -319,6 +321,8 @@ kvm_handler BOOKE_INTERRUPT_DEBUG, EX_PARAMS(DBG), \ SPRN_DSRR0, SPRN_DSRR1, 0 kvm_handler BOOKE_INTERRUPT_DEBUG, EX_PARAMS(CRIT), \ SPRN_CSRR0, SPRN_CSRR1, 0 +kvm_handler BOOKE_INTERRUPT_LRAT_ERROR, EX_PARAMS(GEN), \ + SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR) #else /* * For input register values, see arch/powerpc/include/asm/kvm_booke_hv_asm.h @@ -465,6 +469,15 @@ _GLOBAL(kvmppc_resume_host) mtspr SPRN_EPCR, r3 isync +#ifdef CONFIG_64BIT + /* + * We enter with interrupts disabled in hardware, but + * we need to call RECONCILE_IRQ_STATE to ensure + * that the software state is kept in sync. + */ + RECONCILE_IRQ_STATE(r3,r5) +#endif + /* Switch to kernel stack and jump to handler. */ PPC_LL r3, HOST_RUN(r1) mr r5, r14 /* intno */ diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c index 497b142f651c83..2e02ed849f36d1 100644 --- a/arch/powerpc/kvm/e500.c +++ b/arch/powerpc/kvm/e500.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -573,3 +575,5 @@ static void __exit kvmppc_e500_exit(void) module_init(kvmppc_e500_init); module_exit(kvmppc_e500_exit); +MODULE_ALIAS_MISCDEV(KVM_MINOR); +MODULE_ALIAS("devname:kvm"); diff --git a/arch/powerpc/kvm/e500.h b/arch/powerpc/kvm/e500.h index 4fd9650eb01853..a326178bdea516 100644 --- a/arch/powerpc/kvm/e500.h +++ b/arch/powerpc/kvm/e500.h @@ -31,11 +31,13 @@ enum vcpu_ftr { #define E500_TLB_NUM 2 /* entry is mapped somewhere in host TLB */ -#define E500_TLB_VALID (1 << 0) +#define E500_TLB_VALID (1 << 31) /* TLB1 entry is mapped by host TLB1, tracked by bitmaps */ -#define E500_TLB_BITMAP (1 << 1) +#define E500_TLB_BITMAP (1 << 30) /* TLB1 entry is mapped by host TLB0 */ -#define E500_TLB_TLB0 (1 << 2) +#define E500_TLB_TLB0 (1 << 29) +/* bits [6-5] MAS2_X1 and MAS2_X0 and [4-0] bits for WIMGE */ +#define E500_TLB_MAS2_ATTR (0x7f) struct tlbe_ref { pfn_t pfn; /* valid only for TLB0, except briefly */ diff --git a/arch/powerpc/kvm/e500_mmu.c b/arch/powerpc/kvm/e500_mmu.c index ebca6b88ea5e7d..50860e919cb817 100644 --- a/arch/powerpc/kvm/e500_mmu.c +++ b/arch/powerpc/kvm/e500_mmu.c @@ -127,7 +127,7 @@ static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500, } static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu, - unsigned int eaddr, int as) + gva_t eaddr, int as) { struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); unsigned int victim, tsized; diff --git a/arch/powerpc/kvm/e500_mmu_host.c b/arch/powerpc/kvm/e500_mmu_host.c index ecf2247b13be77..dd2cc03f406f9a 100644 --- a/arch/powerpc/kvm/e500_mmu_host.c +++ b/arch/powerpc/kvm/e500_mmu_host.c @@ -65,15 +65,6 @@ static inline u32 e500_shadow_mas3_attrib(u32 mas3, int usermode) return mas3; } -static inline u32 e500_shadow_mas2_attrib(u32 mas2, int usermode) -{ -#ifdef CONFIG_SMP - return (mas2 & MAS2_ATTRIB_MASK) | MAS2_M; -#else - return mas2 & MAS2_ATTRIB_MASK; -#endif -} - /* * writing shadow tlb entry to host TLB */ @@ -231,15 +222,15 @@ void inval_gtlbe_on_host(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel, ref->flags &= ~(E500_TLB_TLB0 | E500_TLB_VALID); } - /* Already invalidated in between */ - if (!(ref->flags & E500_TLB_VALID)) - return; - - /* Guest tlbe is backed by at most one host tlbe per shadow pid. */ - kvmppc_e500_tlbil_one(vcpu_e500, gtlbe); + /* + * If TLB entry is still valid then it's a TLB0 entry, and thus + * backed by at most one host tlbe per shadow pid + */ + if (ref->flags & E500_TLB_VALID) + kvmppc_e500_tlbil_one(vcpu_e500, gtlbe); /* Mark the TLB as not backed by the host anymore */ - ref->flags &= ~E500_TLB_VALID; + ref->flags = 0; } static inline int tlbe_is_writable(struct kvm_book3e_206_tlb_entry *tlbe) @@ -249,10 +240,13 @@ static inline int tlbe_is_writable(struct kvm_book3e_206_tlb_entry *tlbe) static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref, struct kvm_book3e_206_tlb_entry *gtlbe, - pfn_t pfn) + pfn_t pfn, unsigned int wimg) { ref->pfn = pfn; - ref->flags |= E500_TLB_VALID; + ref->flags = E500_TLB_VALID; + + /* Use guest supplied MAS2_G and MAS2_E */ + ref->flags |= (gtlbe->mas2 & MAS2_ATTRIB_MASK) | wimg; /* Mark the page accessed */ kvm_set_pfn_accessed(pfn); @@ -316,8 +310,7 @@ static void kvmppc_e500_setup_stlbe( /* Force IPROT=0 for all guest mappings. */ stlbe->mas1 = MAS1_TSIZE(tsize) | get_tlb_sts(gtlbe) | MAS1_VALID; - stlbe->mas2 = (gvaddr & MAS2_EPN) | - e500_shadow_mas2_attrib(gtlbe->mas2, pr); + stlbe->mas2 = (gvaddr & MAS2_EPN) | (ref->flags & E500_TLB_MAS2_ATTR); stlbe->mas7_3 = ((u64)pfn << PAGE_SHIFT) | e500_shadow_mas3_attrib(gtlbe->mas7_3, pr); @@ -339,6 +332,10 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, int ret = 0; unsigned long mmu_seq; struct kvm *kvm = vcpu_e500->vcpu.kvm; + unsigned long tsize_pages = 0; + pte_t *ptep; + unsigned int wimg = 0; + pgd_t *pgdir; /* used to check for invalidations in progress */ mmu_seq = kvm->mmu_notifier_seq; @@ -405,7 +402,7 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, */ for (; tsize > BOOK3E_PAGESZ_4K; tsize -= 2) { - unsigned long gfn_start, gfn_end, tsize_pages; + unsigned long gfn_start, gfn_end; tsize_pages = 1 << (tsize - 2); gfn_start = gfn & ~(tsize_pages - 1); @@ -447,11 +444,12 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, } if (likely(!pfnmap)) { - unsigned long tsize_pages = 1 << (tsize + 10 - PAGE_SHIFT); + tsize_pages = 1 << (tsize + 10 - PAGE_SHIFT); pfn = gfn_to_pfn_memslot(slot, gfn); if (is_error_noslot_pfn(pfn)) { - printk(KERN_ERR "Couldn't get real page for gfn %lx!\n", - (long)gfn); + if (printk_ratelimit()) + pr_err("%s: real page not found for gfn %lx\n", + __func__, (long)gfn); return -EINVAL; } @@ -466,7 +464,18 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, goto out; } - kvmppc_e500_ref_setup(ref, gtlbe, pfn); + + pgdir = vcpu_e500->vcpu.arch.pgdir; + ptep = lookup_linux_ptep(pgdir, hva, &tsize_pages); + if (pte_present(*ptep)) + wimg = (*ptep >> PTE_WIMGE_SHIFT) & MAS2_WIMGE_MASK; + else { + if (printk_ratelimit()) + pr_err("%s: pte not present: gfn %lx, pfn %lx\n", + __func__, (long)gfn, pfn); + return -EINVAL; + } + kvmppc_e500_ref_setup(ref, gtlbe, pfn, wimg); kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize, ref, gvaddr, stlbe); diff --git a/arch/powerpc/kvm/e500mc.c b/arch/powerpc/kvm/e500mc.c index 4132cd2fc1715c..17e45627922465 100644 --- a/arch/powerpc/kvm/e500mc.c +++ b/arch/powerpc/kvm/e500mc.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -391,3 +393,5 @@ static void __exit kvmppc_e500mc_exit(void) module_init(kvmppc_e500mc_init); module_exit(kvmppc_e500mc_exit); +MODULE_ALIAS_MISCDEV(KVM_MINOR); +MODULE_ALIAS("devname:kvm"); diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c index 2f9a0873b44fe2..c2b887be2c2922 100644 --- a/arch/powerpc/kvm/emulate.c +++ b/arch/powerpc/kvm/emulate.c @@ -219,7 +219,6 @@ static int kvmppc_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) * lmw * stmw * - * XXX is_bigendian should depend on MMU mapping or MSR[LE] */ /* XXX Should probably auto-generate instruction decoding for a particular core * from opcode tables in the future. */ diff --git a/arch/powerpc/kvm/mpic.c b/arch/powerpc/kvm/mpic.c index 2861ae9eaae6e2..efbd9962a209c9 100644 --- a/arch/powerpc/kvm/mpic.c +++ b/arch/powerpc/kvm/mpic.c @@ -1635,6 +1635,7 @@ static void mpic_destroy(struct kvm_device *dev) dev->kvm->arch.mpic = NULL; kfree(opp); + kfree(dev); } static int mpic_set_default_irq_routing(struct openpic *opp) diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 9ae97686e9f444..3cf541a53e2aef 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -68,14 +68,16 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) */ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu) { - int r = 1; + int r; + + WARN_ON(irqs_disabled()); + hard_irq_disable(); - WARN_ON_ONCE(!irqs_disabled()); while (true) { if (need_resched()) { local_irq_enable(); cond_resched(); - local_irq_disable(); + hard_irq_disable(); continue; } @@ -101,7 +103,7 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu) local_irq_enable(); trace_kvm_check_requests(vcpu); r = kvmppc_core_check_requests(vcpu); - local_irq_disable(); + hard_irq_disable(); if (r > 0) continue; break; @@ -113,22 +115,12 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu) continue; } -#ifdef CONFIG_PPC64 - /* lazy EE magic */ - hard_irq_disable(); - if (lazy_irq_pending()) { - /* Got an interrupt in between, try again */ - local_irq_enable(); - local_irq_disable(); - kvm_guest_exit(); - continue; - } -#endif - kvm_guest_enter(); - break; + return 1; } + /* return to host */ + local_irq_enable(); return r; } EXPORT_SYMBOL_GPL(kvmppc_prepare_to_enter); @@ -656,14 +648,14 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu, kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr); break; case KVM_MMIO_REG_FPR: - vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr; + VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr; break; #ifdef CONFIG_PPC_BOOK3S case KVM_MMIO_REG_QPR: vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr; break; case KVM_MMIO_REG_FQPR: - vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr; + VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr; vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr; break; #endif @@ -673,9 +665,19 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu, } int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, - unsigned int rt, unsigned int bytes, int is_bigendian) + unsigned int rt, unsigned int bytes, + int is_default_endian) { int idx, ret; + int is_bigendian; + + if (kvmppc_need_byteswap(vcpu)) { + /* Default endianness is "little endian". */ + is_bigendian = !is_default_endian; + } else { + /* Default endianness is "big endian". */ + is_bigendian = is_default_endian; + } if (bytes > sizeof(run->mmio.data)) { printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, @@ -711,21 +713,31 @@ EXPORT_SYMBOL_GPL(kvmppc_handle_load); /* Same as above, but sign extends */ int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu, - unsigned int rt, unsigned int bytes, int is_bigendian) + unsigned int rt, unsigned int bytes, + int is_default_endian) { int r; vcpu->arch.mmio_sign_extend = 1; - r = kvmppc_handle_load(run, vcpu, rt, bytes, is_bigendian); + r = kvmppc_handle_load(run, vcpu, rt, bytes, is_default_endian); return r; } int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, - u64 val, unsigned int bytes, int is_bigendian) + u64 val, unsigned int bytes, int is_default_endian) { void *data = run->mmio.data; int idx, ret; + int is_bigendian; + + if (kvmppc_need_byteswap(vcpu)) { + /* Default endianness is "little endian". */ + is_bigendian = !is_default_endian; + } else { + /* Default endianness is "big endian". */ + is_bigendian = is_default_endian; + } if (bytes > sizeof(run->mmio.data)) { printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c index 17e5b236431243..d5edbeb8eb8209 100644 --- a/arch/powerpc/lib/code-patching.c +++ b/arch/powerpc/lib/code-patching.c @@ -159,6 +159,21 @@ unsigned int translate_branch(const unsigned int *dest, const unsigned int *src) return 0; } +#ifdef CONFIG_PPC_BOOK3E_64 +void __patch_exception(int exc, unsigned long addr) +{ + extern unsigned int interrupt_base_book3e; + unsigned int *ibase = &interrupt_base_book3e; + + /* Our exceptions vectors start with a NOP and -then- a branch + * to deal with single stepping from userspace which stops on + * the second instruction. Thus we need to patch the second + * instruction of the exception, not the first one + */ + + patch_branch(ibase + (exc / 4) + 1, addr, 0); +} +#endif #ifdef CONFIG_CODE_PATCHING_SELFTEST diff --git a/arch/powerpc/lib/crtsavres.S b/arch/powerpc/lib/crtsavres.S index b2c68ce139aecb..a5b30c71a8d3f8 100644 --- a/arch/powerpc/lib/crtsavres.S +++ b/arch/powerpc/lib/crtsavres.S @@ -231,6 +231,87 @@ _GLOBAL(_rest32gpr_31_x) mr 1,11 blr +#ifdef CONFIG_ALTIVEC +/* Called with r0 pointing just beyond the end of the vector save area. */ + +_GLOBAL(_savevr_20) + li r11,-192 + stvx vr20,r11,r0 +_GLOBAL(_savevr_21) + li r11,-176 + stvx vr21,r11,r0 +_GLOBAL(_savevr_22) + li r11,-160 + stvx vr22,r11,r0 +_GLOBAL(_savevr_23) + li r11,-144 + stvx vr23,r11,r0 +_GLOBAL(_savevr_24) + li r11,-128 + stvx vr24,r11,r0 +_GLOBAL(_savevr_25) + li r11,-112 + stvx vr25,r11,r0 +_GLOBAL(_savevr_26) + li r11,-96 + stvx vr26,r11,r0 +_GLOBAL(_savevr_27) + li r11,-80 + stvx vr27,r11,r0 +_GLOBAL(_savevr_28) + li r11,-64 + stvx vr28,r11,r0 +_GLOBAL(_savevr_29) + li r11,-48 + stvx vr29,r11,r0 +_GLOBAL(_savevr_30) + li r11,-32 + stvx vr30,r11,r0 +_GLOBAL(_savevr_31) + li r11,-16 + stvx vr31,r11,r0 + blr + +_GLOBAL(_restvr_20) + li r11,-192 + lvx vr20,r11,r0 +_GLOBAL(_restvr_21) + li r11,-176 + lvx vr21,r11,r0 +_GLOBAL(_restvr_22) + li r11,-160 + lvx vr22,r11,r0 +_GLOBAL(_restvr_23) + li r11,-144 + lvx vr23,r11,r0 +_GLOBAL(_restvr_24) + li r11,-128 + lvx vr24,r11,r0 +_GLOBAL(_restvr_25) + li r11,-112 + lvx vr25,r11,r0 +_GLOBAL(_restvr_26) + li r11,-96 + lvx vr26,r11,r0 +_GLOBAL(_restvr_27) + li r11,-80 + lvx vr27,r11,r0 +_GLOBAL(_restvr_28) + li r11,-64 + lvx vr28,r11,r0 +_GLOBAL(_restvr_29) + li r11,-48 + lvx vr29,r11,r0 +_GLOBAL(_restvr_30) + li r11,-32 + lvx vr30,r11,r0 +_GLOBAL(_restvr_31) + li r11,-16 + lvx vr31,r11,r0 + blr + +#endif /* CONFIG_ALTIVEC */ + #else /* CONFIG_PPC64 */ .section ".text.save.restore","ax",@progbits @@ -356,6 +437,111 @@ _restgpr0_31: mtlr r0 blr +#ifdef CONFIG_ALTIVEC +/* Called with r0 pointing just beyond the end of the vector save area. */ + +.globl _savevr_20 +_savevr_20: + li r12,-192 + stvx vr20,r12,r0 +.globl _savevr_21 +_savevr_21: + li r12,-176 + stvx vr21,r12,r0 +.globl _savevr_22 +_savevr_22: + li r12,-160 + stvx vr22,r12,r0 +.globl _savevr_23 +_savevr_23: + li r12,-144 + stvx vr23,r12,r0 +.globl _savevr_24 +_savevr_24: + li r12,-128 + stvx vr24,r12,r0 +.globl _savevr_25 +_savevr_25: + li r12,-112 + stvx vr25,r12,r0 +.globl _savevr_26 +_savevr_26: + li r12,-96 + stvx vr26,r12,r0 +.globl _savevr_27 +_savevr_27: + li r12,-80 + stvx vr27,r12,r0 +.globl _savevr_28 +_savevr_28: + li r12,-64 + stvx vr28,r12,r0 +.globl _savevr_29 +_savevr_29: + li r12,-48 + stvx vr29,r12,r0 +.globl _savevr_30 +_savevr_30: + li r12,-32 + stvx vr30,r12,r0 +.globl _savevr_31 +_savevr_31: + li r12,-16 + stvx vr31,r12,r0 + blr + +.globl _restvr_20 +_restvr_20: + li r12,-192 + lvx vr20,r12,r0 +.globl _restvr_21 +_restvr_21: + li r12,-176 + lvx vr21,r12,r0 +.globl _restvr_22 +_restvr_22: + li r12,-160 + lvx vr22,r12,r0 +.globl _restvr_23 +_restvr_23: + li r12,-144 + lvx vr23,r12,r0 +.globl _restvr_24 +_restvr_24: + li r12,-128 + lvx vr24,r12,r0 +.globl _restvr_25 +_restvr_25: + li r12,-112 + lvx vr25,r12,r0 +.globl _restvr_26 +_restvr_26: + li r12,-96 + lvx vr26,r12,r0 +.globl _restvr_27 +_restvr_27: + li r12,-80 + lvx vr27,r12,r0 +.globl _restvr_28 +_restvr_28: + li r12,-64 + lvx vr28,r12,r0 +.globl _restvr_29 +_restvr_29: + li r12,-48 + lvx vr29,r12,r0 +.globl _restvr_30 +_restvr_30: + li r12,-32 + lvx vr30,r12,r0 +.globl _restvr_31 +_restvr_31: + li r12,-16 + lvx vr31,r12,r0 + blr + +#endif /* CONFIG_ALTIVEC */ + #endif /* CONFIG_PPC64 */ #endif diff --git a/arch/powerpc/math-emu/math_efp.c b/arch/powerpc/math-emu/math_efp.c index a73f0884d358d0..28337c9709ae60 100644 --- a/arch/powerpc/math-emu/math_efp.c +++ b/arch/powerpc/math-emu/math_efp.c @@ -20,6 +20,7 @@ */ #include +#include #include #include @@ -275,21 +276,13 @@ int do_spe_mathemu(struct pt_regs *regs) case EFSCTSF: case EFSCTUF: - if (!((vb.wp[1] >> 23) == 0xff && ((vb.wp[1] & 0x7fffff) > 0))) { - /* NaN */ - if (((vb.wp[1] >> 23) & 0xff) == 0) { - /* denorm */ - vc.wp[1] = 0x0; - } else if ((vb.wp[1] >> 31) == 0) { - /* positive normal */ - vc.wp[1] = (func == EFSCTSF) ? - 0x7fffffff : 0xffffffff; - } else { /* negative normal */ - vc.wp[1] = (func == EFSCTSF) ? - 0x80000000 : 0x0; - } - } else { /* rB is NaN */ - vc.wp[1] = 0x0; + if (SB_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + SB_e += (func == EFSCTSF ? 31 : 32); + FP_TO_INT_ROUND_S(vc.wp[1], SB, 32, + (func == EFSCTSF)); } goto update_regs; @@ -306,16 +299,25 @@ int do_spe_mathemu(struct pt_regs *regs) } case EFSCTSI: - case EFSCTSIZ: case EFSCTUI: + if (SB_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + FP_TO_INT_ROUND_S(vc.wp[1], SB, 32, + ((func & 0x3) != 0)); + } + goto update_regs; + + case EFSCTSIZ: case EFSCTUIZ: - if (func & 0x4) { - _FP_ROUND(1, SB); + if (SB_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); } else { - _FP_ROUND_ZERO(1, SB); + FP_TO_INT_S(vc.wp[1], SB, 32, + ((func & 0x3) != 0)); } - FP_TO_INT_S(vc.wp[1], SB, 32, - (((func & 0x3) != 0) || SB_s)); goto update_regs; default: @@ -404,22 +406,13 @@ int do_spe_mathemu(struct pt_regs *regs) case EFDCTSF: case EFDCTUF: - if (!((vb.wp[0] >> 20) == 0x7ff && - ((vb.wp[0] & 0xfffff) > 0 || (vb.wp[1] > 0)))) { - /* not a NaN */ - if (((vb.wp[0] >> 20) & 0x7ff) == 0) { - /* denorm */ - vc.wp[1] = 0x0; - } else if ((vb.wp[0] >> 31) == 0) { - /* positive normal */ - vc.wp[1] = (func == EFDCTSF) ? - 0x7fffffff : 0xffffffff; - } else { /* negative normal */ - vc.wp[1] = (func == EFDCTSF) ? - 0x80000000 : 0x0; - } - } else { /* NaN */ - vc.wp[1] = 0x0; + if (DB_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + DB_e += (func == EFDCTSF ? 31 : 32); + FP_TO_INT_ROUND_D(vc.wp[1], DB, 32, + (func == EFDCTSF)); } goto update_regs; @@ -437,21 +430,35 @@ int do_spe_mathemu(struct pt_regs *regs) case EFDCTUIDZ: case EFDCTSIDZ: - _FP_ROUND_ZERO(2, DB); - FP_TO_INT_D(vc.dp[0], DB, 64, ((func & 0x1) == 0)); + if (DB_c == FP_CLS_NAN) { + vc.dp[0] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + FP_TO_INT_D(vc.dp[0], DB, 64, + ((func & 0x1) == 0)); + } goto update_regs; case EFDCTUI: case EFDCTSI: + if (DB_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + FP_TO_INT_ROUND_D(vc.wp[1], DB, 32, + ((func & 0x3) != 0)); + } + goto update_regs; + case EFDCTUIZ: case EFDCTSIZ: - if (func & 0x4) { - _FP_ROUND(2, DB); + if (DB_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); } else { - _FP_ROUND_ZERO(2, DB); + FP_TO_INT_D(vc.wp[1], DB, 32, + ((func & 0x3) != 0)); } - FP_TO_INT_D(vc.wp[1], DB, 32, - (((func & 0x3) != 0) || DB_s)); goto update_regs; default: @@ -556,37 +563,60 @@ int do_spe_mathemu(struct pt_regs *regs) cmp = -1; goto cmp_vs; - case EVFSCTSF: - __asm__ __volatile__ ("mtspr 512, %4\n" - "efsctsf %0, %2\n" - "efsctsf %1, %3\n" - : "=r" (vc.wp[0]), "=r" (vc.wp[1]) - : "r" (vb.wp[0]), "r" (vb.wp[1]), "r" (0)); - goto update_regs; - case EVFSCTUF: - __asm__ __volatile__ ("mtspr 512, %4\n" - "efsctuf %0, %2\n" - "efsctuf %1, %3\n" - : "=r" (vc.wp[0]), "=r" (vc.wp[1]) - : "r" (vb.wp[0]), "r" (vb.wp[1]), "r" (0)); + case EVFSCTSF: + if (SB0_c == FP_CLS_NAN) { + vc.wp[0] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + SB0_e += (func == EVFSCTSF ? 31 : 32); + FP_TO_INT_ROUND_S(vc.wp[0], SB0, 32, + (func == EVFSCTSF)); + } + if (SB1_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + SB1_e += (func == EVFSCTSF ? 31 : 32); + FP_TO_INT_ROUND_S(vc.wp[1], SB1, 32, + (func == EVFSCTSF)); + } goto update_regs; case EVFSCTUI: case EVFSCTSI: + if (SB0_c == FP_CLS_NAN) { + vc.wp[0] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + FP_TO_INT_ROUND_S(vc.wp[0], SB0, 32, + ((func & 0x3) != 0)); + } + if (SB1_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + FP_TO_INT_ROUND_S(vc.wp[1], SB1, 32, + ((func & 0x3) != 0)); + } + goto update_regs; + case EVFSCTUIZ: case EVFSCTSIZ: - if (func & 0x4) { - _FP_ROUND(1, SB0); - _FP_ROUND(1, SB1); + if (SB0_c == FP_CLS_NAN) { + vc.wp[0] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); } else { - _FP_ROUND_ZERO(1, SB0); - _FP_ROUND_ZERO(1, SB1); + FP_TO_INT_S(vc.wp[0], SB0, 32, + ((func & 0x3) != 0)); + } + if (SB1_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + FP_TO_INT_S(vc.wp[1], SB1, 32, + ((func & 0x3) != 0)); } - FP_TO_INT_S(vc.wp[0], SB0, 32, - (((func & 0x3) != 0) || SB0_s)); - FP_TO_INT_S(vc.wp[1], SB1, 32, - (((func & 0x3) != 0) || SB1_s)); goto update_regs; default: @@ -630,9 +660,27 @@ int do_spe_mathemu(struct pt_regs *regs) regs->ccr |= (IR << ((7 - ((speinsn >> 23) & 0x7)) << 2)); update_regs: - __FPU_FPSCR &= ~FP_EX_MASK; + /* + * If the "invalid" exception sticky bit was set by the + * processor for non-finite input, but was not set before the + * instruction being emulated, clear it. Likewise for the + * "underflow" bit, which may have been set by the processor + * for exact underflow, not just inexact underflow when the + * flag should be set for IEEE 754 semantics. Other sticky + * exceptions will only be set by the processor when they are + * correct according to IEEE 754 semantics, and we must not + * clear sticky bits that were already set before the emulated + * instruction as they represent the user-visible sticky + * exception status. "inexact" traps to kernel are not + * required for IEEE semantics and are not enabled by default, + * so the "inexact" sticky bit may have been set by a previous + * instruction without the kernel being aware of it. + */ + __FPU_FPSCR + &= ~(FP_EX_INVALID | FP_EX_UNDERFLOW) | current->thread.spefscr_last; __FPU_FPSCR |= (FP_CUR_EXCEPTIONS & FP_EX_MASK); mtspr(SPRN_SPEFSCR, __FPU_FPSCR); + current->thread.spefscr_last = __FPU_FPSCR; current->thread.evr[fc] = vc.wp[0]; regs->gpr[fc] = vc.wp[1]; @@ -644,6 +692,23 @@ int do_spe_mathemu(struct pt_regs *regs) pr_debug("va: %08x %08x\n", va.wp[0], va.wp[1]); pr_debug("vb: %08x %08x\n", vb.wp[0], vb.wp[1]); + if (current->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE) { + if ((FP_CUR_EXCEPTIONS & FP_EX_DIVZERO) + && (current->thread.fpexc_mode & PR_FP_EXC_DIV)) + return 1; + if ((FP_CUR_EXCEPTIONS & FP_EX_OVERFLOW) + && (current->thread.fpexc_mode & PR_FP_EXC_OVF)) + return 1; + if ((FP_CUR_EXCEPTIONS & FP_EX_UNDERFLOW) + && (current->thread.fpexc_mode & PR_FP_EXC_UND)) + return 1; + if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT) + && (current->thread.fpexc_mode & PR_FP_EXC_RES)) + return 1; + if ((FP_CUR_EXCEPTIONS & FP_EX_INVALID) + && (current->thread.fpexc_mode & PR_FP_EXC_INV)) + return 1; + } return 0; illegal: @@ -662,21 +727,28 @@ int speround_handler(struct pt_regs *regs) { union dw_union fgpr; int s_lo, s_hi; - unsigned long speinsn, type, fc; + int lo_inexact, hi_inexact; + int fp_result; + unsigned long speinsn, type, fb, fc, fptype, func; if (get_user(speinsn, (unsigned int __user *) regs->nip)) return -EFAULT; if ((speinsn >> 26) != 4) return -EINVAL; /* not an spe instruction */ - type = insn_type(speinsn & 0x7ff); + func = speinsn & 0x7ff; + type = insn_type(func); if (type == XCR) return -ENOSYS; __FPU_FPSCR = mfspr(SPRN_SPEFSCR); pr_debug("speinsn:%08lx spefscr:%08lx\n", speinsn, __FPU_FPSCR); + fptype = (speinsn >> 5) & 0x7; + /* No need to round if the result is exact */ - if (!(__FPU_FPSCR & FP_EX_INEXACT)) + lo_inexact = __FPU_FPSCR & (SPEFSCR_FG | SPEFSCR_FX); + hi_inexact = __FPU_FPSCR & (SPEFSCR_FGH | SPEFSCR_FXH); + if (!(lo_inexact || (hi_inexact && fptype == VCT))) return 0; fc = (speinsn >> 21) & 0x1f; @@ -685,9 +757,68 @@ int speround_handler(struct pt_regs *regs) fgpr.wp[0] = current->thread.evr[fc]; fgpr.wp[1] = regs->gpr[fc]; + fb = (speinsn >> 11) & 0x1f; + switch (func) { + case EFSCTUIZ: + case EFSCTSIZ: + case EVFSCTUIZ: + case EVFSCTSIZ: + case EFDCTUIDZ: + case EFDCTSIDZ: + case EFDCTUIZ: + case EFDCTSIZ: + /* + * These instructions always round to zero, + * independent of the rounding mode. + */ + return 0; + + case EFSCTUI: + case EFSCTUF: + case EVFSCTUI: + case EVFSCTUF: + case EFDCTUI: + case EFDCTUF: + fp_result = 0; + s_lo = 0; + s_hi = 0; + break; + + case EFSCTSI: + case EFSCTSF: + fp_result = 0; + /* Recover the sign of a zero result if possible. */ + if (fgpr.wp[1] == 0) + s_lo = regs->gpr[fb] & SIGN_BIT_S; + break; + + case EVFSCTSI: + case EVFSCTSF: + fp_result = 0; + /* Recover the sign of a zero result if possible. */ + if (fgpr.wp[1] == 0) + s_lo = regs->gpr[fb] & SIGN_BIT_S; + if (fgpr.wp[0] == 0) + s_hi = current->thread.evr[fb] & SIGN_BIT_S; + break; + + case EFDCTSI: + case EFDCTSF: + fp_result = 0; + s_hi = s_lo; + /* Recover the sign of a zero result if possible. */ + if (fgpr.wp[1] == 0) + s_hi = current->thread.evr[fb] & SIGN_BIT_S; + break; + + default: + fp_result = 1; + break; + } + pr_debug("round fgpr: %08x %08x\n", fgpr.wp[0], fgpr.wp[1]); - switch ((speinsn >> 5) & 0x7) { + switch (fptype) { /* Since SPE instructions on E500 core can handle round to nearest * and round toward zero with IEEE-754 complied, we just need * to handle round toward +Inf and round toward -Inf by software. @@ -696,25 +827,52 @@ int speround_handler(struct pt_regs *regs) if ((FP_ROUNDMODE) == FP_RND_PINF) { if (!s_lo) fgpr.wp[1]++; /* Z > 0, choose Z1 */ } else { /* round to -Inf */ - if (s_lo) fgpr.wp[1]++; /* Z < 0, choose Z2 */ + if (s_lo) { + if (fp_result) + fgpr.wp[1]++; /* Z < 0, choose Z2 */ + else + fgpr.wp[1]--; /* Z < 0, choose Z2 */ + } } break; case DPFP: if (FP_ROUNDMODE == FP_RND_PINF) { - if (!s_hi) fgpr.dp[0]++; /* Z > 0, choose Z1 */ + if (!s_hi) { + if (fp_result) + fgpr.dp[0]++; /* Z > 0, choose Z1 */ + else + fgpr.wp[1]++; /* Z > 0, choose Z1 */ + } } else { /* round to -Inf */ - if (s_hi) fgpr.dp[0]++; /* Z < 0, choose Z2 */ + if (s_hi) { + if (fp_result) + fgpr.dp[0]++; /* Z < 0, choose Z2 */ + else + fgpr.wp[1]--; /* Z < 0, choose Z2 */ + } } break; case VCT: if (FP_ROUNDMODE == FP_RND_PINF) { - if (!s_lo) fgpr.wp[1]++; /* Z_low > 0, choose Z1 */ - if (!s_hi) fgpr.wp[0]++; /* Z_high word > 0, choose Z1 */ + if (lo_inexact && !s_lo) + fgpr.wp[1]++; /* Z_low > 0, choose Z1 */ + if (hi_inexact && !s_hi) + fgpr.wp[0]++; /* Z_high word > 0, choose Z1 */ } else { /* round to -Inf */ - if (s_lo) fgpr.wp[1]++; /* Z_low < 0, choose Z2 */ - if (s_hi) fgpr.wp[0]++; /* Z_high < 0, choose Z2 */ + if (lo_inexact && s_lo) { + if (fp_result) + fgpr.wp[1]++; /* Z_low < 0, choose Z2 */ + else + fgpr.wp[1]--; /* Z_low < 0, choose Z2 */ + } + if (hi_inexact && s_hi) { + if (fp_result) + fgpr.wp[0]++; /* Z_high < 0, choose Z2 */ + else + fgpr.wp[0]--; /* Z_high < 0, choose Z2 */ + } } break; @@ -727,6 +885,8 @@ int speround_handler(struct pt_regs *regs) pr_debug(" to fgpr: %08x %08x\n", fgpr.wp[0], fgpr.wp[1]); + if (current->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE) + return (current->thread.fpexc_mode & PR_FP_EXC_RES) ? 1 : 0; return 0; } diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c index 07ba45b0f07c8e..94cd728166d37a 100644 --- a/arch/powerpc/mm/fsl_booke_mmu.c +++ b/arch/powerpc/mm/fsl_booke_mmu.c @@ -52,6 +52,7 @@ #include #include #include +#include #include "mmu_decl.h" @@ -171,11 +172,10 @@ unsigned long calc_cam_sz(unsigned long ram, unsigned long virt, return 1UL << camsize; } -unsigned long map_mem_in_cams(unsigned long ram, int max_cam_idx) +static unsigned long map_mem_in_cams_addr(phys_addr_t phys, unsigned long virt, + unsigned long ram, int max_cam_idx) { int i; - unsigned long virt = PAGE_OFFSET; - phys_addr_t phys = memstart_addr; unsigned long amount_mapped = 0; /* Calculate CAM values */ @@ -192,9 +192,23 @@ unsigned long map_mem_in_cams(unsigned long ram, int max_cam_idx) } tlbcam_index = i; +#ifdef CONFIG_PPC64 + get_paca()->tcd.esel_next = i; + get_paca()->tcd.esel_max = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY; + get_paca()->tcd.esel_first = i; +#endif + return amount_mapped; } +unsigned long map_mem_in_cams(unsigned long ram, int max_cam_idx) +{ + unsigned long virt = PAGE_OFFSET; + phys_addr_t phys = memstart_addr; + + return map_mem_in_cams_addr(phys, virt, ram, max_cam_idx); +} + #ifdef CONFIG_PPC32 #if defined(CONFIG_LOWMEM_CAM_NUM_BOOL) && (CONFIG_LOWMEM_CAM_NUM >= NUM_TLBCAMS) @@ -222,7 +236,9 @@ void __init adjust_total_lowmem(void) /* adjust lowmem size to __max_low_memory */ ram = min((phys_addr_t)__max_low_memory, (phys_addr_t)total_lowmem); + i = switch_to_as1(); __max_low_memory = map_mem_in_cams(ram, CONFIG_LOWMEM_CAM_NUM); + restore_to_as0(i, 0, 0, 1); pr_info("Memory CAM mapping: "); for (i = 0; i < tlbcam_index - 1; i++) @@ -241,4 +257,62 @@ void setup_initial_memory_limit(phys_addr_t first_memblock_base, /* 64M mapped initially according to head_fsl_booke.S */ memblock_set_current_limit(min_t(u64, limit, 0x04000000)); } + +#ifdef CONFIG_RELOCATABLE +int __initdata is_second_reloc; +notrace void __init relocate_init(u64 dt_ptr, phys_addr_t start) +{ + unsigned long base = KERNELBASE; + + kernstart_addr = start; + if (is_second_reloc) { + virt_phys_offset = PAGE_OFFSET - memstart_addr; + return; + } + + /* + * Relocatable kernel support based on processing of dynamic + * relocation entries. Before we get the real memstart_addr, + * We will compute the virt_phys_offset like this: + * virt_phys_offset = stext.run - kernstart_addr + * + * stext.run = (KERNELBASE & ~0x3ffffff) + + * (kernstart_addr & 0x3ffffff) + * When we relocate, we have : + * + * (kernstart_addr & 0x3ffffff) = (stext.run & 0x3ffffff) + * + * hence: + * virt_phys_offset = (KERNELBASE & ~0x3ffffff) - + * (kernstart_addr & ~0x3ffffff) + * + */ + start &= ~0x3ffffff; + base &= ~0x3ffffff; + virt_phys_offset = base - start; + early_get_first_memblock_info(__va(dt_ptr), NULL); + /* + * We now get the memstart_addr, then we should check if this + * address is the same as what the PAGE_OFFSET map to now. If + * not we have to change the map of PAGE_OFFSET to memstart_addr + * and do a second relocation. + */ + if (start != memstart_addr) { + int n; + long offset = start - memstart_addr; + + is_second_reloc = 1; + n = switch_to_as1(); + /* map a 64M area for the second relocation */ + if (memstart_addr > start) + map_mem_in_cams(0x4000000, CONFIG_LOWMEM_CAM_NUM); + else + map_mem_in_cams_addr(start, PAGE_OFFSET + offset, + 0x4000000, CONFIG_LOWMEM_CAM_NUM); + restore_to_as0(n, offset, __va(dt_ptr), 1); + /* We should never reach here */ + panic("Relocation error"); + } +} +#endif #endif diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S index d3cbda62857b92..1136d26a95ae02 100644 --- a/arch/powerpc/mm/hash_low_64.S +++ b/arch/powerpc/mm/hash_low_64.S @@ -148,7 +148,10 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/ andc r0,r30,r0 /* r0 = pte & ~r0 */ rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */ - ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */ + /* + * Always add "C" bit for perf. Memory coherence is always enabled + */ + ori r3,r3,HPTE_R_C | HPTE_R_M /* We eventually do the icache sync here (maybe inline that * code rather than call a C function...) @@ -457,7 +460,10 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/ andc r0,r3,r0 /* r0 = pte & ~r0 */ rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */ - ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */ + /* + * Always add "C" bit for perf. Memory coherence is always enabled + */ + ori r3,r3,HPTE_R_C | HPTE_R_M /* We eventually do the icache sync here (maybe inline that * code rather than call a C function...) @@ -795,7 +801,10 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/ andc r0,r30,r0 /* r0 = pte & ~r0 */ rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */ - ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */ + /* + * Always add "C" bit for perf. Memory coherence is always enabled + */ + ori r3,r3,HPTE_R_C | HPTE_R_M /* We eventually do the icache sync here (maybe inline that * code rather than call a C function...) diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 6176b3cdf57991..d766d6ee33fe68 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -169,9 +169,10 @@ static unsigned long htab_convert_pte_flags(unsigned long pteflags) if ((pteflags & _PAGE_USER) && !((pteflags & _PAGE_RW) && (pteflags & _PAGE_DIRTY))) rflags |= 1; - - /* Always add C */ - return rflags | HPTE_R_C; + /* + * Always add "C" bit for perf. Memory coherence is always enabled + */ + return rflags | HPTE_R_C | HPTE_R_M; } int htab_bolt_mapping(unsigned long vstart, unsigned long vend, @@ -206,6 +207,20 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, if (overlaps_kernel_text(vaddr, vaddr + step)) tprot &= ~HPTE_R_N; + /* + * If relocatable, check if it overlaps interrupt vectors that + * are copied down to real 0. For relocatable kernel + * (e.g. kdump case) we copy interrupt vectors down to real + * address 0. Mark that region as executable. This is + * because on p8 system with relocation on exception feature + * enabled, exceptions are raised with MMU (IR=DR=1) ON. Hence + * in order to execute the interrupt handlers in virtual + * mode the vector region need to be marked as executable. + */ + if ((PHYSICAL_START > MEMORY_START) && + overlaps_interrupt_vector_text(vaddr, vaddr + step)) + tprot &= ~HPTE_R_N; + hash = hpt_hash(vpn, shift, ssize); hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); diff --git a/arch/powerpc/mm/hugepage-hash64.c b/arch/powerpc/mm/hugepage-hash64.c index 34de9e0cdc3466..826893fcb3a78b 100644 --- a/arch/powerpc/mm/hugepage-hash64.c +++ b/arch/powerpc/mm/hugepage-hash64.c @@ -127,7 +127,11 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid, /* Add in WIMG bits */ rflags |= (new_pmd & (_PAGE_WRITETHRU | _PAGE_NO_CACHE | - _PAGE_COHERENT | _PAGE_GUARDED)); + _PAGE_GUARDED)); + /* + * enable the memory coherence always + */ + rflags |= HPTE_R_M; /* Insert into the hash table, primary slot */ slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags, 0, diff --git a/arch/powerpc/mm/hugetlbpage-book3e.c b/arch/powerpc/mm/hugetlbpage-book3e.c index 74551b5e41e515..5e4ee2573903eb 100644 --- a/arch/powerpc/mm/hugetlbpage-book3e.c +++ b/arch/powerpc/mm/hugetlbpage-book3e.c @@ -8,6 +8,44 @@ #include #include +#ifdef CONFIG_PPC_FSL_BOOK3E +#ifdef CONFIG_PPC64 +static inline int tlb1_next(void) +{ + struct paca_struct *paca = get_paca(); + struct tlb_core_data *tcd; + int this, next; + + tcd = paca->tcd_ptr; + this = tcd->esel_next; + + next = this + 1; + if (next >= tcd->esel_max) + next = tcd->esel_first; + + tcd->esel_next = next; + return this; +} +#else +static inline int tlb1_next(void) +{ + int index, ncams; + + ncams = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY; + + index = __get_cpu_var(next_tlbcam_idx); + + /* Just round-robin the entries and wrap when we hit the end */ + if (unlikely(index == ncams - 1)) + __get_cpu_var(next_tlbcam_idx) = tlbcam_index; + else + __get_cpu_var(next_tlbcam_idx)++; + + return index; +} +#endif /* !PPC64 */ +#endif /* FSL */ + static inline int mmu_get_tsize(int psize) { return mmu_psize_defs[psize].enc; @@ -47,7 +85,7 @@ void book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea, struct mm_struct *mm; #ifdef CONFIG_PPC_FSL_BOOK3E - int index, ncams; + int index; #endif if (unlikely(is_kernel_addr(ea))) @@ -77,18 +115,11 @@ void book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea, } #ifdef CONFIG_PPC_FSL_BOOK3E - ncams = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY; - /* We have to use the CAM(TLB1) on FSL parts for hugepages */ - index = __get_cpu_var(next_tlbcam_idx); + index = tlb1_next(); mtspr(SPRN_MAS0, MAS0_ESEL(index) | MAS0_TLBSEL(1)); - - /* Just round-robin the entries and wrap when we hit the end */ - if (unlikely(index == ncams - 1)) - __get_cpu_var(next_tlbcam_idx) = tlbcam_index; - else - __get_cpu_var(next_tlbcam_idx)++; #endif + mas1 = MAS1_VALID | MAS1_TID(mm->context.id) | MAS1_TSIZE(tsize); mas2 = ea & ~((1UL << shift) - 1); mas2 |= (pte_val(pte) >> PTE_WIMGE_SHIFT) & MAS2_WIMGE_MASK; @@ -103,7 +134,8 @@ void book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea, if (mmu_has_feature(MMU_FTR_USE_PAIRED_MAS)) { mtspr(SPRN_MAS7_MAS3, mas7_3); } else { - mtspr(SPRN_MAS7, upper_32_bits(mas7_3)); + if (mmu_has_feature(MMU_FTR_BIG_PHYS)) + mtspr(SPRN_MAS7, upper_32_bits(mas7_3)); mtspr(SPRN_MAS3, lower_32_bits(mas7_3)); } diff --git a/arch/powerpc/mm/hugetlbpage-hash64.c b/arch/powerpc/mm/hugetlbpage-hash64.c index 0b7fb676101552..a5bcf930119691 100644 --- a/arch/powerpc/mm/hugetlbpage-hash64.c +++ b/arch/powerpc/mm/hugetlbpage-hash64.c @@ -99,6 +99,10 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, /* Add in WIMG bits */ rflags |= (new_pte & (_PAGE_WRITETHRU | _PAGE_NO_CACHE | _PAGE_COHERENT | _PAGE_GUARDED)); + /* + * enable the memory coherence always + */ + rflags |= HPTE_R_M; slot = hpte_insert_repeating(hash, vpn, pa, rflags, 0, mmu_psize, ssize); diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 90bb6d9409bfd7..eb923654ba80e7 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -472,12 +472,13 @@ static void hugepd_free(struct mmu_gather *tlb, void *hugepte) { struct hugepd_freelist **batchp; - batchp = &__get_cpu_var(hugepd_freelist_cur); + batchp = &get_cpu_var(hugepd_freelist_cur); if (atomic_read(&tlb->mm->mm_users) < 2 || cpumask_equal(mm_cpumask(tlb->mm), cpumask_of(smp_processor_id()))) { kmem_cache_free(hugepte_cache, hugepte); + put_cpu_var(hugepd_freelist_cur); return; } @@ -491,6 +492,7 @@ static void hugepd_free(struct mmu_gather *tlb, void *hugepte) call_rcu_sched(&(*batchp)->rcu, hugepd_free_rcu_callback); *batchp = NULL; } + put_cpu_var(hugepd_freelist_cur); } #endif diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 8c1dd23652a13e..4b5cd5c2594d9b 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -307,6 +307,12 @@ static void __init register_page_bootmem_info(void) void __init mem_init(void) { + /* + * book3s is limited to 16 page sizes due to encoding this in + * a 4-bit field for slices. + */ + BUILD_BUG_ON(MMU_PAGE_COUNT > 16); + #ifdef CONFIG_SWIOTLB swiotlb_init(0); #endif @@ -507,7 +513,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, * System memory should not be in /proc/iomem but various tools expect it * (eg kdump). */ -static int add_system_ram_resources(void) +static int __init add_system_ram_resources(void) { struct memblock_region *reg; diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h index 83eb5d5f53d52f..9615d82919b8b4 100644 --- a/arch/powerpc/mm/mmu_decl.h +++ b/arch/powerpc/mm/mmu_decl.h @@ -148,6 +148,8 @@ extern unsigned long calc_cam_sz(unsigned long ram, unsigned long virt, extern void MMU_init_hw(void); extern unsigned long mmu_mapin_ram(unsigned long top); extern void adjust_total_lowmem(void); +extern int switch_to_as1(void); +extern void restore_to_as0(int esel, int offset, void *dt_ptr, int bootcpu); #endif extern void loadcam_entry(unsigned int index); diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 5a944f25e94ff4..30a42e24bf14f4 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include #include @@ -152,9 +154,22 @@ static void __init get_node_active_region(unsigned long pfn, } } -static void map_cpu_to_node(int cpu, int node) +static void reset_numa_cpu_lookup_table(void) +{ + unsigned int cpu; + + for_each_possible_cpu(cpu) + numa_cpu_lookup_table[cpu] = -1; +} + +static void update_numa_cpu_lookup_table(unsigned int cpu, int node) { numa_cpu_lookup_table[cpu] = node; +} + +static void map_cpu_to_node(int cpu, int node) +{ + update_numa_cpu_lookup_table(cpu, node); dbg("adding cpu %d to node %d\n", cpu, node); @@ -522,11 +537,24 @@ static int of_drconf_to_nid_single(struct of_drconf_cell *drmem, */ static int numa_setup_cpu(unsigned long lcpu) { - int nid = 0; - struct device_node *cpu = of_get_cpu_node(lcpu, NULL); + int nid; + struct device_node *cpu; + + /* + * If a valid cpu-to-node mapping is already available, use it + * directly instead of querying the firmware, since it represents + * the most recent mapping notified to us by the platform (eg: VPHN). + */ + if ((nid = numa_cpu_lookup_table[lcpu]) >= 0) { + map_cpu_to_node(lcpu, nid); + return nid; + } + + cpu = of_get_cpu_node(lcpu, NULL); if (!cpu) { WARN_ON(1); + nid = 0; goto out; } @@ -542,16 +570,38 @@ static int numa_setup_cpu(unsigned long lcpu) return nid; } +static void verify_cpu_node_mapping(int cpu, int node) +{ + int base, sibling, i; + + /* Verify that all the threads in the core belong to the same node */ + base = cpu_first_thread_sibling(cpu); + + for (i = 0; i < threads_per_core; i++) { + sibling = base + i; + + if (sibling == cpu || cpu_is_offline(sibling)) + continue; + + if (cpu_to_node(sibling) != node) { + WARN(1, "CPU thread siblings %d and %d don't belong" + " to the same node!\n", cpu, sibling); + break; + } + } +} + static int cpu_numa_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned long lcpu = (unsigned long)hcpu; - int ret = NOTIFY_DONE; + int ret = NOTIFY_DONE, nid; switch (action) { case CPU_UP_PREPARE: case CPU_UP_PREPARE_FROZEN: - numa_setup_cpu(lcpu); + nid = numa_setup_cpu(lcpu); + verify_cpu_node_mapping((int)lcpu, nid); ret = NOTIFY_OK; break; #ifdef CONFIG_HOTPLUG_CPU @@ -1069,6 +1119,7 @@ void __init do_init_bootmem(void) */ setup_node_to_cpumask_map(); + reset_numa_cpu_lookup_table(); register_cpu_notifier(&ppc64_numa_nb); cpu_numa_callback(&ppc64_numa_nb, CPU_UP_PREPARE, (void *)(unsigned long)boot_cpuid); @@ -1447,6 +1498,33 @@ static int update_cpu_topology(void *data) return 0; } +static int update_lookup_table(void *data) +{ + struct topology_update_data *update; + + if (!data) + return -EINVAL; + + /* + * Upon topology update, the numa-cpu lookup table needs to be updated + * for all threads in the core, including offline CPUs, to ensure that + * future hotplug operations respect the cpu-to-node associativity + * properly. + */ + for (update = data; update; update = update->next) { + int nid, base, j; + + nid = update->new_nid; + base = cpu_first_thread_sibling(update->cpu); + + for (j = 0; j < threads_per_core; j++) { + update_numa_cpu_lookup_table(base + j, nid); + } + } + + return 0; +} + /* * Update the node maps and sysfs entries for each cpu whose home node * has changed. Returns 1 when the topology has changed, and 0 otherwise. @@ -1515,6 +1593,14 @@ int arch_update_cpu_topology(void) stop_machine(update_cpu_topology, &updates[0], &updated_cpus); + /* + * Update the numa-cpu lookup table with the new mappings, even for + * offline CPUs. It is best to perform this update from the stop- + * machine context. + */ + stop_machine(update_lookup_table, &updates[0], + cpumask_of(raw_smp_processor_id())); + for (ud = &updates[0]; ud; ud = ud->next) { unregister_cpu_under_node(ud->cpu, ud->old_nid); register_cpu_under_node(ud->cpu, ud->new_nid); @@ -1699,7 +1785,7 @@ static const struct file_operations topology_ops = { static int topology_update_init(void) { start_topology_update(); - proc_create("powerpc/topology_updates", 644, NULL, &topology_ops); + proc_create("powerpc/topology_updates", 0644, NULL, &topology_ops); return 0; } diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c index 841e0d00863c94..c695943a513cc6 100644 --- a/arch/powerpc/mm/pgtable.c +++ b/arch/powerpc/mm/pgtable.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -174,7 +173,7 @@ void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) { #ifdef CONFIG_DEBUG_VM - WARN_ON(pte_present(*ptep)); + WARN_ON(pte_val(*ptep) & _PAGE_PRESENT); #endif /* Note: mm->context.id might not yet have been assigned as * this context might not have been activated yet when this diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 5b9601715289c4..343a87fa78b5eb 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -299,6 +299,7 @@ int map_page(unsigned long va, phys_addr_t pa, int flags) set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags))); } + smp_wmb(); return err; } diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 9d95786aa80ffb..62bf5e8e78daaa 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -153,6 +152,18 @@ int map_kernel_page(unsigned long ea, unsigned long pa, int flags) } #endif /* !CONFIG_PPC_MMU_NOHASH */ } + +#ifdef CONFIG_PPC_BOOK3E_64 + /* + * With hardware tablewalk, a sync is needed to ensure that + * subsequent accesses see the PTE we just wrote. Unlike userspace + * mappings, we can't tolerate spurious faults, so make sure + * the new PTE will be seen the first time. + */ + mb(); +#else + smp_wmb(); +#endif return 0; } @@ -499,7 +510,8 @@ int pmdp_set_access_flags(struct vm_area_struct *vma, unsigned long address, } unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr, - pmd_t *pmdp, unsigned long clr) + pmd_t *pmdp, unsigned long clr, + unsigned long set) { unsigned long old, tmp; @@ -515,14 +527,15 @@ unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr, andi. %1,%0,%6\n\ bne- 1b \n\ andc %1,%0,%4 \n\ + or %1,%1,%7\n\ stdcx. %1,0,%3 \n\ bne- 1b" : "=&r" (old), "=&r" (tmp), "=m" (*pmdp) - : "r" (pmdp), "r" (clr), "m" (*pmdp), "i" (_PAGE_BUSY) + : "r" (pmdp), "r" (clr), "m" (*pmdp), "i" (_PAGE_BUSY), "r" (set) : "cc" ); #else old = pmd_val(*pmdp); - *pmdp = __pmd(old & ~clr); + *pmdp = __pmd((old & ~clr) | set); #endif if (old & _PAGE_HASHPTE) hpte_do_hugepage_flush(mm, addr, pmdp); @@ -687,7 +700,7 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp, pmd_t pmd) { #ifdef CONFIG_DEBUG_VM - WARN_ON(!pmd_none(*pmdp)); + WARN_ON(pmd_val(*pmdp) & _PAGE_PRESENT); assert_spin_locked(&mm->page_table_lock); WARN_ON(!pmd_trans_huge(pmd)); #endif @@ -697,7 +710,7 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr, void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp) { - pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT); + pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, 0); } /* @@ -824,7 +837,7 @@ pmd_t pmdp_get_and_clear(struct mm_struct *mm, unsigned long old; pgtable_t *pgtable_slot; - old = pmd_hugepage_update(mm, addr, pmdp, ~0UL); + old = pmd_hugepage_update(mm, addr, pmdp, ~0UL, 0); old_pmd = __pmd(old); /* * We have pmd == none and we are holding page_table_lock. diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index 7ce9cf3b698835..b0c75cc15efc67 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -408,7 +408,7 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len, if (fixed && (addr & ((1ul << pshift) - 1))) return -EINVAL; if (fixed && addr > (mm->task_size - len)) - return -EINVAL; + return -ENOMEM; /* If hint, make sure it matches our alignment restrictions */ if (!fixed && addr) { diff --git a/arch/powerpc/mm/subpage-prot.c b/arch/powerpc/mm/subpage-prot.c index a770df2dae7050..6c0b1f5f8d2cce 100644 --- a/arch/powerpc/mm/subpage-prot.c +++ b/arch/powerpc/mm/subpage-prot.c @@ -78,7 +78,7 @@ static void hpte_flush_range(struct mm_struct *mm, unsigned long addr, pte = pte_offset_map_lock(mm, pmd, addr, &ptl); arch_enter_lazy_mmu_mode(); for (; npages > 0; --npages) { - pte_update(mm, addr, pte, 0, 0); + pte_update(mm, addr, pte, 0, 0, 0); addr += PAGE_SIZE; ++pte; } diff --git a/arch/powerpc/mm/tlb_hash64.c b/arch/powerpc/mm/tlb_hash64.c index 36e44b4260ebd2..c99f6510a0b267 100644 --- a/arch/powerpc/mm/tlb_hash64.c +++ b/arch/powerpc/mm/tlb_hash64.c @@ -23,7 +23,6 @@ #include #include -#include #include #include #include diff --git a/arch/powerpc/mm/tlb_low_64e.S b/arch/powerpc/mm/tlb_low_64e.S index b4113bf863538a..c95eb323e9ae5a 100644 --- a/arch/powerpc/mm/tlb_low_64e.S +++ b/arch/powerpc/mm/tlb_low_64e.S @@ -136,7 +136,7 @@ BEGIN_MMU_FTR_SECTION */ PPC_TLBSRX_DOT(0,R16) ldx r14,r14,r15 /* grab pgd entry */ - beq normal_tlb_miss_done /* tlb exists already, bail */ + beq tlb_miss_done_bolted /* tlb exists already, bail */ MMU_FTR_SECTION_ELSE ldx r14,r14,r15 /* grab pgd entry */ ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_USE_TLBRSRV) @@ -192,6 +192,7 @@ ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_USE_TLBRSRV) mtspr SPRN_MAS7_MAS3,r15 tlbwe +tlb_miss_done_bolted: TLB_MISS_STATS_X(MMSTAT_TLB_MISS_NORM_OK) tlb_epilog_bolted rfi @@ -239,6 +240,178 @@ itlb_miss_fault_bolted: beq tlb_miss_common_bolted b itlb_miss_kernel_bolted +#ifdef CONFIG_PPC_FSL_BOOK3E +/* + * TLB miss handling for e6500 and derivatives, using hardware tablewalk. + * + * Linear mapping is bolted: no virtual page table or nested TLB misses + * Indirect entries in TLB1, hardware loads resulting direct entries + * into TLB0 + * No HES or NV hint on TLB1, so we need to do software round-robin + * No tlbsrx. so we need a spinlock, and we have to deal + * with MAS-damage caused by tlbsx + * 4K pages only + */ + + START_EXCEPTION(instruction_tlb_miss_e6500) + tlb_prolog_bolted BOOKE_INTERRUPT_ITLB_MISS SPRN_SRR0 + + ld r11,PACA_TCD_PTR(r13) + srdi. r15,r16,60 /* get region */ + ori r16,r16,1 + + TLB_MISS_STATS_SAVE_INFO_BOLTED + bne tlb_miss_kernel_e6500 /* user/kernel test */ + + b tlb_miss_common_e6500 + + START_EXCEPTION(data_tlb_miss_e6500) + tlb_prolog_bolted BOOKE_INTERRUPT_DTLB_MISS SPRN_DEAR + + ld r11,PACA_TCD_PTR(r13) + srdi. r15,r16,60 /* get region */ + rldicr r16,r16,0,62 + + TLB_MISS_STATS_SAVE_INFO_BOLTED + bne tlb_miss_kernel_e6500 /* user vs kernel check */ + +/* + * This is the guts of the TLB miss handler for e6500 and derivatives. + * We are entered with: + * + * r16 = page of faulting address (low bit 0 if data, 1 if instruction) + * r15 = crap (free to use) + * r14 = page table base + * r13 = PACA + * r11 = tlb_per_core ptr + * r10 = crap (free to use) + */ +tlb_miss_common_e6500: + /* + * Search if we already have an indirect entry for that virtual + * address, and if we do, bail out. + * + * MAS6:IND should be already set based on MAS4 + */ + addi r10,r11,TCD_LOCK +1: lbarx r15,0,r10 + cmpdi r15,0 + bne 2f + li r15,1 + stbcx. r15,0,r10 + bne 1b + .subsection 1 +2: lbz r15,0(r10) + cmpdi r15,0 + bne 2b + b 1b + .previous + + mfspr r15,SPRN_MAS2 + + tlbsx 0,r16 + mfspr r10,SPRN_MAS1 + andis. r10,r10,MAS1_VALID@h + bne tlb_miss_done_e6500 + + /* Undo MAS-damage from the tlbsx */ + mfspr r10,SPRN_MAS1 + oris r10,r10,MAS1_VALID@h + mtspr SPRN_MAS1,r10 + mtspr SPRN_MAS2,r15 + + /* Now, we need to walk the page tables. First check if we are in + * range. + */ + rldicl. r10,r16,64-PGTABLE_EADDR_SIZE,PGTABLE_EADDR_SIZE+4 + bne- tlb_miss_fault_e6500 + + rldicl r15,r16,64-PGDIR_SHIFT+3,64-PGD_INDEX_SIZE-3 + cmpldi cr0,r14,0 + clrrdi r15,r15,3 + beq- tlb_miss_fault_e6500 /* No PGDIR, bail */ + ldx r14,r14,r15 /* grab pgd entry */ + + rldicl r15,r16,64-PUD_SHIFT+3,64-PUD_INDEX_SIZE-3 + clrrdi r15,r15,3 + cmpdi cr0,r14,0 + bge tlb_miss_fault_e6500 /* Bad pgd entry or hugepage; bail */ + ldx r14,r14,r15 /* grab pud entry */ + + rldicl r15,r16,64-PMD_SHIFT+3,64-PMD_INDEX_SIZE-3 + clrrdi r15,r15,3 + cmpdi cr0,r14,0 + bge tlb_miss_fault_e6500 + ldx r14,r14,r15 /* Grab pmd entry */ + + mfspr r10,SPRN_MAS0 + cmpdi cr0,r14,0 + bge tlb_miss_fault_e6500 + + /* Now we build the MAS for a 2M indirect page: + * + * MAS 0 : ESEL needs to be filled by software round-robin + * MAS 1 : Fully set up + * - PID already updated by caller if necessary + * - TSIZE for now is base ind page size always + * - TID already cleared if necessary + * MAS 2 : Default not 2M-aligned, need to be redone + * MAS 3+7 : Needs to be done + */ + + ori r14,r14,(BOOK3E_PAGESZ_4K << MAS3_SPSIZE_SHIFT) + mtspr SPRN_MAS7_MAS3,r14 + + clrrdi r15,r16,21 /* make EA 2M-aligned */ + mtspr SPRN_MAS2,r15 + + lbz r15,TCD_ESEL_NEXT(r11) + lbz r16,TCD_ESEL_MAX(r11) + lbz r14,TCD_ESEL_FIRST(r11) + rlwimi r10,r15,16,0x00ff0000 /* insert esel_next into MAS0 */ + addi r15,r15,1 /* increment esel_next */ + mtspr SPRN_MAS0,r10 + cmpw r15,r16 + iseleq r15,r14,r15 /* if next == last use first */ + stb r15,TCD_ESEL_NEXT(r11) + + tlbwe + +tlb_miss_done_e6500: + .macro tlb_unlock_e6500 + li r15,0 + isync + stb r15,TCD_LOCK(r11) + .endm + + tlb_unlock_e6500 + TLB_MISS_STATS_X(MMSTAT_TLB_MISS_NORM_OK) + tlb_epilog_bolted + rfi + +tlb_miss_kernel_e6500: + mfspr r10,SPRN_MAS1 + ld r14,PACA_KERNELPGD(r13) + cmpldi cr0,r15,8 /* Check for vmalloc region */ + rlwinm r10,r10,0,16,1 /* Clear TID */ + mtspr SPRN_MAS1,r10 + beq+ tlb_miss_common_e6500 + +tlb_miss_fault_e6500: + tlb_unlock_e6500 + /* We need to check if it was an instruction miss */ + andi. r16,r16,1 + bne itlb_miss_fault_e6500 +dtlb_miss_fault_e6500: + TLB_MISS_STATS_D(MMSTAT_TLB_MISS_NORM_FAULT) + tlb_epilog_bolted + b exc_data_storage_book3e +itlb_miss_fault_e6500: + TLB_MISS_STATS_I(MMSTAT_TLB_MISS_NORM_FAULT) + tlb_epilog_bolted + b exc_instruction_storage_book3e +#endif /* CONFIG_PPC_FSL_BOOK3E */ + /********************************************************************** * * * TLB miss handling for Book3E with TLB reservation and HES support * diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c index 358d743031385a..b37a58e1c92da8 100644 --- a/arch/powerpc/mm/tlb_nohash.c +++ b/arch/powerpc/mm/tlb_nohash.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "mmu_decl.h" @@ -58,6 +59,10 @@ struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = { .shift = 12, .enc = BOOK3E_PAGESZ_4K, }, + [MMU_PAGE_2M] = { + .shift = 21, + .enc = BOOK3E_PAGESZ_2M, + }, [MMU_PAGE_4M] = { .shift = 22, .enc = BOOK3E_PAGESZ_4M, @@ -136,7 +141,7 @@ static inline int mmu_get_tsize(int psize) int mmu_linear_psize; /* Page size used for the linear mapping */ int mmu_pte_psize; /* Page size used for PTE pages */ int mmu_vmemmap_psize; /* Page size used for the virtual mem map */ -int book3e_htw_enabled; /* Is HW tablewalk enabled ? */ +int book3e_htw_mode; /* HW tablewalk? Value is PPC_HTW_* */ unsigned long linear_map_top; /* Top of linear mapping */ #endif /* CONFIG_PPC64 */ @@ -377,7 +382,7 @@ void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address) { int tsize = mmu_psize_defs[mmu_pte_psize].enc; - if (book3e_htw_enabled) { + if (book3e_htw_mode != PPC_HTW_NONE) { unsigned long start = address & PMD_MASK; unsigned long end = address + PMD_SIZE; unsigned long size = 1UL << mmu_psize_defs[mmu_pte_psize].shift; @@ -430,7 +435,7 @@ static void setup_page_sizes(void) def = &mmu_psize_defs[psize]; shift = def->shift; - if (shift == 0) + if (shift == 0 || shift & 1) continue; /* adjust to be in terms of 4^shift Kb */ @@ -440,21 +445,40 @@ static void setup_page_sizes(void) def->flags |= MMU_PAGE_SIZE_DIRECT; } - goto no_indirect; + goto out; } if (fsl_mmu && (mmucfg & MMUCFG_MAVN) == MMUCFG_MAVN_V2) { - u32 tlb1ps = mfspr(SPRN_TLB1PS); + u32 tlb1cfg, tlb1ps; + + tlb0cfg = mfspr(SPRN_TLB0CFG); + tlb1cfg = mfspr(SPRN_TLB1CFG); + tlb1ps = mfspr(SPRN_TLB1PS); + eptcfg = mfspr(SPRN_EPTCFG); + + if ((tlb1cfg & TLBnCFG_IND) && (tlb0cfg & TLBnCFG_PT)) + book3e_htw_mode = PPC_HTW_E6500; + + /* + * We expect 4K subpage size and unrestricted indirect size. + * The lack of a restriction on indirect size is a Freescale + * extension, indicated by PSn = 0 but SPSn != 0. + */ + if (eptcfg != 2) + book3e_htw_mode = PPC_HTW_NONE; for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { struct mmu_psize_def *def = &mmu_psize_defs[psize]; if (tlb1ps & (1U << (def->shift - 10))) { def->flags |= MMU_PAGE_SIZE_DIRECT; + + if (book3e_htw_mode && psize == MMU_PAGE_2M) + def->flags |= MMU_PAGE_SIZE_INDIRECT; } } - goto no_indirect; + goto out; } #endif @@ -471,8 +495,11 @@ static void setup_page_sizes(void) } /* Indirect page sizes supported ? */ - if ((tlb0cfg & TLBnCFG_IND) == 0) - goto no_indirect; + if ((tlb0cfg & TLBnCFG_IND) == 0 || + (tlb0cfg & TLBnCFG_PT) == 0) + goto out; + + book3e_htw_mode = PPC_HTW_IBM; /* Now, we only deal with one IND page size for each * direct size. Hopefully all implementations today are @@ -497,8 +524,8 @@ static void setup_page_sizes(void) def->ind = ps + 10; } } - no_indirect: +out: /* Cleanup array and print summary */ pr_info("MMU: Supported page sizes\n"); for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { @@ -518,44 +545,27 @@ static void setup_page_sizes(void) } } -static void __patch_exception(int exc, unsigned long addr) -{ - extern unsigned int interrupt_base_book3e; - unsigned int *ibase = &interrupt_base_book3e; - - /* Our exceptions vectors start with a NOP and -then- a branch - * to deal with single stepping from userspace which stops on - * the second instruction. Thus we need to patch the second - * instruction of the exception, not the first one - */ - - patch_branch(ibase + (exc / 4) + 1, addr, 0); -} - -#define patch_exception(exc, name) do { \ - extern unsigned int name; \ - __patch_exception((exc), (unsigned long)&name); \ -} while (0) - static void setup_mmu_htw(void) { - /* Check if HW tablewalk is present, and if yes, enable it by: - * - * - patching the TLB miss handlers to branch to the - * one dedicates to it - * - * - setting the global book3e_htw_enabled - */ - unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG); + /* + * If we want to use HW tablewalk, enable it by patching the TLB miss + * handlers to branch to the one dedicated to it. + */ - if ((tlb0cfg & TLBnCFG_IND) && - (tlb0cfg & TLBnCFG_PT)) { + switch (book3e_htw_mode) { + case PPC_HTW_IBM: patch_exception(0x1c0, exc_data_tlb_miss_htw_book3e); patch_exception(0x1e0, exc_instruction_tlb_miss_htw_book3e); - book3e_htw_enabled = 1; + break; +#ifdef CONFIG_PPC_FSL_BOOK3E + case PPC_HTW_E6500: + patch_exception(0x1c0, exc_data_tlb_miss_e6500_book3e); + patch_exception(0x1e0, exc_instruction_tlb_miss_e6500_book3e); + break; +#endif } pr_info("MMU: Book3E HW tablewalk %s\n", - book3e_htw_enabled ? "enabled" : "not supported"); + book3e_htw_mode != PPC_HTW_NONE ? "enabled" : "not supported"); } /* @@ -595,8 +605,16 @@ static void __early_init_mmu(int boot_cpu) /* Set MAS4 based on page table setting */ mas4 = 0x4 << MAS4_WIMGED_SHIFT; - if (book3e_htw_enabled) { - mas4 |= mas4 | MAS4_INDD; + switch (book3e_htw_mode) { + case PPC_HTW_E6500: + mas4 |= MAS4_INDD; + mas4 |= BOOK3E_PAGESZ_2M << MAS4_TSIZED_SHIFT; + mas4 |= MAS4_TLBSELD(1); + mmu_pte_psize = MMU_PAGE_2M; + break; + + case PPC_HTW_IBM: + mas4 |= MAS4_INDD; #ifdef CONFIG_PPC_64K_PAGES mas4 |= BOOK3E_PAGESZ_256M << MAS4_TSIZED_SHIFT; mmu_pte_psize = MMU_PAGE_256M; @@ -604,13 +622,16 @@ static void __early_init_mmu(int boot_cpu) mas4 |= BOOK3E_PAGESZ_1M << MAS4_TSIZED_SHIFT; mmu_pte_psize = MMU_PAGE_1M; #endif - } else { + break; + + case PPC_HTW_NONE: #ifdef CONFIG_PPC_64K_PAGES mas4 |= BOOK3E_PAGESZ_64K << MAS4_TSIZED_SHIFT; #else mas4 |= BOOK3E_PAGESZ_4K << MAS4_TSIZED_SHIFT; #endif mmu_pte_psize = mmu_virtual_psize; + break; } mtspr(SPRN_MAS4, mas4); @@ -630,8 +651,11 @@ static void __early_init_mmu(int boot_cpu) /* limit memory so we dont have linear faults */ memblock_enforce_memory_limit(linear_map_top); - patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e); - patch_exception(0x1e0, exc_instruction_tlb_miss_bolted_book3e); + if (book3e_htw_mode == PPC_HTW_NONE) { + patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e); + patch_exception(0x1e0, + exc_instruction_tlb_miss_bolted_book3e); + } } #endif diff --git a/arch/powerpc/mm/tlb_nohash_low.S b/arch/powerpc/mm/tlb_nohash_low.S index 626ad081639f0e..43ff3c797fbfed 100644 --- a/arch/powerpc/mm/tlb_nohash_low.S +++ b/arch/powerpc/mm/tlb_nohash_low.S @@ -402,7 +402,9 @@ _GLOBAL(set_context) * Load TLBCAM[index] entry in to the L2 CAM MMU */ _GLOBAL(loadcam_entry) - LOAD_REG_ADDR(r4, TLBCAM) + mflr r5 + LOAD_REG_ADDR_PIC(r4, TLBCAM) + mtlr r5 mulli r5,r3,TLBCAM_SIZE add r3,r5,r4 lwz r4,TLBCAM_MAS0(r3) diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c index ff617246d128b7..d29b6e4e5e721f 100644 --- a/arch/powerpc/oprofile/op_model_7450.c +++ b/arch/powerpc/oprofile/op_model_7450.c @@ -16,7 +16,6 @@ */ #include -#include #include #include #include diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c index b9589c19ccdabf..1f0ebdeea5f77c 100644 --- a/arch/powerpc/oprofile/op_model_cell.c +++ b/arch/powerpc/oprofile/op_model_cell.c @@ -16,7 +16,6 @@ #include #include -#include #include #include #include diff --git a/arch/powerpc/oprofile/op_model_fsl_emb.c b/arch/powerpc/oprofile/op_model_fsl_emb.c index 2a82d3ed464d09..14cf86fdddab43 100644 --- a/arch/powerpc/oprofile/op_model_fsl_emb.c +++ b/arch/powerpc/oprofile/op_model_fsl_emb.c @@ -14,7 +14,6 @@ */ #include -#include #include #include #include diff --git a/arch/powerpc/oprofile/op_model_pa6t.c b/arch/powerpc/oprofile/op_model_pa6t.c index 42f778dff919b3..a114a7c22d40a9 100644 --- a/arch/powerpc/oprofile/op_model_pa6t.c +++ b/arch/powerpc/oprofile/op_model_pa6t.c @@ -22,7 +22,6 @@ */ #include -#include #include #include #include diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c index f444b94935f560..962fe7b3e3fb19 100644 --- a/arch/powerpc/oprofile/op_model_power4.c +++ b/arch/powerpc/oprofile/op_model_power4.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/arch/powerpc/oprofile/op_model_rs64.c b/arch/powerpc/oprofile/op_model_rs64.c index 9b801b8c8c5adb..7e5b8ed3a1b772 100644 --- a/arch/powerpc/oprofile/op_model_rs64.c +++ b/arch/powerpc/oprofile/op_model_rs64.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 29b89e863d7cc1..67cf22083f4c2c 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -1147,6 +1147,9 @@ static void power_pmu_enable(struct pmu *pmu) mmcr0 = ebb_switch_in(ebb, cpuhw->mmcr[0]); mb(); + if (cpuhw->bhrb_users) + ppmu->config_bhrb(cpuhw->bhrb_filter); + write_mmcr0(cpuhw, mmcr0); /* @@ -1158,8 +1161,6 @@ static void power_pmu_enable(struct pmu *pmu) } out: - if (cpuhw->bhrb_users) - ppmu->config_bhrb(cpuhw->bhrb_filter); local_irq_restore(flags); } diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c index a3f7abd2f13f7a..96cee20dcd34ec 100644 --- a/arch/powerpc/perf/power8-pmu.c +++ b/arch/powerpc/perf/power8-pmu.c @@ -25,6 +25,37 @@ #define PM_BRU_FIN 0x10068 #define PM_BR_MPRED_CMPL 0x400f6 +/* All L1 D cache load references counted at finish, gated by reject */ +#define PM_LD_REF_L1 0x100ee +/* Load Missed L1 */ +#define PM_LD_MISS_L1 0x3e054 +/* Store Missed L1 */ +#define PM_ST_MISS_L1 0x300f0 +/* L1 cache data prefetches */ +#define PM_L1_PREF 0x0d8b8 +/* Instruction fetches from L1 */ +#define PM_INST_FROM_L1 0x04080 +/* Demand iCache Miss */ +#define PM_L1_ICACHE_MISS 0x200fd +/* Instruction Demand sectors wriittent into IL1 */ +#define PM_L1_DEMAND_WRITE 0x0408c +/* Instruction prefetch written into IL1 */ +#define PM_IC_PREF_WRITE 0x0408e +/* The data cache was reloaded from local core's L3 due to a demand load */ +#define PM_DATA_FROM_L3 0x4c042 +/* Demand LD - L3 Miss (not L2 hit and not L3 hit) */ +#define PM_DATA_FROM_L3MISS 0x300fe +/* All successful D-side store dispatches for this thread */ +#define PM_L2_ST 0x17080 +/* All successful D-side store dispatches for this thread that were L2 Miss */ +#define PM_L2_ST_MISS 0x17082 +/* Total HW L3 prefetches(Load+store) */ +#define PM_L3_PREF_ALL 0x4e052 +/* Data PTEG reload */ +#define PM_DTLB_MISS 0x300fc +/* ITLB Reloaded */ +#define PM_ITLB_MISS 0x400fc + /* * Raw event encoding for POWER8: @@ -557,6 +588,8 @@ static int power8_generic_events[] = { [PERF_COUNT_HW_INSTRUCTIONS] = PM_INST_CMPL, [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = PM_BRU_FIN, [PERF_COUNT_HW_BRANCH_MISSES] = PM_BR_MPRED_CMPL, + [PERF_COUNT_HW_CACHE_REFERENCES] = PM_LD_REF_L1, + [PERF_COUNT_HW_CACHE_MISSES] = PM_LD_MISS_L1, }; static u64 power8_bhrb_filter_map(u64 branch_sample_type) @@ -596,6 +629,116 @@ static void power8_config_bhrb(u64 pmu_bhrb_filter) mtspr(SPRN_MMCRA, (mfspr(SPRN_MMCRA) | pmu_bhrb_filter)); } +#define C(x) PERF_COUNT_HW_CACHE_##x + +/* + * Table of generalized cache-related events. + * 0 means not supported, -1 means nonsensical, other values + * are event codes. + */ +static int power8_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { + [ C(L1D) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = PM_LD_REF_L1, + [ C(RESULT_MISS) ] = PM_LD_MISS_L1, + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0, + [ C(RESULT_MISS) ] = PM_ST_MISS_L1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = PM_L1_PREF, + [ C(RESULT_MISS) ] = 0, + }, + }, + [ C(L1I) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = PM_INST_FROM_L1, + [ C(RESULT_MISS) ] = PM_L1_ICACHE_MISS, + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = PM_L1_DEMAND_WRITE, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = PM_IC_PREF_WRITE, + [ C(RESULT_MISS) ] = 0, + }, + }, + [ C(LL) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = PM_DATA_FROM_L3, + [ C(RESULT_MISS) ] = PM_DATA_FROM_L3MISS, + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = PM_L2_ST, + [ C(RESULT_MISS) ] = PM_L2_ST_MISS, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = PM_L3_PREF_ALL, + [ C(RESULT_MISS) ] = 0, + }, + }, + [ C(DTLB) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0, + [ C(RESULT_MISS) ] = PM_DTLB_MISS, + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, + [ C(ITLB) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0, + [ C(RESULT_MISS) ] = PM_ITLB_MISS, + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, + [ C(BPU) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = PM_BRU_FIN, + [ C(RESULT_MISS) ] = PM_BR_MPRED_CMPL, + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, + [ C(NODE) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, +}; + +#undef C + static struct power_pmu power8_pmu = { .name = "POWER8", .n_counter = 6, @@ -611,6 +754,7 @@ static struct power_pmu power8_pmu = { .flags = PPMU_HAS_SSLOT | PPMU_HAS_SIER | PPMU_BHRB | PPMU_EBB, .n_generic = ARRAY_SIZE(power8_generic_events), .generic_events = power8_generic_events, + .cache_events = &power8_cache_events, .attr_groups = power8_pmu_attr_groups, .bhrb_nr = 32, }; diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig index fc9c1cbfcb1d5f..5aa3f4b5332c57 100644 --- a/arch/powerpc/platforms/512x/Kconfig +++ b/arch/powerpc/platforms/512x/Kconfig @@ -1,9 +1,9 @@ config PPC_MPC512x bool "512x-based boards" depends on 6xx + select COMMON_CLK select FSL_SOC select IPIC - select PPC_CLOCK select PPC_PCI_CHOICE select FSL_PCI if PCI select ARCH_WANT_OPTIONAL_GPIOLIB diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile index 72fb9340e09fa7..01693121a2b1a5 100644 --- a/arch/powerpc/platforms/512x/Makefile +++ b/arch/powerpc/platforms/512x/Makefile @@ -1,7 +1,8 @@ # # Makefile for the Freescale PowerPC 512x linux kernel. # -obj-y += clock.o mpc512x_shared.o +obj-$(CONFIG_COMMON_CLK) += clock-commonclk.o +obj-y += mpc512x_shared.o obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o mpc5121_ads_cpld.o obj-$(CONFIG_MPC512x_GENERIC) += mpc512x_generic.o obj-$(CONFIG_PDM360NG) += pdm360ng.o diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c new file mode 100644 index 00000000000000..6eb614a271fbe0 --- /dev/null +++ b/arch/powerpc/platforms/512x/clock-commonclk.c @@ -0,0 +1,1221 @@ +/* + * Copyright (C) 2013 DENX Software Engineering + * + * Gerhard Sittig, + * + * common clock driver support for the MPC512x platform + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "mpc512x.h" /* our public mpc5121_clk_init() API */ + +/* helpers to keep the MCLK intermediates "somewhere" in our table */ +enum { + MCLK_IDX_MUX0, + MCLK_IDX_EN0, + MCLK_IDX_DIV0, + MCLK_MAX_IDX, +}; + +#define NR_PSCS 12 +#define NR_MSCANS 4 +#define NR_SPDIFS 1 +#define NR_OUTCLK 4 +#define NR_MCLKS (NR_PSCS + NR_MSCANS + NR_SPDIFS + NR_OUTCLK) + +/* extend the public set of clocks by adding internal slots for management */ +enum { + /* arrange for adjacent numbers after the public set */ + MPC512x_CLK_START_PRIVATE = MPC512x_CLK_LAST_PUBLIC, + /* clocks which aren't announced to the public */ + MPC512x_CLK_DDR, + MPC512x_CLK_MEM, + MPC512x_CLK_IIM, + /* intermediates in div+gate combos or fractional dividers */ + MPC512x_CLK_DDR_UG, + MPC512x_CLK_SDHC_x4, + MPC512x_CLK_SDHC_UG, + MPC512x_CLK_SDHC2_UG, + MPC512x_CLK_DIU_x4, + MPC512x_CLK_DIU_UG, + MPC512x_CLK_MBX_BUS_UG, + MPC512x_CLK_MBX_UG, + MPC512x_CLK_MBX_3D_UG, + MPC512x_CLK_PCI_UG, + MPC512x_CLK_NFC_UG, + MPC512x_CLK_LPC_UG, + MPC512x_CLK_SPDIF_TX_IN, + /* intermediates for the mux+gate+div+mux MCLK generation */ + MPC512x_CLK_MCLKS_FIRST, + MPC512x_CLK_MCLKS_LAST = MPC512x_CLK_MCLKS_FIRST + + NR_MCLKS * MCLK_MAX_IDX, + /* internal, symbolic spec for the number of slots */ + MPC512x_CLK_LAST_PRIVATE, +}; + +/* data required for the OF clock provider registration */ +static struct clk *clks[MPC512x_CLK_LAST_PRIVATE]; +static struct clk_onecell_data clk_data; + +/* CCM register access */ +static struct mpc512x_ccm __iomem *clkregs; +static DEFINE_SPINLOCK(clklock); + +/* SoC variants {{{ */ + +/* + * tell SoC variants apart as they are rather similar yet not identical, + * cache the result in an enum to not repeatedly run the expensive OF test + * + * MPC5123 is an MPC5121 without the MBX graphics accelerator + * + * MPC5125 has many more differences: no MBX, no AXE, no VIU, no SPDIF, + * no PATA, no SATA, no PCI, two FECs (of different compatibility name), + * only 10 PSCs (of different compatibility name), two SDHCs, different + * NFC IP block, output clocks, system PLL status query, different CPMF + * interpretation, no CFM, different fourth PSC/CAN mux0 input -- yet + * those differences can get folded into this clock provider support + * code and don't warrant a separate highly redundant implementation + */ + +static enum soc_type { + MPC512x_SOC_MPC5121, + MPC512x_SOC_MPC5123, + MPC512x_SOC_MPC5125, +} soc; + +static void mpc512x_clk_determine_soc(void) +{ + if (of_machine_is_compatible("fsl,mpc5121")) { + soc = MPC512x_SOC_MPC5121; + return; + } + if (of_machine_is_compatible("fsl,mpc5123")) { + soc = MPC512x_SOC_MPC5123; + return; + } + if (of_machine_is_compatible("fsl,mpc5125")) { + soc = MPC512x_SOC_MPC5125; + return; + } +} + +static bool soc_has_mbx(void) +{ + if (soc == MPC512x_SOC_MPC5121) + return true; + return false; +} + +static bool soc_has_axe(void) +{ + if (soc == MPC512x_SOC_MPC5125) + return false; + return true; +} + +static bool soc_has_viu(void) +{ + if (soc == MPC512x_SOC_MPC5125) + return false; + return true; +} + +static bool soc_has_spdif(void) +{ + if (soc == MPC512x_SOC_MPC5125) + return false; + return true; +} + +static bool soc_has_pata(void) +{ + if (soc == MPC512x_SOC_MPC5125) + return false; + return true; +} + +static bool soc_has_sata(void) +{ + if (soc == MPC512x_SOC_MPC5125) + return false; + return true; +} + +static bool soc_has_pci(void) +{ + if (soc == MPC512x_SOC_MPC5125) + return false; + return true; +} + +static bool soc_has_fec2(void) +{ + if (soc == MPC512x_SOC_MPC5125) + return true; + return false; +} + +static int soc_max_pscnum(void) +{ + if (soc == MPC512x_SOC_MPC5125) + return 10; + return 12; +} + +static bool soc_has_sdhc2(void) +{ + if (soc == MPC512x_SOC_MPC5125) + return true; + return false; +} + +static bool soc_has_nfc_5125(void) +{ + if (soc == MPC512x_SOC_MPC5125) + return true; + return false; +} + +static bool soc_has_outclk(void) +{ + if (soc == MPC512x_SOC_MPC5125) + return true; + return false; +} + +static bool soc_has_cpmf_0_bypass(void) +{ + if (soc == MPC512x_SOC_MPC5125) + return true; + return false; +} + +static bool soc_has_mclk_mux0_canin(void) +{ + if (soc == MPC512x_SOC_MPC5125) + return true; + return false; +} + +/* }}} SoC variants */ +/* common clk API wrappers {{{ */ + +/* convenience wrappers around the common clk API */ +static inline struct clk *mpc512x_clk_fixed(const char *name, int rate) +{ + return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate); +} + +static inline struct clk *mpc512x_clk_factor( + const char *name, const char *parent_name, + int mul, int div) +{ + int clkflags; + + clkflags = CLK_SET_RATE_PARENT; + return clk_register_fixed_factor(NULL, name, parent_name, clkflags, + mul, div); +} + +static inline struct clk *mpc512x_clk_divider( + const char *name, const char *parent_name, u8 clkflags, + u32 __iomem *reg, u8 pos, u8 len, int divflags) +{ + return clk_register_divider(NULL, name, parent_name, clkflags, + reg, pos, len, divflags, &clklock); +} + +static inline struct clk *mpc512x_clk_divtable( + const char *name, const char *parent_name, + u32 __iomem *reg, u8 pos, u8 len, + const struct clk_div_table *divtab) +{ + u8 divflags; + + divflags = 0; + return clk_register_divider_table(NULL, name, parent_name, 0, + reg, pos, len, divflags, + divtab, &clklock); +} + +static inline struct clk *mpc512x_clk_gated( + const char *name, const char *parent_name, + u32 __iomem *reg, u8 pos) +{ + int clkflags; + + clkflags = CLK_SET_RATE_PARENT; + return clk_register_gate(NULL, name, parent_name, clkflags, + reg, pos, 0, &clklock); +} + +static inline struct clk *mpc512x_clk_muxed(const char *name, + const char **parent_names, int parent_count, + u32 __iomem *reg, u8 pos, u8 len) +{ + int clkflags; + u8 muxflags; + + clkflags = CLK_SET_RATE_PARENT; + muxflags = 0; + return clk_register_mux(NULL, name, + parent_names, parent_count, clkflags, + reg, pos, len, muxflags, &clklock); +} + +/* }}} common clk API wrappers */ + +/* helper to isolate a bit field from a register */ +static inline int get_bit_field(uint32_t __iomem *reg, uint8_t pos, uint8_t len) +{ + uint32_t val; + + val = in_be32(reg); + val >>= pos; + val &= (1 << len) - 1; + return val; +} + +/* get the SPMF and translate it into the "sys pll" multiplier */ +static int get_spmf_mult(void) +{ + static int spmf_to_mult[] = { + 68, 1, 12, 16, 20, 24, 28, 32, + 36, 40, 44, 48, 52, 56, 60, 64, + }; + int spmf; + + spmf = get_bit_field(&clkregs->spmr, 24, 4); + return spmf_to_mult[spmf]; +} + +/* + * get the SYS_DIV value and translate it into a divide factor + * + * values returned from here are a multiple of the real factor since the + * divide ratio is fractional + */ +static int get_sys_div_x2(void) +{ + static int sysdiv_code_to_x2[] = { + 4, 5, 6, 7, 8, 9, 10, 14, + 12, 16, 18, 22, 20, 24, 26, 30, + 28, 32, 34, 38, 36, 40, 42, 46, + 44, 48, 50, 54, 52, 56, 58, 62, + 60, 64, 66, + }; + int divcode; + + divcode = get_bit_field(&clkregs->scfr2, 26, 6); + return sysdiv_code_to_x2[divcode]; +} + +/* + * get the CPMF value and translate it into a multiplier factor + * + * values returned from here are a multiple of the real factor since the + * multiplier ratio is fractional + */ +static int get_cpmf_mult_x2(void) +{ + static int cpmf_to_mult_x36[] = { + /* 0b000 is "times 36" */ + 72, 2, 2, 3, 4, 5, 6, 7, + }; + static int cpmf_to_mult_0by[] = { + /* 0b000 is "bypass" */ + 2, 2, 2, 3, 4, 5, 6, 7, + }; + + int *cpmf_to_mult; + int cpmf; + + cpmf = get_bit_field(&clkregs->spmr, 16, 4); + if (soc_has_cpmf_0_bypass()) + cpmf_to_mult = cpmf_to_mult_0by; + else + cpmf_to_mult = cpmf_to_mult_x36; + return cpmf_to_mult[cpmf]; +} + +/* + * some of the clock dividers do scale in a linear way, yet not all of + * their bit combinations are legal; use a divider table to get a + * resulting set of applicable divider values + */ + +/* applies to the IPS_DIV, and PCI_DIV values */ +static struct clk_div_table divtab_2346[] = { + { .val = 2, .div = 2, }, + { .val = 3, .div = 3, }, + { .val = 4, .div = 4, }, + { .val = 6, .div = 6, }, + { .div = 0, }, +}; + +/* applies to the MBX_DIV, LPC_DIV, and NFC_DIV values */ +static struct clk_div_table divtab_1234[] = { + { .val = 1, .div = 1, }, + { .val = 2, .div = 2, }, + { .val = 3, .div = 3, }, + { .val = 4, .div = 4, }, + { .div = 0, }, +}; + +static int get_freq_from_dt(char *propname) +{ + struct device_node *np; + const unsigned int *prop; + int val; + + val = 0; + np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr"); + if (np) { + prop = of_get_property(np, propname, NULL); + if (prop) + val = *prop; + of_node_put(np); + } + return val; +} + +static void mpc512x_clk_preset_data(void) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(clks); i++) + clks[i] = ERR_PTR(-ENODEV); +} + +/* + * - receives the "bus frequency" from the caller (that's the IPS clock + * rate, the historical source of clock information) + * - fetches the system PLL multiplier and divider values as well as the + * IPS divider value from hardware + * - determines the REF clock rate either from the XTAL/OSC spec (if + * there is a device tree node describing the oscillator) or from the + * IPS bus clock (supported for backwards compatibility, such that + * setups without XTAL/OSC specs keep working) + * - creates the "ref" clock item in the clock tree, such that + * subsequent code can create the remainder of the hierarchy (REF -> + * SYS -> CSB -> IPS) from the REF clock rate and the returned mul/div + * values + */ +static void mpc512x_clk_setup_ref_clock(struct device_node *np, int bus_freq, + int *sys_mul, int *sys_div, + int *ips_div) +{ + struct clk *osc_clk; + int calc_freq; + + /* fetch mul/div factors from the hardware */ + *sys_mul = get_spmf_mult(); + *sys_mul *= 2; /* compensate for the fractional divider */ + *sys_div = get_sys_div_x2(); + *ips_div = get_bit_field(&clkregs->scfr1, 23, 3); + + /* lookup the oscillator clock for its rate */ + osc_clk = of_clk_get_by_name(np, "osc"); + + /* + * either descend from OSC to REF (and in bypassing verify the + * IPS rate), or backtrack from IPS and multiplier values that + * were fetched from hardware to REF and thus to the OSC value + * + * in either case the REF clock gets created here and the + * remainder of the clock tree can get spanned from there + */ + if (!IS_ERR(osc_clk)) { + clks[MPC512x_CLK_REF] = mpc512x_clk_factor("ref", "osc", 1, 1); + calc_freq = clk_get_rate(clks[MPC512x_CLK_REF]); + calc_freq *= *sys_mul; + calc_freq /= *sys_div; + calc_freq /= 2; + calc_freq /= *ips_div; + if (bus_freq && calc_freq != bus_freq) + pr_warn("calc rate %d != OF spec %d\n", + calc_freq, bus_freq); + } else { + calc_freq = bus_freq; /* start with IPS */ + calc_freq *= *ips_div; /* IPS -> CSB */ + calc_freq *= 2; /* CSB -> SYS */ + calc_freq *= *sys_div; /* SYS -> PLL out */ + calc_freq /= *sys_mul; /* PLL out -> REF == OSC */ + clks[MPC512x_CLK_REF] = mpc512x_clk_fixed("ref", calc_freq); + } +} + +/* MCLK helpers {{{ */ + +/* + * helper code for the MCLK subtree setup + * + * the overview in section 5.2.4 of the MPC5121e Reference Manual rev4 + * suggests that all instances of the "PSC clock generation" are equal, + * and that one might re-use the PSC setup for MSCAN clock generation + * (section 5.2.5) as well, at least the logic if not the data for + * description + * + * the details (starting at page 5-20) show differences in the specific + * inputs of the first mux stage ("can clk in", "spdif tx"), and the + * factual non-availability of the second mux stage (it's present yet + * only one input is valid) + * + * the MSCAN clock related registers (starting at page 5-35) all + * reference "spdif clk" at the first mux stage and don't mention any + * "can clk" at all, which somehow is unexpected + * + * TODO re-check the document, and clarify whether the RM is correct in + * the overview or in the details, and whether the difference is a + * clipboard induced error or results from chip revisions + * + * it turns out that the RM rev4 as of 2012-06 talks about "can" for the + * PSCs while RM rev3 as of 2008-10 talks about "spdif", so I guess that + * first a doc update is required which better reflects reality in the + * SoC before the implementation should follow while no questions remain + */ + +/* + * note that this declaration raises a checkpatch warning, but + * it's the very data type dictated by , + * "fixing" this warning will break compilation + */ +static const char *parent_names_mux0_spdif[] = { + "sys", "ref", "psc-mclk-in", "spdif-tx", +}; + +static const char *parent_names_mux0_canin[] = { + "sys", "ref", "psc-mclk-in", "can-clk-in", +}; + +enum mclk_type { + MCLK_TYPE_PSC, + MCLK_TYPE_MSCAN, + MCLK_TYPE_SPDIF, + MCLK_TYPE_OUTCLK, +}; + +struct mclk_setup_data { + enum mclk_type type; + bool has_mclk1; + const char *name_mux0; + const char *name_en0; + const char *name_div0; + const char *parent_names_mux1[2]; + const char *name_mclk; +}; + +#define MCLK_SETUP_DATA_PSC(id) { \ + MCLK_TYPE_PSC, 0, \ + "psc" #id "-mux0", \ + "psc" #id "-en0", \ + "psc" #id "_mclk_div", \ + { "psc" #id "_mclk_div", "dummy", }, \ + "psc" #id "_mclk", \ +} + +#define MCLK_SETUP_DATA_MSCAN(id) { \ + MCLK_TYPE_MSCAN, 0, \ + "mscan" #id "-mux0", \ + "mscan" #id "-en0", \ + "mscan" #id "_mclk_div", \ + { "mscan" #id "_mclk_div", "dummy", }, \ + "mscan" #id "_mclk", \ +} + +#define MCLK_SETUP_DATA_SPDIF { \ + MCLK_TYPE_SPDIF, 1, \ + "spdif-mux0", \ + "spdif-en0", \ + "spdif_mclk_div", \ + { "spdif_mclk_div", "spdif-rx", }, \ + "spdif_mclk", \ +} + +#define MCLK_SETUP_DATA_OUTCLK(id) { \ + MCLK_TYPE_OUTCLK, 0, \ + "out" #id "-mux0", \ + "out" #id "-en0", \ + "out" #id "_mclk_div", \ + { "out" #id "_mclk_div", "dummy", }, \ + "out" #id "_clk", \ +} + +static struct mclk_setup_data mclk_psc_data[] = { + MCLK_SETUP_DATA_PSC(0), + MCLK_SETUP_DATA_PSC(1), + MCLK_SETUP_DATA_PSC(2), + MCLK_SETUP_DATA_PSC(3), + MCLK_SETUP_DATA_PSC(4), + MCLK_SETUP_DATA_PSC(5), + MCLK_SETUP_DATA_PSC(6), + MCLK_SETUP_DATA_PSC(7), + MCLK_SETUP_DATA_PSC(8), + MCLK_SETUP_DATA_PSC(9), + MCLK_SETUP_DATA_PSC(10), + MCLK_SETUP_DATA_PSC(11), +}; + +static struct mclk_setup_data mclk_mscan_data[] = { + MCLK_SETUP_DATA_MSCAN(0), + MCLK_SETUP_DATA_MSCAN(1), + MCLK_SETUP_DATA_MSCAN(2), + MCLK_SETUP_DATA_MSCAN(3), +}; + +static struct mclk_setup_data mclk_spdif_data[] = { + MCLK_SETUP_DATA_SPDIF, +}; + +static struct mclk_setup_data mclk_outclk_data[] = { + MCLK_SETUP_DATA_OUTCLK(0), + MCLK_SETUP_DATA_OUTCLK(1), + MCLK_SETUP_DATA_OUTCLK(2), + MCLK_SETUP_DATA_OUTCLK(3), +}; + +/* setup the MCLK clock subtree of an individual PSC/MSCAN/SPDIF */ +static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry, size_t idx) +{ + size_t clks_idx_pub, clks_idx_int; + u32 __iomem *mccr_reg; /* MCLK control register (mux, en, div) */ + int div; + + /* derive a few parameters from the component type and index */ + switch (entry->type) { + case MCLK_TYPE_PSC: + clks_idx_pub = MPC512x_CLK_PSC0_MCLK + idx; + clks_idx_int = MPC512x_CLK_MCLKS_FIRST + + (idx) * MCLK_MAX_IDX; + mccr_reg = &clkregs->psc_ccr[idx]; + break; + case MCLK_TYPE_MSCAN: + clks_idx_pub = MPC512x_CLK_MSCAN0_MCLK + idx; + clks_idx_int = MPC512x_CLK_MCLKS_FIRST + + (NR_PSCS + idx) * MCLK_MAX_IDX; + mccr_reg = &clkregs->mscan_ccr[idx]; + break; + case MCLK_TYPE_SPDIF: + clks_idx_pub = MPC512x_CLK_SPDIF_MCLK; + clks_idx_int = MPC512x_CLK_MCLKS_FIRST + + (NR_PSCS + NR_MSCANS) * MCLK_MAX_IDX; + mccr_reg = &clkregs->spccr; + break; + case MCLK_TYPE_OUTCLK: + clks_idx_pub = MPC512x_CLK_OUT0_CLK + idx; + clks_idx_int = MPC512x_CLK_MCLKS_FIRST + + (NR_PSCS + NR_MSCANS + NR_SPDIFS + idx) + * MCLK_MAX_IDX; + mccr_reg = &clkregs->out_ccr[idx]; + break; + default: + return; + } + + /* + * this was grabbed from the PPC_CLOCK implementation, which + * enforced a specific MCLK divider while the clock was gated + * during setup (that's a documented hardware requirement) + * + * the PPC_CLOCK implementation might even have violated the + * "MCLK <= IPS" constraint, the fixed divider value of 1 + * results in a divider of 2 and thus MCLK = SYS/2 which equals + * CSB which is greater than IPS; the serial port setup may have + * adjusted the divider which the clock setup might have left in + * an undesirable state + * + * initial setup is: + * - MCLK 0 from SYS + * - MCLK DIV such to not exceed the IPS clock + * - MCLK 0 enabled + * - MCLK 1 from MCLK DIV + */ + div = clk_get_rate(clks[MPC512x_CLK_SYS]); + div /= clk_get_rate(clks[MPC512x_CLK_IPS]); + out_be32(mccr_reg, (0 << 16)); + out_be32(mccr_reg, (0 << 16) | ((div - 1) << 17)); + out_be32(mccr_reg, (1 << 16) | ((div - 1) << 17)); + + /* + * create the 'struct clk' items of the MCLK's clock subtree + * + * note that by design we always create all nodes and won't take + * shortcuts here, because + * - the "internal" MCLK_DIV and MCLK_OUT signal in turn are + * selectable inputs to the CFM while those who "actually use" + * the PSC/MSCAN/SPDIF (serial drivers et al) need the MCLK + * for their bitrate + * - in the absence of "aliases" for clocks we need to create + * individial 'struct clk' items for whatever might get + * referenced or looked up, even if several of those items are + * identical from the logical POV (their rate value) + * - for easier future maintenance and for better reflection of + * the SoC's documentation, it appears appropriate to generate + * clock items even for those muxers which actually are NOPs + * (those with two inputs of which one is reserved) + */ + clks[clks_idx_int + MCLK_IDX_MUX0] = mpc512x_clk_muxed( + entry->name_mux0, + soc_has_mclk_mux0_canin() + ? &parent_names_mux0_canin[0] + : &parent_names_mux0_spdif[0], + ARRAY_SIZE(parent_names_mux0_spdif), + mccr_reg, 14, 2); + clks[clks_idx_int + MCLK_IDX_EN0] = mpc512x_clk_gated( + entry->name_en0, entry->name_mux0, + mccr_reg, 16); + clks[clks_idx_int + MCLK_IDX_DIV0] = mpc512x_clk_divider( + entry->name_div0, + entry->name_en0, CLK_SET_RATE_GATE, + mccr_reg, 17, 15, 0); + if (entry->has_mclk1) { + clks[clks_idx_pub] = mpc512x_clk_muxed( + entry->name_mclk, + &entry->parent_names_mux1[0], + ARRAY_SIZE(entry->parent_names_mux1), + mccr_reg, 7, 1); + } else { + clks[clks_idx_pub] = mpc512x_clk_factor( + entry->name_mclk, + entry->parent_names_mux1[0], + 1, 1); + } +} + +/* }}} MCLK helpers */ + +static void mpc512x_clk_setup_clock_tree(struct device_node *np, int busfreq) +{ + int sys_mul, sys_div, ips_div; + int mul, div; + size_t mclk_idx; + int freq; + + /* + * developer's notes: + * - consider whether to handle clocks which have both gates and + * dividers via intermediates or by means of composites + * - fractional dividers appear to not map well to composites + * since they can be seen as a fixed multiplier and an + * adjustable divider, while composites can only combine at + * most one of a mux, div, and gate each into one 'struct clk' + * item + * - PSC/MSCAN/SPDIF clock generation OTOH already is very + * specific and cannot get mapped to componsites (at least not + * a single one, maybe two of them, but then some of these + * intermediate clock signals get referenced elsewhere (e.g. + * in the clock frequency measurement, CFM) and thus need + * publicly available names + * - the current source layout appropriately reflects the + * hardware setup, and it works, so it's questionable whether + * further changes will result in big enough a benefit + */ + + /* regardless of whether XTAL/OSC exists, have REF created */ + mpc512x_clk_setup_ref_clock(np, busfreq, &sys_mul, &sys_div, &ips_div); + + /* now setup the REF -> SYS -> CSB -> IPS hierarchy */ + clks[MPC512x_CLK_SYS] = mpc512x_clk_factor("sys", "ref", + sys_mul, sys_div); + clks[MPC512x_CLK_CSB] = mpc512x_clk_factor("csb", "sys", 1, 2); + clks[MPC512x_CLK_IPS] = mpc512x_clk_divtable("ips", "csb", + &clkregs->scfr1, 23, 3, + divtab_2346); + /* now setup anything below SYS and CSB and IPS */ + + clks[MPC512x_CLK_DDR_UG] = mpc512x_clk_factor("ddr-ug", "sys", 1, 2); + + /* + * the Reference Manual discusses that for SDHC only even divide + * ratios are supported because clock domain synchronization + * between 'per' and 'ipg' is broken; + * keep the divider's bit 0 cleared (per reset value), and only + * allow to setup the divider's bits 7:1, which results in that + * only even divide ratios can get configured upon rate changes; + * keep the "x4" name because this bit shift hack is an internal + * implementation detail, the "fractional divider with quarters" + * semantics remains + */ + clks[MPC512x_CLK_SDHC_x4] = mpc512x_clk_factor("sdhc-x4", "csb", 2, 1); + clks[MPC512x_CLK_SDHC_UG] = mpc512x_clk_divider("sdhc-ug", "sdhc-x4", 0, + &clkregs->scfr2, 1, 7, + CLK_DIVIDER_ONE_BASED); + if (soc_has_sdhc2()) { + clks[MPC512x_CLK_SDHC2_UG] = mpc512x_clk_divider( + "sdhc2-ug", "sdhc-x4", 0, &clkregs->scfr2, + 9, 7, CLK_DIVIDER_ONE_BASED); + } + + clks[MPC512x_CLK_DIU_x4] = mpc512x_clk_factor("diu-x4", "csb", 4, 1); + clks[MPC512x_CLK_DIU_UG] = mpc512x_clk_divider("diu-ug", "diu-x4", 0, + &clkregs->scfr1, 0, 8, + CLK_DIVIDER_ONE_BASED); + + /* + * the "power architecture PLL" was setup from data which was + * sampled from the reset config word, at this point in time the + * configuration can be considered fixed and read only (i.e. no + * longer adjustable, or no longer in need of adjustment), which + * is why we don't register a PLL here but assume fixed factors + */ + mul = get_cpmf_mult_x2(); + div = 2; /* compensate for the fractional factor */ + clks[MPC512x_CLK_E300] = mpc512x_clk_factor("e300", "csb", mul, div); + + if (soc_has_mbx()) { + clks[MPC512x_CLK_MBX_BUS_UG] = mpc512x_clk_factor( + "mbx-bus-ug", "csb", 1, 2); + clks[MPC512x_CLK_MBX_UG] = mpc512x_clk_divtable( + "mbx-ug", "mbx-bus-ug", &clkregs->scfr1, + 14, 3, divtab_1234); + clks[MPC512x_CLK_MBX_3D_UG] = mpc512x_clk_factor( + "mbx-3d-ug", "mbx-ug", 1, 1); + } + if (soc_has_pci()) { + clks[MPC512x_CLK_PCI_UG] = mpc512x_clk_divtable( + "pci-ug", "csb", &clkregs->scfr1, + 20, 3, divtab_2346); + } + if (soc_has_nfc_5125()) { + /* + * XXX TODO implement 5125 NFC clock setup logic, + * with high/low period counters in clkregs->scfr3, + * currently there are no users so it's ENOIMPL + */ + clks[MPC512x_CLK_NFC_UG] = ERR_PTR(-ENOTSUPP); + } else { + clks[MPC512x_CLK_NFC_UG] = mpc512x_clk_divtable( + "nfc-ug", "ips", &clkregs->scfr1, + 8, 3, divtab_1234); + } + clks[MPC512x_CLK_LPC_UG] = mpc512x_clk_divtable("lpc-ug", "ips", + &clkregs->scfr1, 11, 3, + divtab_1234); + + clks[MPC512x_CLK_LPC] = mpc512x_clk_gated("lpc", "lpc-ug", + &clkregs->sccr1, 30); + clks[MPC512x_CLK_NFC] = mpc512x_clk_gated("nfc", "nfc-ug", + &clkregs->sccr1, 29); + if (soc_has_pata()) { + clks[MPC512x_CLK_PATA] = mpc512x_clk_gated( + "pata", "ips", &clkregs->sccr1, 28); + } + /* for PSCs there is a "registers" gate and a bitrate MCLK subtree */ + for (mclk_idx = 0; mclk_idx < soc_max_pscnum(); mclk_idx++) { + char name[12]; + snprintf(name, sizeof(name), "psc%d", mclk_idx); + clks[MPC512x_CLK_PSC0 + mclk_idx] = mpc512x_clk_gated( + name, "ips", &clkregs->sccr1, 27 - mclk_idx); + mpc512x_clk_setup_mclk(&mclk_psc_data[mclk_idx], mclk_idx); + } + clks[MPC512x_CLK_PSC_FIFO] = mpc512x_clk_gated("psc-fifo", "ips", + &clkregs->sccr1, 15); + if (soc_has_sata()) { + clks[MPC512x_CLK_SATA] = mpc512x_clk_gated( + "sata", "ips", &clkregs->sccr1, 14); + } + clks[MPC512x_CLK_FEC] = mpc512x_clk_gated("fec", "ips", + &clkregs->sccr1, 13); + if (soc_has_pci()) { + clks[MPC512x_CLK_PCI] = mpc512x_clk_gated( + "pci", "pci-ug", &clkregs->sccr1, 11); + } + clks[MPC512x_CLK_DDR] = mpc512x_clk_gated("ddr", "ddr-ug", + &clkregs->sccr1, 10); + if (soc_has_fec2()) { + clks[MPC512x_CLK_FEC2] = mpc512x_clk_gated( + "fec2", "ips", &clkregs->sccr1, 9); + } + + clks[MPC512x_CLK_DIU] = mpc512x_clk_gated("diu", "diu-ug", + &clkregs->sccr2, 31); + if (soc_has_axe()) { + clks[MPC512x_CLK_AXE] = mpc512x_clk_gated( + "axe", "csb", &clkregs->sccr2, 30); + } + clks[MPC512x_CLK_MEM] = mpc512x_clk_gated("mem", "ips", + &clkregs->sccr2, 29); + clks[MPC512x_CLK_USB1] = mpc512x_clk_gated("usb1", "csb", + &clkregs->sccr2, 28); + clks[MPC512x_CLK_USB2] = mpc512x_clk_gated("usb2", "csb", + &clkregs->sccr2, 27); + clks[MPC512x_CLK_I2C] = mpc512x_clk_gated("i2c", "ips", + &clkregs->sccr2, 26); + /* MSCAN differs from PSC with just one gate for multiple components */ + clks[MPC512x_CLK_BDLC] = mpc512x_clk_gated("bdlc", "ips", + &clkregs->sccr2, 25); + for (mclk_idx = 0; mclk_idx < ARRAY_SIZE(mclk_mscan_data); mclk_idx++) + mpc512x_clk_setup_mclk(&mclk_mscan_data[mclk_idx], mclk_idx); + clks[MPC512x_CLK_SDHC] = mpc512x_clk_gated("sdhc", "sdhc-ug", + &clkregs->sccr2, 24); + /* there is only one SPDIF component, which shares MCLK support code */ + if (soc_has_spdif()) { + clks[MPC512x_CLK_SPDIF] = mpc512x_clk_gated( + "spdif", "ips", &clkregs->sccr2, 23); + mpc512x_clk_setup_mclk(&mclk_spdif_data[0], 0); + } + if (soc_has_mbx()) { + clks[MPC512x_CLK_MBX_BUS] = mpc512x_clk_gated( + "mbx-bus", "mbx-bus-ug", &clkregs->sccr2, 22); + clks[MPC512x_CLK_MBX] = mpc512x_clk_gated( + "mbx", "mbx-ug", &clkregs->sccr2, 21); + clks[MPC512x_CLK_MBX_3D] = mpc512x_clk_gated( + "mbx-3d", "mbx-3d-ug", &clkregs->sccr2, 20); + } + clks[MPC512x_CLK_IIM] = mpc512x_clk_gated("iim", "csb", + &clkregs->sccr2, 19); + if (soc_has_viu()) { + clks[MPC512x_CLK_VIU] = mpc512x_clk_gated( + "viu", "csb", &clkregs->sccr2, 18); + } + if (soc_has_sdhc2()) { + clks[MPC512x_CLK_SDHC2] = mpc512x_clk_gated( + "sdhc-2", "sdhc2-ug", &clkregs->sccr2, 17); + } + + if (soc_has_outclk()) { + size_t idx; /* used as mclk_idx, just to trim line length */ + for (idx = 0; idx < ARRAY_SIZE(mclk_outclk_data); idx++) + mpc512x_clk_setup_mclk(&mclk_outclk_data[idx], idx); + } + + /* + * externally provided clocks (when implemented in hardware, + * device tree may specify values which otherwise were unknown) + */ + freq = get_freq_from_dt("psc_mclk_in"); + if (!freq) + freq = 25000000; + clks[MPC512x_CLK_PSC_MCLK_IN] = mpc512x_clk_fixed("psc_mclk_in", freq); + if (soc_has_mclk_mux0_canin()) { + freq = get_freq_from_dt("can_clk_in"); + clks[MPC512x_CLK_CAN_CLK_IN] = mpc512x_clk_fixed( + "can_clk_in", freq); + } else { + freq = get_freq_from_dt("spdif_tx_in"); + clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed( + "spdif_tx_in", freq); + freq = get_freq_from_dt("spdif_rx_in"); + clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed( + "spdif_rx_in", freq); + } + + /* fixed frequency for AC97, always 24.567MHz */ + clks[MPC512x_CLK_AC97] = mpc512x_clk_fixed("ac97", 24567000); + + /* + * pre-enable those "internal" clock items which never get + * claimed by any peripheral driver, to not have the clock + * subsystem disable them late at startup + */ + clk_prepare_enable(clks[MPC512x_CLK_DUMMY]); + clk_prepare_enable(clks[MPC512x_CLK_E300]); /* PowerPC CPU */ + clk_prepare_enable(clks[MPC512x_CLK_DDR]); /* DRAM */ + clk_prepare_enable(clks[MPC512x_CLK_MEM]); /* SRAM */ + clk_prepare_enable(clks[MPC512x_CLK_IPS]); /* SoC periph */ + clk_prepare_enable(clks[MPC512x_CLK_LPC]); /* boot media */ +} + +/* + * registers the set of public clocks (those listed in the dt-bindings/ + * header file) for OF lookups, keeps the intermediates private to us + */ +static void mpc5121_clk_register_of_provider(struct device_node *np) +{ + clk_data.clks = clks; + clk_data.clk_num = MPC512x_CLK_LAST_PUBLIC + 1; /* _not_ ARRAY_SIZE() */ + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); +} + +/* + * temporary support for the period of time between introduction of CCF + * support and the adjustment of peripheral drivers to OF based lookups + */ +static void mpc5121_clk_provide_migration_support(void) +{ + + /* + * pre-enable those clock items which are not yet appropriately + * acquired by their peripheral driver + * + * the PCI clock cannot get acquired by its peripheral driver, + * because for this platform the driver won't probe(), instead + * initialization is done from within the .setup_arch() routine + * at a point in time where the clock provider has not been + * setup yet and thus isn't available yet + * + * so we "pre-enable" the clock here, to not have the clock + * subsystem automatically disable this item in a late init call + * + * this PCI clock pre-enable workaround only applies when there + * are device tree nodes for PCI and thus the peripheral driver + * has attached to bridges, otherwise the PCI clock remains + * unused and so it gets disabled + */ + clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */ + if (of_find_compatible_node(NULL, "pci", "fsl,mpc5121-pci")) + clk_prepare_enable(clks[MPC512x_CLK_PCI]); +} + +/* + * those macros are not exactly pretty, but they encapsulate a lot + * of copy'n'paste heavy code which is even more ugly, and reduce + * the potential for inconsistencies in those many code copies + */ +#define FOR_NODES(compatname) \ + for_each_compatible_node(np, NULL, compatname) + +#define NODE_PREP do { \ + of_address_to_resource(np, 0, &res); \ + snprintf(devname, sizeof(devname), "%08x.%s", res.start, np->name); \ +} while (0) + +#define NODE_CHK(clkname, clkitem, regnode, regflag) do { \ + struct clk *clk; \ + clk = of_clk_get_by_name(np, clkname); \ + if (IS_ERR(clk)) { \ + clk = clkitem; \ + clk_register_clkdev(clk, clkname, devname); \ + if (regnode) \ + clk_register_clkdev(clk, clkname, np->name); \ + did_register |= DID_REG_ ## regflag; \ + pr_debug("clock alias name '%s' for dev '%s' pointer %p\n", \ + clkname, devname, clk); \ + } else { \ + clk_put(clk); \ + } \ +} while (0) + +/* + * register source code provided fallback results for clock lookups, + * these get consulted when OF based clock lookup fails (that is in the + * case of not yet adjusted device tree data, where clock related specs + * are missing) + */ +static void mpc5121_clk_provide_backwards_compat(void) +{ + enum did_reg_flags { + DID_REG_PSC = BIT(0), + DID_REG_PSCFIFO = BIT(1), + DID_REG_NFC = BIT(2), + DID_REG_CAN = BIT(3), + DID_REG_I2C = BIT(4), + DID_REG_DIU = BIT(5), + DID_REG_VIU = BIT(6), + DID_REG_FEC = BIT(7), + DID_REG_USB = BIT(8), + DID_REG_PATA = BIT(9), + }; + + int did_register; + struct device_node *np; + struct resource res; + int idx; + char devname[32]; + + did_register = 0; + + FOR_NODES(mpc512x_select_psc_compat()) { + NODE_PREP; + idx = (res.start >> 8) & 0xf; + NODE_CHK("ipg", clks[MPC512x_CLK_PSC0 + idx], 0, PSC); + NODE_CHK("mclk", clks[MPC512x_CLK_PSC0_MCLK + idx], 0, PSC); + } + + FOR_NODES("fsl,mpc5121-psc-fifo") { + NODE_PREP; + NODE_CHK("ipg", clks[MPC512x_CLK_PSC_FIFO], 1, PSCFIFO); + } + + FOR_NODES("fsl,mpc5121-nfc") { + NODE_PREP; + NODE_CHK("ipg", clks[MPC512x_CLK_NFC], 0, NFC); + } + + FOR_NODES("fsl,mpc5121-mscan") { + NODE_PREP; + idx = 0; + idx += (res.start & 0x2000) ? 2 : 0; + idx += (res.start & 0x0080) ? 1 : 0; + NODE_CHK("ipg", clks[MPC512x_CLK_BDLC], 0, CAN); + NODE_CHK("mclk", clks[MPC512x_CLK_MSCAN0_MCLK + idx], 0, CAN); + } + + /* + * do register the 'ips', 'sys', and 'ref' names globally + * instead of inside each individual CAN node, as there is no + * potential for a name conflict (in contrast to 'ipg' and 'mclk') + */ + if (did_register & DID_REG_CAN) { + clk_register_clkdev(clks[MPC512x_CLK_IPS], "ips", NULL); + clk_register_clkdev(clks[MPC512x_CLK_SYS], "sys", NULL); + clk_register_clkdev(clks[MPC512x_CLK_REF], "ref", NULL); + } + + FOR_NODES("fsl,mpc5121-i2c") { + NODE_PREP; + NODE_CHK("ipg", clks[MPC512x_CLK_I2C], 0, I2C); + } + + /* + * workaround for the fact that the I2C driver does an "anonymous" + * lookup (NULL name spec, which yields the first clock spec) for + * which we cannot register an alias -- a _global_ 'ipg' alias that + * is not bound to any device name and returns the I2C clock item + * is not a good idea + * + * so we have the lookup in the peripheral driver fail, which is + * silent and non-fatal, and pre-enable the clock item here such + * that register access is possible + * + * see commit b3bfce2b "i2c: mpc: cleanup clock API use" for + * details, adjusting s/NULL/"ipg"/ in i2c-mpc.c would make this + * workaround obsolete + */ + if (did_register & DID_REG_I2C) + clk_prepare_enable(clks[MPC512x_CLK_I2C]); + + FOR_NODES("fsl,mpc5121-diu") { + NODE_PREP; + NODE_CHK("ipg", clks[MPC512x_CLK_DIU], 1, DIU); + } + + FOR_NODES("fsl,mpc5121-viu") { + NODE_PREP; + NODE_CHK("ipg", clks[MPC512x_CLK_VIU], 0, VIU); + } + + /* + * note that 2771399a "fs_enet: cleanup clock API use" did use the + * "per" string for the clock lookup in contrast to the "ipg" name + * which most other nodes are using -- this is not a fatal thing + * but just something to keep in mind when doing compatibility + * registration, it's a non-issue with up-to-date device tree data + */ + FOR_NODES("fsl,mpc5121-fec") { + NODE_PREP; + NODE_CHK("per", clks[MPC512x_CLK_FEC], 0, FEC); + } + FOR_NODES("fsl,mpc5121-fec-mdio") { + NODE_PREP; + NODE_CHK("per", clks[MPC512x_CLK_FEC], 0, FEC); + } + /* + * MPC5125 has two FECs: FEC1 at 0x2800, FEC2 at 0x4800; + * the clock items don't "form an array" since FEC2 was + * added only later and was not allowed to shift all other + * clock item indices, so the numbers aren't adjacent + */ + FOR_NODES("fsl,mpc5125-fec") { + NODE_PREP; + if (res.start & 0x4000) + idx = MPC512x_CLK_FEC2; + else + idx = MPC512x_CLK_FEC; + NODE_CHK("per", clks[idx], 0, FEC); + } + + FOR_NODES("fsl,mpc5121-usb2-dr") { + NODE_PREP; + idx = (res.start & 0x4000) ? 1 : 0; + NODE_CHK("ipg", clks[MPC512x_CLK_USB1 + idx], 0, USB); + } + + FOR_NODES("fsl,mpc5121-pata") { + NODE_PREP; + NODE_CHK("ipg", clks[MPC512x_CLK_PATA], 0, PATA); + } + + /* + * try to collapse diagnostics into a single line of output yet + * provide a full list of what is missing, to avoid noise in the + * absence of up-to-date device tree data -- backwards + * compatibility to old DTBs is a requirement, updates may be + * desirable or preferrable but are not at all mandatory + */ + if (did_register) { + pr_notice("device tree lacks clock specs, adding fallbacks (0x%x,%s%s%s%s%s%s%s%s%s%s)\n", + did_register, + (did_register & DID_REG_PSC) ? " PSC" : "", + (did_register & DID_REG_PSCFIFO) ? " PSCFIFO" : "", + (did_register & DID_REG_NFC) ? " NFC" : "", + (did_register & DID_REG_CAN) ? " CAN" : "", + (did_register & DID_REG_I2C) ? " I2C" : "", + (did_register & DID_REG_DIU) ? " DIU" : "", + (did_register & DID_REG_VIU) ? " VIU" : "", + (did_register & DID_REG_FEC) ? " FEC" : "", + (did_register & DID_REG_USB) ? " USB" : "", + (did_register & DID_REG_PATA) ? " PATA" : ""); + } else { + pr_debug("device tree has clock specs, no fallbacks added\n"); + } +} + +int __init mpc5121_clk_init(void) +{ + struct device_node *clk_np; + int busfreq; + + /* map the clock control registers */ + clk_np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock"); + if (!clk_np) + return -ENODEV; + clkregs = of_iomap(clk_np, 0); + WARN_ON(!clkregs); + + /* determine the SoC variant we run on */ + mpc512x_clk_determine_soc(); + + /* invalidate all not yet registered clock slots */ + mpc512x_clk_preset_data(); + + /* + * have the device tree scanned for "fixed-clock" nodes (which + * includes the oscillator node if the board's DT provides one) + */ + of_clk_init(NULL); + + /* + * add a dummy clock for those situations where a clock spec is + * required yet no real clock is involved + */ + clks[MPC512x_CLK_DUMMY] = mpc512x_clk_fixed("dummy", 0); + + /* + * have all the real nodes in the clock tree populated from REF + * down to all leaves, either starting from the OSC node or from + * a REF root that was created from the IPS bus clock input + */ + busfreq = get_freq_from_dt("bus-frequency"); + mpc512x_clk_setup_clock_tree(clk_np, busfreq); + + /* register as an OF clock provider */ + mpc5121_clk_register_of_provider(clk_np); + + /* + * unbreak not yet adjusted peripheral drivers during migration + * towards fully operational common clock support, and allow + * operation in the absence of clock related device tree specs + */ + mpc5121_clk_provide_migration_support(); + mpc5121_clk_provide_backwards_compat(); + + return 0; +} diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c deleted file mode 100644 index fd8a3765341773..00000000000000 --- a/arch/powerpc/platforms/512x/clock.c +++ /dev/null @@ -1,754 +0,0 @@ -/* - * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved. - * - * Author: John Rigby - * - * Implements the clk api defined in include/linux/clk.h - * - * Original based on linux/arch/arm/mach-integrator/clock.c - * - * Copyright (C) 2004 ARM Limited. - * Written by Deep Blue Solutions 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. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "mpc512x.h" - -#undef CLK_DEBUG - -static int clocks_initialized; - -#define CLK_HAS_RATE 0x1 /* has rate in MHz */ -#define CLK_HAS_CTRL 0x2 /* has control reg and bit */ - -struct clk { - struct list_head node; - char name[32]; - int flags; - struct device *dev; - unsigned long rate; - struct module *owner; - void (*calc) (struct clk *); - struct clk *parent; - int reg, bit; /* CLK_HAS_CTRL */ - int div_shift; /* only used by generic_div_clk_calc */ -}; - -static LIST_HEAD(clocks); -static DEFINE_MUTEX(clocks_mutex); - -static struct clk *mpc5121_clk_get(struct device *dev, const char *id) -{ - struct clk *p, *clk = ERR_PTR(-ENOENT); - int dev_match; - int id_match; - - if (dev == NULL || id == NULL) - return clk; - - mutex_lock(&clocks_mutex); - list_for_each_entry(p, &clocks, node) { - dev_match = id_match = 0; - - if (dev == p->dev) - dev_match++; - if (strcmp(id, p->name) == 0) - id_match++; - if ((dev_match || id_match) && try_module_get(p->owner)) { - clk = p; - break; - } - } - mutex_unlock(&clocks_mutex); - - return clk; -} - -#ifdef CLK_DEBUG -static void dump_clocks(void) -{ - struct clk *p; - - mutex_lock(&clocks_mutex); - printk(KERN_INFO "CLOCKS:\n"); - list_for_each_entry(p, &clocks, node) { - pr_info(" %s=%ld", p->name, p->rate); - if (p->parent) - pr_cont(" %s=%ld", p->parent->name, - p->parent->rate); - if (p->flags & CLK_HAS_CTRL) - pr_cont(" reg/bit=%d/%d", p->reg, p->bit); - pr_cont("\n"); - } - mutex_unlock(&clocks_mutex); -} -#define DEBUG_CLK_DUMP() dump_clocks() -#else -#define DEBUG_CLK_DUMP() -#endif - - -static void mpc5121_clk_put(struct clk *clk) -{ - module_put(clk->owner); -} - -#define NRPSC 12 - -struct mpc512x_clockctl { - u32 spmr; /* System PLL Mode Reg */ - u32 sccr[2]; /* System Clk Ctrl Reg 1 & 2 */ - u32 scfr1; /* System Clk Freq Reg 1 */ - u32 scfr2; /* System Clk Freq Reg 2 */ - u32 reserved; - u32 bcr; /* Bread Crumb Reg */ - u32 pccr[NRPSC]; /* PSC Clk Ctrl Reg 0-11 */ - u32 spccr; /* SPDIF Clk Ctrl Reg */ - u32 cccr; /* CFM Clk Ctrl Reg */ - u32 dccr; /* DIU Clk Cnfg Reg */ -}; - -static struct mpc512x_clockctl __iomem *clockctl; - -static int mpc5121_clk_enable(struct clk *clk) -{ - unsigned int mask; - - if (clk->flags & CLK_HAS_CTRL) { - mask = in_be32(&clockctl->sccr[clk->reg]); - mask |= 1 << clk->bit; - out_be32(&clockctl->sccr[clk->reg], mask); - } - return 0; -} - -static void mpc5121_clk_disable(struct clk *clk) -{ - unsigned int mask; - - if (clk->flags & CLK_HAS_CTRL) { - mask = in_be32(&clockctl->sccr[clk->reg]); - mask &= ~(1 << clk->bit); - out_be32(&clockctl->sccr[clk->reg], mask); - } -} - -static unsigned long mpc5121_clk_get_rate(struct clk *clk) -{ - if (clk->flags & CLK_HAS_RATE) - return clk->rate; - else - return 0; -} - -static long mpc5121_clk_round_rate(struct clk *clk, unsigned long rate) -{ - return rate; -} - -static int mpc5121_clk_set_rate(struct clk *clk, unsigned long rate) -{ - return 0; -} - -static int clk_register(struct clk *clk) -{ - mutex_lock(&clocks_mutex); - list_add(&clk->node, &clocks); - mutex_unlock(&clocks_mutex); - return 0; -} - -static unsigned long spmf_mult(void) -{ - /* - * Convert spmf to multiplier - */ - static int spmf_to_mult[] = { - 68, 1, 12, 16, - 20, 24, 28, 32, - 36, 40, 44, 48, - 52, 56, 60, 64 - }; - int spmf = (in_be32(&clockctl->spmr) >> 24) & 0xf; - return spmf_to_mult[spmf]; -} - -static unsigned long sysdiv_div_x_2(void) -{ - /* - * Convert sysdiv to divisor x 2 - * Some divisors have fractional parts so - * multiply by 2 then divide by this value - */ - static int sysdiv_to_div_x_2[] = { - 4, 5, 6, 7, - 8, 9, 10, 14, - 12, 16, 18, 22, - 20, 24, 26, 30, - 28, 32, 34, 38, - 36, 40, 42, 46, - 44, 48, 50, 54, - 52, 56, 58, 62, - 60, 64, 66, - }; - int sysdiv = (in_be32(&clockctl->scfr2) >> 26) & 0x3f; - return sysdiv_to_div_x_2[sysdiv]; -} - -static unsigned long ref_to_sys(unsigned long rate) -{ - rate *= spmf_mult(); - rate *= 2; - rate /= sysdiv_div_x_2(); - - return rate; -} - -static unsigned long sys_to_ref(unsigned long rate) -{ - rate *= sysdiv_div_x_2(); - rate /= 2; - rate /= spmf_mult(); - - return rate; -} - -static long ips_to_ref(unsigned long rate) -{ - int ips_div = (in_be32(&clockctl->scfr1) >> 23) & 0x7; - - rate *= ips_div; /* csb_clk = ips_clk * ips_div */ - rate *= 2; /* sys_clk = csb_clk * 2 */ - return sys_to_ref(rate); -} - -static unsigned long devtree_getfreq(char *clockname) -{ - struct device_node *np; - const unsigned int *prop; - unsigned int val = 0; - - np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr"); - if (np) { - prop = of_get_property(np, clockname, NULL); - if (prop) - val = *prop; - of_node_put(np); - } - return val; -} - -static void ref_clk_calc(struct clk *clk) -{ - unsigned long rate; - - rate = devtree_getfreq("bus-frequency"); - if (rate == 0) { - printk(KERN_ERR "No bus-frequency in dev tree\n"); - clk->rate = 0; - return; - } - clk->rate = ips_to_ref(rate); -} - -static struct clk ref_clk = { - .name = "ref_clk", - .calc = ref_clk_calc, -}; - - -static void sys_clk_calc(struct clk *clk) -{ - clk->rate = ref_to_sys(ref_clk.rate); -} - -static struct clk sys_clk = { - .name = "sys_clk", - .calc = sys_clk_calc, -}; - -static void diu_clk_calc(struct clk *clk) -{ - int diudiv_x_2 = in_be32(&clockctl->scfr1) & 0xff; - unsigned long rate; - - rate = sys_clk.rate; - - rate *= 2; - rate /= diudiv_x_2; - - clk->rate = rate; -} - -static void viu_clk_calc(struct clk *clk) -{ - unsigned long rate; - - rate = sys_clk.rate; - rate /= 2; - clk->rate = rate; -} - -static void half_clk_calc(struct clk *clk) -{ - clk->rate = clk->parent->rate / 2; -} - -static void generic_div_clk_calc(struct clk *clk) -{ - int div = (in_be32(&clockctl->scfr1) >> clk->div_shift) & 0x7; - - clk->rate = clk->parent->rate / div; -} - -static void unity_clk_calc(struct clk *clk) -{ - clk->rate = clk->parent->rate; -} - -static struct clk csb_clk = { - .name = "csb_clk", - .calc = half_clk_calc, - .parent = &sys_clk, -}; - -static void e300_clk_calc(struct clk *clk) -{ - int spmf = (in_be32(&clockctl->spmr) >> 16) & 0xf; - int ratex2 = clk->parent->rate * spmf; - - clk->rate = ratex2 / 2; -} - -static struct clk e300_clk = { - .name = "e300_clk", - .calc = e300_clk_calc, - .parent = &csb_clk, -}; - -static struct clk ips_clk = { - .name = "ips_clk", - .calc = generic_div_clk_calc, - .parent = &csb_clk, - .div_shift = 23, -}; - -/* - * Clocks controlled by SCCR1 (.reg = 0) - */ -static struct clk lpc_clk = { - .name = "lpc_clk", - .flags = CLK_HAS_CTRL, - .reg = 0, - .bit = 30, - .calc = generic_div_clk_calc, - .parent = &ips_clk, - .div_shift = 11, -}; - -static struct clk nfc_clk = { - .name = "nfc_clk", - .flags = CLK_HAS_CTRL, - .reg = 0, - .bit = 29, - .calc = generic_div_clk_calc, - .parent = &ips_clk, - .div_shift = 8, -}; - -static struct clk pata_clk = { - .name = "pata_clk", - .flags = CLK_HAS_CTRL, - .reg = 0, - .bit = 28, - .calc = unity_clk_calc, - .parent = &ips_clk, -}; - -/* - * PSC clocks (bits 27 - 16) - * are setup elsewhere - */ - -static struct clk sata_clk = { - .name = "sata_clk", - .flags = CLK_HAS_CTRL, - .reg = 0, - .bit = 14, - .calc = unity_clk_calc, - .parent = &ips_clk, -}; - -static struct clk fec_clk = { - .name = "fec_clk", - .flags = CLK_HAS_CTRL, - .reg = 0, - .bit = 13, - .calc = unity_clk_calc, - .parent = &ips_clk, -}; - -static struct clk pci_clk = { - .name = "pci_clk", - .flags = CLK_HAS_CTRL, - .reg = 0, - .bit = 11, - .calc = generic_div_clk_calc, - .parent = &csb_clk, - .div_shift = 20, -}; - -/* - * Clocks controlled by SCCR2 (.reg = 1) - */ -static struct clk diu_clk = { - .name = "diu_clk", - .flags = CLK_HAS_CTRL, - .reg = 1, - .bit = 31, - .calc = diu_clk_calc, -}; - -static struct clk viu_clk = { - .name = "viu_clk", - .flags = CLK_HAS_CTRL, - .reg = 1, - .bit = 18, - .calc = viu_clk_calc, -}; - -static struct clk axe_clk = { - .name = "axe_clk", - .flags = CLK_HAS_CTRL, - .reg = 1, - .bit = 30, - .calc = unity_clk_calc, - .parent = &csb_clk, -}; - -static struct clk usb1_clk = { - .name = "usb1_clk", - .flags = CLK_HAS_CTRL, - .reg = 1, - .bit = 28, - .calc = unity_clk_calc, - .parent = &csb_clk, -}; - -static struct clk usb2_clk = { - .name = "usb2_clk", - .flags = CLK_HAS_CTRL, - .reg = 1, - .bit = 27, - .calc = unity_clk_calc, - .parent = &csb_clk, -}; - -static struct clk i2c_clk = { - .name = "i2c_clk", - .flags = CLK_HAS_CTRL, - .reg = 1, - .bit = 26, - .calc = unity_clk_calc, - .parent = &ips_clk, -}; - -static struct clk mscan_clk = { - .name = "mscan_clk", - .flags = CLK_HAS_CTRL, - .reg = 1, - .bit = 25, - .calc = unity_clk_calc, - .parent = &ips_clk, -}; - -static struct clk sdhc_clk = { - .name = "sdhc_clk", - .flags = CLK_HAS_CTRL, - .reg = 1, - .bit = 24, - .calc = unity_clk_calc, - .parent = &ips_clk, -}; - -static struct clk mbx_bus_clk = { - .name = "mbx_bus_clk", - .flags = CLK_HAS_CTRL, - .reg = 1, - .bit = 22, - .calc = half_clk_calc, - .parent = &csb_clk, -}; - -static struct clk mbx_clk = { - .name = "mbx_clk", - .flags = CLK_HAS_CTRL, - .reg = 1, - .bit = 21, - .calc = unity_clk_calc, - .parent = &csb_clk, -}; - -static struct clk mbx_3d_clk = { - .name = "mbx_3d_clk", - .flags = CLK_HAS_CTRL, - .reg = 1, - .bit = 20, - .calc = generic_div_clk_calc, - .parent = &mbx_bus_clk, - .div_shift = 14, -}; - -static void psc_mclk_in_calc(struct clk *clk) -{ - clk->rate = devtree_getfreq("psc_mclk_in"); - if (!clk->rate) - clk->rate = 25000000; -} - -static struct clk psc_mclk_in = { - .name = "psc_mclk_in", - .calc = psc_mclk_in_calc, -}; - -static struct clk spdif_txclk = { - .name = "spdif_txclk", - .flags = CLK_HAS_CTRL, - .reg = 1, - .bit = 23, -}; - -static struct clk spdif_rxclk = { - .name = "spdif_rxclk", - .flags = CLK_HAS_CTRL, - .reg = 1, - .bit = 23, -}; - -static void ac97_clk_calc(struct clk *clk) -{ - /* ac97 bit clock is always 24.567 MHz */ - clk->rate = 24567000; -} - -static struct clk ac97_clk = { - .name = "ac97_clk_in", - .calc = ac97_clk_calc, -}; - -static struct clk *rate_clks[] = { - &ref_clk, - &sys_clk, - &diu_clk, - &viu_clk, - &csb_clk, - &e300_clk, - &ips_clk, - &fec_clk, - &sata_clk, - &pata_clk, - &nfc_clk, - &lpc_clk, - &mbx_bus_clk, - &mbx_clk, - &mbx_3d_clk, - &axe_clk, - &usb1_clk, - &usb2_clk, - &i2c_clk, - &mscan_clk, - &sdhc_clk, - &pci_clk, - &psc_mclk_in, - &spdif_txclk, - &spdif_rxclk, - &ac97_clk, - NULL -}; - -static void rate_clk_init(struct clk *clk) -{ - if (clk->calc) { - clk->calc(clk); - clk->flags |= CLK_HAS_RATE; - clk_register(clk); - } else { - printk(KERN_WARNING - "Could not initialize clk %s without a calc routine\n", - clk->name); - } -} - -static void rate_clks_init(void) -{ - struct clk **cpp, *clk; - - cpp = rate_clks; - while ((clk = *cpp++)) - rate_clk_init(clk); -} - -/* - * There are two clk enable registers with 32 enable bits each - * psc clocks and device clocks are all stored in dev_clks - */ -static struct clk dev_clks[2][32]; - -/* - * Given a psc number return the dev_clk - * associated with it - */ -static struct clk *psc_dev_clk(int pscnum) -{ - int reg, bit; - struct clk *clk; - - reg = 0; - bit = 27 - pscnum; - - clk = &dev_clks[reg][bit]; - clk->reg = 0; - clk->bit = bit; - return clk; -} - -/* - * PSC clock rate calculation - */ -static void psc_calc_rate(struct clk *clk, int pscnum, struct device_node *np) -{ - unsigned long mclk_src = sys_clk.rate; - unsigned long mclk_div; - - /* - * Can only change value of mclk divider - * when the divider is disabled. - * - * Zero is not a valid divider so minimum - * divider is 1 - * - * disable/set divider/enable - */ - out_be32(&clockctl->pccr[pscnum], 0); - out_be32(&clockctl->pccr[pscnum], 0x00020000); - out_be32(&clockctl->pccr[pscnum], 0x00030000); - - if (in_be32(&clockctl->pccr[pscnum]) & 0x80) { - clk->rate = spdif_rxclk.rate; - return; - } - - switch ((in_be32(&clockctl->pccr[pscnum]) >> 14) & 0x3) { - case 0: - mclk_src = sys_clk.rate; - break; - case 1: - mclk_src = ref_clk.rate; - break; - case 2: - mclk_src = psc_mclk_in.rate; - break; - case 3: - mclk_src = spdif_txclk.rate; - break; - } - - mclk_div = ((in_be32(&clockctl->pccr[pscnum]) >> 17) & 0x7fff) + 1; - clk->rate = mclk_src / mclk_div; -} - -/* - * Find all psc nodes in device tree and assign a clock - * with name "psc%d_mclk" and dev pointing at the device - * returned from of_find_device_by_node - */ -static void psc_clks_init(void) -{ - struct device_node *np; - struct platform_device *ofdev; - u32 reg; - const char *psc_compat; - - psc_compat = mpc512x_select_psc_compat(); - if (!psc_compat) - return; - - for_each_compatible_node(np, NULL, psc_compat) { - if (!of_property_read_u32(np, "reg", ®)) { - int pscnum = (reg & 0xf00) >> 8; - struct clk *clk = psc_dev_clk(pscnum); - - clk->flags = CLK_HAS_RATE | CLK_HAS_CTRL; - ofdev = of_find_device_by_node(np); - clk->dev = &ofdev->dev; - /* - * AC97 is special rate clock does - * not go through normal path - */ - if (of_device_is_compatible(np, "fsl,mpc5121-psc-ac97")) - clk->rate = ac97_clk.rate; - else - psc_calc_rate(clk, pscnum, np); - sprintf(clk->name, "psc%d_mclk", pscnum); - clk_register(clk); - clk_enable(clk); - } - } -} - -static struct clk_interface mpc5121_clk_functions = { - .clk_get = mpc5121_clk_get, - .clk_enable = mpc5121_clk_enable, - .clk_disable = mpc5121_clk_disable, - .clk_get_rate = mpc5121_clk_get_rate, - .clk_put = mpc5121_clk_put, - .clk_round_rate = mpc5121_clk_round_rate, - .clk_set_rate = mpc5121_clk_set_rate, - .clk_set_parent = NULL, - .clk_get_parent = NULL, -}; - -int __init mpc5121_clk_init(void) -{ - struct device_node *np; - - np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock"); - if (np) { - clockctl = of_iomap(np, 0); - of_node_put(np); - } - - if (!clockctl) { - printk(KERN_ERR "Could not map clock control registers\n"); - return 0; - } - - rate_clks_init(); - psc_clks_init(); - - /* leave clockctl mapped forever */ - /*iounmap(clockctl); */ - DEBUG_CLK_DUMP(); - clocks_initialized++; - clk_functions = mpc5121_clk_functions; - return 0; -} diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c index 36b5652aada200..adb95f03d4d4b2 100644 --- a/arch/powerpc/platforms/512x/mpc512x_shared.c +++ b/arch/powerpc/platforms/512x/mpc512x_shared.c @@ -12,6 +12,7 @@ * (at your option) any later version. */ +#include #include #include #include @@ -68,98 +69,112 @@ struct fsl_diu_shared_fb { bool in_use; }; -#define DIU_DIV_MASK 0x000000ff +/* receives a pixel clock spec in pico seconds, adjusts the DIU clock rate */ static void mpc512x_set_pixel_clock(unsigned int pixclock) { - unsigned long bestval, bestfreq, speed, busfreq; - unsigned long minpixclock, maxpixclock, pixval; - struct mpc512x_ccm __iomem *ccm; struct device_node *np; - u32 temp; - long err; - int i; + struct clk *clk_diu; + unsigned long epsilon, minpixclock, maxpixclock; + unsigned long offset, want, got, delta; - np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock"); + /* lookup and enable the DIU clock */ + np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu"); if (!np) { - pr_err("Can't find clock control module.\n"); + pr_err("Could not find DIU device tree node.\n"); return; } - - ccm = of_iomap(np, 0); + clk_diu = of_clk_get(np, 0); + if (IS_ERR(clk_diu)) { + /* backwards compat with device trees that lack clock specs */ + clk_diu = clk_get_sys(np->name, "ipg"); + } of_node_put(np); - if (!ccm) { - pr_err("Can't map clock control module reg.\n"); + if (IS_ERR(clk_diu)) { + pr_err("Could not lookup DIU clock.\n"); return; } - - np = of_find_node_by_type(NULL, "cpu"); - if (np) { - const unsigned int *prop = - of_get_property(np, "bus-frequency", NULL); - - of_node_put(np); - if (prop) { - busfreq = *prop; - } else { - pr_err("Can't get bus-frequency property\n"); - return; - } - } else { - pr_err("Can't find 'cpu' node.\n"); + if (clk_prepare_enable(clk_diu)) { + pr_err("Could not enable DIU clock.\n"); return; } - /* Pixel Clock configuration */ - pr_debug("DIU: Bus Frequency = %lu\n", busfreq); - speed = busfreq * 4; /* DIU_DIV ratio is 4 * CSB_CLK / DIU_CLK */ - - /* Calculate the pixel clock with the smallest error */ - /* calculate the following in steps to avoid overflow */ - pr_debug("DIU pixclock in ps - %d\n", pixclock); - temp = (1000000000 / pixclock) * 1000; - pixclock = temp; - pr_debug("DIU pixclock freq - %u\n", pixclock); - - temp = temp / 20; /* pixclock * 0.05 */ - pr_debug("deviation = %d\n", temp); - minpixclock = pixclock - temp; - maxpixclock = pixclock + temp; - pr_debug("DIU minpixclock - %lu\n", minpixclock); - pr_debug("DIU maxpixclock - %lu\n", maxpixclock); - pixval = speed/pixclock; - pr_debug("DIU pixval = %lu\n", pixval); - - err = LONG_MAX; - bestval = pixval; - pr_debug("DIU bestval = %lu\n", bestval); - - bestfreq = 0; - for (i = -1; i <= 1; i++) { - temp = speed / (pixval+i); - pr_debug("DIU test pixval i=%d, pixval=%lu, temp freq. = %u\n", - i, pixval, temp); - if ((temp < minpixclock) || (temp > maxpixclock)) - pr_debug("DIU exceeds monitor range (%lu to %lu)\n", - minpixclock, maxpixclock); - else if (abs(temp - pixclock) < err) { - pr_debug("Entered the else if block %d\n", i); - err = abs(temp - pixclock); - bestval = pixval + i; - bestfreq = temp; - } + /* + * convert the picoseconds spec into the desired clock rate, + * determine the acceptable clock range for the monitor (+/- 5%), + * do the calculation in steps to avoid integer overflow + */ + pr_debug("DIU pixclock in ps - %u\n", pixclock); + pixclock = (1000000000 / pixclock) * 1000; + pr_debug("DIU pixclock freq - %u\n", pixclock); + epsilon = pixclock / 20; /* pixclock * 0.05 */ + pr_debug("DIU deviation - %lu\n", epsilon); + minpixclock = pixclock - epsilon; + maxpixclock = pixclock + epsilon; + pr_debug("DIU minpixclock - %lu\n", minpixclock); + pr_debug("DIU maxpixclock - %lu\n", maxpixclock); + + /* + * check whether the DIU supports the desired pixel clock + * + * - simply request the desired clock and see what the + * platform's clock driver will make of it, assuming that it + * will setup the best approximation of the requested value + * - try other candidate frequencies in the order of decreasing + * preference (i.e. with increasing distance from the desired + * pixel clock, and checking the lower frequency before the + * higher frequency to not overload the hardware) until the + * first match is found -- any potential subsequent match + * would only be as good as the former match or typically + * would be less preferrable + * + * the offset increment of pixelclock divided by 64 is an + * arbitrary choice -- it's simple to calculate, in the typical + * case we expect the first check to succeed already, in the + * worst case seven frequencies get tested (the exact center and + * three more values each to the left and to the right) before + * the 5% tolerance window is exceeded, resulting in fast enough + * execution yet high enough probability of finding a suitable + * value, while the error rate will be in the order of single + * percents + */ + for (offset = 0; offset <= epsilon; offset += pixclock / 64) { + want = pixclock - offset; + pr_debug("DIU checking clock - %lu\n", want); + clk_set_rate(clk_diu, want); + got = clk_get_rate(clk_diu); + delta = abs(pixclock - got); + if (delta < epsilon) + break; + if (!offset) + continue; + want = pixclock + offset; + pr_debug("DIU checking clock - %lu\n", want); + clk_set_rate(clk_diu, want); + got = clk_get_rate(clk_diu); + delta = abs(pixclock - got); + if (delta < epsilon) + break; } + if (offset <= epsilon) { + pr_debug("DIU clock accepted - %lu\n", want); + pr_debug("DIU pixclock want %u, got %lu, delta %lu, eps %lu\n", + pixclock, got, delta, epsilon); + return; + } + pr_warn("DIU pixclock auto search unsuccessful\n"); - pr_debug("DIU chose = %lx\n", bestval); - pr_debug("DIU error = %ld\n NomPixClk ", err); - pr_debug("DIU: Best Freq = %lx\n", bestfreq); - /* Modify DIU_DIV in CCM SCFR1 */ - temp = in_be32(&ccm->scfr1); - pr_debug("DIU: Current value of SCFR1: 0x%08x\n", temp); - temp &= ~DIU_DIV_MASK; - temp |= (bestval & DIU_DIV_MASK); - out_be32(&ccm->scfr1, temp); - pr_debug("DIU: Modified value of SCFR1: 0x%08x\n", temp); - iounmap(ccm); + /* + * what is the most appropriate action to take when the search + * for an available pixel clock which is acceptable to the + * monitor has failed? disable the DIU (clock) or just provide + * a "best effort"? we go with the latter + */ + pr_warn("DIU pixclock best effort fallback (backend's choice)\n"); + clk_set_rate(clk_diu, pixclock); + got = clk_get_rate(clk_diu); + delta = abs(pixclock - got); + pr_debug("DIU pixclock want %u, got %lu, delta %lu, eps %lu\n", + pixclock, got, delta, epsilon); } static enum fsl_diu_monitor_port diff --git a/arch/powerpc/platforms/52xx/Kconfig b/arch/powerpc/platforms/52xx/Kconfig index af54174801f7aa..b625a2c6f4f27b 100644 --- a/arch/powerpc/platforms/52xx/Kconfig +++ b/arch/powerpc/platforms/52xx/Kconfig @@ -1,7 +1,7 @@ config PPC_MPC52xx bool "52xx-based boards" depends on 6xx - select PPC_CLOCK + select COMMON_CLK select PPC_PCI_CHOICE config PPC_MPC5200_SIMPLE diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig index 670a033264c0f1..2bdc8c862c46c1 100644 --- a/arch/powerpc/platforms/83xx/Kconfig +++ b/arch/powerpc/platforms/83xx/Kconfig @@ -99,7 +99,6 @@ config SBC834x config ASP834x bool "Analogue & Micro ASP 834x" select PPC_MPC834x - select REDBOOT help This enables support for the Analogue & Micro ASP 83xx board. diff --git a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c index fd71cfdf23802e..e238b6a55b1593 100644 --- a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c +++ b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c @@ -11,7 +11,6 @@ * (at your option) any later version. */ -#include #include #include #include diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c index 3d9716ccd3274b..4b4c081df94db1 100644 --- a/arch/powerpc/platforms/83xx/suspend.c +++ b/arch/powerpc/platforms/83xx/suspend.c @@ -10,7 +10,6 @@ * by the Free Software Foundation. */ -#include #include #include #include diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index 4d4634958cfb09..c17aae80e7ffd7 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -123,6 +123,12 @@ config P1023_RDS help This option enables support for the P1023 RDS and RDB boards +config TWR_P102x + bool "Freescale TWR-P102x" + select DEFAULT_UIMAGE + help + This option enables support for the TWR-P1025 board. + config SOCRATES bool "Socrates" select DEFAULT_UIMAGE diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index dd4c0b59577bb9..25cebe74ac4633 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_P1010_RDB) += p1010rdb.o obj-$(CONFIG_P1022_DS) += p1022_ds.o obj-$(CONFIG_P1022_RDK) += p1022_rdk.o obj-$(CONFIG_P1023_RDS) += p1023_rds.o +obj-$(CONFIG_TWR_P102x) += twr_p102x.o obj-$(CONFIG_CORENET_GENERIC) += corenet_generic.o obj-$(CONFIG_STX_GP3) += stx_gp3.o obj-$(CONFIG_TQM85xx) += tqm85xx.o diff --git a/arch/powerpc/platforms/85xx/common.c b/arch/powerpc/platforms/85xx/common.c index eba78c85303f9f..3b085c7ee539bc 100644 --- a/arch/powerpc/platforms/85xx/common.c +++ b/arch/powerpc/platforms/85xx/common.c @@ -9,6 +9,7 @@ #include #include +#include #include #include "mpc85xx.h" @@ -82,3 +83,40 @@ void __init mpc85xx_cpm2_pic_init(void) irq_set_chained_handler(irq, cpm2_cascade); } #endif + +#ifdef CONFIG_QUICC_ENGINE +void __init mpc85xx_qe_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,qe"); + if (!np) { + np = of_find_node_by_name(NULL, "qe"); + if (!np) { + pr_err("%s: Could not find Quicc Engine node\n", + __func__); + return; + } + } + + if (!of_device_is_available(np)) { + of_node_put(np); + return; + } + + qe_reset(); + of_node_put(np); + + np = of_find_node_by_name(NULL, "par_io"); + if (np) { + struct device_node *ucc; + + par_io_init(np); + of_node_put(np); + + for_each_node_by_name(ucc, "ucc") + par_io_of_config(ucc); + + } +} +#endif diff --git a/arch/powerpc/platforms/85xx/mpc85xx.h b/arch/powerpc/platforms/85xx/mpc85xx.h index 2aa7c5dc2c7f6d..fc51dd4092e5d1 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx.h +++ b/arch/powerpc/platforms/85xx/mpc85xx.h @@ -8,4 +8,10 @@ extern void mpc85xx_cpm2_pic_init(void); static inline void __init mpc85xx_cpm2_pic_init(void) {} #endif /* CONFIG_CPM2 */ +#ifdef CONFIG_QUICC_ENGINE +extern void mpc85xx_qe_init(void); +#else +static inline void __init mpc85xx_qe_init(void) {} +#endif + #endif diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index a7b3621a8df5dc..34f3c5eb3bee77 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2010, 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2006-2010, 2012-2013 Freescale Semiconductor, Inc. * All rights reserved. * * Author: Andy Fleming @@ -238,32 +238,7 @@ static void __init mpc85xx_mds_qe_init(void) { struct device_node *np; - np = of_find_compatible_node(NULL, NULL, "fsl,qe"); - if (!np) { - np = of_find_node_by_name(NULL, "qe"); - if (!np) - return; - } - - if (!of_device_is_available(np)) { - of_node_put(np); - return; - } - - qe_reset(); - of_node_put(np); - - np = of_find_node_by_name(NULL, "par_io"); - if (np) { - struct device_node *ucc; - - par_io_init(np); - of_node_put(np); - - for_each_node_by_name(ucc, "ucc") - par_io_of_config(ucc); - } - + mpc85xx_qe_init(); mpc85xx_mds_reset_ucc_phys(); if (machine_is(p1021_mds)) { diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c index 53b6fb0a3d560a..e15bdd18fdb2f2 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c @@ -1,7 +1,7 @@ /* * MPC85xx RDB Board Setup * - * Copyright 2009,2012 Freescale Semiconductor Inc. + * Copyright 2009,2012-2013 Freescale Semiconductor Inc. * * 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 @@ -98,26 +98,7 @@ static void __init mpc85xx_rdb_setup_arch(void) fsl_pci_assign_primary(); #ifdef CONFIG_QUICC_ENGINE - np = of_find_compatible_node(NULL, NULL, "fsl,qe"); - if (!np) { - pr_err("%s: Could not find Quicc Engine node\n", __func__); - goto qe_fail; - } - - qe_reset(); - of_node_put(np); - - np = of_find_node_by_name(NULL, "par_io"); - if (np) { - struct device_node *ucc; - - par_io_init(np); - of_node_put(np); - - for_each_node_by_name(ucc, "ucc") - par_io_of_config(ucc); - - } + mpc85xx_qe_init(); #if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE) if (machine_is(p1025_rdb)) { @@ -148,8 +129,6 @@ static void __init mpc85xx_rdb_setup_arch(void) } #endif - -qe_fail: #endif /* CONFIG_QUICC_ENGINE */ printk(KERN_INFO "MPC85xx RDB board from Freescale Semiconductor\n"); diff --git a/arch/powerpc/platforms/85xx/sgy_cts1000.c b/arch/powerpc/platforms/85xx/sgy_cts1000.c index b9197cea1854da..bb75add670844e 100644 --- a/arch/powerpc/platforms/85xx/sgy_cts1000.c +++ b/arch/powerpc/platforms/85xx/sgy_cts1000.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 393f975ab397c1..6382098d6f8d88 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -389,15 +389,18 @@ static void mpc85xx_smp_machine_kexec(struct kimage *image) } #endif /* CONFIG_KEXEC */ -static void smp_85xx_setup_cpu(int cpu_nr) +static void smp_85xx_basic_setup(int cpu_nr) { - if (smp_85xx_ops.probe == smp_mpic_probe) - mpic_setup_this_cpu(); - if (cpu_has_feature(CPU_FTR_DBELL)) doorbell_setup_this_cpu(); } +static void smp_85xx_setup_cpu(int cpu_nr) +{ + mpic_setup_this_cpu(); + smp_85xx_basic_setup(cpu_nr); +} + static const struct of_device_id mpc85xx_smp_guts_ids[] = { { .compatible = "fsl,mpc8572-guts", }, { .compatible = "fsl,p1020-guts", }, @@ -412,13 +415,14 @@ void __init mpc85xx_smp_init(void) { struct device_node *np; - smp_85xx_ops.setup_cpu = smp_85xx_setup_cpu; np = of_find_node_by_type(NULL, "open-pic"); if (np) { smp_85xx_ops.probe = smp_mpic_probe; + smp_85xx_ops.setup_cpu = smp_85xx_setup_cpu; smp_85xx_ops.message_pass = smp_mpic_message_pass; - } + } else + smp_85xx_ops.setup_cpu = smp_85xx_basic_setup; if (cpu_has_feature(CPU_FTR_DBELL)) { /* @@ -427,6 +431,7 @@ void __init mpc85xx_smp_init(void) */ smp_85xx_ops.message_pass = NULL; smp_85xx_ops.cause_ipi = doorbell_cause_ipi; + smp_85xx_ops.probe = NULL; } np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids); diff --git a/arch/powerpc/platforms/85xx/twr_p102x.c b/arch/powerpc/platforms/85xx/twr_p102x.c new file mode 100644 index 00000000000000..c25ff10f05ee14 --- /dev/null +++ b/arch/powerpc/platforms/85xx/twr_p102x.c @@ -0,0 +1,147 @@ +/* + * Copyright 2010-2011, 2013 Freescale Semiconductor, Inc. + * + * Author: Michael Johnston + * + * Description: + * TWR-P102x Board Setup + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include "smp.h" + +#include "mpc85xx.h" + +static void __init twr_p1025_pic_init(void) +{ + struct mpic *mpic; + +#ifdef CONFIG_QUICC_ENGINE + struct device_node *np; +#endif + + mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | + MPIC_SINGLE_DEST_CPU, + 0, 256, " OpenPIC "); + + BUG_ON(mpic == NULL); + mpic_init(mpic); + +#ifdef CONFIG_QUICC_ENGINE + np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); + if (np) { + qe_ic_init(np, 0, qe_ic_cascade_low_mpic, + qe_ic_cascade_high_mpic); + of_node_put(np); + } else + pr_err("Could not find qe-ic node\n"); +#endif +} + +/* ************************************************************************ + * + * Setup the architecture + * + */ +static void __init twr_p1025_setup_arch(void) +{ +#ifdef CONFIG_QUICC_ENGINE + struct device_node *np; +#endif + + if (ppc_md.progress) + ppc_md.progress("twr_p1025_setup_arch()", 0); + + mpc85xx_smp_init(); + + fsl_pci_assign_primary(); + +#ifdef CONFIG_QUICC_ENGINE + mpc85xx_qe_init(); + +#if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE) + if (machine_is(twr_p1025)) { + struct ccsr_guts __iomem *guts; + + np = of_find_compatible_node(NULL, NULL, "fsl,p1021-guts"); + if (np) { + guts = of_iomap(np, 0); + if (!guts) + pr_err("twr_p1025: could not map global utilities register\n"); + else { + /* P1025 has pins muxed for QE and other functions. To + * enable QE UEC mode, we need to set bit QE0 for UCC1 + * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9 + * and QE12 for QE MII management signals in PMUXCR + * register. + * Set QE mux bits in PMUXCR */ + setbits32(&guts->pmuxcr, MPC85xx_PMUXCR_QE(0) | + MPC85xx_PMUXCR_QE(3) | + MPC85xx_PMUXCR_QE(9) | + MPC85xx_PMUXCR_QE(12)); + iounmap(guts); + +#if defined(CONFIG_SERIAL_QE) + /* On P1025TWR board, the UCC7 acted as UART port. + * However, The UCC7's CTS pin is low level in default, + * it will impact the transmission in full duplex + * communication. So disable the Flow control pin PA18. + * The UCC7 UART just can use RXD and TXD pins. + */ + par_io_config_pin(0, 18, 0, 0, 0, 0); +#endif + /* Drive PB29 to CPLD low - CPLD will then change + * muxing from LBC to QE */ + par_io_config_pin(1, 29, 1, 0, 0, 0); + par_io_data_set(1, 29, 0); + } + of_node_put(np); + } + } +#endif +#endif /* CONFIG_QUICC_ENGINE */ + + pr_info("TWR-P1025 board from Freescale Semiconductor\n"); +} + +machine_arch_initcall(twr_p1025, mpc85xx_common_publish_devices); + +static int __init twr_p1025_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "fsl,TWR-P1025"); +} + +define_machine(twr_p1025) { + .name = "TWR-P1025", + .probe = twr_p1025_probe, + .setup_arch = twr_p1025_setup_arch, + .init_IRQ = twr_p1025_pic_init, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index 8dec3c0911ad0f..bd6f1a1cf922bc 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig @@ -45,7 +45,6 @@ config PPC_EP88XC config PPC_ADDER875 bool "Analogue & Micro Adder 875" select CPM1 - select REDBOOT help This enables support for the Analogue & Micro Adder 875 board. diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index bca2465a9c347a..434fda39bf8b51 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -72,6 +72,7 @@ config PPC_BOOK3S_64 select PPC_HAVE_PMU_SUPPORT select SYS_SUPPORTS_HUGETLBFS select HAVE_ARCH_TRANSPARENT_HUGEPAGE if PPC_64K_PAGES + select ARCH_SUPPORTS_NUMA_BALANCING config PPC_BOOK3E_64 bool "Embedded processors" diff --git a/arch/powerpc/platforms/cell/beat_htab.c b/arch/powerpc/platforms/cell/beat_htab.c index c34ee4e608734f..d4d245c0d78799 100644 --- a/arch/powerpc/platforms/cell/beat_htab.c +++ b/arch/powerpc/platforms/cell/beat_htab.c @@ -111,7 +111,7 @@ static long beat_lpar_hpte_insert(unsigned long hpte_group, DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r); if (rflags & _PAGE_NO_CACHE) - hpte_r &= ~_PAGE_COHERENT; + hpte_r &= ~HPTE_R_M; raw_spin_lock(&beat_htab_lock); lpar_rc = beat_read_mask(hpte_group); @@ -337,7 +337,7 @@ static long beat_lpar_hpte_insert_v3(unsigned long hpte_group, DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r); if (rflags & _PAGE_NO_CACHE) - hpte_r &= ~_PAGE_COHERENT; + hpte_r &= ~HPTE_R_M; /* insert into not-volted entry */ lpar_rc = beat_insert_htab_entry3(0, hpte_group, hpte_v, hpte_r, diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index b53560660b72e7..2b90ff8a93bea7 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -197,7 +197,7 @@ static int tce_build_cell(struct iommu_table *tbl, long index, long npages, io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset); - for (i = 0; i < npages; i++, uaddr += IOMMU_PAGE_SIZE) + for (i = 0; i < npages; i++, uaddr += tbl->it_page_shift) io_pte[i] = base_pte | (__pa(uaddr) & CBE_IOPTE_RPN_Mask); mb(); @@ -430,7 +430,7 @@ static void cell_iommu_setup_hardware(struct cbe_iommu *iommu, { cell_iommu_setup_stab(iommu, base, size, 0, 0); iommu->ptab = cell_iommu_alloc_ptab(iommu, base, size, 0, 0, - IOMMU_PAGE_SHIFT); + IOMMU_PAGE_SHIFT_4K); cell_iommu_enable_hardware(iommu); } @@ -487,8 +487,10 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np, window->table.it_blocksize = 16; window->table.it_base = (unsigned long)iommu->ptab; window->table.it_index = iommu->nid; - window->table.it_offset = (offset >> IOMMU_PAGE_SHIFT) + pte_offset; - window->table.it_size = size >> IOMMU_PAGE_SHIFT; + window->table.it_page_shift = IOMMU_PAGE_SHIFT_4K; + window->table.it_offset = + (offset >> window->table.it_page_shift) + pte_offset; + window->table.it_size = size >> window->table.it_page_shift; iommu_init_table(&window->table, iommu->nid); @@ -773,7 +775,7 @@ static void __init cell_iommu_init_one(struct device_node *np, /* Setup the iommu_table */ cell_iommu_setup_window(iommu, np, base, size, - offset >> IOMMU_PAGE_SHIFT); + offset >> IOMMU_PAGE_SHIFT_4K); } static void __init cell_disable_iommus(void) @@ -1122,7 +1124,7 @@ static int __init cell_iommu_fixed_mapping_init(void) cell_iommu_setup_stab(iommu, dbase, dsize, fbase, fsize); iommu->ptab = cell_iommu_alloc_ptab(iommu, dbase, dsize, 0, 0, - IOMMU_PAGE_SHIFT); + IOMMU_PAGE_SHIFT_4K); cell_iommu_setup_fixed_ptab(iommu, np, dbase, dsize, fbase, fsize); cell_iommu_enable_hardware(iommu); diff --git a/arch/powerpc/platforms/chrp/smp.c b/arch/powerpc/platforms/chrp/smp.c index dead91b177b9df..b6c9a0dcc92485 100644 --- a/arch/powerpc/platforms/chrp/smp.c +++ b/arch/powerpc/platforms/chrp/smp.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index 302ba43d73a168..6d3c7a9fd047a5 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig @@ -67,6 +67,18 @@ config PPC_C2K This option enables support for the GE Fanuc C2K board (formerly an SBS board). +config MVME5100 + bool "Motorola/Emerson MVME5100" + depends on EMBEDDED6xx + select MPIC + select PCI + select PPC_INDIRECT_PCI + select PPC_I8259 + select PPC_NATIVE + help + This option enables support for the Motorola (now Emerson) MVME5100 + board. + config TSI108_BRIDGE bool select PCI @@ -113,4 +125,3 @@ config WII help Select WII if configuring for the Nintendo Wii. More information at: - diff --git a/arch/powerpc/platforms/embedded6xx/Makefile b/arch/powerpc/platforms/embedded6xx/Makefile index 66c23e423f4078..cdd48d402b93eb 100644 --- a/arch/powerpc/platforms/embedded6xx/Makefile +++ b/arch/powerpc/platforms/embedded6xx/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_USBGECKO_UDBG) += usbgecko_udbg.o obj-$(CONFIG_GAMECUBE_COMMON) += flipper-pic.o obj-$(CONFIG_GAMECUBE) += gamecube.o obj-$(CONFIG_WII) += wii.o hlwd-pic.o +obj-$(CONFIG_MVME5100) += mvme5100.o diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index 6c03034dbbd31b..c269caee58f948 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -15,7 +15,6 @@ #define pr_fmt(fmt) DRV_MODULE_NAME ": " fmt #include -#include #include #include #include diff --git a/arch/powerpc/platforms/embedded6xx/mvme5100.c b/arch/powerpc/platforms/embedded6xx/mvme5100.c new file mode 100644 index 00000000000000..25e3bfb64efbe7 --- /dev/null +++ b/arch/powerpc/platforms/embedded6xx/mvme5100.c @@ -0,0 +1,221 @@ +/* + * Board setup routines for the Motorola/Emerson MVME5100. + * + * Copyright 2013 CSC Australia Pty. Ltd. + * + * Based on earlier code by: + * + * Matt Porter, MontaVista Software Inc. + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Author: Stephen Chivers + * + */ + +#include + +#include +#include +#include +#include +#include +#include + +#define HAWK_MPIC_SIZE 0x00040000U +#define MVME5100_PCI_MEM_OFFSET 0x00000000 + +/* Board register addresses. */ +#define BOARD_STATUS_REG 0xfef88080 +#define BOARD_MODFAIL_REG 0xfef88090 +#define BOARD_MODRST_REG 0xfef880a0 +#define BOARD_TBEN_REG 0xfef880c0 +#define BOARD_SW_READ_REG 0xfef880e0 +#define BOARD_GEO_ADDR_REG 0xfef880e8 +#define BOARD_EXT_FEATURE1_REG 0xfef880f0 +#define BOARD_EXT_FEATURE2_REG 0xfef88100 + +static phys_addr_t pci_membase; +static u_char *restart; + +static void mvme5100_8259_cascade(unsigned int irq, struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int cascade_irq = i8259_irq(); + + if (cascade_irq != NO_IRQ) + generic_handle_irq(cascade_irq); + + chip->irq_eoi(&desc->irq_data); +} + +static void __init mvme5100_pic_init(void) +{ + struct mpic *mpic; + struct device_node *np; + struct device_node *cp = NULL; + unsigned int cirq; + unsigned long intack = 0; + const u32 *prop = NULL; + + np = of_find_node_by_type(NULL, "open-pic"); + if (!np) { + pr_err("Could not find open-pic node\n"); + return; + } + + mpic = mpic_alloc(np, pci_membase, 0, 16, 256, " OpenPIC "); + + BUG_ON(mpic == NULL); + of_node_put(np); + + mpic_assign_isu(mpic, 0, pci_membase + 0x10000); + + mpic_init(mpic); + + cp = of_find_compatible_node(NULL, NULL, "chrp,iic"); + if (cp == NULL) { + pr_warn("mvme5100_pic_init: couldn't find i8259\n"); + return; + } + + cirq = irq_of_parse_and_map(cp, 0); + if (cirq == NO_IRQ) { + pr_warn("mvme5100_pic_init: no cascade interrupt?\n"); + return; + } + + np = of_find_compatible_node(NULL, "pci", "mpc10x-pci"); + if (np) { + prop = of_get_property(np, "8259-interrupt-acknowledge", NULL); + + if (prop) + intack = prop[0]; + + of_node_put(np); + } + + if (intack) + pr_debug("mvme5100_pic_init: PCI 8259 intack at 0x%016lx\n", + intack); + + i8259_init(cp, intack); + of_node_put(cp); + irq_set_chained_handler(cirq, mvme5100_8259_cascade); +} + +static int __init mvme5100_add_bridge(struct device_node *dev) +{ + const int *bus_range; + int len; + struct pci_controller *hose; + unsigned short devid; + + pr_info("Adding PCI host bridge %s\n", dev->full_name); + + bus_range = of_get_property(dev, "bus-range", &len); + + hose = pcibios_alloc_controller(dev); + if (hose == NULL) + return -ENOMEM; + + hose->first_busno = bus_range ? bus_range[0] : 0; + hose->last_busno = bus_range ? bus_range[1] : 0xff; + + setup_indirect_pci(hose, 0xfe000cf8, 0xfe000cfc, 0); + + pci_process_bridge_OF_ranges(hose, dev, 1); + + early_read_config_word(hose, 0, 0, PCI_DEVICE_ID, &devid); + + if (devid != PCI_DEVICE_ID_MOTOROLA_HAWK) { + pr_err("HAWK PHB not present?\n"); + return 0; + } + + early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase); + + if (pci_membase == 0) { + pr_err("HAWK PHB mibar not correctly set?\n"); + return 0; + } + + pr_info("mvme5100_pic_init: pci_membase: %x\n", pci_membase); + + return 0; +} + +static struct of_device_id mvme5100_of_bus_ids[] __initdata = { + { .compatible = "hawk-bridge", }, + {}, +}; + +/* + * Setup the architecture + */ +static void __init mvme5100_setup_arch(void) +{ + struct device_node *np; + + if (ppc_md.progress) + ppc_md.progress("mvme5100_setup_arch()", 0); + + for_each_compatible_node(np, "pci", "hawk-pci") + mvme5100_add_bridge(np); + + restart = ioremap(BOARD_MODRST_REG, 4); +} + + +static void mvme5100_show_cpuinfo(struct seq_file *m) +{ + seq_puts(m, "Vendor\t\t: Motorola/Emerson\n"); + seq_puts(m, "Machine\t\t: MVME5100\n"); +} + +static void mvme5100_restart(char *cmd) +{ + + local_irq_disable(); + mtmsr(mfmsr() | MSR_IP); + + out_8((u_char *) restart, 0x01); + + while (1) + ; +} + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init mvme5100_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "MVME5100"); +} + +static int __init probe_of_platform_devices(void) +{ + + of_platform_bus_probe(NULL, mvme5100_of_bus_ids, NULL); + return 0; +} + +machine_device_initcall(mvme5100, probe_of_platform_devices); + +define_machine(mvme5100) { + .name = "MVME5100", + .probe = mvme5100_probe, + .setup_arch = mvme5100_setup_arch, + .init_IRQ = mvme5100_pic_init, + .show_cpuinfo = mvme5100_show_cpuinfo, + .get_irq = mpic_get_irq, + .restart = mvme5100_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/pasemi/dma_lib.c b/arch/powerpc/platforms/pasemi/dma_lib.c index f3defd8a28069a..aafa01ba062f80 100644 --- a/arch/powerpc/platforms/pasemi/dma_lib.c +++ b/arch/powerpc/platforms/pasemi/dma_lib.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c index 7d2d036754b5b5..2e576f2ae44256 100644 --- a/arch/powerpc/platforms/pasemi/iommu.c +++ b/arch/powerpc/platforms/pasemi/iommu.c @@ -138,8 +138,11 @@ static void iommu_table_iobmap_setup(void) pr_debug(" -> %s\n", __func__); iommu_table_iobmap.it_busno = 0; iommu_table_iobmap.it_offset = 0; + iommu_table_iobmap.it_page_shift = IOBMAP_PAGE_SHIFT; + /* it_size is in number of entries */ - iommu_table_iobmap.it_size = 0x80000000 >> IOBMAP_PAGE_SHIFT; + iommu_table_iobmap.it_size = + 0x80000000 >> iommu_table_iobmap.it_page_shift; /* Initialize the common IOMMU code */ iommu_table_iobmap.it_base = (unsigned long)iob_l2_base; diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c index d588e48dff74cd..43075081721f7e 100644 --- a/arch/powerpc/platforms/powermac/pfunc_core.c +++ b/arch/powerpc/platforms/powermac/pfunc_core.c @@ -5,7 +5,6 @@ * FIXME: LOCKING !!! */ -#include #include #include #include diff --git a/arch/powerpc/platforms/powernv/Kconfig b/arch/powerpc/platforms/powernv/Kconfig index 9fced3f6d2dcfa..895e8a20a3fc06 100644 --- a/arch/powerpc/platforms/powernv/Kconfig +++ b/arch/powerpc/platforms/powernv/Kconfig @@ -13,11 +13,6 @@ config PPC_POWERNV select ARCH_RANDOM default y -config POWERNV_MSI - bool "Support PCI MSI on PowerNV platform" - depends on PCI_MSI - default y - config PPC_POWERNV_RTAS depends on PPC_POWERNV bool "Support for RTAS based PowerNV platforms such as BML" diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile index 873fa1370dc44c..8d767fde5a6ac3 100644 --- a/arch/powerpc/platforms/powernv/Makefile +++ b/arch/powerpc/platforms/powernv/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o obj-$(CONFIG_EEH) += eeh-ioda.o eeh-powernv.o obj-$(CONFIG_PPC_SCOM) += opal-xscom.o +obj-$(CONFIG_MEMORY_FAILURE) += opal-memory-errors.o diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c index d7ddcee7feb8bc..f5147433646025 100644 --- a/arch/powerpc/platforms/powernv/eeh-ioda.c +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -45,7 +44,8 @@ static int ioda_eeh_event(struct notifier_block *nb, /* We simply send special EEH event */ if ((changed_evts & OPAL_EVENT_PCI_ERROR) && - (events & OPAL_EVENT_PCI_ERROR)) + (events & OPAL_EVENT_PCI_ERROR) && + eeh_enabled()) eeh_send_failure_event(NULL); return 0; @@ -490,8 +490,7 @@ static int ioda_eeh_bridge_reset(struct pci_controller *hose, static int ioda_eeh_reset(struct eeh_pe *pe, int option) { struct pci_controller *hose = pe->phb; - struct eeh_dev *edev; - struct pci_dev *dev; + struct pci_bus *bus; int ret; /* @@ -520,31 +519,11 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option) if (pe->type & EEH_PE_PHB) { ret = ioda_eeh_phb_reset(hose, option); } else { - if (pe->type & EEH_PE_DEVICE) { - /* - * If it's device PE, we didn't refer to the parent - * PCI bus yet. So we have to figure it out indirectly. - */ - edev = list_first_entry(&pe->edevs, - struct eeh_dev, list); - dev = eeh_dev_to_pci_dev(edev); - dev = dev->bus->self; - } else { - /* - * If it's bus PE, the parent PCI bus is already there - * and just pick it up. - */ - dev = pe->bus->self; - } - - /* - * Do reset based on the fact that the direct upstream bridge - * is root bridge (port) or not. - */ - if (dev->bus->number == 0) + bus = eeh_pe_bus_get(pe); + if (pci_is_root_bus(bus)) ret = ioda_eeh_root_reset(hose, option); else - ret = ioda_eeh_bridge_reset(hose, dev, option); + ret = ioda_eeh_bridge_reset(hose, bus->self, option); } return ret; @@ -578,11 +557,8 @@ static int ioda_eeh_get_log(struct eeh_pe *pe, int severity, return -EIO; } - /* - * FIXME: We probably need log the error in somewhere. - * Lets make it up in future. - */ - /* pr_info("%s", phb->diag.blob); */ + /* The PHB diag-data is always indicative */ + pnv_pci_dump_phb_diag_data(hose, phb->diag.blob); spin_unlock_irqrestore(&phb->lock, flags); @@ -670,143 +646,9 @@ static void ioda_eeh_hub_diag(struct pci_controller *hose) } } -static void ioda_eeh_p7ioc_phb_diag(struct pci_controller *hose, - struct OpalIoPhbErrorCommon *common) -{ - struct OpalIoP7IOCPhbErrorData *data; - int i; - - data = (struct OpalIoP7IOCPhbErrorData *)common; - - pr_info("P7IOC PHB#%x Diag-data (Version: %d)\n\n", - hose->global_number, common->version); - - pr_info(" brdgCtl: %08x\n", data->brdgCtl); - - pr_info(" portStatusReg: %08x\n", data->portStatusReg); - pr_info(" rootCmplxStatus: %08x\n", data->rootCmplxStatus); - pr_info(" busAgentStatus: %08x\n", data->busAgentStatus); - - pr_info(" deviceStatus: %08x\n", data->deviceStatus); - pr_info(" slotStatus: %08x\n", data->slotStatus); - pr_info(" linkStatus: %08x\n", data->linkStatus); - pr_info(" devCmdStatus: %08x\n", data->devCmdStatus); - pr_info(" devSecStatus: %08x\n", data->devSecStatus); - - pr_info(" rootErrorStatus: %08x\n", data->rootErrorStatus); - pr_info(" uncorrErrorStatus: %08x\n", data->uncorrErrorStatus); - pr_info(" corrErrorStatus: %08x\n", data->corrErrorStatus); - pr_info(" tlpHdr1: %08x\n", data->tlpHdr1); - pr_info(" tlpHdr2: %08x\n", data->tlpHdr2); - pr_info(" tlpHdr3: %08x\n", data->tlpHdr3); - pr_info(" tlpHdr4: %08x\n", data->tlpHdr4); - pr_info(" sourceId: %08x\n", data->sourceId); - - pr_info(" errorClass: %016llx\n", data->errorClass); - pr_info(" correlator: %016llx\n", data->correlator); - pr_info(" p7iocPlssr: %016llx\n", data->p7iocPlssr); - pr_info(" p7iocCsr: %016llx\n", data->p7iocCsr); - pr_info(" lemFir: %016llx\n", data->lemFir); - pr_info(" lemErrorMask: %016llx\n", data->lemErrorMask); - pr_info(" lemWOF: %016llx\n", data->lemWOF); - pr_info(" phbErrorStatus: %016llx\n", data->phbErrorStatus); - pr_info(" phbFirstErrorStatus: %016llx\n", data->phbFirstErrorStatus); - pr_info(" phbErrorLog0: %016llx\n", data->phbErrorLog0); - pr_info(" phbErrorLog1: %016llx\n", data->phbErrorLog1); - pr_info(" mmioErrorStatus: %016llx\n", data->mmioErrorStatus); - pr_info(" mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus); - pr_info(" mmioErrorLog0: %016llx\n", data->mmioErrorLog0); - pr_info(" mmioErrorLog1: %016llx\n", data->mmioErrorLog1); - pr_info(" dma0ErrorStatus: %016llx\n", data->dma0ErrorStatus); - pr_info(" dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus); - pr_info(" dma0ErrorLog0: %016llx\n", data->dma0ErrorLog0); - pr_info(" dma0ErrorLog1: %016llx\n", data->dma0ErrorLog1); - pr_info(" dma1ErrorStatus: %016llx\n", data->dma1ErrorStatus); - pr_info(" dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus); - pr_info(" dma1ErrorLog0: %016llx\n", data->dma1ErrorLog0); - pr_info(" dma1ErrorLog1: %016llx\n", data->dma1ErrorLog1); - - for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) { - if ((data->pestA[i] >> 63) == 0 && - (data->pestB[i] >> 63) == 0) - continue; - - pr_info(" PE[%3d] PESTA: %016llx\n", i, data->pestA[i]); - pr_info(" PESTB: %016llx\n", data->pestB[i]); - } -} - -static void ioda_eeh_phb3_phb_diag(struct pci_controller *hose, - struct OpalIoPhbErrorCommon *common) -{ - struct OpalIoPhb3ErrorData *data; - int i; - - data = (struct OpalIoPhb3ErrorData*)common; - pr_info("PHB3 PHB#%x Diag-data (Version: %d)\n\n", - hose->global_number, common->version); - - pr_info(" brdgCtl: %08x\n", data->brdgCtl); - - pr_info(" portStatusReg: %08x\n", data->portStatusReg); - pr_info(" rootCmplxStatus: %08x\n", data->rootCmplxStatus); - pr_info(" busAgentStatus: %08x\n", data->busAgentStatus); - - pr_info(" deviceStatus: %08x\n", data->deviceStatus); - pr_info(" slotStatus: %08x\n", data->slotStatus); - pr_info(" linkStatus: %08x\n", data->linkStatus); - pr_info(" devCmdStatus: %08x\n", data->devCmdStatus); - pr_info(" devSecStatus: %08x\n", data->devSecStatus); - - pr_info(" rootErrorStatus: %08x\n", data->rootErrorStatus); - pr_info(" uncorrErrorStatus: %08x\n", data->uncorrErrorStatus); - pr_info(" corrErrorStatus: %08x\n", data->corrErrorStatus); - pr_info(" tlpHdr1: %08x\n", data->tlpHdr1); - pr_info(" tlpHdr2: %08x\n", data->tlpHdr2); - pr_info(" tlpHdr3: %08x\n", data->tlpHdr3); - pr_info(" tlpHdr4: %08x\n", data->tlpHdr4); - pr_info(" sourceId: %08x\n", data->sourceId); - pr_info(" errorClass: %016llx\n", data->errorClass); - pr_info(" correlator: %016llx\n", data->correlator); - pr_info(" nFir: %016llx\n", data->nFir); - pr_info(" nFirMask: %016llx\n", data->nFirMask); - pr_info(" nFirWOF: %016llx\n", data->nFirWOF); - pr_info(" PhbPlssr: %016llx\n", data->phbPlssr); - pr_info(" PhbCsr: %016llx\n", data->phbCsr); - pr_info(" lemFir: %016llx\n", data->lemFir); - pr_info(" lemErrorMask: %016llx\n", data->lemErrorMask); - pr_info(" lemWOF: %016llx\n", data->lemWOF); - pr_info(" phbErrorStatus: %016llx\n", data->phbErrorStatus); - pr_info(" phbFirstErrorStatus: %016llx\n", data->phbFirstErrorStatus); - pr_info(" phbErrorLog0: %016llx\n", data->phbErrorLog0); - pr_info(" phbErrorLog1: %016llx\n", data->phbErrorLog1); - pr_info(" mmioErrorStatus: %016llx\n", data->mmioErrorStatus); - pr_info(" mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus); - pr_info(" mmioErrorLog0: %016llx\n", data->mmioErrorLog0); - pr_info(" mmioErrorLog1: %016llx\n", data->mmioErrorLog1); - pr_info(" dma0ErrorStatus: %016llx\n", data->dma0ErrorStatus); - pr_info(" dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus); - pr_info(" dma0ErrorLog0: %016llx\n", data->dma0ErrorLog0); - pr_info(" dma0ErrorLog1: %016llx\n", data->dma0ErrorLog1); - pr_info(" dma1ErrorStatus: %016llx\n", data->dma1ErrorStatus); - pr_info(" dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus); - pr_info(" dma1ErrorLog0: %016llx\n", data->dma1ErrorLog0); - pr_info(" dma1ErrorLog1: %016llx\n", data->dma1ErrorLog1); - - for (i = 0; i < OPAL_PHB3_NUM_PEST_REGS; i++) { - if ((data->pestA[i] >> 63) == 0 && - (data->pestB[i] >> 63) == 0) - continue; - - pr_info(" PE[%3d] PESTA: %016llx\n", i, data->pestA[i]); - pr_info(" PESTB: %016llx\n", data->pestB[i]); - } -} - static void ioda_eeh_phb_diag(struct pci_controller *hose) { struct pnv_phb *phb = hose->private_data; - struct OpalIoPhbErrorCommon *common; long rc; rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob, @@ -817,18 +659,7 @@ static void ioda_eeh_phb_diag(struct pci_controller *hose) return; } - common = (struct OpalIoPhbErrorCommon *)phb->diag.blob; - switch (common->ioType) { - case OPAL_PHB_ERROR_DATA_TYPE_P7IOC: - ioda_eeh_p7ioc_phb_diag(hose, common); - break; - case OPAL_PHB_ERROR_DATA_TYPE_PHB3: - ioda_eeh_phb3_phb_diag(hose, common); - break; - default: - pr_warning("%s: Unrecognized I/O chip %d\n", - __func__, common->ioType); - } + pnv_pci_dump_phb_diag_data(hose, phb->diag.blob); } static int ioda_eeh_get_phb_pe(struct pci_controller *hose, @@ -862,11 +693,7 @@ static int ioda_eeh_get_pe(struct pci_controller *hose, dev.phb = hose; dev.pe_config_addr = pe_no; dev_pe = eeh_pe_get(&dev); - if (!dev_pe) { - pr_warning("%s: Can't find PE for PHB#%x - PE#%x\n", - __func__, hose->global_number, pe_no); - return -EEXIST; - } + if (!dev_pe) return -EEXIST; *pe = dev_pe; return 0; @@ -884,12 +711,12 @@ static int ioda_eeh_get_pe(struct pci_controller *hose, */ static int ioda_eeh_next_error(struct eeh_pe **pe) { - struct pci_controller *hose, *tmp; + struct pci_controller *hose; struct pnv_phb *phb; u64 frozen_pe_no; u16 err_type, severity; long rc; - int ret = 1; + int ret = EEH_NEXT_ERR_NONE; /* * While running here, it's safe to purge the event queue. @@ -899,7 +726,7 @@ static int ioda_eeh_next_error(struct eeh_pe **pe) eeh_remove_event(NULL); opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul); - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { + list_for_each_entry(hose, &hose_list, list_node) { /* * If the subordinate PCI buses of the PHB has been * removed, we needn't take care of it any more. @@ -938,19 +765,19 @@ static int ioda_eeh_next_error(struct eeh_pe **pe) switch (err_type) { case OPAL_EEH_IOC_ERROR: if (severity == OPAL_EEH_SEV_IOC_DEAD) { - list_for_each_entry_safe(hose, tmp, - &hose_list, list_node) { + list_for_each_entry(hose, &hose_list, + list_node) { phb = hose->private_data; phb->eeh_state |= PNV_EEH_STATE_REMOVED; } pr_err("EEH: dead IOC detected\n"); - ret = 4; - goto out; + ret = EEH_NEXT_ERR_DEAD_IOC; } else if (severity == OPAL_EEH_SEV_INF) { pr_info("EEH: IOC informative error " "detected\n"); ioda_eeh_hub_diag(hose); + ret = EEH_NEXT_ERR_NONE; } break; @@ -962,37 +789,61 @@ static int ioda_eeh_next_error(struct eeh_pe **pe) pr_err("EEH: dead PHB#%x detected\n", hose->global_number); phb->eeh_state |= PNV_EEH_STATE_REMOVED; - ret = 3; - goto out; + ret = EEH_NEXT_ERR_DEAD_PHB; } else if (severity == OPAL_EEH_SEV_PHB_FENCED) { if (ioda_eeh_get_phb_pe(hose, pe)) break; pr_err("EEH: fenced PHB#%x detected\n", hose->global_number); - ret = 2; - goto out; + ret = EEH_NEXT_ERR_FENCED_PHB; } else if (severity == OPAL_EEH_SEV_INF) { pr_info("EEH: PHB#%x informative error " "detected\n", hose->global_number); ioda_eeh_phb_diag(hose); + ret = EEH_NEXT_ERR_NONE; } break; case OPAL_EEH_PE_ERROR: - if (ioda_eeh_get_pe(hose, frozen_pe_no, pe)) - break; + /* + * If we can't find the corresponding PE, the + * PEEV / PEST would be messy. So we force an + * fenced PHB so that it can be recovered. + */ + if (ioda_eeh_get_pe(hose, frozen_pe_no, pe)) { + if (!ioda_eeh_get_phb_pe(hose, pe)) { + pr_err("EEH: Escalated fenced PHB#%x " + "detected for PE#%llx\n", + hose->global_number, + frozen_pe_no); + ret = EEH_NEXT_ERR_FENCED_PHB; + } else { + ret = EEH_NEXT_ERR_NONE; + } + } else { + pr_err("EEH: Frozen PE#%x on PHB#%x detected\n", + (*pe)->addr, (*pe)->phb->global_number); + ret = EEH_NEXT_ERR_FROZEN_PE; + } - pr_err("EEH: Frozen PE#%x on PHB#%x detected\n", - (*pe)->addr, (*pe)->phb->global_number); - ret = 1; - goto out; + break; + default: + pr_warn("%s: Unexpected error type %d\n", + __func__, err_type); } + + /* + * If we have no errors on the specific PHB or only + * informative error there, we continue poking it. + * Otherwise, we need actions to be taken by upper + * layer. + */ + if (ret > EEH_NEXT_ERR_INF) + break; } - ret = 0; -out: return ret; } diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index 73b981438cc583..a59788e83b8b37 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -145,7 +145,7 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag) * Enable EEH explicitly so that we will do EEH check * while accessing I/O stuff */ - eeh_subsystem_enabled = 1; + eeh_set_enable(true); /* Save memory bars */ eeh_save_bars(edev); @@ -344,6 +344,27 @@ static int powernv_eeh_next_error(struct eeh_pe **pe) return -EEXIST; } +static int powernv_eeh_restore_config(struct device_node *dn) +{ + struct eeh_dev *edev = of_node_to_eeh_dev(dn); + struct pnv_phb *phb; + s64 ret; + + if (!edev) + return -EEXIST; + + phb = edev->phb->private_data; + ret = opal_pci_reinit(phb->opal_id, + OPAL_REINIT_PCI_DEV, edev->config_addr); + if (ret) { + pr_warn("%s: Can't reinit PCI dev 0x%x (%lld)\n", + __func__, edev->config_addr, ret); + return -EIO; + } + + return 0; +} + static struct eeh_ops powernv_eeh_ops = { .name = "powernv", .init = powernv_eeh_init, @@ -359,7 +380,8 @@ static struct eeh_ops powernv_eeh_ops = { .configure_bridge = powernv_eeh_configure_bridge, .read_config = pnv_pci_cfg_read, .write_config = pnv_pci_cfg_write, - .next_error = powernv_eeh_next_error + .next_error = powernv_eeh_next_error, + .restore_config = powernv_eeh_restore_config }; /** diff --git a/arch/powerpc/platforms/powernv/opal-flash.c b/arch/powerpc/platforms/powernv/opal-flash.c index d8773079ce195a..714ef972406bca 100644 --- a/arch/powerpc/platforms/powernv/opal-flash.c +++ b/arch/powerpc/platforms/powernv/opal-flash.c @@ -76,8 +76,8 @@ /* Validate buffer size */ #define VALIDATE_BUF_SIZE 4096 -/* XXX: Assume candidate image size is <= 256MB */ -#define MAX_IMAGE_SIZE 0x10000000 +/* XXX: Assume candidate image size is <= 1GB */ +#define MAX_IMAGE_SIZE 0x40000000 /* Flash sg list version */ #define SG_LIST_VERSION (1UL) @@ -103,27 +103,6 @@ struct image_header_t { uint32_t size; }; -/* Scatter/gather entry */ -struct opal_sg_entry { - void *data; - long length; -}; - -/* We calculate number of entries based on PAGE_SIZE */ -#define SG_ENTRIES_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct opal_sg_entry)) - -/* - * This struct is very similar but not identical to that - * needed by the opal flash update. All we need to do for - * opal is rewrite num_entries into a version/length and - * translate the pointers to absolute. - */ -struct opal_sg_list { - unsigned long num_entries; - struct opal_sg_list *next; - struct opal_sg_entry entry[SG_ENTRIES_PER_NODE]; -}; - struct validate_flash_t { int status; /* Return status */ void *buf; /* Candidate image buffer */ @@ -333,7 +312,7 @@ static struct opal_sg_list *image_data_to_sglist(void) addr = image_data.data; size = image_data.size; - sg1 = kzalloc((sizeof(struct opal_sg_list)), GFP_KERNEL); + sg1 = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!sg1) return NULL; @@ -351,8 +330,7 @@ static struct opal_sg_list *image_data_to_sglist(void) sg1->num_entries++; if (sg1->num_entries >= SG_ENTRIES_PER_NODE) { - sg1->next = kzalloc((sizeof(struct opal_sg_list)), - GFP_KERNEL); + sg1->next = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!sg1->next) { pr_err("%s : Failed to allocate memory\n", __func__); @@ -402,7 +380,10 @@ static int opal_flash_update(int op) else sg->next = NULL; - /* Make num_entries into the version/length field */ + /* + * Convert num_entries to version/length format + * to satisfy OPAL. + */ sg->num_entries = (SG_LIST_VERSION << 56) | (sg->num_entries * sizeof(struct opal_sg_entry) + 16); } diff --git a/arch/powerpc/platforms/powernv/opal-memory-errors.c b/arch/powerpc/platforms/powernv/opal-memory-errors.c new file mode 100644 index 00000000000000..ec4132239cdf20 --- /dev/null +++ b/arch/powerpc/platforms/powernv/opal-memory-errors.c @@ -0,0 +1,146 @@ +/* + * OPAL asynchronus Memory error handling support in PowreNV. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright 2013 IBM Corporation + * Author: Mahesh Salgaonkar + */ + +#undef DEBUG + +#include +#include +#include +#include +#include + +#include +#include + +static int opal_mem_err_nb_init; +static LIST_HEAD(opal_memory_err_list); +static DEFINE_SPINLOCK(opal_mem_err_lock); + +struct OpalMsgNode { + struct list_head list; + struct opal_msg msg; +}; + +static void handle_memory_error_event(struct OpalMemoryErrorData *merr_evt) +{ + uint64_t paddr_start, paddr_end; + + pr_debug("%s: Retrived memory error event, type: 0x%x\n", + __func__, merr_evt->type); + switch (merr_evt->type) { + case OPAL_MEM_ERR_TYPE_RESILIENCE: + paddr_start = merr_evt->u.resilience.physical_address_start; + paddr_end = merr_evt->u.resilience.physical_address_end; + break; + case OPAL_MEM_ERR_TYPE_DYN_DALLOC: + paddr_start = merr_evt->u.dyn_dealloc.physical_address_start; + paddr_end = merr_evt->u.dyn_dealloc.physical_address_end; + break; + default: + return; + } + + for (; paddr_start < paddr_end; paddr_start += PAGE_SIZE) { + memory_failure(paddr_start >> PAGE_SHIFT, 0, 0); + } +} + +static void handle_memory_error(void) +{ + unsigned long flags; + struct OpalMemoryErrorData *merr_evt; + struct OpalMsgNode *msg_node; + + spin_lock_irqsave(&opal_mem_err_lock, flags); + while (!list_empty(&opal_memory_err_list)) { + msg_node = list_entry(opal_memory_err_list.next, + struct OpalMsgNode, list); + list_del(&msg_node->list); + spin_unlock_irqrestore(&opal_mem_err_lock, flags); + + merr_evt = (struct OpalMemoryErrorData *) + &msg_node->msg.params[0]; + handle_memory_error_event(merr_evt); + kfree(msg_node); + spin_lock_irqsave(&opal_mem_err_lock, flags); + } + spin_unlock_irqrestore(&opal_mem_err_lock, flags); +} + +static void mem_error_handler(struct work_struct *work) +{ + handle_memory_error(); +} + +static DECLARE_WORK(mem_error_work, mem_error_handler); + +/* + * opal_memory_err_event - notifier handler that queues up the opal message + * to be preocessed later. + */ +static int opal_memory_err_event(struct notifier_block *nb, + unsigned long msg_type, void *msg) +{ + unsigned long flags; + struct OpalMsgNode *msg_node; + + if (msg_type != OPAL_MSG_MEM_ERR) + return 0; + + msg_node = kzalloc(sizeof(*msg_node), GFP_ATOMIC); + if (!msg_node) { + pr_err("MEMORY_ERROR: out of memory, Opal message event not" + "handled\n"); + return -ENOMEM; + } + memcpy(&msg_node->msg, msg, sizeof(struct opal_msg)); + + spin_lock_irqsave(&opal_mem_err_lock, flags); + list_add(&msg_node->list, &opal_memory_err_list); + spin_unlock_irqrestore(&opal_mem_err_lock, flags); + + schedule_work(&mem_error_work); + return 0; +} + +static struct notifier_block opal_mem_err_nb = { + .notifier_call = opal_memory_err_event, + .next = NULL, + .priority = 0, +}; + +static int __init opal_mem_err_init(void) +{ + int ret; + + if (!opal_mem_err_nb_init) { + ret = opal_message_notifier_register( + OPAL_MSG_MEM_ERR, &opal_mem_err_nb); + if (ret) { + pr_err("%s: Can't register OPAL event notifier (%d)\n", + __func__, ret); + return ret; + } + opal_mem_err_nb_init = 1; + } + return 0; +} +subsys_initcall(opal_mem_err_init); diff --git a/arch/powerpc/platforms/powernv/opal-rtc.c b/arch/powerpc/platforms/powernv/opal-rtc.c index 7d07c7e80ec09e..b1885db8fdf34b 100644 --- a/arch/powerpc/platforms/powernv/opal-rtc.c +++ b/arch/powerpc/platforms/powernv/opal-rtc.c @@ -18,6 +18,7 @@ #include #include +#include static void opal_to_tm(u32 y_m_d, u64 h_m_s_ms, struct rtc_time *tm) { @@ -48,8 +49,11 @@ unsigned long __init opal_get_boot_time(void) else mdelay(10); } - if (rc != OPAL_SUCCESS) + if (rc != OPAL_SUCCESS) { + ppc_md.get_rtc_time = NULL; + ppc_md.set_rtc_time = NULL; return 0; + } y_m_d = be32_to_cpu(__y_m_d); h_m_s_ms = be64_to_cpu(__h_m_s_ms); opal_to_tm(y_m_d, h_m_s_ms, &tm); diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S index e7806504e97691..3e8829c40fbbfc 100644 --- a/arch/powerpc/platforms/powernv/opal-wrappers.S +++ b/arch/powerpc/platforms/powernv/opal-wrappers.S @@ -126,3 +126,6 @@ OPAL_CALL(opal_return_cpu, OPAL_RETURN_CPU); OPAL_CALL(opal_validate_flash, OPAL_FLASH_VALIDATE); OPAL_CALL(opal_manage_flash, OPAL_FLASH_MANAGE); OPAL_CALL(opal_update_flash, OPAL_FLASH_UPDATE); +OPAL_CALL(opal_get_msg, OPAL_GET_MSG); +OPAL_CALL(opal_check_completion, OPAL_CHECK_ASYNC_COMPLETION); +OPAL_CALL(opal_sync_host_reboot, OPAL_SYNC_HOST_REBOOT); diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 1c798cd553722f..65499adaecff2a 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -18,9 +18,12 @@ #include #include #include +#include #include +#include #include #include +#include #include "powernv.h" @@ -38,6 +41,7 @@ extern u64 opal_mc_secondary_handler[]; static unsigned int *opal_irqs; static unsigned int opal_irq_count; static ATOMIC_NOTIFIER_HEAD(opal_notifier_head); +static struct atomic_notifier_head opal_msg_notifier_head[OPAL_MSG_TYPE_MAX]; static DEFINE_SPINLOCK(opal_notifier_lock); static uint64_t last_notified_mask = 0x0ul; static atomic_t opal_notifier_hold = ATOMIC_INIT(0); @@ -88,14 +92,10 @@ static int __init opal_register_exception_handlers(void) if (!(powerpc_firmware_features & FW_FEATURE_OPAL)) return -ENODEV; - /* Hookup some exception handlers. We use the fwnmi area at 0x7000 - * to provide the glue space to OPAL + /* Hookup some exception handlers except machine check. We use the + * fwnmi area at 0x7000 to provide the glue space to OPAL */ glue = 0x7000; - opal_register_exception_handler(OPAL_MACHINE_CHECK_HANDLER, - __pa(opal_mc_secondary_handler[0]), - glue); - glue += 128; opal_register_exception_handler(OPAL_HYPERVISOR_MAINTENANCE_HANDLER, 0, glue); glue += 128; @@ -169,6 +169,95 @@ void opal_notifier_disable(void) atomic_set(&opal_notifier_hold, 1); } +/* + * Opal message notifier based on message type. Allow subscribers to get + * notified for specific messgae type. + */ +int opal_message_notifier_register(enum OpalMessageType msg_type, + struct notifier_block *nb) +{ + if (!nb) { + pr_warning("%s: Invalid argument (%p)\n", + __func__, nb); + return -EINVAL; + } + if (msg_type > OPAL_MSG_TYPE_MAX) { + pr_warning("%s: Invalid message type argument (%d)\n", + __func__, msg_type); + return -EINVAL; + } + return atomic_notifier_chain_register( + &opal_msg_notifier_head[msg_type], nb); +} + +static void opal_message_do_notify(uint32_t msg_type, void *msg) +{ + /* notify subscribers */ + atomic_notifier_call_chain(&opal_msg_notifier_head[msg_type], + msg_type, msg); +} + +static void opal_handle_message(void) +{ + s64 ret; + /* + * TODO: pre-allocate a message buffer depending on opal-msg-size + * value in /proc/device-tree. + */ + static struct opal_msg msg; + + ret = opal_get_msg(__pa(&msg), sizeof(msg)); + /* No opal message pending. */ + if (ret == OPAL_RESOURCE) + return; + + /* check for errors. */ + if (ret) { + pr_warning("%s: Failed to retrive opal message, err=%lld\n", + __func__, ret); + return; + } + + /* Sanity check */ + if (msg.msg_type > OPAL_MSG_TYPE_MAX) { + pr_warning("%s: Unknown message type: %u\n", + __func__, msg.msg_type); + return; + } + opal_message_do_notify(msg.msg_type, (void *)&msg); +} + +static int opal_message_notify(struct notifier_block *nb, + unsigned long events, void *change) +{ + if (events & OPAL_EVENT_MSG_PENDING) + opal_handle_message(); + return 0; +} + +static struct notifier_block opal_message_nb = { + .notifier_call = opal_message_notify, + .next = NULL, + .priority = 0, +}; + +static int __init opal_message_init(void) +{ + int ret, i; + + for (i = 0; i < OPAL_MSG_TYPE_MAX; i++) + ATOMIC_INIT_NOTIFIER_HEAD(&opal_msg_notifier_head[i]); + + ret = opal_notifier_register(&opal_message_nb); + if (ret) { + pr_err("%s: Can't register OPAL event notifier (%d)\n", + __func__, ret); + return ret; + } + return 0; +} +early_initcall(opal_message_init); + int opal_get_chars(uint32_t vtermno, char *buf, int count) { s64 rc; @@ -254,119 +343,62 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len) return written; } +static int opal_recover_mce(struct pt_regs *regs, + struct machine_check_event *evt) +{ + int recovered = 0; + uint64_t ea = get_mce_fault_addr(evt); + + if (!(regs->msr & MSR_RI)) { + /* If MSR_RI isn't set, we cannot recover */ + recovered = 0; + } else if (evt->disposition == MCE_DISPOSITION_RECOVERED) { + /* Platform corrected itself */ + recovered = 1; + } else if (ea && !is_kernel_addr(ea)) { + /* + * Faulting address is not in kernel text. We should be fine. + * We need to find which process uses this address. + * For now, kill the task if we have received exception when + * in userspace. + * + * TODO: Queue up this address for hwpoisioning later. + */ + if (user_mode(regs) && !is_global_init(current)) { + _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip); + recovered = 1; + } else + recovered = 0; + } else if (user_mode(regs) && !is_global_init(current) && + evt->severity == MCE_SEV_ERROR_SYNC) { + /* + * If we have received a synchronous error when in userspace + * kill the task. + */ + _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip); + recovered = 1; + } + return recovered; +} + int opal_machine_check(struct pt_regs *regs) { - struct opal_machine_check_event *opal_evt = get_paca()->opal_mc_evt; - struct opal_machine_check_event evt; - const char *level, *sevstr, *subtype; - static const char *opal_mc_ue_types[] = { - "Indeterminate", - "Instruction fetch", - "Page table walk ifetch", - "Load/Store", - "Page table walk Load/Store", - }; - static const char *opal_mc_slb_types[] = { - "Indeterminate", - "Parity", - "Multihit", - }; - static const char *opal_mc_erat_types[] = { - "Indeterminate", - "Parity", - "Multihit", - }; - static const char *opal_mc_tlb_types[] = { - "Indeterminate", - "Parity", - "Multihit", - }; - - /* Copy the event structure and release the original */ - evt = *opal_evt; - opal_evt->in_use = 0; + struct machine_check_event evt; + + if (!get_mce_event(&evt, MCE_EVENT_RELEASE)) + return 0; /* Print things out */ - if (evt.version != OpalMCE_V1) { + if (evt.version != MCE_V1) { pr_err("Machine Check Exception, Unknown event version %d !\n", evt.version); return 0; } - switch(evt.severity) { - case OpalMCE_SEV_NO_ERROR: - level = KERN_INFO; - sevstr = "Harmless"; - break; - case OpalMCE_SEV_WARNING: - level = KERN_WARNING; - sevstr = ""; - break; - case OpalMCE_SEV_ERROR_SYNC: - level = KERN_ERR; - sevstr = "Severe"; - break; - case OpalMCE_SEV_FATAL: - default: - level = KERN_ERR; - sevstr = "Fatal"; - break; - } + machine_check_print_event_info(&evt); - printk("%s%s Machine check interrupt [%s]\n", level, sevstr, - evt.disposition == OpalMCE_DISPOSITION_RECOVERED ? - "Recovered" : "[Not recovered"); - printk("%s Initiator: %s\n", level, - evt.initiator == OpalMCE_INITIATOR_CPU ? "CPU" : "Unknown"); - switch(evt.error_type) { - case OpalMCE_ERROR_TYPE_UE: - subtype = evt.u.ue_error.ue_error_type < - ARRAY_SIZE(opal_mc_ue_types) ? - opal_mc_ue_types[evt.u.ue_error.ue_error_type] - : "Unknown"; - printk("%s Error type: UE [%s]\n", level, subtype); - if (evt.u.ue_error.effective_address_provided) - printk("%s Effective address: %016llx\n", - level, evt.u.ue_error.effective_address); - if (evt.u.ue_error.physical_address_provided) - printk("%s Physial address: %016llx\n", - level, evt.u.ue_error.physical_address); - break; - case OpalMCE_ERROR_TYPE_SLB: - subtype = evt.u.slb_error.slb_error_type < - ARRAY_SIZE(opal_mc_slb_types) ? - opal_mc_slb_types[evt.u.slb_error.slb_error_type] - : "Unknown"; - printk("%s Error type: SLB [%s]\n", level, subtype); - if (evt.u.slb_error.effective_address_provided) - printk("%s Effective address: %016llx\n", - level, evt.u.slb_error.effective_address); - break; - case OpalMCE_ERROR_TYPE_ERAT: - subtype = evt.u.erat_error.erat_error_type < - ARRAY_SIZE(opal_mc_erat_types) ? - opal_mc_erat_types[evt.u.erat_error.erat_error_type] - : "Unknown"; - printk("%s Error type: ERAT [%s]\n", level, subtype); - if (evt.u.erat_error.effective_address_provided) - printk("%s Effective address: %016llx\n", - level, evt.u.erat_error.effective_address); - break; - case OpalMCE_ERROR_TYPE_TLB: - subtype = evt.u.tlb_error.tlb_error_type < - ARRAY_SIZE(opal_mc_tlb_types) ? - opal_mc_tlb_types[evt.u.tlb_error.tlb_error_type] - : "Unknown"; - printk("%s Error type: TLB [%s]\n", level, subtype); - if (evt.u.tlb_error.effective_address_provided) - printk("%s Effective address: %016llx\n", - level, evt.u.tlb_error.effective_address); - break; - default: - case OpalMCE_ERROR_TYPE_UNKNOWN: - printk("%s Error type: Unknown\n", level); - break; - } - return evt.severity == OpalMCE_SEV_FATAL ? 0 : 1; + if (opal_recover_mce(regs, &evt)) + return 1; + return 0; } static irqreturn_t opal_interrupt(int irq, void *data) @@ -451,10 +483,25 @@ subsys_initcall(opal_init); void opal_shutdown(void) { unsigned int i; + long rc = OPAL_BUSY; + /* First free interrupts, which will also mask them */ for (i = 0; i < opal_irq_count; i++) { if (opal_irqs[i]) free_irq(opal_irqs[i], NULL); opal_irqs[i] = 0; } + + /* + * Then sync with OPAL which ensure anything that can + * potentially write to our memory has completed such + * as an ongoing dump retrieval + */ + while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { + rc = opal_sync_host_reboot(); + if (rc == OPAL_BUSY) + opal_poll_events(NULL); + else + mdelay(10); + } } diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 2c6d173842b2f1..3b2b4fb3585b6b 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -460,7 +461,37 @@ static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev return; pe = &phb->ioda.pe_array[pdn->pe_number]; - set_iommu_table_base(&pdev->dev, &pe->tce32_table); + WARN_ON(get_dma_ops(&pdev->dev) != &dma_iommu_ops); + set_iommu_table_base_and_group(&pdev->dev, &pe->tce32_table); +} + +static int pnv_pci_ioda_dma_set_mask(struct pnv_phb *phb, + struct pci_dev *pdev, u64 dma_mask) +{ + struct pci_dn *pdn = pci_get_pdn(pdev); + struct pnv_ioda_pe *pe; + uint64_t top; + bool bypass = false; + + if (WARN_ON(!pdn || pdn->pe_number == IODA_INVALID_PE)) + return -ENODEV;; + + pe = &phb->ioda.pe_array[pdn->pe_number]; + if (pe->tce_bypass_enabled) { + top = pe->tce_bypass_base + memblock_end_of_DRAM() - 1; + bypass = (dma_mask >= top); + } + + if (bypass) { + dev_info(&pdev->dev, "Using 64-bit DMA iommu bypass\n"); + set_dma_ops(&pdev->dev, &dma_direct_ops); + set_dma_offset(&pdev->dev, pe->tce_bypass_base); + } else { + dev_info(&pdev->dev, "Using 32-bit DMA via iommu\n"); + set_dma_ops(&pdev->dev, &dma_iommu_ops); + set_iommu_table_base(&pdev->dev, &pe->tce32_table); + } + return 0; } static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus) @@ -468,7 +499,7 @@ static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus) struct pci_dev *dev; list_for_each_entry(dev, &bus->devices, bus_list) { - set_iommu_table_base(&dev->dev, &pe->tce32_table); + set_iommu_table_base_and_group(&dev->dev, &pe->tce32_table); if (dev->subordinate) pnv_ioda_setup_bus_dma(pe, dev->subordinate); } @@ -644,7 +675,7 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb, iommu_register_group(tbl, pci_domain_nr(pe->pbus), pe->pe_number); if (pe->pdev) - set_iommu_table_base(&pe->pdev->dev, tbl); + set_iommu_table_base_and_group(&pe->pdev->dev, tbl); else pnv_ioda_setup_bus_dma(pe, pe->pbus); @@ -657,6 +688,56 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb, __free_pages(tce_mem, get_order(TCE32_TABLE_SIZE * segs)); } +static void pnv_pci_ioda2_set_bypass(struct iommu_table *tbl, bool enable) +{ + struct pnv_ioda_pe *pe = container_of(tbl, struct pnv_ioda_pe, + tce32_table); + uint16_t window_id = (pe->pe_number << 1 ) + 1; + int64_t rc; + + pe_info(pe, "%sabling 64-bit DMA bypass\n", enable ? "En" : "Dis"); + if (enable) { + phys_addr_t top = memblock_end_of_DRAM(); + + top = roundup_pow_of_two(top); + rc = opal_pci_map_pe_dma_window_real(pe->phb->opal_id, + pe->pe_number, + window_id, + pe->tce_bypass_base, + top); + } else { + rc = opal_pci_map_pe_dma_window_real(pe->phb->opal_id, + pe->pe_number, + window_id, + pe->tce_bypass_base, + 0); + + /* + * We might want to reset the DMA ops of all devices on + * this PE. However in theory, that shouldn't be necessary + * as this is used for VFIO/KVM pass-through and the device + * hasn't yet been returned to its kernel driver + */ + } + if (rc) + pe_err(pe, "OPAL error %lld configuring bypass window\n", rc); + else + pe->tce_bypass_enabled = enable; +} + +static void pnv_pci_ioda2_setup_bypass_pe(struct pnv_phb *phb, + struct pnv_ioda_pe *pe) +{ + /* TVE #1 is selected by PCI address bit 59 */ + pe->tce_bypass_base = 1ull << 59; + + /* Install set_bypass callback for VFIO */ + pe->tce32_table.set_bypass = pnv_pci_ioda2_set_bypass; + + /* Enable bypass by default */ + pnv_pci_ioda2_set_bypass(&pe->tce32_table, true); +} + static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe) { @@ -723,10 +804,12 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb, iommu_register_group(tbl, pci_domain_nr(pe->pbus), pe->pe_number); if (pe->pdev) - set_iommu_table_base(&pe->pdev->dev, tbl); + set_iommu_table_base_and_group(&pe->pdev->dev, tbl); else pnv_ioda_setup_bus_dma(pe, pe->pbus); + /* Also create a bypass window */ + pnv_pci_ioda2_setup_bypass_pe(phb, pe); return; fail: if (pe->tce32_seg >= 0) @@ -1144,7 +1227,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np, { struct pci_controller *hose; struct pnv_phb *phb; - unsigned long size, m32map_off, iomap_off, pemap_off; + unsigned long size, m32map_off, pemap_off, iomap_off = 0; const __be64 *prop64; const __be32 *prop32; int len; @@ -1231,7 +1314,6 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np, size = _ALIGN_UP(phb->ioda.total_pe / 8, sizeof(unsigned long)); m32map_off = size; size += phb->ioda.total_pe * sizeof(phb->ioda.m32_segmap[0]); - iomap_off = size; if (phb->type == PNV_PHB_IODA1) { iomap_off = size; size += phb->ioda.total_pe * sizeof(phb->ioda.io_segmap[0]); @@ -1287,6 +1369,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np, /* Setup TCEs */ phb->dma_dev_setup = pnv_pci_ioda_dma_dev_setup; + phb->dma_set_mask = pnv_pci_ioda_dma_set_mask; /* Setup shutdown function for kexec */ phb->shutdown = pnv_pci_ioda_shutdown; diff --git a/arch/powerpc/platforms/powernv/pci-p5ioc2.c b/arch/powerpc/platforms/powernv/pci-p5ioc2.c index f8b4bd8afb2e5d..e3807d69393e02 100644 --- a/arch/powerpc/platforms/powernv/pci-p5ioc2.c +++ b/arch/powerpc/platforms/powernv/pci-p5ioc2.c @@ -92,7 +92,7 @@ static void pnv_pci_p5ioc2_dma_dev_setup(struct pnv_phb *phb, pci_domain_nr(phb->hose->bus), phb->opal_id); } - set_iommu_table_base(&pdev->dev, &phb->p5ioc2.iommu_table); + set_iommu_table_base_and_group(&pdev->dev, &phb->p5ioc2.iommu_table); } static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np, u64 hub_id, diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 4eb33a9ed5325a..95633d79ef5d6d 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -124,77 +124,157 @@ static void pnv_teardown_msi_irqs(struct pci_dev *pdev) } #endif /* CONFIG_PCI_MSI */ -static void pnv_pci_dump_p7ioc_diag_data(struct pnv_phb *phb) +static void pnv_pci_dump_p7ioc_diag_data(struct pci_controller *hose, + struct OpalIoPhbErrorCommon *common) { - struct OpalIoP7IOCPhbErrorData *data = &phb->diag.p7ioc; + struct OpalIoP7IOCPhbErrorData *data; int i; - pr_info("PHB %d diagnostic data:\n", phb->hose->global_number); - - pr_info(" brdgCtl = 0x%08x\n", data->brdgCtl); - - pr_info(" portStatusReg = 0x%08x\n", data->portStatusReg); - pr_info(" rootCmplxStatus = 0x%08x\n", data->rootCmplxStatus); - pr_info(" busAgentStatus = 0x%08x\n", data->busAgentStatus); - - pr_info(" deviceStatus = 0x%08x\n", data->deviceStatus); - pr_info(" slotStatus = 0x%08x\n", data->slotStatus); - pr_info(" linkStatus = 0x%08x\n", data->linkStatus); - pr_info(" devCmdStatus = 0x%08x\n", data->devCmdStatus); - pr_info(" devSecStatus = 0x%08x\n", data->devSecStatus); - - pr_info(" rootErrorStatus = 0x%08x\n", data->rootErrorStatus); - pr_info(" uncorrErrorStatus = 0x%08x\n", data->uncorrErrorStatus); - pr_info(" corrErrorStatus = 0x%08x\n", data->corrErrorStatus); - pr_info(" tlpHdr1 = 0x%08x\n", data->tlpHdr1); - pr_info(" tlpHdr2 = 0x%08x\n", data->tlpHdr2); - pr_info(" tlpHdr3 = 0x%08x\n", data->tlpHdr3); - pr_info(" tlpHdr4 = 0x%08x\n", data->tlpHdr4); - pr_info(" sourceId = 0x%08x\n", data->sourceId); - - pr_info(" errorClass = 0x%016llx\n", data->errorClass); - pr_info(" correlator = 0x%016llx\n", data->correlator); - - pr_info(" p7iocPlssr = 0x%016llx\n", data->p7iocPlssr); - pr_info(" p7iocCsr = 0x%016llx\n", data->p7iocCsr); - pr_info(" lemFir = 0x%016llx\n", data->lemFir); - pr_info(" lemErrorMask = 0x%016llx\n", data->lemErrorMask); - pr_info(" lemWOF = 0x%016llx\n", data->lemWOF); - pr_info(" phbErrorStatus = 0x%016llx\n", data->phbErrorStatus); - pr_info(" phbFirstErrorStatus = 0x%016llx\n", data->phbFirstErrorStatus); - pr_info(" phbErrorLog0 = 0x%016llx\n", data->phbErrorLog0); - pr_info(" phbErrorLog1 = 0x%016llx\n", data->phbErrorLog1); - pr_info(" mmioErrorStatus = 0x%016llx\n", data->mmioErrorStatus); - pr_info(" mmioFirstErrorStatus = 0x%016llx\n", data->mmioFirstErrorStatus); - pr_info(" mmioErrorLog0 = 0x%016llx\n", data->mmioErrorLog0); - pr_info(" mmioErrorLog1 = 0x%016llx\n", data->mmioErrorLog1); - pr_info(" dma0ErrorStatus = 0x%016llx\n", data->dma0ErrorStatus); - pr_info(" dma0FirstErrorStatus = 0x%016llx\n", data->dma0FirstErrorStatus); - pr_info(" dma0ErrorLog0 = 0x%016llx\n", data->dma0ErrorLog0); - pr_info(" dma0ErrorLog1 = 0x%016llx\n", data->dma0ErrorLog1); - pr_info(" dma1ErrorStatus = 0x%016llx\n", data->dma1ErrorStatus); - pr_info(" dma1FirstErrorStatus = 0x%016llx\n", data->dma1FirstErrorStatus); - pr_info(" dma1ErrorLog0 = 0x%016llx\n", data->dma1ErrorLog0); - pr_info(" dma1ErrorLog1 = 0x%016llx\n", data->dma1ErrorLog1); + data = (struct OpalIoP7IOCPhbErrorData *)common; + pr_info("P7IOC PHB#%d Diag-data (Version: %d)\n\n", + hose->global_number, common->version); + + pr_info(" brdgCtl: %08x\n", data->brdgCtl); + + pr_info(" portStatusReg: %08x\n", data->portStatusReg); + pr_info(" rootCmplxStatus: %08x\n", data->rootCmplxStatus); + pr_info(" busAgentStatus: %08x\n", data->busAgentStatus); + + pr_info(" deviceStatus: %08x\n", data->deviceStatus); + pr_info(" slotStatus: %08x\n", data->slotStatus); + pr_info(" linkStatus: %08x\n", data->linkStatus); + pr_info(" devCmdStatus: %08x\n", data->devCmdStatus); + pr_info(" devSecStatus: %08x\n", data->devSecStatus); + + pr_info(" rootErrorStatus: %08x\n", data->rootErrorStatus); + pr_info(" uncorrErrorStatus: %08x\n", data->uncorrErrorStatus); + pr_info(" corrErrorStatus: %08x\n", data->corrErrorStatus); + pr_info(" tlpHdr1: %08x\n", data->tlpHdr1); + pr_info(" tlpHdr2: %08x\n", data->tlpHdr2); + pr_info(" tlpHdr3: %08x\n", data->tlpHdr3); + pr_info(" tlpHdr4: %08x\n", data->tlpHdr4); + pr_info(" sourceId: %08x\n", data->sourceId); + pr_info(" errorClass: %016llx\n", data->errorClass); + pr_info(" correlator: %016llx\n", data->correlator); + pr_info(" p7iocPlssr: %016llx\n", data->p7iocPlssr); + pr_info(" p7iocCsr: %016llx\n", data->p7iocCsr); + pr_info(" lemFir: %016llx\n", data->lemFir); + pr_info(" lemErrorMask: %016llx\n", data->lemErrorMask); + pr_info(" lemWOF: %016llx\n", data->lemWOF); + pr_info(" phbErrorStatus: %016llx\n", data->phbErrorStatus); + pr_info(" phbFirstErrorStatus: %016llx\n", data->phbFirstErrorStatus); + pr_info(" phbErrorLog0: %016llx\n", data->phbErrorLog0); + pr_info(" phbErrorLog1: %016llx\n", data->phbErrorLog1); + pr_info(" mmioErrorStatus: %016llx\n", data->mmioErrorStatus); + pr_info(" mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus); + pr_info(" mmioErrorLog0: %016llx\n", data->mmioErrorLog0); + pr_info(" mmioErrorLog1: %016llx\n", data->mmioErrorLog1); + pr_info(" dma0ErrorStatus: %016llx\n", data->dma0ErrorStatus); + pr_info(" dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus); + pr_info(" dma0ErrorLog0: %016llx\n", data->dma0ErrorLog0); + pr_info(" dma0ErrorLog1: %016llx\n", data->dma0ErrorLog1); + pr_info(" dma1ErrorStatus: %016llx\n", data->dma1ErrorStatus); + pr_info(" dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus); + pr_info(" dma1ErrorLog0: %016llx\n", data->dma1ErrorLog0); + pr_info(" dma1ErrorLog1: %016llx\n", data->dma1ErrorLog1); for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) { if ((data->pestA[i] >> 63) == 0 && (data->pestB[i] >> 63) == 0) continue; - pr_info(" PE[%3d] PESTA = 0x%016llx\n", i, data->pestA[i]); - pr_info(" PESTB = 0x%016llx\n", data->pestB[i]); + + pr_info(" PE[%3d] PESTA: %016llx\n", i, data->pestA[i]); + pr_info(" PESTB: %016llx\n", data->pestB[i]); } } -static void pnv_pci_dump_phb_diag_data(struct pnv_phb *phb) +static void pnv_pci_dump_phb3_diag_data(struct pci_controller *hose, + struct OpalIoPhbErrorCommon *common) { - switch(phb->model) { - case PNV_PHB_MODEL_P7IOC: - pnv_pci_dump_p7ioc_diag_data(phb); + struct OpalIoPhb3ErrorData *data; + int i; + + data = (struct OpalIoPhb3ErrorData*)common; + pr_info("PHB3 PHB#%d Diag-data (Version: %d)\n\n", + hose->global_number, common->version); + + pr_info(" brdgCtl: %08x\n", data->brdgCtl); + + pr_info(" portStatusReg: %08x\n", data->portStatusReg); + pr_info(" rootCmplxStatus: %08x\n", data->rootCmplxStatus); + pr_info(" busAgentStatus: %08x\n", data->busAgentStatus); + + pr_info(" deviceStatus: %08x\n", data->deviceStatus); + pr_info(" slotStatus: %08x\n", data->slotStatus); + pr_info(" linkStatus: %08x\n", data->linkStatus); + pr_info(" devCmdStatus: %08x\n", data->devCmdStatus); + pr_info(" devSecStatus: %08x\n", data->devSecStatus); + + pr_info(" rootErrorStatus: %08x\n", data->rootErrorStatus); + pr_info(" uncorrErrorStatus: %08x\n", data->uncorrErrorStatus); + pr_info(" corrErrorStatus: %08x\n", data->corrErrorStatus); + pr_info(" tlpHdr1: %08x\n", data->tlpHdr1); + pr_info(" tlpHdr2: %08x\n", data->tlpHdr2); + pr_info(" tlpHdr3: %08x\n", data->tlpHdr3); + pr_info(" tlpHdr4: %08x\n", data->tlpHdr4); + pr_info(" sourceId: %08x\n", data->sourceId); + pr_info(" errorClass: %016llx\n", data->errorClass); + pr_info(" correlator: %016llx\n", data->correlator); + + pr_info(" nFir: %016llx\n", data->nFir); + pr_info(" nFirMask: %016llx\n", data->nFirMask); + pr_info(" nFirWOF: %016llx\n", data->nFirWOF); + pr_info(" PhbPlssr: %016llx\n", data->phbPlssr); + pr_info(" PhbCsr: %016llx\n", data->phbCsr); + pr_info(" lemFir: %016llx\n", data->lemFir); + pr_info(" lemErrorMask: %016llx\n", data->lemErrorMask); + pr_info(" lemWOF: %016llx\n", data->lemWOF); + pr_info(" phbErrorStatus: %016llx\n", data->phbErrorStatus); + pr_info(" phbFirstErrorStatus: %016llx\n", data->phbFirstErrorStatus); + pr_info(" phbErrorLog0: %016llx\n", data->phbErrorLog0); + pr_info(" phbErrorLog1: %016llx\n", data->phbErrorLog1); + pr_info(" mmioErrorStatus: %016llx\n", data->mmioErrorStatus); + pr_info(" mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus); + pr_info(" mmioErrorLog0: %016llx\n", data->mmioErrorLog0); + pr_info(" mmioErrorLog1: %016llx\n", data->mmioErrorLog1); + pr_info(" dma0ErrorStatus: %016llx\n", data->dma0ErrorStatus); + pr_info(" dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus); + pr_info(" dma0ErrorLog0: %016llx\n", data->dma0ErrorLog0); + pr_info(" dma0ErrorLog1: %016llx\n", data->dma0ErrorLog1); + pr_info(" dma1ErrorStatus: %016llx\n", data->dma1ErrorStatus); + pr_info(" dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus); + pr_info(" dma1ErrorLog0: %016llx\n", data->dma1ErrorLog0); + pr_info(" dma1ErrorLog1: %016llx\n", data->dma1ErrorLog1); + + for (i = 0; i < OPAL_PHB3_NUM_PEST_REGS; i++) { + if ((data->pestA[i] >> 63) == 0 && + (data->pestB[i] >> 63) == 0) + continue; + + pr_info(" PE[%3d] PESTA: %016llx\n", i, data->pestA[i]); + pr_info(" PESTB: %016llx\n", data->pestB[i]); + } +} + +void pnv_pci_dump_phb_diag_data(struct pci_controller *hose, + unsigned char *log_buff) +{ + struct OpalIoPhbErrorCommon *common; + + if (!hose || !log_buff) + return; + + common = (struct OpalIoPhbErrorCommon *)log_buff; + switch (common->ioType) { + case OPAL_PHB_ERROR_DATA_TYPE_P7IOC: + pnv_pci_dump_p7ioc_diag_data(hose, common); + break; + case OPAL_PHB_ERROR_DATA_TYPE_PHB3: + pnv_pci_dump_phb3_diag_data(hose, common); break; default: - pr_warning("PCI %d: Can't decode this PHB diag data\n", - phb->hose->global_number); + pr_warn("%s: Unrecognized ioType %d\n", + __func__, common->ioType); } } @@ -222,7 +302,7 @@ static void pnv_pci_handle_eeh_config(struct pnv_phb *phb, u32 pe_no) * with the normal errors generated when probing empty slots */ if (has_diag) - pnv_pci_dump_phb_diag_data(phb); + pnv_pci_dump_phb_diag_data(phb->hose, phb->diag.blob); else pr_warning("PCI %d: No diag data available\n", phb->hose->global_number); @@ -484,7 +564,8 @@ void pnv_pci_setup_iommu_table(struct iommu_table *tbl, { tbl->it_blocksize = 16; tbl->it_base = (unsigned long)tce_mem; - tbl->it_offset = dma_offset >> IOMMU_PAGE_SHIFT; + tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K; + tbl->it_offset = dma_offset >> tbl->it_page_shift; tbl->it_index = 0; tbl->it_size = tce_size >> 3; tbl->it_busno = 0; @@ -536,7 +617,7 @@ static void pnv_pci_dma_fallback_setup(struct pci_controller *hose, pdn->iommu_table = pnv_pci_setup_bml_iommu(hose); if (!pdn->iommu_table) return; - set_iommu_table_base(&pdev->dev, pdn->iommu_table); + set_iommu_table_base_and_group(&pdev->dev, pdn->iommu_table); } static void pnv_pci_dma_dev_setup(struct pci_dev *pdev) @@ -553,6 +634,16 @@ static void pnv_pci_dma_dev_setup(struct pci_dev *pdev) pnv_pci_dma_fallback_setup(hose, pdev); } +int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask) +{ + struct pci_controller *hose = pci_bus_to_host(pdev->bus); + struct pnv_phb *phb = hose->private_data; + + if (phb && phb->dma_set_mask) + return phb->dma_set_mask(phb, pdev, dma_mask); + return __dma_set_mask(&pdev->dev, dma_mask); +} + void pnv_pci_shutdown(void) { struct pci_controller *hose; @@ -657,3 +748,32 @@ void __init pnv_pci_init(void) ppc_md.teardown_msi_irqs = pnv_teardown_msi_irqs; #endif } + +static int tce_iommu_bus_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + + switch (action) { + case BUS_NOTIFY_ADD_DEVICE: + return iommu_add_device(dev); + case BUS_NOTIFY_DEL_DEVICE: + if (dev->iommu_group) + iommu_del_device(dev); + return 0; + default: + return 0; + } +} + +static struct notifier_block tce_iommu_bus_nb = { + .notifier_call = tce_iommu_bus_notifier, +}; + +static int __init tce_iommu_bus_notifier_init(void) +{ + bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb); + return 0; +} + +subsys_initcall_sync(tce_iommu_bus_notifier_init); diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 1ed8d5f40f5ad1..cde169442775c1 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -54,7 +54,9 @@ struct pnv_ioda_pe { struct iommu_table tce32_table; phys_addr_t tce_inval_reg_phys; - /* XXX TODO: Add support for additional 64-bit iommus */ + /* 64-bit TCE bypass region */ + bool tce_bypass_enabled; + uint64_t tce_bypass_base; /* MSIs. MVE index is identical for for 32 and 64 bit MSI * and -1 if not supported. (It's actually identical to the @@ -113,6 +115,8 @@ struct pnv_phb { unsigned int hwirq, unsigned int virq, unsigned int is_64, struct msi_msg *msg); void (*dma_dev_setup)(struct pnv_phb *phb, struct pci_dev *pdev); + int (*dma_set_mask)(struct pnv_phb *phb, struct pci_dev *pdev, + u64 dma_mask); void (*fixup_phb)(struct pci_controller *hose); u32 (*bdfn_to_pe)(struct pnv_phb *phb, struct pci_bus *bus, u32 devfn); void (*shutdown)(struct pnv_phb *phb); @@ -176,6 +180,7 @@ struct pnv_phb { union { unsigned char blob[PNV_PCI_DIAG_BUF_SIZE]; struct OpalIoP7IOCPhbErrorData p7ioc; + struct OpalIoPhb3ErrorData phb3; struct OpalIoP7IOCErrorData hub_diag; } diag; @@ -186,6 +191,8 @@ extern struct pci_ops pnv_pci_ops; extern struct pnv_eeh_ops ioda_eeh_ops; #endif +void pnv_pci_dump_phb_diag_data(struct pci_controller *hose, + unsigned char *log_buff); int pnv_pci_cfg_read(struct device_node *dn, int where, int size, u32 *val); int pnv_pci_cfg_write(struct device_node *dn, diff --git a/arch/powerpc/platforms/powernv/powernv.h b/arch/powerpc/platforms/powernv/powernv.h index de6819be1f95ea..0051e108ef0f86 100644 --- a/arch/powerpc/platforms/powernv/powernv.h +++ b/arch/powerpc/platforms/powernv/powernv.h @@ -7,12 +7,20 @@ extern void pnv_smp_init(void); static inline void pnv_smp_init(void) { } #endif +struct pci_dev; + #ifdef CONFIG_PCI extern void pnv_pci_init(void); extern void pnv_pci_shutdown(void); +extern int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask); #else static inline void pnv_pci_init(void) { } static inline void pnv_pci_shutdown(void) { } + +static inline int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask) +{ + return -ENODEV; +} #endif extern void pnv_lpc_init(void); diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 19884b2a51b474..110f4fbd319f62 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include @@ -140,13 +142,22 @@ static void pnv_progress(char *s, unsigned short hex) { } +static int pnv_dma_set_mask(struct device *dev, u64 dma_mask) +{ + if (dev_is_pci(dev)) + return pnv_pci_dma_set_mask(to_pci_dev(dev), dma_mask); + return __dma_set_mask(dev, dma_mask); +} + static void pnv_shutdown(void) { /* Let the PCI code clear up IODA tables */ pnv_pci_shutdown(); - /* And unregister all OPAL interrupts so they don't fire - * up while we kexec + /* + * Stop OPAL activity: Unregister all OPAL interrupts so they + * don't fire up while we kexec and make sure all potentially + * DMA'ing ops are complete (such as dump retrieval). */ opal_shutdown(); } @@ -214,6 +225,16 @@ static int __init pnv_probe(void) return 1; } +void powernv_idle(void) +{ + /* Hook to cpuidle framework if available, else + * call on default platform idle code + */ + if (cpuidle_idle_call()) { + power7_idle(); + } +} + define_machine(powernv) { .name = "PowerNV", .probe = pnv_probe, @@ -223,8 +244,9 @@ define_machine(powernv) { .show_cpuinfo = pnv_show_cpuinfo, .progress = pnv_progress, .machine_shutdown = pnv_shutdown, - .power_save = power7_idle, + .power_save = powernv_idle, .calibrate_decr = generic_calibrate_decr, + .dma_set_mask = pnv_dma_set_mask, #ifdef CONFIG_KEXEC .kexec_cpu_down = pnv_kexec_cpu_down, #endif diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index e17fa1432d8070..a0bca05e26b0c7 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c @@ -143,7 +143,7 @@ static void _dump_areas(unsigned int spe_id, unsigned long priv2, pr_debug("%s:%d: shadow: %lxh\n", func, line, shadow); } -inline u64 ps3_get_spe_id(void *arg) +u64 ps3_get_spe_id(void *arg) { return spu_pdata(arg)->spe_id; } diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 62b4f8025de005..80b1d57c306a99 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -20,6 +20,7 @@ config PPC_PSERIES select PPC_DOORBELL select HAVE_CONTEXT_TRACKING select HOTPLUG_CPU if SMP + select ARCH_RANDOM default y config PPC_SPLPAR @@ -34,7 +35,7 @@ config PPC_SPLPAR config PSERIES_MSI bool - depends on PCI_MSI && EEH + depends on PCI_MSI && PPC_PSERIES && EEH default y config PSERIES_ENERGY @@ -119,12 +120,3 @@ config DTL which are accessible through a debugfs file. Say N if you are unsure. - -config PSERIES_IDLE - bool "Cpuidle driver for pSeries platforms" - depends on CPU_IDLE - depends on PPC_PSERIES - default y - help - Select this option to enable processor idle state management - through cpuidle subsystem. diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index fbccac9cd2dc39..03480796af9a55 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -21,7 +21,6 @@ obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o obj-$(CONFIG_CMM) += cmm.o obj-$(CONFIG_DTL) += dtl.o obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o -obj-$(CONFIG_PSERIES_IDLE) += processor_idle.o obj-$(CONFIG_LPARCFG) += lparcfg.o ifeq ($(CONFIG_PPC_PSERIES),y) diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c index 1e561bef459b42..2d8bf15879fdd3 100644 --- a/arch/powerpc/platforms/pseries/cmm.c +++ b/arch/powerpc/platforms/pseries/cmm.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c index 5db66f1fbc2648..7d61498e45c082 100644 --- a/arch/powerpc/platforms/pseries/dtl.c +++ b/arch/powerpc/platforms/pseries/dtl.c @@ -20,7 +20,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c index ccb633e077b16d..8a8f0472d98fd0 100644 --- a/arch/powerpc/platforms/pseries/eeh_pseries.c +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c @@ -265,7 +265,7 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag) enable = 1; if (enable) { - eeh_subsystem_enabled = 1; + eeh_set_enable(true); eeh_add_to_parent_pe(edev); pr_debug("%s: EEH enabled on %s PHB#%d-PE#%x, config addr#%x\n", @@ -689,7 +689,9 @@ static struct eeh_ops pseries_eeh_ops = { .get_log = pseries_eeh_get_log, .configure_bridge = pseries_eeh_configure_bridge, .read_config = pseries_eeh_read_config, - .write_config = pseries_eeh_write_config + .write_config = pseries_eeh_write_config, + .next_error = NULL, + .restore_config = NULL }; /** diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index f253361552aee3..33b552ffbe576d 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -486,9 +486,10 @@ static void iommu_table_setparms(struct pci_controller *phb, memset((void *)tbl->it_base, 0, *sizep); tbl->it_busno = phb->bus->number; + tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K; /* Units of tce entries */ - tbl->it_offset = phb->dma_window_base_cur >> IOMMU_PAGE_SHIFT; + tbl->it_offset = phb->dma_window_base_cur >> tbl->it_page_shift; /* Test if we are going over 2GB of DMA space */ if (phb->dma_window_base_cur + phb->dma_window_size > 0x80000000ul) { @@ -499,7 +500,7 @@ static void iommu_table_setparms(struct pci_controller *phb, phb->dma_window_base_cur += phb->dma_window_size; /* Set the tce table size - measured in entries */ - tbl->it_size = phb->dma_window_size >> IOMMU_PAGE_SHIFT; + tbl->it_size = phb->dma_window_size >> tbl->it_page_shift; tbl->it_index = 0; tbl->it_blocksize = 16; @@ -537,11 +538,12 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb, of_parse_dma_window(dn, dma_window, &tbl->it_index, &offset, &size); tbl->it_busno = phb->bus->number; + tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K; tbl->it_base = 0; tbl->it_blocksize = 16; tbl->it_type = TCE_PCI; - tbl->it_offset = offset >> IOMMU_PAGE_SHIFT; - tbl->it_size = size >> IOMMU_PAGE_SHIFT; + tbl->it_offset = offset >> tbl->it_page_shift; + tbl->it_size = size >> tbl->it_page_shift; } static void pci_dma_bus_setup_pSeries(struct pci_bus *bus) @@ -687,7 +689,8 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev) iommu_table_setparms(phb, dn, tbl); PCI_DN(dn)->iommu_table = iommu_init_table(tbl, phb->node); iommu_register_group(tbl, pci_domain_nr(phb->bus), 0); - set_iommu_table_base(&dev->dev, PCI_DN(dn)->iommu_table); + set_iommu_table_base_and_group(&dev->dev, + PCI_DN(dn)->iommu_table); return; } @@ -699,7 +702,8 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev) dn = dn->parent; if (dn && PCI_DN(dn)) - set_iommu_table_base(&dev->dev, PCI_DN(dn)->iommu_table); + set_iommu_table_base_and_group(&dev->dev, + PCI_DN(dn)->iommu_table); else printk(KERN_WARNING "iommu: Device %s has no iommu table\n", pci_name(dev)); @@ -717,21 +721,6 @@ static int __init disable_ddw_setup(char *str) early_param("disable_ddw", disable_ddw_setup); -static inline void __remove_ddw(struct device_node *np, const u32 *ddw_avail, u64 liobn) -{ - int ret; - - ret = rtas_call(ddw_avail[2], 1, 1, NULL, liobn); - if (ret) - pr_warning("%s: failed to remove DMA window: rtas returned " - "%d to ibm,remove-pe-dma-window(%x) %llx\n", - np->full_name, ret, ddw_avail[2], liobn); - else - pr_debug("%s: successfully removed DMA window: rtas returned " - "%d to ibm,remove-pe-dma-window(%x) %llx\n", - np->full_name, ret, ddw_avail[2], liobn); -} - static void remove_ddw(struct device_node *np) { struct dynamic_dma_window_prop *dwp; @@ -761,7 +750,15 @@ static void remove_ddw(struct device_node *np) pr_debug("%s successfully cleared tces in window.\n", np->full_name); - __remove_ddw(np, ddw_avail, liobn); + ret = rtas_call(ddw_avail[2], 1, 1, NULL, liobn); + if (ret) + pr_warning("%s: failed to remove direct window: rtas returned " + "%d to ibm,remove-pe-dma-window(%x) %llx\n", + np->full_name, ret, ddw_avail[2], liobn); + else + pr_debug("%s: successfully removed direct window: rtas returned " + "%d to ibm,remove-pe-dma-window(%x) %llx\n", + np->full_name, ret, ddw_avail[2], liobn); delprop: ret = of_remove_property(np, win64); @@ -790,68 +787,33 @@ static u64 find_existing_ddw(struct device_node *pdn) return dma_addr; } -static void __restore_default_window(struct eeh_dev *edev, - u32 ddw_restore_token) -{ - u32 cfg_addr; - u64 buid; - int ret; - - /* - * Get the config address and phb buid of the PE window. - * Rely on eeh to retrieve this for us. - * Retrieve them from the pci device, not the node with the - * dma-window property - */ - cfg_addr = edev->config_addr; - if (edev->pe_config_addr) - cfg_addr = edev->pe_config_addr; - buid = edev->phb->buid; - - do { - ret = rtas_call(ddw_restore_token, 3, 1, NULL, cfg_addr, - BUID_HI(buid), BUID_LO(buid)); - } while (rtas_busy_delay(ret)); - pr_info("ibm,reset-pe-dma-windows(%x) %x %x %x returned %d\n", - ddw_restore_token, cfg_addr, BUID_HI(buid), BUID_LO(buid), ret); -} - static int find_existing_ddw_windows(void) { + int len; struct device_node *pdn; + struct direct_window *window; const struct dynamic_dma_window_prop *direct64; - const u32 *ddw_extensions; if (!firmware_has_feature(FW_FEATURE_LPAR)) return 0; for_each_node_with_property(pdn, DIRECT64_PROPNAME) { - direct64 = of_get_property(pdn, DIRECT64_PROPNAME, NULL); + direct64 = of_get_property(pdn, DIRECT64_PROPNAME, &len); if (!direct64) continue; - /* - * We need to ensure the IOMMU table is active when we - * return from the IOMMU setup so that the common code - * can clear the table or find the holes. To that end, - * first, remove any existing DDW configuration. - */ - remove_ddw(pdn); + window = kzalloc(sizeof(*window), GFP_KERNEL); + if (!window || len < sizeof(struct dynamic_dma_window_prop)) { + kfree(window); + remove_ddw(pdn); + continue; + } - /* - * Second, if we are running on a new enough level of - * firmware where the restore API is present, use it to - * restore the 32-bit window, which was removed in - * create_ddw. - * If the API is not present, then create_ddw couldn't - * have removed the 32-bit window in the first place, so - * removing the DDW configuration should be sufficient. - */ - ddw_extensions = of_get_property(pdn, "ibm,ddw-extensions", - NULL); - if (ddw_extensions && ddw_extensions[0] > 0) - __restore_default_window(of_node_to_eeh_dev(pdn), - ddw_extensions[1]); + window->device = pdn; + window->prop = direct64; + spin_lock(&direct_window_list_lock); + list_add(&window->list, &direct_window_list); + spin_unlock(&direct_window_list_lock); } return 0; @@ -921,12 +883,6 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail, return ret; } -static void restore_default_window(struct pci_dev *dev, - u32 ddw_restore_token) -{ - __restore_default_window(pci_dev_to_eeh_dev(dev), ddw_restore_token); -} - struct failed_ddw_pdn { struct device_node *pdn; struct list_head list; @@ -954,13 +910,9 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) u64 dma_addr, max_addr; struct device_node *dn; const u32 *uninitialized_var(ddw_avail); - const u32 *uninitialized_var(ddw_extensions); - u32 ddw_restore_token = 0; struct direct_window *window; struct property *win64; struct dynamic_dma_window_prop *ddwprop; - const void *dma_window = NULL; - unsigned long liobn, offset, size; struct failed_ddw_pdn *fpdn; mutex_lock(&direct_window_init_mutex); @@ -991,42 +943,9 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) */ ddw_avail = of_get_property(pdn, "ibm,ddw-applicable", &len); if (!ddw_avail || len < 3 * sizeof(u32)) - goto out_unlock; - - /* - * the extensions property is only required to exist in certain - * levels of firmware and later - * the ibm,ddw-extensions property is a list with the first - * element containing the number of extensions and each - * subsequent entry is a value corresponding to that extension - */ - ddw_extensions = of_get_property(pdn, "ibm,ddw-extensions", &len); - if (ddw_extensions) { - /* - * each new defined extension length should be added to - * the top of the switch so the "earlier" entries also - * get picked up - */ - switch (ddw_extensions[0]) { - /* ibm,reset-pe-dma-windows */ - case 1: - ddw_restore_token = ddw_extensions[1]; - break; - } - } - - /* - * Only remove the existing DMA window if we can restore back to - * the default state. Removing the existing window maximizes the - * resources available to firmware for dynamic window creation. - */ - if (ddw_restore_token) { - dma_window = of_get_property(pdn, "ibm,dma-window", NULL); - of_parse_dma_window(pdn, dma_window, &liobn, &offset, &size); - __remove_ddw(pdn, ddw_avail, liobn); - } + goto out_failed; - /* + /* * Query if there is a second window of size to map the * whole partition. Query returns number of windows, largest * block assigned to PE (partition endpoint), and two bitmasks @@ -1035,7 +954,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) dn = pci_device_to_OF_node(dev); ret = query_ddw(dev, ddw_avail, &query); if (ret != 0) - goto out_restore_window; + goto out_failed; if (query.windows_available == 0) { /* @@ -1044,7 +963,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) * trading in for a larger page size. */ dev_dbg(&dev->dev, "no free dynamic windows"); - goto out_restore_window; + goto out_failed; } if (be32_to_cpu(query.page_size) & 4) { page_shift = 24; /* 16MB */ @@ -1055,7 +974,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) } else { dev_dbg(&dev->dev, "no supported direct page size in mask %x", query.page_size); - goto out_restore_window; + goto out_failed; } /* verify the window * number of ptes will map the partition */ /* check largest block * page size > max memory hotplug addr */ @@ -1064,14 +983,14 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) dev_dbg(&dev->dev, "can't map partiton max 0x%llx with %u " "%llu-sized pages\n", max_addr, query.largest_available_block, 1ULL << page_shift); - goto out_restore_window; + goto out_failed; } len = order_base_2(max_addr); win64 = kzalloc(sizeof(struct property), GFP_KERNEL); if (!win64) { dev_info(&dev->dev, "couldn't allocate property for 64bit dma window\n"); - goto out_restore_window; + goto out_failed; } win64->name = kstrdup(DIRECT64_PROPNAME, GFP_KERNEL); win64->value = ddwprop = kmalloc(sizeof(*ddwprop), GFP_KERNEL); @@ -1133,9 +1052,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) kfree(win64->value); kfree(win64); -out_restore_window: - if (ddw_restore_token) - restore_default_window(dev, ddw_restore_token); +out_failed: fpdn = kzalloc(sizeof(*fpdn), GFP_KERNEL); if (!fpdn) @@ -1193,7 +1110,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) pr_debug(" found DMA window, table: %p\n", pci->iommu_table); } - set_iommu_table_base(&dev->dev, pci->iommu_table); + set_iommu_table_base_and_group(&dev->dev, pci->iommu_table); } static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask) diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 4fca3def9db951..b02af9ef3ff61a 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -92,7 +92,7 @@ void vpa_init(int cpu) * PAPR says this feature is SLB-Buffer but firmware never * reports that. All SPLPAR support SLB shadow buffer. */ - addr = __pa(&slb_shadow[cpu]); + addr = __pa(paca[cpu].slb_shadow_ptr); if (firmware_has_feature(FW_FEATURE_SPLPAR)) { ret = register_slb_shadow(hwcpu, addr); if (ret) @@ -153,7 +153,8 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group, /* Make pHyp happy */ if ((rflags & _PAGE_NO_CACHE) && !(rflags & _PAGE_WRITETHRU)) - hpte_r &= ~_PAGE_COHERENT; + hpte_r &= ~HPTE_R_M; + if (firmware_has_feature(FW_FEATURE_XCMO) && !(hpte_r & HPTE_R_N)) flags |= H_COALESCE_CAND; diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c index 70670a2d9cf2dd..c413ec158ff5a6 100644 --- a/arch/powerpc/platforms/pseries/pci.c +++ b/arch/powerpc/platforms/pseries/pci.c @@ -113,7 +113,8 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge) { struct device_node *dn, *pdn; struct pci_bus *bus; - const __be32 *pcie_link_speed_stats; + u32 pcie_link_speed_stats[2]; + int rc; bus = bridge->bus; @@ -122,38 +123,45 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge) return 0; for (pdn = dn; pdn != NULL; pdn = of_get_next_parent(pdn)) { - pcie_link_speed_stats = of_get_property(pdn, - "ibm,pcie-link-speed-stats", NULL); - if (pcie_link_speed_stats) + rc = of_property_read_u32_array(pdn, + "ibm,pcie-link-speed-stats", + &pcie_link_speed_stats[0], 2); + if (!rc) break; } of_node_put(pdn); - if (!pcie_link_speed_stats) { + if (rc) { pr_err("no ibm,pcie-link-speed-stats property\n"); return 0; } - switch (be32_to_cpup(pcie_link_speed_stats)) { + switch (pcie_link_speed_stats[0]) { case 0x01: bus->max_bus_speed = PCIE_SPEED_2_5GT; break; case 0x02: bus->max_bus_speed = PCIE_SPEED_5_0GT; break; + case 0x04: + bus->max_bus_speed = PCIE_SPEED_8_0GT; + break; default: bus->max_bus_speed = PCI_SPEED_UNKNOWN; break; } - switch (be32_to_cpup(pcie_link_speed_stats)) { + switch (pcie_link_speed_stats[1]) { case 0x01: bus->cur_bus_speed = PCIE_SPEED_2_5GT; break; case 0x02: bus->cur_bus_speed = PCIE_SPEED_5_0GT; break; + case 0x04: + bus->cur_bus_speed = PCIE_SPEED_8_0GT; + break; default: bus->cur_bus_speed = PCI_SPEED_UNKNOWN; break; diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 6f76ae417f47e5..972df0ffd4dcc4 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -72,7 +72,7 @@ int CMO_PrPSP = -1; int CMO_SecPSP = -1; -unsigned long CMO_PageSize = (ASM_CONST(1) << IOMMU_PAGE_SHIFT); +unsigned long CMO_PageSize = (ASM_CONST(1) << IOMMU_PAGE_SHIFT_4K); EXPORT_SYMBOL(CMO_PageSize); int fwnmi_active; /* TRUE if an FWNMI handler is present */ @@ -430,8 +430,7 @@ static void pSeries_machine_kexec(struct kimage *image) { long rc; - if (firmware_has_feature(FW_FEATURE_SET_MODE) && - (image->type != KEXEC_TYPE_CRASH)) { + if (firmware_has_feature(FW_FEATURE_SET_MODE)) { rc = pSeries_disable_reloc_on_exc(); if (rc != H_SUCCESS) pr_warning("Warning: Failed to disable relocation on " @@ -569,7 +568,7 @@ void pSeries_cmo_feature_init(void) { char *ptr, *key, *value, *end; int call_status; - int page_order = IOMMU_PAGE_SHIFT; + int page_order = IOMMU_PAGE_SHIFT_4K; pr_debug(" -> fw_cmo_feature_init()\n"); spin_lock(&rtas_data_buf_lock); diff --git a/arch/powerpc/platforms/wsp/wsp_pci.c b/arch/powerpc/platforms/wsp/wsp_pci.c index 62cb527493e774..9a15e5b39bb851 100644 --- a/arch/powerpc/platforms/wsp/wsp_pci.c +++ b/arch/powerpc/platforms/wsp/wsp_pci.c @@ -260,7 +260,7 @@ static int tce_build_wsp(struct iommu_table *tbl, long index, long npages, *tcep = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; dma_debug("[DMA] TCE %p set to 0x%016llx (dma addr: 0x%lx)\n", - tcep, *tcep, (tbl->it_offset + index) << IOMMU_PAGE_SHIFT); + tcep, *tcep, (tbl->it_offset + index) << IOMMU_PAGE_SHIFT_4K); uaddr += TCE_PAGE_SIZE; index++; @@ -381,8 +381,9 @@ static struct wsp_dma_table *wsp_pci_create_dma32_table(struct wsp_phb *phb, /* Init bits and pieces */ tbl->table.it_blocksize = 16; - tbl->table.it_offset = addr >> IOMMU_PAGE_SHIFT; - tbl->table.it_size = size >> IOMMU_PAGE_SHIFT; + tbl->table.it_page_shift = IOMMU_PAGE_SHIFT_4K; + tbl->table.it_offset = addr >> tbl->table.it_page_shift; + tbl->table.it_size = size >> tbl->table.it_page_shift; /* * It's already blank but we clear it anyway. @@ -449,8 +450,8 @@ static void wsp_pci_dma_dev_setup(struct pci_dev *pdev) if (table) { pr_info("%s: Setup iommu: 32-bit DMA region 0x%08lx..0x%08lx\n", pci_name(pdev), - table->table.it_offset << IOMMU_PAGE_SHIFT, - (table->table.it_offset << IOMMU_PAGE_SHIFT) + table->table.it_offset << IOMMU_PAGE_SHIFT_4K, + (table->table.it_offset << IOMMU_PAGE_SHIFT_4K) + phb->dma32_region_size - 1); archdata->dma_data.iommu_table_base = &table->table; return; diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig index 13ec968be4c7a2..7baa70d6dc016c 100644 --- a/arch/powerpc/sysdev/Kconfig +++ b/arch/powerpc/sysdev/Kconfig @@ -19,7 +19,7 @@ config PPC_MSI_BITMAP default y if MPIC default y if FSL_PCI default y if PPC4xx_MSI - default y if POWERNV_MSI + default y if PPC_POWERNV source "arch/powerpc/sysdev/xics/Kconfig" diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index 1c16141c031c9e..47b6b9f81d4305 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -109,27 +109,28 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio) struct axon_ram_bank *bank = bio->bi_bdev->bd_disk->private_data; unsigned long phys_mem, phys_end; void *user_mem; - struct bio_vec *vec; + struct bio_vec vec; unsigned int transfered; - unsigned short idx; + struct bvec_iter iter; - phys_mem = bank->io_addr + (bio->bi_sector << AXON_RAM_SECTOR_SHIFT); + phys_mem = bank->io_addr + (bio->bi_iter.bi_sector << + AXON_RAM_SECTOR_SHIFT); phys_end = bank->io_addr + bank->size; transfered = 0; - bio_for_each_segment(vec, bio, idx) { - if (unlikely(phys_mem + vec->bv_len > phys_end)) { + bio_for_each_segment(vec, bio, iter) { + if (unlikely(phys_mem + vec.bv_len > phys_end)) { bio_io_error(bio); return; } - user_mem = page_address(vec->bv_page) + vec->bv_offset; + user_mem = page_address(vec.bv_page) + vec.bv_offset; if (bio_data_dir(bio) == READ) - memcpy(user_mem, (void *) phys_mem, vec->bv_len); + memcpy(user_mem, (void *) phys_mem, vec.bv_len); else - memcpy((void *) phys_mem, user_mem, vec->bv_len); + memcpy((void *) phys_mem, user_mem, vec.bv_len); - phys_mem += vec->bv_len; - transfered += vec->bv_len; + phys_mem += vec.bv_len; + transfered += vec.bv_len; } bio_endio(bio, 0); } diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index 10386b676d8758..a11bd1d433adf7 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c @@ -27,7 +27,6 @@ */ #include -#include #include #include #include diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c index bd968a43a48b29..62c47bb765178a 100644 --- a/arch/powerpc/sysdev/dart_iommu.c +++ b/arch/powerpc/sysdev/dart_iommu.c @@ -292,6 +292,7 @@ static void iommu_table_dart_setup(void) iommu_table_dart.it_offset = 0; /* it_size is in number of entries */ iommu_table_dart.it_size = dart_tablesize / sizeof(u32); + iommu_table_dart.it_page_shift = IOMMU_PAGE_SHIFT_4K; /* Initialize the common IOMMU code */ iommu_table_dart.it_base = (unsigned long)dart_vbase; diff --git a/arch/powerpc/sysdev/fsl_ifc.c b/arch/powerpc/sysdev/fsl_ifc.c index d7fc7223914487..fbc885b3194690 100644 --- a/arch/powerpc/sysdev/fsl_ifc.c +++ b/arch/powerpc/sysdev/fsl_ifc.c @@ -19,7 +19,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c index 6bc5a546d49fad..d631022ffb4b3c 100644 --- a/arch/powerpc/sysdev/fsl_lbc.c +++ b/arch/powerpc/sysdev/fsl_lbc.c @@ -214,10 +214,14 @@ static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data) struct fsl_lbc_ctrl *ctrl = data; struct fsl_lbc_regs __iomem *lbc = ctrl->regs; u32 status; + unsigned long flags; + spin_lock_irqsave(&fsl_lbc_lock, flags); status = in_be32(&lbc->ltesr); - if (!status) + if (!status) { + spin_unlock_irqrestore(&fsl_lbc_lock, flags); return IRQ_NONE; + } out_be32(&lbc->ltesr, LTESR_CLEAR); out_be32(&lbc->lteatr, 0); @@ -260,6 +264,7 @@ static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data) if (status & ~LTESR_MASK) dev_err(ctrl->dev, "Unknown error: " "LTESR 0x%08X\n", status); + spin_unlock_irqrestore(&fsl_lbc_lock, flags); return IRQ_HANDLED; } @@ -298,8 +303,8 @@ static int fsl_lbc_ctrl_probe(struct platform_device *dev) goto err; } - fsl_lbc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0); - if (fsl_lbc_ctrl_dev->irq == NO_IRQ) { + fsl_lbc_ctrl_dev->irq[0] = irq_of_parse_and_map(dev->dev.of_node, 0); + if (!fsl_lbc_ctrl_dev->irq[0]) { dev_err(&dev->dev, "failed to get irq resource\n"); ret = -ENODEV; goto err; @@ -311,20 +316,34 @@ static int fsl_lbc_ctrl_probe(struct platform_device *dev) if (ret < 0) goto err; - ret = request_irq(fsl_lbc_ctrl_dev->irq, fsl_lbc_ctrl_irq, 0, + ret = request_irq(fsl_lbc_ctrl_dev->irq[0], fsl_lbc_ctrl_irq, 0, "fsl-lbc", fsl_lbc_ctrl_dev); if (ret != 0) { dev_err(&dev->dev, "failed to install irq (%d)\n", - fsl_lbc_ctrl_dev->irq); - ret = fsl_lbc_ctrl_dev->irq; + fsl_lbc_ctrl_dev->irq[0]); + ret = fsl_lbc_ctrl_dev->irq[0]; goto err; } + fsl_lbc_ctrl_dev->irq[1] = irq_of_parse_and_map(dev->dev.of_node, 1); + if (fsl_lbc_ctrl_dev->irq[1]) { + ret = request_irq(fsl_lbc_ctrl_dev->irq[1], fsl_lbc_ctrl_irq, + IRQF_SHARED, "fsl-lbc-err", fsl_lbc_ctrl_dev); + if (ret) { + dev_err(&dev->dev, "failed to install irq (%d)\n", + fsl_lbc_ctrl_dev->irq[1]); + ret = fsl_lbc_ctrl_dev->irq[1]; + goto err1; + } + } + /* Enable interrupts for any detected events */ out_be32(&fsl_lbc_ctrl_dev->regs->lteir, LTEIR_ENABLE); return 0; +err1: + free_irq(fsl_lbc_ctrl_dev->irq[0], fsl_lbc_ctrl_dev); err: iounmap(fsl_lbc_ctrl_dev->regs); kfree(fsl_lbc_ctrl_dev); diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 4dfd61df8aba99..a625dcf26b2b7c 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -122,7 +122,7 @@ static int fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask) * address width of the SoC such that we can address any internal * SoC address from across PCI if needed */ - if ((dev->bus == &pci_bus_type) && + if ((dev_is_pci(dev)) && dma_mask >= DMA_BIT_MASK(MAX_PHYS_ADDR_BITS)) { set_dma_ops(dev, &dma_direct_ops); set_dma_offset(dev, pci64_dma_offset); @@ -454,7 +454,7 @@ void fsl_pcibios_fixup_bus(struct pci_bus *bus) } } -int __init fsl_add_bridge(struct platform_device *pdev, int is_primary) +int fsl_add_bridge(struct platform_device *pdev, int is_primary) { int len; struct pci_controller *hose; @@ -1035,6 +1035,7 @@ static const struct of_device_id pci_ids[] = { { .compatible = "fsl,mpc8548-pcie", }, { .compatible = "fsl,mpc8610-pci", }, { .compatible = "fsl,mpc8641-pcie", }, + { .compatible = "fsl,qoriq-pcie", }, { .compatible = "fsl,qoriq-pcie-v2.1", }, { .compatible = "fsl,qoriq-pcie-v2.2", }, { .compatible = "fsl,qoriq-pcie-v2.3", }, diff --git a/arch/powerpc/sysdev/ge/ge_pic.h b/arch/powerpc/sysdev/ge/ge_pic.h index 6149916da3f48c..908dbd9826b6e1 100644 --- a/arch/powerpc/sysdev/ge/ge_pic.h +++ b/arch/powerpc/sysdev/ge/ge_pic.h @@ -1,7 +1,6 @@ #ifndef __GEF_PIC_H__ #define __GEF_PIC_H__ -#include void gef_pic_cascade(unsigned int, struct irq_desc *); unsigned int gef_pic_get_irq(void); diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c index 997df6a7ab5d19..45598da0b32142 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c @@ -8,7 +8,6 @@ */ #undef DEBUG -#include #include #include #include diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c index c6c8b526a4f6e5..1f6c570d66d45e 100644 --- a/arch/powerpc/sysdev/indirect_pci.c +++ b/arch/powerpc/sysdev/indirect_pci.c @@ -152,10 +152,8 @@ static struct pci_ops indirect_pci_ops = .write = indirect_write_config, }; -void __init -setup_indirect_pci(struct pci_controller* hose, - resource_size_t cfg_addr, - resource_size_t cfg_data, u32 flags) +void setup_indirect_pci(struct pci_controller *hose, resource_size_t cfg_addr, + resource_size_t cfg_data, u32 flags) { resource_size_t base = cfg_addr & PAGE_MASK; void __iomem *mbase; diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index b724622c3a0b74..c4828c0be5bd86 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 0e166ed4cd16b7..8209744b28290b 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -886,25 +886,25 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) /* Default: read HW settings */ if (flow_type == IRQ_TYPE_DEFAULT) { - switch(vold & (MPIC_INFO(VECPRI_POLARITY_MASK) | - MPIC_INFO(VECPRI_SENSE_MASK))) { - case MPIC_INFO(VECPRI_SENSE_EDGE) | - MPIC_INFO(VECPRI_POLARITY_POSITIVE): - flow_type = IRQ_TYPE_EDGE_RISING; - break; - case MPIC_INFO(VECPRI_SENSE_EDGE) | - MPIC_INFO(VECPRI_POLARITY_NEGATIVE): - flow_type = IRQ_TYPE_EDGE_FALLING; - break; - case MPIC_INFO(VECPRI_SENSE_LEVEL) | - MPIC_INFO(VECPRI_POLARITY_POSITIVE): - flow_type = IRQ_TYPE_LEVEL_HIGH; - break; - case MPIC_INFO(VECPRI_SENSE_LEVEL) | - MPIC_INFO(VECPRI_POLARITY_NEGATIVE): - flow_type = IRQ_TYPE_LEVEL_LOW; - break; - } + int vold_ps; + + vold_ps = vold & (MPIC_INFO(VECPRI_POLARITY_MASK) | + MPIC_INFO(VECPRI_SENSE_MASK)); + + if (vold_ps == (MPIC_INFO(VECPRI_SENSE_EDGE) | + MPIC_INFO(VECPRI_POLARITY_POSITIVE))) + flow_type = IRQ_TYPE_EDGE_RISING; + else if (vold_ps == (MPIC_INFO(VECPRI_SENSE_EDGE) | + MPIC_INFO(VECPRI_POLARITY_NEGATIVE))) + flow_type = IRQ_TYPE_EDGE_FALLING; + else if (vold_ps == (MPIC_INFO(VECPRI_SENSE_LEVEL) | + MPIC_INFO(VECPRI_POLARITY_POSITIVE))) + flow_type = IRQ_TYPE_LEVEL_HIGH; + else if (vold_ps == (MPIC_INFO(VECPRI_SENSE_LEVEL) | + MPIC_INFO(VECPRI_POLARITY_NEGATIVE))) + flow_type = IRQ_TYPE_LEVEL_LOW; + else + WARN_ONCE(1, "mpic: unknown IRQ type %d\n", vold); } /* Apply to irq desc */ diff --git a/arch/powerpc/sysdev/mpic_timer.c b/arch/powerpc/sysdev/mpic_timer.c index 22d7d57eead9d8..9d9b06217f8b9d 100644 --- a/arch/powerpc/sysdev/mpic_timer.c +++ b/arch/powerpc/sysdev/mpic_timer.c @@ -41,6 +41,7 @@ #define MPIC_TIMER_TCR_ROVR_OFFSET 24 #define TIMER_STOP 0x80000000 +#define GTCCR_TOG 0x80000000 #define TIMERS_PER_GROUP 4 #define MAX_TICKS (~0U >> 1) #define MAX_TICKS_CASCADE (~0U) @@ -96,8 +97,11 @@ static void convert_ticks_to_time(struct timer_group_priv *priv, time->tv_sec = (__kernel_time_t)div_u64(ticks, priv->timerfreq); tmp_sec = (u64)time->tv_sec * (u64)priv->timerfreq; - time->tv_usec = (__kernel_suseconds_t) - div_u64((ticks - tmp_sec) * 1000000, priv->timerfreq); + time->tv_usec = 0; + + if (tmp_sec <= ticks) + time->tv_usec = (__kernel_suseconds_t) + div_u64((ticks - tmp_sec) * 1000000, priv->timerfreq); return; } @@ -327,11 +331,13 @@ void mpic_get_remain_time(struct mpic_timer *handle, struct timeval *time) casc_priv = priv->timer[handle->num].cascade_handle; if (casc_priv) { tmp_ticks = in_be32(&priv->regs[handle->num].gtccr); + tmp_ticks &= ~GTCCR_TOG; ticks = ((u64)tmp_ticks & UINT_MAX) * (u64)MAX_TICKS_CASCADE; tmp_ticks = in_be32(&priv->regs[handle->num - 1].gtccr); ticks += tmp_ticks; } else { ticks = in_be32(&priv->regs[handle->num].gtccr); + ticks &= ~GTCCR_TOG; } convert_ticks_to_time(priv, ticks, time); diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c index a88807b3dd578b..d09994164dafd3 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_io.c +++ b/arch/powerpc/sysdev/qe_lib/qe_io.c @@ -16,7 +16,6 @@ #include #include -#include #include #include #include diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c index 134b07d2943564..621575b7e84aa3 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc.c +++ b/arch/powerpc/sysdev/qe_lib/ucc.c @@ -14,7 +14,6 @@ * option) any later version. */ #include -#include #include #include #include diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c index cceb2e366738f9..65aaf15032aee2 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc_fast.c +++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c @@ -13,7 +13,6 @@ * option) any later version. */ #include -#include #include #include #include diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c index 1c062f48f1ac87..befaf1123f7f0c 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc_slow.c +++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c @@ -13,7 +13,6 @@ * option) any later version. */ #include -#include #include #include #include diff --git a/arch/powerpc/sysdev/udbg_memcons.c b/arch/powerpc/sysdev/udbg_memcons.c index ce5a7b489e4b42..9998c0de12d056 100644 --- a/arch/powerpc/sysdev/udbg_memcons.c +++ b/arch/powerpc/sysdev/udbg_memcons.c @@ -18,7 +18,6 @@ * 2 of the License, or (at your option) any later version. */ -#include #include #include #include diff --git a/arch/powerpc/sysdev/xics/icp-hv.c b/arch/powerpc/sysdev/xics/icp-hv.c index df0fc582146976..c1917cf67c3ded 100644 --- a/arch/powerpc/sysdev/xics/icp-hv.c +++ b/arch/powerpc/sysdev/xics/icp-hv.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index af9d3469fb9933..b07909850f7715 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -309,16 +309,23 @@ static void get_output_lock(void) if (xmon_speaker == me) return; + for (;;) { - if (xmon_speaker == 0) { - last_speaker = cmpxchg(&xmon_speaker, 0, me); - if (last_speaker == 0) - return; - } - timeout = 10000000; + last_speaker = cmpxchg(&xmon_speaker, 0, me); + if (last_speaker == 0) + return; + + /* + * Wait a full second for the lock, we might be on a slow + * console, but check every 100us. + */ + timeout = 10000; while (xmon_speaker == last_speaker) { - if (--timeout > 0) + if (--timeout > 0) { + udelay(100); continue; + } + /* hostile takeover */ prev = cmpxchg(&xmon_speaker, last_speaker, me); if (prev == last_speaker) @@ -397,7 +404,6 @@ static int xmon_core(struct pt_regs *regs, int fromipi) } xmon_fault_jmp[cpu] = recurse_jmp; - cpumask_set_cpu(cpu, &cpus_in_xmon); bp = NULL; if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) @@ -419,6 +425,8 @@ static int xmon_core(struct pt_regs *regs, int fromipi) release_output_lock(); } + cpumask_set_cpu(cpu, &cpus_in_xmon); + waiting: secondary = 1; while (secondary && !xmon_gate) { @@ -2051,6 +2059,10 @@ static void dump_one_paca(int cpu) DUMP(p, stab_addr, "lx"); #endif DUMP(p, emergency_sp, "p"); +#ifdef CONFIG_PPC_BOOK3S_64 + DUMP(p, mc_emergency_sp, "p"); + DUMP(p, in_mce, "x"); +#endif DUMP(p, data_offset, "lx"); DUMP(p, hw_cpu_id, "x"); DUMP(p, cpu_start, "x"); diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 4f858f77d870d8..65a07750f4f946 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -596,7 +596,7 @@ config CRASH_DUMP config ZFCPDUMP def_bool n prompt "zfcpdump support" - depends on SMP + depends on 64BIT && SMP help Select this option if you want to build an zfcpdump enabled kernel. Refer to for more details on this. diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index 4c4a1cef52087b..47c8630c93cdd6 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -529,6 +529,7 @@ static int __init appldata_init(void) { int rc; + init_virt_timer(&appldata_timer); appldata_timer.function = appldata_timer_function; appldata_timer.data = (unsigned long) &appldata_work; diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index b3feabd39f31f8..cf3c0089bef253 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "crypt_s390.h" #define AES_KEYLEN_128 1 @@ -32,6 +33,7 @@ #define AES_KEYLEN_256 4 static u8 *ctrblk; +static DEFINE_SPINLOCK(ctrblk_lock); static char keylen_flag; struct s390_aes_ctx { @@ -758,43 +760,67 @@ static int ctr_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, return aes_set_key(tfm, in_key, key_len); } +static unsigned int __ctrblk_init(u8 *ctrptr, unsigned int nbytes) +{ + unsigned int i, n; + + /* only use complete blocks, max. PAGE_SIZE */ + n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : nbytes & ~(AES_BLOCK_SIZE - 1); + for (i = AES_BLOCK_SIZE; i < n; i += AES_BLOCK_SIZE) { + memcpy(ctrptr + i, ctrptr + i - AES_BLOCK_SIZE, + AES_BLOCK_SIZE); + crypto_inc(ctrptr + i, AES_BLOCK_SIZE); + } + return n; +} + static int ctr_aes_crypt(struct blkcipher_desc *desc, long func, struct s390_aes_ctx *sctx, struct blkcipher_walk *walk) { int ret = blkcipher_walk_virt_block(desc, walk, AES_BLOCK_SIZE); - unsigned int i, n, nbytes; - u8 buf[AES_BLOCK_SIZE]; - u8 *out, *in; + unsigned int n, nbytes; + u8 buf[AES_BLOCK_SIZE], ctrbuf[AES_BLOCK_SIZE]; + u8 *out, *in, *ctrptr = ctrbuf; if (!walk->nbytes) return ret; - memcpy(ctrblk, walk->iv, AES_BLOCK_SIZE); + if (spin_trylock(&ctrblk_lock)) + ctrptr = ctrblk; + + memcpy(ctrptr, walk->iv, AES_BLOCK_SIZE); while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) { out = walk->dst.virt.addr; in = walk->src.virt.addr; while (nbytes >= AES_BLOCK_SIZE) { - /* only use complete blocks, max. PAGE_SIZE */ - n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : - nbytes & ~(AES_BLOCK_SIZE - 1); - for (i = AES_BLOCK_SIZE; i < n; i += AES_BLOCK_SIZE) { - memcpy(ctrblk + i, ctrblk + i - AES_BLOCK_SIZE, - AES_BLOCK_SIZE); - crypto_inc(ctrblk + i, AES_BLOCK_SIZE); - } - ret = crypt_s390_kmctr(func, sctx->key, out, in, n, ctrblk); - if (ret < 0 || ret != n) + if (ctrptr == ctrblk) + n = __ctrblk_init(ctrptr, nbytes); + else + n = AES_BLOCK_SIZE; + ret = crypt_s390_kmctr(func, sctx->key, out, in, + n, ctrptr); + if (ret < 0 || ret != n) { + if (ctrptr == ctrblk) + spin_unlock(&ctrblk_lock); return -EIO; + } if (n > AES_BLOCK_SIZE) - memcpy(ctrblk, ctrblk + n - AES_BLOCK_SIZE, + memcpy(ctrptr, ctrptr + n - AES_BLOCK_SIZE, AES_BLOCK_SIZE); - crypto_inc(ctrblk, AES_BLOCK_SIZE); + crypto_inc(ctrptr, AES_BLOCK_SIZE); out += n; in += n; nbytes -= n; } ret = blkcipher_walk_done(desc, walk, nbytes); } + if (ctrptr == ctrblk) { + if (nbytes) + memcpy(ctrbuf, ctrptr, AES_BLOCK_SIZE); + else + memcpy(walk->iv, ctrptr, AES_BLOCK_SIZE); + spin_unlock(&ctrblk_lock); + } /* * final block may be < AES_BLOCK_SIZE, copy only nbytes */ @@ -802,14 +828,15 @@ static int ctr_aes_crypt(struct blkcipher_desc *desc, long func, out = walk->dst.virt.addr; in = walk->src.virt.addr; ret = crypt_s390_kmctr(func, sctx->key, buf, in, - AES_BLOCK_SIZE, ctrblk); + AES_BLOCK_SIZE, ctrbuf); if (ret < 0 || ret != AES_BLOCK_SIZE) return -EIO; memcpy(out, buf, nbytes); - crypto_inc(ctrblk, AES_BLOCK_SIZE); + crypto_inc(ctrbuf, AES_BLOCK_SIZE); ret = blkcipher_walk_done(desc, walk, 0); + memcpy(walk->iv, ctrbuf, AES_BLOCK_SIZE); } - memcpy(walk->iv, ctrblk, AES_BLOCK_SIZE); + return ret; } diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index 200f2a1b599d16..0a5aac8a9412b6 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c @@ -25,6 +25,7 @@ #define DES3_KEY_SIZE (3 * DES_KEY_SIZE) static u8 *ctrblk; +static DEFINE_SPINLOCK(ctrblk_lock); struct s390_des_ctx { u8 iv[DES_BLOCK_SIZE]; @@ -105,29 +106,35 @@ static int ecb_desall_crypt(struct blkcipher_desc *desc, long func, } static int cbc_desall_crypt(struct blkcipher_desc *desc, long func, - u8 *iv, struct blkcipher_walk *walk) + struct blkcipher_walk *walk) { + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); int ret = blkcipher_walk_virt(desc, walk); unsigned int nbytes = walk->nbytes; + struct { + u8 iv[DES_BLOCK_SIZE]; + u8 key[DES3_KEY_SIZE]; + } param; if (!nbytes) goto out; - memcpy(iv, walk->iv, DES_BLOCK_SIZE); + memcpy(param.iv, walk->iv, DES_BLOCK_SIZE); + memcpy(param.key, ctx->key, DES3_KEY_SIZE); do { /* only use complete blocks */ unsigned int n = nbytes & ~(DES_BLOCK_SIZE - 1); u8 *out = walk->dst.virt.addr; u8 *in = walk->src.virt.addr; - ret = crypt_s390_kmc(func, iv, out, in, n); + ret = crypt_s390_kmc(func, ¶m, out, in, n); if (ret < 0 || ret != n) return -EIO; nbytes &= DES_BLOCK_SIZE - 1; ret = blkcipher_walk_done(desc, walk, nbytes); } while ((nbytes = walk->nbytes)); - memcpy(walk->iv, iv, DES_BLOCK_SIZE); + memcpy(walk->iv, param.iv, DES_BLOCK_SIZE); out: return ret; @@ -179,22 +186,20 @@ static int cbc_des_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { - struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_desall_crypt(desc, KMC_DEA_ENCRYPT, ctx->iv, &walk); + return cbc_desall_crypt(desc, KMC_DEA_ENCRYPT, &walk); } static int cbc_des_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { - struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_desall_crypt(desc, KMC_DEA_DECRYPT, ctx->iv, &walk); + return cbc_desall_crypt(desc, KMC_DEA_DECRYPT, &walk); } static struct crypto_alg cbc_des_alg = { @@ -327,22 +332,20 @@ static int cbc_des3_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { - struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_desall_crypt(desc, KMC_TDEA_192_ENCRYPT, ctx->iv, &walk); + return cbc_desall_crypt(desc, KMC_TDEA_192_ENCRYPT, &walk); } static int cbc_des3_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { - struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_desall_crypt(desc, KMC_TDEA_192_DECRYPT, ctx->iv, &walk); + return cbc_desall_crypt(desc, KMC_TDEA_192_DECRYPT, &walk); } static struct crypto_alg cbc_des3_alg = { @@ -366,54 +369,80 @@ static struct crypto_alg cbc_des3_alg = { } }; +static unsigned int __ctrblk_init(u8 *ctrptr, unsigned int nbytes) +{ + unsigned int i, n; + + /* align to block size, max. PAGE_SIZE */ + n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : nbytes & ~(DES_BLOCK_SIZE - 1); + for (i = DES_BLOCK_SIZE; i < n; i += DES_BLOCK_SIZE) { + memcpy(ctrptr + i, ctrptr + i - DES_BLOCK_SIZE, DES_BLOCK_SIZE); + crypto_inc(ctrptr + i, DES_BLOCK_SIZE); + } + return n; +} + static int ctr_desall_crypt(struct blkcipher_desc *desc, long func, - struct s390_des_ctx *ctx, struct blkcipher_walk *walk) + struct s390_des_ctx *ctx, + struct blkcipher_walk *walk) { int ret = blkcipher_walk_virt_block(desc, walk, DES_BLOCK_SIZE); - unsigned int i, n, nbytes; - u8 buf[DES_BLOCK_SIZE]; - u8 *out, *in; + unsigned int n, nbytes; + u8 buf[DES_BLOCK_SIZE], ctrbuf[DES_BLOCK_SIZE]; + u8 *out, *in, *ctrptr = ctrbuf; + + if (!walk->nbytes) + return ret; - memcpy(ctrblk, walk->iv, DES_BLOCK_SIZE); + if (spin_trylock(&ctrblk_lock)) + ctrptr = ctrblk; + + memcpy(ctrptr, walk->iv, DES_BLOCK_SIZE); while ((nbytes = walk->nbytes) >= DES_BLOCK_SIZE) { out = walk->dst.virt.addr; in = walk->src.virt.addr; while (nbytes >= DES_BLOCK_SIZE) { - /* align to block size, max. PAGE_SIZE */ - n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : - nbytes & ~(DES_BLOCK_SIZE - 1); - for (i = DES_BLOCK_SIZE; i < n; i += DES_BLOCK_SIZE) { - memcpy(ctrblk + i, ctrblk + i - DES_BLOCK_SIZE, - DES_BLOCK_SIZE); - crypto_inc(ctrblk + i, DES_BLOCK_SIZE); - } - ret = crypt_s390_kmctr(func, ctx->key, out, in, n, ctrblk); - if (ret < 0 || ret != n) + if (ctrptr == ctrblk) + n = __ctrblk_init(ctrptr, nbytes); + else + n = DES_BLOCK_SIZE; + ret = crypt_s390_kmctr(func, ctx->key, out, in, + n, ctrptr); + if (ret < 0 || ret != n) { + if (ctrptr == ctrblk) + spin_unlock(&ctrblk_lock); return -EIO; + } if (n > DES_BLOCK_SIZE) - memcpy(ctrblk, ctrblk + n - DES_BLOCK_SIZE, + memcpy(ctrptr, ctrptr + n - DES_BLOCK_SIZE, DES_BLOCK_SIZE); - crypto_inc(ctrblk, DES_BLOCK_SIZE); + crypto_inc(ctrptr, DES_BLOCK_SIZE); out += n; in += n; nbytes -= n; } ret = blkcipher_walk_done(desc, walk, nbytes); } - + if (ctrptr == ctrblk) { + if (nbytes) + memcpy(ctrbuf, ctrptr, DES_BLOCK_SIZE); + else + memcpy(walk->iv, ctrptr, DES_BLOCK_SIZE); + spin_unlock(&ctrblk_lock); + } /* final block may be < DES_BLOCK_SIZE, copy only nbytes */ if (nbytes) { out = walk->dst.virt.addr; in = walk->src.virt.addr; ret = crypt_s390_kmctr(func, ctx->key, buf, in, - DES_BLOCK_SIZE, ctrblk); + DES_BLOCK_SIZE, ctrbuf); if (ret < 0 || ret != DES_BLOCK_SIZE) return -EIO; memcpy(out, buf, nbytes); - crypto_inc(ctrblk, DES_BLOCK_SIZE); + crypto_inc(ctrbuf, DES_BLOCK_SIZE); ret = blkcipher_walk_done(desc, walk, 0); + memcpy(walk->iv, ctrbuf, DES_BLOCK_SIZE); } - memcpy(walk->iv, ctrblk, DES_BLOCK_SIZE); return ret; } diff --git a/arch/s390/hypfs/Makefile b/arch/s390/hypfs/Makefile index 2e671d5004ca56..06f8d95a16cdc9 100644 --- a/arch/s390/hypfs/Makefile +++ b/arch/s390/hypfs/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o -s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o +s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o hypfs_sprp.o diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h index 79f2ac55253f92..b34b5ab90a313b 100644 --- a/arch/s390/hypfs/hypfs.h +++ b/arch/s390/hypfs/hypfs.h @@ -13,6 +13,7 @@ #include #include #include +#include #define REG_FILE_MODE 0440 #define UPDATE_FILE_MODE 0220 @@ -36,6 +37,10 @@ extern int hypfs_vm_init(void); extern void hypfs_vm_exit(void); extern int hypfs_vm_create_files(struct dentry *root); +/* Set Partition-Resource Parameter */ +int hypfs_sprp_init(void); +void hypfs_sprp_exit(void); + /* debugfs interface */ struct hypfs_dbfs_file; @@ -52,6 +57,8 @@ struct hypfs_dbfs_file { int (*data_create)(void **data, void **data_free_ptr, size_t *size); void (*data_free)(const void *buf_free_ptr); + long (*unlocked_ioctl) (struct file *, unsigned int, + unsigned long); /* Private data for hypfs_dbfs.c */ struct hypfs_dbfs_data *data; diff --git a/arch/s390/hypfs/hypfs_dbfs.c b/arch/s390/hypfs/hypfs_dbfs.c index 17ab8b7b53cc58..2badf2bf9cd742 100644 --- a/arch/s390/hypfs/hypfs_dbfs.c +++ b/arch/s390/hypfs/hypfs_dbfs.c @@ -81,9 +81,25 @@ static ssize_t dbfs_read(struct file *file, char __user *buf, return rc; } +static long dbfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct hypfs_dbfs_file *df; + long rc; + + df = file->f_path.dentry->d_inode->i_private; + mutex_lock(&df->lock); + if (df->unlocked_ioctl) + rc = df->unlocked_ioctl(file, cmd, arg); + else + rc = -ENOTTY; + mutex_unlock(&df->lock); + return rc; +} + static const struct file_operations dbfs_ops = { .read = dbfs_read, .llseek = no_llseek, + .unlocked_ioctl = dbfs_ioctl, }; int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df) diff --git a/arch/s390/hypfs/hypfs_sprp.c b/arch/s390/hypfs/hypfs_sprp.c new file mode 100644 index 00000000000000..f043c3c7e73ccd --- /dev/null +++ b/arch/s390/hypfs/hypfs_sprp.c @@ -0,0 +1,141 @@ +/* + * Hypervisor filesystem for Linux on s390. + * Set Partition-Resource Parameter interface. + * + * Copyright IBM Corp. 2013 + * Author(s): Martin Schwidefsky + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "hypfs.h" + +#define DIAG304_SET_WEIGHTS 0 +#define DIAG304_QUERY_PRP 1 +#define DIAG304_SET_CAPPING 2 + +#define DIAG304_CMD_MAX 2 + +static unsigned long hypfs_sprp_diag304(void *data, unsigned long cmd) +{ + register unsigned long _data asm("2") = (unsigned long) data; + register unsigned long _rc asm("3"); + register unsigned long _cmd asm("4") = cmd; + + asm volatile("diag %1,%2,0x304\n" + : "=d" (_rc) : "d" (_data), "d" (_cmd) : "memory"); + + return _rc; +} + +static void hypfs_sprp_free(const void *data) +{ + free_page((unsigned long) data); +} + +static int hypfs_sprp_create(void **data_ptr, void **free_ptr, size_t *size) +{ + unsigned long rc; + void *data; + + data = (void *) get_zeroed_page(GFP_KERNEL); + if (!data) + return -ENOMEM; + rc = hypfs_sprp_diag304(data, DIAG304_QUERY_PRP); + if (rc != 1) { + *data_ptr = *free_ptr = NULL; + *size = 0; + free_page((unsigned long) data); + return -EIO; + } + *data_ptr = *free_ptr = data; + *size = PAGE_SIZE; + return 0; +} + +static int __hypfs_sprp_ioctl(void __user *user_area) +{ + struct hypfs_diag304 diag304; + unsigned long cmd; + void __user *udata; + void *data; + int rc; + + if (copy_from_user(&diag304, user_area, sizeof(diag304))) + return -EFAULT; + if ((diag304.args[0] >> 8) != 0 || diag304.args[1] > DIAG304_CMD_MAX) + return -EINVAL; + + data = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!data) + return -ENOMEM; + + udata = (void __user *)(unsigned long) diag304.data; + if (diag304.args[1] == DIAG304_SET_WEIGHTS || + diag304.args[1] == DIAG304_SET_CAPPING) + if (copy_from_user(data, udata, PAGE_SIZE)) { + rc = -EFAULT; + goto out; + } + + cmd = *(unsigned long *) &diag304.args[0]; + diag304.rc = hypfs_sprp_diag304(data, cmd); + + if (diag304.args[1] == DIAG304_QUERY_PRP) + if (copy_to_user(udata, data, PAGE_SIZE)) { + rc = -EFAULT; + goto out; + } + + rc = copy_to_user(user_area, &diag304, sizeof(diag304)) ? -EFAULT : 0; +out: + free_page((unsigned long) data); + return rc; +} + +static long hypfs_sprp_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (is_compat_task()) + argp = compat_ptr(arg); + else + argp = (void __user *) arg; + switch (cmd) { + case HYPFS_DIAG304: + return __hypfs_sprp_ioctl(argp); + default: /* unknown ioctl number */ + return -ENOTTY; + } + return 0; +} + +static struct hypfs_dbfs_file hypfs_sprp_file = { + .name = "diag_304", + .data_create = hypfs_sprp_create, + .data_free = hypfs_sprp_free, + .unlocked_ioctl = hypfs_sprp_ioctl, +}; + +int hypfs_sprp_init(void) +{ + if (!sclp_has_sprp()) + return 0; + return hypfs_dbfs_create_file(&hypfs_sprp_file); +} + +void hypfs_sprp_exit(void) +{ + if (!sclp_has_sprp()) + return; + hypfs_dbfs_remove_file(&hypfs_sprp_file); +} diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index ddfe09b4513492..c952b981e4f288 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -478,10 +478,14 @@ static int __init hypfs_init(void) rc = -ENODATA; goto fail_hypfs_diag_exit; } + if (hypfs_sprp_init()) { + rc = -ENODATA; + goto fail_hypfs_vm_exit; + } s390_kobj = kobject_create_and_add("s390", hypervisor_kobj); if (!s390_kobj) { rc = -ENOMEM; - goto fail_hypfs_vm_exit; + goto fail_hypfs_sprp_exit; } rc = register_filesystem(&hypfs_type); if (rc) @@ -490,6 +494,8 @@ static int __init hypfs_init(void) fail_filesystem: kobject_put(s390_kobj); +fail_hypfs_sprp_exit: + hypfs_sprp_exit(); fail_hypfs_vm_exit: hypfs_vm_exit(); fail_hypfs_diag_exit: @@ -502,11 +508,12 @@ static int __init hypfs_init(void) static void __exit hypfs_exit(void) { - hypfs_diag_exit(); - hypfs_vm_exit(); - hypfs_dbfs_exit(); unregister_filesystem(&hypfs_type); kobject_put(s390_kobj); + hypfs_sprp_exit(); + hypfs_vm_exit(); + hypfs_diag_exit(); + hypfs_dbfs_exit(); } module_init(hypfs_init) diff --git a/arch/s390/include/asm/cmpxchg.h b/arch/s390/include/asm/cmpxchg.h index 0f636cbdf34209..4236408070e5f7 100644 --- a/arch/s390/include/asm/cmpxchg.h +++ b/arch/s390/include/asm/cmpxchg.h @@ -185,11 +185,12 @@ static inline unsigned long long __cmpxchg64(void *ptr, { register_pair rp_old = {.pair = old}; register_pair rp_new = {.pair = new}; + unsigned long long *ullptr = ptr; asm volatile( " cds %0,%2,%1" - : "+&d" (rp_old), "=Q" (ptr) - : "d" (rp_new), "Q" (ptr) + : "+d" (rp_old), "+Q" (*ullptr) + : "d" (rp_new) : "memory", "cc"); return rp_old.pair; } diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index d5bc3750616eba..eef3dd3fd9a9f7 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -106,9 +106,22 @@ struct kvm_s390_sie_block { __u64 gbea; /* 0x0180 */ __u8 reserved188[24]; /* 0x0188 */ __u32 fac; /* 0x01a0 */ - __u8 reserved1a4[92]; /* 0x01a4 */ + __u8 reserved1a4[68]; /* 0x01a4 */ + __u64 itdba; /* 0x01e8 */ + __u8 reserved1f0[16]; /* 0x01f0 */ } __attribute__((packed)); +struct kvm_s390_itdb { + __u8 data[256]; +} __packed; + +struct sie_page { + struct kvm_s390_sie_block sie_block; + __u8 reserved200[1024]; /* 0x0200 */ + struct kvm_s390_itdb itdb; /* 0x0600 */ + __u8 reserved700[2304]; /* 0x0700 */ +} __packed; + struct kvm_vcpu_stat { u32 exit_userspace; u32 exit_null; diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index 220e171413f857..abaca2275c7a5a 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h @@ -54,6 +54,7 @@ int sclp_chp_read_info(struct sclp_chp_info *info); void sclp_get_ipl_info(struct sclp_ipl_info *info); bool __init sclp_has_linemode(void); bool __init sclp_has_vt220(void); +bool sclp_has_sprp(void); int sclp_pci_configure(u32 fid); int sclp_pci_deconfigure(u32 fid); int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode); diff --git a/arch/s390/include/uapi/asm/hypfs.h b/arch/s390/include/uapi/asm/hypfs.h new file mode 100644 index 00000000000000..37998b449531ed --- /dev/null +++ b/arch/s390/include/uapi/asm/hypfs.h @@ -0,0 +1,25 @@ +/* + * IOCTL interface for hypfs + * + * Copyright IBM Corp. 2013 + * + * Author: Martin Schwidefsky + */ + +#ifndef _ASM_HYPFS_CTL_H +#define _ASM_HYPFS_CTL_H + +#include + +struct hypfs_diag304 { + __u32 args[2]; + __u64 data; + __u64 rc; +} __attribute__((packed)); + +#define HYPFS_IOCTL_MAGIC 0x10 + +#define HYPFS_DIAG304 \ + _IOWR(HYPFS_IOCTL_MAGIC, 0x20, struct hypfs_diag304) + +#endif diff --git a/arch/s390/include/uapi/asm/statfs.h b/arch/s390/include/uapi/asm/statfs.h index a61d538756f29c..471eb09184d455 100644 --- a/arch/s390/include/uapi/asm/statfs.h +++ b/arch/s390/include/uapi/asm/statfs.h @@ -35,11 +35,11 @@ struct statfs { struct statfs64 { unsigned int f_type; unsigned int f_bsize; - unsigned long f_blocks; - unsigned long f_bfree; - unsigned long f_bavail; - unsigned long f_files; - unsigned long f_ffree; + unsigned long long f_blocks; + unsigned long long f_bfree; + unsigned long long f_bavail; + unsigned long long f_files; + unsigned long long f_ffree; __kernel_fsid_t f_fsid; unsigned int f_namelen; unsigned int f_frsize; diff --git a/arch/s390/include/uapi/asm/unistd.h b/arch/s390/include/uapi/asm/unistd.h index 864f693c237fe4..5eb5c9ddb12002 100644 --- a/arch/s390/include/uapi/asm/unistd.h +++ b/arch/s390/include/uapi/asm/unistd.h @@ -280,6 +280,8 @@ #define __NR_s390_runtime_instr 342 #define __NR_kcmp 343 #define __NR_finit_module 344 +#define __NR_sched_setattr 345 +#define __NR_sched_getattr 346 #define NR_syscalls 345 /* diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index e030d2bdec1b6a..db02052bd13725 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -286,8 +286,8 @@ asmlinkage long sys32_getegid16(void) } #ifdef CONFIG_SYSVIPC -COMPAT_SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, unsigned long, second, - unsigned long, third, compat_uptr_t, ptr) +COMPAT_SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, compat_ulong_t, second, + compat_ulong_t, third, compat_uptr_t, ptr) { if (call >> 16) /* hack for backward compatibility */ return -EINVAL; diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 9cb1b975b3532f..59c8efce1b99b5 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -1412,3 +1412,14 @@ ENTRY(sys_finit_module_wrapper) llgtr %r3,%r3 # const char __user * lgfr %r4,%r4 # int jg sys_finit_module + +ENTRY(sys_sched_setattr_wrapper) + lgfr %r2,%r2 # pid_t + llgtr %r3,%r3 # struct sched_attr __user * + jg sys_sched_setattr + +ENTRY(sys_sched_getattr_wrapper) + lgfr %r2,%r2 # pid_t + llgtr %r3,%r3 # const char __user * + llgfr %r3,%r3 # unsigned int + jg sys_sched_getattr diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index b9e25ae2579c9f..d7c00507568a73 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -59,7 +59,7 @@ ENTRY(startup_continue) .quad 0 # cr12: tracing off .quad 0 # cr13: home space segment table .quad 0xc0000000 # cr14: machine check handling off - .quad 0 # cr15: linkage stack operations + .quad .Llinkage_stack # cr15: linkage stack operations .Lpcmsk:.quad 0x0000000180000000 .L4malign:.quad 0xffffffffffc00000 .Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8 @@ -67,12 +67,15 @@ ENTRY(startup_continue) .Lparmaddr: .quad PARMAREA .align 64 -.Lduct: .long 0,0,0,0,.Lduald,0,0,0 +.Lduct: .long 0,.Laste,.Laste,0,.Lduald,0,0,0 .long 0,0,0,0,0,0,0,0 +.Laste: .quad 0,0xffffffffffffffff,0,0,0,0,0,0 .align 128 .Lduald:.rept 8 .long 0x80000000,0,0,0 # invalid access-list entries .endr +.Llinkage_stack: + .long 0,0,0x89000000,0,0,0,0x8a000000,0 ENTRY(_ehead) diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index 913410bd74a335..143992152ec95d 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -353,3 +353,5 @@ SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev SYSCALL(sys_ni_syscall,sys_s390_runtime_instr,sys_s390_runtime_instr_wrapper) SYSCALL(sys_kcmp,sys_kcmp,sys_kcmp_wrapper) SYSCALL(sys_finit_module,sys_finit_module,sys_finit_module_wrapper) +SYSCALL(sys_sched_setattr,sys_sched_setattr,sys_sched_setattr_wrapper) /* 345 */ +SYSCALL(sys_sched_getattr,sys_sched_getattr,sys_sched_getattr_wrapper) diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index 5ddbbde6f65c32..eeb1ac7d8fa487 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c @@ -112,6 +112,17 @@ static int handle_instruction(struct kvm_vcpu *vcpu) static int handle_prog(struct kvm_vcpu *vcpu) { vcpu->stat.exit_program_interruption++; + + /* Restore ITDB to Program-Interruption TDB in guest memory */ + if (IS_TE_ENABLED(vcpu) && + !(current->thread.per_flags & PER_FLAG_NO_TE) && + IS_ITDB_VALID(vcpu)) { + copy_to_guest(vcpu, TDB_ADDR, vcpu->arch.sie_block->itdba, + sizeof(struct kvm_s390_itdb)); + memset((void *) vcpu->arch.sie_block->itdba, 0, + sizeof(struct kvm_s390_itdb)); + } + trace_kvm_s390_intercept_prog(vcpu, vcpu->arch.sie_block->iprcc); return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc); } diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 7635c00a147942..e0676f390d57d2 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -395,6 +395,9 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) CPUSTAT_STOPPED | CPUSTAT_GED); vcpu->arch.sie_block->ecb = 6; + if (test_vfacility(50) && test_vfacility(73)) + vcpu->arch.sie_block->ecb |= 0x10; + vcpu->arch.sie_block->ecb2 = 8; vcpu->arch.sie_block->eca = 0xC1002001U; vcpu->arch.sie_block->fac = (int) (long) vfacilities; @@ -411,6 +414,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) { struct kvm_vcpu *vcpu; + struct sie_page *sie_page; int rc = -EINVAL; if (id >= KVM_MAX_VCPUS) @@ -422,12 +426,13 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, if (!vcpu) goto out; - vcpu->arch.sie_block = (struct kvm_s390_sie_block *) - get_zeroed_page(GFP_KERNEL); - - if (!vcpu->arch.sie_block) + sie_page = (struct sie_page *) get_zeroed_page(GFP_KERNEL); + if (!sie_page) goto out_free_cpu; + vcpu->arch.sie_block = &sie_page->sie_block; + vcpu->arch.sie_block->itdba = (unsigned long) &sie_page->itdb; + vcpu->arch.sie_block->icpua = id; if (!kvm_is_ucontrol(kvm)) { if (!kvm->arch.sca) { @@ -1182,8 +1187,8 @@ static int __init kvm_s390_init(void) return -ENOMEM; } memcpy(vfacilities, S390_lowcore.stfle_fac_list, 16); - vfacilities[0] &= 0xff82fff3f47c0000UL; - vfacilities[1] &= 0x001c000000000000UL; + vfacilities[0] &= 0xff82fff3f4fc2000UL; + vfacilities[1] &= 0x005c000000000000UL; return 0; } diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index 095cf51b16ec59..f9559b0bd62096 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h @@ -26,6 +26,12 @@ extern unsigned long *vfacilities; int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu); +/* Transactional Memory Execution related macros */ +#define IS_TE_ENABLED(vcpu) ((vcpu->arch.sie_block->ecb & 0x10)) +#define TDB_ADDR 0x1800UL +#define TDB_FORMAT1 1 +#define IS_ITDB_VALID(vcpu) ((*(char *)vcpu->arch.sie_block->itdba == TDB_FORMAT1)) + #define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\ do { \ debug_sprintf_event(d_kvm->arch.dbf, d_loglevel, d_string "\n", \ diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h index 315dbe09983e51..b1a22173d027b9 100644 --- a/arch/s390/lib/uaccess.h +++ b/arch/s390/lib/uaccess.h @@ -6,15 +6,6 @@ #ifndef __ARCH_S390_LIB_UACCESS_H #define __ARCH_S390_LIB_UACCESS_H -extern size_t copy_from_user_std(size_t, const void __user *, void *); -extern size_t copy_to_user_std(size_t, void __user *, const void *); -extern size_t strnlen_user_std(size_t, const char __user *); -extern size_t strncpy_from_user_std(size_t, const char __user *, char *); -extern int futex_atomic_cmpxchg_std(u32 *, u32 __user *, u32, u32); -extern int futex_atomic_op_std(int, u32 __user *, int, int *); - -extern size_t copy_from_user_pt(size_t, const void __user *, void *); -extern size_t copy_to_user_pt(size_t, void __user *, const void *); extern int futex_atomic_op_pt(int, u32 __user *, int, int *); extern int futex_atomic_cmpxchg_pt(u32 *, u32 __user *, u32, u32); diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c index 0632dc50da78b8..61ebcc9ccb3472 100644 --- a/arch/s390/lib/uaccess_pt.c +++ b/arch/s390/lib/uaccess_pt.c @@ -153,6 +153,8 @@ static __always_inline size_t __user_copy_pt(unsigned long uaddr, void *kptr, unsigned long offset, done, size, kaddr; void *from, *to; + if (!mm) + return n; done = 0; retry: spin_lock(&mm->page_table_lock); @@ -209,7 +211,7 @@ static __always_inline unsigned long __dat_user_addr(unsigned long uaddr, return 0; } -size_t copy_from_user_pt(size_t n, const void __user *from, void *to) +static size_t copy_from_user_pt(size_t n, const void __user *from, void *to) { size_t rc; @@ -221,7 +223,7 @@ size_t copy_from_user_pt(size_t n, const void __user *from, void *to) return rc; } -size_t copy_to_user_pt(size_t n, void __user *to, const void *from) +static size_t copy_to_user_pt(size_t n, void __user *to, const void *from) { if (segment_eq(get_fs(), KERNEL_DS)) return copy_in_kernel(n, to, (void __user *) from); @@ -262,6 +264,8 @@ static size_t strnlen_user_pt(size_t count, const char __user *src) return 0; if (segment_eq(get_fs(), KERNEL_DS)) return strnlen_kernel(count, src); + if (!mm) + return 0; done = 0; retry: spin_lock(&mm->page_table_lock); @@ -323,6 +327,8 @@ static size_t copy_in_user_pt(size_t n, void __user *to, if (segment_eq(get_fs(), KERNEL_DS)) return copy_in_kernel(n, to, from); + if (!mm) + return n; done = 0; retry: spin_lock(&mm->page_table_lock); @@ -411,6 +417,8 @@ int futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old) if (segment_eq(get_fs(), KERNEL_DS)) return __futex_atomic_op_pt(op, uaddr, oparg, old); + if (unlikely(!current->mm)) + return -EFAULT; spin_lock(¤t->mm->page_table_lock); uaddr = (u32 __force __user *) __dat_user_addr((__force unsigned long) uaddr, 1); @@ -448,6 +456,8 @@ int futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr, if (segment_eq(get_fs(), KERNEL_DS)) return __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval); + if (unlikely(!current->mm)) + return -EFAULT; spin_lock(¤t->mm->page_table_lock); uaddr = (u32 __force __user *) __dat_user_addr((__force unsigned long) uaddr, 1); diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c index a90d45e9dfb0cb..27c50f4d90cb32 100644 --- a/arch/s390/mm/page-states.c +++ b/arch/s390/mm/page-states.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #define ESSA_SET_STABLE 1 #define ESSA_SET_UNUSED 2 @@ -41,6 +43,14 @@ void __init cmma_init(void) if (!cmma_flag) return; + /* + * Disable CMM for dump, otherwise the tprot based memory + * detection can fail because of unstable pages. + */ + if (OLDMEM_BASE || ipl_info.type == IPL_TYPE_FCP_DUMP) { + cmma_flag = 0; + return; + } asm volatile( " .insn rrf,0xb9ab0000,%1,%1,0,0\n" "0: la %0,0\n" diff --git a/arch/score/lib/checksum.S b/arch/score/lib/checksum.S index 706157edc7d546..1141f2b4a50186 100644 --- a/arch/score/lib/checksum.S +++ b/arch/score/lib/checksum.S @@ -137,7 +137,7 @@ ENTRY(csum_partial) ldi r25, 0 mv r10, r5 cmpi.c r5, 0x8 - blt small_csumcpy /* < 8(singed) bytes to copy */ + blt small_csumcpy /* < 8(signed) bytes to copy */ cmpi.c r5, 0x0 beq out andri.c r25, src, 0x1 /* odd buffer? */ diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index c51efdcd07a2d0..7d8b7e94b93b6f 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -27,7 +27,7 @@ config SPARC select RTC_DRV_M48T59 select HAVE_DMA_ATTRS select HAVE_DMA_API_DEBUG - select HAVE_ARCH_JUMP_LABEL + select HAVE_ARCH_JUMP_LABEL if SPARC64 select GENERIC_IRQ_SHOW select ARCH_WANT_IPC_PARSE_VERSION select GENERIC_PCI_IOMAP diff --git a/arch/sparc/include/uapi/asm/unistd.h b/arch/sparc/include/uapi/asm/unistd.h index 62ced589bcf78f..b73274fb961a27 100644 --- a/arch/sparc/include/uapi/asm/unistd.h +++ b/arch/sparc/include/uapi/asm/unistd.h @@ -408,8 +408,10 @@ #define __NR_kern_features 340 #define __NR_kcmp 341 #define __NR_finit_module 342 +#define __NR_sched_setattr 343 +#define __NR_sched_getattr 344 -#define NR_syscalls 343 +#define NR_syscalls 345 /* Bitmask values returned from kern_features system call. */ #define KERN_FEATURE_MIXED_MODE_STACK 0x00000001 diff --git a/arch/sparc/kernel/cpumap.c b/arch/sparc/kernel/cpumap.c index cb5d272d658acc..de1c844dfabc02 100644 --- a/arch/sparc/kernel/cpumap.c +++ b/arch/sparc/kernel/cpumap.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c index e306fb08ee5e1f..acf8314cec489d 100644 --- a/arch/sparc/kernel/ebus.c +++ b/arch/sparc/kernel/ebus.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/arch/sparc/kernel/hvtramp.S b/arch/sparc/kernel/hvtramp.S index 4eb1a5a1d54406..b7ddcdd1dea943 100644 --- a/arch/sparc/kernel/hvtramp.S +++ b/arch/sparc/kernel/hvtramp.S @@ -3,7 +3,6 @@ * Copyright (C) 2007, 2008 David S. Miller */ -#include #include #include diff --git a/arch/sparc/kernel/of_device_common.c b/arch/sparc/kernel/of_device_common.c index de199bf0cb051c..3241f56331c2ac 100644 --- a/arch/sparc/kernel/of_device_common.c +++ b/arch/sparc/kernel/of_device_common.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index 7de8d1f590b7fb..1555bbcae1eee6 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -1005,6 +1005,5 @@ static int __init of_pci_slot_init(void) return 0; } - -module_init(of_pci_slot_init); +device_initcall(of_pci_slot_init); #endif diff --git a/arch/sparc/kernel/pci_common.c b/arch/sparc/kernel/pci_common.c index a6895987fb7025..944a06536ecc12 100644 --- a/arch/sparc/kernel/pci_common.c +++ b/arch/sparc/kernel/pci_common.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index fdd819dfdacf20..510baec1b69b2c 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include diff --git a/arch/sparc/kernel/sparc_ksyms_32.c b/arch/sparc/kernel/sparc_ksyms_32.c index e521c54560f9df..bf4ccb10a78c60 100644 --- a/arch/sparc/kernel/sparc_ksyms_32.c +++ b/arch/sparc/kernel/sparc_ksyms_32.c @@ -6,7 +6,6 @@ */ #include -#include #include #include diff --git a/arch/sparc/kernel/sparc_ksyms_64.c b/arch/sparc/kernel/sparc_ksyms_64.c index 9f5e24ddcc70b0..a92d5d2c46a3a6 100644 --- a/arch/sparc/kernel/sparc_ksyms_64.c +++ b/arch/sparc/kernel/sparc_ksyms_64.c @@ -7,7 +7,6 @@ #include #include -#include #include #include diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S index 7b87171ecf1e91..151ace8766cc2d 100644 --- a/arch/sparc/kernel/systbls_32.S +++ b/arch/sparc/kernel/systbls_32.S @@ -85,4 +85,4 @@ sys_call_table: /*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init /*330*/ .long sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime /*335*/ .long sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev -/*340*/ .long sys_ni_syscall, sys_kcmp, sys_finit_module +/*340*/ .long sys_ni_syscall, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index 6d81597064b6b5..4bd4e2bb26cf4d 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S @@ -86,7 +86,7 @@ sys_call_table32: .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init /*330*/ .word compat_sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime .word sys_syncfs, compat_sys_sendmmsg, sys_setns, compat_sys_process_vm_readv, compat_sys_process_vm_writev -/*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module +/*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr #endif /* CONFIG_COMPAT */ @@ -164,4 +164,4 @@ sys_call_table: .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init /*330*/ .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime .word sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev -/*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module +/*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr diff --git a/arch/sparc/kernel/trampoline_32.S b/arch/sparc/kernel/trampoline_32.S index 76dcbd3c988aed..3eed99fc69892f 100644 --- a/arch/sparc/kernel/trampoline_32.S +++ b/arch/sparc/kernel/trampoline_32.S @@ -5,7 +5,6 @@ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ -#include #include #include #include diff --git a/arch/sparc/kernel/trampoline_64.S b/arch/sparc/kernel/trampoline_64.S index ad4bde3bb61e67..737f8cbc7d56cd 100644 --- a/arch/sparc/kernel/trampoline_64.S +++ b/arch/sparc/kernel/trampoline_64.S @@ -4,7 +4,6 @@ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ -#include #include #include diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c index 30963178d7e940..9bd9ce80bf77eb 100644 --- a/arch/sparc/mm/hugetlbpage.c +++ b/arch/sparc/mm/hugetlbpage.c @@ -4,7 +4,6 @@ * Copyright (C) 2002, 2003, 2006 David S. Miller (davem@davemloft.net) */ -#include #include #include #include diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 869023abe5a444..cfbe53c17b0dbb 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,7 @@ extern unsigned long last_valid_pfn; static pgd_t *srmmu_swapper_pg_dir; const struct sparc32_cachetlb_ops *sparc32_cachetlb_ops; +EXPORT_SYMBOL(sparc32_cachetlb_ops); #ifdef CONFIG_SMP const struct sparc32_cachetlb_ops *local_ops; diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c index ad3bf4b4324d94..b12cb5e7281214 100644 --- a/arch/sparc/mm/tlb.c +++ b/arch/sparc/mm/tlb.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/arch/sparc/prom/p1275.c b/arch/sparc/prom/p1275.c index 04a4540509dd87..e58b817263199f 100644 --- a/arch/sparc/prom/p1275.c +++ b/arch/sparc/prom/p1275.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h index 78f1f2ded86c7a..ffd4493efc7812 100644 --- a/arch/tile/include/asm/compat.h +++ b/arch/tile/include/asm/compat.h @@ -281,7 +281,6 @@ long compat_sys_pread64(unsigned int fd, char __user *ubuf, size_t count, u32 dummy, u32 low, u32 high); long compat_sys_pwrite64(unsigned int fd, char __user *ubuf, size_t count, u32 dummy, u32 low, u32 high); -long compat_sys_lookup_dcookie(u32 low, u32 high, char __user *buf, size_t len); long compat_sys_sync_file_range2(int fd, unsigned int flags, u32 offset_lo, u32 offset_hi, u32 nbytes_lo, u32 nbytes_hi); diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild index 75de4abe4f94af..88a330dcdede1b 100644 --- a/arch/um/include/asm/Kbuild +++ b/arch/um/include/asm/Kbuild @@ -5,3 +5,4 @@ generic-y += switch_to.h clkdev.h generic-y += trace_clock.h generic-y += preempt.h generic-y += hash.h +generic-y += barrier.h diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h index d89b02bb6262d2..cbc5edd5a901b3 100644 --- a/arch/um/include/asm/processor-generic.h +++ b/arch/um/include/asm/processor-generic.h @@ -25,10 +25,8 @@ struct thread_struct { void *fault_addr; jmp_buf *fault_catcher; struct task_struct *prev_sched; - unsigned long temp_stack; struct arch_thread arch; jmp_buf switch_buf; - int mm_count; struct { int op; union { @@ -52,7 +50,6 @@ struct thread_struct { .regs = EMPTY_REGS, \ .fault_addr = NULL, \ .prev_sched = NULL, \ - .temp_stack = 0, \ .arch = INIT_ARCH_THREAD, \ .request = { 0 } \ } diff --git a/arch/unicore32/kernel/early_printk.c b/arch/unicore32/kernel/early_printk.c index 9be0d5d02a9a76..f2f6323c8d64e4 100644 --- a/arch/unicore32/kernel/early_printk.c +++ b/arch/unicore32/kernel/early_printk.c @@ -35,17 +35,11 @@ static struct console early_ocd_console = { static int __init setup_early_printk(char *buf) { - int keep_early; - if (!buf || early_console) return 0; - if (strstr(buf, "keep")) - keep_early = 1; - early_console = &early_ocd_console; - - if (keep_early) + if (strstr(buf, "keep")) early_console->flags &= ~CON_BOOT; else early_console->flags |= CON_BOOT; diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 940e50ebfafa66..0af5250d914fd7 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -444,6 +444,7 @@ config X86_INTEL_MID bool "Intel MID platform support" depends on X86_32 depends on X86_EXTENDED_PLATFORM + depends on X86_PLATFORM_DEVICES depends on PCI depends on PCI_GOANY depends on X86_IO_APIC @@ -1051,9 +1052,9 @@ config MICROCODE_INTEL This options enables microcode patch loading support for Intel processors. - For latest news and information on obtaining all the required - Intel ingredients for this driver, check: - . + For the current Intel microcode data package go to + and search for + 'Linux Processor Microcode Data File'. config MICROCODE_AMD bool "AMD microcode loading support" diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 0f3621ed1db6f9..321a52ccf63ad5 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -184,6 +184,7 @@ config HAVE_MMIOTRACE_SUPPORT config X86_DECODER_SELFTEST bool "x86 instruction decoder selftest" depends on DEBUG_KERNEL && KPROBES + depends on !COMPILE_TEST ---help--- Perform x86 instruction decoder selftests at build time. This option is useful for checking the sanity of x86 instruction diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 13b22e0f681dbe..eeda43abed6ec8 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -11,6 +11,28 @@ else KBUILD_DEFCONFIG := $(ARCH)_defconfig endif +# How to compile the 16-bit code. Note we always compile for -march=i386; +# that way we can complain to the user if the CPU is insufficient. +# +# The -m16 option is supported by GCC >= 4.9 and clang >= 3.5. For +# older versions of GCC, we need to play evil and unreliable tricks to +# attempt to ensure that our asm(".code16gcc") is first in the asm +# output. +CODE16GCC_CFLAGS := -m32 -include $(srctree)/arch/x86/boot/code16gcc.h \ + $(call cc-option, -fno-toplevel-reorder,\ + $(call cc-option, -fno-unit-at-a-time)) +M16_CFLAGS := $(call cc-option, -m16, $(CODE16GCC_CFLAGS)) + +REALMODE_CFLAGS := $(M16_CFLAGS) -g -Os -D__KERNEL__ \ + -DDISABLE_BRANCH_PROFILING \ + -Wall -Wstrict-prototypes -march=i386 -mregparm=3 \ + -fno-strict-aliasing -fomit-frame-pointer -fno-pic \ + -mno-mmx -mno-sse \ + $(call cc-option, -ffreestanding) \ + $(call cc-option, -fno-stack-protector) \ + $(call cc-option, -mpreferred-stack-boundary=2) +export REALMODE_CFLAGS + # BITS is used as extension for files which are available in a 32 bit # and a 64 bit version to simplify shared Makefiles. # e.g.: obj-y += foo_$(BITS).o diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index de706691800521..878df7e88cd4d9 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile @@ -51,20 +51,7 @@ $(obj)/cpustr.h: $(obj)/mkcpustr FORCE # --------------------------------------------------------------------------- -# How to compile the 16-bit code. Note we always compile for -march=i386, -# that way we can complain to the user if the CPU is insufficient. -KBUILD_CFLAGS := $(USERINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ \ - -DDISABLE_BRANCH_PROFILING \ - -Wall -Wstrict-prototypes \ - -march=i386 -mregparm=3 \ - -include $(srctree)/$(src)/code16gcc.h \ - -fno-strict-aliasing -fomit-frame-pointer -fno-pic \ - -mno-mmx -mno-sse \ - $(call cc-option, -ffreestanding) \ - $(call cc-option, -fno-toplevel-reorder,\ - $(call cc-option, -fno-unit-at-a-time)) \ - $(call cc-option, -fno-stack-protector) \ - $(call cc-option, -mpreferred-stack-boundary=2) +KBUILD_CFLAGS := $(USERINCLUDE) $(REALMODE_CFLAGS) -D_SETUP KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ GCOV_PROFILE := n diff --git a/arch/x86/boot/cpuflags.c b/arch/x86/boot/cpuflags.c index a9fcb7cfb2411f..431fa5f84537d1 100644 --- a/arch/x86/boot/cpuflags.c +++ b/arch/x86/boot/cpuflags.c @@ -28,20 +28,35 @@ static int has_fpu(void) return fsw == 0 && (fcw & 0x103f) == 0x003f; } +/* + * For building the 16-bit code we want to explicitly specify 32-bit + * push/pop operations, rather than just saying 'pushf' or 'popf' and + * letting the compiler choose. But this is also included from the + * compressed/ directory where it may be 64-bit code, and thus needs + * to be 'pushfq' or 'popfq' in that case. + */ +#ifdef __x86_64__ +#define PUSHF "pushfq" +#define POPF "popfq" +#else +#define PUSHF "pushfl" +#define POPF "popfl" +#endif + int has_eflag(unsigned long mask) { unsigned long f0, f1; - asm volatile("pushf \n\t" - "pushf \n\t" + asm volatile(PUSHF " \n\t" + PUSHF " \n\t" "pop %0 \n\t" "mov %0,%1 \n\t" "xor %2,%1 \n\t" "push %1 \n\t" - "popf \n\t" - "pushf \n\t" + POPF " \n\t" + PUSHF " \n\t" "pop %1 \n\t" - "popf" + POPF : "=&r" (f0), "=&r" (f1) : "ri" (mask)); diff --git a/arch/x86/boot/video.h b/arch/x86/boot/video.h index ff339c5db31127..0bb25491262d00 100644 --- a/arch/x86/boot/video.h +++ b/arch/x86/boot/video.h @@ -80,7 +80,7 @@ struct card_info { u16 xmode_n; /* Size of unprobed mode range */ }; -#define __videocard struct card_info __attribute__((section(".videocards"))) +#define __videocard struct card_info __attribute__((used,section(".videocards"))) extern struct card_info video_cards[], video_cards_end[]; int mode_defined(u16 mode); /* video.c */ diff --git a/arch/x86/include/asm/amd_nb.h b/arch/x86/include/asm/amd_nb.h index a54ee1d054d92e..aaac3b2fb746d3 100644 --- a/arch/x86/include/asm/amd_nb.h +++ b/arch/x86/include/asm/amd_nb.h @@ -19,7 +19,7 @@ extern int amd_cache_northbridges(void); extern void amd_flush_garts(void); extern int amd_numa_init(void); extern int amd_get_subcaches(int); -extern int amd_set_subcaches(int, int); +extern int amd_set_subcaches(int, unsigned long); struct amd_l3_cache { unsigned indices; diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 3b978c472d08b5..3d6b9f81cc683e 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -132,6 +132,8 @@ extern void __init efi_map_region_fixed(efi_memory_desc_t *md); extern void efi_sync_low_kernel_mappings(void); extern void efi_setup_page_tables(void); extern void __init old_map_region(efi_memory_desc_t *md); +extern void __init runtime_code_page_mkexec(void); +extern void __init efi_runtime_mkexec(void); struct efi_setup_data { u64 fw_vendor; diff --git a/arch/x86/include/asm/kvm_para.h b/arch/x86/include/asm/kvm_para.h index 1df11590975886..c7678e43465bd6 100644 --- a/arch/x86/include/asm/kvm_para.h +++ b/arch/x86/include/asm/kvm_para.h @@ -85,28 +85,9 @@ static inline long kvm_hypercall4(unsigned int nr, unsigned long p1, return ret; } -static inline uint32_t kvm_cpuid_base(void) -{ - if (boot_cpu_data.cpuid_level < 0) - return 0; /* So we don't blow up on old processors */ - - if (cpu_has_hypervisor) - return hypervisor_cpuid_base("KVMKVMKVM\0\0\0", 0); - - return 0; -} - -static inline bool kvm_para_available(void) -{ - return kvm_cpuid_base() != 0; -} - -static inline unsigned int kvm_arch_para_features(void) -{ - return cpuid_eax(KVM_CPUID_FEATURES); -} - #ifdef CONFIG_KVM_GUEST +bool kvm_para_available(void); +unsigned int kvm_arch_para_features(void); void __init kvm_guest_init(void); void kvm_async_pf_task_wait(u32 token); void kvm_async_pf_task_wake(u32 token); @@ -126,6 +107,16 @@ static inline void kvm_spinlock_init(void) #define kvm_async_pf_task_wait(T) do {} while(0) #define kvm_async_pf_task_wake(T) do {} while(0) +static inline bool kvm_para_available(void) +{ + return 0; +} + +static inline unsigned int kvm_arch_para_features(void) +{ + return 0; +} + static inline u32 kvm_read_and_reset_pf_reason(void) { return 0; diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h index 2f59cce3b38aaa..f97fbe3abb67f5 100644 --- a/arch/x86/include/asm/page_types.h +++ b/arch/x86/include/asm/page_types.h @@ -51,9 +51,9 @@ extern int devmem_is_allowed(unsigned long pagenr); extern unsigned long max_low_pfn_mapped; extern unsigned long max_pfn_mapped; -static inline phys_addr_t get_max_low_mapped(void) +static inline phys_addr_t get_max_mapped(void) { - return (phys_addr_t)max_low_pfn_mapped << PAGE_SHIFT; + return (phys_addr_t)max_pfn_mapped << PAGE_SHIFT; } bool pfn_range_is_mapped(unsigned long start_pfn, unsigned long end_pfn); diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index 401f350ef71b90..cd6e1610e29ee0 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -781,9 +781,9 @@ static __always_inline void __ticket_unlock_kick(struct arch_spinlock *lock, */ #define PV_CALLEE_SAVE_REGS_THUNK(func) \ extern typeof(func) __raw_callee_save_##func; \ - static void *__##func##__ __used = func; \ \ asm(".pushsection .text;" \ + ".globl __raw_callee_save_" #func " ; " \ "__raw_callee_save_" #func ": " \ PV_SAVE_ALL_CALLER_REGS \ "call " #func ";" \ diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h index aab8f671b523f7..7549b8b369e47c 100644 --- a/arch/x86/include/asm/paravirt_types.h +++ b/arch/x86/include/asm/paravirt_types.h @@ -388,10 +388,11 @@ extern struct pv_lock_ops pv_lock_ops; _paravirt_alt(insn_string, "%c[paravirt_typenum]", "%c[paravirt_clobber]") /* Simple instruction patching code. */ -#define DEF_NATIVE(ops, name, code) \ - extern const char start_##ops##_##name[] __visible, \ - end_##ops##_##name[] __visible; \ - asm("start_" #ops "_" #name ": " code "; end_" #ops "_" #name ":") +#define NATIVE_LABEL(a,x,b) "\n\t.globl " a #x "_" #b "\n" a #x "_" #b ":\n\t" + +#define DEF_NATIVE(ops, name, code) \ + __visible extern const char start_##ops##_##name[], end_##ops##_##name[]; \ + asm(NATIVE_LABEL("start_", ops, name) code NATIVE_LABEL("end_", ops, name)) unsigned paravirt_patch_nop(void); unsigned paravirt_patch_ident_32(void *insnbuf, unsigned len); diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index bbc8b12fa443d4..5ad38ad07890fc 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -445,10 +445,20 @@ static inline int pte_same(pte_t a, pte_t b) return a.pte == b.pte; } +static inline int pteval_present(pteval_t pteval) +{ + /* + * Yes Linus, _PAGE_PROTNONE == _PAGE_NUMA. Expressing it this + * way clearly states that the intent is that protnone and numa + * hinting ptes are considered present for the purposes of + * pagetable operations like zapping, protection changes, gup etc. + */ + return pteval & (_PAGE_PRESENT | _PAGE_PROTNONE | _PAGE_NUMA); +} + static inline int pte_present(pte_t a) { - return pte_flags(a) & (_PAGE_PRESENT | _PAGE_PROTNONE | - _PAGE_NUMA); + return pteval_present(pte_flags(a)); } #define pte_accessible pte_accessible diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index a83aa44bb1fb83..1aa9ccd432236a 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h @@ -121,7 +121,8 @@ /* Set of bits not changed in pte_modify */ #define _PAGE_CHG_MASK (PTE_PFN_MASK | _PAGE_PCD | _PAGE_PWT | \ - _PAGE_SPECIAL | _PAGE_ACCESSED | _PAGE_DIRTY) + _PAGE_SPECIAL | _PAGE_ACCESSED | _PAGE_DIRTY | \ + _PAGE_SOFT_DIRTY) #define _HPAGE_CHG_MASK (_PAGE_CHG_MASK | _PAGE_PSE) #define _PAGE_CACHE_MASK (_PAGE_PCD | _PAGE_PWT) diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 3ba3de457d053e..e1940c06ed022d 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -163,9 +163,11 @@ struct thread_info { */ #ifndef __ASSEMBLY__ - -/* how to get the current stack pointer from C */ -register unsigned long current_stack_pointer asm("esp") __used; +#define current_stack_pointer ({ \ + unsigned long sp; \ + asm("mov %%esp,%0" : "=g" (sp)); \ + sp; \ +}) /* how to get the thread information struct from C */ static inline struct thread_info *current_thread_info(void) diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index e6d90babc245c1..04905bfc508b99 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h @@ -62,7 +62,7 @@ static inline void __flush_tlb_all(void) static inline void __flush_tlb_one(unsigned long addr) { - count_vm_event(NR_TLB_LOCAL_FLUSH_ONE); + count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ONE); __flush_tlb_single(addr); } @@ -93,13 +93,13 @@ static inline void __flush_tlb_one(unsigned long addr) */ static inline void __flush_tlb_up(void) { - count_vm_event(NR_TLB_LOCAL_FLUSH_ALL); + count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL); __flush_tlb(); } static inline void flush_tlb_all(void) { - count_vm_event(NR_TLB_LOCAL_FLUSH_ALL); + count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL); __flush_tlb_all(); } diff --git a/arch/x86/include/asm/uv/uv.h b/arch/x86/include/asm/uv/uv.h index 6b964a0b86d1bb..062921ef34e913 100644 --- a/arch/x86/include/asm/uv/uv.h +++ b/arch/x86/include/asm/uv/uv.h @@ -12,7 +12,6 @@ extern enum uv_system_type get_uv_system_type(void); extern int is_uv_system(void); extern void uv_cpu_init(void); extern void uv_nmi_init(void); -extern void uv_register_nmi_notifier(void); extern void uv_system_init(void); extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask, struct mm_struct *mm, @@ -26,7 +25,6 @@ static inline enum uv_system_type get_uv_system_type(void) { return UV_NONE; } static inline int is_uv_system(void) { return 0; } static inline void uv_cpu_init(void) { } static inline void uv_system_init(void) { } -static inline void uv_register_nmi_notifier(void) { } static inline const struct cpumask * uv_flush_tlb_others(const struct cpumask *cpumask, struct mm_struct *mm, unsigned long start, unsigned long end, unsigned int cpu) diff --git a/arch/x86/include/uapi/asm/sembuf.h b/arch/x86/include/uapi/asm/sembuf.h index ee50c801f7b7ed..cc2d6a3aeae7ed 100644 --- a/arch/x86/include/uapi/asm/sembuf.h +++ b/arch/x86/include/uapi/asm/sembuf.h @@ -13,12 +13,12 @@ struct semid64_ds { struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ __kernel_time_t sem_otime; /* last semop time */ - unsigned long __unused1; + __kernel_ulong_t __unused1; __kernel_time_t sem_ctime; /* last change time */ - unsigned long __unused2; - unsigned long sem_nsems; /* no. of semaphores in array */ - unsigned long __unused3; - unsigned long __unused4; + __kernel_ulong_t __unused2; + __kernel_ulong_t sem_nsems; /* no. of semaphores in array */ + __kernel_ulong_t __unused3; + __kernel_ulong_t __unused4; }; #endif /* _ASM_X86_SEMBUF_H */ diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index 59554dca96ec89..dec8de4e1663fd 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -179,7 +179,7 @@ int amd_get_subcaches(int cpu) return (mask >> (4 * cuid)) & 0xf; } -int amd_set_subcaches(int cpu, int mask) +int amd_set_subcaches(int cpu, unsigned long mask) { static unsigned int reset, ban; struct amd_northbridge *nb = node_to_amd_nb(amd_get_nb_id(cpu)); diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index ad0dc0428baf8c..d263b1307de1e5 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -980,7 +980,6 @@ void __init uv_system_init(void) uv_nmi_setup(); uv_cpu_init(); uv_scir_register_cpu_notifier(); - uv_register_nmi_notifier(); proc_mkdir("sgi_uv", NULL); /* register Legacy VGA I/O redirection handler */ diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index d3153e281d7291..c67ffa6860642a 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -767,10 +767,7 @@ static unsigned int amd_size_cache(struct cpuinfo_x86 *c, unsigned int size) static void cpu_set_tlb_flushall_shift(struct cpuinfo_x86 *c) { - tlb_flushall_shift = 5; - - if (c->x86 <= 0x11) - tlb_flushall_shift = 4; + tlb_flushall_shift = 6; } static void cpu_detect_tlb_amd(struct cpuinfo_x86 *c) diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 24b6fd10625a5a..8e28bf2fc3ef4a 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -284,8 +284,13 @@ static __always_inline void setup_smap(struct cpuinfo_x86 *c) raw_local_save_flags(eflags); BUG_ON(eflags & X86_EFLAGS_AC); - if (cpu_has(c, X86_FEATURE_SMAP)) + if (cpu_has(c, X86_FEATURE_SMAP)) { +#ifdef CONFIG_X86_SMAP set_in_cr4(X86_CR4_SMAP); +#else + clear_in_cr4(X86_CR4_SMAP); +#endif + } } /* diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 3db61c644e440e..5cd9bfabd6450e 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -640,21 +640,17 @@ static void intel_tlb_flushall_shift_set(struct cpuinfo_x86 *c) case 0x61d: /* six-core 45 nm xeon "Dunnington" */ tlb_flushall_shift = -1; break; + case 0x63a: /* Ivybridge */ + tlb_flushall_shift = 2; + break; case 0x61a: /* 45 nm nehalem, "Bloomfield" */ case 0x61e: /* 45 nm nehalem, "Lynnfield" */ case 0x625: /* 32 nm nehalem, "Clarkdale" */ case 0x62c: /* 32 nm nehalem, "Gulftown" */ case 0x62e: /* 45 nm nehalem-ex, "Beckton" */ case 0x62f: /* 32 nm Xeon E7 */ - tlb_flushall_shift = 6; - break; case 0x62a: /* SandyBridge */ case 0x62d: /* SandyBridge, "Romely-EP" */ - tlb_flushall_shift = 5; - break; - case 0x63a: /* Ivybridge */ - tlb_flushall_shift = 1; - break; default: tlb_flushall_shift = 6; } diff --git a/arch/x86/kernel/cpu/microcode/amd_early.c b/arch/x86/kernel/cpu/microcode/amd_early.c index 8384c0fa206f17..617a9e28424560 100644 --- a/arch/x86/kernel/cpu/microcode/amd_early.c +++ b/arch/x86/kernel/cpu/microcode/amd_early.c @@ -285,6 +285,15 @@ static void __init collect_cpu_sig_on_bsp(void *arg) uci->cpu_sig.sig = cpuid_eax(0x00000001); } + +static void __init get_bsp_sig(void) +{ + unsigned int bsp = boot_cpu_data.cpu_index; + struct ucode_cpu_info *uci = ucode_cpu_info + bsp; + + if (!uci->cpu_sig.sig) + smp_call_function_single(bsp, collect_cpu_sig_on_bsp, NULL, 1); +} #else void load_ucode_amd_ap(void) { @@ -337,31 +346,37 @@ void load_ucode_amd_ap(void) int __init save_microcode_in_initrd_amd(void) { + unsigned long cont; enum ucode_state ret; u32 eax; -#ifdef CONFIG_X86_32 - unsigned int bsp = boot_cpu_data.cpu_index; - struct ucode_cpu_info *uci = ucode_cpu_info + bsp; - - if (!uci->cpu_sig.sig) - smp_call_function_single(bsp, collect_cpu_sig_on_bsp, NULL, 1); + if (!container) + return -EINVAL; +#ifdef CONFIG_X86_32 + get_bsp_sig(); + cont = (unsigned long)container; +#else /* - * Take into account the fact that the ramdisk might get relocated - * and therefore we need to recompute the container's position in - * virtual memory space. + * We need the physical address of the container for both bitness since + * boot_params.hdr.ramdisk_image is a physical address. */ - container = (u8 *)(__va((u32)relocated_ramdisk) + - ((u32)container - boot_params.hdr.ramdisk_image)); + cont = __pa(container); #endif + + /* + * Take into account the fact that the ramdisk might get relocated and + * therefore we need to recompute the container's position in virtual + * memory space. + */ + if (relocated_ramdisk) + container = (u8 *)(__va(relocated_ramdisk) + + (cont - boot_params.hdr.ramdisk_image)); + if (ucode_new_rev) pr_info("microcode: updated early to new patch_level=0x%08x\n", ucode_new_rev); - if (!container) - return -EINVAL; - eax = cpuid_eax(0x00000001); eax = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff); diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c index ce2d0a2c3e4ff5..0e25a1bc5ab5cf 100644 --- a/arch/x86/kernel/cpu/mtrr/generic.c +++ b/arch/x86/kernel/cpu/mtrr/generic.c @@ -683,7 +683,7 @@ static void prepare_set(void) __acquires(set_atomicity_lock) } /* Flush all TLBs via a mov %cr3, %reg; mov %reg, %cr3 */ - count_vm_event(NR_TLB_LOCAL_FLUSH_ALL); + count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL); __flush_tlb(); /* Save MTRR state */ @@ -697,7 +697,7 @@ static void prepare_set(void) __acquires(set_atomicity_lock) static void post_set(void) __releases(set_atomicity_lock) { /* Flush TLBs (no need to flush caches - they are disabled) */ - count_vm_event(NR_TLB_LOCAL_FLUSH_ALL); + count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL); __flush_tlb(); /* Intel (P6) standard MTRRs */ diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index d4bdd253fea713..e6253195a301ad 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -77,8 +77,7 @@ within(unsigned long addr, unsigned long start, unsigned long end) return addr >= start && addr < end; } -static int -do_ftrace_mod_code(unsigned long ip, const void *new_code) +static unsigned long text_ip_addr(unsigned long ip) { /* * On x86_64, kernel text mappings are mapped read-only with @@ -91,7 +90,7 @@ do_ftrace_mod_code(unsigned long ip, const void *new_code) if (within(ip, (unsigned long)_text, (unsigned long)_etext)) ip = (unsigned long)__va(__pa_symbol(ip)); - return probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE); + return ip; } static const unsigned char *ftrace_nop_replace(void) @@ -123,8 +122,10 @@ ftrace_modify_code_direct(unsigned long ip, unsigned const char *old_code, if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0) return -EINVAL; + ip = text_ip_addr(ip); + /* replace the text with the new text */ - if (do_ftrace_mod_code(ip, new_code)) + if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE)) return -EPERM; sync_core(); @@ -221,37 +222,51 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, return -EINVAL; } -int ftrace_update_ftrace_func(ftrace_func_t func) +static unsigned long ftrace_update_func; + +static int update_ftrace_func(unsigned long ip, void *new) { - unsigned long ip = (unsigned long)(&ftrace_call); - unsigned char old[MCOUNT_INSN_SIZE], *new; + unsigned char old[MCOUNT_INSN_SIZE]; int ret; - memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE); - new = ftrace_call_replace(ip, (unsigned long)func); + memcpy(old, (void *)ip, MCOUNT_INSN_SIZE); + + ftrace_update_func = ip; + /* Make sure the breakpoints see the ftrace_update_func update */ + smp_wmb(); /* See comment above by declaration of modifying_ftrace_code */ atomic_inc(&modifying_ftrace_code); ret = ftrace_modify_code(ip, old, new); + atomic_dec(&modifying_ftrace_code); + + return ret; +} + +int ftrace_update_ftrace_func(ftrace_func_t func) +{ + unsigned long ip = (unsigned long)(&ftrace_call); + unsigned char *new; + int ret; + + new = ftrace_call_replace(ip, (unsigned long)func); + ret = update_ftrace_func(ip, new); + /* Also update the regs callback function */ if (!ret) { ip = (unsigned long)(&ftrace_regs_call); - memcpy(old, &ftrace_regs_call, MCOUNT_INSN_SIZE); new = ftrace_call_replace(ip, (unsigned long)func); - ret = ftrace_modify_code(ip, old, new); + ret = update_ftrace_func(ip, new); } - atomic_dec(&modifying_ftrace_code); - return ret; } static int is_ftrace_caller(unsigned long ip) { - if (ip == (unsigned long)(&ftrace_call) || - ip == (unsigned long)(&ftrace_regs_call)) + if (ip == ftrace_update_func) return 1; return 0; @@ -677,45 +692,41 @@ int __init ftrace_dyn_arch_init(void *data) #ifdef CONFIG_DYNAMIC_FTRACE extern void ftrace_graph_call(void); -static int ftrace_mod_jmp(unsigned long ip, - int old_offset, int new_offset) +static unsigned char *ftrace_jmp_replace(unsigned long ip, unsigned long addr) { - unsigned char code[MCOUNT_INSN_SIZE]; + static union ftrace_code_union calc; - if (probe_kernel_read(code, (void *)ip, MCOUNT_INSN_SIZE)) - return -EFAULT; + /* Jmp not a call (ignore the .e8) */ + calc.e8 = 0xe9; + calc.offset = ftrace_calc_offset(ip + MCOUNT_INSN_SIZE, addr); - if (code[0] != 0xe9 || old_offset != *(int *)(&code[1])) - return -EINVAL; + /* + * ftrace external locks synchronize the access to the static variable. + */ + return calc.code; +} - *(int *)(&code[1]) = new_offset; +static int ftrace_mod_jmp(unsigned long ip, void *func) +{ + unsigned char *new; - if (do_ftrace_mod_code(ip, &code)) - return -EPERM; + new = ftrace_jmp_replace(ip, (unsigned long)func); - return 0; + return update_ftrace_func(ip, new); } int ftrace_enable_ftrace_graph_caller(void) { unsigned long ip = (unsigned long)(&ftrace_graph_call); - int old_offset, new_offset; - old_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE); - new_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE); - - return ftrace_mod_jmp(ip, old_offset, new_offset); + return ftrace_mod_jmp(ip, &ftrace_graph_caller); } int ftrace_disable_ftrace_graph_caller(void) { unsigned long ip = (unsigned long)(&ftrace_graph_call); - int old_offset, new_offset; - - old_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE); - new_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE); - return ftrace_mod_jmp(ip, old_offset, new_offset); + return ftrace_mod_jmp(ip, &ftrace_stub); } #endif /* !CONFIG_DYNAMIC_FTRACE */ diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index dbb60878b744d9..d99f31d9a75021 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -266,6 +266,14 @@ __visible void smp_trace_x86_platform_ipi(struct pt_regs *regs) EXPORT_SYMBOL_GPL(vector_used_by_percpu_irq); #ifdef CONFIG_HOTPLUG_CPU + +/* These two declarations are only used in check_irq_vectors_for_cpu_disable() + * below, which is protected by stop_machine(). Putting them on the stack + * results in a stack frame overflow. Dynamically allocating could result in a + * failure so declare these two cpumasks as global. + */ +static struct cpumask affinity_new, online_new; + /* * This cpu is going to be removed and its vectors migrated to the remaining * online cpus. Check to see if there are enough vectors in the remaining cpus. @@ -277,7 +285,6 @@ int check_irq_vectors_for_cpu_disable(void) unsigned int this_cpu, vector, this_count, count; struct irq_desc *desc; struct irq_data *data; - struct cpumask affinity_new, online_new; this_cpu = smp_processor_id(); cpumask_copy(&online_new, cpu_online_mask); diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 6dd802c6d7806c..713f1b3bad52a6 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -500,6 +500,38 @@ void __init kvm_guest_init(void) #endif } +static noinline uint32_t __kvm_cpuid_base(void) +{ + if (boot_cpu_data.cpuid_level < 0) + return 0; /* So we don't blow up on old processors */ + + if (cpu_has_hypervisor) + return hypervisor_cpuid_base("KVMKVMKVM\0\0\0", 0); + + return 0; +} + +static inline uint32_t kvm_cpuid_base(void) +{ + static int kvm_cpuid_base = -1; + + if (kvm_cpuid_base == -1) + kvm_cpuid_base = __kvm_cpuid_base(); + + return kvm_cpuid_base; +} + +bool kvm_para_available(void) +{ + return kvm_cpuid_base() != 0; +} +EXPORT_SYMBOL_GPL(kvm_para_available); + +unsigned int kvm_arch_para_features(void) +{ + return cpuid_eax(kvm_cpuid_base() | KVM_CPUID_FEATURES); +} + static uint32_t __init kvm_detect(void) { return kvm_cpuid_base(); @@ -673,7 +705,7 @@ static cpumask_t waiting_cpus; /* Track spinlock on which a cpu is waiting */ static DEFINE_PER_CPU(struct kvm_lock_waiting, klock_waiting); -static void kvm_lock_spinning(struct arch_spinlock *lock, __ticket_t want) +__visible void kvm_lock_spinning(struct arch_spinlock *lock, __ticket_t want) { struct kvm_lock_waiting *w; int cpu; diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 872079a67e4d26..f7d0672481fd7c 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -100,8 +100,10 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size, flag |= __GFP_ZERO; again: page = NULL; - if (!(flag & GFP_ATOMIC)) + /* CMA can be used only in the context which permits sleeping */ + if (flag & __GFP_WAIT) page = dma_alloc_from_contiguous(dev, count, get_order(size)); + /* fallback */ if (!page) page = alloc_pages_node(dev_to_node(dev), flag, get_order(size)); if (!page) diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index 04ee1e2e4c0251..7c6acd4b8995e5 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c @@ -571,3 +571,40 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F5, quirk_amd_nb_node); #endif + +#ifdef CONFIG_PCI +/* + * Processor does not ensure DRAM scrub read/write sequence + * is atomic wrt accesses to CC6 save state area. Therefore + * if a concurrent scrub read/write access is to same address + * the entry may appear as if it is not written. This quirk + * applies to Fam16h models 00h-0Fh + * + * See "Revision Guide" for AMD F16h models 00h-0fh, + * document 51810 rev. 3.04, Nov 2013 + */ +static void amd_disable_seq_and_redirect_scrub(struct pci_dev *dev) +{ + u32 val; + + /* + * Suggested workaround: + * set D18F3x58[4:0] = 00h and set D18F3x5C[0] = 0b + */ + pci_read_config_dword(dev, 0x58, &val); + if (val & 0x1F) { + val &= ~(0x1F); + pci_write_config_dword(dev, 0x58, val); + } + + pci_read_config_dword(dev, 0x5C, &val); + if (val & BIT(0)) { + val &= ~BIT(0); + pci_write_config_dword(dev, 0x5c, val); + } +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3, + amd_disable_seq_and_redirect_scrub); + +#endif diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index c9675594d7caee..06853e6703541f 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1119,7 +1119,7 @@ void __init setup_arch(char **cmdline_p) setup_real_mode(); - memblock_set_current_limit(get_max_low_mapped()); + memblock_set_current_limit(get_max_mapped()); dma_contiguous_reserve(0); /* diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 19e5adb49a27d8..acb3b606613eb5 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -209,7 +209,7 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc) * dance when its actually needed. */ - preempt_disable(); + preempt_disable_notrace(); data = this_cpu_read(cyc2ns.head); tail = this_cpu_read(cyc2ns.tail); @@ -229,7 +229,7 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc) if (!--data->__count) this_cpu_write(cyc2ns.tail, data); } - preempt_enable(); + preempt_enable_notrace(); return ns; } diff --git a/arch/x86/kernel/vsmp_64.c b/arch/x86/kernel/vsmp_64.c index 992f890283e926..f6584a90aba346 100644 --- a/arch/x86/kernel/vsmp_64.c +++ b/arch/x86/kernel/vsmp_64.c @@ -33,7 +33,7 @@ * and vice versa. */ -static unsigned long vsmp_save_fl(void) +asmlinkage unsigned long vsmp_save_fl(void) { unsigned long flags = native_save_fl(); @@ -43,7 +43,7 @@ static unsigned long vsmp_save_fl(void) } PV_CALLEE_SAVE_REGS_THUNK(vsmp_save_fl); -static void vsmp_restore_fl(unsigned long flags) +__visible void vsmp_restore_fl(unsigned long flags) { if (flags & X86_EFLAGS_IF) flags &= ~X86_EFLAGS_AC; @@ -53,7 +53,7 @@ static void vsmp_restore_fl(unsigned long flags) } PV_CALLEE_SAVE_REGS_THUNK(vsmp_restore_fl); -static void vsmp_irq_disable(void) +asmlinkage void vsmp_irq_disable(void) { unsigned long flags = native_save_fl(); @@ -61,7 +61,7 @@ static void vsmp_irq_disable(void) } PV_CALLEE_SAVE_REGS_THUNK(vsmp_irq_disable); -static void vsmp_irq_enable(void) +asmlinkage void vsmp_irq_enable(void) { unsigned long flags = native_save_fl(); diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index f1e4895174b247..a2a1bb7ed8c1b3 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -72,4 +72,12 @@ static inline bool guest_cpuid_has_pcid(struct kvm_vcpu *vcpu) return best && (best->ecx & bit(X86_FEATURE_PCID)); } +static inline bool guest_cpuid_has_x2apic(struct kvm_vcpu *vcpu) +{ + struct kvm_cpuid_entry2 *best; + + best = kvm_find_cpuid_entry(vcpu, 1, 0); + return best && (best->ecx & bit(X86_FEATURE_X2APIC)); +} + #endif diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index c8b0d0d2da5ce2..6a11845fd8b944 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -65,7 +65,7 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, struct kvm_lapic_irq *irq, int *r, unsigned long *dest_map); u64 kvm_get_apic_base(struct kvm_vcpu *vcpu); -void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data); +int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info); void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s); int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 5c8879127cfa8d..a06f101ef64b4a 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -4392,7 +4392,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) static void vmx_vcpu_reset(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); - u64 msr; + struct msr_data apic_base_msr; vmx->rmode.vm86_active = 0; @@ -4400,10 +4400,11 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu) vmx->vcpu.arch.regs[VCPU_REGS_RDX] = get_rdx_init_val(); kvm_set_cr8(&vmx->vcpu, 0); - msr = 0xfee00000 | MSR_IA32_APICBASE_ENABLE; + apic_base_msr.data = 0xfee00000 | MSR_IA32_APICBASE_ENABLE; if (kvm_vcpu_is_bsp(&vmx->vcpu)) - msr |= MSR_IA32_APICBASE_BSP; - kvm_set_apic_base(&vmx->vcpu, msr); + apic_base_msr.data |= MSR_IA32_APICBASE_BSP; + apic_base_msr.host_initiated = true; + kvm_set_apic_base(&vmx->vcpu, &apic_base_msr); vmx_segment_cache_clear(vmx); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0c76f7cfdb32c0..39c28f09dfd5f0 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -257,10 +257,26 @@ u64 kvm_get_apic_base(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(kvm_get_apic_base); -void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data) -{ - /* TODO: reserve bits check */ - kvm_lapic_set_base(vcpu, data); +int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info) +{ + u64 old_state = vcpu->arch.apic_base & + (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE); + u64 new_state = msr_info->data & + (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE); + u64 reserved_bits = ((~0ULL) << cpuid_maxphyaddr(vcpu)) | + 0x2ff | (guest_cpuid_has_x2apic(vcpu) ? 0 : X2APIC_ENABLE); + + if (!msr_info->host_initiated && + ((msr_info->data & reserved_bits) != 0 || + new_state == X2APIC_ENABLE || + (new_state == MSR_IA32_APICBASE_ENABLE && + old_state == (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE)) || + (new_state == (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE) && + old_state == 0))) + return 1; + + kvm_lapic_set_base(vcpu, msr_info->data); + return 0; } EXPORT_SYMBOL_GPL(kvm_set_apic_base); @@ -1840,6 +1856,7 @@ static int set_msr_hyperv_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data) if (__copy_to_user((void __user *)addr, instructions, 4)) return 1; kvm->arch.hv_hypercall = data; + mark_page_dirty(kvm, gfn); break; } case HV_X64_MSR_REFERENCE_TSC: { @@ -1868,19 +1885,21 @@ static int set_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 data) { switch (msr) { case HV_X64_MSR_APIC_ASSIST_PAGE: { + u64 gfn; unsigned long addr; if (!(data & HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE)) { vcpu->arch.hv_vapic = data; break; } - addr = gfn_to_hva(vcpu->kvm, data >> - HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT); + gfn = data >> HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT; + addr = gfn_to_hva(vcpu->kvm, gfn); if (kvm_is_error_hva(addr)) return 1; if (__clear_user((void __user *)addr, PAGE_SIZE)) return 1; vcpu->arch.hv_vapic = data; + mark_page_dirty(vcpu->kvm, gfn); break; } case HV_X64_MSR_EOI: @@ -2006,8 +2025,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case 0x200 ... 0x2ff: return set_msr_mtrr(vcpu, msr, data); case MSR_IA32_APICBASE: - kvm_set_apic_base(vcpu, data); - break; + return kvm_set_apic_base(vcpu, msr_info); case APIC_BASE_MSR ... APIC_BASE_MSR + 0x3ff: return kvm_x2apic_msr_write(vcpu, msr, data); case MSR_IA32_TSCDEADLINE: @@ -2598,10 +2616,10 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_GET_TSC_KHZ: case KVM_CAP_KVMCLOCK_CTRL: case KVM_CAP_READONLY_MEM: + case KVM_CAP_HYPERV_TIME: #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT case KVM_CAP_ASSIGN_DEV_IRQ: case KVM_CAP_PCI_2_3: - case KVM_CAP_HYPERV_TIME: #endif r = 1; break; @@ -6409,6 +6427,7 @@ EXPORT_SYMBOL_GPL(kvm_task_switch); int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) { + struct msr_data apic_base_msr; int mmu_reset_needed = 0; int pending_vec, max_bits, idx; struct desc_ptr dt; @@ -6432,7 +6451,9 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, mmu_reset_needed |= vcpu->arch.efer != sregs->efer; kvm_x86_ops->set_efer(vcpu, sregs->efer); - kvm_set_apic_base(vcpu, sregs->apic_base); + apic_base_msr.data = sregs->apic_base; + apic_base_msr.host_initiated = true; + kvm_set_apic_base(vcpu, &apic_base_msr); mmu_reset_needed |= kvm_read_cr0(vcpu) != sregs->cr0; kvm_x86_ops->set_cr0(vcpu, sregs->cr0); diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index bdf8532494fed0..ad1fb5f53925e8 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -233,13 +233,13 @@ static void lguest_end_context_switch(struct task_struct *next) * flags word contains all kind of stuff, but in practice Linux only cares * about the interrupt flag. Our "save_flags()" just returns that. */ -static unsigned long save_fl(void) +asmlinkage unsigned long lguest_save_fl(void) { return lguest_data.irq_enabled; } /* Interrupts go off... */ -static void irq_disable(void) +asmlinkage void lguest_irq_disable(void) { lguest_data.irq_enabled = 0; } @@ -253,8 +253,8 @@ static void irq_disable(void) * PV_CALLEE_SAVE_REGS_THUNK(), which pushes %eax onto the stack, calls the * C function, then restores it. */ -PV_CALLEE_SAVE_REGS_THUNK(save_fl); -PV_CALLEE_SAVE_REGS_THUNK(irq_disable); +PV_CALLEE_SAVE_REGS_THUNK(lguest_save_fl); +PV_CALLEE_SAVE_REGS_THUNK(lguest_irq_disable); /*:*/ /* These are in i386_head.S */ @@ -1291,9 +1291,9 @@ __init void lguest_init(void) */ /* Interrupt-related operations */ - pv_irq_ops.save_fl = PV_CALLEE_SAVE(save_fl); + pv_irq_ops.save_fl = PV_CALLEE_SAVE(lguest_save_fl); pv_irq_ops.restore_fl = __PV_IS_CALLEE_SAVE(lg_restore_fl); - pv_irq_ops.irq_disable = PV_CALLEE_SAVE(irq_disable); + pv_irq_ops.irq_disable = PV_CALLEE_SAVE(lguest_irq_disable); pv_irq_ops.irq_enable = __PV_IS_CALLEE_SAVE(lg_irq_enable); pv_irq_ops.safe_halt = lguest_safe_halt; diff --git a/arch/x86/math-emu/errors.c b/arch/x86/math-emu/errors.c index 59d353d2c599ec..a5449089cd9fef 100644 --- a/arch/x86/math-emu/errors.c +++ b/arch/x86/math-emu/errors.c @@ -330,11 +330,6 @@ asmlinkage void FPU_exception(int n) RE_ENTRANT_CHECK_OFF; if ((~control_word & n & CW_Exceptions) || (n == EX_INTERNAL)) { -#ifdef PRINT_MESSAGES - /* My message from the sponsor */ - printk(FPU_VERSION " " __DATE__ " (C) W. Metzenthen.\n"); -#endif /* PRINT_MESSAGES */ - /* Get a name string for error reporting */ for (i = 0; exception_names[i].type; i++) if ((exception_names[i].type & n) == diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 9d591c89580310..6dea040cc3a1d7 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -1001,6 +1001,12 @@ static int fault_in_kernel_space(unsigned long address) static inline bool smap_violation(int error_code, struct pt_regs *regs) { + if (!IS_ENABLED(CONFIG_X86_SMAP)) + return false; + + if (!static_cpu_has(X86_FEATURE_SMAP)) + return false; + if (error_code & PF_USER) return false; @@ -1087,11 +1093,9 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code) if (unlikely(error_code & PF_RSVD)) pgtable_bad(regs, error_code, address); - if (static_cpu_has(X86_FEATURE_SMAP)) { - if (unlikely(smap_violation(error_code, regs))) { - bad_area_nosemaphore(regs, error_code, address); - return; - } + if (unlikely(smap_violation(error_code, regs))) { + bad_area_nosemaphore(regs, error_code, address); + return; } /* diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index 81b2750f3666f1..27aa0455fab31b 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -493,14 +493,6 @@ static int __init numa_register_memblks(struct numa_meminfo *mi) struct numa_memblk *mb = &mi->blk[i]; memblock_set_node(mb->start, mb->end - mb->start, &memblock.memory, mb->nid); - - /* - * At this time, all memory regions reserved by memblock are - * used by the kernel. Set the nid in memblock.reserved will - * mark out all the nodes the kernel resides in. - */ - memblock_set_node(mb->start, mb->end - mb->start, - &memblock.reserved, mb->nid); } /* @@ -565,10 +557,21 @@ static void __init numa_init_array(void) static void __init numa_clear_kernel_node_hotplug(void) { int i, nid; - nodemask_t numa_kernel_nodes; + nodemask_t numa_kernel_nodes = NODE_MASK_NONE; unsigned long start, end; struct memblock_type *type = &memblock.reserved; + /* + * At this time, all memory regions reserved by memblock are + * used by the kernel. Set the nid in memblock.reserved will + * mark out all the nodes the kernel resides in. + */ + for (i = 0; i < numa_meminfo.nr_blks; i++) { + struct numa_memblk *mb = &numa_meminfo.blk[i]; + memblock_set_node(mb->start, mb->end - mb->start, + &memblock.reserved, mb->nid); + } + /* Mark all kernel nodes. */ for (i = 0; i < type->cnt; i++) node_set(type->regions[i].nid, numa_kernel_nodes); diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 0342d27ca79869..47b6436e41c24a 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -52,6 +52,8 @@ void memory_present(int nid, unsigned long start, unsigned long end) nid, start, end); printk(KERN_DEBUG " Setting physnode_map array to node %d for pfns:\n", nid); printk(KERN_DEBUG " "); + start = round_down(start, PAGES_PER_SECTION); + end = round_up(end, PAGES_PER_SECTION); for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) { physnode_map[pfn / PAGES_PER_SECTION] = nid; printk(KERN_CONT "%lx ", pfn); diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c index 1a25187e151e90..1953e9c9391aec 100644 --- a/arch/x86/mm/srat.c +++ b/arch/x86/mm/srat.c @@ -42,15 +42,25 @@ static __init inline int srat_disabled(void) return acpi_numa < 0; } -/* Callback for SLIT parsing */ +/* + * Callback for SLIT parsing. pxm_to_node() returns NUMA_NO_NODE for + * I/O localities since SRAT does not list them. I/O localities are + * not supported at this point. + */ void __init acpi_numa_slit_init(struct acpi_table_slit *slit) { int i, j; - for (i = 0; i < slit->locality_count; i++) - for (j = 0; j < slit->locality_count; j++) + for (i = 0; i < slit->locality_count; i++) { + if (pxm_to_node(i) == NUMA_NO_NODE) + continue; + for (j = 0; j < slit->locality_count; j++) { + if (pxm_to_node(j) == NUMA_NO_NODE) + continue; numa_set_distance(pxm_to_node(i), pxm_to_node(j), slit->entry[slit->locality_count * i + j]); + } + } } /* Callback for Proximity Domain -> x2APIC mapping */ diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index ae699b3bbac84a..dd8dda167a2426 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -103,7 +103,7 @@ static void flush_tlb_func(void *info) if (f->flush_mm != this_cpu_read(cpu_tlbstate.active_mm)) return; - count_vm_event(NR_TLB_REMOTE_FLUSH_RECEIVED); + count_vm_tlb_event(NR_TLB_REMOTE_FLUSH_RECEIVED); if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_OK) { if (f->flush_end == TLB_FLUSH_ALL) local_flush_tlb(); @@ -131,7 +131,7 @@ void native_flush_tlb_others(const struct cpumask *cpumask, info.flush_start = start; info.flush_end = end; - count_vm_event(NR_TLB_REMOTE_FLUSH); + count_vm_tlb_event(NR_TLB_REMOTE_FLUSH); if (is_uv_system()) { unsigned int cpu; @@ -151,44 +151,19 @@ void flush_tlb_current_task(void) preempt_disable(); - count_vm_event(NR_TLB_LOCAL_FLUSH_ALL); + count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL); local_flush_tlb(); if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids) flush_tlb_others(mm_cpumask(mm), mm, 0UL, TLB_FLUSH_ALL); preempt_enable(); } -/* - * It can find out the THP large page, or - * HUGETLB page in tlb_flush when THP disabled - */ -static inline unsigned long has_large_page(struct mm_struct *mm, - unsigned long start, unsigned long end) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - unsigned long addr = ALIGN(start, HPAGE_SIZE); - for (; addr < end; addr += HPAGE_SIZE) { - pgd = pgd_offset(mm, addr); - if (likely(!pgd_none(*pgd))) { - pud = pud_offset(pgd, addr); - if (likely(!pud_none(*pud))) { - pmd = pmd_offset(pud, addr); - if (likely(!pmd_none(*pmd))) - if (pmd_large(*pmd)) - return addr; - } - } - } - return 0; -} - void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, unsigned long end, unsigned long vmflag) { unsigned long addr; unsigned act_entries, tlb_entries = 0; + unsigned long nr_base_pages; preempt_disable(); if (current->active_mm != mm) @@ -210,21 +185,20 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, tlb_entries = tlb_lli_4k[ENTRIES]; else tlb_entries = tlb_lld_4k[ENTRIES]; + /* Assume all of TLB entries was occupied by this task */ - act_entries = mm->total_vm > tlb_entries ? tlb_entries : mm->total_vm; + act_entries = tlb_entries >> tlb_flushall_shift; + act_entries = mm->total_vm > act_entries ? act_entries : mm->total_vm; + nr_base_pages = (end - start) >> PAGE_SHIFT; /* tlb_flushall_shift is on balance point, details in commit log */ - if ((end - start) >> PAGE_SHIFT > act_entries >> tlb_flushall_shift) { - count_vm_event(NR_TLB_LOCAL_FLUSH_ALL); + if (nr_base_pages > act_entries) { + count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL); local_flush_tlb(); } else { - if (has_large_page(mm, start, end)) { - local_flush_tlb(); - goto flush_all; - } /* flush range by one by one 'invlpg' */ for (addr = start; addr < end; addr += PAGE_SIZE) { - count_vm_event(NR_TLB_LOCAL_FLUSH_ONE); + count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ONE); __flush_tlb_single(addr); } @@ -262,7 +236,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long start) static void do_flush_tlb_all(void *info) { - count_vm_event(NR_TLB_REMOTE_FLUSH_RECEIVED); + count_vm_tlb_event(NR_TLB_REMOTE_FLUSH_RECEIVED); __flush_tlb_all(); if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_LAZY) leave_mm(smp_processor_id()); @@ -270,7 +244,7 @@ static void do_flush_tlb_all(void *info) void flush_tlb_all(void) { - count_vm_event(NR_TLB_REMOTE_FLUSH); + count_vm_tlb_event(NR_TLB_REMOTE_FLUSH); on_each_cpu(do_flush_tlb_all, NULL, 1); } diff --git a/arch/x86/platform/efi/efi-bgrt.c b/arch/x86/platform/efi/efi-bgrt.c index 7145ec63c5205f..f15103dff4b43f 100644 --- a/arch/x86/platform/efi/efi-bgrt.c +++ b/arch/x86/platform/efi/efi-bgrt.c @@ -42,14 +42,15 @@ void __init efi_bgrt_init(void) if (bgrt_tab->header.length < sizeof(*bgrt_tab)) return; - if (bgrt_tab->version != 1) + if (bgrt_tab->version != 1 || bgrt_tab->status != 1) return; if (bgrt_tab->image_type != 0 || !bgrt_tab->image_address) return; image = efi_lookup_mapped_addr(bgrt_tab->image_address); if (!image) { - image = ioremap(bgrt_tab->image_address, sizeof(bmp_header)); + image = early_memremap(bgrt_tab->image_address, + sizeof(bmp_header)); ioremapped = true; if (!image) return; @@ -57,7 +58,7 @@ void __init efi_bgrt_init(void) memcpy_fromio(&bmp_header, image, sizeof(bmp_header)); if (ioremapped) - iounmap(image); + early_iounmap(image, sizeof(bmp_header)); bgrt_image_size = bmp_header.size; bgrt_image = kmalloc(bgrt_image_size, GFP_KERNEL); @@ -65,7 +66,8 @@ void __init efi_bgrt_init(void) return; if (ioremapped) { - image = ioremap(bgrt_tab->image_address, bmp_header.size); + image = early_memremap(bgrt_tab->image_address, + bmp_header.size); if (!image) { kfree(bgrt_image); bgrt_image = NULL; @@ -75,5 +77,5 @@ void __init efi_bgrt_init(void) memcpy_fromio(bgrt_image, image, bgrt_image_size); if (ioremapped) - iounmap(image); + early_iounmap(image, bmp_header.size); } diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index d62ec87a2b26d5..1a201ac7cef8a1 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -792,7 +792,7 @@ void __init efi_set_executable(efi_memory_desc_t *md, bool executable) set_memory_nx(addr, npages); } -static void __init runtime_code_page_mkexec(void) +void __init runtime_code_page_mkexec(void) { efi_memory_desc_t *md; void *p; @@ -1069,8 +1069,7 @@ void __init efi_enter_virtual_mode(void) efi.update_capsule = virt_efi_update_capsule; efi.query_capsule_caps = virt_efi_query_capsule_caps; - if (efi_enabled(EFI_OLD_MEMMAP) && (__supported_pte_mask & _PAGE_NX)) - runtime_code_page_mkexec(); + efi_runtime_mkexec(); kfree(new_memmap); diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c index 249b183cf41799..0b74cdf7f816aa 100644 --- a/arch/x86/platform/efi/efi_32.c +++ b/arch/x86/platform/efi/efi_32.c @@ -77,3 +77,9 @@ void efi_call_phys_epilog(void) local_irq_restore(efi_rt_eflags); } + +void __init efi_runtime_mkexec(void) +{ + if (__supported_pte_mask & _PAGE_NX) + runtime_code_page_mkexec(); +} diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index 6284f158a47d85..0c2a234fef1e48 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -233,3 +233,12 @@ void __init parse_efi_setup(u64 phys_addr, u32 data_len) { efi_setup = phys_addr + sizeof(struct setup_data); } + +void __init efi_runtime_mkexec(void) +{ + if (!efi_enabled(EFI_OLD_MEMMAP)) + return; + + if (__supported_pte_mask & _PAGE_NX) + runtime_code_page_mkexec(); +} diff --git a/arch/x86/platform/intel-mid/device_libs/platform_ipc.h b/arch/x86/platform/intel-mid/device_libs/platform_ipc.h index 8f568dd7960505..79bb09d4f718f0 100644 --- a/arch/x86/platform/intel-mid/device_libs/platform_ipc.h +++ b/arch/x86/platform/intel-mid/device_libs/platform_ipc.h @@ -12,6 +12,7 @@ #ifndef _PLATFORM_IPC_H_ #define _PLATFORM_IPC_H_ -extern void __init ipc_device_handler(struct sfi_device_table_entry *pentry, - struct devs_id *dev) __attribute__((weak)); +void __init +ipc_device_handler(struct sfi_device_table_entry *pentry, struct devs_id *dev); + #endif diff --git a/arch/x86/platform/intel-mid/device_libs/platform_msic.h b/arch/x86/platform/intel-mid/device_libs/platform_msic.h index 917eb56d77dab1..b7be1d041da233 100644 --- a/arch/x86/platform/intel-mid/device_libs/platform_msic.h +++ b/arch/x86/platform/intel-mid/device_libs/platform_msic.h @@ -14,6 +14,6 @@ extern struct intel_msic_platform_data msic_pdata; -extern void *msic_generic_platform_data(void *info, - enum intel_msic_block block) __attribute__((weak)); +void *msic_generic_platform_data(void *info, enum intel_msic_block block); + #endif diff --git a/arch/x86/platform/intel-mid/intel_mid_weak_decls.h b/arch/x86/platform/intel-mid/intel_mid_weak_decls.h index a537ffc16299bf..46aa25c8ce06c3 100644 --- a/arch/x86/platform/intel-mid/intel_mid_weak_decls.h +++ b/arch/x86/platform/intel-mid/intel_mid_weak_decls.h @@ -14,6 +14,6 @@ /* For every CPU addition a new get__ops interface needs * to be added. */ -extern void * __cpuinit get_penwell_ops(void) __attribute__((weak)); -extern void * __cpuinit get_cloverview_ops(void) __attribute__((weak)); -extern void * __init get_tangier_ops(void) __attribute__((weak)); +extern void *get_penwell_ops(void) __attribute__((weak)); +extern void *get_cloverview_ops(void) __attribute__((weak)); +extern void *get_tangier_ops(void) __attribute__((weak)); diff --git a/arch/x86/platform/intel-mid/mfld.c b/arch/x86/platform/intel-mid/mfld.c index 4f7884eebc149a..23381d2174ae1d 100644 --- a/arch/x86/platform/intel-mid/mfld.c +++ b/arch/x86/platform/intel-mid/mfld.c @@ -58,18 +58,18 @@ static unsigned long __init mfld_calibrate_tsc(void) return 0; } -static void __init penwell_arch_setup() +static void __init penwell_arch_setup(void) { x86_platform.calibrate_tsc = mfld_calibrate_tsc; pm_power_off = mfld_power_off; } -void * __cpuinit get_penwell_ops() +void *get_penwell_ops(void) { return &penwell_ops; } -void * __cpuinit get_cloverview_ops() +void *get_cloverview_ops(void) { return &penwell_ops; } diff --git a/arch/x86/platform/intel-mid/mrfl.c b/arch/x86/platform/intel-mid/mrfl.c index 09d10159e7b7f9..aaca91753d3267 100644 --- a/arch/x86/platform/intel-mid/mrfl.c +++ b/arch/x86/platform/intel-mid/mrfl.c @@ -97,7 +97,7 @@ static struct intel_mid_ops tangier_ops = { .arch_setup = tangier_arch_setup, }; -void * __cpuinit get_tangier_ops() +void *get_tangier_ops(void) { return &tangier_ops; } diff --git a/arch/x86/platform/uv/uv_nmi.c b/arch/x86/platform/uv/uv_nmi.c index 8eeccba731304b..be27da60dc8f8d 100644 --- a/arch/x86/platform/uv/uv_nmi.c +++ b/arch/x86/platform/uv/uv_nmi.c @@ -74,7 +74,6 @@ static atomic_t uv_in_nmi; static atomic_t uv_nmi_cpu = ATOMIC_INIT(-1); static atomic_t uv_nmi_cpus_in_nmi = ATOMIC_INIT(-1); static atomic_t uv_nmi_slave_continue; -static atomic_t uv_nmi_kexec_failed; static cpumask_var_t uv_nmi_cpu_mask; /* Values for uv_nmi_slave_continue */ @@ -149,7 +148,8 @@ module_param_named(retry_count, uv_nmi_retry_count, int, 0644); * "dump" - dump process stack for each cpu * "ips" - dump IP info for each cpu * "kdump" - do crash dump - * "kdb" - enter KDB/KGDB (default) + * "kdb" - enter KDB (default) + * "kgdb" - enter KGDB */ static char uv_nmi_action[8] = "kdb"; module_param_string(action, uv_nmi_action, sizeof(uv_nmi_action), 0644); @@ -504,6 +504,7 @@ static void uv_nmi_touch_watchdogs(void) } #if defined(CONFIG_KEXEC) +static atomic_t uv_nmi_kexec_failed; static void uv_nmi_kdump(int cpu, int master, struct pt_regs *regs) { /* Call crash to dump system state */ @@ -537,18 +538,45 @@ static inline void uv_nmi_kdump(int cpu, int master, struct pt_regs *regs) } #endif /* !CONFIG_KEXEC */ +#ifdef CONFIG_KGDB #ifdef CONFIG_KGDB_KDB -/* Call KDB from NMI handler */ -static void uv_call_kdb(int cpu, struct pt_regs *regs, int master) +static inline int uv_nmi_kdb_reason(void) { - int ret; + return KDB_REASON_SYSTEM_NMI; +} +#else /* !CONFIG_KGDB_KDB */ +static inline int uv_nmi_kdb_reason(void) +{ + /* Insure user is expecting to attach gdb remote */ + if (uv_nmi_action_is("kgdb")) + return 0; + + pr_err("UV: NMI error: KDB is not enabled in this kernel\n"); + return -1; +} +#endif /* CONFIG_KGDB_KDB */ +/* + * Call KGDB/KDB from NMI handler + * + * Note that if both KGDB and KDB are configured, then the action of 'kgdb' or + * 'kdb' has no affect on which is used. See the KGDB documention for further + * information. + */ +static void uv_call_kgdb_kdb(int cpu, struct pt_regs *regs, int master) +{ if (master) { + int reason = uv_nmi_kdb_reason(); + int ret; + + if (reason < 0) + return; + /* call KGDB NMI handler as MASTER */ - ret = kgdb_nmicallin(cpu, X86_TRAP_NMI, regs, - &uv_nmi_slave_continue); + ret = kgdb_nmicallin(cpu, X86_TRAP_NMI, regs, reason, + &uv_nmi_slave_continue); if (ret) { - pr_alert("KDB returned error, is kgdboc set?\n"); + pr_alert("KGDB returned error, is kgdboc set?\n"); atomic_set(&uv_nmi_slave_continue, SLAVE_EXIT); } } else { @@ -567,12 +595,12 @@ static void uv_call_kdb(int cpu, struct pt_regs *regs, int master) uv_nmi_sync_exit(master); } -#else /* !CONFIG_KGDB_KDB */ -static inline void uv_call_kdb(int cpu, struct pt_regs *regs, int master) +#else /* !CONFIG_KGDB */ +static inline void uv_call_kgdb_kdb(int cpu, struct pt_regs *regs, int master) { - pr_err("UV: NMI error: KGDB/KDB is not enabled in this kernel\n"); + pr_err("UV: NMI error: KGDB is not enabled in this kernel\n"); } -#endif /* !CONFIG_KGDB_KDB */ +#endif /* !CONFIG_KGDB */ /* * UV NMI handler @@ -606,9 +634,9 @@ int uv_handle_nmi(unsigned int reason, struct pt_regs *regs) if (uv_nmi_action_is("ips") || uv_nmi_action_is("dump")) uv_nmi_dump_state(cpu, regs, master); - /* Call KDB if enabled */ - else if (uv_nmi_action_is("kdb")) - uv_call_kdb(cpu, regs, master); + /* Call KGDB/KDB if enabled */ + else if (uv_nmi_action_is("kdb") || uv_nmi_action_is("kgdb")) + uv_call_kgdb_kdb(cpu, regs, master); /* Clear per_cpu "in nmi" flag */ atomic_set(&uv_cpu_nmi.state, UV_NMI_STATE_OUT); @@ -634,7 +662,7 @@ int uv_handle_nmi(unsigned int reason, struct pt_regs *regs) /* * NMI handler for pulling in CPUs when perf events are grabbing our NMI */ -int uv_handle_nmi_ping(unsigned int reason, struct pt_regs *regs) +static int uv_handle_nmi_ping(unsigned int reason, struct pt_regs *regs) { int ret; @@ -651,7 +679,7 @@ int uv_handle_nmi_ping(unsigned int reason, struct pt_regs *regs) return ret; } -void uv_register_nmi_notifier(void) +static void uv_register_nmi_notifier(void) { if (register_nmi_handler(NMI_UNKNOWN, uv_handle_nmi, 0, "uv")) pr_warn("UV: NMI handler failed to register\n"); @@ -695,6 +723,5 @@ void uv_nmi_setup(void) uv_hub_nmi_per(cpu) = uv_hub_nmi_list[nid]; } BUG_ON(!alloc_cpumask_var(&uv_nmi_cpu_mask, GFP_KERNEL)); + uv_register_nmi_notifier(); } - - diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile index 9cac82588cbc49..3497f14e4dea8a 100644 --- a/arch/x86/realmode/rm/Makefile +++ b/arch/x86/realmode/rm/Makefile @@ -64,20 +64,7 @@ $(obj)/realmode.relocs: $(obj)/realmode.elf FORCE # --------------------------------------------------------------------------- -# How to compile the 16-bit code. Note we always compile for -march=i386, -# that way we can complain to the user if the CPU is insufficient. -KBUILD_CFLAGS := $(LINUXINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ -D_WAKEUP \ - -I$(srctree)/arch/x86/boot \ - -DDISABLE_BRANCH_PROFILING \ - -Wall -Wstrict-prototypes \ - -march=i386 -mregparm=3 \ - -include $(srctree)/$(src)/../../boot/code16gcc.h \ - -fno-strict-aliasing -fomit-frame-pointer -fno-pic \ - -mno-mmx -mno-sse \ - $(call cc-option, -ffreestanding) \ - $(call cc-option, -fno-toplevel-reorder,\ - $(call cc-option, -fno-unit-at-a-time)) \ - $(call cc-option, -fno-stack-protector) \ - $(call cc-option, -mpreferred-stack-boundary=2) +KBUILD_CFLAGS := $(LINUXINCLUDE) $(REALMODE_CFLAGS) -D_SETUP -D_WAKEUP \ + -I$(srctree)/arch/x86/boot KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ GCOV_PROFILE := n diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c index 11f9285a2ff667..cfbdbdb4e1737c 100644 --- a/arch/x86/tools/relocs.c +++ b/arch/x86/tools/relocs.c @@ -1025,6 +1025,29 @@ static void emit_relocs(int as_text, int use_real_mode) } } +/* + * As an aid to debugging problems with different linkers + * print summary information about the relocs. + * Since different linkers tend to emit the sections in + * different orders we use the section names in the output. + */ +static int do_reloc_info(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, + const char *symname) +{ + printf("%s\t%s\t%s\t%s\n", + sec_name(sec->shdr.sh_info), + rel_type(ELF_R_TYPE(rel->r_info)), + symname, + sec_name(sym->st_shndx)); + return 0; +} + +static void print_reloc_info(void) +{ + printf("reloc section\treloc type\tsymbol\tsymbol section\n"); + walk_relocs(do_reloc_info); +} + #if ELF_BITS == 64 # define process process_64 #else @@ -1032,7 +1055,8 @@ static void emit_relocs(int as_text, int use_real_mode) #endif void process(FILE *fp, int use_real_mode, int as_text, - int show_absolute_syms, int show_absolute_relocs) + int show_absolute_syms, int show_absolute_relocs, + int show_reloc_info) { regex_init(use_real_mode); read_ehdr(fp); @@ -1050,5 +1074,9 @@ void process(FILE *fp, int use_real_mode, int as_text, print_absolute_relocs(); return; } + if (show_reloc_info) { + print_reloc_info(); + return; + } emit_relocs(as_text, use_real_mode); } diff --git a/arch/x86/tools/relocs.h b/arch/x86/tools/relocs.h index 07cdb1eca4fa60..f59590645b6864 100644 --- a/arch/x86/tools/relocs.h +++ b/arch/x86/tools/relocs.h @@ -29,8 +29,9 @@ enum symtype { }; void process_32(FILE *fp, int use_real_mode, int as_text, - int show_absolute_syms, int show_absolute_relocs); + int show_absolute_syms, int show_absolute_relocs, + int show_reloc_info); void process_64(FILE *fp, int use_real_mode, int as_text, - int show_absolute_syms, int show_absolute_relocs); - + int show_absolute_syms, int show_absolute_relocs, + int show_reloc_info); #endif /* RELOCS_H */ diff --git a/arch/x86/tools/relocs_common.c b/arch/x86/tools/relocs_common.c index 44d396823a5309..acab636bcb3481 100644 --- a/arch/x86/tools/relocs_common.c +++ b/arch/x86/tools/relocs_common.c @@ -11,12 +11,13 @@ void die(char *fmt, ...) static void usage(void) { - die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n"); + die("relocs [--abs-syms|--abs-relocs|--reloc-info|--text|--realmode]" \ + " vmlinux\n"); } int main(int argc, char **argv) { - int show_absolute_syms, show_absolute_relocs; + int show_absolute_syms, show_absolute_relocs, show_reloc_info; int as_text, use_real_mode; const char *fname; FILE *fp; @@ -25,6 +26,7 @@ int main(int argc, char **argv) show_absolute_syms = 0; show_absolute_relocs = 0; + show_reloc_info = 0; as_text = 0; use_real_mode = 0; fname = NULL; @@ -39,6 +41,10 @@ int main(int argc, char **argv) show_absolute_relocs = 1; continue; } + if (strcmp(arg, "--reloc-info") == 0) { + show_reloc_info = 1; + continue; + } if (strcmp(arg, "--text") == 0) { as_text = 1; continue; @@ -67,10 +73,12 @@ int main(int argc, char **argv) rewind(fp); if (e_ident[EI_CLASS] == ELFCLASS64) process_64(fp, use_real_mode, as_text, - show_absolute_syms, show_absolute_relocs); + show_absolute_syms, show_absolute_relocs, + show_reloc_info); else process_32(fp, use_real_mode, as_text, - show_absolute_syms, show_absolute_relocs); + show_absolute_syms, show_absolute_relocs, + show_reloc_info); fclose(fp); return 0; } diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index a4d7b647867f30..201d09a7c46bba 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -1473,6 +1473,18 @@ static void xen_pvh_set_cr_flags(int cpu) * X86_CR0_TS, X86_CR0_PE, X86_CR0_ET are set by Xen for HVM guests * (which PVH shared codepaths), while X86_CR0_PG is for PVH. */ write_cr0(read_cr0() | X86_CR0_MP | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM); + + if (!cpu) + return; + /* + * For BSP, PSE PGE are set in probe_page_size_mask(), for APs + * set them here. For all, OSFXSR OSXMMEXCPT are set in fpu_init. + */ + if (cpu_has_pse) + set_in_cr4(X86_CR4_PSE); + + if (cpu_has_pge) + set_in_cr4(X86_CR4_PGE); } /* diff --git a/arch/x86/xen/grant-table.c b/arch/x86/xen/grant-table.c index 103c93f874b27c..c985835885802a 100644 --- a/arch/x86/xen/grant-table.c +++ b/arch/x86/xen/grant-table.c @@ -162,14 +162,15 @@ static int __init xlated_setup_gnttab_pages(void) rc = arch_gnttab_map_shared(pfns, nr_grant_frames, nr_grant_frames, &xen_auto_xlat_grant_frames.vaddr); - kfree(pages); if (rc) { pr_warn("%s Couldn't map %ld pfns rc:%d\n", __func__, nr_grant_frames, rc); free_xenballooned_pages(nr_grant_frames, pages); + kfree(pages); kfree(pfns); return rc; } + kfree(pages); xen_auto_xlat_grant_frames.pfn = pfns; xen_auto_xlat_grant_frames.count = nr_grant_frames; diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c index 76ca326105f71d..08f763de26fe41 100644 --- a/arch/x86/xen/irq.c +++ b/arch/x86/xen/irq.c @@ -23,7 +23,7 @@ void xen_force_evtchn_callback(void) (void)HYPERVISOR_xen_version(0, NULL); } -static unsigned long xen_save_fl(void) +asmlinkage unsigned long xen_save_fl(void) { struct vcpu_info *vcpu; unsigned long flags; @@ -41,7 +41,7 @@ static unsigned long xen_save_fl(void) } PV_CALLEE_SAVE_REGS_THUNK(xen_save_fl); -static void xen_restore_fl(unsigned long flags) +__visible void xen_restore_fl(unsigned long flags) { struct vcpu_info *vcpu; @@ -63,7 +63,7 @@ static void xen_restore_fl(unsigned long flags) } PV_CALLEE_SAVE_REGS_THUNK(xen_restore_fl); -static void xen_irq_disable(void) +asmlinkage void xen_irq_disable(void) { /* There's a one instruction preempt window here. We need to make sure we're don't switch CPUs between getting the vcpu @@ -74,7 +74,7 @@ static void xen_irq_disable(void) } PV_CALLEE_SAVE_REGS_THUNK(xen_irq_disable); -static void xen_irq_enable(void) +asmlinkage void xen_irq_enable(void) { struct vcpu_info *vcpu; diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index c1d406f3552314..256282e7888b11 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -365,7 +365,7 @@ void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr, /* Assume pteval_t is equivalent to all the other *val_t types. */ static pteval_t pte_mfn_to_pfn(pteval_t val) { - if (val & _PAGE_PRESENT) { + if (pteval_present(val)) { unsigned long mfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT; unsigned long pfn = mfn_to_pfn(mfn); @@ -381,7 +381,7 @@ static pteval_t pte_mfn_to_pfn(pteval_t val) static pteval_t pte_pfn_to_mfn(pteval_t val) { - if (val & _PAGE_PRESENT) { + if (pteval_present(val)) { unsigned long pfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT; pteval_t flags = val & PTE_FLAGS_MASK; unsigned long mfn; @@ -431,7 +431,7 @@ static pteval_t iomap_pte(pteval_t val) return val; } -static pteval_t xen_pte_val(pte_t pte) +__visible pteval_t xen_pte_val(pte_t pte) { pteval_t pteval = pte.pte; #if 0 @@ -448,7 +448,7 @@ static pteval_t xen_pte_val(pte_t pte) } PV_CALLEE_SAVE_REGS_THUNK(xen_pte_val); -static pgdval_t xen_pgd_val(pgd_t pgd) +__visible pgdval_t xen_pgd_val(pgd_t pgd) { return pte_mfn_to_pfn(pgd.pgd); } @@ -479,7 +479,7 @@ void xen_set_pat(u64 pat) WARN_ON(pat != 0x0007010600070106ull); } -static pte_t xen_make_pte(pteval_t pte) +__visible pte_t xen_make_pte(pteval_t pte) { phys_addr_t addr = (pte & PTE_PFN_MASK); #if 0 @@ -514,14 +514,14 @@ static pte_t xen_make_pte(pteval_t pte) } PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte); -static pgd_t xen_make_pgd(pgdval_t pgd) +__visible pgd_t xen_make_pgd(pgdval_t pgd) { pgd = pte_pfn_to_mfn(pgd); return native_make_pgd(pgd); } PV_CALLEE_SAVE_REGS_THUNK(xen_make_pgd); -static pmdval_t xen_pmd_val(pmd_t pmd) +__visible pmdval_t xen_pmd_val(pmd_t pmd) { return pte_mfn_to_pfn(pmd.pmd); } @@ -580,7 +580,7 @@ static void xen_pmd_clear(pmd_t *pmdp) } #endif /* CONFIG_X86_PAE */ -static pmd_t xen_make_pmd(pmdval_t pmd) +__visible pmd_t xen_make_pmd(pmdval_t pmd) { pmd = pte_pfn_to_mfn(pmd); return native_make_pmd(pmd); @@ -588,13 +588,13 @@ static pmd_t xen_make_pmd(pmdval_t pmd) PV_CALLEE_SAVE_REGS_THUNK(xen_make_pmd); #if PAGETABLE_LEVELS == 4 -static pudval_t xen_pud_val(pud_t pud) +__visible pudval_t xen_pud_val(pud_t pud) { return pte_mfn_to_pfn(pud.pud); } PV_CALLEE_SAVE_REGS_THUNK(xen_pud_val); -static pud_t xen_make_pud(pudval_t pud) +__visible pud_t xen_make_pud(pudval_t pud) { pud = pte_pfn_to_mfn(pud); diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index dd5f905e33d5e1..0982233b9b8433 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -35,7 +35,7 @@ extern const char xen_hypervisor_callback[]; extern const char xen_failsafe_callback[]; #ifdef CONFIG_X86_64 -extern const char nmi[]; +extern asmlinkage void nmi(void); #endif extern void xen_sysenter_target(void); extern void xen_syscall_target(void); @@ -577,7 +577,7 @@ void xen_enable_syscall(void) void xen_enable_nmi(void) { #ifdef CONFIG_X86_64 - if (register_callback(CALLBACKTYPE_nmi, nmi)) + if (register_callback(CALLBACKTYPE_nmi, (char *)nmi)) BUG(); #endif } diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c index 0e36cde12f7e7d..581521c843a576 100644 --- a/arch/x86/xen/spinlock.c +++ b/arch/x86/xen/spinlock.c @@ -106,7 +106,7 @@ static DEFINE_PER_CPU(struct xen_lock_waiting, lock_waiting); static cpumask_t waiting_cpus; static bool xen_pvspin = true; -static void xen_lock_spinning(struct arch_spinlock *lock, __ticket_t want) +__visible void xen_lock_spinning(struct arch_spinlock *lock, __ticket_t want) { int irq = __this_cpu_read(lock_kicker_irq); struct xen_lock_waiting *w = &__get_cpu_var(lock_waiting); diff --git a/arch/xtensa/platforms/iss/simdisk.c b/arch/xtensa/platforms/iss/simdisk.c index 8c6e819cd8edcc..48eebacdf5fe08 100644 --- a/arch/xtensa/platforms/iss/simdisk.c +++ b/arch/xtensa/platforms/iss/simdisk.c @@ -103,18 +103,18 @@ static void simdisk_transfer(struct simdisk *dev, unsigned long sector, static int simdisk_xfer_bio(struct simdisk *dev, struct bio *bio) { - int i; - struct bio_vec *bvec; - sector_t sector = bio->bi_sector; + struct bio_vec bvec; + struct bvec_iter iter; + sector_t sector = bio->bi_iter.bi_sector; - bio_for_each_segment(bvec, bio, i) { - char *buffer = __bio_kmap_atomic(bio, i); - unsigned len = bvec->bv_len >> SECTOR_SHIFT; + bio_for_each_segment(bvec, bio, iter) { + char *buffer = __bio_kmap_atomic(bio, iter); + unsigned len = bvec.bv_len >> SECTOR_SHIFT; simdisk_transfer(dev, sector, len, buffer, bio_data_dir(bio) == WRITE); sector += len; - __bio_kunmap_atomic(bio); + __bio_kunmap_atomic(buffer); } return 0; } diff --git a/block/blk-core.c b/block/blk-core.c index 8bdd0121212a51..853f92749202cb 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -38,6 +38,7 @@ #include "blk.h" #include "blk-cgroup.h" +#include "blk-mq.h" EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap); EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap); @@ -130,7 +131,7 @@ static void req_bio_endio(struct request *rq, struct bio *bio, bio_advance(bio, nbytes); /* don't actually finish bio if it's part of flush sequence */ - if (bio->bi_size == 0 && !(rq->cmd_flags & REQ_FLUSH_SEQ)) + if (bio->bi_iter.bi_size == 0 && !(rq->cmd_flags & REQ_FLUSH_SEQ)) bio_endio(bio, error); } @@ -245,7 +246,16 @@ EXPORT_SYMBOL(blk_stop_queue); void blk_sync_queue(struct request_queue *q) { del_timer_sync(&q->timeout); - cancel_delayed_work_sync(&q->delay_work); + + if (q->mq_ops) { + struct blk_mq_hw_ctx *hctx; + int i; + + queue_for_each_hw_ctx(q, hctx, i) + cancel_delayed_work_sync(&hctx->delayed_work); + } else { + cancel_delayed_work_sync(&q->delay_work); + } } EXPORT_SYMBOL(blk_sync_queue); @@ -497,8 +507,13 @@ void blk_cleanup_queue(struct request_queue *q) * Drain all requests queued before DYING marking. Set DEAD flag to * prevent that q->request_fn() gets invoked after draining finished. */ - spin_lock_irq(lock); - __blk_drain_queue(q, true); + if (q->mq_ops) { + blk_mq_drain_queue(q); + spin_lock_irq(lock); + } else { + spin_lock_irq(lock); + __blk_drain_queue(q, true); + } queue_flag_set(QUEUE_FLAG_DEAD, q); spin_unlock_irq(lock); @@ -678,11 +693,20 @@ blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id) if (!uninit_q) return NULL; + uninit_q->flush_rq = kzalloc(sizeof(struct request), GFP_KERNEL); + if (!uninit_q->flush_rq) + goto out_cleanup_queue; + q = blk_init_allocated_queue(uninit_q, rfn, lock); if (!q) - blk_cleanup_queue(uninit_q); - + goto out_free_flush_rq; return q; + +out_free_flush_rq: + kfree(uninit_q->flush_rq); +out_cleanup_queue: + blk_cleanup_queue(uninit_q); + return NULL; } EXPORT_SYMBOL(blk_init_queue_node); @@ -1112,7 +1136,7 @@ static struct request *blk_old_get_request(struct request_queue *q, int rw, struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask) { if (q->mq_ops) - return blk_mq_alloc_request(q, rw, gfp_mask, false); + return blk_mq_alloc_request(q, rw, gfp_mask); else return blk_old_get_request(q, rw, gfp_mask); } @@ -1263,6 +1287,11 @@ void __blk_put_request(struct request_queue *q, struct request *req) if (unlikely(!q)) return; + if (q->mq_ops) { + blk_mq_free_request(req); + return; + } + blk_pm_put_request(req); elv_completed_request(q, req); @@ -1326,7 +1355,7 @@ void blk_add_request_payload(struct request *rq, struct page *page, bio->bi_io_vec->bv_offset = 0; bio->bi_io_vec->bv_len = len; - bio->bi_size = len; + bio->bi_iter.bi_size = len; bio->bi_vcnt = 1; bio->bi_phys_segments = 1; @@ -1351,7 +1380,7 @@ bool bio_attempt_back_merge(struct request_queue *q, struct request *req, req->biotail->bi_next = bio; req->biotail = bio; - req->__data_len += bio->bi_size; + req->__data_len += bio->bi_iter.bi_size; req->ioprio = ioprio_best(req->ioprio, bio_prio(bio)); blk_account_io_start(req, false); @@ -1380,8 +1409,8 @@ bool bio_attempt_front_merge(struct request_queue *q, struct request *req, * not touch req->buffer either... */ req->buffer = bio_data(bio); - req->__sector = bio->bi_sector; - req->__data_len += bio->bi_size; + req->__sector = bio->bi_iter.bi_sector; + req->__data_len += bio->bi_iter.bi_size; req->ioprio = ioprio_best(req->ioprio, bio_prio(bio)); blk_account_io_start(req, false); @@ -1459,7 +1488,7 @@ void init_request_from_bio(struct request *req, struct bio *bio) req->cmd_flags |= REQ_FAILFAST_MASK; req->errors = 0; - req->__sector = bio->bi_sector; + req->__sector = bio->bi_iter.bi_sector; req->ioprio = bio_prio(bio); blk_rq_bio_prep(req->q, req, bio); } @@ -1583,12 +1612,12 @@ static inline void blk_partition_remap(struct bio *bio) if (bio_sectors(bio) && bdev != bdev->bd_contains) { struct hd_struct *p = bdev->bd_part; - bio->bi_sector += p->start_sect; + bio->bi_iter.bi_sector += p->start_sect; bio->bi_bdev = bdev->bd_contains; trace_block_bio_remap(bdev_get_queue(bio->bi_bdev), bio, bdev->bd_dev, - bio->bi_sector - p->start_sect); + bio->bi_iter.bi_sector - p->start_sect); } } @@ -1654,7 +1683,7 @@ static inline int bio_check_eod(struct bio *bio, unsigned int nr_sectors) /* Test device or partition size, when known. */ maxsector = i_size_read(bio->bi_bdev->bd_inode) >> 9; if (maxsector) { - sector_t sector = bio->bi_sector; + sector_t sector = bio->bi_iter.bi_sector; if (maxsector < nr_sectors || maxsector - nr_sectors < sector) { /* @@ -1690,7 +1719,7 @@ generic_make_request_checks(struct bio *bio) "generic_make_request: Trying to access " "nonexistent block-device %s (%Lu)\n", bdevname(bio->bi_bdev, b), - (long long) bio->bi_sector); + (long long) bio->bi_iter.bi_sector); goto end_io; } @@ -1704,9 +1733,9 @@ generic_make_request_checks(struct bio *bio) } part = bio->bi_bdev->bd_part; - if (should_fail_request(part, bio->bi_size) || + if (should_fail_request(part, bio->bi_iter.bi_size) || should_fail_request(&part_to_disk(part)->part0, - bio->bi_size)) + bio->bi_iter.bi_size)) goto end_io; /* @@ -1865,7 +1894,7 @@ void submit_bio(int rw, struct bio *bio) if (rw & WRITE) { count_vm_events(PGPGOUT, count); } else { - task_io_account_read(bio->bi_size); + task_io_account_read(bio->bi_iter.bi_size); count_vm_events(PGPGIN, count); } @@ -1874,7 +1903,7 @@ void submit_bio(int rw, struct bio *bio) printk(KERN_DEBUG "%s(%d): %s block %Lu on %s (%u sectors)\n", current->comm, task_pid_nr(current), (rw & WRITE) ? "WRITE" : "READ", - (unsigned long long)bio->bi_sector, + (unsigned long long)bio->bi_iter.bi_sector, bdevname(bio->bi_bdev, b), count); } @@ -2007,7 +2036,7 @@ unsigned int blk_rq_err_bytes(const struct request *rq) for (bio = rq->bio; bio; bio = bio->bi_next) { if ((bio->bi_rw & ff) != ff) break; - bytes += bio->bi_size; + bytes += bio->bi_iter.bi_size; } /* this could lead to infinite loop */ @@ -2378,9 +2407,9 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes) total_bytes = 0; while (req->bio) { struct bio *bio = req->bio; - unsigned bio_bytes = min(bio->bi_size, nr_bytes); + unsigned bio_bytes = min(bio->bi_iter.bi_size, nr_bytes); - if (bio_bytes == bio->bi_size) + if (bio_bytes == bio->bi_iter.bi_size) req->bio = bio->bi_next; req_bio_endio(req, bio, bio_bytes, error); @@ -2728,7 +2757,7 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq, rq->nr_phys_segments = bio_phys_segments(q, bio); rq->buffer = bio_data(bio); } - rq->__data_len = bio->bi_size; + rq->__data_len = bio->bi_iter.bi_size; rq->bio = rq->biotail = bio; if (bio->bi_bdev) @@ -2746,10 +2775,10 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq, void rq_flush_dcache_pages(struct request *rq) { struct req_iterator iter; - struct bio_vec *bvec; + struct bio_vec bvec; rq_for_each_segment(bvec, rq, iter) - flush_dcache_page(bvec->bv_page); + flush_dcache_page(bvec.bv_page); } EXPORT_SYMBOL_GPL(rq_flush_dcache_pages); #endif diff --git a/block/blk-exec.c b/block/blk-exec.c index c3edf9dff566f4..c68613bb4c79b7 100644 --- a/block/blk-exec.c +++ b/block/blk-exec.c @@ -60,8 +60,12 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, rq->rq_disk = bd_disk; rq->end_io = done; + /* + * don't check dying flag for MQ because the request won't + * be resued after dying flag is set + */ if (q->mq_ops) { - blk_mq_insert_request(q, rq, true); + blk_mq_insert_request(q, rq, at_head, true); return; } diff --git a/block/blk-flush.c b/block/blk-flush.c index fb6f3c0ffa494f..66e2b697f5db12 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -130,20 +130,26 @@ static void blk_flush_restore_request(struct request *rq) blk_clear_rq_complete(rq); } -static void mq_flush_data_run(struct work_struct *work) +static void mq_flush_run(struct work_struct *work) { struct request *rq; - rq = container_of(work, struct request, mq_flush_data); + rq = container_of(work, struct request, mq_flush_work); memset(&rq->csd, 0, sizeof(rq->csd)); blk_mq_run_request(rq, true, false); } -static void blk_mq_flush_data_insert(struct request *rq) +static bool blk_flush_queue_rq(struct request *rq) { - INIT_WORK(&rq->mq_flush_data, mq_flush_data_run); - kblockd_schedule_work(rq->q, &rq->mq_flush_data); + if (rq->q->mq_ops) { + INIT_WORK(&rq->mq_flush_work, mq_flush_run); + kblockd_schedule_work(rq->q, &rq->mq_flush_work); + return false; + } else { + list_add_tail(&rq->queuelist, &rq->q->queue_head); + return true; + } } /** @@ -187,12 +193,7 @@ static bool blk_flush_complete_seq(struct request *rq, unsigned int seq, case REQ_FSEQ_DATA: list_move_tail(&rq->flush.list, &q->flush_data_in_flight); - if (q->mq_ops) - blk_mq_flush_data_insert(rq); - else { - list_add(&rq->queuelist, &q->queue_head); - queued = true; - } + queued = blk_flush_queue_rq(rq); break; case REQ_FSEQ_DONE: @@ -216,9 +217,6 @@ static bool blk_flush_complete_seq(struct request *rq, unsigned int seq, } kicked = blk_kick_flush(q); - /* blk_mq_run_flush will run queue */ - if (q->mq_ops) - return queued; return kicked | queued; } @@ -230,10 +228,9 @@ static void flush_end_io(struct request *flush_rq, int error) struct request *rq, *n; unsigned long flags = 0; - if (q->mq_ops) { - blk_mq_free_request(flush_rq); + if (q->mq_ops) spin_lock_irqsave(&q->mq_flush_lock, flags); - } + running = &q->flush_queue[q->flush_running_idx]; BUG_ON(q->flush_pending_idx == q->flush_running_idx); @@ -263,49 +260,14 @@ static void flush_end_io(struct request *flush_rq, int error) * kblockd. */ if (queued || q->flush_queue_delayed) { - if (!q->mq_ops) - blk_run_queue_async(q); - else - /* - * This can be optimized to only run queues with requests - * queued if necessary. - */ - blk_mq_run_queues(q, true); + WARN_ON(q->mq_ops); + blk_run_queue_async(q); } q->flush_queue_delayed = 0; if (q->mq_ops) spin_unlock_irqrestore(&q->mq_flush_lock, flags); } -static void mq_flush_work(struct work_struct *work) -{ - struct request_queue *q; - struct request *rq; - - q = container_of(work, struct request_queue, mq_flush_work); - - /* We don't need set REQ_FLUSH_SEQ, it's for consistency */ - rq = blk_mq_alloc_request(q, WRITE_FLUSH|REQ_FLUSH_SEQ, - __GFP_WAIT|GFP_ATOMIC, true); - rq->cmd_type = REQ_TYPE_FS; - rq->end_io = flush_end_io; - - blk_mq_run_request(rq, true, false); -} - -/* - * We can't directly use q->flush_rq, because it doesn't have tag and is not in - * hctx->rqs[]. so we must allocate a new request, since we can't sleep here, - * so offload the work to workqueue. - * - * Note: we assume a flush request finished in any hardware queue will flush - * the whole disk cache. - */ -static void mq_run_flush(struct request_queue *q) -{ - kblockd_schedule_work(q, &q->mq_flush_work); -} - /** * blk_kick_flush - consider issuing flush request * @q: request_queue being kicked @@ -340,19 +302,31 @@ static bool blk_kick_flush(struct request_queue *q) * different from running_idx, which means flush is in flight. */ q->flush_pending_idx ^= 1; + if (q->mq_ops) { - mq_run_flush(q); - return true; + struct blk_mq_ctx *ctx = first_rq->mq_ctx; + struct blk_mq_hw_ctx *hctx = q->mq_ops->map_queue(q, ctx->cpu); + + blk_mq_rq_init(hctx, q->flush_rq); + q->flush_rq->mq_ctx = ctx; + + /* + * Reuse the tag value from the fist waiting request, + * with blk-mq the tag is generated during request + * allocation and drivers can rely on it being inside + * the range they asked for. + */ + q->flush_rq->tag = first_rq->tag; + } else { + blk_rq_init(q, q->flush_rq); } - blk_rq_init(q, &q->flush_rq); - q->flush_rq.cmd_type = REQ_TYPE_FS; - q->flush_rq.cmd_flags = WRITE_FLUSH | REQ_FLUSH_SEQ; - q->flush_rq.rq_disk = first_rq->rq_disk; - q->flush_rq.end_io = flush_end_io; + q->flush_rq->cmd_type = REQ_TYPE_FS; + q->flush_rq->cmd_flags = WRITE_FLUSH | REQ_FLUSH_SEQ; + q->flush_rq->rq_disk = first_rq->rq_disk; + q->flush_rq->end_io = flush_end_io; - list_add_tail(&q->flush_rq.queuelist, &q->queue_head); - return true; + return blk_flush_queue_rq(q->flush_rq); } static void flush_data_end_io(struct request *rq, int error) @@ -548,7 +522,7 @@ int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask, * copied from blk_rq_pos(rq). */ if (error_sector) - *error_sector = bio->bi_sector; + *error_sector = bio->bi_iter.bi_sector; bio_put(bio); return ret; @@ -558,5 +532,4 @@ EXPORT_SYMBOL(blkdev_issue_flush); void blk_mq_init_flush(struct request_queue *q) { spin_lock_init(&q->mq_flush_lock); - INIT_WORK(&q->mq_flush_work, mq_flush_work); } diff --git a/block/blk-integrity.c b/block/blk-integrity.c index 03cf7179e8ef1a..7fbab84399e6c9 100644 --- a/block/blk-integrity.c +++ b/block/blk-integrity.c @@ -43,30 +43,32 @@ static const char *bi_unsupported_name = "unsupported"; */ int blk_rq_count_integrity_sg(struct request_queue *q, struct bio *bio) { - struct bio_vec *iv, *ivprv = NULL; + struct bio_vec iv, ivprv = { NULL }; unsigned int segments = 0; unsigned int seg_size = 0; - unsigned int i = 0; + struct bvec_iter iter; + int prev = 0; - bio_for_each_integrity_vec(iv, bio, i) { + bio_for_each_integrity_vec(iv, bio, iter) { - if (ivprv) { - if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv)) + if (prev) { + if (!BIOVEC_PHYS_MERGEABLE(&ivprv, &iv)) goto new_segment; - if (!BIOVEC_SEG_BOUNDARY(q, ivprv, iv)) + if (!BIOVEC_SEG_BOUNDARY(q, &ivprv, &iv)) goto new_segment; - if (seg_size + iv->bv_len > queue_max_segment_size(q)) + if (seg_size + iv.bv_len > queue_max_segment_size(q)) goto new_segment; - seg_size += iv->bv_len; + seg_size += iv.bv_len; } else { new_segment: segments++; - seg_size = iv->bv_len; + seg_size = iv.bv_len; } + prev = 1; ivprv = iv; } @@ -87,24 +89,25 @@ EXPORT_SYMBOL(blk_rq_count_integrity_sg); int blk_rq_map_integrity_sg(struct request_queue *q, struct bio *bio, struct scatterlist *sglist) { - struct bio_vec *iv, *ivprv = NULL; + struct bio_vec iv, ivprv = { NULL }; struct scatterlist *sg = NULL; unsigned int segments = 0; - unsigned int i = 0; + struct bvec_iter iter; + int prev = 0; - bio_for_each_integrity_vec(iv, bio, i) { + bio_for_each_integrity_vec(iv, bio, iter) { - if (ivprv) { - if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv)) + if (prev) { + if (!BIOVEC_PHYS_MERGEABLE(&ivprv, &iv)) goto new_segment; - if (!BIOVEC_SEG_BOUNDARY(q, ivprv, iv)) + if (!BIOVEC_SEG_BOUNDARY(q, &ivprv, &iv)) goto new_segment; - if (sg->length + iv->bv_len > queue_max_segment_size(q)) + if (sg->length + iv.bv_len > queue_max_segment_size(q)) goto new_segment; - sg->length += iv->bv_len; + sg->length += iv.bv_len; } else { new_segment: if (!sg) @@ -114,10 +117,11 @@ int blk_rq_map_integrity_sg(struct request_queue *q, struct bio *bio, sg = sg_next(sg); } - sg_set_page(sg, iv->bv_page, iv->bv_len, iv->bv_offset); + sg_set_page(sg, iv.bv_page, iv.bv_len, iv.bv_offset); segments++; } + prev = 1; ivprv = iv; } diff --git a/block/blk-lib.c b/block/blk-lib.c index 9b5b561cb92812..97a733cf3d5f92 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -108,17 +108,25 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector, req_sects = end_sect - sector; } - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_end_io = bio_batch_end_io; bio->bi_bdev = bdev; bio->bi_private = &bb; - bio->bi_size = req_sects << 9; + bio->bi_iter.bi_size = req_sects << 9; nr_sects -= req_sects; sector = end_sect; atomic_inc(&bb.done); submit_bio(type, bio); + + /* + * We can loop for a long time in here, if someone does + * full device discards (like mkfs). Be nice and allow + * us to schedule out to avoid softlocking if preempt + * is disabled. + */ + cond_resched(); } blk_finish_plug(&plug); @@ -174,7 +182,7 @@ int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, break; } - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_end_io = bio_batch_end_io; bio->bi_bdev = bdev; bio->bi_private = &bb; @@ -184,11 +192,11 @@ int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, bio->bi_io_vec->bv_len = bdev_logical_block_size(bdev); if (nr_sects > max_write_same_sectors) { - bio->bi_size = max_write_same_sectors << 9; + bio->bi_iter.bi_size = max_write_same_sectors << 9; nr_sects -= max_write_same_sectors; sector += max_write_same_sectors; } else { - bio->bi_size = nr_sects << 9; + bio->bi_iter.bi_size = nr_sects << 9; nr_sects = 0; } @@ -240,7 +248,7 @@ int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, break; } - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_bdev = bdev; bio->bi_end_io = bio_batch_end_io; bio->bi_private = &bb; diff --git a/block/blk-map.c b/block/blk-map.c index 623e1cd4cffe99..ae4ae1047fd995 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -20,7 +20,7 @@ int blk_rq_append_bio(struct request_queue *q, struct request *rq, rq->biotail->bi_next = bio; rq->biotail = bio; - rq->__data_len += bio->bi_size; + rq->__data_len += bio->bi_iter.bi_size; } return 0; } @@ -76,7 +76,7 @@ static int __blk_rq_map_user(struct request_queue *q, struct request *rq, ret = blk_rq_append_bio(q, rq, bio); if (!ret) - return bio->bi_size; + return bio->bi_iter.bi_size; /* if it was boucned we must call the end io function */ bio_endio(bio, 0); @@ -220,7 +220,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, if (IS_ERR(bio)) return PTR_ERR(bio); - if (bio->bi_size != len) { + if (bio->bi_iter.bi_size != len) { /* * Grab an extra reference to this bio, as bio_unmap_user() * expects to be able to drop it twice as it happens on the diff --git a/block/blk-merge.c b/block/blk-merge.c index 1ffc58977835ff..6c583f9c5b65d0 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -12,38 +12,47 @@ static unsigned int __blk_recalc_rq_segments(struct request_queue *q, struct bio *bio) { - struct bio_vec *bv, *bvprv = NULL; - int cluster, i, high, highprv = 1; + struct bio_vec bv, bvprv = { NULL }; + int cluster, high, highprv = 1; unsigned int seg_size, nr_phys_segs; struct bio *fbio, *bbio; + struct bvec_iter iter; if (!bio) return 0; + /* + * This should probably be returning 0, but blk_add_request_payload() + * (Christoph!!!!) + */ + if (bio->bi_rw & REQ_DISCARD) + return 1; + + if (bio->bi_rw & REQ_WRITE_SAME) + return 1; + fbio = bio; cluster = blk_queue_cluster(q); seg_size = 0; nr_phys_segs = 0; for_each_bio(bio) { - bio_for_each_segment(bv, bio, i) { + bio_for_each_segment(bv, bio, iter) { /* * the trick here is making sure that a high page is * never considered part of another segment, since that * might change with the bounce page. */ - high = page_to_pfn(bv->bv_page) > queue_bounce_pfn(q); - if (high || highprv) - goto new_segment; - if (cluster) { - if (seg_size + bv->bv_len + high = page_to_pfn(bv.bv_page) > queue_bounce_pfn(q); + if (!high && !highprv && cluster) { + if (seg_size + bv.bv_len > queue_max_segment_size(q)) goto new_segment; - if (!BIOVEC_PHYS_MERGEABLE(bvprv, bv)) + if (!BIOVEC_PHYS_MERGEABLE(&bvprv, &bv)) goto new_segment; - if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bv)) + if (!BIOVEC_SEG_BOUNDARY(q, &bvprv, &bv)) goto new_segment; - seg_size += bv->bv_len; + seg_size += bv.bv_len; bvprv = bv; continue; } @@ -54,7 +63,7 @@ static unsigned int __blk_recalc_rq_segments(struct request_queue *q, nr_phys_segs++; bvprv = bv; - seg_size = bv->bv_len; + seg_size = bv.bv_len; highprv = high; } bbio = bio; @@ -87,6 +96,9 @@ EXPORT_SYMBOL(blk_recount_segments); static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio, struct bio *nxt) { + struct bio_vec end_bv = { NULL }, nxt_bv; + struct bvec_iter iter; + if (!blk_queue_cluster(q)) return 0; @@ -97,34 +109,40 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio, if (!bio_has_data(bio)) return 1; - if (!BIOVEC_PHYS_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt))) + bio_for_each_segment(end_bv, bio, iter) + if (end_bv.bv_len == iter.bi_size) + break; + + nxt_bv = bio_iovec(nxt); + + if (!BIOVEC_PHYS_MERGEABLE(&end_bv, &nxt_bv)) return 0; /* * bio and nxt are contiguous in memory; check if the queue allows * these two to be merged into one */ - if (BIO_SEG_BOUNDARY(q, bio, nxt)) + if (BIOVEC_SEG_BOUNDARY(q, &end_bv, &nxt_bv)) return 1; return 0; } -static void +static inline void __blk_segment_map_sg(struct request_queue *q, struct bio_vec *bvec, - struct scatterlist *sglist, struct bio_vec **bvprv, + struct scatterlist *sglist, struct bio_vec *bvprv, struct scatterlist **sg, int *nsegs, int *cluster) { int nbytes = bvec->bv_len; - if (*bvprv && *cluster) { + if (*sg && *cluster) { if ((*sg)->length + nbytes > queue_max_segment_size(q)) goto new_segment; - if (!BIOVEC_PHYS_MERGEABLE(*bvprv, bvec)) + if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) goto new_segment; - if (!BIOVEC_SEG_BOUNDARY(q, *bvprv, bvec)) + if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bvec)) goto new_segment; (*sg)->length += nbytes; @@ -150,7 +168,49 @@ __blk_segment_map_sg(struct request_queue *q, struct bio_vec *bvec, sg_set_page(*sg, bvec->bv_page, nbytes, bvec->bv_offset); (*nsegs)++; } - *bvprv = bvec; + *bvprv = *bvec; +} + +static int __blk_bios_map_sg(struct request_queue *q, struct bio *bio, + struct scatterlist *sglist, + struct scatterlist **sg) +{ + struct bio_vec bvec, bvprv = { NULL }; + struct bvec_iter iter; + int nsegs, cluster; + + nsegs = 0; + cluster = blk_queue_cluster(q); + + if (bio->bi_rw & REQ_DISCARD) { + /* + * This is a hack - drivers should be neither modifying the + * biovec, nor relying on bi_vcnt - but because of + * blk_add_request_payload(), a discard bio may or may not have + * a payload we need to set up here (thank you Christoph) and + * bi_vcnt is really the only way of telling if we need to. + */ + + if (bio->bi_vcnt) + goto single_segment; + + return 0; + } + + if (bio->bi_rw & REQ_WRITE_SAME) { +single_segment: + *sg = sglist; + bvec = bio_iovec(bio); + sg_set_page(*sg, bvec.bv_page, bvec.bv_len, bvec.bv_offset); + return 1; + } + + for_each_bio(bio) + bio_for_each_segment(bvec, bio, iter) + __blk_segment_map_sg(q, &bvec, sglist, &bvprv, sg, + &nsegs, &cluster); + + return nsegs; } /* @@ -160,24 +220,11 @@ __blk_segment_map_sg(struct request_queue *q, struct bio_vec *bvec, int blk_rq_map_sg(struct request_queue *q, struct request *rq, struct scatterlist *sglist) { - struct bio_vec *bvec, *bvprv; - struct req_iterator iter; - struct scatterlist *sg; - int nsegs, cluster; - - nsegs = 0; - cluster = blk_queue_cluster(q); - - /* - * for each bio in rq - */ - bvprv = NULL; - sg = NULL; - rq_for_each_segment(bvec, rq, iter) { - __blk_segment_map_sg(q, bvec, sglist, &bvprv, &sg, - &nsegs, &cluster); - } /* segments in rq */ + struct scatterlist *sg = NULL; + int nsegs = 0; + if (rq->bio) + nsegs = __blk_bios_map_sg(q, rq->bio, sglist, &sg); if (unlikely(rq->cmd_flags & REQ_COPY_USER) && (blk_rq_bytes(rq) & q->dma_pad_mask)) { @@ -223,21 +270,13 @@ EXPORT_SYMBOL(blk_rq_map_sg); int blk_bio_map_sg(struct request_queue *q, struct bio *bio, struct scatterlist *sglist) { - struct bio_vec *bvec, *bvprv; - struct scatterlist *sg; - int nsegs, cluster; - unsigned long i; - - nsegs = 0; - cluster = blk_queue_cluster(q); - - bvprv = NULL; - sg = NULL; - bio_for_each_segment(bvec, bio, i) { - __blk_segment_map_sg(q, bvec, sglist, &bvprv, &sg, - &nsegs, &cluster); - } /* segments in bio */ + struct scatterlist *sg = NULL; + int nsegs; + struct bio *next = bio->bi_next; + bio->bi_next = NULL; + nsegs = __blk_bios_map_sg(q, bio, sglist, &sg); + bio->bi_next = next; if (sg) sg_mark_end(sg); @@ -543,9 +582,9 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio) int blk_try_merge(struct request *rq, struct bio *bio) { - if (blk_rq_pos(rq) + blk_rq_sectors(rq) == bio->bi_sector) + if (blk_rq_pos(rq) + blk_rq_sectors(rq) == bio->bi_iter.bi_sector) return ELEVATOR_BACK_MERGE; - else if (blk_rq_pos(rq) - bio_sectors(bio) == bio->bi_sector) + else if (blk_rq_pos(rq) - bio_sectors(bio) == bio->bi_iter.bi_sector) return ELEVATOR_FRONT_MERGE; return ELEVATOR_NO_MERGE; } diff --git a/block/blk-mq-cpu.c b/block/blk-mq-cpu.c index 0045ace9bdf030..3146befb56aaac 100644 --- a/block/blk-mq-cpu.c +++ b/block/blk-mq-cpu.c @@ -28,36 +28,6 @@ static int blk_mq_main_cpu_notify(struct notifier_block *self, return NOTIFY_OK; } -static void blk_mq_cpu_notify(void *data, unsigned long action, - unsigned int cpu) -{ - if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) { - /* - * If the CPU goes away, ensure that we run any pending - * completions. - */ - struct llist_node *node; - struct request *rq; - - local_irq_disable(); - - node = llist_del_all(&per_cpu(ipi_lists, cpu)); - while (node) { - struct llist_node *next = node->next; - - rq = llist_entry(node, struct request, ll_list); - __blk_mq_end_io(rq, rq->errors); - node = next; - } - - local_irq_enable(); - } -} - -static struct notifier_block __cpuinitdata blk_mq_main_cpu_notifier = { - .notifier_call = blk_mq_main_cpu_notify, -}; - void blk_mq_register_cpu_notifier(struct blk_mq_cpu_notifier *notifier) { BUG_ON(!notifier->notify); @@ -82,12 +52,7 @@ void blk_mq_init_cpu_notifier(struct blk_mq_cpu_notifier *notifier, notifier->data = data; } -static struct blk_mq_cpu_notifier __cpuinitdata cpu_notifier = { - .notify = blk_mq_cpu_notify, -}; - void __init blk_mq_cpu_init(void) { - register_hotcpu_notifier(&blk_mq_main_cpu_notifier); - blk_mq_register_cpu_notifier(&cpu_notifier); + hotcpu_notifier(blk_mq_main_cpu_notify, 0); } diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c index d64a02fb1f7307..83ae96c51a2762 100644 --- a/block/blk-mq-tag.c +++ b/block/blk-mq-tag.c @@ -36,7 +36,8 @@ static unsigned int __blk_mq_get_tag(struct blk_mq_tags *tags, gfp_t gfp) { int tag; - tag = percpu_ida_alloc(&tags->free_tags, gfp); + tag = percpu_ida_alloc(&tags->free_tags, (gfp & __GFP_WAIT) ? + TASK_UNINTERRUPTIBLE : TASK_RUNNING); if (tag < 0) return BLK_MQ_TAG_FAIL; return tag + tags->nr_reserved_tags; @@ -52,7 +53,8 @@ static unsigned int __blk_mq_get_reserved_tag(struct blk_mq_tags *tags, return BLK_MQ_TAG_FAIL; } - tag = percpu_ida_alloc(&tags->reserved_tags, gfp); + tag = percpu_ida_alloc(&tags->reserved_tags, (gfp & __GFP_WAIT) ? + TASK_UNINTERRUPTIBLE : TASK_RUNNING); if (tag < 0) return BLK_MQ_TAG_FAIL; return tag; @@ -182,7 +184,7 @@ void blk_mq_free_tags(struct blk_mq_tags *tags) ssize_t blk_mq_tag_sysfs_show(struct blk_mq_tags *tags, char *page) { char *orig_page = page; - int cpu; + unsigned int cpu; if (!tags) return 0; diff --git a/block/blk-mq.c b/block/blk-mq.c index c79126e110308e..1fa9dd153fde22 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -27,8 +27,6 @@ static LIST_HEAD(all_q_list); static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx); -DEFINE_PER_CPU(struct llist_head, ipi_lists); - static struct blk_mq_ctx *__blk_mq_get_ctx(struct request_queue *q, unsigned int cpu) { @@ -106,10 +104,13 @@ static int blk_mq_queue_enter(struct request_queue *q) spin_lock_irq(q->queue_lock); ret = wait_event_interruptible_lock_irq(q->mq_freeze_wq, - !blk_queue_bypass(q), *q->queue_lock); + !blk_queue_bypass(q) || blk_queue_dying(q), + *q->queue_lock); /* inc usage with lock hold to avoid freeze_queue runs here */ - if (!ret) + if (!ret && !blk_queue_dying(q)) __percpu_counter_add(&q->mq_usage_counter, 1, 1000000); + else if (blk_queue_dying(q)) + ret = -ENODEV; spin_unlock_irq(q->queue_lock); return ret; @@ -120,6 +121,22 @@ static void blk_mq_queue_exit(struct request_queue *q) __percpu_counter_add(&q->mq_usage_counter, -1, 1000000); } +static void __blk_mq_drain_queue(struct request_queue *q) +{ + while (true) { + s64 count; + + spin_lock_irq(q->queue_lock); + count = percpu_counter_sum(&q->mq_usage_counter); + spin_unlock_irq(q->queue_lock); + + if (count == 0) + break; + blk_mq_run_queues(q, false); + msleep(10); + } +} + /* * Guarantee no request is in use, so we can change any data structure of * the queue afterward. @@ -133,21 +150,13 @@ static void blk_mq_freeze_queue(struct request_queue *q) queue_flag_set(QUEUE_FLAG_BYPASS, q); spin_unlock_irq(q->queue_lock); - if (!drain) - return; - - while (true) { - s64 count; - - spin_lock_irq(q->queue_lock); - count = percpu_counter_sum(&q->mq_usage_counter); - spin_unlock_irq(q->queue_lock); + if (drain) + __blk_mq_drain_queue(q); +} - if (count == 0) - break; - blk_mq_run_queues(q, false); - msleep(10); - } +void blk_mq_drain_queue(struct request_queue *q) +{ + __blk_mq_drain_queue(q); } static void blk_mq_unfreeze_queue(struct request_queue *q) @@ -179,6 +188,8 @@ static void blk_mq_rq_ctx_init(struct request_queue *q, struct blk_mq_ctx *ctx, rq->mq_ctx = ctx; rq->cmd_flags = rw_flags; + rq->start_time = jiffies; + set_start_time_ns(rq); ctx->rq_dispatched[rw_is_sync(rw_flags)]++; } @@ -215,15 +226,14 @@ static struct request *blk_mq_alloc_request_pinned(struct request_queue *q, return rq; } -struct request *blk_mq_alloc_request(struct request_queue *q, int rw, - gfp_t gfp, bool reserved) +struct request *blk_mq_alloc_request(struct request_queue *q, int rw, gfp_t gfp) { struct request *rq; if (blk_mq_queue_enter(q)) return NULL; - rq = blk_mq_alloc_request_pinned(q, rw, gfp, reserved); + rq = blk_mq_alloc_request_pinned(q, rw, gfp, false); if (rq) blk_mq_put_ctx(rq->mq_ctx); return rq; @@ -247,7 +257,7 @@ EXPORT_SYMBOL(blk_mq_alloc_reserved_request); /* * Re-init and set pdu, if we have it */ -static void blk_mq_rq_init(struct blk_mq_hw_ctx *hctx, struct request *rq) +void blk_mq_rq_init(struct blk_mq_hw_ctx *hctx, struct request *rq) { blk_rq_init(hctx->queue, rq); @@ -294,7 +304,7 @@ static void blk_mq_bio_endio(struct request *rq, struct bio *bio, int error) bio_endio(bio, error); } -void blk_mq_complete_request(struct request *rq, int error) +void blk_mq_end_io(struct request *rq, int error) { struct bio *bio = rq->bio; unsigned int bytes = 0; @@ -305,7 +315,7 @@ void blk_mq_complete_request(struct request *rq, int error) struct bio *next = bio->bi_next; bio->bi_next = NULL; - bytes += bio->bi_size; + bytes += bio->bi_iter.bi_size; blk_mq_bio_endio(rq, bio, error); bio = next; } @@ -319,87 +329,55 @@ void blk_mq_complete_request(struct request *rq, int error) else blk_mq_free_request(rq); } +EXPORT_SYMBOL(blk_mq_end_io); -void __blk_mq_end_io(struct request *rq, int error) -{ - if (!blk_mark_rq_complete(rq)) - blk_mq_complete_request(rq, error); -} - -#if defined(CONFIG_SMP) - -/* - * Called with interrupts disabled. - */ -static void ipi_end_io(void *data) -{ - struct llist_head *list = &per_cpu(ipi_lists, smp_processor_id()); - struct llist_node *entry, *next; - struct request *rq; - - entry = llist_del_all(list); - - while (entry) { - next = entry->next; - rq = llist_entry(entry, struct request, ll_list); - __blk_mq_end_io(rq, rq->errors); - entry = next; - } -} - -static int ipi_remote_cpu(struct blk_mq_ctx *ctx, const int cpu, - struct request *rq, const int error) +static void __blk_mq_complete_request_remote(void *data) { - struct call_single_data *data = &rq->csd; - - rq->errors = error; - rq->ll_list.next = NULL; - - /* - * If the list is non-empty, an existing IPI must already - * be "in flight". If that is the case, we need not schedule - * a new one. - */ - if (llist_add(&rq->ll_list, &per_cpu(ipi_lists, ctx->cpu))) { - data->func = ipi_end_io; - data->flags = 0; - __smp_call_function_single(ctx->cpu, data, 0); - } + struct request *rq = data; - return true; -} -#else /* CONFIG_SMP */ -static int ipi_remote_cpu(struct blk_mq_ctx *ctx, const int cpu, - struct request *rq, const int error) -{ - return false; + rq->q->softirq_done_fn(rq); } -#endif -/* - * End IO on this request on a multiqueue enabled driver. We'll either do - * it directly inline, or punt to a local IPI handler on the matching - * remote CPU. - */ -void blk_mq_end_io(struct request *rq, int error) +void __blk_mq_complete_request(struct request *rq) { struct blk_mq_ctx *ctx = rq->mq_ctx; int cpu; - if (!ctx->ipi_redirect) - return __blk_mq_end_io(rq, error); + if (!ctx->ipi_redirect) { + rq->q->softirq_done_fn(rq); + return; + } cpu = get_cpu(); - - if (cpu == ctx->cpu || !cpu_online(ctx->cpu) || - !ipi_remote_cpu(ctx, cpu, rq, error)) - __blk_mq_end_io(rq, error); - + if (cpu != ctx->cpu && cpu_online(ctx->cpu)) { + rq->csd.func = __blk_mq_complete_request_remote; + rq->csd.info = rq; + rq->csd.flags = 0; + __smp_call_function_single(ctx->cpu, &rq->csd, 0); + } else { + rq->q->softirq_done_fn(rq); + } put_cpu(); } -EXPORT_SYMBOL(blk_mq_end_io); -static void blk_mq_start_request(struct request *rq) +/** + * blk_mq_complete_request - end I/O on a request + * @rq: the request being processed + * + * Description: + * Ends all I/O on a request. It does not handle partial completions. + * The actual completion happens out-of-order, through a IPI handler. + **/ +void blk_mq_complete_request(struct request *rq) +{ + if (unlikely(blk_should_fake_timeout(rq->q))) + return; + if (!blk_mark_rq_complete(rq)) + __blk_mq_complete_request(rq); +} +EXPORT_SYMBOL(blk_mq_complete_request); + +static void blk_mq_start_request(struct request *rq, bool last) { struct request_queue *q = rq->q; @@ -412,6 +390,25 @@ static void blk_mq_start_request(struct request *rq) */ rq->deadline = jiffies + q->rq_timeout; set_bit(REQ_ATOM_STARTED, &rq->atomic_flags); + + if (q->dma_drain_size && blk_rq_bytes(rq)) { + /* + * Make sure space for the drain appears. We know we can do + * this because max_hw_segments has been adjusted to be one + * fewer than the device can handle. + */ + rq->nr_phys_segments++; + } + + /* + * Flag the last request in the series so that drivers know when IO + * should be kicked off, if they don't do it on a per-request basis. + * + * Note: the flag isn't the only condition drivers should do kick off. + * If drive is busy, the last request might not have the bit set. + */ + if (last) + rq->cmd_flags |= REQ_END; } static void blk_mq_requeue_request(struct request *rq) @@ -420,6 +417,11 @@ static void blk_mq_requeue_request(struct request *rq) trace_block_rq_requeue(q, rq); clear_bit(REQ_ATOM_STARTED, &rq->atomic_flags); + + rq->cmd_flags &= ~REQ_END; + + if (q->dma_drain_size && blk_rq_bytes(rq)) + rq->nr_phys_segments--; } struct blk_mq_timeout_data { @@ -587,19 +589,8 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx) rq = list_first_entry(&rq_list, struct request, queuelist); list_del_init(&rq->queuelist); - blk_mq_start_request(rq); - /* - * Last request in the series. Flag it as such, this - * enables drivers to know when IO should be kicked off, - * if they don't do it on a per-request basis. - * - * Note: the flag isn't the only condition drivers - * should do kick off. If drive is busy, the last - * request might not have the bit set. - */ - if (list_empty(&rq_list)) - rq->cmd_flags |= REQ_END; + blk_mq_start_request(rq, list_empty(&rq_list)); ret = q->mq_ops->queue_rq(hctx, rq); switch (ret) { @@ -617,8 +608,8 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx) break; default: pr_err("blk-mq: bad return on queue: %d\n", ret); - rq->errors = -EIO; case BLK_MQ_RQ_QUEUE_ERROR: + rq->errors = -EIO; blk_mq_end_io(rq, rq->errors); break; } @@ -721,13 +712,16 @@ static void blk_mq_work_fn(struct work_struct *work) } static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx, - struct request *rq) + struct request *rq, bool at_head) { struct blk_mq_ctx *ctx = rq->mq_ctx; trace_block_rq_insert(hctx->queue, rq); - list_add_tail(&rq->queuelist, &ctx->rq_list); + if (at_head) + list_add(&rq->queuelist, &ctx->rq_list); + else + list_add_tail(&rq->queuelist, &ctx->rq_list); blk_mq_hctx_mark_pending(hctx, ctx); /* @@ -737,7 +731,7 @@ static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx, } void blk_mq_insert_request(struct request_queue *q, struct request *rq, - bool run_queue) + bool at_head, bool run_queue) { struct blk_mq_hw_ctx *hctx; struct blk_mq_ctx *ctx, *current_ctx; @@ -756,7 +750,7 @@ void blk_mq_insert_request(struct request_queue *q, struct request *rq, rq->mq_ctx = ctx; } spin_lock(&ctx->lock); - __blk_mq_insert_request(hctx, rq); + __blk_mq_insert_request(hctx, rq, at_head); spin_unlock(&ctx->lock); blk_mq_put_ctx(current_ctx); @@ -788,7 +782,7 @@ void blk_mq_run_request(struct request *rq, bool run_queue, bool async) /* ctx->cpu might be offline */ spin_lock(&ctx->lock); - __blk_mq_insert_request(hctx, rq); + __blk_mq_insert_request(hctx, rq, false); spin_unlock(&ctx->lock); blk_mq_put_ctx(current_ctx); @@ -826,7 +820,7 @@ static void blk_mq_insert_requests(struct request_queue *q, rq = list_first_entry(list, struct request, queuelist); list_del_init(&rq->queuelist); rq->mq_ctx = ctx; - __blk_mq_insert_request(hctx, rq); + __blk_mq_insert_request(hctx, rq, false); } spin_unlock(&ctx->lock); @@ -916,6 +910,11 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio) blk_queue_bounce(q, &bio); + if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { + bio_endio(bio, -EIO); + return; + } + if (use_plug && blk_attempt_plug_merge(q, bio, &request_count)) return; @@ -978,7 +977,7 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio) __blk_mq_free_request(hctx, ctx, rq); else { blk_mq_bio_to_request(rq, bio); - __blk_mq_insert_request(hctx, rq); + __blk_mq_insert_request(hctx, rq, false); } spin_unlock(&ctx->lock); @@ -1091,8 +1090,8 @@ static void blk_mq_free_rq_map(struct blk_mq_hw_ctx *hctx) struct page *page; while (!list_empty(&hctx->page_list)) { - page = list_first_entry(&hctx->page_list, struct page, list); - list_del_init(&page->list); + page = list_first_entry(&hctx->page_list, struct page, lru); + list_del_init(&page->lru); __free_pages(page, page->private); } @@ -1156,7 +1155,7 @@ static int blk_mq_init_rq_map(struct blk_mq_hw_ctx *hctx, break; page->private = this_order; - list_add_tail(&page->list, &hctx->page_list); + list_add_tail(&page->lru, &hctx->page_list); p = page_address(page); entries_per_page = order_to_size(this_order) / rq_size; @@ -1337,15 +1336,6 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_reg *reg, reg->queue_depth = BLK_MQ_MAX_DEPTH; } - /* - * Set aside a tag for flush requests. It will only be used while - * another flush request is in progress but outside the driver. - * - * TODO: only allocate if flushes are supported - */ - reg->queue_depth++; - reg->reserved_tags++; - if (reg->queue_depth < (reg->reserved_tags + BLK_MQ_TAG_MIN)) return ERR_PTR(-EINVAL); @@ -1388,17 +1378,27 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_reg *reg, q->mq_ops = reg->ops; q->queue_flags |= QUEUE_FLAG_MQ_DEFAULT; + q->sg_reserved_size = INT_MAX; + blk_queue_make_request(q, blk_mq_make_request); blk_queue_rq_timed_out(q, reg->ops->timeout); if (reg->timeout) blk_queue_rq_timeout(q, reg->timeout); + if (reg->ops->complete) + blk_queue_softirq_done(q, reg->ops->complete); + blk_mq_init_flush(q); blk_mq_init_cpu_queues(q, reg->nr_hw_queues); - if (blk_mq_init_hw_queues(q, reg, driver_data)) + q->flush_rq = kzalloc(round_up(sizeof(struct request) + reg->cmd_size, + cache_line_size()), GFP_KERNEL); + if (!q->flush_rq) goto err_hw; + if (blk_mq_init_hw_queues(q, reg, driver_data)) + goto err_flush_rq; + blk_mq_map_swqueue(q); mutex_lock(&all_q_mutex); @@ -1406,6 +1406,9 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_reg *reg, mutex_unlock(&all_q_mutex); return q; + +err_flush_rq: + kfree(q->flush_rq); err_hw: kfree(q->mq_map); err_map: @@ -1429,7 +1432,6 @@ void blk_mq_free_queue(struct request_queue *q) int i; queue_for_each_hw_ctx(q, hctx, i) { - cancel_delayed_work_sync(&hctx->delayed_work); kfree(hctx->ctx_map); kfree(hctx->ctxs); blk_mq_free_rq_map(hctx); @@ -1451,7 +1453,6 @@ void blk_mq_free_queue(struct request_queue *q) list_del_init(&q->all_q_node); mutex_unlock(&all_q_mutex); } -EXPORT_SYMBOL(blk_mq_free_queue); /* Basically redo blk_mq_init_queue with queue frozen */ static void blk_mq_queue_reinit(struct request_queue *q) @@ -1495,11 +1496,6 @@ static int blk_mq_queue_reinit_notify(struct notifier_block *nb, static int __init blk_mq_init(void) { - unsigned int i; - - for_each_possible_cpu(i) - init_llist_head(&per_cpu(ipi_lists, i)); - blk_mq_cpu_init(); /* Must be called after percpu_counter_hotcpu_callback() */ diff --git a/block/blk-mq.h b/block/blk-mq.h index 52bf1f96a2c239..ed0035cd458ee8 100644 --- a/block/blk-mq.h +++ b/block/blk-mq.h @@ -22,11 +22,13 @@ struct blk_mq_ctx { struct kobject kobj; }; -void __blk_mq_end_io(struct request *rq, int error); -void blk_mq_complete_request(struct request *rq, int error); +void __blk_mq_complete_request(struct request *rq); void blk_mq_run_request(struct request *rq, bool run_queue, bool async); void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async); void blk_mq_init_flush(struct request_queue *q); +void blk_mq_drain_queue(struct request_queue *q); +void blk_mq_free_queue(struct request_queue *q); +void blk_mq_rq_init(struct blk_mq_hw_ctx *hctx, struct request *rq); /* * CPU hotplug helpers @@ -38,7 +40,6 @@ void blk_mq_init_cpu_notifier(struct blk_mq_cpu_notifier *notifier, void blk_mq_register_cpu_notifier(struct blk_mq_cpu_notifier *notifier); void blk_mq_unregister_cpu_notifier(struct blk_mq_cpu_notifier *notifier); void blk_mq_cpu_init(void); -DECLARE_PER_CPU(struct llist_head, ipi_lists); /* * CPU -> queue mappings diff --git a/block/blk-settings.c b/block/blk-settings.c index 05e826793e4e36..5d21239bc8599f 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -592,6 +592,10 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, ret = -1; } + t->raid_partial_stripes_expensive = + max(t->raid_partial_stripes_expensive, + b->raid_partial_stripes_expensive); + /* Find lowest common alignment_offset */ t->alignment_offset = lcm(t->alignment_offset, alignment) & (max(t->physical_block_size, t->io_min) - 1); diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 97779522472f83..7500f876dae40e 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -11,6 +11,7 @@ #include "blk.h" #include "blk-cgroup.h" +#include "blk-mq.h" struct queue_sysfs_entry { struct attribute attr; @@ -548,6 +549,8 @@ static void blk_release_queue(struct kobject *kobj) if (q->mq_ops) blk_mq_free_queue(q); + kfree(q->flush_rq); + blk_trace_shutdown(q); bdi_destroy(&q->backing_dev_info); diff --git a/block/blk-throttle.c b/block/blk-throttle.c index a760857e6b6260..1474c3ab7e72cb 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -877,14 +877,14 @@ static bool tg_with_in_bps_limit(struct throtl_grp *tg, struct bio *bio, do_div(tmp, HZ); bytes_allowed = tmp; - if (tg->bytes_disp[rw] + bio->bi_size <= bytes_allowed) { + if (tg->bytes_disp[rw] + bio->bi_iter.bi_size <= bytes_allowed) { if (wait) *wait = 0; return 1; } /* Calc approx time to dispatch */ - extra_bytes = tg->bytes_disp[rw] + bio->bi_size - bytes_allowed; + extra_bytes = tg->bytes_disp[rw] + bio->bi_iter.bi_size - bytes_allowed; jiffy_wait = div64_u64(extra_bytes * HZ, tg->bps[rw]); if (!jiffy_wait) @@ -987,7 +987,7 @@ static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio) bool rw = bio_data_dir(bio); /* Charge the bio to the group */ - tg->bytes_disp[rw] += bio->bi_size; + tg->bytes_disp[rw] += bio->bi_iter.bi_size; tg->io_disp[rw]++; /* @@ -1003,8 +1003,8 @@ static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio) */ if (!(bio->bi_rw & REQ_THROTTLED)) { bio->bi_rw |= REQ_THROTTLED; - throtl_update_dispatch_stats(tg_to_blkg(tg), bio->bi_size, - bio->bi_rw); + throtl_update_dispatch_stats(tg_to_blkg(tg), + bio->bi_iter.bi_size, bio->bi_rw); } } @@ -1503,7 +1503,7 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio) if (tg) { if (!tg->has_rules[rw]) { throtl_update_dispatch_stats(tg_to_blkg(tg), - bio->bi_size, bio->bi_rw); + bio->bi_iter.bi_size, bio->bi_rw); goto out_unlock_rcu; } } @@ -1559,7 +1559,7 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio) /* out-of-limit, queue to @tg */ throtl_log(sq, "[%c] bio. bdisp=%llu sz=%u bps=%llu iodisp=%u iops=%u queued=%d/%d", rw == READ ? 'R' : 'W', - tg->bytes_disp[rw], bio->bi_size, tg->bps[rw], + tg->bytes_disp[rw], bio->bi_iter.bi_size, tg->bps[rw], tg->io_disp[rw], tg->iops[rw], sq->nr_queued[READ], sq->nr_queued[WRITE]); diff --git a/block/blk-timeout.c b/block/blk-timeout.c index bba81c9348e1cc..d96f7061c6fd87 100644 --- a/block/blk-timeout.c +++ b/block/blk-timeout.c @@ -91,7 +91,7 @@ static void blk_rq_timed_out(struct request *req) case BLK_EH_HANDLED: /* Can we use req->errors here? */ if (q->mq_ops) - blk_mq_complete_request(req, req->errors); + __blk_mq_complete_request(req); else __blk_complete_request(req); break; diff --git a/block/blk.h b/block/blk.h index c90e1d8f7a2b39..d23b415b8a28f9 100644 --- a/block/blk.h +++ b/block/blk.h @@ -113,7 +113,7 @@ static inline struct request *__elv_next_request(struct request_queue *q) q->flush_queue_delayed = 1; return NULL; } - if (unlikely(blk_queue_dying(q)) || + if (unlikely(blk_queue_bypass(q)) || !q->elevator->type->ops.elevator_dispatch_fn(q, 0)) return NULL; } diff --git a/block/cmdline-parser.c b/block/cmdline-parser.c index cc2637f8674ed6..9dbc67e42a9931 100644 --- a/block/cmdline-parser.c +++ b/block/cmdline-parser.c @@ -4,8 +4,7 @@ * Written by Cai Zhiyong * */ -#include -#include +#include #include static int parse_subpart(struct cmdline_subpart **subpart, char *partdef) @@ -159,6 +158,7 @@ void cmdline_parts_free(struct cmdline_parts **parts) *parts = next_parts; } } +EXPORT_SYMBOL(cmdline_parts_free); int cmdline_parts_parse(struct cmdline_parts **parts, const char *cmdline) { @@ -206,6 +206,7 @@ int cmdline_parts_parse(struct cmdline_parts **parts, const char *cmdline) cmdline_parts_free(parts); goto done; } +EXPORT_SYMBOL(cmdline_parts_parse); struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts, const char *bdev) @@ -214,17 +215,17 @@ struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts, parts = parts->next_parts; return parts; } +EXPORT_SYMBOL(cmdline_parts_find); /* * add_part() * 0 success. * 1 can not add so many partitions. */ -void cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size, - int slot, - int (*add_part)(int, struct cmdline_subpart *, void *), - void *param) - +int cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size, + int slot, + int (*add_part)(int, struct cmdline_subpart *, void *), + void *param) { sector_t from = 0; struct cmdline_subpart *subpart; @@ -247,4 +248,7 @@ void cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size, if (add_part(slot, subpart, param)) break; } + + return slot; } +EXPORT_SYMBOL(cmdline_parts_set); diff --git a/block/elevator.c b/block/elevator.c index b7ff2861b6bdc0..42c45a7d67144a 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -440,7 +440,7 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio) /* * See if our hash lookup can find a potential backmerge. */ - __rq = elv_rqhash_find(q, bio->bi_sector); + __rq = elv_rqhash_find(q, bio->bi_iter.bi_sector); if (__rq && elv_rq_merge_ok(__rq, bio)) { *req = __rq; return ELEVATOR_BACK_MERGE; diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 625e3e471d65f5..26487972ac549b 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -323,12 +323,14 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk, if (hdr->iovec_count) { size_t iov_data_len; - struct iovec *iov; + struct iovec *iov = NULL; ret = rw_copy_check_uvector(-1, hdr->dxferp, hdr->iovec_count, 0, NULL, &iov); - if (ret < 0) + if (ret < 0) { + kfree(iov); goto out; + } iov_data_len = ret; ret = 0; diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index e7515aa43d6bd6..6f190bc2b8b784 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -243,6 +243,8 @@ static int acpi_ac_resume(struct device *dev) kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE); return 0; } +#else +#define acpi_ac_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_ac_pm_ops, NULL, acpi_ac_resume); diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index c9311be29a6499..c29c2c3ec0ad8f 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -261,7 +261,7 @@ static int acpi_processor_get_info(struct acpi_device *device) apic_id = acpi_get_apicid(pr->handle, device_declaration, pr->acpi_id); if (apic_id < 0) { - acpi_handle_err(pr->handle, "failed to get CPU APIC ID.\n"); + acpi_handle_debug(pr->handle, "failed to get CPU APIC ID.\n"); return -ENODEV; } pr->apic_id = apic_id; diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 24db8e153bf0e8..4ed1aa384df2fd 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -108,7 +108,7 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE); /* * Optionally enable output from the AML Debug Object. */ -bool ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE); +u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE); /* * Optionally copy the entire DSDT to local memory (instead of simply diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 470e7542bf31a3..797a6938d0515e 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -549,7 +549,7 @@ static ssize_t acpi_battery_alarm_store(struct device *dev, { unsigned long x; struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); - if (sscanf(buf, "%ld\n", &x) == 1) + if (sscanf(buf, "%lu\n", &x) == 1) battery->alarm = x/1000; if (acpi_battery_present(battery)) acpi_battery_set_alarm(battery); @@ -841,6 +841,8 @@ static int acpi_battery_resume(struct device *dev) acpi_battery_update(battery); return 0; } +#else +#define acpi_battery_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume); diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 10e4964d051a9c..afec4526c48aa0 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -260,14 +260,6 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { }, { .callback = dmi_disable_osi_win8, - .ident = "Dell Inspiron 15R SE", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7520"), - }, - }, - { - .callback = dmi_disable_osi_win8, .ident = "ThinkPad Edge E530", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), @@ -322,56 +314,6 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_VERSION, "2349D15"), }, }, - { - .callback = dmi_disable_osi_win8, - .ident = "HP ProBook 2013 models", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook "), - DMI_MATCH(DMI_PRODUCT_NAME, " G1"), - }, - }, - { - .callback = dmi_disable_osi_win8, - .ident = "HP EliteBook 2013 models", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook "), - DMI_MATCH(DMI_PRODUCT_NAME, " G1"), - }, - }, - { - .callback = dmi_disable_osi_win8, - .ident = "HP ZBook 14", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 14"), - }, - }, - { - .callback = dmi_disable_osi_win8, - .ident = "HP ZBook 15", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 15"), - }, - }, - { - .callback = dmi_disable_osi_win8, - .ident = "HP ZBook 17", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 17"), - }, - }, - { - .callback = dmi_disable_osi_win8, - .ident = "HP EliteBook 8780w", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8780w"), - }, - }, /* * BIOS invocation of _OSI(Linux) is almost always a BIOS bug. diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 384da5ab595573..fcb59c21c68d5c 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef CONFIG_X86 #include #endif @@ -509,6 +510,14 @@ void __init acpi_early_init(void) goto error0; } + /* + * If the system is using ACPI then we can be reasonably + * confident that any regulators are managed by the firmware + * so tell the regulator core it has everything it needs to + * know. + */ + regulator_has_full_constraints(); + return; error0: diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 11c11f6b8fa145..714e957a871a80 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -80,6 +80,8 @@ static void acpi_button_notify(struct acpi_device *device, u32 event); #ifdef CONFIG_PM_SLEEP static int acpi_button_resume(struct device *dev); +#else +#define acpi_button_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_button_pm, NULL, acpi_button_resume); diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 0b6ae6eb5c4a8f..368f9ddb848077 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -79,9 +79,10 @@ static int container_device_attach(struct acpi_device *adev, ACPI_COMPANION_SET(dev, adev); dev->release = acpi_container_release; ret = device_register(dev); - if (ret) + if (ret) { + put_device(dev); return ret; - + } adev->driver_data = dev; return 1; } diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index d49f1e46470370..c14a00d3dca61e 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -726,18 +726,6 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable) } #endif /* CONFIG_PM_SLEEP */ -/** - * acpi_dev_pm_get_node - Get ACPI device node for the given physical device. - * @dev: Device to get the ACPI node for. - */ -struct acpi_device *acpi_dev_pm_get_node(struct device *dev) -{ - acpi_handle handle = ACPI_HANDLE(dev); - struct acpi_device *adev; - - return handle && !acpi_bus_get_device(handle, &adev) ? adev : NULL; -} - /** * acpi_dev_pm_low_power - Put ACPI device into a low-power state. * @dev: Device to put into a low-power state. @@ -778,7 +766,7 @@ static int acpi_dev_pm_full_power(struct acpi_device *adev) */ int acpi_dev_runtime_suspend(struct device *dev) { - struct acpi_device *adev = acpi_dev_pm_get_node(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); bool remote_wakeup; int error; @@ -809,7 +797,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_runtime_suspend); */ int acpi_dev_runtime_resume(struct device *dev) { - struct acpi_device *adev = acpi_dev_pm_get_node(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); int error; if (!adev) @@ -862,7 +850,7 @@ EXPORT_SYMBOL_GPL(acpi_subsys_runtime_resume); */ int acpi_dev_suspend_late(struct device *dev) { - struct acpi_device *adev = acpi_dev_pm_get_node(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); u32 target_state; bool wakeup; int error; @@ -894,7 +882,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_suspend_late); */ int acpi_dev_resume_early(struct device *dev) { - struct acpi_device *adev = acpi_dev_pm_get_node(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); int error; if (!adev) @@ -985,7 +973,7 @@ static struct dev_pm_domain acpi_general_pm_domain = { */ int acpi_dev_pm_attach(struct device *dev, bool power_on) { - struct acpi_device *adev = acpi_dev_pm_get_node(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); if (!adev) return -ENODEV; @@ -1017,7 +1005,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_pm_attach); */ void acpi_dev_pm_detach(struct device *dev, bool power_off) { - struct acpi_device *adev = acpi_dev_pm_get_node(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); if (adev && dev->pm_domain == &acpi_general_pm_domain) { dev->pm_domain = NULL; diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index c431c88faaffa1..5bfd769fc91fa5 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -609,7 +609,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event) static void dock_notify(struct dock_station *ds, u32 event) { acpi_handle handle = ds->handle; - struct acpi_device *ad; + struct acpi_device *adev = NULL; int surprise_removal = 0; /* @@ -632,7 +632,8 @@ static void dock_notify(struct dock_station *ds, u32 event) switch (event) { case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_DEVICE_CHECK: - if (!dock_in_progress(ds) && acpi_bus_get_device(handle, &ad)) { + acpi_bus_get_device(handle, &adev); + if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) { begin_dock(ds); dock(ds); if (!dock_present(ds)) { @@ -712,13 +713,11 @@ static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl, static ssize_t show_docked(struct device *dev, struct device_attribute *attr, char *buf) { - struct acpi_device *tmp; - struct dock_station *dock_station = dev->platform_data; + struct acpi_device *adev = NULL; - if (!acpi_bus_get_device(dock_station->handle, &tmp)) - return snprintf(buf, PAGE_SIZE, "1\n"); - return snprintf(buf, PAGE_SIZE, "0\n"); + acpi_bus_get_device(dock_station->handle, &adev); + return snprintf(buf, PAGE_SIZE, "%u\n", acpi_device_enumerated(adev)); } static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 1fb62900f32a9c..09e423f3d8ad30 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -55,6 +55,9 @@ MODULE_DEVICE_TABLE(acpi, fan_device_ids); #ifdef CONFIG_PM_SLEEP static int acpi_fan_suspend(struct device *dev); static int acpi_fan_resume(struct device *dev); +#else +#define acpi_fan_suspend NULL +#define acpi_fan_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_fan_pm, acpi_fan_suspend, acpi_fan_resume); diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 52d45ea2bc4f63..361b40c10c3f52 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -430,6 +430,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) pin_name(pin)); } + kfree(entry); return 0; } diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index 50fe34ffe932fb..75c28eae886049 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c @@ -60,7 +60,7 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) seq_printf(seq, "%c%-8s %s:%s\n", dev->wakeup.flags.run_wake ? '*' : ' ', (device_may_wakeup(&dev->dev) || - (ldev && device_may_wakeup(ldev))) ? + device_may_wakeup(ldev)) ? "enabled" : "disabled", ldev->bus ? ldev->bus->name : "no-bus", dev_name(ldev)); diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 34e7b3c6a08de1..a4eea9a508d3ef 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -44,13 +44,13 @@ static int map_lapic_id(struct acpi_subtable_header *entry, (struct acpi_madt_local_apic *)entry; if (!(lapic->lapic_flags & ACPI_MADT_ENABLED)) - return 0; + return -ENODEV; if (lapic->processor_id != acpi_id) - return 0; + return -EINVAL; *apic_id = lapic->id; - return 1; + return 0; } static int map_x2apic_id(struct acpi_subtable_header *entry, @@ -60,14 +60,14 @@ static int map_x2apic_id(struct acpi_subtable_header *entry, (struct acpi_madt_local_x2apic *)entry; if (!(apic->lapic_flags & ACPI_MADT_ENABLED)) - return 0; + return -ENODEV; if (device_declaration && (apic->uid == acpi_id)) { *apic_id = apic->local_apic_id; - return 1; + return 0; } - return 0; + return -EINVAL; } static int map_lsapic_id(struct acpi_subtable_header *entry, @@ -77,16 +77,16 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, (struct acpi_madt_local_sapic *)entry; if (!(lsapic->lapic_flags & ACPI_MADT_ENABLED)) - return 0; + return -ENODEV; if (device_declaration) { if ((entry->length < 16) || (lsapic->uid != acpi_id)) - return 0; + return -EINVAL; } else if (lsapic->processor_id != acpi_id) - return 0; + return -EINVAL; *apic_id = (lsapic->id << 8) | lsapic->eid; - return 1; + return 0; } static int map_madt_entry(int type, u32 acpi_id) @@ -116,13 +116,13 @@ static int map_madt_entry(int type, u32 acpi_id) struct acpi_subtable_header *header = (struct acpi_subtable_header *)entry; if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) { - if (map_lapic_id(header, acpi_id, &apic_id)) + if (!map_lapic_id(header, acpi_id, &apic_id)) break; } else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) { - if (map_x2apic_id(header, type, acpi_id, &apic_id)) + if (!map_x2apic_id(header, type, acpi_id, &apic_id)) break; } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) { - if (map_lsapic_id(header, type, acpi_id, &apic_id)) + if (!map_lsapic_id(header, type, acpi_id, &apic_id)) break; } entry += header->length; diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index d465ae6cdd004b..dbd48498b93863 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -450,7 +450,7 @@ static ssize_t acpi_battery_alarm_store(struct device *dev, { unsigned long x; struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); - if (sscanf(buf, "%ld\n", &x) == 1) + if (sscanf(buf, "%lu\n", &x) == 1) battery->alarm_capacity = x / (1000 * acpi_battery_scale(battery)); if (battery->present) @@ -668,6 +668,8 @@ static int acpi_sbs_resume(struct device *dev) acpi_sbs_callback(sbs); return 0; } +#else +#define acpi_sbs_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_sbs_pm, NULL, acpi_sbs_resume); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index e00365ccb89750..57b053f424d13e 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -484,7 +484,6 @@ static void acpi_device_hotplug(void *data, u32 src) static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) { u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - struct acpi_scan_handler *handler = data; struct acpi_device *adev; acpi_status status; @@ -500,7 +499,10 @@ static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) break; case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - if (!handler->hotplug.enabled) { + if (!adev->handler) + goto err_out; + + if (!adev->handler->hotplug.enabled) { acpi_handle_err(handle, "Eject disabled\n"); ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; goto err_out; @@ -2105,6 +2107,7 @@ void acpi_bus_trim(struct acpi_device *adev) list_for_each_entry_reverse(child, &adev->children, node) acpi_bus_trim(child); + adev->flags.match_driver = false; if (handler) { if (handler->detach) handler->detach(adev); diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 443dc9366052f6..91a32cefb11f60 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -226,7 +226,7 @@ module_param_call(trace_state, param_set_trace_state, param_get_trace_state, /* /sys/modules/acpi/parameters/aml_debug_output */ module_param_named(aml_debug_output, acpi_gbl_enable_aml_debug_object, - bool, 0644); + byte, 0644); MODULE_PARM_DESC(aml_debug_output, "To enable/disable the ACPI Debug Object output."); diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 8349a555b92b8a..08626c851be7ee 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -102,6 +102,8 @@ MODULE_DEVICE_TABLE(acpi, thermal_device_ids); #ifdef CONFIG_PM_SLEEP static int acpi_thermal_resume(struct device *dev); +#else +#define acpi_thermal_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, NULL, acpi_thermal_resume); diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 0347a37eb4389d..85e3b612bdc0d4 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -99,10 +99,6 @@ acpi_extract_package(union acpi_object *package, union acpi_object *element = &(package->package.elements[i]); - if (!element) { - return AE_BAD_DATA; - } - switch (element->type) { case ACPI_TYPE_INTEGER: diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index b727d105046d23..b6ba88ed31aeeb 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -81,11 +81,12 @@ static bool allow_duplicates; module_param(allow_duplicates, bool, 0644); /* - * For Windows 8 systems: if set ture and the GPU driver has - * registered a backlight interface, skip registering ACPI video's. + * For Windows 8 systems: used to decide if video module + * should skip registering backlight interface of its own. */ -static bool use_native_backlight = false; -module_param(use_native_backlight, bool, 0644); +static int use_native_backlight_param = -1; +module_param_named(use_native_backlight, use_native_backlight_param, int, 0444); +static bool use_native_backlight_dmi = false; static int register_count; static struct mutex video_list_lock; @@ -231,9 +232,17 @@ static int acpi_video_get_next_level(struct acpi_video_device *device, static int acpi_video_switch_brightness(struct acpi_video_device *device, int event); +static bool acpi_video_use_native_backlight(void) +{ + if (use_native_backlight_param != -1) + return use_native_backlight_param; + else + return use_native_backlight_dmi; +} + static bool acpi_video_verify_backlight_support(void) { - if (acpi_osi_is_win8() && use_native_backlight && + if (acpi_osi_is_win8() && acpi_video_use_native_backlight() && backlight_device_registered(BACKLIGHT_RAW)) return false; return acpi_video_backlight_support(); @@ -398,6 +407,12 @@ static int __init video_set_bqc_offset(const struct dmi_system_id *d) return 0; } +static int __init video_set_use_native_backlight(const struct dmi_system_id *d) +{ + use_native_backlight_dmi = true; + return 0; +} + static struct dmi_system_id video_dmi_table[] __initdata = { /* * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121 @@ -442,6 +457,120 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"), }, }, + { + .callback = video_set_use_native_backlight, + .ident = "ThinkPad T430s", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T430s"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "ThinkPad X230", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X230"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "ThinkPad X1 Carbon", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X1 Carbon"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "Lenovo Yoga 13", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga 13"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "Dell Inspiron 7520", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_VERSION, "Inspiron 7520"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "Acer Aspire 5733Z", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5733Z"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "Acer Aspire V5-431", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-431"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP ProBook 4340s", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_VERSION, "HP ProBook 4340s"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP ProBook 2013 models", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook "), + DMI_MATCH(DMI_PRODUCT_NAME, " G1"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP EliteBook 2013 models", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook "), + DMI_MATCH(DMI_PRODUCT_NAME, " G1"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP ZBook 14", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 14"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP ZBook 15", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 15"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP ZBook 17", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 17"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP EliteBook 8780w", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8780w"), + }, + }, {} }; @@ -685,6 +814,7 @@ acpi_video_init_brightness(struct acpi_video_device *device) union acpi_object *o; struct acpi_video_device_brightness *br = NULL; int result = -EINVAL; + u32 value; if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available " @@ -715,7 +845,12 @@ acpi_video_init_brightness(struct acpi_video_device *device) printk(KERN_ERR PREFIX "Invalid data\n"); continue; } - br->levels[count] = (u32) o->integer.value; + value = (u32) o->integer.value; + /* Skip duplicate entries */ + if (count > 2 && br->levels[count - 1] == value) + continue; + + br->levels[count] = value; if (br->levels[count] > max_level) max_level = br->levels[count]; diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index f0447d3daf2c43..19080c8e2f2a9c 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -168,14 +168,6 @@ static struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"), }, }, - { - .callback = video_detect_force_vendor, - .ident = "Lenovo Yoga 13", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga 13"), - }, - }, { }, }; diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 4e737728aee207..868429a47be41a 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -247,6 +247,7 @@ config SATA_HIGHBANK config SATA_MV tristate "Marvell SATA support" + select GENERIC_PHY help This option enables support for the Marvell Serial ATA family. Currently supports 88SX[56]0[48][01] PCI(-X) chips, diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index dc2756fb6f3369..c81d809c111b23 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -61,6 +61,7 @@ enum board_ids { /* board IDs by feature in alphabetical order */ board_ahci, board_ahci_ign_iferr, + board_ahci_noncq, board_ahci_nosntf, board_ahci_yes_fbs, @@ -121,6 +122,13 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, + [board_ahci_noncq] = { + AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ), + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, [board_ahci_nosntf] = { AHCI_HFLAGS (AHCI_HFLAG_NO_SNTF), .flags = AHCI_FLAG_COMMON, @@ -452,6 +460,12 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */ { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */ + /* + * Samsung SSDs found on some macbooks. NCQ times out. + * https://bugzilla.kernel.org/show_bug.cgi?id=60731 + */ + { PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_noncq }, + /* Enmotus */ { PCI_DEVICE(0x1c44, 0x8000), board_ahci }, @@ -1170,8 +1184,10 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, nvec = rc; rc = pci_enable_msi_block(pdev, nvec); - if (rc) + if (rc < 0) goto intx; + else if (rc > 0) + goto single_msi; return nvec; diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 20fd337a57314a..7ccc084bf1dfb8 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -447,8 +447,11 @@ static void sata_pmp_quirks(struct ata_port *ap) * otherwise. Don't try hard to recover it. */ ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY; - } else if (vendor == 0x197b && devid == 0x2352) { - /* chip found in Thermaltake BlackX Duet, jmicron JMB350? */ + } else if (vendor == 0x197b && (devid == 0x2352 || devid == 0x0325)) { + /* + * 0x2352: found in Thermaltake BlackX Duet, jmicron JMB350? + * 0x0325: jmicron JMB394. + */ ata_for_each_link(link, ap, EDGE) { /* SRST breaks detection and disks get misclassified * LPM disabled to avoid potential problems diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c index 26386f0b89a8f4..b0b18ec5465ffe 100644 --- a/drivers/ata/pata_imx.c +++ b/drivers/ata/pata_imx.c @@ -119,7 +119,9 @@ static int pata_imx_probe(struct platform_device *pdev) return PTR_ERR(priv->clk); } - clk_prepare_enable(priv->clk); + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; host = ata_host_alloc(&pdev->dev, 1); if (!host) { @@ -212,7 +214,9 @@ static int pata_imx_resume(struct device *dev) struct ata_host *host = dev_get_drvdata(dev); struct pata_imx_priv *priv = host->private_data; - clk_prepare_enable(priv->clk); + int ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; __raw_writel(priv->ata_ctl, priv->host_regs + PATA_IMX_ATA_CONTROL); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 20a7517bd3393d..05c8a44adf8ede 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -4104,7 +4104,6 @@ static int mv_platform_probe(struct platform_device *pdev) if (!hpriv->port_phys) return -ENOMEM; host->private_data = hpriv; - hpriv->n_ports = n_ports; hpriv->board_idx = chip_soc; host->iomap = NULL; @@ -4126,17 +4125,24 @@ static int mv_platform_probe(struct platform_device *pdev) clk_prepare_enable(hpriv->port_clks[port]); sprintf(port_number, "port%d", port); - hpriv->port_phys[port] = devm_phy_get(&pdev->dev, port_number); + hpriv->port_phys[port] = devm_phy_optional_get(&pdev->dev, + port_number); if (IS_ERR(hpriv->port_phys[port])) { rc = PTR_ERR(hpriv->port_phys[port]); hpriv->port_phys[port] = NULL; - if ((rc != -EPROBE_DEFER) && (rc != -ENODEV)) - dev_warn(&pdev->dev, "error getting phy"); + if (rc != -EPROBE_DEFER) + dev_warn(&pdev->dev, "error getting phy %d", rc); + + /* Cleanup only the initialized ports */ + hpriv->n_ports = port; goto err; } else phy_power_on(hpriv->port_phys[port]); } + /* All the ports have been initialized */ + hpriv->n_ports = n_ports; + /* * (Re-)program MBUS remapping windows if we are asked to. */ @@ -4174,7 +4180,7 @@ static int mv_platform_probe(struct platform_device *pdev) clk_disable_unprepare(hpriv->clk); clk_put(hpriv->clk); } - for (port = 0; port < n_ports; port++) { + for (port = 0; port < hpriv->n_ports; port++) { if (!IS_ERR(hpriv->port_clks[port])) { clk_disable_unprepare(hpriv->port_clks[port]); clk_put(hpriv->port_clks[port]); diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index d67fc351343ca8..b7695e804635b8 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -157,6 +157,7 @@ static const struct sil_drivelist { { "ST380011ASL", SIL_QUIRK_MOD15WRITE }, { "ST3120022ASL", SIL_QUIRK_MOD15WRITE }, { "ST3160021ASL", SIL_QUIRK_MOD15WRITE }, + { "TOSHIBA MK2561GSYN", SIL_QUIRK_MOD15WRITE }, { "Maxtor 4D060H3", SIL_QUIRK_UDMA5MAX }, { } }; diff --git a/drivers/base/component.c b/drivers/base/component.c index c53efe6c6d8eb4..c4778995cd7280 100644 --- a/drivers/base/component.c +++ b/drivers/base/component.c @@ -133,9 +133,16 @@ static int try_to_bring_up_master(struct master *master, goto out; } + if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) { + ret = -ENOMEM; + goto out; + } + /* Found all components */ ret = master->ops->bind(master->dev); if (ret < 0) { + devres_release_group(master->dev, NULL); + dev_info(master->dev, "master bind failed: %d\n", ret); master_remove_components(master); goto out; } @@ -166,6 +173,7 @@ static void take_down_master(struct master *master) { if (master->bound) { master->ops->unbind(master->dev); + devres_release_group(master->dev, NULL); master->bound = false; } diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c index 1e16cbd61da278..61d6d62cc0d35f 100644 --- a/drivers/base/dma-buf.c +++ b/drivers/base/dma-buf.c @@ -616,36 +616,35 @@ static int dma_buf_describe(struct seq_file *s) if (ret) return ret; - seq_printf(s, "\nDma-buf Objects:\n"); - seq_printf(s, "\texp_name\tsize\tflags\tmode\tcount\n"); + seq_puts(s, "\nDma-buf Objects:\n"); + seq_puts(s, "size\tflags\tmode\tcount\texp_name\n"); list_for_each_entry(buf_obj, &db_list.head, list_node) { ret = mutex_lock_interruptible(&buf_obj->lock); if (ret) { - seq_printf(s, - "\tERROR locking buffer object: skipping\n"); + seq_puts(s, + "\tERROR locking buffer object: skipping\n"); continue; } - seq_printf(s, "\t"); - - seq_printf(s, "\t%s\t%08zu\t%08x\t%08x\t%08ld\n", - buf_obj->exp_name, buf_obj->size, + seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\n", + buf_obj->size, buf_obj->file->f_flags, buf_obj->file->f_mode, - (long)(buf_obj->file->f_count.counter)); + (long)(buf_obj->file->f_count.counter), + buf_obj->exp_name); - seq_printf(s, "\t\tAttached Devices:\n"); + seq_puts(s, "\tAttached Devices:\n"); attach_count = 0; list_for_each_entry(attach_obj, &buf_obj->attachments, node) { - seq_printf(s, "\t\t"); + seq_puts(s, "\t"); - seq_printf(s, "%s\n", attach_obj->dev->init_name); + seq_printf(s, "%s\n", dev_name(attach_obj->dev)); attach_count++; } - seq_printf(s, "\n\t\tTotal %d devices attached\n", + seq_printf(s, "Total %d devices attached\n\n", attach_count); count++; diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig index 7c081b38ef3e84..0ee48be23837e2 100644 --- a/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig @@ -75,6 +75,7 @@ config BCMA_DRIVER_GMAC_CMN config BCMA_DRIVER_GPIO bool "BCMA GPIO driver" depends on BCMA && GPIOLIB + select IRQ_DOMAIN if BCMA_HOST_SOC help Driver to provide access to the GPIO pins of the bcma bus. diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c index 45f0996a375231..25f9887a35d08e 100644 --- a/drivers/bcma/driver_gpio.c +++ b/drivers/bcma/driver_gpio.c @@ -9,6 +9,9 @@ */ #include +#include +#include +#include #include #include @@ -73,19 +76,136 @@ static void bcma_gpio_free(struct gpio_chip *chip, unsigned gpio) bcma_chipco_gpio_pullup(cc, 1 << gpio, 0); } +#if IS_BUILTIN(CONFIG_BCMA_HOST_SOC) static int bcma_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) { struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip); if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC) - return bcma_core_irq(cc->core); + return irq_find_mapping(cc->irq_domain, gpio); else return -EINVAL; } +static void bcma_gpio_irq_unmask(struct irq_data *d) +{ + struct bcma_drv_cc *cc = irq_data_get_irq_chip_data(d); + int gpio = irqd_to_hwirq(d); + u32 val = bcma_chipco_gpio_in(cc, BIT(gpio)); + + bcma_chipco_gpio_polarity(cc, BIT(gpio), val); + bcma_chipco_gpio_intmask(cc, BIT(gpio), BIT(gpio)); +} + +static void bcma_gpio_irq_mask(struct irq_data *d) +{ + struct bcma_drv_cc *cc = irq_data_get_irq_chip_data(d); + int gpio = irqd_to_hwirq(d); + + bcma_chipco_gpio_intmask(cc, BIT(gpio), 0); +} + +static struct irq_chip bcma_gpio_irq_chip = { + .name = "BCMA-GPIO", + .irq_mask = bcma_gpio_irq_mask, + .irq_unmask = bcma_gpio_irq_unmask, +}; + +static irqreturn_t bcma_gpio_irq_handler(int irq, void *dev_id) +{ + struct bcma_drv_cc *cc = dev_id; + u32 val = bcma_cc_read32(cc, BCMA_CC_GPIOIN); + u32 mask = bcma_cc_read32(cc, BCMA_CC_GPIOIRQ); + u32 pol = bcma_cc_read32(cc, BCMA_CC_GPIOPOL); + unsigned long irqs = (val ^ pol) & mask; + int gpio; + + if (!irqs) + return IRQ_NONE; + + for_each_set_bit(gpio, &irqs, cc->gpio.ngpio) + generic_handle_irq(bcma_gpio_to_irq(&cc->gpio, gpio)); + bcma_chipco_gpio_polarity(cc, irqs, val & irqs); + + return IRQ_HANDLED; +} + +static int bcma_gpio_irq_domain_init(struct bcma_drv_cc *cc) +{ + struct gpio_chip *chip = &cc->gpio; + int gpio, hwirq, err; + + if (cc->core->bus->hosttype != BCMA_HOSTTYPE_SOC) + return 0; + + cc->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, + &irq_domain_simple_ops, cc); + if (!cc->irq_domain) { + err = -ENODEV; + goto err_irq_domain; + } + for (gpio = 0; gpio < chip->ngpio; gpio++) { + int irq = irq_create_mapping(cc->irq_domain, gpio); + + irq_set_chip_data(irq, cc); + irq_set_chip_and_handler(irq, &bcma_gpio_irq_chip, + handle_simple_irq); + } + + hwirq = bcma_core_irq(cc->core); + err = request_irq(hwirq, bcma_gpio_irq_handler, IRQF_SHARED, "gpio", + cc); + if (err) + goto err_req_irq; + + bcma_chipco_gpio_intmask(cc, ~0, 0); + bcma_cc_set32(cc, BCMA_CC_IRQMASK, BCMA_CC_IRQ_GPIO); + + return 0; + +err_req_irq: + for (gpio = 0; gpio < chip->ngpio; gpio++) { + int irq = irq_find_mapping(cc->irq_domain, gpio); + + irq_dispose_mapping(irq); + } + irq_domain_remove(cc->irq_domain); +err_irq_domain: + return err; +} + +static void bcma_gpio_irq_domain_exit(struct bcma_drv_cc *cc) +{ + struct gpio_chip *chip = &cc->gpio; + int gpio; + + if (cc->core->bus->hosttype != BCMA_HOSTTYPE_SOC) + return; + + bcma_cc_mask32(cc, BCMA_CC_IRQMASK, ~BCMA_CC_IRQ_GPIO); + free_irq(bcma_core_irq(cc->core), cc); + for (gpio = 0; gpio < chip->ngpio; gpio++) { + int irq = irq_find_mapping(cc->irq_domain, gpio); + + irq_dispose_mapping(irq); + } + irq_domain_remove(cc->irq_domain); +} +#else +static int bcma_gpio_irq_domain_init(struct bcma_drv_cc *cc) +{ + return 0; +} + +static void bcma_gpio_irq_domain_exit(struct bcma_drv_cc *cc) +{ +} +#endif + int bcma_gpio_init(struct bcma_drv_cc *cc) { struct gpio_chip *chip = &cc->gpio; + int err; chip->label = "bcma_gpio"; chip->owner = THIS_MODULE; @@ -95,7 +215,9 @@ int bcma_gpio_init(struct bcma_drv_cc *cc) chip->set = bcma_gpio_set_value; chip->direction_input = bcma_gpio_direction_input; chip->direction_output = bcma_gpio_direction_output; +#if IS_BUILTIN(CONFIG_BCMA_HOST_SOC) chip->to_irq = bcma_gpio_to_irq; +#endif chip->ngpio = 16; /* There is just one SoC in one device and its GPIO addresses should be * deterministic to address them more easily. The other buses could get @@ -105,10 +227,21 @@ int bcma_gpio_init(struct bcma_drv_cc *cc) else chip->base = -1; - return gpiochip_add(chip); + err = bcma_gpio_irq_domain_init(cc); + if (err) + return err; + + err = gpiochip_add(chip); + if (err) { + bcma_gpio_irq_domain_exit(cc); + return err; + } + + return 0; } int bcma_gpio_unregister(struct bcma_drv_cc *cc) { + bcma_gpio_irq_domain_exit(cc); return gpiochip_remove(&cc->gpio); } diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 9ffa90c6201c38..014a1cfc41c51f 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -108,6 +108,8 @@ source "drivers/block/paride/Kconfig" source "drivers/block/mtip32xx/Kconfig" +source "drivers/block/zram/Kconfig" + config BLK_CPQ_DA tristate "Compaq SMART2 support" depends on PCI && VIRT_TO_BUS && 0 diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 816d979c32667f..02b688d1438d95 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_BLK_DEV_PCIESSD_MTIP32XX) += mtip32xx/ obj-$(CONFIG_BLK_DEV_RSXX) += rsxx/ obj-$(CONFIG_BLK_DEV_NULL_BLK) += null_blk.o +obj-$(CONFIG_ZRAM) += zram/ nvme-y := nvme-core.o nvme-scsi.o skd-y := skd_main.o diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 14a9d1912318b9..9220f8e833d082 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -100,11 +100,8 @@ enum { struct buf { ulong nframesout; - ulong resid; - ulong bv_resid; - sector_t sector; struct bio *bio; - struct bio_vec *bv; + struct bvec_iter iter; struct request *rq; }; @@ -120,13 +117,10 @@ struct frame { ulong waited; ulong waited_total; struct aoetgt *t; /* parent target I belong to */ - sector_t lba; struct sk_buff *skb; /* command skb freed on module exit */ struct sk_buff *r_skb; /* response skb for async processing */ struct buf *buf; - struct bio_vec *bv; - ulong bcnt; - ulong bv_off; + struct bvec_iter iter; char flags; }; diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index d2515435e23f2f..8184451b57c049 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -196,8 +196,7 @@ aoe_freetframe(struct frame *f) t = f->t; f->buf = NULL; - f->lba = 0; - f->bv = NULL; + memset(&f->iter, 0, sizeof(f->iter)); f->r_skb = NULL; f->flags = 0; list_add(&f->head, &t->ffree); @@ -295,21 +294,14 @@ newframe(struct aoedev *d) } static void -skb_fillup(struct sk_buff *skb, struct bio_vec *bv, ulong off, ulong cnt) +skb_fillup(struct sk_buff *skb, struct bio *bio, struct bvec_iter iter) { int frag = 0; - ulong fcnt; -loop: - fcnt = bv->bv_len - (off - bv->bv_offset); - if (fcnt > cnt) - fcnt = cnt; - skb_fill_page_desc(skb, frag++, bv->bv_page, off, fcnt); - cnt -= fcnt; - if (cnt <= 0) - return; - bv++; - off = bv->bv_offset; - goto loop; + struct bio_vec bv; + + __bio_for_each_segment(bv, bio, iter, iter) + skb_fill_page_desc(skb, frag++, bv.bv_page, + bv.bv_offset, bv.bv_len); } static void @@ -346,12 +338,10 @@ ata_rw_frameinit(struct frame *f) t->nout++; f->waited = 0; f->waited_total = 0; - if (f->buf) - f->lba = f->buf->sector; /* set up ata header */ - ah->scnt = f->bcnt >> 9; - put_lba(ah, f->lba); + ah->scnt = f->iter.bi_size >> 9; + put_lba(ah, f->iter.bi_sector); if (t->d->flags & DEVFL_EXT) { ah->aflags |= AOEAFL_EXT; } else { @@ -360,11 +350,11 @@ ata_rw_frameinit(struct frame *f) ah->lba3 |= 0xe0; /* LBA bit + obsolete 0xa0 */ } if (f->buf && bio_data_dir(f->buf->bio) == WRITE) { - skb_fillup(skb, f->bv, f->bv_off, f->bcnt); + skb_fillup(skb, f->buf->bio, f->iter); ah->aflags |= AOEAFL_WRITE; - skb->len += f->bcnt; - skb->data_len = f->bcnt; - skb->truesize += f->bcnt; + skb->len += f->iter.bi_size; + skb->data_len = f->iter.bi_size; + skb->truesize += f->iter.bi_size; t->wpkts++; } else { t->rpkts++; @@ -382,7 +372,6 @@ aoecmd_ata_rw(struct aoedev *d) struct buf *buf; struct sk_buff *skb; struct sk_buff_head queue; - ulong bcnt, fbcnt; buf = nextbuf(d); if (buf == NULL) @@ -390,39 +379,22 @@ aoecmd_ata_rw(struct aoedev *d) f = newframe(d); if (f == NULL) return 0; - bcnt = d->maxbcnt; - if (bcnt == 0) - bcnt = DEFAULTBCNT; - if (bcnt > buf->resid) - bcnt = buf->resid; - fbcnt = bcnt; - f->bv = buf->bv; - f->bv_off = f->bv->bv_offset + (f->bv->bv_len - buf->bv_resid); - do { - if (fbcnt < buf->bv_resid) { - buf->bv_resid -= fbcnt; - buf->resid -= fbcnt; - break; - } - fbcnt -= buf->bv_resid; - buf->resid -= buf->bv_resid; - if (buf->resid == 0) { - d->ip.buf = NULL; - break; - } - buf->bv++; - buf->bv_resid = buf->bv->bv_len; - WARN_ON(buf->bv_resid == 0); - } while (fbcnt); /* initialize the headers & frame */ f->buf = buf; - f->bcnt = bcnt; - ata_rw_frameinit(f); + f->iter = buf->iter; + f->iter.bi_size = min_t(unsigned long, + d->maxbcnt ?: DEFAULTBCNT, + f->iter.bi_size); + bio_advance_iter(buf->bio, &buf->iter, f->iter.bi_size); + + if (!buf->iter.bi_size) + d->ip.buf = NULL; /* mark all tracking fields and load out */ buf->nframesout += 1; - buf->sector += bcnt >> 9; + + ata_rw_frameinit(f); skb = skb_clone(f->skb, GFP_ATOMIC); if (skb) { @@ -613,10 +585,7 @@ reassign_frame(struct frame *f) skb = nf->skb; nf->skb = f->skb; nf->buf = f->buf; - nf->bcnt = f->bcnt; - nf->lba = f->lba; - nf->bv = f->bv; - nf->bv_off = f->bv_off; + nf->iter = f->iter; nf->waited = 0; nf->waited_total = f->waited_total; nf->sent = f->sent; @@ -648,19 +617,19 @@ probe(struct aoetgt *t) } f->flags |= FFL_PROBE; ifrotate(t); - f->bcnt = t->d->maxbcnt ? t->d->maxbcnt : DEFAULTBCNT; + f->iter.bi_size = t->d->maxbcnt ? t->d->maxbcnt : DEFAULTBCNT; ata_rw_frameinit(f); skb = f->skb; - for (frag = 0, n = f->bcnt; n > 0; ++frag, n -= m) { + for (frag = 0, n = f->iter.bi_size; n > 0; ++frag, n -= m) { if (n < PAGE_SIZE) m = n; else m = PAGE_SIZE; skb_fill_page_desc(skb, frag, empty_page, 0, m); } - skb->len += f->bcnt; - skb->data_len = f->bcnt; - skb->truesize += f->bcnt; + skb->len += f->iter.bi_size; + skb->data_len = f->iter.bi_size; + skb->truesize += f->iter.bi_size; skb = skb_clone(f->skb, GFP_ATOMIC); if (skb) { @@ -897,15 +866,15 @@ rqbiocnt(struct request *r) static void bio_pageinc(struct bio *bio) { - struct bio_vec *bv; + struct bio_vec bv; struct page *page; - int i; + struct bvec_iter iter; - bio_for_each_segment(bv, bio, i) { + bio_for_each_segment(bv, bio, iter) { /* Non-zero page count for non-head members of * compound pages is no longer allowed by the kernel. */ - page = compound_trans_head(bv->bv_page); + page = compound_trans_head(bv.bv_page); atomic_inc(&page->_count); } } @@ -913,12 +882,12 @@ bio_pageinc(struct bio *bio) static void bio_pagedec(struct bio *bio) { - struct bio_vec *bv; struct page *page; - int i; + struct bio_vec bv; + struct bvec_iter iter; - bio_for_each_segment(bv, bio, i) { - page = compound_trans_head(bv->bv_page); + bio_for_each_segment(bv, bio, iter) { + page = compound_trans_head(bv.bv_page); atomic_dec(&page->_count); } } @@ -929,12 +898,8 @@ bufinit(struct buf *buf, struct request *rq, struct bio *bio) memset(buf, 0, sizeof(*buf)); buf->rq = rq; buf->bio = bio; - buf->resid = bio->bi_size; - buf->sector = bio->bi_sector; + buf->iter = bio->bi_iter; bio_pageinc(bio); - buf->bv = bio_iovec(bio); - buf->bv_resid = buf->bv->bv_len; - WARN_ON(buf->bv_resid == 0); } static struct buf * @@ -1119,24 +1084,18 @@ gettgt(struct aoedev *d, char *addr) } static void -bvcpy(struct bio_vec *bv, ulong off, struct sk_buff *skb, long cnt) +bvcpy(struct sk_buff *skb, struct bio *bio, struct bvec_iter iter, long cnt) { - ulong fcnt; - char *p; int soff = 0; -loop: - fcnt = bv->bv_len - (off - bv->bv_offset); - if (fcnt > cnt) - fcnt = cnt; - p = page_address(bv->bv_page) + off; - skb_copy_bits(skb, soff, p, fcnt); - soff += fcnt; - cnt -= fcnt; - if (cnt <= 0) - return; - bv++; - off = bv->bv_offset; - goto loop; + struct bio_vec bv; + + iter.bi_size = cnt; + + __bio_for_each_segment(bv, bio, iter, iter) { + char *p = page_address(bv.bv_page) + bv.bv_offset; + skb_copy_bits(skb, soff, p, bv.bv_len); + soff += bv.bv_len; + } } void @@ -1152,7 +1111,7 @@ aoe_end_request(struct aoedev *d, struct request *rq, int fastfail) do { bio = rq->bio; bok = !fastfail && test_bit(BIO_UPTODATE, &bio->bi_flags); - } while (__blk_end_request(rq, bok ? 0 : -EIO, bio->bi_size)); + } while (__blk_end_request(rq, bok ? 0 : -EIO, bio->bi_iter.bi_size)); /* cf. http://lkml.org/lkml/2006/10/31/28 */ if (!fastfail) @@ -1229,7 +1188,15 @@ noskb: if (buf) clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); break; } - bvcpy(f->bv, f->bv_off, skb, n); + if (n > f->iter.bi_size) { + pr_err_ratelimited("%s e%ld.%d. bytes=%ld need=%u\n", + "aoe: too-large data size in read from", + (long) d->aoemajor, d->aoeminor, + n, f->iter.bi_size); + clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); + break; + } + bvcpy(skb, f->buf->bio, f->iter, n); case ATA_CMD_PIO_WRITE: case ATA_CMD_PIO_WRITE_EXT: spin_lock_irq(&d->lock); @@ -1272,7 +1239,7 @@ noskb: if (buf) aoe_freetframe(f); - if (buf && --buf->nframesout == 0 && buf->resid == 0) + if (buf && --buf->nframesout == 0 && buf->iter.bi_size == 0) aoe_end_buf(d, buf); spin_unlock_irq(&d->lock); @@ -1727,7 +1694,7 @@ aoe_failbuf(struct aoedev *d, struct buf *buf) { if (buf == NULL) return; - buf->resid = 0; + buf->iter.bi_size = 0; clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); if (buf->nframesout == 0) aoe_end_buf(d, buf); diff --git a/drivers/block/brd.c b/drivers/block/brd.c index d91f1a56e8617f..e73b85cf075687 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -328,18 +328,18 @@ static void brd_make_request(struct request_queue *q, struct bio *bio) struct block_device *bdev = bio->bi_bdev; struct brd_device *brd = bdev->bd_disk->private_data; int rw; - struct bio_vec *bvec; + struct bio_vec bvec; sector_t sector; - int i; + struct bvec_iter iter; int err = -EIO; - sector = bio->bi_sector; + sector = bio->bi_iter.bi_sector; if (bio_end_sector(bio) > get_capacity(bdev->bd_disk)) goto out; if (unlikely(bio->bi_rw & REQ_DISCARD)) { err = 0; - discard_from_brd(brd, sector, bio->bi_size); + discard_from_brd(brd, sector, bio->bi_iter.bi_size); goto out; } @@ -347,10 +347,10 @@ static void brd_make_request(struct request_queue *q, struct bio *bio) if (rw == READA) rw = READ; - bio_for_each_segment(bvec, bio, i) { - unsigned int len = bvec->bv_len; - err = brd_do_bvec(brd, bvec->bv_page, len, - bvec->bv_offset, rw, sector); + bio_for_each_segment(bvec, bio, iter) { + unsigned int len = bvec.bv_len; + err = brd_do_bvec(brd, bvec.bv_page, len, + bvec.bv_offset, rw, sector); if (err) break; sector += len >> SECTOR_SHIFT; diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index b35fc4f5237c3b..036e8ab86c7180 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -5004,7 +5004,7 @@ static int cciss_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) i = alloc_cciss_hba(pdev); if (i < 0) - return -1; + return -ENOMEM; h = hba[i]; h->pdev = pdev; @@ -5205,7 +5205,7 @@ static int cciss_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) */ pci_set_drvdata(pdev, NULL); free_hba(h); - return -1; + return -ENODEV; } static void cciss_shutdown(struct pci_dev *pdev) diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 28c73ca320a8f7..a9b13f2cc420b0 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -159,7 +159,7 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev, bio = bio_alloc_drbd(GFP_NOIO); bio->bi_bdev = bdev->md_bdev; - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; err = -EIO; if (bio_add_page(bio, page, size, 0) != size) goto out; diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index b12c11ec4bd21e..597f111df67b35 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -1028,7 +1028,7 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must } else page = b->bm_pages[page_nr]; bio->bi_bdev = mdev->ldev->md_bdev; - bio->bi_sector = on_disk_sector; + bio->bi_iter.bi_sector = on_disk_sector; /* bio_add_page of a single page to an empty bio will always succeed, * according to api. Do we want to assert that? */ bio_add_page(bio, page, len, 0); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 9e3818b1bc8321..929468e1512a68 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1537,15 +1537,17 @@ static int _drbd_send_page(struct drbd_conf *mdev, struct page *page, static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio) { - struct bio_vec *bvec; - int i; + struct bio_vec bvec; + struct bvec_iter iter; + /* hint all but last page with MSG_MORE */ - bio_for_each_segment(bvec, bio, i) { + bio_for_each_segment(bvec, bio, iter) { int err; - err = _drbd_no_send_page(mdev, bvec->bv_page, - bvec->bv_offset, bvec->bv_len, - i == bio->bi_vcnt - 1 ? 0 : MSG_MORE); + err = _drbd_no_send_page(mdev, bvec.bv_page, + bvec.bv_offset, bvec.bv_len, + bio_iter_last(bvec, iter) + ? 0 : MSG_MORE); if (err) return err; } @@ -1554,15 +1556,16 @@ static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio) static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio) { - struct bio_vec *bvec; - int i; + struct bio_vec bvec; + struct bvec_iter iter; + /* hint all but last page with MSG_MORE */ - bio_for_each_segment(bvec, bio, i) { + bio_for_each_segment(bvec, bio, iter) { int err; - err = _drbd_send_page(mdev, bvec->bv_page, - bvec->bv_offset, bvec->bv_len, - i == bio->bi_vcnt - 1 ? 0 : MSG_MORE); + err = _drbd_send_page(mdev, bvec.bv_page, + bvec.bv_offset, bvec.bv_len, + bio_iter_last(bvec, iter) ? 0 : MSG_MORE); if (err) return err; } diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 6fa6673b36b396..d073305ffd5e76 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1333,7 +1333,7 @@ int drbd_submit_peer_request(struct drbd_conf *mdev, goto fail; } /* > peer_req->i.sector, unless this is the first bio */ - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_bdev = mdev->ldev->backing_bdev; bio->bi_rw = rw; bio->bi_private = peer_req; @@ -1353,7 +1353,7 @@ int drbd_submit_peer_request(struct drbd_conf *mdev, dev_err(DEV, "bio_add_page failed for len=%u, " "bi_vcnt=0 (bi_sector=%llu)\n", - len, (unsigned long long)bio->bi_sector); + len, (uint64_t)bio->bi_iter.bi_sector); err = -ENOSPC; goto fail; } @@ -1595,9 +1595,10 @@ static int drbd_drain_block(struct drbd_conf *mdev, int data_size) static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, sector_t sector, int data_size) { - struct bio_vec *bvec; + struct bio_vec bvec; + struct bvec_iter iter; struct bio *bio; - int dgs, err, i, expect; + int dgs, err, expect; void *dig_in = mdev->tconn->int_dig_in; void *dig_vv = mdev->tconn->int_dig_vv; @@ -1615,13 +1616,13 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, mdev->recv_cnt += data_size>>9; bio = req->master_bio; - D_ASSERT(sector == bio->bi_sector); + D_ASSERT(sector == bio->bi_iter.bi_sector); - bio_for_each_segment(bvec, bio, i) { - void *mapped = kmap(bvec->bv_page) + bvec->bv_offset; - expect = min_t(int, data_size, bvec->bv_len); + bio_for_each_segment(bvec, bio, iter) { + void *mapped = kmap(bvec.bv_page) + bvec.bv_offset; + expect = min_t(int, data_size, bvec.bv_len); err = drbd_recv_all_warn(mdev->tconn, mapped, expect); - kunmap(bvec->bv_page); + kunmap(bvec.bv_page); if (err) return err; data_size -= expect; diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index fec7bef44994cf..104a040f24de74 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -77,8 +77,8 @@ static struct drbd_request *drbd_req_new(struct drbd_conf *mdev, req->epoch = 0; drbd_clear_interval(&req->i); - req->i.sector = bio_src->bi_sector; - req->i.size = bio_src->bi_size; + req->i.sector = bio_src->bi_iter.bi_sector; + req->i.size = bio_src->bi_iter.bi_size; req->i.local = true; req->i.waiting = false; @@ -1280,7 +1280,7 @@ void drbd_make_request(struct request_queue *q, struct bio *bio) /* * what we "blindly" assume: */ - D_ASSERT(IS_ALIGNED(bio->bi_size, 512)); + D_ASSERT(IS_ALIGNED(bio->bi_iter.bi_size, 512)); inc_ap_bio(mdev); __drbd_make_request(mdev, bio, start_time); diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 978cb1addc9884..28e15d91197af1 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -269,7 +269,7 @@ static inline void drbd_req_make_private_bio(struct drbd_request *req, struct bi /* Short lived temporary struct on the stack. * We could squirrel the error to be returned into - * bio->bi_size, or similar. But that would be too ugly. */ + * bio->bi_iter.bi_size, or similar. But that would be too ugly. */ struct bio_and_error { struct bio *bio; int error; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 891c0ecaa292c8..84d3175d493aae 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -313,8 +313,8 @@ void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio * { struct hash_desc desc; struct scatterlist sg; - struct bio_vec *bvec; - int i; + struct bio_vec bvec; + struct bvec_iter iter; desc.tfm = tfm; desc.flags = 0; @@ -322,8 +322,8 @@ void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio * sg_init_table(&sg, 1); crypto_hash_init(&desc); - bio_for_each_segment(bvec, bio, i) { - sg_set_page(&sg, bvec->bv_page, bvec->bv_len, bvec->bv_offset); + bio_for_each_segment(bvec, bio, iter) { + sg_set_page(&sg, bvec.bv_page, bvec.bv_len, bvec.bv_offset); crypto_hash_update(&desc, &sg, sg.length); } crypto_hash_final(&desc, digest); diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 000abe2f105c60..2023043ce7c0e9 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -2351,7 +2351,7 @@ static void rw_interrupt(void) /* Compute maximal contiguous buffer size. */ static int buffer_chain_size(void) { - struct bio_vec *bv; + struct bio_vec bv; int size; struct req_iterator iter; char *base; @@ -2360,10 +2360,10 @@ static int buffer_chain_size(void) size = 0; rq_for_each_segment(bv, current_req, iter) { - if (page_address(bv->bv_page) + bv->bv_offset != base + size) + if (page_address(bv.bv_page) + bv.bv_offset != base + size) break; - size += bv->bv_len; + size += bv.bv_len; } return size >> 9; @@ -2389,7 +2389,7 @@ static int transfer_size(int ssize, int max_sector, int max_size) static void copy_buffer(int ssize, int max_sector, int max_sector_2) { int remaining; /* number of transferred 512-byte sectors */ - struct bio_vec *bv; + struct bio_vec bv; char *buffer; char *dma_buffer; int size; @@ -2427,10 +2427,10 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) if (!remaining) break; - size = bv->bv_len; + size = bv.bv_len; SUPBOUND(size, remaining); - buffer = page_address(bv->bv_page) + bv->bv_offset; + buffer = page_address(bv.bv_page) + bv.bv_offset; if (dma_buffer + size > floppy_track_buffer + (max_buffer_sectors << 10) || dma_buffer < floppy_track_buffer) { @@ -3691,9 +3691,12 @@ static int floppy_open(struct block_device *bdev, fmode_t mode) if (!(mode & FMODE_NDELAY)) { if (mode & (FMODE_READ|FMODE_WRITE)) { UDRS->last_checked = 0; + clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags); check_disk_change(bdev); if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags)) goto out; + if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags)) + goto out; } res = -EROFS; if ((mode & FMODE_WRITE) && @@ -3746,17 +3749,29 @@ static unsigned int floppy_check_events(struct gendisk *disk, * a disk in the drive, and whether that disk is writable. */ -static void floppy_rb0_complete(struct bio *bio, int err) +struct rb0_cbdata { + int drive; + struct completion complete; +}; + +static void floppy_rb0_cb(struct bio *bio, int err) { - complete((struct completion *)bio->bi_private); + struct rb0_cbdata *cbdata = (struct rb0_cbdata *)bio->bi_private; + int drive = cbdata->drive; + + if (err) { + pr_info("floppy: error %d while reading block 0", err); + set_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags); + } + complete(&cbdata->complete); } -static int __floppy_read_block_0(struct block_device *bdev) +static int __floppy_read_block_0(struct block_device *bdev, int drive) { struct bio bio; struct bio_vec bio_vec; - struct completion complete; struct page *page; + struct rb0_cbdata cbdata; size_t size; page = alloc_page(GFP_NOIO); @@ -3769,23 +3784,26 @@ static int __floppy_read_block_0(struct block_device *bdev) if (!size) size = 1024; + cbdata.drive = drive; + bio_init(&bio); bio.bi_io_vec = &bio_vec; bio_vec.bv_page = page; bio_vec.bv_len = size; bio_vec.bv_offset = 0; bio.bi_vcnt = 1; - bio.bi_size = size; + bio.bi_iter.bi_size = size; bio.bi_bdev = bdev; - bio.bi_sector = 0; + bio.bi_iter.bi_sector = 0; bio.bi_flags = (1 << BIO_QUIET); - init_completion(&complete); - bio.bi_private = &complete; - bio.bi_end_io = floppy_rb0_complete; + bio.bi_private = &cbdata; + bio.bi_end_io = floppy_rb0_cb; submit_bio(READ, &bio); process_fd_request(); - wait_for_completion(&complete); + + init_completion(&cbdata.complete); + wait_for_completion(&cbdata.complete); __free_page(page); @@ -3827,7 +3845,7 @@ static int floppy_revalidate(struct gendisk *disk) UDRS->generation++; if (drive_no_geom(drive)) { /* auto-sensing */ - res = __floppy_read_block_0(opened_bdev[drive]); + res = __floppy_read_block_0(opened_bdev[drive], drive); } else { if (cf) poll_drive(false, FD_RAW_NEED_DISK); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index c8dac730524408..66e8c3b94ef354 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -288,9 +288,10 @@ static int lo_send(struct loop_device *lo, struct bio *bio, loff_t pos) { int (*do_lo_send)(struct loop_device *, struct bio_vec *, loff_t, struct page *page); - struct bio_vec *bvec; + struct bio_vec bvec; + struct bvec_iter iter; struct page *page = NULL; - int i, ret = 0; + int ret = 0; if (lo->transfer != transfer_none) { page = alloc_page(GFP_NOIO | __GFP_HIGHMEM); @@ -302,11 +303,11 @@ static int lo_send(struct loop_device *lo, struct bio *bio, loff_t pos) do_lo_send = do_lo_send_direct_write; } - bio_for_each_segment(bvec, bio, i) { - ret = do_lo_send(lo, bvec, pos, page); + bio_for_each_segment(bvec, bio, iter) { + ret = do_lo_send(lo, &bvec, pos, page); if (ret < 0) break; - pos += bvec->bv_len; + pos += bvec.bv_len; } if (page) { kunmap(page); @@ -392,20 +393,20 @@ do_lo_receive(struct loop_device *lo, static int lo_receive(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos) { - struct bio_vec *bvec; + struct bio_vec bvec; + struct bvec_iter iter; ssize_t s; - int i; - bio_for_each_segment(bvec, bio, i) { - s = do_lo_receive(lo, bvec, bsize, pos); + bio_for_each_segment(bvec, bio, iter) { + s = do_lo_receive(lo, &bvec, bsize, pos); if (s < 0) return s; - if (s != bvec->bv_len) { + if (s != bvec.bv_len) { zero_fill_bio(bio); break; } - pos += bvec->bv_len; + pos += bvec.bv_len; } return 0; } @@ -415,7 +416,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio) loff_t pos; int ret; - pos = ((loff_t) bio->bi_sector << 9) + lo->lo_offset; + pos = ((loff_t) bio->bi_iter.bi_sector << 9) + lo->lo_offset; if (bio_rw(bio) == WRITE) { struct file *file = lo->lo_backing_file; @@ -444,7 +445,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio) goto out; } ret = file->f_op->fallocate(file, mode, pos, - bio->bi_size); + bio->bi_iter.bi_size); if (unlikely(ret && ret != -EINVAL && ret != -EOPNOTSUPP)) ret = -EIO; @@ -798,7 +799,7 @@ static void loop_config_discard(struct loop_device *lo) /* * We use punch hole to reclaim the free space used by the - * image a.k.a. discard. However we do support discard if + * image a.k.a. discard. However we do not support discard if * encryption is enabled, because it may give an attacker * useful information. */ diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index 7bc363f1ee8224..eb59b124136690 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -915,7 +915,7 @@ static int mg_probe(struct platform_device *plat_dev) /* disk reset */ if (prv_data->dev_attr == MG_STORAGE_DEV) { - /* If POR seq. not yet finised, wait */ + /* If POR seq. not yet finished, wait */ err = mg_wait_rstout(host->rstout, MG_TMAX_RSTOUT); if (err) goto probe_err_3b; diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 050c71267f1463..516026954be62d 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -41,10 +41,31 @@ #include "mtip32xx.h" #define HW_CMD_SLOT_SZ (MTIP_MAX_COMMAND_SLOTS * 32) -#define HW_CMD_TBL_SZ (AHCI_CMD_TBL_HDR_SZ + (MTIP_MAX_SG * 16)) -#define HW_CMD_TBL_AR_SZ (HW_CMD_TBL_SZ * MTIP_MAX_COMMAND_SLOTS) -#define HW_PORT_PRIV_DMA_SZ \ - (HW_CMD_SLOT_SZ + HW_CMD_TBL_AR_SZ + AHCI_RX_FIS_SZ) + +/* DMA region containing RX Fis, Identify, RLE10, and SMART buffers */ +#define AHCI_RX_FIS_SZ 0x100 +#define AHCI_RX_FIS_OFFSET 0x0 +#define AHCI_IDFY_SZ ATA_SECT_SIZE +#define AHCI_IDFY_OFFSET 0x400 +#define AHCI_SECTBUF_SZ ATA_SECT_SIZE +#define AHCI_SECTBUF_OFFSET 0x800 +#define AHCI_SMARTBUF_SZ ATA_SECT_SIZE +#define AHCI_SMARTBUF_OFFSET 0xC00 +/* 0x100 + 0x200 + 0x200 + 0x200 is smaller than 4k but we pad it out */ +#define BLOCK_DMA_ALLOC_SZ 4096 + +/* DMA region containing command table (should be 8192 bytes) */ +#define AHCI_CMD_SLOT_SZ sizeof(struct mtip_cmd_hdr) +#define AHCI_CMD_TBL_SZ (MTIP_MAX_COMMAND_SLOTS * AHCI_CMD_SLOT_SZ) +#define AHCI_CMD_TBL_OFFSET 0x0 + +/* DMA region per command (contains header and SGL) */ +#define AHCI_CMD_TBL_HDR_SZ 0x80 +#define AHCI_CMD_TBL_HDR_OFFSET 0x0 +#define AHCI_CMD_TBL_SGL_SZ (MTIP_MAX_SG * sizeof(struct mtip_cmd_sg)) +#define AHCI_CMD_TBL_SGL_OFFSET AHCI_CMD_TBL_HDR_SZ +#define CMD_DMA_ALLOC_SZ (AHCI_CMD_TBL_SGL_SZ + AHCI_CMD_TBL_HDR_SZ) + #define HOST_CAP_NZDMA (1 << 19) #define HOST_HSORG 0xFC @@ -899,8 +920,9 @@ static void mtip_handle_tfe(struct driver_data *dd) fail_reason = "thermal shutdown"; } if (buf[288] == 0xBF) { + set_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag); dev_info(&dd->pdev->dev, - "Drive indicates rebuild has failed.\n"); + "Drive indicates rebuild has failed. Secure erase required.\n"); fail_all_ncq_cmds = 1; fail_reason = "rebuild failed"; } @@ -1566,6 +1588,12 @@ static int mtip_get_identify(struct mtip_port *port, void __user *user_buffer) } #endif + /* Check security locked state */ + if (port->identify[128] & 0x4) + set_bit(MTIP_DDF_SEC_LOCK_BIT, &port->dd->dd_flag); + else + clear_bit(MTIP_DDF_SEC_LOCK_BIT, &port->dd->dd_flag); + #ifdef MTIP_TRIM /* Disabling TRIM support temporarily */ /* Demux ID.DRAT & ID.RZAT to determine trim support */ if (port->identify[69] & (1 << 14) && port->identify[69] & (1 << 5)) @@ -1887,6 +1915,10 @@ static void mtip_dump_identify(struct mtip_port *port) strlcpy(cbuf, (char *)(port->identify+27), 41); dev_info(&port->dd->pdev->dev, "Model: %s\n", cbuf); + dev_info(&port->dd->pdev->dev, "Security: %04x %s\n", + port->identify[128], + port->identify[128] & 0x4 ? "(LOCKED)" : ""); + if (mtip_hw_get_capacity(port->dd, §ors)) dev_info(&port->dd->pdev->dev, "Capacity: %llu sectors (%llu MB)\n", @@ -3312,6 +3344,118 @@ static int mtip_service_thread(void *data) return 0; } +/* + * DMA region teardown + * + * @dd Pointer to driver_data structure + * + * return value + * None + */ +static void mtip_dma_free(struct driver_data *dd) +{ + int i; + struct mtip_port *port = dd->port; + + if (port->block1) + dmam_free_coherent(&dd->pdev->dev, BLOCK_DMA_ALLOC_SZ, + port->block1, port->block1_dma); + + if (port->command_list) { + dmam_free_coherent(&dd->pdev->dev, AHCI_CMD_TBL_SZ, + port->command_list, port->command_list_dma); + } + + for (i = 0; i < MTIP_MAX_COMMAND_SLOTS; i++) { + if (port->commands[i].command) + dmam_free_coherent(&dd->pdev->dev, CMD_DMA_ALLOC_SZ, + port->commands[i].command, + port->commands[i].command_dma); + } +} + +/* + * DMA region setup + * + * @dd Pointer to driver_data structure + * + * return value + * -ENOMEM Not enough free DMA region space to initialize driver + */ +static int mtip_dma_alloc(struct driver_data *dd) +{ + struct mtip_port *port = dd->port; + int i, rv = 0; + u32 host_cap_64 = readl(dd->mmio + HOST_CAP) & HOST_CAP_64; + + /* Allocate dma memory for RX Fis, Identify, and Sector Bufffer */ + port->block1 = + dmam_alloc_coherent(&dd->pdev->dev, BLOCK_DMA_ALLOC_SZ, + &port->block1_dma, GFP_KERNEL); + if (!port->block1) + return -ENOMEM; + memset(port->block1, 0, BLOCK_DMA_ALLOC_SZ); + + /* Allocate dma memory for command list */ + port->command_list = + dmam_alloc_coherent(&dd->pdev->dev, AHCI_CMD_TBL_SZ, + &port->command_list_dma, GFP_KERNEL); + if (!port->command_list) { + dmam_free_coherent(&dd->pdev->dev, BLOCK_DMA_ALLOC_SZ, + port->block1, port->block1_dma); + port->block1 = NULL; + port->block1_dma = 0; + return -ENOMEM; + } + memset(port->command_list, 0, AHCI_CMD_TBL_SZ); + + /* Setup all pointers into first DMA region */ + port->rxfis = port->block1 + AHCI_RX_FIS_OFFSET; + port->rxfis_dma = port->block1_dma + AHCI_RX_FIS_OFFSET; + port->identify = port->block1 + AHCI_IDFY_OFFSET; + port->identify_dma = port->block1_dma + AHCI_IDFY_OFFSET; + port->log_buf = port->block1 + AHCI_SECTBUF_OFFSET; + port->log_buf_dma = port->block1_dma + AHCI_SECTBUF_OFFSET; + port->smart_buf = port->block1 + AHCI_SMARTBUF_OFFSET; + port->smart_buf_dma = port->block1_dma + AHCI_SMARTBUF_OFFSET; + + /* Setup per command SGL DMA region */ + + /* Point the command headers at the command tables */ + for (i = 0; i < MTIP_MAX_COMMAND_SLOTS; i++) { + port->commands[i].command = + dmam_alloc_coherent(&dd->pdev->dev, CMD_DMA_ALLOC_SZ, + &port->commands[i].command_dma, GFP_KERNEL); + if (!port->commands[i].command) { + rv = -ENOMEM; + mtip_dma_free(dd); + return rv; + } + memset(port->commands[i].command, 0, CMD_DMA_ALLOC_SZ); + + port->commands[i].command_header = port->command_list + + (sizeof(struct mtip_cmd_hdr) * i); + port->commands[i].command_header_dma = + dd->port->command_list_dma + + (sizeof(struct mtip_cmd_hdr) * i); + + if (host_cap_64) + port->commands[i].command_header->ctbau = + __force_bit2int cpu_to_le32( + (port->commands[i].command_dma >> 16) >> 16); + + port->commands[i].command_header->ctba = + __force_bit2int cpu_to_le32( + port->commands[i].command_dma & 0xFFFFFFFF); + + sg_init_table(port->commands[i].sg, MTIP_MAX_SG); + + /* Mark command as currently inactive */ + atomic_set(&dd->port->commands[i].active, 0); + } + return 0; +} + /* * Called once for each card. * @@ -3370,83 +3514,10 @@ static int mtip_hw_init(struct driver_data *dd) dd->port->mmio = dd->mmio + PORT_OFFSET; dd->port->dd = dd; - /* Allocate memory for the command list. */ - dd->port->command_list = - dmam_alloc_coherent(&dd->pdev->dev, - HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4), - &dd->port->command_list_dma, - GFP_KERNEL); - if (!dd->port->command_list) { - dev_err(&dd->pdev->dev, - "Memory allocation: command list\n"); - rv = -ENOMEM; + /* DMA allocations */ + rv = mtip_dma_alloc(dd); + if (rv < 0) goto out1; - } - - /* Clear the memory we have allocated. */ - memset(dd->port->command_list, - 0, - HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4)); - - /* Setup the addresse of the RX FIS. */ - dd->port->rxfis = dd->port->command_list + HW_CMD_SLOT_SZ; - dd->port->rxfis_dma = dd->port->command_list_dma + HW_CMD_SLOT_SZ; - - /* Setup the address of the command tables. */ - dd->port->command_table = dd->port->rxfis + AHCI_RX_FIS_SZ; - dd->port->command_tbl_dma = dd->port->rxfis_dma + AHCI_RX_FIS_SZ; - - /* Setup the address of the identify data. */ - dd->port->identify = dd->port->command_table + - HW_CMD_TBL_AR_SZ; - dd->port->identify_dma = dd->port->command_tbl_dma + - HW_CMD_TBL_AR_SZ; - - /* Setup the address of the sector buffer - for some non-ncq cmds */ - dd->port->sector_buffer = (void *) dd->port->identify + ATA_SECT_SIZE; - dd->port->sector_buffer_dma = dd->port->identify_dma + ATA_SECT_SIZE; - - /* Setup the address of the log buf - for read log command */ - dd->port->log_buf = (void *)dd->port->sector_buffer + ATA_SECT_SIZE; - dd->port->log_buf_dma = dd->port->sector_buffer_dma + ATA_SECT_SIZE; - - /* Setup the address of the smart buf - for smart read data command */ - dd->port->smart_buf = (void *)dd->port->log_buf + ATA_SECT_SIZE; - dd->port->smart_buf_dma = dd->port->log_buf_dma + ATA_SECT_SIZE; - - - /* Point the command headers at the command tables. */ - for (i = 0; i < num_command_slots; i++) { - dd->port->commands[i].command_header = - dd->port->command_list + - (sizeof(struct mtip_cmd_hdr) * i); - dd->port->commands[i].command_header_dma = - dd->port->command_list_dma + - (sizeof(struct mtip_cmd_hdr) * i); - - dd->port->commands[i].command = - dd->port->command_table + (HW_CMD_TBL_SZ * i); - dd->port->commands[i].command_dma = - dd->port->command_tbl_dma + (HW_CMD_TBL_SZ * i); - - if (readl(dd->mmio + HOST_CAP) & HOST_CAP_64) - dd->port->commands[i].command_header->ctbau = - __force_bit2int cpu_to_le32( - (dd->port->commands[i].command_dma >> 16) >> 16); - dd->port->commands[i].command_header->ctba = - __force_bit2int cpu_to_le32( - dd->port->commands[i].command_dma & 0xFFFFFFFF); - - /* - * If this is not done, a bug is reported by the stock - * FC11 i386. Due to the fact that it has lots of kernel - * debugging enabled. - */ - sg_init_table(dd->port->commands[i].sg, MTIP_MAX_SG); - - /* Mark all commands as currently inactive.*/ - atomic_set(&dd->port->commands[i].active, 0); - } /* Setup the pointers to the extended s_active and CI registers. */ for (i = 0; i < dd->slot_groups; i++) { @@ -3594,12 +3665,8 @@ static int mtip_hw_init(struct driver_data *dd) out2: mtip_deinit_port(dd->port); + mtip_dma_free(dd); - /* Free the command/command header memory. */ - dmam_free_coherent(&dd->pdev->dev, - HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4), - dd->port->command_list, - dd->port->command_list_dma); out1: /* Free the memory allocated for the for structure. */ kfree(dd->port); @@ -3622,7 +3689,8 @@ static int mtip_hw_exit(struct driver_data *dd) * saves its state. */ if (!dd->sr) { - if (!test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag)) + if (!test_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags) && + !test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag)) if (mtip_standby_immediate(dd->port)) dev_warn(&dd->pdev->dev, "STANDBY IMMEDIATE failed\n"); @@ -3641,11 +3709,9 @@ static int mtip_hw_exit(struct driver_data *dd) irq_set_affinity_hint(dd->pdev->irq, NULL); devm_free_irq(&dd->pdev->dev, dd->pdev->irq, dd); - /* Free the command/command header memory. */ - dmam_free_coherent(&dd->pdev->dev, - HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4), - dd->port->command_list, - dd->port->command_list_dma); + /* Free dma regions */ + mtip_dma_free(dd); + /* Free the memory allocated for the for structure. */ kfree(dd->port); dd->port = NULL; @@ -3962,8 +4028,9 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) { struct driver_data *dd = queue->queuedata; struct scatterlist *sg; - struct bio_vec *bvec; - int i, nents = 0; + struct bio_vec bvec; + struct bvec_iter iter; + int nents = 0; int tag = 0, unaligned = 0; if (unlikely(dd->dd_flag & MTIP_DDF_STOP_IO)) { @@ -3993,7 +4060,7 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) } if (unlikely(bio->bi_rw & REQ_DISCARD)) { - bio_endio(bio, mtip_send_trim(dd, bio->bi_sector, + bio_endio(bio, mtip_send_trim(dd, bio->bi_iter.bi_sector, bio_sectors(bio))); return; } @@ -4006,7 +4073,8 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) if (bio_data_dir(bio) == WRITE && bio_sectors(bio) <= 64 && dd->unal_qdepth) { - if (bio->bi_sector % 8 != 0) /* Unaligned on 4k boundaries */ + if (bio->bi_iter.bi_sector % 8 != 0) + /* Unaligned on 4k boundaries */ unaligned = 1; else if (bio_sectors(bio) % 8 != 0) /* Aligned but not 4k/8k */ unaligned = 1; @@ -4025,17 +4093,17 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) } /* Create the scatter list for this bio. */ - bio_for_each_segment(bvec, bio, i) { + bio_for_each_segment(bvec, bio, iter) { sg_set_page(&sg[nents], - bvec->bv_page, - bvec->bv_len, - bvec->bv_offset); + bvec.bv_page, + bvec.bv_len, + bvec.bv_offset); nents++; } /* Issue the read/write. */ mtip_hw_submit_io(dd, - bio->bi_sector, + bio->bi_iter.bi_sector, bio_sectors(bio), nents, tag, diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index 9be7a1582ad347..b52e9a6d6aad6d 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h @@ -69,7 +69,7 @@ * Maximum number of scatter gather entries * a single command may have. */ -#define MTIP_MAX_SG 128 +#define MTIP_MAX_SG 504 /* * Maximum number of slot groups (Command Issue & s_active registers) @@ -92,7 +92,7 @@ /* Driver name and version strings */ #define MTIP_DRV_NAME "mtip32xx" -#define MTIP_DRV_VERSION "1.2.6os3" +#define MTIP_DRV_VERSION "1.3.0" /* Maximum number of minor device numbers per device. */ #define MTIP_MAX_MINORS 16 @@ -391,15 +391,13 @@ struct mtip_port { */ dma_addr_t rxfis_dma; /* - * Pointer to the beginning of the command table memory as used - * by the driver. + * Pointer to the DMA region for RX Fis, Identify, RLE10, and SMART */ - void *command_table; + void *block1; /* - * Pointer to the beginning of the command table memory as used - * by the DMA. + * DMA address of region for RX Fis, Identify, RLE10, and SMART */ - dma_addr_t command_tbl_dma; + dma_addr_t block1_dma; /* * Pointer to the beginning of the identify data memory as used * by the driver. diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 2dc3b5153f0d82..55298db36b2d61 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -271,18 +271,18 @@ static int nbd_send_req(struct nbd_device *nbd, struct request *req) if (nbd_cmd(req) == NBD_CMD_WRITE) { struct req_iterator iter; - struct bio_vec *bvec; + struct bio_vec bvec; /* * we are really probing at internals to determine * whether to set MSG_MORE or not... */ rq_for_each_segment(bvec, req, iter) { flags = 0; - if (!rq_iter_last(req, iter)) + if (!rq_iter_last(bvec, iter)) flags = MSG_MORE; dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n", - nbd->disk->disk_name, req, bvec->bv_len); - result = sock_send_bvec(nbd, bvec, flags); + nbd->disk->disk_name, req, bvec.bv_len); + result = sock_send_bvec(nbd, &bvec, flags); if (result <= 0) { dev_err(disk_to_dev(nbd->disk), "Send data failed (result %d)\n", @@ -378,10 +378,10 @@ static struct request *nbd_read_stat(struct nbd_device *nbd) nbd->disk->disk_name, req); if (nbd_cmd(req) == NBD_CMD_READ) { struct req_iterator iter; - struct bio_vec *bvec; + struct bio_vec bvec; rq_for_each_segment(bvec, req, iter) { - result = sock_recv_bvec(nbd, bvec); + result = sock_recv_bvec(nbd, &bvec); if (result <= 0) { dev_err(disk_to_dev(nbd->disk), "Receive data failed (result %d)\n", result); @@ -389,7 +389,7 @@ static struct request *nbd_read_stat(struct nbd_device *nbd) return req; } dprintk(DBG_RX, "%s: request %p: got %d bytes data\n", - nbd->disk->disk_name, req, bvec->bv_len); + nbd->disk->disk_name, req, bvec.bv_len); } } return req; diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index 83a598ebb65a4a..091b9ea14feb58 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -60,7 +60,9 @@ enum { NULL_IRQ_NONE = 0, NULL_IRQ_SOFTIRQ = 1, NULL_IRQ_TIMER = 2, +}; +enum { NULL_Q_BIO = 0, NULL_Q_RQ = 1, NULL_Q_MQ = 2, @@ -172,18 +174,20 @@ static struct nullb_cmd *alloc_cmd(struct nullb_queue *nq, int can_wait) static void end_cmd(struct nullb_cmd *cmd) { - if (cmd->rq) { - if (queue_mode == NULL_Q_MQ) - blk_mq_end_io(cmd->rq, 0); - else { - INIT_LIST_HEAD(&cmd->rq->queuelist); - blk_end_request_all(cmd->rq, 0); - } - } else if (cmd->bio) + switch (queue_mode) { + case NULL_Q_MQ: + blk_mq_end_io(cmd->rq, 0); + return; + case NULL_Q_RQ: + INIT_LIST_HEAD(&cmd->rq->queuelist); + blk_end_request_all(cmd->rq, 0); + break; + case NULL_Q_BIO: bio_endio(cmd->bio, 0); + break; + } - if (queue_mode != NULL_Q_MQ) - free_cmd(cmd); + free_cmd(cmd); } static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer) @@ -195,6 +199,7 @@ static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer) cq = &per_cpu(completion_queues, smp_processor_id()); while ((entry = llist_del_all(&cq->list)) != NULL) { + entry = llist_reverse_order(entry); do { cmd = container_of(entry, struct nullb_cmd, ll_list); end_cmd(cmd); @@ -221,61 +226,31 @@ static void null_cmd_end_timer(struct nullb_cmd *cmd) static void null_softirq_done_fn(struct request *rq) { - blk_end_request_all(rq, 0); -} - -#ifdef CONFIG_SMP - -static void null_ipi_cmd_end_io(void *data) -{ - struct completion_queue *cq; - struct llist_node *entry, *next; - struct nullb_cmd *cmd; - - cq = &per_cpu(completion_queues, smp_processor_id()); - - entry = llist_del_all(&cq->list); - - while (entry) { - next = entry->next; - cmd = llist_entry(entry, struct nullb_cmd, ll_list); - end_cmd(cmd); - entry = next; - } + end_cmd(rq->special); } -static void null_cmd_end_ipi(struct nullb_cmd *cmd) -{ - struct call_single_data *data = &cmd->csd; - int cpu = get_cpu(); - struct completion_queue *cq = &per_cpu(completion_queues, cpu); - - cmd->ll_list.next = NULL; - - if (llist_add(&cmd->ll_list, &cq->list)) { - data->func = null_ipi_cmd_end_io; - data->flags = 0; - __smp_call_function_single(cpu, data, 0); - } - - put_cpu(); -} - -#endif /* CONFIG_SMP */ - static inline void null_handle_cmd(struct nullb_cmd *cmd) { /* Complete IO by inline, softirq or timer */ switch (irqmode) { - case NULL_IRQ_NONE: - end_cmd(cmd); - break; case NULL_IRQ_SOFTIRQ: -#ifdef CONFIG_SMP - null_cmd_end_ipi(cmd); -#else + switch (queue_mode) { + case NULL_Q_MQ: + blk_mq_complete_request(cmd->rq); + break; + case NULL_Q_RQ: + blk_complete_request(cmd->rq); + break; + case NULL_Q_BIO: + /* + * XXX: no proper submitting cpu information available. + */ + end_cmd(cmd); + break; + } + break; + case NULL_IRQ_NONE: end_cmd(cmd); -#endif break; case NULL_IRQ_TIMER: null_cmd_end_timer(cmd); @@ -411,6 +386,7 @@ static struct blk_mq_ops null_mq_ops = { .queue_rq = null_queue_rq, .map_queue = blk_mq_map_queue, .init_hctx = null_init_hctx, + .complete = null_softirq_done_fn, }; static struct blk_mq_reg null_mq_reg = { @@ -609,13 +585,11 @@ static int __init null_init(void) { unsigned int i; -#if !defined(CONFIG_SMP) - if (irqmode == NULL_IRQ_SOFTIRQ) { - pr_warn("null_blk: softirq completions not available.\n"); - pr_warn("null_blk: using direct completions.\n"); - irqmode = NULL_IRQ_NONE; + if (bs > PAGE_SIZE) { + pr_warn("null_blk: invalid block size\n"); + pr_warn("null_blk: defaults block size to %lu\n", PAGE_SIZE); + bs = PAGE_SIZE; } -#endif if (queue_mode == NULL_Q_MQ && use_per_node_hctx) { if (submit_queues < nr_online_nodes) { diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 26d03fa0bf2669..51824d1f23ea53 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -46,7 +46,6 @@ #define NVME_Q_DEPTH 1024 #define SQ_SIZE(depth) (depth * sizeof(struct nvme_command)) #define CQ_SIZE(depth) (depth * sizeof(struct nvme_completion)) -#define NVME_MINORS 64 #define ADMIN_TIMEOUT (60 * HZ) static int nvme_major; @@ -58,6 +57,17 @@ module_param(use_threaded_interrupts, int, 0); static DEFINE_SPINLOCK(dev_list_lock); static LIST_HEAD(dev_list); static struct task_struct *nvme_thread; +static struct workqueue_struct *nvme_workq; + +static void nvme_reset_failed_dev(struct work_struct *ws); + +struct async_cmd_info { + struct kthread_work work; + struct kthread_worker *worker; + u32 result; + int status; + void *ctx; +}; /* * An NVM Express queue. Each device has at least two (one for admin @@ -66,6 +76,7 @@ static struct task_struct *nvme_thread; struct nvme_queue { struct device *q_dmadev; struct nvme_dev *dev; + char irqname[24]; /* nvme4294967295-65535\0 */ spinlock_t q_lock; struct nvme_command *sq_cmds; volatile struct nvme_completion *cqes; @@ -80,9 +91,11 @@ struct nvme_queue { u16 sq_head; u16 sq_tail; u16 cq_head; + u16 qid; u8 cq_phase; u8 cqe_seen; u8 q_suspended; + struct async_cmd_info cmdinfo; unsigned long cmdid_data[]; }; @@ -97,6 +110,7 @@ static inline void _nvme_check_size(void) BUILD_BUG_ON(sizeof(struct nvme_delete_queue) != 64); BUILD_BUG_ON(sizeof(struct nvme_features) != 64); BUILD_BUG_ON(sizeof(struct nvme_format_cmd) != 64); + BUILD_BUG_ON(sizeof(struct nvme_abort_cmd) != 64); BUILD_BUG_ON(sizeof(struct nvme_command) != 64); BUILD_BUG_ON(sizeof(struct nvme_id_ctrl) != 4096); BUILD_BUG_ON(sizeof(struct nvme_id_ns) != 4096); @@ -111,6 +125,7 @@ struct nvme_cmd_info { nvme_completion_fn fn; void *ctx; unsigned long timeout; + int aborted; }; static struct nvme_cmd_info *nvme_cmd_info(struct nvme_queue *nvmeq) @@ -154,6 +169,7 @@ static int alloc_cmdid(struct nvme_queue *nvmeq, void *ctx, info[cmdid].fn = handler; info[cmdid].ctx = ctx; info[cmdid].timeout = jiffies + timeout; + info[cmdid].aborted = 0; return cmdid; } @@ -172,6 +188,7 @@ static int alloc_cmdid_killable(struct nvme_queue *nvmeq, void *ctx, #define CMD_CTX_COMPLETED (0x310 + CMD_CTX_BASE) #define CMD_CTX_INVALID (0x314 + CMD_CTX_BASE) #define CMD_CTX_FLUSH (0x318 + CMD_CTX_BASE) +#define CMD_CTX_ABORT (0x31C + CMD_CTX_BASE) static void special_completion(struct nvme_dev *dev, void *ctx, struct nvme_completion *cqe) @@ -180,6 +197,10 @@ static void special_completion(struct nvme_dev *dev, void *ctx, return; if (ctx == CMD_CTX_FLUSH) return; + if (ctx == CMD_CTX_ABORT) { + ++dev->abort_limit; + return; + } if (ctx == CMD_CTX_COMPLETED) { dev_warn(&dev->pci_dev->dev, "completed id %d twice on queue %d\n", @@ -196,6 +217,15 @@ static void special_completion(struct nvme_dev *dev, void *ctx, dev_warn(&dev->pci_dev->dev, "Unknown special completion %p\n", ctx); } +static void async_completion(struct nvme_dev *dev, void *ctx, + struct nvme_completion *cqe) +{ + struct async_cmd_info *cmdinfo = ctx; + cmdinfo->result = le32_to_cpup(&cqe->result); + cmdinfo->status = le16_to_cpup(&cqe->status) >> 1; + queue_kthread_work(cmdinfo->worker, &cmdinfo->work); +} + /* * Called with local interrupts disabled and the q_lock held. May not sleep. */ @@ -441,104 +471,19 @@ int nvme_setup_prps(struct nvme_dev *dev, struct nvme_common_command *cmd, return total_len; } -struct nvme_bio_pair { - struct bio b1, b2, *parent; - struct bio_vec *bv1, *bv2; - int err; - atomic_t cnt; -}; - -static void nvme_bio_pair_endio(struct bio *bio, int err) -{ - struct nvme_bio_pair *bp = bio->bi_private; - - if (err) - bp->err = err; - - if (atomic_dec_and_test(&bp->cnt)) { - bio_endio(bp->parent, bp->err); - kfree(bp->bv1); - kfree(bp->bv2); - kfree(bp); - } -} - -static struct nvme_bio_pair *nvme_bio_split(struct bio *bio, int idx, - int len, int offset) -{ - struct nvme_bio_pair *bp; - - BUG_ON(len > bio->bi_size); - BUG_ON(idx > bio->bi_vcnt); - - bp = kmalloc(sizeof(*bp), GFP_ATOMIC); - if (!bp) - return NULL; - bp->err = 0; - - bp->b1 = *bio; - bp->b2 = *bio; - - bp->b1.bi_size = len; - bp->b2.bi_size -= len; - bp->b1.bi_vcnt = idx; - bp->b2.bi_idx = idx; - bp->b2.bi_sector += len >> 9; - - if (offset) { - bp->bv1 = kmalloc(bio->bi_max_vecs * sizeof(struct bio_vec), - GFP_ATOMIC); - if (!bp->bv1) - goto split_fail_1; - - bp->bv2 = kmalloc(bio->bi_max_vecs * sizeof(struct bio_vec), - GFP_ATOMIC); - if (!bp->bv2) - goto split_fail_2; - - memcpy(bp->bv1, bio->bi_io_vec, - bio->bi_max_vecs * sizeof(struct bio_vec)); - memcpy(bp->bv2, bio->bi_io_vec, - bio->bi_max_vecs * sizeof(struct bio_vec)); - - bp->b1.bi_io_vec = bp->bv1; - bp->b2.bi_io_vec = bp->bv2; - bp->b2.bi_io_vec[idx].bv_offset += offset; - bp->b2.bi_io_vec[idx].bv_len -= offset; - bp->b1.bi_io_vec[idx].bv_len = offset; - bp->b1.bi_vcnt++; - } else - bp->bv1 = bp->bv2 = NULL; - - bp->b1.bi_private = bp; - bp->b2.bi_private = bp; - - bp->b1.bi_end_io = nvme_bio_pair_endio; - bp->b2.bi_end_io = nvme_bio_pair_endio; - - bp->parent = bio; - atomic_set(&bp->cnt, 2); - - return bp; - - split_fail_2: - kfree(bp->bv1); - split_fail_1: - kfree(bp); - return NULL; -} - static int nvme_split_and_submit(struct bio *bio, struct nvme_queue *nvmeq, - int idx, int len, int offset) + int len) { - struct nvme_bio_pair *bp = nvme_bio_split(bio, idx, len, offset); - if (!bp) + struct bio *split = bio_split(bio, len >> 9, GFP_ATOMIC, NULL); + if (!split) return -ENOMEM; + bio_chain(split, bio); + if (bio_list_empty(&nvmeq->sq_cong)) add_wait_queue(&nvmeq->sq_full, &nvmeq->sq_cong_wait); - bio_list_add(&nvmeq->sq_cong, &bp->b1); - bio_list_add(&nvmeq->sq_cong, &bp->b2); + bio_list_add(&nvmeq->sq_cong, split); + bio_list_add(&nvmeq->sq_cong, bio); return 0; } @@ -550,41 +495,44 @@ static int nvme_split_and_submit(struct bio *bio, struct nvme_queue *nvmeq, static int nvme_map_bio(struct nvme_queue *nvmeq, struct nvme_iod *iod, struct bio *bio, enum dma_data_direction dma_dir, int psegs) { - struct bio_vec *bvec, *bvprv = NULL; + struct bio_vec bvec, bvprv; + struct bvec_iter iter; struct scatterlist *sg = NULL; - int i, length = 0, nsegs = 0, split_len = bio->bi_size; + int length = 0, nsegs = 0, split_len = bio->bi_iter.bi_size; + int first = 1; if (nvmeq->dev->stripe_size) split_len = nvmeq->dev->stripe_size - - ((bio->bi_sector << 9) & (nvmeq->dev->stripe_size - 1)); + ((bio->bi_iter.bi_sector << 9) & + (nvmeq->dev->stripe_size - 1)); sg_init_table(iod->sg, psegs); - bio_for_each_segment(bvec, bio, i) { - if (bvprv && BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) { - sg->length += bvec->bv_len; + bio_for_each_segment(bvec, bio, iter) { + if (!first && BIOVEC_PHYS_MERGEABLE(&bvprv, &bvec)) { + sg->length += bvec.bv_len; } else { - if (bvprv && BIOVEC_NOT_VIRT_MERGEABLE(bvprv, bvec)) - return nvme_split_and_submit(bio, nvmeq, i, - length, 0); + if (!first && BIOVEC_NOT_VIRT_MERGEABLE(&bvprv, &bvec)) + return nvme_split_and_submit(bio, nvmeq, + length); sg = sg ? sg + 1 : iod->sg; - sg_set_page(sg, bvec->bv_page, bvec->bv_len, - bvec->bv_offset); + sg_set_page(sg, bvec.bv_page, + bvec.bv_len, bvec.bv_offset); nsegs++; } - if (split_len - length < bvec->bv_len) - return nvme_split_and_submit(bio, nvmeq, i, split_len, - split_len - length); - length += bvec->bv_len; + if (split_len - length < bvec.bv_len) + return nvme_split_and_submit(bio, nvmeq, split_len); + length += bvec.bv_len; bvprv = bvec; + first = 0; } iod->nents = nsegs; sg_mark_end(sg); if (dma_map_sg(nvmeq->q_dmadev, iod->sg, iod->nents, dma_dir) == 0) return -ENOMEM; - BUG_ON(length != bio->bi_size); + BUG_ON(length != bio->bi_iter.bi_size); return length; } @@ -608,8 +556,8 @@ static int nvme_submit_discard(struct nvme_queue *nvmeq, struct nvme_ns *ns, iod->npages = 0; range->cattr = cpu_to_le32(0); - range->nlb = cpu_to_le32(bio->bi_size >> ns->lba_shift); - range->slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_sector)); + range->nlb = cpu_to_le32(bio->bi_iter.bi_size >> ns->lba_shift); + range->slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_iter.bi_sector)); memset(cmnd, 0, sizeof(*cmnd)); cmnd->dsm.opcode = nvme_cmd_dsm; @@ -674,7 +622,7 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns, } result = -ENOMEM; - iod = nvme_alloc_iod(psegs, bio->bi_size, GFP_ATOMIC); + iod = nvme_alloc_iod(psegs, bio->bi_iter.bi_size, GFP_ATOMIC); if (!iod) goto nomem; iod->private = bio; @@ -723,7 +671,7 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns, cmnd->rw.nsid = cpu_to_le32(ns->ns_id); length = nvme_setup_prps(nvmeq->dev, &cmnd->common, iod, length, GFP_ATOMIC); - cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_sector)); + cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_iter.bi_sector)); cmnd->rw.length = cpu_to_le16((length >> ns->lba_shift) - 1); cmnd->rw.control = cpu_to_le16(control); cmnd->rw.dsmgmt = cpu_to_le32(dsmgmt); @@ -775,7 +723,7 @@ static int nvme_process_cq(struct nvme_queue *nvmeq) if (head == nvmeq->cq_head && phase == nvmeq->cq_phase) return 0; - writel(head, nvmeq->q_db + (1 << nvmeq->dev->db_stride)); + writel(head, nvmeq->q_db + nvmeq->dev->db_stride); nvmeq->cq_head = head; nvmeq->cq_phase = phase; @@ -886,12 +834,34 @@ int nvme_submit_sync_cmd(struct nvme_queue *nvmeq, struct nvme_command *cmd, return cmdinfo.status; } +static int nvme_submit_async_cmd(struct nvme_queue *nvmeq, + struct nvme_command *cmd, + struct async_cmd_info *cmdinfo, unsigned timeout) +{ + int cmdid; + + cmdid = alloc_cmdid_killable(nvmeq, cmdinfo, async_completion, timeout); + if (cmdid < 0) + return cmdid; + cmdinfo->status = -EINTR; + cmd->common.command_id = cmdid; + nvme_submit_cmd(nvmeq, cmd); + return 0; +} + int nvme_submit_admin_cmd(struct nvme_dev *dev, struct nvme_command *cmd, u32 *result) { return nvme_submit_sync_cmd(dev->queues[0], cmd, result, ADMIN_TIMEOUT); } +static int nvme_submit_admin_cmd_async(struct nvme_dev *dev, + struct nvme_command *cmd, struct async_cmd_info *cmdinfo) +{ + return nvme_submit_async_cmd(dev->queues[0], cmd, cmdinfo, + ADMIN_TIMEOUT); +} + static int adapter_delete_queue(struct nvme_dev *dev, u8 opcode, u16 id) { int status; @@ -1001,6 +971,56 @@ int nvme_set_features(struct nvme_dev *dev, unsigned fid, unsigned dword11, return nvme_submit_admin_cmd(dev, &c, result); } +/** + * nvme_abort_cmd - Attempt aborting a command + * @cmdid: Command id of a timed out IO + * @queue: The queue with timed out IO + * + * Schedule controller reset if the command was already aborted once before and + * still hasn't been returned to the driver, or if this is the admin queue. + */ +static void nvme_abort_cmd(int cmdid, struct nvme_queue *nvmeq) +{ + int a_cmdid; + struct nvme_command cmd; + struct nvme_dev *dev = nvmeq->dev; + struct nvme_cmd_info *info = nvme_cmd_info(nvmeq); + + if (!nvmeq->qid || info[cmdid].aborted) { + if (work_busy(&dev->reset_work)) + return; + list_del_init(&dev->node); + dev_warn(&dev->pci_dev->dev, + "I/O %d QID %d timeout, reset controller\n", cmdid, + nvmeq->qid); + PREPARE_WORK(&dev->reset_work, nvme_reset_failed_dev); + queue_work(nvme_workq, &dev->reset_work); + return; + } + + if (!dev->abort_limit) + return; + + a_cmdid = alloc_cmdid(dev->queues[0], CMD_CTX_ABORT, special_completion, + ADMIN_TIMEOUT); + if (a_cmdid < 0) + return; + + memset(&cmd, 0, sizeof(cmd)); + cmd.abort.opcode = nvme_admin_abort_cmd; + cmd.abort.cid = cmdid; + cmd.abort.sqid = cpu_to_le16(nvmeq->qid); + cmd.abort.command_id = a_cmdid; + + --dev->abort_limit; + info[cmdid].aborted = 1; + info[cmdid].timeout = jiffies + ADMIN_TIMEOUT; + + dev_warn(nvmeq->q_dmadev, "Aborting I/O %d QID %d\n", cmdid, + nvmeq->qid); + nvme_submit_cmd(dev->queues[0], &cmd); +} + /** * nvme_cancel_ios - Cancel outstanding I/Os * @queue: The queue to cancel I/Os on @@ -1024,7 +1044,12 @@ static void nvme_cancel_ios(struct nvme_queue *nvmeq, bool timeout) continue; if (info[cmdid].ctx == CMD_CTX_CANCELLED) continue; - dev_warn(nvmeq->q_dmadev, "Cancelling I/O %d\n", cmdid); + if (timeout && nvmeq->dev->initialized) { + nvme_abort_cmd(cmdid, nvmeq); + continue; + } + dev_warn(nvmeq->q_dmadev, "Cancelling I/O %d QID %d\n", cmdid, + nvmeq->qid); ctx = cancel_cmdid(nvmeq, cmdid, &fn); fn(nvmeq->dev, ctx, &cqe); } @@ -1046,26 +1071,31 @@ static void nvme_free_queue(struct nvme_queue *nvmeq) kfree(nvmeq); } -static void nvme_free_queues(struct nvme_dev *dev) +static void nvme_free_queues(struct nvme_dev *dev, int lowest) { int i; - for (i = dev->queue_count - 1; i >= 0; i--) { + for (i = dev->queue_count - 1; i >= lowest; i--) { nvme_free_queue(dev->queues[i]); dev->queue_count--; dev->queues[i] = NULL; } } -static void nvme_disable_queue(struct nvme_dev *dev, int qid) +/** + * nvme_suspend_queue - put queue into suspended state + * @nvmeq - queue to suspend + * + * Returns 1 if already suspended, 0 otherwise. + */ +static int nvme_suspend_queue(struct nvme_queue *nvmeq) { - struct nvme_queue *nvmeq = dev->queues[qid]; - int vector = dev->entry[nvmeq->cq_vector].vector; + int vector = nvmeq->dev->entry[nvmeq->cq_vector].vector; spin_lock_irq(&nvmeq->q_lock); if (nvmeq->q_suspended) { spin_unlock_irq(&nvmeq->q_lock); - return; + return 1; } nvmeq->q_suspended = 1; spin_unlock_irq(&nvmeq->q_lock); @@ -1073,18 +1103,35 @@ static void nvme_disable_queue(struct nvme_dev *dev, int qid) irq_set_affinity_hint(vector, NULL); free_irq(vector, nvmeq); - /* Don't tell the adapter to delete the admin queue */ - if (qid) { - adapter_delete_sq(dev, qid); - adapter_delete_cq(dev, qid); - } + return 0; +} +static void nvme_clear_queue(struct nvme_queue *nvmeq) +{ spin_lock_irq(&nvmeq->q_lock); nvme_process_cq(nvmeq); nvme_cancel_ios(nvmeq, false); spin_unlock_irq(&nvmeq->q_lock); } +static void nvme_disable_queue(struct nvme_dev *dev, int qid) +{ + struct nvme_queue *nvmeq = dev->queues[qid]; + + if (!nvmeq) + return; + if (nvme_suspend_queue(nvmeq)) + return; + + /* Don't tell the adapter to delete the admin queue. + * Don't tell a removed adapter to delete IO queues. */ + if (qid && readl(&dev->bar->csts) != -1) { + adapter_delete_sq(dev, qid); + adapter_delete_cq(dev, qid); + } + nvme_clear_queue(nvmeq); +} + static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, int depth, int vector) { @@ -1107,15 +1154,18 @@ static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, nvmeq->q_dmadev = dmadev; nvmeq->dev = dev; + snprintf(nvmeq->irqname, sizeof(nvmeq->irqname), "nvme%dq%d", + dev->instance, qid); spin_lock_init(&nvmeq->q_lock); nvmeq->cq_head = 0; nvmeq->cq_phase = 1; init_waitqueue_head(&nvmeq->sq_full); init_waitqueue_entry(&nvmeq->sq_cong_wait, nvme_thread); bio_list_init(&nvmeq->sq_cong); - nvmeq->q_db = &dev->dbs[qid << (dev->db_stride + 1)]; + nvmeq->q_db = &dev->dbs[qid * 2 * dev->db_stride]; nvmeq->q_depth = depth; nvmeq->cq_vector = vector; + nvmeq->qid = qid; nvmeq->q_suspended = 1; dev->queue_count++; @@ -1134,11 +1184,10 @@ static int queue_request_irq(struct nvme_dev *dev, struct nvme_queue *nvmeq, { if (use_threaded_interrupts) return request_threaded_irq(dev->entry[nvmeq->cq_vector].vector, - nvme_irq_check, nvme_irq, - IRQF_DISABLED | IRQF_SHARED, + nvme_irq_check, nvme_irq, IRQF_SHARED, name, nvmeq); return request_irq(dev->entry[nvmeq->cq_vector].vector, nvme_irq, - IRQF_DISABLED | IRQF_SHARED, name, nvmeq); + IRQF_SHARED, name, nvmeq); } static void nvme_init_queue(struct nvme_queue *nvmeq, u16 qid) @@ -1149,7 +1198,7 @@ static void nvme_init_queue(struct nvme_queue *nvmeq, u16 qid) nvmeq->sq_tail = 0; nvmeq->cq_head = 0; nvmeq->cq_phase = 1; - nvmeq->q_db = &dev->dbs[qid << (dev->db_stride + 1)]; + nvmeq->q_db = &dev->dbs[qid * 2 * dev->db_stride]; memset(nvmeq->cmdid_data, 0, extra); memset((void *)nvmeq->cqes, 0, CQ_SIZE(nvmeq->q_depth)); nvme_cancel_ios(nvmeq, false); @@ -1169,13 +1218,13 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) if (result < 0) goto release_cq; - result = queue_request_irq(dev, nvmeq, "nvme"); + result = queue_request_irq(dev, nvmeq, nvmeq->irqname); if (result < 0) goto release_sq; - spin_lock(&nvmeq->q_lock); + spin_lock_irq(&nvmeq->q_lock); nvme_init_queue(nvmeq, qid); - spin_unlock(&nvmeq->q_lock); + spin_unlock_irq(&nvmeq->q_lock); return result; @@ -1287,13 +1336,13 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) if (result) return result; - result = queue_request_irq(dev, nvmeq, "nvme admin"); + result = queue_request_irq(dev, nvmeq, nvmeq->irqname); if (result) return result; - spin_lock(&nvmeq->q_lock); + spin_lock_irq(&nvmeq->q_lock); nvme_init_queue(nvmeq, 0); - spin_unlock(&nvmeq->q_lock); + spin_unlock_irq(&nvmeq->q_lock); return result; } @@ -1569,10 +1618,47 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, } } +#ifdef CONFIG_COMPAT +static int nvme_compat_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) +{ + struct nvme_ns *ns = bdev->bd_disk->private_data; + + switch (cmd) { + case SG_IO: + return nvme_sg_io32(ns, arg); + } + return nvme_ioctl(bdev, mode, cmd, arg); +} +#else +#define nvme_compat_ioctl NULL +#endif + +static int nvme_open(struct block_device *bdev, fmode_t mode) +{ + struct nvme_ns *ns = bdev->bd_disk->private_data; + struct nvme_dev *dev = ns->dev; + + kref_get(&dev->kref); + return 0; +} + +static void nvme_free_dev(struct kref *kref); + +static void nvme_release(struct gendisk *disk, fmode_t mode) +{ + struct nvme_ns *ns = disk->private_data; + struct nvme_dev *dev = ns->dev; + + kref_put(&dev->kref, nvme_free_dev); +} + static const struct block_device_operations nvme_fops = { .owner = THIS_MODULE, .ioctl = nvme_ioctl, - .compat_ioctl = nvme_ioctl, + .compat_ioctl = nvme_compat_ioctl, + .open = nvme_open, + .release = nvme_release, }; static void nvme_resubmit_bios(struct nvme_queue *nvmeq) @@ -1596,13 +1682,25 @@ static void nvme_resubmit_bios(struct nvme_queue *nvmeq) static int nvme_kthread(void *data) { - struct nvme_dev *dev; + struct nvme_dev *dev, *next; while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); spin_lock(&dev_list_lock); - list_for_each_entry(dev, &dev_list, node) { + list_for_each_entry_safe(dev, next, &dev_list, node) { int i; + if (readl(&dev->bar->csts) & NVME_CSTS_CFS && + dev->initialized) { + if (work_busy(&dev->reset_work)) + continue; + list_del_init(&dev->node); + dev_warn(&dev->pci_dev->dev, + "Failed status, reset controller\n"); + PREPARE_WORK(&dev->reset_work, + nvme_reset_failed_dev); + queue_work(nvme_workq, &dev->reset_work); + continue; + } for (i = 0; i < dev->queue_count; i++) { struct nvme_queue *nvmeq = dev->queues[i]; if (!nvmeq) @@ -1623,33 +1721,6 @@ static int nvme_kthread(void *data) return 0; } -static DEFINE_IDA(nvme_index_ida); - -static int nvme_get_ns_idx(void) -{ - int index, error; - - do { - if (!ida_pre_get(&nvme_index_ida, GFP_KERNEL)) - return -1; - - spin_lock(&dev_list_lock); - error = ida_get_new(&nvme_index_ida, &index); - spin_unlock(&dev_list_lock); - } while (error == -EAGAIN); - - if (error) - index = -1; - return index; -} - -static void nvme_put_ns_idx(int index) -{ - spin_lock(&dev_list_lock); - ida_remove(&nvme_index_ida, index); - spin_unlock(&dev_list_lock); -} - static void nvme_config_discard(struct nvme_ns *ns) { u32 logical_block_size = queue_logical_block_size(ns->queue); @@ -1683,7 +1754,7 @@ static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid, ns->dev = dev; ns->queue->queuedata = ns; - disk = alloc_disk(NVME_MINORS); + disk = alloc_disk(0); if (!disk) goto out_free_queue; ns->ns_id = nsid; @@ -1696,12 +1767,12 @@ static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid, blk_queue_max_hw_sectors(ns->queue, dev->max_hw_sectors); disk->major = nvme_major; - disk->minors = NVME_MINORS; - disk->first_minor = NVME_MINORS * nvme_get_ns_idx(); + disk->first_minor = 0; disk->fops = &nvme_fops; disk->private_data = ns; disk->queue = ns->queue; disk->driverfs_dev = &dev->pci_dev->dev; + disk->flags = GENHD_FL_EXT_DEVT; sprintf(disk->disk_name, "nvme%dn%d", dev->instance, nsid); set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9)); @@ -1717,15 +1788,6 @@ static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid, return NULL; } -static void nvme_ns_free(struct nvme_ns *ns) -{ - int index = ns->disk->first_minor / NVME_MINORS; - put_disk(ns->disk); - nvme_put_ns_idx(index); - blk_cleanup_queue(ns->queue); - kfree(ns); -} - static int set_queue_count(struct nvme_dev *dev, int count) { int status; @@ -1741,11 +1803,12 @@ static int set_queue_count(struct nvme_dev *dev, int count) static size_t db_bar_size(struct nvme_dev *dev, unsigned nr_io_queues) { - return 4096 + ((nr_io_queues + 1) << (dev->db_stride + 3)); + return 4096 + ((nr_io_queues + 1) * 8 * dev->db_stride); } static int nvme_setup_io_queues(struct nvme_dev *dev) { + struct nvme_queue *adminq = dev->queues[0]; struct pci_dev *pdev = dev->pci_dev; int result, cpu, i, vecs, nr_io_queues, size, q_depth; @@ -1772,7 +1835,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) } /* Deregister the admin queue's interrupt */ - free_irq(dev->entry[0].vector, dev->queues[0]); + free_irq(dev->entry[0].vector, adminq); vecs = nr_io_queues; for (i = 0; i < vecs; i++) @@ -1810,9 +1873,9 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) */ nr_io_queues = vecs; - result = queue_request_irq(dev, dev->queues[0], "nvme admin"); + result = queue_request_irq(dev, adminq, adminq->irqname); if (result) { - dev->queues[0]->q_suspended = 1; + adminq->q_suspended = 1; goto free_queues; } @@ -1821,9 +1884,9 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) for (i = dev->queue_count - 1; i > nr_io_queues; i--) { struct nvme_queue *nvmeq = dev->queues[i]; - spin_lock(&nvmeq->q_lock); + spin_lock_irq(&nvmeq->q_lock); nvme_cancel_ios(nvmeq, false); - spin_unlock(&nvmeq->q_lock); + spin_unlock_irq(&nvmeq->q_lock); nvme_free_queue(nvmeq); dev->queue_count--; @@ -1864,7 +1927,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) return 0; free_queues: - nvme_free_queues(dev); + nvme_free_queues(dev, 1); return result; } @@ -1876,6 +1939,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) */ static int nvme_dev_add(struct nvme_dev *dev) { + struct pci_dev *pdev = dev->pci_dev; int res; unsigned nn, i; struct nvme_ns *ns; @@ -1885,8 +1949,7 @@ static int nvme_dev_add(struct nvme_dev *dev) dma_addr_t dma_addr; int shift = NVME_CAP_MPSMIN(readq(&dev->bar->cap)) + 12; - mem = dma_alloc_coherent(&dev->pci_dev->dev, 8192, &dma_addr, - GFP_KERNEL); + mem = dma_alloc_coherent(&pdev->dev, 8192, &dma_addr, GFP_KERNEL); if (!mem) return -ENOMEM; @@ -1899,13 +1962,14 @@ static int nvme_dev_add(struct nvme_dev *dev) ctrl = mem; nn = le32_to_cpup(&ctrl->nn); dev->oncs = le16_to_cpup(&ctrl->oncs); + dev->abort_limit = ctrl->acl + 1; memcpy(dev->serial, ctrl->sn, sizeof(ctrl->sn)); memcpy(dev->model, ctrl->mn, sizeof(ctrl->mn)); memcpy(dev->firmware_rev, ctrl->fr, sizeof(ctrl->fr)); if (ctrl->mdts) dev->max_hw_sectors = 1 << (ctrl->mdts + shift - 9); - if ((dev->pci_dev->vendor == PCI_VENDOR_ID_INTEL) && - (dev->pci_dev->device == 0x0953) && ctrl->vs[3]) + if ((pdev->vendor == PCI_VENDOR_ID_INTEL) && + (pdev->device == 0x0953) && ctrl->vs[3]) dev->stripe_size = 1 << (ctrl->vs[3] + shift); id_ns = mem; @@ -1953,16 +2017,21 @@ static int nvme_dev_map(struct nvme_dev *dev) dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) goto disable; - pci_set_drvdata(pdev, dev); dev->bar = ioremap(pci_resource_start(pdev, 0), 8192); if (!dev->bar) goto disable; - - dev->db_stride = NVME_CAP_STRIDE(readq(&dev->bar->cap)); + if (readl(&dev->bar->csts) == -1) { + result = -ENODEV; + goto unmap; + } + dev->db_stride = 1 << NVME_CAP_STRIDE(readq(&dev->bar->cap)); dev->dbs = ((void __iomem *)dev->bar) + 4096; return 0; + unmap: + iounmap(dev->bar); + dev->bar = NULL; disable: pci_release_regions(pdev); disable_pci: @@ -1980,37 +2049,183 @@ static void nvme_dev_unmap(struct nvme_dev *dev) if (dev->bar) { iounmap(dev->bar); dev->bar = NULL; + pci_release_regions(dev->pci_dev); } - pci_release_regions(dev->pci_dev); if (pci_is_enabled(dev->pci_dev)) pci_disable_device(dev->pci_dev); } +struct nvme_delq_ctx { + struct task_struct *waiter; + struct kthread_worker *worker; + atomic_t refcount; +}; + +static void nvme_wait_dq(struct nvme_delq_ctx *dq, struct nvme_dev *dev) +{ + dq->waiter = current; + mb(); + + for (;;) { + set_current_state(TASK_KILLABLE); + if (!atomic_read(&dq->refcount)) + break; + if (!schedule_timeout(ADMIN_TIMEOUT) || + fatal_signal_pending(current)) { + set_current_state(TASK_RUNNING); + + nvme_disable_ctrl(dev, readq(&dev->bar->cap)); + nvme_disable_queue(dev, 0); + + send_sig(SIGKILL, dq->worker->task, 1); + flush_kthread_worker(dq->worker); + return; + } + } + set_current_state(TASK_RUNNING); +} + +static void nvme_put_dq(struct nvme_delq_ctx *dq) +{ + atomic_dec(&dq->refcount); + if (dq->waiter) + wake_up_process(dq->waiter); +} + +static struct nvme_delq_ctx *nvme_get_dq(struct nvme_delq_ctx *dq) +{ + atomic_inc(&dq->refcount); + return dq; +} + +static void nvme_del_queue_end(struct nvme_queue *nvmeq) +{ + struct nvme_delq_ctx *dq = nvmeq->cmdinfo.ctx; + + nvme_clear_queue(nvmeq); + nvme_put_dq(dq); +} + +static int adapter_async_del_queue(struct nvme_queue *nvmeq, u8 opcode, + kthread_work_func_t fn) +{ + struct nvme_command c; + + memset(&c, 0, sizeof(c)); + c.delete_queue.opcode = opcode; + c.delete_queue.qid = cpu_to_le16(nvmeq->qid); + + init_kthread_work(&nvmeq->cmdinfo.work, fn); + return nvme_submit_admin_cmd_async(nvmeq->dev, &c, &nvmeq->cmdinfo); +} + +static void nvme_del_cq_work_handler(struct kthread_work *work) +{ + struct nvme_queue *nvmeq = container_of(work, struct nvme_queue, + cmdinfo.work); + nvme_del_queue_end(nvmeq); +} + +static int nvme_delete_cq(struct nvme_queue *nvmeq) +{ + return adapter_async_del_queue(nvmeq, nvme_admin_delete_cq, + nvme_del_cq_work_handler); +} + +static void nvme_del_sq_work_handler(struct kthread_work *work) +{ + struct nvme_queue *nvmeq = container_of(work, struct nvme_queue, + cmdinfo.work); + int status = nvmeq->cmdinfo.status; + + if (!status) + status = nvme_delete_cq(nvmeq); + if (status) + nvme_del_queue_end(nvmeq); +} + +static int nvme_delete_sq(struct nvme_queue *nvmeq) +{ + return adapter_async_del_queue(nvmeq, nvme_admin_delete_sq, + nvme_del_sq_work_handler); +} + +static void nvme_del_queue_start(struct kthread_work *work) +{ + struct nvme_queue *nvmeq = container_of(work, struct nvme_queue, + cmdinfo.work); + allow_signal(SIGKILL); + if (nvme_delete_sq(nvmeq)) + nvme_del_queue_end(nvmeq); +} + +static void nvme_disable_io_queues(struct nvme_dev *dev) +{ + int i; + DEFINE_KTHREAD_WORKER_ONSTACK(worker); + struct nvme_delq_ctx dq; + struct task_struct *kworker_task = kthread_run(kthread_worker_fn, + &worker, "nvme%d", dev->instance); + + if (IS_ERR(kworker_task)) { + dev_err(&dev->pci_dev->dev, + "Failed to create queue del task\n"); + for (i = dev->queue_count - 1; i > 0; i--) + nvme_disable_queue(dev, i); + return; + } + + dq.waiter = NULL; + atomic_set(&dq.refcount, 0); + dq.worker = &worker; + for (i = dev->queue_count - 1; i > 0; i--) { + struct nvme_queue *nvmeq = dev->queues[i]; + + if (nvme_suspend_queue(nvmeq)) + continue; + nvmeq->cmdinfo.ctx = nvme_get_dq(&dq); + nvmeq->cmdinfo.worker = dq.worker; + init_kthread_work(&nvmeq->cmdinfo.work, nvme_del_queue_start); + queue_kthread_work(dq.worker, &nvmeq->cmdinfo.work); + } + nvme_wait_dq(&dq, dev); + kthread_stop(kworker_task); +} + static void nvme_dev_shutdown(struct nvme_dev *dev) { int i; - for (i = dev->queue_count - 1; i >= 0; i--) - nvme_disable_queue(dev, i); + dev->initialized = 0; spin_lock(&dev_list_lock); list_del_init(&dev->node); spin_unlock(&dev_list_lock); - if (dev->bar) + if (!dev->bar || (dev->bar && readl(&dev->bar->csts) == -1)) { + for (i = dev->queue_count - 1; i >= 0; i--) { + struct nvme_queue *nvmeq = dev->queues[i]; + nvme_suspend_queue(nvmeq); + nvme_clear_queue(nvmeq); + } + } else { + nvme_disable_io_queues(dev); nvme_shutdown_ctrl(dev); + nvme_disable_queue(dev, 0); + } nvme_dev_unmap(dev); } static void nvme_dev_remove(struct nvme_dev *dev) { - struct nvme_ns *ns, *next; + struct nvme_ns *ns; - list_for_each_entry_safe(ns, next, &dev->namespaces, list) { - list_del(&ns->list); - del_gendisk(ns->disk); - nvme_ns_free(ns); + list_for_each_entry(ns, &dev->namespaces, list) { + if (ns->disk->flags & GENHD_FL_UP) + del_gendisk(ns->disk); + if (!blk_queue_dying(ns->queue)) + blk_cleanup_queue(ns->queue); } } @@ -2067,14 +2282,22 @@ static void nvme_release_instance(struct nvme_dev *dev) spin_unlock(&dev_list_lock); } +static void nvme_free_namespaces(struct nvme_dev *dev) +{ + struct nvme_ns *ns, *next; + + list_for_each_entry_safe(ns, next, &dev->namespaces, list) { + list_del(&ns->list); + put_disk(ns->disk); + kfree(ns); + } +} + static void nvme_free_dev(struct kref *kref) { struct nvme_dev *dev = container_of(kref, struct nvme_dev, kref); - nvme_dev_remove(dev); - nvme_dev_shutdown(dev); - nvme_free_queues(dev); - nvme_release_instance(dev); - nvme_release_prp_pools(dev); + + nvme_free_namespaces(dev); kfree(dev->queues); kfree(dev->entry); kfree(dev); @@ -2138,6 +2361,7 @@ static int nvme_dev_start(struct nvme_dev *dev) return result; disable: + nvme_disable_queue(dev, 0); spin_lock(&dev_list_lock); list_del_init(&dev->node); spin_unlock(&dev_list_lock); @@ -2146,6 +2370,71 @@ static int nvme_dev_start(struct nvme_dev *dev) return result; } +static int nvme_remove_dead_ctrl(void *arg) +{ + struct nvme_dev *dev = (struct nvme_dev *)arg; + struct pci_dev *pdev = dev->pci_dev; + + if (pci_get_drvdata(pdev)) + pci_stop_and_remove_bus_device(pdev); + kref_put(&dev->kref, nvme_free_dev); + return 0; +} + +static void nvme_remove_disks(struct work_struct *ws) +{ + int i; + struct nvme_dev *dev = container_of(ws, struct nvme_dev, reset_work); + + nvme_dev_remove(dev); + spin_lock(&dev_list_lock); + for (i = dev->queue_count - 1; i > 0; i--) { + BUG_ON(!dev->queues[i] || !dev->queues[i]->q_suspended); + nvme_free_queue(dev->queues[i]); + dev->queue_count--; + dev->queues[i] = NULL; + } + spin_unlock(&dev_list_lock); +} + +static int nvme_dev_resume(struct nvme_dev *dev) +{ + int ret; + + ret = nvme_dev_start(dev); + if (ret && ret != -EBUSY) + return ret; + if (ret == -EBUSY) { + spin_lock(&dev_list_lock); + PREPARE_WORK(&dev->reset_work, nvme_remove_disks); + queue_work(nvme_workq, &dev->reset_work); + spin_unlock(&dev_list_lock); + } + dev->initialized = 1; + return 0; +} + +static void nvme_dev_reset(struct nvme_dev *dev) +{ + nvme_dev_shutdown(dev); + if (nvme_dev_resume(dev)) { + dev_err(&dev->pci_dev->dev, "Device failed to resume\n"); + kref_get(&dev->kref); + if (IS_ERR(kthread_run(nvme_remove_dead_ctrl, dev, "nvme%d", + dev->instance))) { + dev_err(&dev->pci_dev->dev, + "Failed to start controller remove task\n"); + kref_put(&dev->kref, nvme_free_dev); + } + } +} + +static void nvme_reset_failed_dev(struct work_struct *ws) +{ + struct nvme_dev *dev = container_of(ws, struct nvme_dev, reset_work); + nvme_dev_reset(dev); +} + static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int result = -ENOMEM; @@ -2164,8 +2453,9 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto free; INIT_LIST_HEAD(&dev->namespaces); + INIT_WORK(&dev->reset_work, nvme_reset_failed_dev); dev->pci_dev = pdev; - + pci_set_drvdata(pdev, dev); result = nvme_set_instance(dev); if (result) goto free; @@ -2181,6 +2471,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto release_pools; } + kref_init(&dev->kref); result = nvme_dev_add(dev); if (result) goto shutdown; @@ -2195,15 +2486,16 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (result) goto remove; - kref_init(&dev->kref); + dev->initialized = 1; return 0; remove: nvme_dev_remove(dev); + nvme_free_namespaces(dev); shutdown: nvme_dev_shutdown(dev); release_pools: - nvme_free_queues(dev); + nvme_free_queues(dev, 0); nvme_release_prp_pools(dev); release: nvme_release_instance(dev); @@ -2214,10 +2506,28 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) return result; } +static void nvme_shutdown(struct pci_dev *pdev) +{ + struct nvme_dev *dev = pci_get_drvdata(pdev); + nvme_dev_shutdown(dev); +} + static void nvme_remove(struct pci_dev *pdev) { struct nvme_dev *dev = pci_get_drvdata(pdev); + + spin_lock(&dev_list_lock); + list_del_init(&dev->node); + spin_unlock(&dev_list_lock); + + pci_set_drvdata(pdev, NULL); + flush_work(&dev->reset_work); misc_deregister(&dev->miscdev); + nvme_dev_remove(dev); + nvme_dev_shutdown(dev); + nvme_free_queues(dev, 0); + nvme_release_instance(dev); + nvme_release_prp_pools(dev); kref_put(&dev->kref, nvme_free_dev); } @@ -2241,13 +2551,12 @@ static int nvme_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct nvme_dev *ndev = pci_get_drvdata(pdev); - int ret; - ret = nvme_dev_start(ndev); - /* XXX: should remove gendisks if resume fails */ - if (ret) - nvme_free_queues(ndev); - return ret; + if (nvme_dev_resume(ndev) && !work_busy(&ndev->reset_work)) { + PREPARE_WORK(&ndev->reset_work, nvme_reset_failed_dev); + queue_work(nvme_workq, &ndev->reset_work); + } + return 0; } static SIMPLE_DEV_PM_OPS(nvme_dev_pm_ops, nvme_suspend, nvme_resume); @@ -2274,6 +2583,7 @@ static struct pci_driver nvme_driver = { .id_table = nvme_id_table, .probe = nvme_probe, .remove = nvme_remove, + .shutdown = nvme_shutdown, .driver = { .pm = &nvme_dev_pm_ops, }, @@ -2288,9 +2598,14 @@ static int __init nvme_init(void) if (IS_ERR(nvme_thread)) return PTR_ERR(nvme_thread); + result = -ENOMEM; + nvme_workq = create_singlethread_workqueue("nvme"); + if (!nvme_workq) + goto kill_kthread; + result = register_blkdev(nvme_major, "nvme"); if (result < 0) - goto kill_kthread; + goto kill_workq; else if (result > 0) nvme_major = result; @@ -2301,6 +2616,8 @@ static int __init nvme_init(void) unregister_blkdev: unregister_blkdev(nvme_major, "nvme"); + kill_workq: + destroy_workqueue(nvme_workq); kill_kthread: kthread_stop(nvme_thread); return result; @@ -2310,6 +2627,7 @@ static void __exit nvme_exit(void) { pci_unregister_driver(&nvme_driver); unregister_blkdev(nvme_major, "nvme"); + destroy_workqueue(nvme_workq); kthread_stop(nvme_thread); } diff --git a/drivers/block/nvme-scsi.c b/drivers/block/nvme-scsi.c index 4a4ff4eb8e2331..4a0ceb64e26924 100644 --- a/drivers/block/nvme-scsi.c +++ b/drivers/block/nvme-scsi.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -3038,6 +3039,152 @@ int nvme_sg_io(struct nvme_ns *ns, struct sg_io_hdr __user *u_hdr) return retcode; } +#ifdef CONFIG_COMPAT +typedef struct sg_io_hdr32 { + compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */ + compat_int_t dxfer_direction; /* [i] data transfer direction */ + unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ + unsigned char mx_sb_len; /* [i] max length to write to sbp */ + unsigned short iovec_count; /* [i] 0 implies no scatter gather */ + compat_uint_t dxfer_len; /* [i] byte count of data transfer */ + compat_uint_t dxferp; /* [i], [*io] points to data transfer memory + or scatter gather list */ + compat_uptr_t cmdp; /* [i], [*i] points to command to perform */ + compat_uptr_t sbp; /* [i], [*o] points to sense_buffer memory */ + compat_uint_t timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */ + compat_uint_t flags; /* [i] 0 -> default, see SG_FLAG... */ + compat_int_t pack_id; /* [i->o] unused internally (normally) */ + compat_uptr_t usr_ptr; /* [i->o] unused internally */ + unsigned char status; /* [o] scsi status */ + unsigned char masked_status; /* [o] shifted, masked scsi status */ + unsigned char msg_status; /* [o] messaging level data (optional) */ + unsigned char sb_len_wr; /* [o] byte count actually written to sbp */ + unsigned short host_status; /* [o] errors from host adapter */ + unsigned short driver_status; /* [o] errors from software driver */ + compat_int_t resid; /* [o] dxfer_len - actual_transferred */ + compat_uint_t duration; /* [o] time taken by cmd (unit: millisec) */ + compat_uint_t info; /* [o] auxiliary information */ +} sg_io_hdr32_t; /* 64 bytes long (on sparc32) */ + +typedef struct sg_iovec32 { + compat_uint_t iov_base; + compat_uint_t iov_len; +} sg_iovec32_t; + +static int sg_build_iovec(sg_io_hdr_t __user *sgio, void __user *dxferp, u16 iovec_count) +{ + sg_iovec_t __user *iov = (sg_iovec_t __user *) (sgio + 1); + sg_iovec32_t __user *iov32 = dxferp; + int i; + + for (i = 0; i < iovec_count; i++) { + u32 base, len; + + if (get_user(base, &iov32[i].iov_base) || + get_user(len, &iov32[i].iov_len) || + put_user(compat_ptr(base), &iov[i].iov_base) || + put_user(len, &iov[i].iov_len)) + return -EFAULT; + } + + if (put_user(iov, &sgio->dxferp)) + return -EFAULT; + return 0; +} + +int nvme_sg_io32(struct nvme_ns *ns, unsigned long arg) +{ + sg_io_hdr32_t __user *sgio32 = (sg_io_hdr32_t __user *)arg; + sg_io_hdr_t __user *sgio; + u16 iovec_count; + u32 data; + void __user *dxferp; + int err; + int interface_id; + + if (get_user(interface_id, &sgio32->interface_id)) + return -EFAULT; + if (interface_id != 'S') + return -EINVAL; + + if (get_user(iovec_count, &sgio32->iovec_count)) + return -EFAULT; + + { + void __user *top = compat_alloc_user_space(0); + void __user *new = compat_alloc_user_space(sizeof(sg_io_hdr_t) + + (iovec_count * sizeof(sg_iovec_t))); + if (new > top) + return -EINVAL; + + sgio = new; + } + + /* Ok, now construct. */ + if (copy_in_user(&sgio->interface_id, &sgio32->interface_id, + (2 * sizeof(int)) + + (2 * sizeof(unsigned char)) + + (1 * sizeof(unsigned short)) + + (1 * sizeof(unsigned int)))) + return -EFAULT; + + if (get_user(data, &sgio32->dxferp)) + return -EFAULT; + dxferp = compat_ptr(data); + if (iovec_count) { + if (sg_build_iovec(sgio, dxferp, iovec_count)) + return -EFAULT; + } else { + if (put_user(dxferp, &sgio->dxferp)) + return -EFAULT; + } + + { + unsigned char __user *cmdp; + unsigned char __user *sbp; + + if (get_user(data, &sgio32->cmdp)) + return -EFAULT; + cmdp = compat_ptr(data); + + if (get_user(data, &sgio32->sbp)) + return -EFAULT; + sbp = compat_ptr(data); + + if (put_user(cmdp, &sgio->cmdp) || + put_user(sbp, &sgio->sbp)) + return -EFAULT; + } + + if (copy_in_user(&sgio->timeout, &sgio32->timeout, + 3 * sizeof(int))) + return -EFAULT; + + if (get_user(data, &sgio32->usr_ptr)) + return -EFAULT; + if (put_user(compat_ptr(data), &sgio->usr_ptr)) + return -EFAULT; + + err = nvme_sg_io(ns, sgio); + if (err >= 0) { + void __user *datap; + + if (copy_in_user(&sgio32->pack_id, &sgio->pack_id, + sizeof(int)) || + get_user(datap, &sgio->usr_ptr) || + put_user((u32)(unsigned long)datap, + &sgio32->usr_ptr) || + copy_in_user(&sgio32->status, &sgio->status, + (4 * sizeof(unsigned char)) + + (2 * sizeof(unsigned short)) + + (3 * sizeof(int)))) + err = -EFAULT; + } + + return err; +} +#endif + int nvme_sg_get_version_num(int __user *ip) { return put_user(sg_version_num, ip); diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c index 4a27b1de5fcb9f..2ce3dfd7e6b9ba 100644 --- a/drivers/block/paride/pg.c +++ b/drivers/block/paride/pg.c @@ -581,7 +581,7 @@ static ssize_t pg_write(struct file *filp, const char __user *buf, size_t count, if (hdr.magic != PG_MAGIC) return -EINVAL; - if (hdr.dlen > PG_MAX_DATA) + if (hdr.dlen < 0 || hdr.dlen > PG_MAX_DATA) return -EINVAL; if ((count - hs) > PG_MAX_DATA) return -EINVAL; diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index ff8668c5efb10e..a2af73db187b69 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -651,7 +651,7 @@ static struct pkt_rb_node *pkt_rbtree_find(struct pktcdvd_device *pd, sector_t s for (;;) { tmp = rb_entry(n, struct pkt_rb_node, rb_node); - if (s <= tmp->bio->bi_sector) + if (s <= tmp->bio->bi_iter.bi_sector) next = n->rb_left; else next = n->rb_right; @@ -660,12 +660,12 @@ static struct pkt_rb_node *pkt_rbtree_find(struct pktcdvd_device *pd, sector_t s n = next; } - if (s > tmp->bio->bi_sector) { + if (s > tmp->bio->bi_iter.bi_sector) { tmp = pkt_rbtree_next(tmp); if (!tmp) return NULL; } - BUG_ON(s > tmp->bio->bi_sector); + BUG_ON(s > tmp->bio->bi_iter.bi_sector); return tmp; } @@ -676,13 +676,13 @@ static void pkt_rbtree_insert(struct pktcdvd_device *pd, struct pkt_rb_node *nod { struct rb_node **p = &pd->bio_queue.rb_node; struct rb_node *parent = NULL; - sector_t s = node->bio->bi_sector; + sector_t s = node->bio->bi_iter.bi_sector; struct pkt_rb_node *tmp; while (*p) { parent = *p; tmp = rb_entry(parent, struct pkt_rb_node, rb_node); - if (s < tmp->bio->bi_sector) + if (s < tmp->bio->bi_iter.bi_sector) p = &(*p)->rb_left; else p = &(*p)->rb_right; @@ -706,7 +706,9 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * WRITE : READ, __GFP_WAIT); if (cgc->buflen) { - if (blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, __GFP_WAIT)) + ret = blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, + __GFP_WAIT); + if (ret) goto out; } @@ -857,7 +859,8 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd) spin_lock(&pd->iosched.lock); bio = bio_list_peek(&pd->iosched.write_queue); spin_unlock(&pd->iosched.lock); - if (bio && (bio->bi_sector == pd->iosched.last_write)) + if (bio && (bio->bi_iter.bi_sector == + pd->iosched.last_write)) need_write_seek = 0; if (need_write_seek && reads_queued) { if (atomic_read(&pd->cdrw.pending_bios) > 0) { @@ -888,7 +891,8 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd) continue; if (bio_data_dir(bio) == READ) - pd->iosched.successive_reads += bio->bi_size >> 10; + pd->iosched.successive_reads += + bio->bi_iter.bi_size >> 10; else { pd->iosched.successive_reads = 0; pd->iosched.last_write = bio_end_sector(bio); @@ -978,7 +982,7 @@ static void pkt_end_io_read(struct bio *bio, int err) pkt_dbg(2, pd, "bio=%p sec0=%llx sec=%llx err=%d\n", bio, (unsigned long long)pkt->sector, - (unsigned long long)bio->bi_sector, err); + (unsigned long long)bio->bi_iter.bi_sector, err); if (err) atomic_inc(&pkt->io_errors); @@ -1026,8 +1030,9 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) memset(written, 0, sizeof(written)); spin_lock(&pkt->lock); bio_list_for_each(bio, &pkt->orig_bios) { - int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9); - int num_frames = bio->bi_size / CD_FRAMESIZE; + int first_frame = (bio->bi_iter.bi_sector - pkt->sector) / + (CD_FRAMESIZE >> 9); + int num_frames = bio->bi_iter.bi_size / CD_FRAMESIZE; pd->stats.secs_w += num_frames * (CD_FRAMESIZE >> 9); BUG_ON(first_frame < 0); BUG_ON(first_frame + num_frames > pkt->frames); @@ -1053,7 +1058,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) bio = pkt->r_bios[f]; bio_reset(bio); - bio->bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9); + bio->bi_iter.bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9); bio->bi_bdev = pd->bdev; bio->bi_end_io = pkt_end_io_read; bio->bi_private = pkt; @@ -1150,8 +1155,8 @@ static int pkt_start_recovery(struct packet_data *pkt) bio_reset(pkt->bio); pkt->bio->bi_bdev = pd->bdev; pkt->bio->bi_rw = REQ_WRITE; - pkt->bio->bi_sector = new_sector; - pkt->bio->bi_size = pkt->frames * CD_FRAMESIZE; + pkt->bio->bi_iter.bi_sector = new_sector; + pkt->bio->bi_iter.bi_size = pkt->frames * CD_FRAMESIZE; pkt->bio->bi_vcnt = pkt->frames; pkt->bio->bi_end_io = pkt_end_io_packet_write; @@ -1213,7 +1218,7 @@ static int pkt_handle_queue(struct pktcdvd_device *pd) node = first_node; while (node) { bio = node->bio; - zone = get_zone(bio->bi_sector, pd); + zone = get_zone(bio->bi_iter.bi_sector, pd); list_for_each_entry(p, &pd->cdrw.pkt_active_list, list) { if (p->sector == zone) { bio = NULL; @@ -1252,14 +1257,14 @@ static int pkt_handle_queue(struct pktcdvd_device *pd) pkt_dbg(2, pd, "looking for zone %llx\n", (unsigned long long)zone); while ((node = pkt_rbtree_find(pd, zone)) != NULL) { bio = node->bio; - pkt_dbg(2, pd, "found zone=%llx\n", - (unsigned long long)get_zone(bio->bi_sector, pd)); - if (get_zone(bio->bi_sector, pd) != zone) + pkt_dbg(2, pd, "found zone=%llx\n", (unsigned long long) + get_zone(bio->bi_iter.bi_sector, pd)); + if (get_zone(bio->bi_iter.bi_sector, pd) != zone) break; pkt_rbtree_erase(pd, node); spin_lock(&pkt->lock); bio_list_add(&pkt->orig_bios, bio); - pkt->write_size += bio->bi_size / CD_FRAMESIZE; + pkt->write_size += bio->bi_iter.bi_size / CD_FRAMESIZE; spin_unlock(&pkt->lock); } /* check write congestion marks, and if bio_queue_size is @@ -1293,7 +1298,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt) struct bio_vec *bvec = pkt->w_bio->bi_io_vec; bio_reset(pkt->w_bio); - pkt->w_bio->bi_sector = pkt->sector; + pkt->w_bio->bi_iter.bi_sector = pkt->sector; pkt->w_bio->bi_bdev = pd->bdev; pkt->w_bio->bi_end_io = pkt_end_io_packet_write; pkt->w_bio->bi_private = pkt; @@ -2335,75 +2340,29 @@ static void pkt_end_io_read_cloned(struct bio *bio, int err) pkt_bio_finished(pd); } -static void pkt_make_request(struct request_queue *q, struct bio *bio) +static void pkt_make_request_read(struct pktcdvd_device *pd, struct bio *bio) { - struct pktcdvd_device *pd; - char b[BDEVNAME_SIZE]; + struct bio *cloned_bio = bio_clone(bio, GFP_NOIO); + struct packet_stacked_data *psd = mempool_alloc(psd_pool, GFP_NOIO); + + psd->pd = pd; + psd->bio = bio; + cloned_bio->bi_bdev = pd->bdev; + cloned_bio->bi_private = psd; + cloned_bio->bi_end_io = pkt_end_io_read_cloned; + pd->stats.secs_r += bio_sectors(bio); + pkt_queue_bio(pd, cloned_bio); +} + +static void pkt_make_request_write(struct request_queue *q, struct bio *bio) +{ + struct pktcdvd_device *pd = q->queuedata; sector_t zone; struct packet_data *pkt; int was_empty, blocked_bio; struct pkt_rb_node *node; - pd = q->queuedata; - if (!pd) { - pr_err("%s incorrect request queue\n", - bdevname(bio->bi_bdev, b)); - goto end_io; - } - - /* - * Clone READ bios so we can have our own bi_end_io callback. - */ - if (bio_data_dir(bio) == READ) { - struct bio *cloned_bio = bio_clone(bio, GFP_NOIO); - struct packet_stacked_data *psd = mempool_alloc(psd_pool, GFP_NOIO); - - psd->pd = pd; - psd->bio = bio; - cloned_bio->bi_bdev = pd->bdev; - cloned_bio->bi_private = psd; - cloned_bio->bi_end_io = pkt_end_io_read_cloned; - pd->stats.secs_r += bio_sectors(bio); - pkt_queue_bio(pd, cloned_bio); - return; - } - - if (!test_bit(PACKET_WRITABLE, &pd->flags)) { - pkt_notice(pd, "WRITE for ro device (%llu)\n", - (unsigned long long)bio->bi_sector); - goto end_io; - } - - if (!bio->bi_size || (bio->bi_size % CD_FRAMESIZE)) { - pkt_err(pd, "wrong bio size\n"); - goto end_io; - } - - blk_queue_bounce(q, &bio); - - zone = get_zone(bio->bi_sector, pd); - pkt_dbg(2, pd, "start = %6llx stop = %6llx\n", - (unsigned long long)bio->bi_sector, - (unsigned long long)bio_end_sector(bio)); - - /* Check if we have to split the bio */ - { - struct bio_pair *bp; - sector_t last_zone; - int first_sectors; - - last_zone = get_zone(bio_end_sector(bio) - 1, pd); - if (last_zone != zone) { - BUG_ON(last_zone != zone + pd->settings.size); - first_sectors = last_zone - bio->bi_sector; - bp = bio_split(bio, first_sectors); - BUG_ON(!bp); - pkt_make_request(q, &bp->bio1); - pkt_make_request(q, &bp->bio2); - bio_pair_release(bp); - return; - } - } + zone = get_zone(bio->bi_iter.bi_sector, pd); /* * If we find a matching packet in state WAITING or READ_WAIT, we can @@ -2417,7 +2376,8 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) if ((pkt->state == PACKET_WAITING_STATE) || (pkt->state == PACKET_READ_WAIT_STATE)) { bio_list_add(&pkt->orig_bios, bio); - pkt->write_size += bio->bi_size / CD_FRAMESIZE; + pkt->write_size += + bio->bi_iter.bi_size / CD_FRAMESIZE; if ((pkt->write_size >= pkt->frames) && (pkt->state == PACKET_WAITING_STATE)) { atomic_inc(&pkt->run_sm); @@ -2476,6 +2436,64 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) */ wake_up(&pd->wqueue); } +} + +static void pkt_make_request(struct request_queue *q, struct bio *bio) +{ + struct pktcdvd_device *pd; + char b[BDEVNAME_SIZE]; + struct bio *split; + + pd = q->queuedata; + if (!pd) { + pr_err("%s incorrect request queue\n", + bdevname(bio->bi_bdev, b)); + goto end_io; + } + + pkt_dbg(2, pd, "start = %6llx stop = %6llx\n", + (unsigned long long)bio->bi_iter.bi_sector, + (unsigned long long)bio_end_sector(bio)); + + /* + * Clone READ bios so we can have our own bi_end_io callback. + */ + if (bio_data_dir(bio) == READ) { + pkt_make_request_read(pd, bio); + return; + } + + if (!test_bit(PACKET_WRITABLE, &pd->flags)) { + pkt_notice(pd, "WRITE for ro device (%llu)\n", + (unsigned long long)bio->bi_iter.bi_sector); + goto end_io; + } + + if (!bio->bi_iter.bi_size || (bio->bi_iter.bi_size % CD_FRAMESIZE)) { + pkt_err(pd, "wrong bio size\n"); + goto end_io; + } + + blk_queue_bounce(q, &bio); + + do { + sector_t zone = get_zone(bio->bi_iter.bi_sector, pd); + sector_t last_zone = get_zone(bio_end_sector(bio) - 1, pd); + + if (last_zone != zone) { + BUG_ON(last_zone != zone + pd->settings.size); + + split = bio_split(bio, last_zone - + bio->bi_iter.bi_sector, + GFP_NOIO, fs_bio_set); + bio_chain(split, bio); + } else { + split = bio; + } + + pkt_make_request_write(q, split); + } while (split != bio); + return; end_io: bio_io_error(bio); diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index d754a88d75858e..c120d70d3fb3b3 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -94,26 +94,25 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, { unsigned int offset = 0; struct req_iterator iter; - struct bio_vec *bvec; + struct bio_vec bvec; unsigned int i = 0; size_t size; void *buf; rq_for_each_segment(bvec, req, iter) { unsigned long flags; - dev_dbg(&dev->sbd.core, - "%s:%u: bio %u: %u segs %u sectors from %lu\n", - __func__, __LINE__, i, bio_segments(iter.bio), - bio_sectors(iter.bio), iter.bio->bi_sector); + dev_dbg(&dev->sbd.core, "%s:%u: bio %u: %u sectors from %lu\n", + __func__, __LINE__, i, bio_sectors(iter.bio), + iter.bio->bi_iter.bi_sector); - size = bvec->bv_len; - buf = bvec_kmap_irq(bvec, &flags); + size = bvec.bv_len; + buf = bvec_kmap_irq(&bvec, &flags); if (gather) memcpy(dev->bounce_buf+offset, buf, size); else memcpy(buf, dev->bounce_buf+offset, size); offset += size; - flush_kernel_dcache_page(bvec->bv_page); + flush_kernel_dcache_page(bvec.bv_page); bvec_kunmap_irq(buf, &flags); i++; } @@ -130,7 +129,7 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, #ifdef DEBUG unsigned int n = 0; - struct bio_vec *bv; + struct bio_vec bv; struct req_iterator iter; rq_for_each_segment(bv, req, iter) diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 06a2e53e5f3729..ef45cfb98fd2f1 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -553,16 +553,16 @@ static struct bio *ps3vram_do_bio(struct ps3_system_bus_device *dev, struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); int write = bio_data_dir(bio) == WRITE; const char *op = write ? "write" : "read"; - loff_t offset = bio->bi_sector << 9; + loff_t offset = bio->bi_iter.bi_sector << 9; int error = 0; - struct bio_vec *bvec; - unsigned int i; + struct bio_vec bvec; + struct bvec_iter iter; struct bio *next; - bio_for_each_segment(bvec, bio, i) { + bio_for_each_segment(bvec, bio, iter) { /* PS3 is ppc64, so we don't handle highmem */ - char *ptr = page_address(bvec->bv_page) + bvec->bv_offset; - size_t len = bvec->bv_len, retlen; + char *ptr = page_address(bvec.bv_page) + bvec.bv_offset; + size_t len = bvec.bv_len, retlen; dev_dbg(&dev->core, " %s %zu bytes at offset %llu\n", op, len, offset); diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index cb1db2979d3d7b..b365e0dfccb66f 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "rbd_types.h" @@ -89,9 +90,9 @@ static int atomic_dec_return_safe(atomic_t *v) } #define RBD_DRV_NAME "rbd" -#define RBD_DRV_NAME_LONG "rbd (rados block device)" -#define RBD_MINORS_PER_MAJOR 256 /* max minors per blkdev */ +#define RBD_MINORS_PER_MAJOR 256 +#define RBD_SINGLE_MAJOR_PART_SHIFT 4 #define RBD_SNAP_DEV_NAME_PREFIX "snap_" #define RBD_MAX_SNAP_NAME_LEN \ @@ -323,6 +324,7 @@ struct rbd_device { int dev_id; /* blkdev unique id */ int major; /* blkdev assigned major */ + int minor; struct gendisk *disk; /* blkdev's gendisk and rq */ u32 image_format; /* Either 1 or 2 */ @@ -386,6 +388,17 @@ static struct kmem_cache *rbd_img_request_cache; static struct kmem_cache *rbd_obj_request_cache; static struct kmem_cache *rbd_segment_name_cache; +static int rbd_major; +static DEFINE_IDA(rbd_dev_id_ida); + +/* + * Default to false for now, as single-major requires >= 0.75 version of + * userspace rbd utility. + */ +static bool single_major = false; +module_param(single_major, bool, S_IRUGO); +MODULE_PARM_DESC(single_major, "Use a single major number for all rbd devices (default: false)"); + static int rbd_img_request_submit(struct rbd_img_request *img_request); static void rbd_dev_device_release(struct device *dev); @@ -394,18 +407,52 @@ static ssize_t rbd_add(struct bus_type *bus, const char *buf, size_t count); static ssize_t rbd_remove(struct bus_type *bus, const char *buf, size_t count); +static ssize_t rbd_add_single_major(struct bus_type *bus, const char *buf, + size_t count); +static ssize_t rbd_remove_single_major(struct bus_type *bus, const char *buf, + size_t count); static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping); static void rbd_spec_put(struct rbd_spec *spec); +static int rbd_dev_id_to_minor(int dev_id) +{ + return dev_id << RBD_SINGLE_MAJOR_PART_SHIFT; +} + +static int minor_to_rbd_dev_id(int minor) +{ + return minor >> RBD_SINGLE_MAJOR_PART_SHIFT; +} + static BUS_ATTR(add, S_IWUSR, NULL, rbd_add); static BUS_ATTR(remove, S_IWUSR, NULL, rbd_remove); +static BUS_ATTR(add_single_major, S_IWUSR, NULL, rbd_add_single_major); +static BUS_ATTR(remove_single_major, S_IWUSR, NULL, rbd_remove_single_major); static struct attribute *rbd_bus_attrs[] = { &bus_attr_add.attr, &bus_attr_remove.attr, + &bus_attr_add_single_major.attr, + &bus_attr_remove_single_major.attr, NULL, }; -ATTRIBUTE_GROUPS(rbd_bus); + +static umode_t rbd_bus_is_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + if (!single_major && + (attr == &bus_attr_add_single_major.attr || + attr == &bus_attr_remove_single_major.attr)) + return 0; + + return attr->mode; +} + +static const struct attribute_group rbd_bus_group = { + .attrs = rbd_bus_attrs, + .is_visible = rbd_bus_is_visible, +}; +__ATTRIBUTE_GROUPS(rbd_bus); static struct bus_type rbd_bus_type = { .name = "rbd", @@ -1041,9 +1088,9 @@ static const char *rbd_segment_name(struct rbd_device *rbd_dev, u64 offset) name_format = "%s.%012llx"; if (rbd_dev->image_format == 2) name_format = "%s.%016llx"; - ret = snprintf(name, MAX_OBJ_NAME_SIZE + 1, name_format, + ret = snprintf(name, CEPH_MAX_OID_NAME_LEN + 1, name_format, rbd_dev->header.object_prefix, segment); - if (ret < 0 || ret > MAX_OBJ_NAME_SIZE) { + if (ret < 0 || ret > CEPH_MAX_OID_NAME_LEN) { pr_err("error formatting segment name for #%llu (%d)\n", segment, ret); kfree(name); @@ -1109,23 +1156,23 @@ static void bio_chain_put(struct bio *chain) */ static void zero_bio_chain(struct bio *chain, int start_ofs) { - struct bio_vec *bv; + struct bio_vec bv; + struct bvec_iter iter; unsigned long flags; void *buf; - int i; int pos = 0; while (chain) { - bio_for_each_segment(bv, chain, i) { - if (pos + bv->bv_len > start_ofs) { + bio_for_each_segment(bv, chain, iter) { + if (pos + bv.bv_len > start_ofs) { int remainder = max(start_ofs - pos, 0); - buf = bvec_kmap_irq(bv, &flags); + buf = bvec_kmap_irq(&bv, &flags); memset(buf + remainder, 0, - bv->bv_len - remainder); - flush_dcache_page(bv->bv_page); + bv.bv_len - remainder); + flush_dcache_page(bv.bv_page); bvec_kunmap_irq(buf, &flags); } - pos += bv->bv_len; + pos += bv.bv_len; } chain = chain->bi_next; @@ -1173,74 +1220,14 @@ static struct bio *bio_clone_range(struct bio *bio_src, unsigned int len, gfp_t gfpmask) { - struct bio_vec *bv; - unsigned int resid; - unsigned short idx; - unsigned int voff; - unsigned short end_idx; - unsigned short vcnt; struct bio *bio; - /* Handle the easy case for the caller */ - - if (!offset && len == bio_src->bi_size) - return bio_clone(bio_src, gfpmask); - - if (WARN_ON_ONCE(!len)) - return NULL; - if (WARN_ON_ONCE(len > bio_src->bi_size)) - return NULL; - if (WARN_ON_ONCE(offset > bio_src->bi_size - len)) - return NULL; - - /* Find first affected segment... */ - - resid = offset; - bio_for_each_segment(bv, bio_src, idx) { - if (resid < bv->bv_len) - break; - resid -= bv->bv_len; - } - voff = resid; - - /* ...and the last affected segment */ - - resid += len; - __bio_for_each_segment(bv, bio_src, end_idx, idx) { - if (resid <= bv->bv_len) - break; - resid -= bv->bv_len; - } - vcnt = end_idx - idx + 1; - - /* Build the clone */ - - bio = bio_alloc(gfpmask, (unsigned int) vcnt); + bio = bio_clone(bio_src, gfpmask); if (!bio) return NULL; /* ENOMEM */ - bio->bi_bdev = bio_src->bi_bdev; - bio->bi_sector = bio_src->bi_sector + (offset >> SECTOR_SHIFT); - bio->bi_rw = bio_src->bi_rw; - bio->bi_flags |= 1 << BIO_CLONED; - - /* - * Copy over our part of the bio_vec, then update the first - * and last (or only) entries. - */ - memcpy(&bio->bi_io_vec[0], &bio_src->bi_io_vec[idx], - vcnt * sizeof (struct bio_vec)); - bio->bi_io_vec[0].bv_offset += voff; - if (vcnt > 1) { - bio->bi_io_vec[0].bv_len -= voff; - bio->bi_io_vec[vcnt - 1].bv_len = resid; - } else { - bio->bi_io_vec[0].bv_len = len; - } - - bio->bi_vcnt = vcnt; - bio->bi_size = len; - bio->bi_idx = 0; + bio_advance(bio, offset); + bio->bi_iter.bi_size = len; return bio; } @@ -1271,7 +1258,7 @@ static struct bio *bio_chain_clone_range(struct bio **bio_src, /* Build up a chain of clone bios up to the limit */ - if (!bi || off >= bi->bi_size || !len) + if (!bi || off >= bi->bi_iter.bi_size || !len) return NULL; /* Nothing to clone */ end = &chain; @@ -1283,7 +1270,7 @@ static struct bio *bio_chain_clone_range(struct bio **bio_src, rbd_warn(NULL, "bio_chain exhausted with %u left", len); goto out_err; /* EINVAL; ran out of bio's */ } - bi_size = min_t(unsigned int, bi->bi_size - off, len); + bi_size = min_t(unsigned int, bi->bi_iter.bi_size - off, len); bio = bio_clone_range(bi, off, bi_size, gfpmask); if (!bio) goto out_err; /* ENOMEM */ @@ -1292,7 +1279,7 @@ static struct bio *bio_chain_clone_range(struct bio **bio_src, end = &bio->bi_next; off += bi_size; - if (off == bi->bi_size) { + if (off == bi->bi_iter.bi_size) { bi = bi->bi_next; off = 0; } @@ -1761,11 +1748,8 @@ static struct ceph_osd_request *rbd_osd_req_create( osd_req->r_callback = rbd_osd_req_callback; osd_req->r_priv = obj_request; - osd_req->r_oid_len = strlen(obj_request->object_name); - rbd_assert(osd_req->r_oid_len < sizeof (osd_req->r_oid)); - memcpy(osd_req->r_oid, obj_request->object_name, osd_req->r_oid_len); - - osd_req->r_file_layout = rbd_dev->layout; /* struct */ + osd_req->r_base_oloc.pool = ceph_file_layout_pg_pool(rbd_dev->layout); + ceph_oid_set_name(&osd_req->r_base_oid, obj_request->object_name); return osd_req; } @@ -1802,11 +1786,8 @@ rbd_osd_req_create_copyup(struct rbd_obj_request *obj_request) osd_req->r_callback = rbd_osd_req_callback; osd_req->r_priv = obj_request; - osd_req->r_oid_len = strlen(obj_request->object_name); - rbd_assert(osd_req->r_oid_len < sizeof (osd_req->r_oid)); - memcpy(osd_req->r_oid, obj_request->object_name, osd_req->r_oid_len); - - osd_req->r_file_layout = rbd_dev->layout; /* struct */ + osd_req->r_base_oloc.pool = ceph_file_layout_pg_pool(rbd_dev->layout); + ceph_oid_set_name(&osd_req->r_base_oid, obj_request->object_name); return osd_req; } @@ -2186,7 +2167,8 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request, if (type == OBJ_REQUEST_BIO) { bio_list = data_desc; - rbd_assert(img_offset == bio_list->bi_sector << SECTOR_SHIFT); + rbd_assert(img_offset == + bio_list->bi_iter.bi_sector << SECTOR_SHIFT); } else { rbd_assert(type == OBJ_REQUEST_PAGES); pages = data_desc; @@ -2866,7 +2848,7 @@ static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data) * Request sync osd watch/unwatch. The value of "start" determines * whether a watch request is being initiated or torn down. */ -static int rbd_dev_header_watch_sync(struct rbd_device *rbd_dev, bool start) +static int __rbd_dev_header_watch_sync(struct rbd_device *rbd_dev, bool start) { struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc; struct rbd_obj_request *obj_request; @@ -2941,6 +2923,22 @@ static int rbd_dev_header_watch_sync(struct rbd_device *rbd_dev, bool start) return ret; } +static int rbd_dev_header_watch_sync(struct rbd_device *rbd_dev) +{ + return __rbd_dev_header_watch_sync(rbd_dev, true); +} + +static void rbd_dev_header_unwatch_sync(struct rbd_device *rbd_dev) +{ + int ret; + + ret = __rbd_dev_header_watch_sync(rbd_dev, false); + if (ret) { + rbd_warn(rbd_dev, "unable to tear down watch request: %d\n", + ret); + } +} + /* * Synchronous osd object method call. Returns the number of bytes * returned in the outbound buffer, or a negative error code. @@ -3388,14 +3386,18 @@ static int rbd_init_disk(struct rbd_device *rbd_dev) u64 segment_size; /* create gendisk info */ - disk = alloc_disk(RBD_MINORS_PER_MAJOR); + disk = alloc_disk(single_major ? + (1 << RBD_SINGLE_MAJOR_PART_SHIFT) : + RBD_MINORS_PER_MAJOR); if (!disk) return -ENOMEM; snprintf(disk->disk_name, sizeof(disk->disk_name), RBD_DRV_NAME "%d", rbd_dev->dev_id); disk->major = rbd_dev->major; - disk->first_minor = 0; + disk->first_minor = rbd_dev->minor; + if (single_major) + disk->flags |= GENHD_FL_EXT_DEVT; disk->fops = &rbd_bd_ops; disk->private_data = rbd_dev; @@ -3467,7 +3469,14 @@ static ssize_t rbd_major_show(struct device *dev, return sprintf(buf, "%d\n", rbd_dev->major); return sprintf(buf, "(none)\n"); +} + +static ssize_t rbd_minor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); + return sprintf(buf, "%d\n", rbd_dev->minor); } static ssize_t rbd_client_id_show(struct device *dev, @@ -3589,6 +3598,7 @@ static ssize_t rbd_image_refresh(struct device *dev, static DEVICE_ATTR(size, S_IRUGO, rbd_size_show, NULL); static DEVICE_ATTR(features, S_IRUGO, rbd_features_show, NULL); static DEVICE_ATTR(major, S_IRUGO, rbd_major_show, NULL); +static DEVICE_ATTR(minor, S_IRUGO, rbd_minor_show, NULL); static DEVICE_ATTR(client_id, S_IRUGO, rbd_client_id_show, NULL); static DEVICE_ATTR(pool, S_IRUGO, rbd_pool_show, NULL); static DEVICE_ATTR(pool_id, S_IRUGO, rbd_pool_id_show, NULL); @@ -3602,6 +3612,7 @@ static struct attribute *rbd_attrs[] = { &dev_attr_size.attr, &dev_attr_features.attr, &dev_attr_major.attr, + &dev_attr_minor.attr, &dev_attr_client_id.attr, &dev_attr_pool.attr, &dev_attr_pool_id.attr, @@ -4372,21 +4383,29 @@ static void rbd_bus_del_dev(struct rbd_device *rbd_dev) device_unregister(&rbd_dev->dev); } -static atomic64_t rbd_dev_id_max = ATOMIC64_INIT(0); - /* * Get a unique rbd identifier for the given new rbd_dev, and add - * the rbd_dev to the global list. The minimum rbd id is 1. + * the rbd_dev to the global list. */ -static void rbd_dev_id_get(struct rbd_device *rbd_dev) +static int rbd_dev_id_get(struct rbd_device *rbd_dev) { - rbd_dev->dev_id = atomic64_inc_return(&rbd_dev_id_max); + int new_dev_id; + + new_dev_id = ida_simple_get(&rbd_dev_id_ida, + 0, minor_to_rbd_dev_id(1 << MINORBITS), + GFP_KERNEL); + if (new_dev_id < 0) + return new_dev_id; + + rbd_dev->dev_id = new_dev_id; spin_lock(&rbd_dev_list_lock); list_add_tail(&rbd_dev->node, &rbd_dev_list); spin_unlock(&rbd_dev_list_lock); - dout("rbd_dev %p given dev id %llu\n", rbd_dev, - (unsigned long long) rbd_dev->dev_id); + + dout("rbd_dev %p given dev id %d\n", rbd_dev, rbd_dev->dev_id); + + return 0; } /* @@ -4395,49 +4414,13 @@ static void rbd_dev_id_get(struct rbd_device *rbd_dev) */ static void rbd_dev_id_put(struct rbd_device *rbd_dev) { - struct list_head *tmp; - int rbd_id = rbd_dev->dev_id; - int max_id; - - rbd_assert(rbd_id > 0); - - dout("rbd_dev %p released dev id %llu\n", rbd_dev, - (unsigned long long) rbd_dev->dev_id); spin_lock(&rbd_dev_list_lock); list_del_init(&rbd_dev->node); - - /* - * If the id being "put" is not the current maximum, there - * is nothing special we need to do. - */ - if (rbd_id != atomic64_read(&rbd_dev_id_max)) { - spin_unlock(&rbd_dev_list_lock); - return; - } - - /* - * We need to update the current maximum id. Search the - * list to find out what it is. We're more likely to find - * the maximum at the end, so search the list backward. - */ - max_id = 0; - list_for_each_prev(tmp, &rbd_dev_list) { - struct rbd_device *rbd_dev; - - rbd_dev = list_entry(tmp, struct rbd_device, node); - if (rbd_dev->dev_id > max_id) - max_id = rbd_dev->dev_id; - } spin_unlock(&rbd_dev_list_lock); - /* - * The max id could have been updated by rbd_dev_id_get(), in - * which case it now accurately reflects the new maximum. - * Be careful not to overwrite the maximum value in that - * case. - */ - atomic64_cmpxchg(&rbd_dev_id_max, rbd_id, max_id); - dout(" max dev id has been reset\n"); + ida_simple_remove(&rbd_dev_id_ida, rbd_dev->dev_id); + + dout("rbd_dev %p released dev id %d\n", rbd_dev, rbd_dev->dev_id); } /* @@ -4860,20 +4843,29 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev) { int ret; - /* generate unique id: find highest unique id, add one */ - rbd_dev_id_get(rbd_dev); + /* Get an id and fill in device name. */ + + ret = rbd_dev_id_get(rbd_dev); + if (ret) + return ret; - /* Fill in the device name, now that we have its id. */ BUILD_BUG_ON(DEV_NAME_LEN < sizeof (RBD_DRV_NAME) + MAX_INT_FORMAT_WIDTH); sprintf(rbd_dev->name, "%s%d", RBD_DRV_NAME, rbd_dev->dev_id); - /* Get our block major device number. */ + /* Record our major and minor device numbers. */ - ret = register_blkdev(0, rbd_dev->name); - if (ret < 0) - goto err_out_id; - rbd_dev->major = ret; + if (!single_major) { + ret = register_blkdev(0, rbd_dev->name); + if (ret < 0) + goto err_out_id; + + rbd_dev->major = ret; + rbd_dev->minor = 0; + } else { + rbd_dev->major = rbd_major; + rbd_dev->minor = rbd_dev_id_to_minor(rbd_dev->dev_id); + } /* Set up the blkdev mapping. */ @@ -4905,7 +4897,8 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev) err_out_disk: rbd_free_disk(rbd_dev); err_out_blkdev: - unregister_blkdev(rbd_dev->major, rbd_dev->name); + if (!single_major) + unregister_blkdev(rbd_dev->major, rbd_dev->name); err_out_id: rbd_dev_id_put(rbd_dev); rbd_dev_mapping_clear(rbd_dev); @@ -4961,7 +4954,6 @@ static void rbd_dev_image_release(struct rbd_device *rbd_dev) static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) { int ret; - int tmp; /* * Get the id from the image id object. Unless there's an @@ -4980,7 +4972,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) goto err_out_format; if (mapping) { - ret = rbd_dev_header_watch_sync(rbd_dev, true); + ret = rbd_dev_header_watch_sync(rbd_dev); if (ret) goto out_header_name; } @@ -5007,12 +4999,8 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) err_out_probe: rbd_dev_unprobe(rbd_dev); err_out_watch: - if (mapping) { - tmp = rbd_dev_header_watch_sync(rbd_dev, false); - if (tmp) - rbd_warn(rbd_dev, "unable to tear down " - "watch request (%d)\n", tmp); - } + if (mapping) + rbd_dev_header_unwatch_sync(rbd_dev); out_header_name: kfree(rbd_dev->header_name); rbd_dev->header_name = NULL; @@ -5026,9 +5014,9 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) return ret; } -static ssize_t rbd_add(struct bus_type *bus, - const char *buf, - size_t count) +static ssize_t do_rbd_add(struct bus_type *bus, + const char *buf, + size_t count) { struct rbd_device *rbd_dev = NULL; struct ceph_options *ceph_opts = NULL; @@ -5090,6 +5078,12 @@ static ssize_t rbd_add(struct bus_type *bus, rc = rbd_dev_device_setup(rbd_dev); if (rc) { + /* + * rbd_dev_header_unwatch_sync() can't be moved into + * rbd_dev_image_release() without refactoring, see + * commit 1f3ef78861ac. + */ + rbd_dev_header_unwatch_sync(rbd_dev); rbd_dev_image_release(rbd_dev); goto err_out_module; } @@ -5110,6 +5104,23 @@ static ssize_t rbd_add(struct bus_type *bus, return (ssize_t)rc; } +static ssize_t rbd_add(struct bus_type *bus, + const char *buf, + size_t count) +{ + if (single_major) + return -EINVAL; + + return do_rbd_add(bus, buf, count); +} + +static ssize_t rbd_add_single_major(struct bus_type *bus, + const char *buf, + size_t count) +{ + return do_rbd_add(bus, buf, count); +} + static void rbd_dev_device_release(struct device *dev) { struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); @@ -5117,8 +5128,8 @@ static void rbd_dev_device_release(struct device *dev) rbd_free_disk(rbd_dev); clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags); rbd_dev_mapping_clear(rbd_dev); - unregister_blkdev(rbd_dev->major, rbd_dev->name); - rbd_dev->major = 0; + if (!single_major) + unregister_blkdev(rbd_dev->major, rbd_dev->name); rbd_dev_id_put(rbd_dev); rbd_dev_mapping_clear(rbd_dev); } @@ -5149,9 +5160,9 @@ static void rbd_dev_remove_parent(struct rbd_device *rbd_dev) } } -static ssize_t rbd_remove(struct bus_type *bus, - const char *buf, - size_t count) +static ssize_t do_rbd_remove(struct bus_type *bus, + const char *buf, + size_t count) { struct rbd_device *rbd_dev = NULL; struct list_head *tmp; @@ -5191,16 +5202,14 @@ static ssize_t rbd_remove(struct bus_type *bus, if (ret < 0 || already) return ret; - ret = rbd_dev_header_watch_sync(rbd_dev, false); - if (ret) - rbd_warn(rbd_dev, "failed to cancel watch event (%d)\n", ret); - + rbd_dev_header_unwatch_sync(rbd_dev); /* * flush remaining watch callbacks - these must be complete * before the osd_client is shutdown */ dout("%s: flushing notifies", __func__); ceph_osdc_flush_notifies(&rbd_dev->rbd_client->client->osdc); + /* * Don't free anything from rbd_dev->disk until after all * notifies are completely processed. Otherwise @@ -5214,6 +5223,23 @@ static ssize_t rbd_remove(struct bus_type *bus, return count; } +static ssize_t rbd_remove(struct bus_type *bus, + const char *buf, + size_t count) +{ + if (single_major) + return -EINVAL; + + return do_rbd_remove(bus, buf, count); +} + +static ssize_t rbd_remove_single_major(struct bus_type *bus, + const char *buf, + size_t count) +{ + return do_rbd_remove(bus, buf, count); +} + /* * create control files in sysfs * /sys/bus/rbd/... @@ -5259,7 +5285,7 @@ static int rbd_slab_init(void) rbd_assert(!rbd_segment_name_cache); rbd_segment_name_cache = kmem_cache_create("rbd_segment_name", - MAX_OBJ_NAME_SIZE + 1, 1, 0, NULL); + CEPH_MAX_OID_NAME_LEN + 1, 1, 0, NULL); if (rbd_segment_name_cache) return 0; out_err: @@ -5295,24 +5321,45 @@ static int __init rbd_init(void) if (!libceph_compatible(NULL)) { rbd_warn(NULL, "libceph incompatibility (quitting)"); - return -EINVAL; } + rc = rbd_slab_init(); if (rc) return rc; + + if (single_major) { + rbd_major = register_blkdev(0, RBD_DRV_NAME); + if (rbd_major < 0) { + rc = rbd_major; + goto err_out_slab; + } + } + rc = rbd_sysfs_init(); if (rc) - rbd_slab_exit(); + goto err_out_blkdev; + + if (single_major) + pr_info("loaded (major %d)\n", rbd_major); else - pr_info("loaded " RBD_DRV_NAME_LONG "\n"); + pr_info("loaded\n"); + + return 0; +err_out_blkdev: + if (single_major) + unregister_blkdev(rbd_major, RBD_DRV_NAME); +err_out_slab: + rbd_slab_exit(); return rc; } static void __exit rbd_exit(void) { rbd_sysfs_cleanup(); + if (single_major) + unregister_blkdev(rbd_major, RBD_DRV_NAME); rbd_slab_exit(); } @@ -5322,9 +5369,8 @@ module_exit(rbd_exit); MODULE_AUTHOR("Alex Elder "); MODULE_AUTHOR("Sage Weil "); MODULE_AUTHOR("Yehuda Sadeh "); -MODULE_DESCRIPTION("rados block device"); - /* following authorship retained from original osdblk.c */ MODULE_AUTHOR("Jeff Garzik "); +MODULE_DESCRIPTION("RADOS Block Device (RBD) driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/block/rsxx/dev.c b/drivers/block/rsxx/dev.c index 2284f5d3a54ad0..2839d37e5af779 100644 --- a/drivers/block/rsxx/dev.c +++ b/drivers/block/rsxx/dev.c @@ -174,7 +174,7 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio) if (!card) goto req_err; - if (bio->bi_sector + (bio->bi_size >> 9) > get_capacity(card->gendisk)) + if (bio_end_sector(bio) > get_capacity(card->gendisk)) goto req_err; if (unlikely(card->halt)) { @@ -187,7 +187,7 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio) goto req_err; } - if (bio->bi_size == 0) { + if (bio->bi_iter.bi_size == 0) { dev_err(CARD_TO_DEV(card), "size zero BIO!\n"); goto req_err; } @@ -208,7 +208,7 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio) dev_dbg(CARD_TO_DEV(card), "BIO[%c]: meta: %p addr8: x%llx size: %d\n", bio_data_dir(bio) ? 'W' : 'R', bio_meta, - (u64)bio->bi_sector << 9, bio->bi_size); + (u64)bio->bi_iter.bi_sector << 9, bio->bi_iter.bi_size); st = rsxx_dma_queue_bio(card, bio, &bio_meta->pending_dmas, bio_dma_done_cb, bio_meta); diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index fc88ba3e1bd278..cf8cd293abb51d 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -684,7 +684,8 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card, void *cb_data) { struct list_head dma_list[RSXX_MAX_TARGETS]; - struct bio_vec *bvec; + struct bio_vec bvec; + struct bvec_iter iter; unsigned long long addr8; unsigned int laddr; unsigned int bv_len; @@ -696,7 +697,7 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card, int st; int i; - addr8 = bio->bi_sector << 9; /* sectors are 512 bytes */ + addr8 = bio->bi_iter.bi_sector << 9; /* sectors are 512 bytes */ atomic_set(n_dmas, 0); for (i = 0; i < card->n_targets; i++) { @@ -705,7 +706,7 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card, } if (bio->bi_rw & REQ_DISCARD) { - bv_len = bio->bi_size; + bv_len = bio->bi_iter.bi_size; while (bv_len > 0) { tgt = rsxx_get_dma_tgt(card, addr8); @@ -722,9 +723,9 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card, bv_len -= RSXX_HW_BLK_SIZE; } } else { - bio_for_each_segment(bvec, bio, i) { - bv_len = bvec->bv_len; - bv_off = bvec->bv_offset; + bio_for_each_segment(bvec, bio, iter) { + bv_len = bvec.bv_len; + bv_off = bvec.bv_offset; while (bv_len > 0) { tgt = rsxx_get_dma_tgt(card, addr8); @@ -736,7 +737,7 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card, st = rsxx_queue_dma(card, &dma_list[tgt], bio_data_dir(bio), dma_off, dma_len, - laddr, bvec->bv_page, + laddr, bvec.bv_page, bv_off, cb, cb_data); if (st) goto bvec_err; diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index 3fb6ab4c8b4e9e..d5e2d12b9d9e32 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -1744,20 +1744,6 @@ static void carm_remove_one (struct pci_dev *pdev) kfree(host); pci_release_regions(pdev); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); } -static int __init carm_init(void) -{ - return pci_register_driver(&carm_driver); -} - -static void __exit carm_exit(void) -{ - pci_unregister_driver(&carm_driver); -} - -module_init(carm_init); -module_exit(carm_exit); - - +module_pci_driver(carm_driver); diff --git a/drivers/block/umem.c b/drivers/block/umem.c index ad70868f8a967b..4cf81b5bf0f7fb 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -108,8 +108,7 @@ struct cardinfo { * have been written */ struct bio *bio, *currentbio, **biotail; - int current_idx; - sector_t current_sector; + struct bvec_iter current_iter; struct request_queue *queue; @@ -118,7 +117,7 @@ struct cardinfo { struct mm_dma_desc *desc; int cnt, headcnt; struct bio *bio, **biotail; - int idx; + struct bvec_iter iter; } mm_pages[2]; #define DESC_PER_PAGE ((PAGE_SIZE*2)/sizeof(struct mm_dma_desc)) @@ -344,16 +343,13 @@ static int add_bio(struct cardinfo *card) dma_addr_t dma_handle; int offset; struct bio *bio; - struct bio_vec *vec; - int idx; + struct bio_vec vec; int rw; - int len; bio = card->currentbio; if (!bio && card->bio) { card->currentbio = card->bio; - card->current_idx = card->bio->bi_idx; - card->current_sector = card->bio->bi_sector; + card->current_iter = card->bio->bi_iter; card->bio = card->bio->bi_next; if (card->bio == NULL) card->biotail = &card->bio; @@ -362,18 +358,17 @@ static int add_bio(struct cardinfo *card) } if (!bio) return 0; - idx = card->current_idx; rw = bio_rw(bio); if (card->mm_pages[card->Ready].cnt >= DESC_PER_PAGE) return 0; - vec = bio_iovec_idx(bio, idx); - len = vec->bv_len; + vec = bio_iter_iovec(bio, card->current_iter); + dma_handle = pci_map_page(card->dev, - vec->bv_page, - vec->bv_offset, - len, + vec.bv_page, + vec.bv_offset, + vec.bv_len, (rw == READ) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); @@ -381,7 +376,7 @@ static int add_bio(struct cardinfo *card) desc = &p->desc[p->cnt]; p->cnt++; if (p->bio == NULL) - p->idx = idx; + p->iter = card->current_iter; if ((p->biotail) != &bio->bi_next) { *(p->biotail) = bio; p->biotail = &(bio->bi_next); @@ -391,8 +386,8 @@ static int add_bio(struct cardinfo *card) desc->data_dma_handle = dma_handle; desc->pci_addr = cpu_to_le64((u64)desc->data_dma_handle); - desc->local_addr = cpu_to_le64(card->current_sector << 9); - desc->transfer_size = cpu_to_le32(len); + desc->local_addr = cpu_to_le64(card->current_iter.bi_sector << 9); + desc->transfer_size = cpu_to_le32(vec.bv_len); offset = (((char *)&desc->sem_control_bits) - ((char *)p->desc)); desc->sem_addr = cpu_to_le64((u64)(p->page_dma+offset)); desc->zero1 = desc->zero2 = 0; @@ -407,10 +402,9 @@ static int add_bio(struct cardinfo *card) desc->control_bits |= cpu_to_le32(DMASCR_TRANSFER_READ); desc->sem_control_bits = desc->control_bits; - card->current_sector += (len >> 9); - idx++; - card->current_idx = idx; - if (idx >= bio->bi_vcnt) + + bio_advance_iter(bio, &card->current_iter, vec.bv_len); + if (!card->current_iter.bi_size) card->currentbio = NULL; return 1; @@ -439,23 +433,25 @@ static void process_page(unsigned long data) struct mm_dma_desc *desc = &page->desc[page->headcnt]; int control = le32_to_cpu(desc->sem_control_bits); int last = 0; - int idx; + struct bio_vec vec; if (!(control & DMASCR_DMA_COMPLETE)) { control = dma_status; last = 1; } + page->headcnt++; - idx = page->idx; - page->idx++; - if (page->idx >= bio->bi_vcnt) { + vec = bio_iter_iovec(bio, page->iter); + bio_advance_iter(bio, &page->iter, vec.bv_len); + + if (!page->iter.bi_size) { page->bio = bio->bi_next; if (page->bio) - page->idx = page->bio->bi_idx; + page->iter = page->bio->bi_iter; } pci_unmap_page(card->dev, desc->data_dma_handle, - bio_iovec_idx(bio, idx)->bv_len, + vec.bv_len, (control & DMASCR_TRANSFER_READ) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); if (control & DMASCR_HARD_ERROR) { @@ -532,7 +528,8 @@ static void mm_make_request(struct request_queue *q, struct bio *bio) { struct cardinfo *card = q->queuedata; pr_debug("mm_make_request %llu %u\n", - (unsigned long long)bio->bi_sector, bio->bi_size); + (unsigned long long)bio->bi_iter.bi_sector, + bio->bi_iter.bi_size); spin_lock_irq(&card->lock); *card->biotail = bio; diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 6a680d4de7f1c3..b1cb3f4c4db455 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -110,9 +110,9 @@ static int __virtblk_add_req(struct virtqueue *vq, return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC); } -static inline void virtblk_request_done(struct virtblk_req *vbr) +static inline void virtblk_request_done(struct request *req) { - struct request *req = vbr->req; + struct virtblk_req *vbr = req->special; int error = virtblk_result(vbr); if (req->cmd_type == REQ_TYPE_BLOCK_PC) { @@ -138,7 +138,7 @@ static void virtblk_done(struct virtqueue *vq) do { virtqueue_disable_cb(vq); while ((vbr = virtqueue_get_buf(vblk->vq, &len)) != NULL) { - virtblk_request_done(vbr); + blk_mq_complete_request(vbr->req); req_done = true; } if (unlikely(virtqueue_is_broken(vq))) @@ -479,6 +479,7 @@ static struct blk_mq_ops virtio_mq_ops = { .map_queue = blk_mq_map_queue, .alloc_hctx = blk_mq_alloc_single_hw_queue, .free_hctx = blk_mq_free_single_hw_queue, + .complete = virtblk_request_done, }; static struct blk_mq_reg virtio_mq_reg = { diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 6620b73d049061..64c60edcdfbc55 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -299,7 +299,7 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root, BUG_ON(num != 0); } -static void unmap_purged_grants(struct work_struct *work) +void xen_blkbk_unmap_purged_grants(struct work_struct *work) { struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; @@ -375,7 +375,7 @@ static void purge_persistent_gnt(struct xen_blkif *blkif) pr_debug(DRV_PFX "Going to purge %u persistent grants\n", num_clean); - INIT_LIST_HEAD(&blkif->persistent_purge_list); + BUG_ON(!list_empty(&blkif->persistent_purge_list)); root = &blkif->persistent_gnts; purge_list: foreach_grant_safe(persistent_gnt, n, root, node) { @@ -420,7 +420,6 @@ static void purge_persistent_gnt(struct xen_blkif *blkif) blkif->vbd.overflow_max_grants = 0; /* We can defer this work */ - INIT_WORK(&blkif->persistent_purge_work, unmap_purged_grants); schedule_work(&blkif->persistent_purge_work); pr_debug(DRV_PFX "Purged %u/%u\n", (total - num_clean), total); return; @@ -625,9 +624,23 @@ int xen_blkif_schedule(void *arg) print_stats(blkif); } - /* Since we are shutting down remove all pages from the buffer */ - shrink_free_pagepool(blkif, 0 /* All */); + /* Drain pending purge work */ + flush_work(&blkif->persistent_purge_work); + if (log_stats) + print_stats(blkif); + + blkif->xenblkd = NULL; + xen_blkif_put(blkif); + + return 0; +} + +/* + * Remove persistent grants and empty the pool of free pages + */ +void xen_blkbk_free_caches(struct xen_blkif *blkif) +{ /* Free all persistent grant pages */ if (!RB_EMPTY_ROOT(&blkif->persistent_gnts)) free_persistent_gnts(blkif, &blkif->persistent_gnts, @@ -636,13 +649,8 @@ int xen_blkif_schedule(void *arg) BUG_ON(!RB_EMPTY_ROOT(&blkif->persistent_gnts)); blkif->persistent_gnt_c = 0; - if (log_stats) - print_stats(blkif); - - blkif->xenblkd = NULL; - xen_blkif_put(blkif); - - return 0; + /* Since we are shutting down remove all pages from the buffer */ + shrink_free_pagepool(blkif, 0 /* All */); } /* @@ -838,7 +846,7 @@ static int xen_blkbk_parse_indirect(struct blkif_request *req, struct grant_page **pages = pending_req->indirect_pages; struct xen_blkif *blkif = pending_req->blkif; int indirect_grefs, rc, n, nseg, i; - struct blkif_request_segment_aligned *segments = NULL; + struct blkif_request_segment *segments = NULL; nseg = pending_req->nr_pages; indirect_grefs = INDIRECT_PAGES(nseg); @@ -934,9 +942,7 @@ static void xen_blk_drain_io(struct xen_blkif *blkif) { atomic_set(&blkif->drain, 1); do { - /* The initial value is one, and one refcnt taken at the - * start of the xen_blkif_schedule thread. */ - if (atomic_read(&blkif->refcnt) <= 2) + if (atomic_read(&blkif->inflight) == 0) break; wait_for_completion_interruptible_timeout( &blkif->drain_complete, HZ); @@ -976,17 +982,30 @@ static void __end_block_io_op(struct pending_req *pending_req, int error) * the proper response on the ring. */ if (atomic_dec_and_test(&pending_req->pendcnt)) { - xen_blkbk_unmap(pending_req->blkif, + struct xen_blkif *blkif = pending_req->blkif; + + xen_blkbk_unmap(blkif, pending_req->segments, pending_req->nr_pages); - make_response(pending_req->blkif, pending_req->id, + make_response(blkif, pending_req->id, pending_req->operation, pending_req->status); - xen_blkif_put(pending_req->blkif); - if (atomic_read(&pending_req->blkif->refcnt) <= 2) { - if (atomic_read(&pending_req->blkif->drain)) - complete(&pending_req->blkif->drain_complete); + free_req(blkif, pending_req); + /* + * Make sure the request is freed before releasing blkif, + * or there could be a race between free_req and the + * cleanup done in xen_blkif_free during shutdown. + * + * NB: The fact that we might try to wake up pending_free_wq + * before drain_complete (in case there's a drain going on) + * it's not a problem with our current implementation + * because we can assure there's no thread waiting on + * pending_free_wq if there's a drain going on, but it has + * to be taken into account if the current model is changed. + */ + if (atomic_dec_and_test(&blkif->inflight) && atomic_read(&blkif->drain)) { + complete(&blkif->drain_complete); } - free_req(pending_req->blkif, pending_req); + xen_blkif_put(blkif); } } @@ -1240,6 +1259,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, * below (in "!bio") if we are handling a BLKIF_OP_DISCARD. */ xen_blkif_get(blkif); + atomic_inc(&blkif->inflight); for (i = 0; i < nseg; i++) { while ((bio == NULL) || @@ -1257,7 +1277,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, bio->bi_bdev = preq.bdev; bio->bi_private = pending_req; bio->bi_end_io = end_block_io_op; - bio->bi_sector = preq.sector_number; + bio->bi_iter.bi_sector = preq.sector_number; } preq.sector_number += seg[i].nsec; diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index 8d8807563d9967..be052773ad03c1 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -57,7 +57,7 @@ #define MAX_INDIRECT_SEGMENTS 256 #define SEGS_PER_INDIRECT_FRAME \ - (PAGE_SIZE/sizeof(struct blkif_request_segment_aligned)) + (PAGE_SIZE/sizeof(struct blkif_request_segment)) #define MAX_INDIRECT_PAGES \ ((MAX_INDIRECT_SEGMENTS + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME) #define INDIRECT_PAGES(_segs) \ @@ -278,6 +278,7 @@ struct xen_blkif { /* for barrier (drain) requests */ struct completion drain_complete; atomic_t drain; + atomic_t inflight; /* One thread per one blkif. */ struct task_struct *xenblkd; unsigned int waiting_reqs; @@ -376,6 +377,7 @@ int xen_blkif_xenbus_init(void); irqreturn_t xen_blkif_be_int(int irq, void *dev_id); int xen_blkif_schedule(void *arg); int xen_blkif_purge_persistent(void *arg); +void xen_blkbk_free_caches(struct xen_blkif *blkif); int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt, struct backend_info *be, int state); @@ -383,6 +385,7 @@ int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt, int xen_blkbk_barrier(struct xenbus_transaction xbt, struct backend_info *be, int state); struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be); +void xen_blkbk_unmap_purged_grants(struct work_struct *work); static inline void blkif_get_x86_32_req(struct blkif_request *dst, struct blkif_x86_32_request *src) diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index c2014a0aa206b2..9a547e6b6ebf02 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -125,8 +125,11 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid) blkif->persistent_gnts.rb_node = NULL; spin_lock_init(&blkif->free_pages_lock); INIT_LIST_HEAD(&blkif->free_pages); + INIT_LIST_HEAD(&blkif->persistent_purge_list); blkif->free_pages_num = 0; atomic_set(&blkif->persistent_gnt_in_use, 0); + atomic_set(&blkif->inflight, 0); + INIT_WORK(&blkif->persistent_purge_work, xen_blkbk_unmap_purged_grants); INIT_LIST_HEAD(&blkif->pending_free); @@ -259,6 +262,17 @@ static void xen_blkif_free(struct xen_blkif *blkif) if (!atomic_dec_and_test(&blkif->refcnt)) BUG(); + /* Remove all persistent grants and the cache of ballooned pages. */ + xen_blkbk_free_caches(blkif); + + /* Make sure everything is drained before shutting down */ + BUG_ON(blkif->persistent_gnt_c != 0); + BUG_ON(atomic_read(&blkif->persistent_gnt_in_use) != 0); + BUG_ON(blkif->free_pages_num != 0); + BUG_ON(!list_empty(&blkif->persistent_purge_list)); + BUG_ON(!list_empty(&blkif->free_pages)); + BUG_ON(!RB_EMPTY_ROOT(&blkif->persistent_gnts)); + /* Check that there is no request in use */ list_for_each_entry_safe(req, n, &blkif->pending_free, free_list) { list_del(&req->free_list); diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index f9c43f91f03e5d..efe1b4761735a7 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -162,7 +162,7 @@ static DEFINE_SPINLOCK(minor_lock); #define DEV_NAME "xvd" /* name in /dev */ #define SEGS_PER_INDIRECT_FRAME \ - (PAGE_SIZE/sizeof(struct blkif_request_segment_aligned)) + (PAGE_SIZE/sizeof(struct blkif_request_segment)) #define INDIRECT_GREFS(_segs) \ ((_segs + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME) @@ -393,7 +393,7 @@ static int blkif_queue_request(struct request *req) unsigned long id; unsigned int fsect, lsect; int i, ref, n; - struct blkif_request_segment_aligned *segments = NULL; + struct blkif_request_segment *segments = NULL; /* * Used to store if we are able to queue the request by just using @@ -550,7 +550,7 @@ static int blkif_queue_request(struct request *req) } else { n = i % SEGS_PER_INDIRECT_FRAME; segments[n] = - (struct blkif_request_segment_aligned) { + (struct blkif_request_segment) { .gref = ref, .first_sect = fsect, .last_sect = lsect }; @@ -1547,7 +1547,7 @@ static int blkif_recover(struct blkfront_info *info) for (i = 0; i < pending; i++) { offset = (i * segs * PAGE_SIZE) >> 9; size = min((unsigned int)(segs * PAGE_SIZE) >> 9, - (unsigned int)(bio->bi_size >> 9) - offset); + (unsigned int)bio_sectors(bio) - offset); cloned_bio = bio_clone(bio, GFP_NOIO); BUG_ON(cloned_bio == NULL); bio_trim(cloned_bio, offset, size); @@ -1904,13 +1904,16 @@ static void blkback_changed(struct xenbus_device *dev, case XenbusStateReconfiguring: case XenbusStateReconfigured: case XenbusStateUnknown: - case XenbusStateClosed: break; case XenbusStateConnected: blkfront_connect(info); break; + case XenbusStateClosed: + if (dev->state == XenbusStateClosed) + break; + /* Missed the backend's Closing state -- fallthrough */ case XenbusStateClosing: blkfront_closing(info); break; diff --git a/drivers/staging/zram/Kconfig b/drivers/block/zram/Kconfig similarity index 93% rename from drivers/staging/zram/Kconfig rename to drivers/block/zram/Kconfig index 983314c4134966..3450be85039943 100644 --- a/drivers/staging/zram/Kconfig +++ b/drivers/block/zram/Kconfig @@ -14,7 +14,6 @@ config ZRAM disks and maybe many more. See zram.txt for more information. - Project home: config ZRAM_DEBUG bool "Compressed RAM block device debug support" diff --git a/drivers/staging/zram/Makefile b/drivers/block/zram/Makefile similarity index 100% rename from drivers/staging/zram/Makefile rename to drivers/block/zram/Makefile diff --git a/drivers/staging/zram/zram_drv.c b/drivers/block/zram/zram_drv.c similarity index 87% rename from drivers/staging/zram/zram_drv.c rename to drivers/block/zram/zram_drv.c index 3277d9838f4e92..011e55d820b181 100644 --- a/drivers/staging/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -2,6 +2,7 @@ * Compressed RAM block device * * Copyright (C) 2008, 2009, 2010 Nitin Gupta + * 2012, 2013 Minchan Kim * * This code is released using a dual license strategy: BSD/GPL * You can choose the licence that better fits your requirements. @@ -9,7 +10,6 @@ * Released under the terms of 3-clause BSD License * Released under the terms of GNU General Public License Version 2.0 * - * Project home: http://compcache.googlecode.com */ #define KMSG_COMPONENT "zram" @@ -104,7 +104,7 @@ static ssize_t zero_pages_show(struct device *dev, { struct zram *zram = dev_to_zram(dev); - return sprintf(buf, "%u\n", zram->stats.pages_zero); + return sprintf(buf, "%u\n", atomic_read(&zram->stats.pages_zero)); } static ssize_t orig_data_size_show(struct device *dev, @@ -113,7 +113,7 @@ static ssize_t orig_data_size_show(struct device *dev, struct zram *zram = dev_to_zram(dev); return sprintf(buf, "%llu\n", - (u64)(zram->stats.pages_stored) << PAGE_SHIFT); + (u64)(atomic_read(&zram->stats.pages_stored)) << PAGE_SHIFT); } static ssize_t compr_data_size_show(struct device *dev, @@ -140,6 +140,7 @@ static ssize_t mem_used_total_show(struct device *dev, return sprintf(buf, "%llu\n", val); } +/* flag operations needs meta->tb_lock */ static int zram_test_flag(struct zram_meta *meta, u32 index, enum zram_pageflags flag) { @@ -171,13 +172,14 @@ static inline int valid_io_request(struct zram *zram, struct bio *bio) u64 start, end, bound; /* unaligned request */ - if (unlikely(bio->bi_sector & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1))) + if (unlikely(bio->bi_iter.bi_sector & + (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1))) return 0; - if (unlikely(bio->bi_size & (ZRAM_LOGICAL_BLOCK_SIZE - 1))) + if (unlikely(bio->bi_iter.bi_size & (ZRAM_LOGICAL_BLOCK_SIZE - 1))) return 0; - start = bio->bi_sector; - end = start + (bio->bi_size >> SECTOR_SHIFT); + start = bio->bi_iter.bi_sector; + end = start + (bio->bi_iter.bi_size >> SECTOR_SHIFT); bound = zram->disksize >> SECTOR_SHIFT; /* out of range range */ if (unlikely(start >= bound || end > bound || start > end)) @@ -227,6 +229,8 @@ static struct zram_meta *zram_meta_alloc(u64 disksize) goto free_table; } + rwlock_init(&meta->tb_lock); + mutex_init(&meta->buffer_lock); return meta; free_table: @@ -279,6 +283,7 @@ static void handle_zero_page(struct bio_vec *bvec) flush_dcache_page(page); } +/* NOTE: caller should hold meta->tb_lock with write-side */ static void zram_free_page(struct zram *zram, size_t index) { struct zram_meta *meta = zram->meta; @@ -292,21 +297,21 @@ static void zram_free_page(struct zram *zram, size_t index) */ if (zram_test_flag(meta, index, ZRAM_ZERO)) { zram_clear_flag(meta, index, ZRAM_ZERO); - zram->stats.pages_zero--; + atomic_dec(&zram->stats.pages_zero); } return; } if (unlikely(size > max_zpage_size)) - zram->stats.bad_compress--; + atomic_dec(&zram->stats.bad_compress); zs_free(meta->mem_pool, handle); if (size <= PAGE_SIZE / 2) - zram->stats.good_compress--; + atomic_dec(&zram->stats.good_compress); atomic64_sub(meta->table[index].size, &zram->stats.compr_size); - zram->stats.pages_stored--; + atomic_dec(&zram->stats.pages_stored); meta->table[index].handle = 0; meta->table[index].size = 0; @@ -318,20 +323,26 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index) size_t clen = PAGE_SIZE; unsigned char *cmem; struct zram_meta *meta = zram->meta; - unsigned long handle = meta->table[index].handle; + unsigned long handle; + u16 size; + + read_lock(&meta->tb_lock); + handle = meta->table[index].handle; + size = meta->table[index].size; if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) { + read_unlock(&meta->tb_lock); clear_page(mem); return 0; } cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_RO); - if (meta->table[index].size == PAGE_SIZE) + if (size == PAGE_SIZE) copy_page(mem, cmem); else - ret = lzo1x_decompress_safe(cmem, meta->table[index].size, - mem, &clen); + ret = lzo1x_decompress_safe(cmem, size, mem, &clen); zs_unmap_object(meta->mem_pool, handle); + read_unlock(&meta->tb_lock); /* Should NEVER happen. Return bio error if it does. */ if (unlikely(ret != LZO_E_OK)) { @@ -352,11 +363,14 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, struct zram_meta *meta = zram->meta; page = bvec->bv_page; + read_lock(&meta->tb_lock); if (unlikely(!meta->table[index].handle) || zram_test_flag(meta, index, ZRAM_ZERO)) { + read_unlock(&meta->tb_lock); handle_zero_page(bvec); return 0; } + read_unlock(&meta->tb_lock); if (is_partial_io(bvec)) /* Use a temporary buffer to decompress the page */ @@ -399,6 +413,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, struct page *page; unsigned char *user_mem, *cmem, *src, *uncmem = NULL; struct zram_meta *meta = zram->meta; + bool locked = false; page = bvec->bv_page; src = meta->compress_buffer; @@ -418,6 +433,8 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, goto out; } + mutex_lock(&meta->buffer_lock); + locked = true; user_mem = kmap_atomic(page); if (is_partial_io(bvec)) { @@ -432,25 +449,18 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, if (page_zero_filled(uncmem)) { kunmap_atomic(user_mem); /* Free memory associated with this sector now. */ + write_lock(&zram->meta->tb_lock); zram_free_page(zram, index); - - zram->stats.pages_zero++; zram_set_flag(meta, index, ZRAM_ZERO); + write_unlock(&zram->meta->tb_lock); + + atomic_inc(&zram->stats.pages_zero); ret = 0; goto out; } - /* - * zram_slot_free_notify could miss free so that let's - * double check. - */ - if (unlikely(meta->table[index].handle || - zram_test_flag(meta, index, ZRAM_ZERO))) - zram_free_page(zram, index); - ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen, meta->compress_workmem); - if (!is_partial_io(bvec)) { kunmap_atomic(user_mem); user_mem = NULL; @@ -463,7 +473,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, } if (unlikely(clen > max_zpage_size)) { - zram->stats.bad_compress++; + atomic_inc(&zram->stats.bad_compress); clen = PAGE_SIZE; src = NULL; if (is_partial_io(bvec)) @@ -493,18 +503,22 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, * Free memory associated with this sector * before overwriting unused sectors. */ + write_lock(&zram->meta->tb_lock); zram_free_page(zram, index); meta->table[index].handle = handle; meta->table[index].size = clen; + write_unlock(&zram->meta->tb_lock); /* Update stats */ atomic64_add(clen, &zram->stats.compr_size); - zram->stats.pages_stored++; + atomic_inc(&zram->stats.pages_stored); if (clen <= PAGE_SIZE / 2) - zram->stats.good_compress++; + atomic_inc(&zram->stats.good_compress); out: + if (locked) + mutex_unlock(&meta->buffer_lock); if (is_partial_io(bvec)) kfree(uncmem); @@ -513,36 +527,15 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, return ret; } -static void handle_pending_slot_free(struct zram *zram) -{ - struct zram_slot_free *free_rq; - - spin_lock(&zram->slot_free_lock); - while (zram->slot_free_rq) { - free_rq = zram->slot_free_rq; - zram->slot_free_rq = free_rq->next; - zram_free_page(zram, free_rq->index); - kfree(free_rq); - } - spin_unlock(&zram->slot_free_lock); -} - static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index, int offset, struct bio *bio, int rw) { int ret; - if (rw == READ) { - down_read(&zram->lock); - handle_pending_slot_free(zram); + if (rw == READ) ret = zram_bvec_read(zram, bvec, index, offset, bio); - up_read(&zram->lock); - } else { - down_write(&zram->lock); - handle_pending_slot_free(zram); + else ret = zram_bvec_write(zram, bvec, index, offset); - up_write(&zram->lock); - } return ret; } @@ -552,8 +545,6 @@ static void zram_reset_device(struct zram *zram, bool reset_capacity) size_t index; struct zram_meta *meta; - flush_work(&zram->free_work); - down_write(&zram->init_lock); if (!zram->init_done) { up_write(&zram->init_lock); @@ -680,9 +671,10 @@ static ssize_t reset_store(struct device *dev, static void __zram_make_request(struct zram *zram, struct bio *bio, int rw) { - int i, offset; + int offset; u32 index; - struct bio_vec *bvec; + struct bio_vec bvec; + struct bvec_iter iter; switch (rw) { case READ: @@ -693,36 +685,37 @@ static void __zram_make_request(struct zram *zram, struct bio *bio, int rw) break; } - index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT; - offset = (bio->bi_sector & (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT; + index = bio->bi_iter.bi_sector >> SECTORS_PER_PAGE_SHIFT; + offset = (bio->bi_iter.bi_sector & + (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT; - bio_for_each_segment(bvec, bio, i) { + bio_for_each_segment(bvec, bio, iter) { int max_transfer_size = PAGE_SIZE - offset; - if (bvec->bv_len > max_transfer_size) { + if (bvec.bv_len > max_transfer_size) { /* * zram_bvec_rw() can only make operation on a single * zram page. Split the bio vector. */ struct bio_vec bv; - bv.bv_page = bvec->bv_page; + bv.bv_page = bvec.bv_page; bv.bv_len = max_transfer_size; - bv.bv_offset = bvec->bv_offset; + bv.bv_offset = bvec.bv_offset; if (zram_bvec_rw(zram, &bv, index, offset, bio, rw) < 0) goto out; - bv.bv_len = bvec->bv_len - max_transfer_size; + bv.bv_len = bvec.bv_len - max_transfer_size; bv.bv_offset += max_transfer_size; if (zram_bvec_rw(zram, &bv, index+1, 0, bio, rw) < 0) goto out; } else - if (zram_bvec_rw(zram, bvec, index, offset, bio, rw) + if (zram_bvec_rw(zram, &bvec, index, offset, bio, rw) < 0) goto out; - update_position(&index, &offset, bvec); + update_position(&index, &offset, &bvec); } set_bit(BIO_UPTODATE, &bio->bi_flags); @@ -759,40 +752,19 @@ static void zram_make_request(struct request_queue *queue, struct bio *bio) bio_io_error(bio); } -static void zram_slot_free(struct work_struct *work) -{ - struct zram *zram; - - zram = container_of(work, struct zram, free_work); - down_write(&zram->lock); - handle_pending_slot_free(zram); - up_write(&zram->lock); -} - -static void add_slot_free(struct zram *zram, struct zram_slot_free *free_rq) -{ - spin_lock(&zram->slot_free_lock); - free_rq->next = zram->slot_free_rq; - zram->slot_free_rq = free_rq; - spin_unlock(&zram->slot_free_lock); -} - static void zram_slot_free_notify(struct block_device *bdev, unsigned long index) { struct zram *zram; - struct zram_slot_free *free_rq; + struct zram_meta *meta; zram = bdev->bd_disk->private_data; - atomic64_inc(&zram->stats.notify_free); - - free_rq = kmalloc(sizeof(struct zram_slot_free), GFP_ATOMIC); - if (!free_rq) - return; + meta = zram->meta; - free_rq->index = index; - add_slot_free(zram, free_rq); - schedule_work(&zram->free_work); + write_lock(&meta->tb_lock); + zram_free_page(zram, index); + write_unlock(&meta->tb_lock); + atomic64_inc(&zram->stats.notify_free); } static const struct block_device_operations zram_devops = { @@ -836,13 +808,8 @@ static int create_device(struct zram *zram, int device_id) { int ret = -ENOMEM; - init_rwsem(&zram->lock); init_rwsem(&zram->init_lock); - INIT_WORK(&zram->free_work, zram_slot_free); - spin_lock_init(&zram->slot_free_lock); - zram->slot_free_rq = NULL; - zram->queue = blk_alloc_queue(GFP_KERNEL); if (!zram->queue) { pr_err("Error allocating disk queue for device %d\n", diff --git a/drivers/staging/zram/zram_drv.h b/drivers/block/zram/zram_drv.h similarity index 74% rename from drivers/staging/zram/zram_drv.h rename to drivers/block/zram/zram_drv.h index 97a3acf6ab7613..ad8aa35bae00e9 100644 --- a/drivers/staging/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h @@ -2,6 +2,7 @@ * Compressed RAM block device * * Copyright (C) 2008, 2009, 2010 Nitin Gupta + * 2012, 2013 Minchan Kim * * This code is released using a dual license strategy: BSD/GPL * You can choose the licence that better fits your requirements. @@ -9,7 +10,6 @@ * Released under the terms of 3-clause BSD License * Released under the terms of GNU General Public License Version 2.0 * - * Project home: http://compcache.googlecode.com */ #ifndef _ZRAM_DRV_H_ @@ -17,8 +17,7 @@ #include #include - -#include "../zsmalloc/zsmalloc.h" +#include /* * Some arbitrary value. This is just to catch @@ -69,10 +68,6 @@ struct table { u8 flags; } __aligned(4); -/* - * All 64bit fields should only be manipulated by 64bit atomic accessors. - * All modifications to 32bit counter should be protected by zram->lock. - */ struct zram_stats { atomic64_t compr_size; /* compressed size of pages stored */ atomic64_t num_reads; /* failed + successful */ @@ -81,33 +76,23 @@ struct zram_stats { atomic64_t failed_writes; /* can happen when memory is too low */ atomic64_t invalid_io; /* non-page-aligned I/O requests */ atomic64_t notify_free; /* no. of swap slot free notifications */ - u32 pages_zero; /* no. of zero filled pages */ - u32 pages_stored; /* no. of pages currently stored */ - u32 good_compress; /* % of pages with compression ratio<=50% */ - u32 bad_compress; /* % of pages with compression ratio>=75% */ + atomic_t pages_zero; /* no. of zero filled pages */ + atomic_t pages_stored; /* no. of pages currently stored */ + atomic_t good_compress; /* % of pages with compression ratio<=50% */ + atomic_t bad_compress; /* % of pages with compression ratio>=75% */ }; struct zram_meta { + rwlock_t tb_lock; /* protect table */ void *compress_workmem; void *compress_buffer; struct table *table; struct zs_pool *mem_pool; -}; - -struct zram_slot_free { - unsigned long index; - struct zram_slot_free *next; + struct mutex buffer_lock; /* protect compress buffers */ }; struct zram { struct zram_meta *meta; - struct rw_semaphore lock; /* protect compression buffers, table, - * 32bit stat counters against concurrent - * notifications, reads and writes */ - - struct work_struct free_work; /* handle pending free request */ - struct zram_slot_free *slot_free_rq; /* list head of free request */ - struct request_queue *queue; struct gendisk *disk; int init_done; @@ -118,7 +103,6 @@ struct zram { * we can store in a disk. */ u64 disksize; /* bytes */ - spinlock_t slot_free_lock; struct zram_stats stats; }; diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c index b6739cb78e3207..962fd35cbd8d24 100644 --- a/drivers/bus/arm-cci.c +++ b/drivers/bus/arm-cci.c @@ -979,7 +979,7 @@ static int cci_probe(void) nb_cci_ports = cci_config->nb_ace + cci_config->nb_ace_lite; - ports = kcalloc(sizeof(*ports), nb_cci_ports, GFP_KERNEL); + ports = kcalloc(nb_cci_ports, sizeof(*ports), GFP_KERNEL); if (!ports) return -ENOMEM; diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index 5980cb9af85789..51e75ad964223e 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -561,11 +561,11 @@ static int gdrom_set_interrupt_handlers(void) int err; err = request_irq(HW_EVENT_GDROM_CMD, gdrom_command_interrupt, - IRQF_DISABLED, "gdrom_command", &gd); + 0, "gdrom_command", &gd); if (err) return err; err = request_irq(HW_EVENT_GDROM_DMA, gdrom_dma_interrupt, - IRQF_DISABLED, "gdrom_dma", &gd); + 0, "gdrom_dma", &gd); if (err) free_irq(HW_EVENT_GDROM_CMD, &gd); return err; diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index fa3243d71c76d0..1386749b48ffd6 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -499,6 +499,7 @@ config RAW_DRIVER config MAX_RAW_DEVS int "Maximum number of RAW devices to support (1-65536)" depends on RAW_DRIVER + range 1 65536 default "256" help The maximum number of RAW devices that are supported. diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 290fe5b7fd327f..a324f9303e36da 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -49,7 +49,7 @@ obj-$(CONFIG_GPIO_TB0219) += tb0219.o obj-$(CONFIG_TELCLOCK) += tlclk.o obj-$(CONFIG_MWAVE) += mwave/ -obj-$(CONFIG_AGP) += agp/ +obj-y += agp/ obj-$(CONFIG_PCMCIA) += pcmcia/ obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index d8b1b576556cf8..c528f96ee204fb 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig @@ -68,6 +68,7 @@ config AGP_AMD64 config AGP_INTEL tristate "Intel 440LX/BX/GX, I8xx and E7x05 chipset support" depends on AGP && X86 + select INTEL_GTT help This option gives you AGP support for the GLX component of X on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850, 860, 875, @@ -155,3 +156,7 @@ config AGP_SGI_TIOCA This option gives you AGP GART support for the SGI TIO chipset for IA64 processors. +config INTEL_GTT + tristate + depends on X86 && PCI + diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile index 8eb56e273e7571..604489bcdbf9b6 100644 --- a/drivers/char/agp/Makefile +++ b/drivers/char/agp/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o obj-$(CONFIG_AGP_PARISC) += parisc-agp.o obj-$(CONFIG_AGP_I460) += i460-agp.o obj-$(CONFIG_AGP_INTEL) += intel-agp.o -obj-$(CONFIG_AGP_INTEL) += intel-gtt.o +obj-$(CONFIG_INTEL_GTT) += intel-gtt.o obj-$(CONFIG_AGP_NVIDIA) += nvidia-agp.o obj-$(CONFIG_AGP_SGI_TIOCA) += sgi-agp.o obj-$(CONFIG_AGP_SIS) += sis-agp.o diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index a7c276585a9f4f..f9b9ca5d31b794 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -14,9 +14,6 @@ #include "intel-agp.h" #include -int intel_agp_enabled; -EXPORT_SYMBOL(intel_agp_enabled); - static int intel_fetch_size(void) { int i; @@ -806,8 +803,6 @@ static int agp_intel_probe(struct pci_dev *pdev, found_gmch: pci_set_drvdata(pdev, bridge); err = agp_add_bridge(bridge); - if (!err) - intel_agp_enabled = 1; return err; } diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index ad5da1ffcbe9a8..5c85350f4c3d06 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -94,6 +94,7 @@ static struct _intel_private { #define IS_IRONLAKE intel_private.driver->is_ironlake #define HAS_PGTBL_EN intel_private.driver->has_pgtbl_enable +#if IS_ENABLED(CONFIG_AGP_INTEL) static int intel_gtt_map_memory(struct page **pages, unsigned int num_entries, struct sg_table *st) @@ -168,6 +169,7 @@ static void i8xx_destroy_pages(struct page *page) __free_pages(page, 2); atomic_dec(&agp_bridge->current_memory_agp); } +#endif #define I810_GTT_ORDER 4 static int i810_setup(void) @@ -208,6 +210,7 @@ static void i810_cleanup(void) free_gatt_pages(intel_private.i81x_gtt_table, I810_GTT_ORDER); } +#if IS_ENABLED(CONFIG_AGP_INTEL) static int i810_insert_dcache_entries(struct agp_memory *mem, off_t pg_start, int type) { @@ -288,6 +291,7 @@ static void intel_i810_free_by_type(struct agp_memory *curr) } kfree(curr); } +#endif static int intel_gtt_setup_scratch_page(void) { @@ -645,7 +649,9 @@ static int intel_gtt_init(void) return -ENOMEM; } +#if IS_ENABLED(CONFIG_AGP_INTEL) global_cache_flush(); /* FIXME: ? */ +#endif intel_private.stolen_size = intel_gtt_stolen_size(); @@ -666,6 +672,7 @@ static int intel_gtt_init(void) return 0; } +#if IS_ENABLED(CONFIG_AGP_INTEL) static int intel_fake_agp_fetch_size(void) { int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes); @@ -684,6 +691,7 @@ static int intel_fake_agp_fetch_size(void) return 0; } +#endif static void i830_cleanup(void) { @@ -795,6 +803,7 @@ static int i830_setup(void) return 0; } +#if IS_ENABLED(CONFIG_AGP_INTEL) static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge) { agp_bridge->gatt_table_real = NULL; @@ -819,6 +828,7 @@ static int intel_fake_agp_configure(void) return 0; } +#endif static bool i830_check_flags(unsigned int flags) { @@ -857,6 +867,7 @@ void intel_gtt_insert_sg_entries(struct sg_table *st, } EXPORT_SYMBOL(intel_gtt_insert_sg_entries); +#if IS_ENABLED(CONFIG_AGP_INTEL) static void intel_gtt_insert_pages(unsigned int first_entry, unsigned int num_entries, struct page **pages, @@ -922,6 +933,7 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem, mem->is_flushed = true; return ret; } +#endif void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries) { @@ -935,6 +947,7 @@ void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries) } EXPORT_SYMBOL(intel_gtt_clear_range); +#if IS_ENABLED(CONFIG_AGP_INTEL) static int intel_fake_agp_remove_entries(struct agp_memory *mem, off_t pg_start, int type) { @@ -976,6 +989,7 @@ static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count, /* always return NULL for other allocation types for now */ return NULL; } +#endif static int intel_alloc_chipset_flush_resource(void) { @@ -1129,6 +1143,7 @@ static int i9xx_setup(void) return 0; } +#if IS_ENABLED(CONFIG_AGP_INTEL) static const struct agp_bridge_driver intel_fake_agp_driver = { .owner = THIS_MODULE, .size_type = FIXED_APER_SIZE, @@ -1150,6 +1165,7 @@ static const struct agp_bridge_driver intel_fake_agp_driver = { .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, }; +#endif static const struct intel_gtt_driver i81x_gtt_driver = { .gen = 1, @@ -1367,11 +1383,13 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, intel_private.refcount++; +#if IS_ENABLED(CONFIG_AGP_INTEL) if (bridge) { bridge->driver = &intel_fake_agp_driver; bridge->dev_private_data = &intel_private; bridge->dev = bridge_pdev; } +#endif intel_private.bridge_dev = pci_dev_get(bridge_pdev); diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index e210f858d3cbf8..d915707d2ba1d3 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -4,7 +4,7 @@ * Copyright (C) 2001 Massimo Dal Zotto * * Hwmon integration: - * Copyright (C) 2011 Jean Delvare + * Copyright (C) 2011 Jean Delvare * Copyright (C) 2013 Guenter Roeck * * This program is free software; you can redistribute it and/or modify it diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 671c3852d35921..03f41896d09050 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2724,6 +2724,7 @@ static struct platform_driver ipmi_driver = { static int ipmi_parisc_probe(struct parisc_device *dev) { struct smi_info *info; + int rv; info = smi_info_alloc(); diff --git a/drivers/char/raw.c b/drivers/char/raw.c index f3223aac4df11c..6e8d65e9b1d3c1 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -190,7 +190,7 @@ static int bind_get(int number, dev_t *dev) struct raw_device_data *rawdev; struct block_device *bdev; - if (number <= 0 || number >= MAX_RAW_MINORS) + if (number <= 0 || number >= max_raw_minors) return -EINVAL; rawdev = &raw_devices[number]; diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index feea87cc6b8fb6..6928d094451d60 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -890,12 +890,10 @@ static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf, } else { /* Failback to copying a page */ struct page *page = alloc_page(GFP_KERNEL); - char *src = buf->ops->map(pipe, buf, 1); - char *dst; + char *src; if (!page) return -ENOMEM; - dst = kmap(page); offset = sd->pos & ~PAGE_MASK; @@ -903,9 +901,8 @@ static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf, if (len + offset > PAGE_SIZE) len = PAGE_SIZE - offset; - memcpy(dst + offset, src + buf->offset, len); - - kunmap(page); + src = buf->ops->map(pipe, buf, 1); + memcpy(page_address(page) + offset, src + buf->offset, len); buf->ops->unmap(pipe, buf, src); sg_set_page(&(sgl->sg[sgl->n]), page, len, offset); diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 0c16e9cdfb8785..a367a98317175f 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -9,45 +9,44 @@ obj-$(CONFIG_COMMON_CLK) += clk-gate.o obj-$(CONFIG_COMMON_CLK) += clk-mux.o obj-$(CONFIG_COMMON_CLK) += clk-composite.o -# SoCs specific -obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o -obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o -obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o -obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o -obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ -obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o -obj-$(CONFIG_ARCH_MXS) += mxs/ -obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ -obj-$(CONFIG_PLAT_SPEAR) += spear/ -obj-$(CONFIG_ARCH_U300) += clk-u300.o -obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ -obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ -obj-$(CONFIG_PLAT_ORION) += mvebu/ +# hardware specific clock types +# please keep this section sorted lexicographically by file/directory path name +obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o +obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o +obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o +obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o +obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o +obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o +obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o +obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o +obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o +obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o +obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o +obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o +obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o +obj-$(CONFIG_ARCH_U300) += clk-u300.o +obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o +obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o +obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o +obj-$(CONFIG_COMMON_CLK_AT91) += at91/ +obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ +obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ ifeq ($(CONFIG_COMMON_CLK), y) -obj-$(CONFIG_ARCH_MMP) += mmp/ +obj-$(CONFIG_ARCH_MMP) += mmp/ endif -obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o -obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ -obj-$(CONFIG_ARCH_SUNXI) += sunxi/ -obj-$(CONFIG_ARCH_U8500) += ux500/ -obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o -obj-$(CONFIG_ARCH_SIRF) += sirf/ -obj-$(CONFIG_ARCH_ZYNQ) += zynq/ -obj-$(CONFIG_ARCH_TEGRA) += tegra/ -obj-$(CONFIG_PLAT_SAMSUNG) += samsung/ -obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o -obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ -obj-$(CONFIG_COMMON_CLK_AT91) += at91/ +obj-$(CONFIG_PLAT_ORION) += mvebu/ +obj-$(CONFIG_ARCH_MXS) += mxs/ +obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ +obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ +obj-$(CONFIG_PLAT_SAMSUNG) += samsung/ obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += shmobile/ - -obj-$(CONFIG_X86) += x86/ - -# Chip specific -obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o -obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o -obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o -obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o -obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o -obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o -obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o -obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o +obj-$(CONFIG_ARCH_SIRF) += sirf/ +obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ +obj-$(CONFIG_PLAT_SPEAR) += spear/ +obj-$(CONFIG_ARCH_SUNXI) += sunxi/ +obj-$(CONFIG_ARCH_TEGRA) += tegra/ +obj-$(CONFIG_ARCH_OMAP2PLUS) += ti/ +obj-$(CONFIG_ARCH_U8500) += ux500/ +obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ +obj-$(CONFIG_X86) += x86/ +obj-$(CONFIG_ARCH_ZYNQ) += zynq/ diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index c50e83744b0aec..3b2a66f7875511 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -1111,11 +1111,11 @@ static const struct of_device_id si5351_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, si5351_dt_ids); -static int si5351_dt_parse(struct i2c_client *client) +static int si5351_dt_parse(struct i2c_client *client, + enum si5351_variant variant) { struct device_node *child, *np = client->dev.of_node; struct si5351_platform_data *pdata; - const struct of_device_id *match; struct property *prop; const __be32 *p; int num = 0; @@ -1124,15 +1124,10 @@ static int si5351_dt_parse(struct i2c_client *client) if (np == NULL) return 0; - match = of_match_node(si5351_dt_ids, np); - if (match == NULL) - return -EINVAL; - pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - pdata->variant = (enum si5351_variant)match->data; pdata->clk_xtal = of_clk_get(np, 0); if (!IS_ERR(pdata->clk_xtal)) clk_put(pdata->clk_xtal); @@ -1163,7 +1158,7 @@ static int si5351_dt_parse(struct i2c_client *client) pdata->pll_src[num] = SI5351_PLL_SRC_XTAL; break; case 1: - if (pdata->variant != SI5351_VARIANT_C) { + if (variant != SI5351_VARIANT_C) { dev_err(&client->dev, "invalid parent %d for pll %d\n", val, num); @@ -1187,7 +1182,7 @@ static int si5351_dt_parse(struct i2c_client *client) } if (num >= 8 || - (pdata->variant == SI5351_VARIANT_A3 && num >= 3)) { + (variant == SI5351_VARIANT_A3 && num >= 3)) { dev_err(&client->dev, "invalid clkout %d\n", num); return -EINVAL; } @@ -1226,7 +1221,7 @@ static int si5351_dt_parse(struct i2c_client *client) SI5351_CLKOUT_SRC_XTAL; break; case 3: - if (pdata->variant != SI5351_VARIANT_C) { + if (variant != SI5351_VARIANT_C) { dev_err(&client->dev, "invalid parent %d for clkout %d\n", val, num); @@ -1298,7 +1293,7 @@ static int si5351_dt_parse(struct i2c_client *client) return 0; } #else -static int si5351_dt_parse(struct i2c_client *client) +static int si5351_dt_parse(struct i2c_client *client, enum si5351_variant variant) { return 0; } @@ -1307,6 +1302,7 @@ static int si5351_dt_parse(struct i2c_client *client) static int si5351_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { + enum si5351_variant variant = (enum si5351_variant)id->driver_data; struct si5351_platform_data *pdata; struct si5351_driver_data *drvdata; struct clk_init_data init; @@ -1315,7 +1311,7 @@ static int si5351_i2c_probe(struct i2c_client *client, u8 num_parents, num_clocks; int ret, n; - ret = si5351_dt_parse(client); + ret = si5351_dt_parse(client, variant); if (ret) return ret; @@ -1331,7 +1327,7 @@ static int si5351_i2c_probe(struct i2c_client *client, i2c_set_clientdata(client, drvdata); drvdata->client = client; - drvdata->variant = pdata->variant; + drvdata->variant = variant; drvdata->pxtal = pdata->clk_xtal; drvdata->pclkin = pdata->clk_clkin; @@ -1568,10 +1564,10 @@ static int si5351_i2c_probe(struct i2c_client *client, } static const struct i2c_device_id si5351_i2c_ids[] = { - { "si5351a", 0 }, - { "si5351a-msop", 0 }, - { "si5351b", 0 }, - { "si5351c", 0 }, + { "si5351a", SI5351_VARIANT_A }, + { "si5351a-msop", SI5351_VARIANT_A3 }, + { "si5351b", SI5351_VARIANT_B }, + { "si5351c", SI5351_VARIANT_C }, { } }; MODULE_DEVICE_TABLE(i2c, si5351_i2c_ids); diff --git a/drivers/clk/clk-si5351.h b/drivers/clk/clk-si5351.h index c0dbf267687299..4d0746b50c32e8 100644 --- a/drivers/clk/clk-si5351.h +++ b/drivers/clk/clk-si5351.h @@ -153,4 +153,18 @@ #define SI5351_XTAL_ENABLE (1<<6) #define SI5351_MULTISYNTH_ENABLE (1<<4) +/** + * enum si5351_variant - SiLabs Si5351 chip variant + * @SI5351_VARIANT_A: Si5351A (8 output clocks, XTAL input) + * @SI5351_VARIANT_A3: Si5351A MSOP10 (3 output clocks, XTAL input) + * @SI5351_VARIANT_B: Si5351B (8 output clocks, XTAL/VXCO input) + * @SI5351_VARIANT_C: Si5351C (8 output clocks, XTAL/CLKIN input) + */ +enum si5351_variant { + SI5351_VARIANT_A = 1, + SI5351_VARIANT_A3 = 2, + SI5351_VARIANT_B = 3, + SI5351_VARIANT_C = 4, +}; + #endif diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 2b38dc99063f1b..5517944495d893 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -575,16 +575,19 @@ struct clk_hw *__clk_get_hw(struct clk *clk) { return !clk ? NULL : clk->hw; } +EXPORT_SYMBOL_GPL(__clk_get_hw); u8 __clk_get_num_parents(struct clk *clk) { return !clk ? 0 : clk->num_parents; } +EXPORT_SYMBOL_GPL(__clk_get_num_parents); struct clk *__clk_get_parent(struct clk *clk) { return !clk ? NULL : clk->parent; } +EXPORT_SYMBOL_GPL(__clk_get_parent); struct clk *clk_get_parent_by_index(struct clk *clk, u8 index) { @@ -598,6 +601,7 @@ struct clk *clk_get_parent_by_index(struct clk *clk, u8 index) else return clk->parents[index]; } +EXPORT_SYMBOL_GPL(clk_get_parent_by_index); unsigned int __clk_get_enable_count(struct clk *clk) { @@ -629,6 +633,7 @@ unsigned long __clk_get_rate(struct clk *clk) out: return ret; } +EXPORT_SYMBOL_GPL(__clk_get_rate); unsigned long __clk_get_accuracy(struct clk *clk) { @@ -685,6 +690,7 @@ bool __clk_is_enabled(struct clk *clk) out: return !!ret; } +EXPORT_SYMBOL_GPL(__clk_is_enabled); static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk) { @@ -776,6 +782,7 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, return best; } +EXPORT_SYMBOL_GPL(__clk_mux_determine_rate); /*** clk api ***/ @@ -2373,8 +2380,6 @@ struct of_clk_provider { void *data; }; -extern struct of_device_id __clk_of_table[]; - static const struct of_device_id __clk_of_table_sentinel __used __section(__clk_of_table_end); @@ -2534,7 +2539,7 @@ void __init of_clk_init(const struct of_device_id *matches) struct device_node *np; if (!matches) - matches = __clk_of_table; + matches = &__clk_of_table; for_each_matching_node_and_match(np, matches, &match) { of_clk_init_cb_t clk_init_cb = match->data; diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 190d38433202db..f60db2ef1aee6a 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -1,11 +1,11 @@ obj-$(CONFIG_COMMON_CLK_QCOM) += clk-qcom.o -clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-regmap.o -clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-pll.o -clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-rcg.o -clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-rcg2.o -clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-branch.o -clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += reset.o +clk-qcom-y += clk-regmap.o +clk-qcom-y += clk-pll.o +clk-qcom-y += clk-rcg.o +clk-qcom-y += clk-rcg2.o +clk-qcom-y += clk-branch.o +clk-qcom-y += reset.o obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 529e11dc2c6b0e..81e6d2f49aa001 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -375,7 +375,7 @@ static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate, break; default: break; - }; + } /* Set new configuration. */ __raw_writel(con1, pll->con_reg + 0x4); diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 659e4ea31893a4..abb6c5ac8a1029 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -875,7 +875,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, if (!clk_data) return; - clks = kzalloc(SUNXI_DIVS_MAX_QTY * sizeof(struct clk *), GFP_KERNEL); + clks = kzalloc((SUNXI_DIVS_MAX_QTY+1) * sizeof(*clks), GFP_KERNEL); if (!clks) goto free_clkdata; diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile new file mode 100644 index 00000000000000..4319d4031aa378 --- /dev/null +++ b/drivers/clk/ti/Makefile @@ -0,0 +1,11 @@ +ifneq ($(CONFIG_OF),) +obj-y += clk.o autoidle.o clockdomain.o +clk-common = dpll.o composite.o divider.o gate.o \ + fixed-factor.o mux.o apll.o +obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o +obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o clk-3xxx.o +obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o +obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o +obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o +obj-$(CONFIG_SOC_AM43XX) += $(clk-common) clk-43xx.o +endif diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c new file mode 100644 index 00000000000000..b986f61f5a7713 --- /dev/null +++ b/drivers/clk/ti/apll.c @@ -0,0 +1,223 @@ +/* + * OMAP APLL clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * J Keerthy + * + * 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 "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define APLL_FORCE_LOCK 0x1 +#define APLL_AUTO_IDLE 0x2 +#define MAX_APLL_WAIT_TRIES 1000000 + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +static int dra7_apll_enable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + int r = 0, i = 0; + struct dpll_data *ad; + const char *clk_name; + u8 state = 1; + u32 v; + + ad = clk->dpll_data; + if (!ad) + return -EINVAL; + + clk_name = __clk_get_name(clk->hw.clk); + + state <<= __ffs(ad->idlest_mask); + + /* Check is already locked */ + v = ti_clk_ll_ops->clk_readl(ad->idlest_reg); + + if ((v & ad->idlest_mask) == state) + return r; + + v = ti_clk_ll_ops->clk_readl(ad->control_reg); + v &= ~ad->enable_mask; + v |= APLL_FORCE_LOCK << __ffs(ad->enable_mask); + ti_clk_ll_ops->clk_writel(v, ad->control_reg); + + state <<= __ffs(ad->idlest_mask); + + while (1) { + v = ti_clk_ll_ops->clk_readl(ad->idlest_reg); + if ((v & ad->idlest_mask) == state) + break; + if (i > MAX_APLL_WAIT_TRIES) + break; + i++; + udelay(1); + } + + if (i == MAX_APLL_WAIT_TRIES) { + pr_warn("clock: %s failed transition to '%s'\n", + clk_name, (state) ? "locked" : "bypassed"); + } else { + pr_debug("clock: %s transition to '%s' in %d loops\n", + clk_name, (state) ? "locked" : "bypassed", i); + + r = 0; + } + + return r; +} + +static void dra7_apll_disable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *ad; + u8 state = 1; + u32 v; + + ad = clk->dpll_data; + + state <<= __ffs(ad->idlest_mask); + + v = ti_clk_ll_ops->clk_readl(ad->control_reg); + v &= ~ad->enable_mask; + v |= APLL_AUTO_IDLE << __ffs(ad->enable_mask); + ti_clk_ll_ops->clk_writel(v, ad->control_reg); +} + +static int dra7_apll_is_enabled(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *ad; + u32 v; + + ad = clk->dpll_data; + + v = ti_clk_ll_ops->clk_readl(ad->control_reg); + v &= ad->enable_mask; + + v >>= __ffs(ad->enable_mask); + + return v == APLL_AUTO_IDLE ? 0 : 1; +} + +static u8 dra7_init_apll_parent(struct clk_hw *hw) +{ + return 0; +} + +static const struct clk_ops apll_ck_ops = { + .enable = &dra7_apll_enable, + .disable = &dra7_apll_disable, + .is_enabled = &dra7_apll_is_enabled, + .get_parent = &dra7_init_apll_parent, +}; + +static void __init omap_clk_register_apll(struct clk_hw *hw, + struct device_node *node) +{ + struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw); + struct dpll_data *ad = clk_hw->dpll_data; + struct clk *clk; + + ad->clk_ref = of_clk_get(node, 0); + ad->clk_bypass = of_clk_get(node, 1); + + if (IS_ERR(ad->clk_ref) || IS_ERR(ad->clk_bypass)) { + pr_debug("clk-ref or clk-bypass for %s not ready, retry\n", + node->name); + if (!ti_clk_retry_init(node, hw, omap_clk_register_apll)) + return; + + goto cleanup; + } + + clk = clk_register(NULL, &clk_hw->hw); + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + kfree(clk_hw->hw.init->parent_names); + kfree(clk_hw->hw.init); + return; + } + +cleanup: + kfree(clk_hw->dpll_data); + kfree(clk_hw->hw.init->parent_names); + kfree(clk_hw->hw.init); + kfree(clk_hw); +} + +static void __init of_dra7_apll_setup(struct device_node *node) +{ + struct dpll_data *ad = NULL; + struct clk_hw_omap *clk_hw = NULL; + struct clk_init_data *init = NULL; + const char **parent_names = NULL; + int i; + + ad = kzalloc(sizeof(*ad), GFP_KERNEL); + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + init = kzalloc(sizeof(*init), GFP_KERNEL); + if (!ad || !clk_hw || !init) + goto cleanup; + + clk_hw->dpll_data = ad; + clk_hw->hw.init = init; + clk_hw->flags = MEMMAP_ADDRESSING; + + init->name = node->name; + init->ops = &apll_ck_ops; + + init->num_parents = of_clk_get_parent_count(node); + if (init->num_parents < 1) { + pr_err("dra7 apll %s must have parent(s)\n", node->name); + goto cleanup; + } + + parent_names = kzalloc(sizeof(char *) * init->num_parents, GFP_KERNEL); + if (!parent_names) + goto cleanup; + + for (i = 0; i < init->num_parents; i++) + parent_names[i] = of_clk_get_parent_name(node, i); + + init->parent_names = parent_names; + + ad->control_reg = ti_clk_get_reg_addr(node, 0); + ad->idlest_reg = ti_clk_get_reg_addr(node, 1); + + if (!ad->control_reg || !ad->idlest_reg) + goto cleanup; + + ad->idlest_mask = 0x1; + ad->enable_mask = 0x3; + + omap_clk_register_apll(&clk_hw->hw, node); + return; + +cleanup: + kfree(parent_names); + kfree(ad); + kfree(clk_hw); + kfree(init); +} +CLK_OF_DECLARE(dra7_apll_clock, "ti,dra7-apll-clock", of_dra7_apll_setup); diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c new file mode 100644 index 00000000000000..8912ff80af347c --- /dev/null +++ b/drivers/clk/ti/autoidle.c @@ -0,0 +1,133 @@ +/* + * TI clock autoidle support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo + * + * 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 "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +struct clk_ti_autoidle { + void __iomem *reg; + u8 shift; + u8 flags; + const char *name; + struct list_head node; +}; + +#define AUTOIDLE_LOW 0x1 + +static LIST_HEAD(autoidle_clks); + +static void ti_allow_autoidle(struct clk_ti_autoidle *clk) +{ + u32 val; + + val = ti_clk_ll_ops->clk_readl(clk->reg); + + if (clk->flags & AUTOIDLE_LOW) + val &= ~(1 << clk->shift); + else + val |= (1 << clk->shift); + + ti_clk_ll_ops->clk_writel(val, clk->reg); +} + +static void ti_deny_autoidle(struct clk_ti_autoidle *clk) +{ + u32 val; + + val = ti_clk_ll_ops->clk_readl(clk->reg); + + if (clk->flags & AUTOIDLE_LOW) + val |= (1 << clk->shift); + else + val &= ~(1 << clk->shift); + + ti_clk_ll_ops->clk_writel(val, clk->reg); +} + +/** + * of_ti_clk_allow_autoidle_all - enable autoidle for all clocks + * + * Enables hardware autoidle for all registered DT clocks, which have + * the feature. + */ +void of_ti_clk_allow_autoidle_all(void) +{ + struct clk_ti_autoidle *c; + + list_for_each_entry(c, &autoidle_clks, node) + ti_allow_autoidle(c); +} + +/** + * of_ti_clk_deny_autoidle_all - disable autoidle for all clocks + * + * Disables hardware autoidle for all registered DT clocks, which have + * the feature. + */ +void of_ti_clk_deny_autoidle_all(void) +{ + struct clk_ti_autoidle *c; + + list_for_each_entry(c, &autoidle_clks, node) + ti_deny_autoidle(c); +} + +/** + * of_ti_clk_autoidle_setup - sets up hardware autoidle for a clock + * @node: pointer to the clock device node + * + * Checks if a clock has hardware autoidle support or not (check + * for presence of 'ti,autoidle-shift' property in the device tree + * node) and sets up the hardware autoidle feature for the clock + * if available. If autoidle is available, the clock is also added + * to the autoidle list for later processing. Returns 0 on success, + * negative error value on failure. + */ +int __init of_ti_clk_autoidle_setup(struct device_node *node) +{ + u32 shift; + struct clk_ti_autoidle *clk; + + /* Check if this clock has autoidle support or not */ + if (of_property_read_u32(node, "ti,autoidle-shift", &shift)) + return 0; + + clk = kzalloc(sizeof(*clk), GFP_KERNEL); + + if (!clk) + return -ENOMEM; + + clk->shift = shift; + clk->name = node->name; + clk->reg = ti_clk_get_reg_addr(node, 0); + + if (!clk->reg) { + kfree(clk); + return -EINVAL; + } + + if (of_property_read_bool(node, "ti,invert-autoidle-bit")) + clk->flags |= AUTOIDLE_LOW; + + list_add(&clk->node, &autoidle_clks); + + return 0; +} diff --git a/drivers/clk/ti/clk-33xx.c b/drivers/clk/ti/clk-33xx.c new file mode 100644 index 00000000000000..776ee4594bd44a --- /dev/null +++ b/drivers/clk/ti/clk-33xx.c @@ -0,0 +1,161 @@ +/* + * AM33XX Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc + * Tero Kristo (t-kristo@ti.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +static struct ti_dt_clk am33xx_clks[] = { + DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"), + DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_24000000_ck", "virt_24000000_ck"), + DT_CLK(NULL, "virt_25000000_ck", "virt_25000000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "sys_clkin_ck", "sys_clkin_ck"), + DT_CLK(NULL, "tclkin_ck", "tclkin_ck"), + DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), + DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), + DT_CLK(NULL, "dpll_core_m4_ck", "dpll_core_m4_ck"), + DT_CLK(NULL, "dpll_core_m5_ck", "dpll_core_m5_ck"), + DT_CLK(NULL, "dpll_core_m6_ck", "dpll_core_m6_ck"), + DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), + DT_CLK("cpu0", NULL, "dpll_mpu_ck"), + DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), + DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"), + DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"), + DT_CLK(NULL, "dpll_ddr_m2_div2_ck", "dpll_ddr_m2_div2_ck"), + DT_CLK(NULL, "dpll_disp_ck", "dpll_disp_ck"), + DT_CLK(NULL, "dpll_disp_m2_ck", "dpll_disp_m2_ck"), + DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), + DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), + DT_CLK(NULL, "dpll_per_m2_div4_wkupdm_ck", "dpll_per_m2_div4_wkupdm_ck"), + DT_CLK(NULL, "dpll_per_m2_div4_ck", "dpll_per_m2_div4_ck"), + DT_CLK(NULL, "adc_tsc_fck", "adc_tsc_fck"), + DT_CLK(NULL, "cefuse_fck", "cefuse_fck"), + DT_CLK(NULL, "clkdiv32k_ck", "clkdiv32k_ck"), + DT_CLK(NULL, "clkdiv32k_ick", "clkdiv32k_ick"), + DT_CLK(NULL, "dcan0_fck", "dcan0_fck"), + DT_CLK("481cc000.d_can", NULL, "dcan0_fck"), + DT_CLK(NULL, "dcan1_fck", "dcan1_fck"), + DT_CLK("481d0000.d_can", NULL, "dcan1_fck"), + DT_CLK(NULL, "pruss_ocp_gclk", "pruss_ocp_gclk"), + DT_CLK(NULL, "mcasp0_fck", "mcasp0_fck"), + DT_CLK(NULL, "mcasp1_fck", "mcasp1_fck"), + DT_CLK(NULL, "mmu_fck", "mmu_fck"), + DT_CLK(NULL, "smartreflex0_fck", "smartreflex0_fck"), + DT_CLK(NULL, "smartreflex1_fck", "smartreflex1_fck"), + DT_CLK(NULL, "sha0_fck", "sha0_fck"), + DT_CLK(NULL, "aes0_fck", "aes0_fck"), + DT_CLK(NULL, "rng_fck", "rng_fck"), + DT_CLK(NULL, "timer1_fck", "timer1_fck"), + DT_CLK(NULL, "timer2_fck", "timer2_fck"), + DT_CLK(NULL, "timer3_fck", "timer3_fck"), + DT_CLK(NULL, "timer4_fck", "timer4_fck"), + DT_CLK(NULL, "timer5_fck", "timer5_fck"), + DT_CLK(NULL, "timer6_fck", "timer6_fck"), + DT_CLK(NULL, "timer7_fck", "timer7_fck"), + DT_CLK(NULL, "usbotg_fck", "usbotg_fck"), + DT_CLK(NULL, "ieee5000_fck", "ieee5000_fck"), + DT_CLK(NULL, "wdt1_fck", "wdt1_fck"), + DT_CLK(NULL, "l4_rtc_gclk", "l4_rtc_gclk"), + DT_CLK(NULL, "l3_gclk", "l3_gclk"), + DT_CLK(NULL, "dpll_core_m4_div2_ck", "dpll_core_m4_div2_ck"), + DT_CLK(NULL, "l4hs_gclk", "l4hs_gclk"), + DT_CLK(NULL, "l3s_gclk", "l3s_gclk"), + DT_CLK(NULL, "l4fw_gclk", "l4fw_gclk"), + DT_CLK(NULL, "l4ls_gclk", "l4ls_gclk"), + DT_CLK(NULL, "clk_24mhz", "clk_24mhz"), + DT_CLK(NULL, "sysclk_div_ck", "sysclk_div_ck"), + DT_CLK(NULL, "cpsw_125mhz_gclk", "cpsw_125mhz_gclk"), + DT_CLK(NULL, "cpsw_cpts_rft_clk", "cpsw_cpts_rft_clk"), + DT_CLK(NULL, "gpio0_dbclk_mux_ck", "gpio0_dbclk_mux_ck"), + DT_CLK(NULL, "gpio0_dbclk", "gpio0_dbclk"), + DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), + DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), + DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), + DT_CLK(NULL, "lcd_gclk", "lcd_gclk"), + DT_CLK(NULL, "mmc_clk", "mmc_clk"), + DT_CLK(NULL, "gfx_fclk_clksel_ck", "gfx_fclk_clksel_ck"), + DT_CLK(NULL, "gfx_fck_div_ck", "gfx_fck_div_ck"), + DT_CLK(NULL, "sysclkout_pre_ck", "sysclkout_pre_ck"), + DT_CLK(NULL, "clkout2_div_ck", "clkout2_div_ck"), + DT_CLK(NULL, "timer_32k_ck", "clkdiv32k_ick"), + DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"), + DT_CLK(NULL, "dbg_sysclk_ck", "dbg_sysclk_ck"), + DT_CLK(NULL, "dbg_clka_ck", "dbg_clka_ck"), + DT_CLK(NULL, "stm_pmd_clock_mux_ck", "stm_pmd_clock_mux_ck"), + DT_CLK(NULL, "trace_pmd_clk_mux_ck", "trace_pmd_clk_mux_ck"), + DT_CLK(NULL, "stm_clk_div_ck", "stm_clk_div_ck"), + DT_CLK(NULL, "trace_clk_div_ck", "trace_clk_div_ck"), + DT_CLK(NULL, "clkout2_ck", "clkout2_ck"), + DT_CLK("48300200.ehrpwm", "tbclk", "ehrpwm0_tbclk"), + DT_CLK("48302200.ehrpwm", "tbclk", "ehrpwm1_tbclk"), + DT_CLK("48304200.ehrpwm", "tbclk", "ehrpwm2_tbclk"), + { .node_name = NULL }, +}; + +static const char *enable_init_clks[] = { + "dpll_ddr_m2_ck", + "dpll_mpu_m2_ck", + "l3_gclk", + "l4hs_gclk", + "l4fw_gclk", + "l4ls_gclk", + /* Required for external peripherals like, Audio codecs */ + "clkout2_ck", +}; + +int __init am33xx_dt_clk_init(void) +{ + struct clk *clk1, *clk2; + + ti_dt_clocks_register(am33xx_clks); + + omap2_clk_disable_autoidle_all(); + + omap2_clk_enable_init_clocks(enable_init_clks, + ARRAY_SIZE(enable_init_clks)); + + /* TRM ERRATA: Timer 3 & 6 default parent (TCLKIN) may not be always + * physically present, in such a case HWMOD enabling of + * clock would be failure with default parent. And timer + * probe thinks clock is already enabled, this leads to + * crash upon accessing timer 3 & 6 registers in probe. + * Fix by setting parent of both these timers to master + * oscillator clock. + */ + + clk1 = clk_get_sys(NULL, "sys_clkin_ck"); + clk2 = clk_get_sys(NULL, "timer3_fck"); + clk_set_parent(clk2, clk1); + + clk2 = clk_get_sys(NULL, "timer6_fck"); + clk_set_parent(clk2, clk1); + /* + * The On-Chip 32K RC Osc clock is not an accurate clock-source as per + * the design/spec, so as a result, for example, timer which supposed + * to get expired @60Sec, but will expire somewhere ~@40Sec, which is + * not expected by any use-case, so change WDT1 clock source to PRCM + * 32KHz clock. + */ + clk1 = clk_get_sys(NULL, "wdt1_fck"); + clk2 = clk_get_sys(NULL, "clkdiv32k_ick"); + clk_set_parent(clk1, clk2); + + return 0; +} diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c new file mode 100644 index 00000000000000..d3230234f07b98 --- /dev/null +++ b/drivers/clk/ti/clk-3xxx.c @@ -0,0 +1,401 @@ +/* + * OMAP3 Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc + * Tero Kristo (t-kristo@ti.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + + +static struct ti_dt_clk omap3xxx_clks[] = { + DT_CLK(NULL, "apb_pclk", "dummy_apb_pclk"), + DT_CLK(NULL, "omap_32k_fck", "omap_32k_fck"), + DT_CLK(NULL, "virt_12m_ck", "virt_12m_ck"), + DT_CLK(NULL, "virt_13m_ck", "virt_13m_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "virt_38_4m_ck", "virt_38_4m_ck"), + DT_CLK(NULL, "osc_sys_ck", "osc_sys_ck"), + DT_CLK("twl", "fck", "osc_sys_ck"), + DT_CLK(NULL, "sys_ck", "sys_ck"), + DT_CLK(NULL, "omap_96m_alwon_fck", "omap_96m_alwon_fck"), + DT_CLK("etb", "emu_core_alwon_ck", "emu_core_alwon_ck"), + DT_CLK(NULL, "sys_altclk", "sys_altclk"), + DT_CLK(NULL, "mcbsp_clks", "mcbsp_clks"), + DT_CLK(NULL, "sys_clkout1", "sys_clkout1"), + DT_CLK(NULL, "dpll1_ck", "dpll1_ck"), + DT_CLK(NULL, "dpll1_x2_ck", "dpll1_x2_ck"), + DT_CLK(NULL, "dpll1_x2m2_ck", "dpll1_x2m2_ck"), + DT_CLK(NULL, "dpll3_ck", "dpll3_ck"), + DT_CLK(NULL, "core_ck", "core_ck"), + DT_CLK(NULL, "dpll3_x2_ck", "dpll3_x2_ck"), + DT_CLK(NULL, "dpll3_m2_ck", "dpll3_m2_ck"), + DT_CLK(NULL, "dpll3_m2x2_ck", "dpll3_m2x2_ck"), + DT_CLK(NULL, "dpll3_m3_ck", "dpll3_m3_ck"), + DT_CLK(NULL, "dpll3_m3x2_ck", "dpll3_m3x2_ck"), + DT_CLK(NULL, "dpll4_ck", "dpll4_ck"), + DT_CLK(NULL, "dpll4_x2_ck", "dpll4_x2_ck"), + DT_CLK(NULL, "omap_96m_fck", "omap_96m_fck"), + DT_CLK(NULL, "cm_96m_fck", "cm_96m_fck"), + DT_CLK(NULL, "omap_54m_fck", "omap_54m_fck"), + DT_CLK(NULL, "omap_48m_fck", "omap_48m_fck"), + DT_CLK(NULL, "omap_12m_fck", "omap_12m_fck"), + DT_CLK(NULL, "dpll4_m2_ck", "dpll4_m2_ck"), + DT_CLK(NULL, "dpll4_m2x2_ck", "dpll4_m2x2_ck"), + DT_CLK(NULL, "dpll4_m3_ck", "dpll4_m3_ck"), + DT_CLK(NULL, "dpll4_m3x2_ck", "dpll4_m3x2_ck"), + DT_CLK(NULL, "dpll4_m4_ck", "dpll4_m4_ck"), + DT_CLK(NULL, "dpll4_m4x2_ck", "dpll4_m4x2_ck"), + DT_CLK(NULL, "dpll4_m5_ck", "dpll4_m5_ck"), + DT_CLK(NULL, "dpll4_m5x2_ck", "dpll4_m5x2_ck"), + DT_CLK(NULL, "dpll4_m6_ck", "dpll4_m6_ck"), + DT_CLK(NULL, "dpll4_m6x2_ck", "dpll4_m6x2_ck"), + DT_CLK("etb", "emu_per_alwon_ck", "emu_per_alwon_ck"), + DT_CLK(NULL, "clkout2_src_ck", "clkout2_src_ck"), + DT_CLK(NULL, "sys_clkout2", "sys_clkout2"), + DT_CLK(NULL, "corex2_fck", "corex2_fck"), + DT_CLK(NULL, "dpll1_fck", "dpll1_fck"), + DT_CLK(NULL, "mpu_ck", "mpu_ck"), + DT_CLK(NULL, "arm_fck", "arm_fck"), + DT_CLK("etb", "emu_mpu_alwon_ck", "emu_mpu_alwon_ck"), + DT_CLK(NULL, "l3_ick", "l3_ick"), + DT_CLK(NULL, "l4_ick", "l4_ick"), + DT_CLK(NULL, "rm_ick", "rm_ick"), + DT_CLK(NULL, "gpt10_fck", "gpt10_fck"), + DT_CLK(NULL, "gpt11_fck", "gpt11_fck"), + DT_CLK(NULL, "core_96m_fck", "core_96m_fck"), + DT_CLK(NULL, "mmchs2_fck", "mmchs2_fck"), + DT_CLK(NULL, "mmchs1_fck", "mmchs1_fck"), + DT_CLK(NULL, "i2c3_fck", "i2c3_fck"), + DT_CLK(NULL, "i2c2_fck", "i2c2_fck"), + DT_CLK(NULL, "i2c1_fck", "i2c1_fck"), + DT_CLK(NULL, "mcbsp5_fck", "mcbsp5_fck"), + DT_CLK(NULL, "mcbsp1_fck", "mcbsp1_fck"), + DT_CLK(NULL, "core_48m_fck", "core_48m_fck"), + DT_CLK(NULL, "mcspi4_fck", "mcspi4_fck"), + DT_CLK(NULL, "mcspi3_fck", "mcspi3_fck"), + DT_CLK(NULL, "mcspi2_fck", "mcspi2_fck"), + DT_CLK(NULL, "mcspi1_fck", "mcspi1_fck"), + DT_CLK(NULL, "uart2_fck", "uart2_fck"), + DT_CLK(NULL, "uart1_fck", "uart1_fck"), + DT_CLK(NULL, "core_12m_fck", "core_12m_fck"), + DT_CLK("omap_hdq.0", "fck", "hdq_fck"), + DT_CLK(NULL, "hdq_fck", "hdq_fck"), + DT_CLK(NULL, "core_l3_ick", "core_l3_ick"), + DT_CLK(NULL, "sdrc_ick", "sdrc_ick"), + DT_CLK(NULL, "gpmc_fck", "gpmc_fck"), + DT_CLK(NULL, "core_l4_ick", "core_l4_ick"), + DT_CLK("omap_hsmmc.1", "ick", "mmchs2_ick"), + DT_CLK("omap_hsmmc.0", "ick", "mmchs1_ick"), + DT_CLK(NULL, "mmchs2_ick", "mmchs2_ick"), + DT_CLK(NULL, "mmchs1_ick", "mmchs1_ick"), + DT_CLK("omap_hdq.0", "ick", "hdq_ick"), + DT_CLK(NULL, "hdq_ick", "hdq_ick"), + DT_CLK("omap2_mcspi.4", "ick", "mcspi4_ick"), + DT_CLK("omap2_mcspi.3", "ick", "mcspi3_ick"), + DT_CLK("omap2_mcspi.2", "ick", "mcspi2_ick"), + DT_CLK("omap2_mcspi.1", "ick", "mcspi1_ick"), + DT_CLK(NULL, "mcspi4_ick", "mcspi4_ick"), + DT_CLK(NULL, "mcspi3_ick", "mcspi3_ick"), + DT_CLK(NULL, "mcspi2_ick", "mcspi2_ick"), + DT_CLK(NULL, "mcspi1_ick", "mcspi1_ick"), + DT_CLK("omap_i2c.3", "ick", "i2c3_ick"), + DT_CLK("omap_i2c.2", "ick", "i2c2_ick"), + DT_CLK("omap_i2c.1", "ick", "i2c1_ick"), + DT_CLK(NULL, "i2c3_ick", "i2c3_ick"), + DT_CLK(NULL, "i2c2_ick", "i2c2_ick"), + DT_CLK(NULL, "i2c1_ick", "i2c1_ick"), + DT_CLK(NULL, "uart2_ick", "uart2_ick"), + DT_CLK(NULL, "uart1_ick", "uart1_ick"), + DT_CLK(NULL, "gpt11_ick", "gpt11_ick"), + DT_CLK(NULL, "gpt10_ick", "gpt10_ick"), + DT_CLK("omap-mcbsp.5", "ick", "mcbsp5_ick"), + DT_CLK("omap-mcbsp.1", "ick", "mcbsp1_ick"), + DT_CLK(NULL, "mcbsp5_ick", "mcbsp5_ick"), + DT_CLK(NULL, "mcbsp1_ick", "mcbsp1_ick"), + DT_CLK(NULL, "omapctrl_ick", "omapctrl_ick"), + DT_CLK(NULL, "dss_tv_fck", "dss_tv_fck"), + DT_CLK(NULL, "dss_96m_fck", "dss_96m_fck"), + DT_CLK(NULL, "dss2_alwon_fck", "dss2_alwon_fck"), + DT_CLK(NULL, "utmi_p1_gfclk", "dummy_ck"), + DT_CLK(NULL, "utmi_p2_gfclk", "dummy_ck"), + DT_CLK(NULL, "xclk60mhsp1_ck", "dummy_ck"), + DT_CLK(NULL, "xclk60mhsp2_ck", "dummy_ck"), + DT_CLK(NULL, "init_60m_fclk", "dummy_ck"), + DT_CLK(NULL, "gpt1_fck", "gpt1_fck"), + DT_CLK(NULL, "aes2_ick", "aes2_ick"), + DT_CLK(NULL, "wkup_32k_fck", "wkup_32k_fck"), + DT_CLK(NULL, "gpio1_dbck", "gpio1_dbck"), + DT_CLK(NULL, "sha12_ick", "sha12_ick"), + DT_CLK(NULL, "wdt2_fck", "wdt2_fck"), + DT_CLK("omap_wdt", "ick", "wdt2_ick"), + DT_CLK(NULL, "wdt2_ick", "wdt2_ick"), + DT_CLK(NULL, "wdt1_ick", "wdt1_ick"), + DT_CLK(NULL, "gpio1_ick", "gpio1_ick"), + DT_CLK(NULL, "omap_32ksync_ick", "omap_32ksync_ick"), + DT_CLK(NULL, "gpt12_ick", "gpt12_ick"), + DT_CLK(NULL, "gpt1_ick", "gpt1_ick"), + DT_CLK(NULL, "per_96m_fck", "per_96m_fck"), + DT_CLK(NULL, "per_48m_fck", "per_48m_fck"), + DT_CLK(NULL, "uart3_fck", "uart3_fck"), + DT_CLK(NULL, "gpt2_fck", "gpt2_fck"), + DT_CLK(NULL, "gpt3_fck", "gpt3_fck"), + DT_CLK(NULL, "gpt4_fck", "gpt4_fck"), + DT_CLK(NULL, "gpt5_fck", "gpt5_fck"), + DT_CLK(NULL, "gpt6_fck", "gpt6_fck"), + DT_CLK(NULL, "gpt7_fck", "gpt7_fck"), + DT_CLK(NULL, "gpt8_fck", "gpt8_fck"), + DT_CLK(NULL, "gpt9_fck", "gpt9_fck"), + DT_CLK(NULL, "per_32k_alwon_fck", "per_32k_alwon_fck"), + DT_CLK(NULL, "gpio6_dbck", "gpio6_dbck"), + DT_CLK(NULL, "gpio5_dbck", "gpio5_dbck"), + DT_CLK(NULL, "gpio4_dbck", "gpio4_dbck"), + DT_CLK(NULL, "gpio3_dbck", "gpio3_dbck"), + DT_CLK(NULL, "gpio2_dbck", "gpio2_dbck"), + DT_CLK(NULL, "wdt3_fck", "wdt3_fck"), + DT_CLK(NULL, "per_l4_ick", "per_l4_ick"), + DT_CLK(NULL, "gpio6_ick", "gpio6_ick"), + DT_CLK(NULL, "gpio5_ick", "gpio5_ick"), + DT_CLK(NULL, "gpio4_ick", "gpio4_ick"), + DT_CLK(NULL, "gpio3_ick", "gpio3_ick"), + DT_CLK(NULL, "gpio2_ick", "gpio2_ick"), + DT_CLK(NULL, "wdt3_ick", "wdt3_ick"), + DT_CLK(NULL, "uart3_ick", "uart3_ick"), + DT_CLK(NULL, "uart4_ick", "uart4_ick"), + DT_CLK(NULL, "gpt9_ick", "gpt9_ick"), + DT_CLK(NULL, "gpt8_ick", "gpt8_ick"), + DT_CLK(NULL, "gpt7_ick", "gpt7_ick"), + DT_CLK(NULL, "gpt6_ick", "gpt6_ick"), + DT_CLK(NULL, "gpt5_ick", "gpt5_ick"), + DT_CLK(NULL, "gpt4_ick", "gpt4_ick"), + DT_CLK(NULL, "gpt3_ick", "gpt3_ick"), + DT_CLK(NULL, "gpt2_ick", "gpt2_ick"), + DT_CLK("omap-mcbsp.2", "ick", "mcbsp2_ick"), + DT_CLK("omap-mcbsp.3", "ick", "mcbsp3_ick"), + DT_CLK("omap-mcbsp.4", "ick", "mcbsp4_ick"), + DT_CLK(NULL, "mcbsp4_ick", "mcbsp2_ick"), + DT_CLK(NULL, "mcbsp3_ick", "mcbsp3_ick"), + DT_CLK(NULL, "mcbsp2_ick", "mcbsp4_ick"), + DT_CLK(NULL, "mcbsp2_fck", "mcbsp2_fck"), + DT_CLK(NULL, "mcbsp3_fck", "mcbsp3_fck"), + DT_CLK(NULL, "mcbsp4_fck", "mcbsp4_fck"), + DT_CLK("etb", "emu_src_ck", "emu_src_ck"), + DT_CLK(NULL, "emu_src_ck", "emu_src_ck"), + DT_CLK(NULL, "pclk_fck", "pclk_fck"), + DT_CLK(NULL, "pclkx2_fck", "pclkx2_fck"), + DT_CLK(NULL, "atclk_fck", "atclk_fck"), + DT_CLK(NULL, "traceclk_src_fck", "traceclk_src_fck"), + DT_CLK(NULL, "traceclk_fck", "traceclk_fck"), + DT_CLK(NULL, "secure_32k_fck", "secure_32k_fck"), + DT_CLK(NULL, "gpt12_fck", "gpt12_fck"), + DT_CLK(NULL, "wdt1_fck", "wdt1_fck"), + DT_CLK(NULL, "timer_32k_ck", "omap_32k_fck"), + DT_CLK(NULL, "timer_sys_ck", "sys_ck"), + DT_CLK(NULL, "cpufreq_ck", "dpll1_ck"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk omap34xx_omap36xx_clks[] = { + DT_CLK(NULL, "aes1_ick", "aes1_ick"), + DT_CLK("omap_rng", "ick", "rng_ick"), + DT_CLK("omap3-rom-rng", "ick", "rng_ick"), + DT_CLK(NULL, "sha11_ick", "sha11_ick"), + DT_CLK(NULL, "des1_ick", "des1_ick"), + DT_CLK(NULL, "cam_mclk", "cam_mclk"), + DT_CLK(NULL, "cam_ick", "cam_ick"), + DT_CLK(NULL, "csi2_96m_fck", "csi2_96m_fck"), + DT_CLK(NULL, "security_l3_ick", "security_l3_ick"), + DT_CLK(NULL, "pka_ick", "pka_ick"), + DT_CLK(NULL, "icr_ick", "icr_ick"), + DT_CLK("omap-aes", "ick", "aes2_ick"), + DT_CLK("omap-sham", "ick", "sha12_ick"), + DT_CLK(NULL, "des2_ick", "des2_ick"), + DT_CLK(NULL, "mspro_ick", "mspro_ick"), + DT_CLK(NULL, "mailboxes_ick", "mailboxes_ick"), + DT_CLK(NULL, "ssi_l4_ick", "ssi_l4_ick"), + DT_CLK(NULL, "sr1_fck", "sr1_fck"), + DT_CLK(NULL, "sr2_fck", "sr2_fck"), + DT_CLK(NULL, "sr_l4_ick", "sr_l4_ick"), + DT_CLK(NULL, "security_l4_ick2", "security_l4_ick2"), + DT_CLK(NULL, "wkup_l4_ick", "wkup_l4_ick"), + DT_CLK(NULL, "dpll2_fck", "dpll2_fck"), + DT_CLK(NULL, "iva2_ck", "iva2_ck"), + DT_CLK(NULL, "modem_fck", "modem_fck"), + DT_CLK(NULL, "sad2d_ick", "sad2d_ick"), + DT_CLK(NULL, "mad2d_ick", "mad2d_ick"), + DT_CLK(NULL, "mspro_fck", "mspro_fck"), + DT_CLK(NULL, "dpll2_ck", "dpll2_ck"), + DT_CLK(NULL, "dpll2_m2_ck", "dpll2_m2_ck"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk omap36xx_omap3430es2plus_clks[] = { + DT_CLK(NULL, "ssi_ssr_fck", "ssi_ssr_fck_3430es2"), + DT_CLK(NULL, "ssi_sst_fck", "ssi_sst_fck_3430es2"), + DT_CLK("musb-omap2430", "ick", "hsotgusb_ick_3430es2"), + DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_3430es2"), + DT_CLK(NULL, "ssi_ick", "ssi_ick_3430es2"), + DT_CLK(NULL, "usim_fck", "usim_fck"), + DT_CLK(NULL, "usim_ick", "usim_ick"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk omap3430es1_clks[] = { + DT_CLK(NULL, "gfx_l3_ck", "gfx_l3_ck"), + DT_CLK(NULL, "gfx_l3_fck", "gfx_l3_fck"), + DT_CLK(NULL, "gfx_l3_ick", "gfx_l3_ick"), + DT_CLK(NULL, "gfx_cg1_ck", "gfx_cg1_ck"), + DT_CLK(NULL, "gfx_cg2_ck", "gfx_cg2_ck"), + DT_CLK(NULL, "d2d_26m_fck", "d2d_26m_fck"), + DT_CLK(NULL, "fshostusb_fck", "fshostusb_fck"), + DT_CLK(NULL, "ssi_ssr_fck", "ssi_ssr_fck_3430es1"), + DT_CLK(NULL, "ssi_sst_fck", "ssi_sst_fck_3430es1"), + DT_CLK("musb-omap2430", "ick", "hsotgusb_ick_3430es1"), + DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_3430es1"), + DT_CLK(NULL, "fac_ick", "fac_ick"), + DT_CLK(NULL, "ssi_ick", "ssi_ick_3430es1"), + DT_CLK(NULL, "usb_l4_ick", "usb_l4_ick"), + DT_CLK(NULL, "dss1_alwon_fck", "dss1_alwon_fck_3430es1"), + DT_CLK("omapdss_dss", "ick", "dss_ick_3430es1"), + DT_CLK(NULL, "dss_ick", "dss_ick_3430es1"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk omap36xx_am35xx_omap3430es2plus_clks[] = { + DT_CLK(NULL, "virt_16_8m_ck", "virt_16_8m_ck"), + DT_CLK(NULL, "dpll5_ck", "dpll5_ck"), + DT_CLK(NULL, "dpll5_m2_ck", "dpll5_m2_ck"), + DT_CLK(NULL, "sgx_fck", "sgx_fck"), + DT_CLK(NULL, "sgx_ick", "sgx_ick"), + DT_CLK(NULL, "cpefuse_fck", "cpefuse_fck"), + DT_CLK(NULL, "ts_fck", "ts_fck"), + DT_CLK(NULL, "usbtll_fck", "usbtll_fck"), + DT_CLK(NULL, "usbtll_ick", "usbtll_ick"), + DT_CLK("omap_hsmmc.2", "ick", "mmchs3_ick"), + DT_CLK(NULL, "mmchs3_ick", "mmchs3_ick"), + DT_CLK(NULL, "mmchs3_fck", "mmchs3_fck"), + DT_CLK(NULL, "dss1_alwon_fck", "dss1_alwon_fck_3430es2"), + DT_CLK("omapdss_dss", "ick", "dss_ick_3430es2"), + DT_CLK(NULL, "dss_ick", "dss_ick_3430es2"), + DT_CLK(NULL, "usbhost_120m_fck", "usbhost_120m_fck"), + DT_CLK(NULL, "usbhost_48m_fck", "usbhost_48m_fck"), + DT_CLK(NULL, "usbhost_ick", "usbhost_ick"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk am35xx_clks[] = { + DT_CLK(NULL, "ipss_ick", "ipss_ick"), + DT_CLK(NULL, "rmii_ck", "rmii_ck"), + DT_CLK(NULL, "pclk_ck", "pclk_ck"), + DT_CLK(NULL, "emac_ick", "emac_ick"), + DT_CLK(NULL, "emac_fck", "emac_fck"), + DT_CLK("davinci_emac.0", NULL, "emac_ick"), + DT_CLK("davinci_mdio.0", NULL, "emac_fck"), + DT_CLK("vpfe-capture", "master", "vpfe_ick"), + DT_CLK("vpfe-capture", "slave", "vpfe_fck"), + DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_am35xx"), + DT_CLK(NULL, "hsotgusb_fck", "hsotgusb_fck_am35xx"), + DT_CLK(NULL, "hecc_ck", "hecc_ck"), + DT_CLK(NULL, "uart4_ick", "uart4_ick_am35xx"), + DT_CLK(NULL, "uart4_fck", "uart4_fck_am35xx"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk omap36xx_clks[] = { + DT_CLK(NULL, "omap_192m_alwon_fck", "omap_192m_alwon_fck"), + DT_CLK(NULL, "uart4_fck", "uart4_fck"), + { .node_name = NULL }, +}; + +static const char *enable_init_clks[] = { + "sdrc_ick", + "gpmc_fck", + "omapctrl_ick", +}; + +enum { + OMAP3_SOC_AM35XX, + OMAP3_SOC_OMAP3430_ES1, + OMAP3_SOC_OMAP3430_ES2_PLUS, + OMAP3_SOC_OMAP3630, + OMAP3_SOC_TI81XX, +}; + +static int __init omap3xxx_dt_clk_init(int soc_type) +{ + if (soc_type == OMAP3_SOC_AM35XX || soc_type == OMAP3_SOC_OMAP3630 || + soc_type == OMAP3_SOC_OMAP3430_ES1 || + soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS) + ti_dt_clocks_register(omap3xxx_clks); + + if (soc_type == OMAP3_SOC_AM35XX) + ti_dt_clocks_register(am35xx_clks); + + if (soc_type == OMAP3_SOC_OMAP3630 || soc_type == OMAP3_SOC_AM35XX || + soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS) + ti_dt_clocks_register(omap36xx_am35xx_omap3430es2plus_clks); + + if (soc_type == OMAP3_SOC_OMAP3430_ES1) + ti_dt_clocks_register(omap3430es1_clks); + + if (soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS || + soc_type == OMAP3_SOC_OMAP3630) + ti_dt_clocks_register(omap36xx_omap3430es2plus_clks); + + if (soc_type == OMAP3_SOC_OMAP3430_ES1 || + soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS || + soc_type == OMAP3_SOC_OMAP3630) + ti_dt_clocks_register(omap34xx_omap36xx_clks); + + if (soc_type == OMAP3_SOC_OMAP3630) + ti_dt_clocks_register(omap36xx_clks); + + omap2_clk_disable_autoidle_all(); + + omap2_clk_enable_init_clocks(enable_init_clks, + ARRAY_SIZE(enable_init_clks)); + + pr_info("Clocking rate (Crystal/Core/MPU): %ld.%01ld/%ld/%ld MHz\n", + (clk_get_rate(clk_get_sys(NULL, "osc_sys_ck")) / 1000000), + (clk_get_rate(clk_get_sys(NULL, "osc_sys_ck")) / 100000) % 10, + (clk_get_rate(clk_get_sys(NULL, "core_ck")) / 1000000), + (clk_get_rate(clk_get_sys(NULL, "arm_fck")) / 1000000)); + + if (soc_type != OMAP3_SOC_TI81XX && soc_type != OMAP3_SOC_OMAP3430_ES1) + omap3_clk_lock_dpll5(); + + return 0; +} + +int __init omap3430_dt_clk_init(void) +{ + return omap3xxx_dt_clk_init(OMAP3_SOC_OMAP3430_ES2_PLUS); +} + +int __init omap3630_dt_clk_init(void) +{ + return omap3xxx_dt_clk_init(OMAP3_SOC_OMAP3630); +} + +int __init am35xx_dt_clk_init(void) +{ + return omap3xxx_dt_clk_init(OMAP3_SOC_AM35XX); +} + +int __init ti81xx_dt_clk_init(void) +{ + return omap3xxx_dt_clk_init(OMAP3_SOC_TI81XX); +} diff --git a/drivers/clk/ti/clk-43xx.c b/drivers/clk/ti/clk-43xx.c new file mode 100644 index 00000000000000..67c8de572c5018 --- /dev/null +++ b/drivers/clk/ti/clk-43xx.c @@ -0,0 +1,118 @@ +/* + * AM43XX Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc + * Tero Kristo (t-kristo@ti.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +static struct ti_dt_clk am43xx_clks[] = { + DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"), + DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_24000000_ck", "virt_24000000_ck"), + DT_CLK(NULL, "virt_25000000_ck", "virt_25000000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "sys_clkin_ck", "sys_clkin_ck"), + DT_CLK(NULL, "tclkin_ck", "tclkin_ck"), + DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), + DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), + DT_CLK(NULL, "dpll_core_m4_ck", "dpll_core_m4_ck"), + DT_CLK(NULL, "dpll_core_m5_ck", "dpll_core_m5_ck"), + DT_CLK(NULL, "dpll_core_m6_ck", "dpll_core_m6_ck"), + DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), + DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), + DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"), + DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"), + DT_CLK(NULL, "dpll_disp_ck", "dpll_disp_ck"), + DT_CLK(NULL, "dpll_disp_m2_ck", "dpll_disp_m2_ck"), + DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), + DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), + DT_CLK(NULL, "dpll_per_m2_div4_wkupdm_ck", "dpll_per_m2_div4_wkupdm_ck"), + DT_CLK(NULL, "dpll_per_m2_div4_ck", "dpll_per_m2_div4_ck"), + DT_CLK(NULL, "adc_tsc_fck", "adc_tsc_fck"), + DT_CLK(NULL, "clkdiv32k_ck", "clkdiv32k_ck"), + DT_CLK(NULL, "clkdiv32k_ick", "clkdiv32k_ick"), + DT_CLK(NULL, "dcan0_fck", "dcan0_fck"), + DT_CLK(NULL, "dcan1_fck", "dcan1_fck"), + DT_CLK(NULL, "pruss_ocp_gclk", "pruss_ocp_gclk"), + DT_CLK(NULL, "mcasp0_fck", "mcasp0_fck"), + DT_CLK(NULL, "mcasp1_fck", "mcasp1_fck"), + DT_CLK(NULL, "smartreflex0_fck", "smartreflex0_fck"), + DT_CLK(NULL, "smartreflex1_fck", "smartreflex1_fck"), + DT_CLK(NULL, "sha0_fck", "sha0_fck"), + DT_CLK(NULL, "aes0_fck", "aes0_fck"), + DT_CLK(NULL, "timer1_fck", "timer1_fck"), + DT_CLK(NULL, "timer2_fck", "timer2_fck"), + DT_CLK(NULL, "timer3_fck", "timer3_fck"), + DT_CLK(NULL, "timer4_fck", "timer4_fck"), + DT_CLK(NULL, "timer5_fck", "timer5_fck"), + DT_CLK(NULL, "timer6_fck", "timer6_fck"), + DT_CLK(NULL, "timer7_fck", "timer7_fck"), + DT_CLK(NULL, "wdt1_fck", "wdt1_fck"), + DT_CLK(NULL, "l3_gclk", "l3_gclk"), + DT_CLK(NULL, "dpll_core_m4_div2_ck", "dpll_core_m4_div2_ck"), + DT_CLK(NULL, "l4hs_gclk", "l4hs_gclk"), + DT_CLK(NULL, "l3s_gclk", "l3s_gclk"), + DT_CLK(NULL, "l4ls_gclk", "l4ls_gclk"), + DT_CLK(NULL, "clk_24mhz", "clk_24mhz"), + DT_CLK(NULL, "cpsw_125mhz_gclk", "cpsw_125mhz_gclk"), + DT_CLK(NULL, "cpsw_cpts_rft_clk", "cpsw_cpts_rft_clk"), + DT_CLK(NULL, "gpio0_dbclk_mux_ck", "gpio0_dbclk_mux_ck"), + DT_CLK(NULL, "gpio0_dbclk", "gpio0_dbclk"), + DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), + DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), + DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), + DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"), + DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"), + DT_CLK(NULL, "mmc_clk", "mmc_clk"), + DT_CLK(NULL, "gfx_fclk_clksel_ck", "gfx_fclk_clksel_ck"), + DT_CLK(NULL, "gfx_fck_div_ck", "gfx_fck_div_ck"), + DT_CLK(NULL, "timer_32k_ck", "clkdiv32k_ick"), + DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"), + DT_CLK(NULL, "sysclk_div", "sysclk_div"), + DT_CLK(NULL, "disp_clk", "disp_clk"), + DT_CLK(NULL, "clk_32k_mosc_ck", "clk_32k_mosc_ck"), + DT_CLK(NULL, "clk_32k_tpm_ck", "clk_32k_tpm_ck"), + DT_CLK(NULL, "dpll_extdev_ck", "dpll_extdev_ck"), + DT_CLK(NULL, "dpll_extdev_m2_ck", "dpll_extdev_m2_ck"), + DT_CLK(NULL, "mux_synctimer32k_ck", "mux_synctimer32k_ck"), + DT_CLK(NULL, "synctimer_32kclk", "synctimer_32kclk"), + DT_CLK(NULL, "timer8_fck", "timer8_fck"), + DT_CLK(NULL, "timer9_fck", "timer9_fck"), + DT_CLK(NULL, "timer10_fck", "timer10_fck"), + DT_CLK(NULL, "timer11_fck", "timer11_fck"), + DT_CLK(NULL, "cpsw_50m_clkdiv", "cpsw_50m_clkdiv"), + DT_CLK(NULL, "cpsw_5m_clkdiv", "cpsw_5m_clkdiv"), + DT_CLK(NULL, "dpll_ddr_x2_ck", "dpll_ddr_x2_ck"), + DT_CLK(NULL, "dpll_ddr_m4_ck", "dpll_ddr_m4_ck"), + DT_CLK(NULL, "dpll_per_clkdcoldo", "dpll_per_clkdcoldo"), + DT_CLK(NULL, "dll_aging_clk_div", "dll_aging_clk_div"), + DT_CLK(NULL, "div_core_25m_ck", "div_core_25m_ck"), + DT_CLK(NULL, "func_12m_clk", "func_12m_clk"), + DT_CLK(NULL, "vtp_clk_div", "vtp_clk_div"), + DT_CLK(NULL, "usbphy_32khz_clkmux", "usbphy_32khz_clkmux"), + { .node_name = NULL }, +}; + +int __init am43xx_dt_clk_init(void) +{ + ti_dt_clocks_register(am43xx_clks); + + omap2_clk_disable_autoidle_all(); + + return 0; +} diff --git a/drivers/clk/ti/clk-44xx.c b/drivers/clk/ti/clk-44xx.c new file mode 100644 index 00000000000000..ae00218b5da34a --- /dev/null +++ b/drivers/clk/ti/clk-44xx.c @@ -0,0 +1,316 @@ +/* + * OMAP4 Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo (t-kristo@ti.com) + * + * 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. + */ + +#include +#include +#include +#include +#include + +/* + * OMAP4 ABE DPLL default frequency. In OMAP4460 TRM version V, section + * "3.6.3.2.3 CM1_ABE Clock Generator" states that the "DPLL_ABE_X2_CLK + * must be set to 196.608 MHz" and hence, the DPLL locked frequency is + * half of this value. + */ +#define OMAP4_DPLL_ABE_DEFFREQ 98304000 + +/* + * OMAP4 USB DPLL default frequency. In OMAP4430 TRM version V, section + * "3.6.3.9.5 DPLL_USB Preferred Settings" shows that the preferred + * locked frequency for the USB DPLL is 960MHz. + */ +#define OMAP4_DPLL_USB_DEFFREQ 960000000 + +static struct ti_dt_clk omap44xx_clks[] = { + DT_CLK(NULL, "extalt_clkin_ck", "extalt_clkin_ck"), + DT_CLK(NULL, "pad_clks_src_ck", "pad_clks_src_ck"), + DT_CLK(NULL, "pad_clks_ck", "pad_clks_ck"), + DT_CLK(NULL, "pad_slimbus_core_clks_ck", "pad_slimbus_core_clks_ck"), + DT_CLK(NULL, "secure_32k_clk_src_ck", "secure_32k_clk_src_ck"), + DT_CLK(NULL, "slimbus_src_clk", "slimbus_src_clk"), + DT_CLK(NULL, "slimbus_clk", "slimbus_clk"), + DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"), + DT_CLK(NULL, "virt_12000000_ck", "virt_12000000_ck"), + DT_CLK(NULL, "virt_13000000_ck", "virt_13000000_ck"), + DT_CLK(NULL, "virt_16800000_ck", "virt_16800000_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "virt_27000000_ck", "virt_27000000_ck"), + DT_CLK(NULL, "virt_38400000_ck", "virt_38400000_ck"), + DT_CLK(NULL, "sys_clkin_ck", "sys_clkin_ck"), + DT_CLK(NULL, "tie_low_clock_ck", "tie_low_clock_ck"), + DT_CLK(NULL, "utmi_phy_clkout_ck", "utmi_phy_clkout_ck"), + DT_CLK(NULL, "xclk60mhsp1_ck", "xclk60mhsp1_ck"), + DT_CLK(NULL, "xclk60mhsp2_ck", "xclk60mhsp2_ck"), + DT_CLK(NULL, "xclk60motg_ck", "xclk60motg_ck"), + DT_CLK(NULL, "abe_dpll_bypass_clk_mux_ck", "abe_dpll_bypass_clk_mux_ck"), + DT_CLK(NULL, "abe_dpll_refclk_mux_ck", "abe_dpll_refclk_mux_ck"), + DT_CLK(NULL, "dpll_abe_ck", "dpll_abe_ck"), + DT_CLK(NULL, "dpll_abe_x2_ck", "dpll_abe_x2_ck"), + DT_CLK(NULL, "dpll_abe_m2x2_ck", "dpll_abe_m2x2_ck"), + DT_CLK(NULL, "abe_24m_fclk", "abe_24m_fclk"), + DT_CLK(NULL, "abe_clk", "abe_clk"), + DT_CLK(NULL, "aess_fclk", "aess_fclk"), + DT_CLK(NULL, "dpll_abe_m3x2_ck", "dpll_abe_m3x2_ck"), + DT_CLK(NULL, "core_hsd_byp_clk_mux_ck", "core_hsd_byp_clk_mux_ck"), + DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), + DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), + DT_CLK(NULL, "dpll_core_m6x2_ck", "dpll_core_m6x2_ck"), + DT_CLK(NULL, "dbgclk_mux_ck", "dbgclk_mux_ck"), + DT_CLK(NULL, "dpll_core_m2_ck", "dpll_core_m2_ck"), + DT_CLK(NULL, "ddrphy_ck", "ddrphy_ck"), + DT_CLK(NULL, "dpll_core_m5x2_ck", "dpll_core_m5x2_ck"), + DT_CLK(NULL, "div_core_ck", "div_core_ck"), + DT_CLK(NULL, "div_iva_hs_clk", "div_iva_hs_clk"), + DT_CLK(NULL, "div_mpu_hs_clk", "div_mpu_hs_clk"), + DT_CLK(NULL, "dpll_core_m4x2_ck", "dpll_core_m4x2_ck"), + DT_CLK(NULL, "dll_clk_div_ck", "dll_clk_div_ck"), + DT_CLK(NULL, "dpll_abe_m2_ck", "dpll_abe_m2_ck"), + DT_CLK(NULL, "dpll_core_m3x2_ck", "dpll_core_m3x2_ck"), + DT_CLK(NULL, "dpll_core_m7x2_ck", "dpll_core_m7x2_ck"), + DT_CLK(NULL, "iva_hsd_byp_clk_mux_ck", "iva_hsd_byp_clk_mux_ck"), + DT_CLK(NULL, "dpll_iva_ck", "dpll_iva_ck"), + DT_CLK(NULL, "dpll_iva_x2_ck", "dpll_iva_x2_ck"), + DT_CLK(NULL, "dpll_iva_m4x2_ck", "dpll_iva_m4x2_ck"), + DT_CLK(NULL, "dpll_iva_m5x2_ck", "dpll_iva_m5x2_ck"), + DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), + DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), + DT_CLK(NULL, "per_hs_clk_div_ck", "per_hs_clk_div_ck"), + DT_CLK(NULL, "per_hsd_byp_clk_mux_ck", "per_hsd_byp_clk_mux_ck"), + DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), + DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), + DT_CLK(NULL, "dpll_per_x2_ck", "dpll_per_x2_ck"), + DT_CLK(NULL, "dpll_per_m2x2_ck", "dpll_per_m2x2_ck"), + DT_CLK(NULL, "dpll_per_m3x2_ck", "dpll_per_m3x2_ck"), + DT_CLK(NULL, "dpll_per_m4x2_ck", "dpll_per_m4x2_ck"), + DT_CLK(NULL, "dpll_per_m5x2_ck", "dpll_per_m5x2_ck"), + DT_CLK(NULL, "dpll_per_m6x2_ck", "dpll_per_m6x2_ck"), + DT_CLK(NULL, "dpll_per_m7x2_ck", "dpll_per_m7x2_ck"), + DT_CLK(NULL, "usb_hs_clk_div_ck", "usb_hs_clk_div_ck"), + DT_CLK(NULL, "dpll_usb_ck", "dpll_usb_ck"), + DT_CLK(NULL, "dpll_usb_clkdcoldo_ck", "dpll_usb_clkdcoldo_ck"), + DT_CLK(NULL, "dpll_usb_m2_ck", "dpll_usb_m2_ck"), + DT_CLK(NULL, "ducati_clk_mux_ck", "ducati_clk_mux_ck"), + DT_CLK(NULL, "func_12m_fclk", "func_12m_fclk"), + DT_CLK(NULL, "func_24m_clk", "func_24m_clk"), + DT_CLK(NULL, "func_24mc_fclk", "func_24mc_fclk"), + DT_CLK(NULL, "func_48m_fclk", "func_48m_fclk"), + DT_CLK(NULL, "func_48mc_fclk", "func_48mc_fclk"), + DT_CLK(NULL, "func_64m_fclk", "func_64m_fclk"), + DT_CLK(NULL, "func_96m_fclk", "func_96m_fclk"), + DT_CLK(NULL, "init_60m_fclk", "init_60m_fclk"), + DT_CLK(NULL, "l3_div_ck", "l3_div_ck"), + DT_CLK(NULL, "l4_div_ck", "l4_div_ck"), + DT_CLK(NULL, "lp_clk_div_ck", "lp_clk_div_ck"), + DT_CLK(NULL, "l4_wkup_clk_mux_ck", "l4_wkup_clk_mux_ck"), + DT_CLK("smp_twd", NULL, "mpu_periphclk"), + DT_CLK(NULL, "ocp_abe_iclk", "ocp_abe_iclk"), + DT_CLK(NULL, "per_abe_24m_fclk", "per_abe_24m_fclk"), + DT_CLK(NULL, "per_abe_nc_fclk", "per_abe_nc_fclk"), + DT_CLK(NULL, "syc_clk_div_ck", "syc_clk_div_ck"), + DT_CLK(NULL, "aes1_fck", "aes1_fck"), + DT_CLK(NULL, "aes2_fck", "aes2_fck"), + DT_CLK(NULL, "dmic_sync_mux_ck", "dmic_sync_mux_ck"), + DT_CLK(NULL, "func_dmic_abe_gfclk", "func_dmic_abe_gfclk"), + DT_CLK(NULL, "dss_sys_clk", "dss_sys_clk"), + DT_CLK(NULL, "dss_tv_clk", "dss_tv_clk"), + DT_CLK(NULL, "dss_dss_clk", "dss_dss_clk"), + DT_CLK(NULL, "dss_48mhz_clk", "dss_48mhz_clk"), + DT_CLK(NULL, "dss_fck", "dss_fck"), + DT_CLK("omapdss_dss", "ick", "dss_fck"), + DT_CLK(NULL, "fdif_fck", "fdif_fck"), + DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), + DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), + DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), + DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"), + DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"), + DT_CLK(NULL, "gpio6_dbclk", "gpio6_dbclk"), + DT_CLK(NULL, "sgx_clk_mux", "sgx_clk_mux"), + DT_CLK(NULL, "hsi_fck", "hsi_fck"), + DT_CLK(NULL, "iss_ctrlclk", "iss_ctrlclk"), + DT_CLK(NULL, "mcasp_sync_mux_ck", "mcasp_sync_mux_ck"), + DT_CLK(NULL, "func_mcasp_abe_gfclk", "func_mcasp_abe_gfclk"), + DT_CLK(NULL, "mcbsp1_sync_mux_ck", "mcbsp1_sync_mux_ck"), + DT_CLK(NULL, "func_mcbsp1_gfclk", "func_mcbsp1_gfclk"), + DT_CLK(NULL, "mcbsp2_sync_mux_ck", "mcbsp2_sync_mux_ck"), + DT_CLK(NULL, "func_mcbsp2_gfclk", "func_mcbsp2_gfclk"), + DT_CLK(NULL, "mcbsp3_sync_mux_ck", "mcbsp3_sync_mux_ck"), + DT_CLK(NULL, "func_mcbsp3_gfclk", "func_mcbsp3_gfclk"), + DT_CLK(NULL, "mcbsp4_sync_mux_ck", "mcbsp4_sync_mux_ck"), + DT_CLK(NULL, "per_mcbsp4_gfclk", "per_mcbsp4_gfclk"), + DT_CLK(NULL, "hsmmc1_fclk", "hsmmc1_fclk"), + DT_CLK(NULL, "hsmmc2_fclk", "hsmmc2_fclk"), + DT_CLK(NULL, "ocp2scp_usb_phy_phy_48m", "ocp2scp_usb_phy_phy_48m"), + DT_CLK(NULL, "sha2md5_fck", "sha2md5_fck"), + DT_CLK(NULL, "slimbus1_fclk_1", "slimbus1_fclk_1"), + DT_CLK(NULL, "slimbus1_fclk_0", "slimbus1_fclk_0"), + DT_CLK(NULL, "slimbus1_fclk_2", "slimbus1_fclk_2"), + DT_CLK(NULL, "slimbus1_slimbus_clk", "slimbus1_slimbus_clk"), + DT_CLK(NULL, "slimbus2_fclk_1", "slimbus2_fclk_1"), + DT_CLK(NULL, "slimbus2_fclk_0", "slimbus2_fclk_0"), + DT_CLK(NULL, "slimbus2_slimbus_clk", "slimbus2_slimbus_clk"), + DT_CLK(NULL, "smartreflex_core_fck", "smartreflex_core_fck"), + DT_CLK(NULL, "smartreflex_iva_fck", "smartreflex_iva_fck"), + DT_CLK(NULL, "smartreflex_mpu_fck", "smartreflex_mpu_fck"), + DT_CLK(NULL, "dmt1_clk_mux", "dmt1_clk_mux"), + DT_CLK(NULL, "cm2_dm10_mux", "cm2_dm10_mux"), + DT_CLK(NULL, "cm2_dm11_mux", "cm2_dm11_mux"), + DT_CLK(NULL, "cm2_dm2_mux", "cm2_dm2_mux"), + DT_CLK(NULL, "cm2_dm3_mux", "cm2_dm3_mux"), + DT_CLK(NULL, "cm2_dm4_mux", "cm2_dm4_mux"), + DT_CLK(NULL, "timer5_sync_mux", "timer5_sync_mux"), + DT_CLK(NULL, "timer6_sync_mux", "timer6_sync_mux"), + DT_CLK(NULL, "timer7_sync_mux", "timer7_sync_mux"), + DT_CLK(NULL, "timer8_sync_mux", "timer8_sync_mux"), + DT_CLK(NULL, "cm2_dm9_mux", "cm2_dm9_mux"), + DT_CLK(NULL, "usb_host_fs_fck", "usb_host_fs_fck"), + DT_CLK("usbhs_omap", "fs_fck", "usb_host_fs_fck"), + DT_CLK(NULL, "utmi_p1_gfclk", "utmi_p1_gfclk"), + DT_CLK(NULL, "usb_host_hs_utmi_p1_clk", "usb_host_hs_utmi_p1_clk"), + DT_CLK(NULL, "utmi_p2_gfclk", "utmi_p2_gfclk"), + DT_CLK(NULL, "usb_host_hs_utmi_p2_clk", "usb_host_hs_utmi_p2_clk"), + DT_CLK(NULL, "usb_host_hs_utmi_p3_clk", "usb_host_hs_utmi_p3_clk"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p1_clk", "usb_host_hs_hsic480m_p1_clk"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p1_clk", "usb_host_hs_hsic60m_p1_clk"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p2_clk", "usb_host_hs_hsic60m_p2_clk"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p2_clk", "usb_host_hs_hsic480m_p2_clk"), + DT_CLK(NULL, "usb_host_hs_func48mclk", "usb_host_hs_func48mclk"), + DT_CLK(NULL, "usb_host_hs_fck", "usb_host_hs_fck"), + DT_CLK("usbhs_omap", "hs_fck", "usb_host_hs_fck"), + DT_CLK(NULL, "otg_60m_gfclk", "otg_60m_gfclk"), + DT_CLK(NULL, "usb_otg_hs_xclk", "usb_otg_hs_xclk"), + DT_CLK(NULL, "usb_otg_hs_ick", "usb_otg_hs_ick"), + DT_CLK("musb-omap2430", "ick", "usb_otg_hs_ick"), + DT_CLK(NULL, "usb_phy_cm_clk32k", "usb_phy_cm_clk32k"), + DT_CLK(NULL, "usb_tll_hs_usb_ch2_clk", "usb_tll_hs_usb_ch2_clk"), + DT_CLK(NULL, "usb_tll_hs_usb_ch0_clk", "usb_tll_hs_usb_ch0_clk"), + DT_CLK(NULL, "usb_tll_hs_usb_ch1_clk", "usb_tll_hs_usb_ch1_clk"), + DT_CLK(NULL, "usb_tll_hs_ick", "usb_tll_hs_ick"), + DT_CLK("usbhs_omap", "usbtll_ick", "usb_tll_hs_ick"), + DT_CLK("usbhs_tll", "usbtll_ick", "usb_tll_hs_ick"), + DT_CLK(NULL, "usim_ck", "usim_ck"), + DT_CLK(NULL, "usim_fclk", "usim_fclk"), + DT_CLK(NULL, "pmd_stm_clock_mux_ck", "pmd_stm_clock_mux_ck"), + DT_CLK(NULL, "pmd_trace_clk_mux_ck", "pmd_trace_clk_mux_ck"), + DT_CLK(NULL, "stm_clk_div_ck", "stm_clk_div_ck"), + DT_CLK(NULL, "trace_clk_div_ck", "trace_clk_div_ck"), + DT_CLK(NULL, "auxclk0_src_ck", "auxclk0_src_ck"), + DT_CLK(NULL, "auxclk0_ck", "auxclk0_ck"), + DT_CLK(NULL, "auxclkreq0_ck", "auxclkreq0_ck"), + DT_CLK(NULL, "auxclk1_src_ck", "auxclk1_src_ck"), + DT_CLK(NULL, "auxclk1_ck", "auxclk1_ck"), + DT_CLK(NULL, "auxclkreq1_ck", "auxclkreq1_ck"), + DT_CLK(NULL, "auxclk2_src_ck", "auxclk2_src_ck"), + DT_CLK(NULL, "auxclk2_ck", "auxclk2_ck"), + DT_CLK(NULL, "auxclkreq2_ck", "auxclkreq2_ck"), + DT_CLK(NULL, "auxclk3_src_ck", "auxclk3_src_ck"), + DT_CLK(NULL, "auxclk3_ck", "auxclk3_ck"), + DT_CLK(NULL, "auxclkreq3_ck", "auxclkreq3_ck"), + DT_CLK(NULL, "auxclk4_src_ck", "auxclk4_src_ck"), + DT_CLK(NULL, "auxclk4_ck", "auxclk4_ck"), + DT_CLK(NULL, "auxclkreq4_ck", "auxclkreq4_ck"), + DT_CLK(NULL, "auxclk5_src_ck", "auxclk5_src_ck"), + DT_CLK(NULL, "auxclk5_ck", "auxclk5_ck"), + DT_CLK(NULL, "auxclkreq5_ck", "auxclkreq5_ck"), + DT_CLK("50000000.gpmc", "fck", "dummy_ck"), + DT_CLK("omap_i2c.1", "ick", "dummy_ck"), + DT_CLK("omap_i2c.2", "ick", "dummy_ck"), + DT_CLK("omap_i2c.3", "ick", "dummy_ck"), + DT_CLK("omap_i2c.4", "ick", "dummy_ck"), + DT_CLK(NULL, "mailboxes_ick", "dummy_ck"), + DT_CLK("omap_hsmmc.0", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.1", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.2", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.3", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.4", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.1", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.2", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.3", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.4", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.1", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.2", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.3", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.4", "ick", "dummy_ck"), + DT_CLK(NULL, "uart1_ick", "dummy_ck"), + DT_CLK(NULL, "uart2_ick", "dummy_ck"), + DT_CLK(NULL, "uart3_ick", "dummy_ck"), + DT_CLK(NULL, "uart4_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbhost_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"), + DT_CLK("usbhs_tll", "usbtll_fck", "dummy_ck"), + DT_CLK("omap_wdt", "ick", "dummy_ck"), + DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"), + DT_CLK("omap_timer.1", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.2", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.3", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.4", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.9", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.10", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.11", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.5", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("omap_timer.6", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("omap_timer.7", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("omap_timer.8", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("4a318000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("48032000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("48034000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("48036000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("4803e000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("48086000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("48088000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("40138000.timer", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("4013a000.timer", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("4013c000.timer", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("4013e000.timer", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK(NULL, "cpufreq_ck", "dpll_mpu_ck"), + DT_CLK(NULL, "bandgap_fclk", "bandgap_fclk"), + DT_CLK(NULL, "div_ts_ck", "div_ts_ck"), + DT_CLK(NULL, "bandgap_ts_fclk", "bandgap_ts_fclk"), + { .node_name = NULL }, +}; + +int __init omap4xxx_dt_clk_init(void) +{ + int rc; + struct clk *abe_dpll_ref, *abe_dpll, *sys_32k_ck, *usb_dpll; + + ti_dt_clocks_register(omap44xx_clks); + + omap2_clk_disable_autoidle_all(); + + /* + * Lock USB DPLL on OMAP4 devices so that the L3INIT power + * domain can transition to retention state when not in use. + */ + usb_dpll = clk_get_sys(NULL, "dpll_usb_ck"); + rc = clk_set_rate(usb_dpll, OMAP4_DPLL_USB_DEFFREQ); + if (rc) + pr_err("%s: failed to configure USB DPLL!\n", __func__); + + /* + * On OMAP4460 the ABE DPLL fails to turn on if in idle low-power + * state when turning the ABE clock domain. Workaround this by + * locking the ABE DPLL on boot. + * Lock the ABE DPLL in any case to avoid issues with audio. + */ + abe_dpll_ref = clk_get_sys(NULL, "abe_dpll_refclk_mux_ck"); + sys_32k_ck = clk_get_sys(NULL, "sys_32k_ck"); + rc = clk_set_parent(abe_dpll_ref, sys_32k_ck); + abe_dpll = clk_get_sys(NULL, "dpll_abe_ck"); + if (!rc) + rc = clk_set_rate(abe_dpll, OMAP4_DPLL_ABE_DEFFREQ); + if (rc) + pr_err("%s: failed to configure ABE DPLL!\n", __func__); + + return 0; +} diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c new file mode 100644 index 00000000000000..0ef9f581286bcc --- /dev/null +++ b/drivers/clk/ti/clk-54xx.c @@ -0,0 +1,255 @@ +/* + * OMAP5 Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo (t-kristo@ti.com) + * + * 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. + */ + +#include +#include +#include +#include +#include +#include + +#define OMAP5_DPLL_ABE_DEFFREQ 98304000 + +/* + * OMAP543x TRM, section "3.6.3.9.5 DPLL_USB Preferred Settings" + * states it must be at 960MHz + */ +#define OMAP5_DPLL_USB_DEFFREQ 960000000 + +static struct ti_dt_clk omap54xx_clks[] = { + DT_CLK(NULL, "pad_clks_src_ck", "pad_clks_src_ck"), + DT_CLK(NULL, "pad_clks_ck", "pad_clks_ck"), + DT_CLK(NULL, "secure_32k_clk_src_ck", "secure_32k_clk_src_ck"), + DT_CLK(NULL, "slimbus_src_clk", "slimbus_src_clk"), + DT_CLK(NULL, "slimbus_clk", "slimbus_clk"), + DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"), + DT_CLK(NULL, "virt_12000000_ck", "virt_12000000_ck"), + DT_CLK(NULL, "virt_13000000_ck", "virt_13000000_ck"), + DT_CLK(NULL, "virt_16800000_ck", "virt_16800000_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "virt_27000000_ck", "virt_27000000_ck"), + DT_CLK(NULL, "virt_38400000_ck", "virt_38400000_ck"), + DT_CLK(NULL, "sys_clkin", "sys_clkin"), + DT_CLK(NULL, "xclk60mhsp1_ck", "xclk60mhsp1_ck"), + DT_CLK(NULL, "xclk60mhsp2_ck", "xclk60mhsp2_ck"), + DT_CLK(NULL, "abe_dpll_bypass_clk_mux", "abe_dpll_bypass_clk_mux"), + DT_CLK(NULL, "abe_dpll_clk_mux", "abe_dpll_clk_mux"), + DT_CLK(NULL, "dpll_abe_ck", "dpll_abe_ck"), + DT_CLK(NULL, "dpll_abe_x2_ck", "dpll_abe_x2_ck"), + DT_CLK(NULL, "dpll_abe_m2x2_ck", "dpll_abe_m2x2_ck"), + DT_CLK(NULL, "abe_24m_fclk", "abe_24m_fclk"), + DT_CLK(NULL, "abe_clk", "abe_clk"), + DT_CLK(NULL, "abe_iclk", "abe_iclk"), + DT_CLK(NULL, "abe_lp_clk_div", "abe_lp_clk_div"), + DT_CLK(NULL, "dpll_abe_m3x2_ck", "dpll_abe_m3x2_ck"), + DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), + DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), + DT_CLK(NULL, "dpll_core_h21x2_ck", "dpll_core_h21x2_ck"), + DT_CLK(NULL, "c2c_fclk", "c2c_fclk"), + DT_CLK(NULL, "c2c_iclk", "c2c_iclk"), + DT_CLK(NULL, "custefuse_sys_gfclk_div", "custefuse_sys_gfclk_div"), + DT_CLK(NULL, "dpll_core_h11x2_ck", "dpll_core_h11x2_ck"), + DT_CLK(NULL, "dpll_core_h12x2_ck", "dpll_core_h12x2_ck"), + DT_CLK(NULL, "dpll_core_h13x2_ck", "dpll_core_h13x2_ck"), + DT_CLK(NULL, "dpll_core_h14x2_ck", "dpll_core_h14x2_ck"), + DT_CLK(NULL, "dpll_core_h22x2_ck", "dpll_core_h22x2_ck"), + DT_CLK(NULL, "dpll_core_h23x2_ck", "dpll_core_h23x2_ck"), + DT_CLK(NULL, "dpll_core_h24x2_ck", "dpll_core_h24x2_ck"), + DT_CLK(NULL, "dpll_core_m2_ck", "dpll_core_m2_ck"), + DT_CLK(NULL, "dpll_core_m3x2_ck", "dpll_core_m3x2_ck"), + DT_CLK(NULL, "iva_dpll_hs_clk_div", "iva_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_iva_ck", "dpll_iva_ck"), + DT_CLK(NULL, "dpll_iva_x2_ck", "dpll_iva_x2_ck"), + DT_CLK(NULL, "dpll_iva_h11x2_ck", "dpll_iva_h11x2_ck"), + DT_CLK(NULL, "dpll_iva_h12x2_ck", "dpll_iva_h12x2_ck"), + DT_CLK(NULL, "mpu_dpll_hs_clk_div", "mpu_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), + DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), + DT_CLK(NULL, "per_dpll_hs_clk_div", "per_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), + DT_CLK(NULL, "dpll_per_x2_ck", "dpll_per_x2_ck"), + DT_CLK(NULL, "dpll_per_h11x2_ck", "dpll_per_h11x2_ck"), + DT_CLK(NULL, "dpll_per_h12x2_ck", "dpll_per_h12x2_ck"), + DT_CLK(NULL, "dpll_per_h14x2_ck", "dpll_per_h14x2_ck"), + DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), + DT_CLK(NULL, "dpll_per_m2x2_ck", "dpll_per_m2x2_ck"), + DT_CLK(NULL, "dpll_per_m3x2_ck", "dpll_per_m3x2_ck"), + DT_CLK(NULL, "dpll_unipro1_ck", "dpll_unipro1_ck"), + DT_CLK(NULL, "dpll_unipro1_clkdcoldo", "dpll_unipro1_clkdcoldo"), + DT_CLK(NULL, "dpll_unipro1_m2_ck", "dpll_unipro1_m2_ck"), + DT_CLK(NULL, "dpll_unipro2_ck", "dpll_unipro2_ck"), + DT_CLK(NULL, "dpll_unipro2_clkdcoldo", "dpll_unipro2_clkdcoldo"), + DT_CLK(NULL, "dpll_unipro2_m2_ck", "dpll_unipro2_m2_ck"), + DT_CLK(NULL, "usb_dpll_hs_clk_div", "usb_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_usb_ck", "dpll_usb_ck"), + DT_CLK(NULL, "dpll_usb_clkdcoldo", "dpll_usb_clkdcoldo"), + DT_CLK(NULL, "dpll_usb_m2_ck", "dpll_usb_m2_ck"), + DT_CLK(NULL, "dss_syc_gfclk_div", "dss_syc_gfclk_div"), + DT_CLK(NULL, "func_128m_clk", "func_128m_clk"), + DT_CLK(NULL, "func_12m_fclk", "func_12m_fclk"), + DT_CLK(NULL, "func_24m_clk", "func_24m_clk"), + DT_CLK(NULL, "func_48m_fclk", "func_48m_fclk"), + DT_CLK(NULL, "func_96m_fclk", "func_96m_fclk"), + DT_CLK(NULL, "l3_iclk_div", "l3_iclk_div"), + DT_CLK(NULL, "gpu_l3_iclk", "gpu_l3_iclk"), + DT_CLK(NULL, "l3init_60m_fclk", "l3init_60m_fclk"), + DT_CLK(NULL, "wkupaon_iclk_mux", "wkupaon_iclk_mux"), + DT_CLK(NULL, "l3instr_ts_gclk_div", "l3instr_ts_gclk_div"), + DT_CLK(NULL, "l4_root_clk_div", "l4_root_clk_div"), + DT_CLK(NULL, "dss_32khz_clk", "dss_32khz_clk"), + DT_CLK(NULL, "dss_48mhz_clk", "dss_48mhz_clk"), + DT_CLK(NULL, "dss_dss_clk", "dss_dss_clk"), + DT_CLK(NULL, "dss_sys_clk", "dss_sys_clk"), + DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), + DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), + DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), + DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"), + DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"), + DT_CLK(NULL, "gpio6_dbclk", "gpio6_dbclk"), + DT_CLK(NULL, "gpio7_dbclk", "gpio7_dbclk"), + DT_CLK(NULL, "gpio8_dbclk", "gpio8_dbclk"), + DT_CLK(NULL, "iss_ctrlclk", "iss_ctrlclk"), + DT_CLK(NULL, "lli_txphy_clk", "lli_txphy_clk"), + DT_CLK(NULL, "lli_txphy_ls_clk", "lli_txphy_ls_clk"), + DT_CLK(NULL, "mmc1_32khz_clk", "mmc1_32khz_clk"), + DT_CLK(NULL, "sata_ref_clk", "sata_ref_clk"), + DT_CLK(NULL, "slimbus1_slimbus_clk", "slimbus1_slimbus_clk"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p1_clk", "usb_host_hs_hsic480m_p1_clk"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p2_clk", "usb_host_hs_hsic480m_p2_clk"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p3_clk", "usb_host_hs_hsic480m_p3_clk"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p1_clk", "usb_host_hs_hsic60m_p1_clk"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p2_clk", "usb_host_hs_hsic60m_p2_clk"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p3_clk", "usb_host_hs_hsic60m_p3_clk"), + DT_CLK(NULL, "usb_host_hs_utmi_p1_clk", "usb_host_hs_utmi_p1_clk"), + DT_CLK(NULL, "usb_host_hs_utmi_p2_clk", "usb_host_hs_utmi_p2_clk"), + DT_CLK(NULL, "usb_host_hs_utmi_p3_clk", "usb_host_hs_utmi_p3_clk"), + DT_CLK(NULL, "usb_otg_ss_refclk960m", "usb_otg_ss_refclk960m"), + DT_CLK(NULL, "usb_phy_cm_clk32k", "usb_phy_cm_clk32k"), + DT_CLK(NULL, "usb_tll_hs_usb_ch0_clk", "usb_tll_hs_usb_ch0_clk"), + DT_CLK(NULL, "usb_tll_hs_usb_ch1_clk", "usb_tll_hs_usb_ch1_clk"), + DT_CLK(NULL, "usb_tll_hs_usb_ch2_clk", "usb_tll_hs_usb_ch2_clk"), + DT_CLK(NULL, "aess_fclk", "aess_fclk"), + DT_CLK(NULL, "dmic_sync_mux_ck", "dmic_sync_mux_ck"), + DT_CLK(NULL, "dmic_gfclk", "dmic_gfclk"), + DT_CLK(NULL, "fdif_fclk", "fdif_fclk"), + DT_CLK(NULL, "gpu_core_gclk_mux", "gpu_core_gclk_mux"), + DT_CLK(NULL, "gpu_hyd_gclk_mux", "gpu_hyd_gclk_mux"), + DT_CLK(NULL, "hsi_fclk", "hsi_fclk"), + DT_CLK(NULL, "mcasp_sync_mux_ck", "mcasp_sync_mux_ck"), + DT_CLK(NULL, "mcasp_gfclk", "mcasp_gfclk"), + DT_CLK(NULL, "mcbsp1_sync_mux_ck", "mcbsp1_sync_mux_ck"), + DT_CLK(NULL, "mcbsp1_gfclk", "mcbsp1_gfclk"), + DT_CLK(NULL, "mcbsp2_sync_mux_ck", "mcbsp2_sync_mux_ck"), + DT_CLK(NULL, "mcbsp2_gfclk", "mcbsp2_gfclk"), + DT_CLK(NULL, "mcbsp3_sync_mux_ck", "mcbsp3_sync_mux_ck"), + DT_CLK(NULL, "mcbsp3_gfclk", "mcbsp3_gfclk"), + DT_CLK(NULL, "mmc1_fclk_mux", "mmc1_fclk_mux"), + DT_CLK(NULL, "mmc1_fclk", "mmc1_fclk"), + DT_CLK(NULL, "mmc2_fclk_mux", "mmc2_fclk_mux"), + DT_CLK(NULL, "mmc2_fclk", "mmc2_fclk"), + DT_CLK(NULL, "timer10_gfclk_mux", "timer10_gfclk_mux"), + DT_CLK(NULL, "timer11_gfclk_mux", "timer11_gfclk_mux"), + DT_CLK(NULL, "timer1_gfclk_mux", "timer1_gfclk_mux"), + DT_CLK(NULL, "timer2_gfclk_mux", "timer2_gfclk_mux"), + DT_CLK(NULL, "timer3_gfclk_mux", "timer3_gfclk_mux"), + DT_CLK(NULL, "timer4_gfclk_mux", "timer4_gfclk_mux"), + DT_CLK(NULL, "timer5_gfclk_mux", "timer5_gfclk_mux"), + DT_CLK(NULL, "timer6_gfclk_mux", "timer6_gfclk_mux"), + DT_CLK(NULL, "timer7_gfclk_mux", "timer7_gfclk_mux"), + DT_CLK(NULL, "timer8_gfclk_mux", "timer8_gfclk_mux"), + DT_CLK(NULL, "timer9_gfclk_mux", "timer9_gfclk_mux"), + DT_CLK(NULL, "utmi_p1_gfclk", "utmi_p1_gfclk"), + DT_CLK(NULL, "utmi_p2_gfclk", "utmi_p2_gfclk"), + DT_CLK(NULL, "auxclk0_src_ck", "auxclk0_src_ck"), + DT_CLK(NULL, "auxclk0_ck", "auxclk0_ck"), + DT_CLK(NULL, "auxclkreq0_ck", "auxclkreq0_ck"), + DT_CLK(NULL, "auxclk1_src_ck", "auxclk1_src_ck"), + DT_CLK(NULL, "auxclk1_ck", "auxclk1_ck"), + DT_CLK(NULL, "auxclkreq1_ck", "auxclkreq1_ck"), + DT_CLK(NULL, "auxclk2_src_ck", "auxclk2_src_ck"), + DT_CLK(NULL, "auxclk2_ck", "auxclk2_ck"), + DT_CLK(NULL, "auxclkreq2_ck", "auxclkreq2_ck"), + DT_CLK(NULL, "auxclk3_src_ck", "auxclk3_src_ck"), + DT_CLK(NULL, "auxclk3_ck", "auxclk3_ck"), + DT_CLK(NULL, "auxclkreq3_ck", "auxclkreq3_ck"), + DT_CLK(NULL, "gpmc_ck", "dummy_ck"), + DT_CLK("omap_i2c.1", "ick", "dummy_ck"), + DT_CLK("omap_i2c.2", "ick", "dummy_ck"), + DT_CLK("omap_i2c.3", "ick", "dummy_ck"), + DT_CLK("omap_i2c.4", "ick", "dummy_ck"), + DT_CLK(NULL, "mailboxes_ick", "dummy_ck"), + DT_CLK("omap_hsmmc.0", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.1", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.2", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.3", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.4", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.1", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.2", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.3", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.4", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.1", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.2", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.3", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.4", "ick", "dummy_ck"), + DT_CLK(NULL, "uart1_ick", "dummy_ck"), + DT_CLK(NULL, "uart2_ick", "dummy_ck"), + DT_CLK(NULL, "uart3_ick", "dummy_ck"), + DT_CLK(NULL, "uart4_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbhost_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"), + DT_CLK("omap_wdt", "ick", "dummy_ck"), + DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"), + DT_CLK("omap_timer.1", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.2", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.3", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.4", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.9", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.10", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.11", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.5", "sys_ck", "dss_syc_gfclk_div"), + DT_CLK("omap_timer.6", "sys_ck", "dss_syc_gfclk_div"), + DT_CLK("omap_timer.7", "sys_ck", "dss_syc_gfclk_div"), + DT_CLK("omap_timer.8", "sys_ck", "dss_syc_gfclk_div"), + { .node_name = NULL }, +}; + +int __init omap5xxx_dt_clk_init(void) +{ + int rc; + struct clk *abe_dpll_ref, *abe_dpll, *sys_32k_ck, *usb_dpll; + + ti_dt_clocks_register(omap54xx_clks); + + omap2_clk_disable_autoidle_all(); + + abe_dpll_ref = clk_get_sys(NULL, "abe_dpll_clk_mux"); + sys_32k_ck = clk_get_sys(NULL, "sys_32k_ck"); + rc = clk_set_parent(abe_dpll_ref, sys_32k_ck); + abe_dpll = clk_get_sys(NULL, "dpll_abe_ck"); + if (!rc) + rc = clk_set_rate(abe_dpll, OMAP5_DPLL_ABE_DEFFREQ); + if (rc) + pr_err("%s: failed to configure ABE DPLL!\n", __func__); + + usb_dpll = clk_get_sys(NULL, "dpll_usb_ck"); + rc = clk_set_rate(usb_dpll, OMAP5_DPLL_USB_DEFFREQ); + if (rc) + pr_err("%s: failed to configure USB DPLL!\n", __func__); + + usb_dpll = clk_get_sys(NULL, "dpll_usb_m2_ck"); + rc = clk_set_rate(usb_dpll, OMAP5_DPLL_USB_DEFFREQ/2); + if (rc) + pr_err("%s: failed to set USB_DPLL M2 OUT\n", __func__); + + return 0; +} diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c new file mode 100644 index 00000000000000..9977653f2d6317 --- /dev/null +++ b/drivers/clk/ti/clk-7xx.c @@ -0,0 +1,332 @@ +/* + * DRA7 Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo (t-kristo@ti.com) + * + * 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. + */ + +#include +#include +#include +#include +#include + +#define DRA7_DPLL_ABE_DEFFREQ 361267200 +#define DRA7_DPLL_GMAC_DEFFREQ 1000000000 + + +static struct ti_dt_clk dra7xx_clks[] = { + DT_CLK(NULL, "atl_clkin0_ck", "atl_clkin0_ck"), + DT_CLK(NULL, "atl_clkin1_ck", "atl_clkin1_ck"), + DT_CLK(NULL, "atl_clkin2_ck", "atl_clkin2_ck"), + DT_CLK(NULL, "atlclkin3_ck", "atlclkin3_ck"), + DT_CLK(NULL, "hdmi_clkin_ck", "hdmi_clkin_ck"), + DT_CLK(NULL, "mlb_clkin_ck", "mlb_clkin_ck"), + DT_CLK(NULL, "mlbp_clkin_ck", "mlbp_clkin_ck"), + DT_CLK(NULL, "pciesref_acs_clk_ck", "pciesref_acs_clk_ck"), + DT_CLK(NULL, "ref_clkin0_ck", "ref_clkin0_ck"), + DT_CLK(NULL, "ref_clkin1_ck", "ref_clkin1_ck"), + DT_CLK(NULL, "ref_clkin2_ck", "ref_clkin2_ck"), + DT_CLK(NULL, "ref_clkin3_ck", "ref_clkin3_ck"), + DT_CLK(NULL, "rmii_clk_ck", "rmii_clk_ck"), + DT_CLK(NULL, "sdvenc_clkin_ck", "sdvenc_clkin_ck"), + DT_CLK(NULL, "secure_32k_clk_src_ck", "secure_32k_clk_src_ck"), + DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"), + DT_CLK(NULL, "virt_12000000_ck", "virt_12000000_ck"), + DT_CLK(NULL, "virt_13000000_ck", "virt_13000000_ck"), + DT_CLK(NULL, "virt_16800000_ck", "virt_16800000_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_20000000_ck", "virt_20000000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "virt_27000000_ck", "virt_27000000_ck"), + DT_CLK(NULL, "virt_38400000_ck", "virt_38400000_ck"), + DT_CLK(NULL, "sys_clkin1", "sys_clkin1"), + DT_CLK(NULL, "sys_clkin2", "sys_clkin2"), + DT_CLK(NULL, "usb_otg_clkin_ck", "usb_otg_clkin_ck"), + DT_CLK(NULL, "video1_clkin_ck", "video1_clkin_ck"), + DT_CLK(NULL, "video1_m2_clkin_ck", "video1_m2_clkin_ck"), + DT_CLK(NULL, "video2_clkin_ck", "video2_clkin_ck"), + DT_CLK(NULL, "video2_m2_clkin_ck", "video2_m2_clkin_ck"), + DT_CLK(NULL, "abe_dpll_sys_clk_mux", "abe_dpll_sys_clk_mux"), + DT_CLK(NULL, "abe_dpll_bypass_clk_mux", "abe_dpll_bypass_clk_mux"), + DT_CLK(NULL, "abe_dpll_clk_mux", "abe_dpll_clk_mux"), + DT_CLK(NULL, "dpll_abe_ck", "dpll_abe_ck"), + DT_CLK(NULL, "dpll_abe_x2_ck", "dpll_abe_x2_ck"), + DT_CLK(NULL, "dpll_abe_m2x2_ck", "dpll_abe_m2x2_ck"), + DT_CLK(NULL, "abe_24m_fclk", "abe_24m_fclk"), + DT_CLK(NULL, "abe_clk", "abe_clk"), + DT_CLK(NULL, "aess_fclk", "aess_fclk"), + DT_CLK(NULL, "abe_giclk_div", "abe_giclk_div"), + DT_CLK(NULL, "abe_lp_clk_div", "abe_lp_clk_div"), + DT_CLK(NULL, "abe_sys_clk_div", "abe_sys_clk_div"), + DT_CLK(NULL, "adc_gfclk_mux", "adc_gfclk_mux"), + DT_CLK(NULL, "dpll_pcie_ref_ck", "dpll_pcie_ref_ck"), + DT_CLK(NULL, "dpll_pcie_ref_m2ldo_ck", "dpll_pcie_ref_m2ldo_ck"), + DT_CLK(NULL, "apll_pcie_ck", "apll_pcie_ck"), + DT_CLK(NULL, "apll_pcie_clkvcoldo", "apll_pcie_clkvcoldo"), + DT_CLK(NULL, "apll_pcie_clkvcoldo_div", "apll_pcie_clkvcoldo_div"), + DT_CLK(NULL, "apll_pcie_m2_ck", "apll_pcie_m2_ck"), + DT_CLK(NULL, "sys_clk1_dclk_div", "sys_clk1_dclk_div"), + DT_CLK(NULL, "sys_clk2_dclk_div", "sys_clk2_dclk_div"), + DT_CLK(NULL, "dpll_abe_m2_ck", "dpll_abe_m2_ck"), + DT_CLK(NULL, "per_abe_x1_dclk_div", "per_abe_x1_dclk_div"), + DT_CLK(NULL, "dpll_abe_m3x2_ck", "dpll_abe_m3x2_ck"), + DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), + DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), + DT_CLK(NULL, "dpll_core_h12x2_ck", "dpll_core_h12x2_ck"), + DT_CLK(NULL, "mpu_dpll_hs_clk_div", "mpu_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), + DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), + DT_CLK(NULL, "mpu_dclk_div", "mpu_dclk_div"), + DT_CLK(NULL, "dsp_dpll_hs_clk_div", "dsp_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_dsp_ck", "dpll_dsp_ck"), + DT_CLK(NULL, "dpll_dsp_m2_ck", "dpll_dsp_m2_ck"), + DT_CLK(NULL, "dsp_gclk_div", "dsp_gclk_div"), + DT_CLK(NULL, "iva_dpll_hs_clk_div", "iva_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_iva_ck", "dpll_iva_ck"), + DT_CLK(NULL, "dpll_iva_m2_ck", "dpll_iva_m2_ck"), + DT_CLK(NULL, "iva_dclk", "iva_dclk"), + DT_CLK(NULL, "dpll_gpu_ck", "dpll_gpu_ck"), + DT_CLK(NULL, "dpll_gpu_m2_ck", "dpll_gpu_m2_ck"), + DT_CLK(NULL, "gpu_dclk", "gpu_dclk"), + DT_CLK(NULL, "dpll_core_m2_ck", "dpll_core_m2_ck"), + DT_CLK(NULL, "core_dpll_out_dclk_div", "core_dpll_out_dclk_div"), + DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"), + DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"), + DT_CLK(NULL, "emif_phy_dclk_div", "emif_phy_dclk_div"), + DT_CLK(NULL, "dpll_gmac_ck", "dpll_gmac_ck"), + DT_CLK(NULL, "dpll_gmac_m2_ck", "dpll_gmac_m2_ck"), + DT_CLK(NULL, "gmac_250m_dclk_div", "gmac_250m_dclk_div"), + DT_CLK(NULL, "video2_dclk_div", "video2_dclk_div"), + DT_CLK(NULL, "video1_dclk_div", "video1_dclk_div"), + DT_CLK(NULL, "hdmi_dclk_div", "hdmi_dclk_div"), + DT_CLK(NULL, "per_dpll_hs_clk_div", "per_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), + DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), + DT_CLK(NULL, "func_96m_aon_dclk_div", "func_96m_aon_dclk_div"), + DT_CLK(NULL, "usb_dpll_hs_clk_div", "usb_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_usb_ck", "dpll_usb_ck"), + DT_CLK(NULL, "dpll_usb_m2_ck", "dpll_usb_m2_ck"), + DT_CLK(NULL, "l3init_480m_dclk_div", "l3init_480m_dclk_div"), + DT_CLK(NULL, "usb_otg_dclk_div", "usb_otg_dclk_div"), + DT_CLK(NULL, "sata_dclk_div", "sata_dclk_div"), + DT_CLK(NULL, "dpll_pcie_ref_m2_ck", "dpll_pcie_ref_m2_ck"), + DT_CLK(NULL, "pcie2_dclk_div", "pcie2_dclk_div"), + DT_CLK(NULL, "pcie_dclk_div", "pcie_dclk_div"), + DT_CLK(NULL, "emu_dclk_div", "emu_dclk_div"), + DT_CLK(NULL, "secure_32k_dclk_div", "secure_32k_dclk_div"), + DT_CLK(NULL, "eve_dpll_hs_clk_div", "eve_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_eve_ck", "dpll_eve_ck"), + DT_CLK(NULL, "dpll_eve_m2_ck", "dpll_eve_m2_ck"), + DT_CLK(NULL, "eve_dclk_div", "eve_dclk_div"), + DT_CLK(NULL, "clkoutmux0_clk_mux", "clkoutmux0_clk_mux"), + DT_CLK(NULL, "clkoutmux1_clk_mux", "clkoutmux1_clk_mux"), + DT_CLK(NULL, "clkoutmux2_clk_mux", "clkoutmux2_clk_mux"), + DT_CLK(NULL, "custefuse_sys_gfclk_div", "custefuse_sys_gfclk_div"), + DT_CLK(NULL, "dpll_core_h13x2_ck", "dpll_core_h13x2_ck"), + DT_CLK(NULL, "dpll_core_h14x2_ck", "dpll_core_h14x2_ck"), + DT_CLK(NULL, "dpll_core_h22x2_ck", "dpll_core_h22x2_ck"), + DT_CLK(NULL, "dpll_core_h23x2_ck", "dpll_core_h23x2_ck"), + DT_CLK(NULL, "dpll_core_h24x2_ck", "dpll_core_h24x2_ck"), + DT_CLK(NULL, "dpll_ddr_x2_ck", "dpll_ddr_x2_ck"), + DT_CLK(NULL, "dpll_ddr_h11x2_ck", "dpll_ddr_h11x2_ck"), + DT_CLK(NULL, "dpll_dsp_x2_ck", "dpll_dsp_x2_ck"), + DT_CLK(NULL, "dpll_dsp_m3x2_ck", "dpll_dsp_m3x2_ck"), + DT_CLK(NULL, "dpll_gmac_x2_ck", "dpll_gmac_x2_ck"), + DT_CLK(NULL, "dpll_gmac_h11x2_ck", "dpll_gmac_h11x2_ck"), + DT_CLK(NULL, "dpll_gmac_h12x2_ck", "dpll_gmac_h12x2_ck"), + DT_CLK(NULL, "dpll_gmac_h13x2_ck", "dpll_gmac_h13x2_ck"), + DT_CLK(NULL, "dpll_gmac_m3x2_ck", "dpll_gmac_m3x2_ck"), + DT_CLK(NULL, "dpll_per_x2_ck", "dpll_per_x2_ck"), + DT_CLK(NULL, "dpll_per_h11x2_ck", "dpll_per_h11x2_ck"), + DT_CLK(NULL, "dpll_per_h12x2_ck", "dpll_per_h12x2_ck"), + DT_CLK(NULL, "dpll_per_h13x2_ck", "dpll_per_h13x2_ck"), + DT_CLK(NULL, "dpll_per_h14x2_ck", "dpll_per_h14x2_ck"), + DT_CLK(NULL, "dpll_per_m2x2_ck", "dpll_per_m2x2_ck"), + DT_CLK(NULL, "dpll_usb_clkdcoldo", "dpll_usb_clkdcoldo"), + DT_CLK(NULL, "eve_clk", "eve_clk"), + DT_CLK(NULL, "func_128m_clk", "func_128m_clk"), + DT_CLK(NULL, "func_12m_fclk", "func_12m_fclk"), + DT_CLK(NULL, "func_24m_clk", "func_24m_clk"), + DT_CLK(NULL, "func_48m_fclk", "func_48m_fclk"), + DT_CLK(NULL, "func_96m_fclk", "func_96m_fclk"), + DT_CLK(NULL, "gmii_m_clk_div", "gmii_m_clk_div"), + DT_CLK(NULL, "hdmi_clk2_div", "hdmi_clk2_div"), + DT_CLK(NULL, "hdmi_div_clk", "hdmi_div_clk"), + DT_CLK(NULL, "hdmi_dpll_clk_mux", "hdmi_dpll_clk_mux"), + DT_CLK(NULL, "l3_iclk_div", "l3_iclk_div"), + DT_CLK(NULL, "l3init_60m_fclk", "l3init_60m_fclk"), + DT_CLK(NULL, "l4_root_clk_div", "l4_root_clk_div"), + DT_CLK(NULL, "mlb_clk", "mlb_clk"), + DT_CLK(NULL, "mlbp_clk", "mlbp_clk"), + DT_CLK(NULL, "per_abe_x1_gfclk2_div", "per_abe_x1_gfclk2_div"), + DT_CLK(NULL, "timer_sys_clk_div", "timer_sys_clk_div"), + DT_CLK(NULL, "video1_clk2_div", "video1_clk2_div"), + DT_CLK(NULL, "video1_div_clk", "video1_div_clk"), + DT_CLK(NULL, "video1_dpll_clk_mux", "video1_dpll_clk_mux"), + DT_CLK(NULL, "video2_clk2_div", "video2_clk2_div"), + DT_CLK(NULL, "video2_div_clk", "video2_div_clk"), + DT_CLK(NULL, "video2_dpll_clk_mux", "video2_dpll_clk_mux"), + DT_CLK(NULL, "wkupaon_iclk_mux", "wkupaon_iclk_mux"), + DT_CLK(NULL, "dss_32khz_clk", "dss_32khz_clk"), + DT_CLK(NULL, "dss_48mhz_clk", "dss_48mhz_clk"), + DT_CLK(NULL, "dss_dss_clk", "dss_dss_clk"), + DT_CLK(NULL, "dss_hdmi_clk", "dss_hdmi_clk"), + DT_CLK(NULL, "dss_video1_clk", "dss_video1_clk"), + DT_CLK(NULL, "dss_video2_clk", "dss_video2_clk"), + DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), + DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), + DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), + DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"), + DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"), + DT_CLK(NULL, "gpio6_dbclk", "gpio6_dbclk"), + DT_CLK(NULL, "gpio7_dbclk", "gpio7_dbclk"), + DT_CLK(NULL, "gpio8_dbclk", "gpio8_dbclk"), + DT_CLK(NULL, "mmc1_clk32k", "mmc1_clk32k"), + DT_CLK(NULL, "mmc2_clk32k", "mmc2_clk32k"), + DT_CLK(NULL, "mmc3_clk32k", "mmc3_clk32k"), + DT_CLK(NULL, "mmc4_clk32k", "mmc4_clk32k"), + DT_CLK(NULL, "sata_ref_clk", "sata_ref_clk"), + DT_CLK(NULL, "usb_otg_ss1_refclk960m", "usb_otg_ss1_refclk960m"), + DT_CLK(NULL, "usb_otg_ss2_refclk960m", "usb_otg_ss2_refclk960m"), + DT_CLK(NULL, "usb_phy1_always_on_clk32k", "usb_phy1_always_on_clk32k"), + DT_CLK(NULL, "usb_phy2_always_on_clk32k", "usb_phy2_always_on_clk32k"), + DT_CLK(NULL, "usb_phy3_always_on_clk32k", "usb_phy3_always_on_clk32k"), + DT_CLK(NULL, "atl_dpll_clk_mux", "atl_dpll_clk_mux"), + DT_CLK(NULL, "atl_gfclk_mux", "atl_gfclk_mux"), + DT_CLK(NULL, "dcan1_sys_clk_mux", "dcan1_sys_clk_mux"), + DT_CLK(NULL, "gmac_gmii_ref_clk_div", "gmac_gmii_ref_clk_div"), + DT_CLK(NULL, "gmac_rft_clk_mux", "gmac_rft_clk_mux"), + DT_CLK(NULL, "gpu_core_gclk_mux", "gpu_core_gclk_mux"), + DT_CLK(NULL, "gpu_hyd_gclk_mux", "gpu_hyd_gclk_mux"), + DT_CLK(NULL, "ipu1_gfclk_mux", "ipu1_gfclk_mux"), + DT_CLK(NULL, "l3instr_ts_gclk_div", "l3instr_ts_gclk_div"), + DT_CLK(NULL, "mcasp1_ahclkr_mux", "mcasp1_ahclkr_mux"), + DT_CLK(NULL, "mcasp1_ahclkx_mux", "mcasp1_ahclkx_mux"), + DT_CLK(NULL, "mcasp1_aux_gfclk_mux", "mcasp1_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp2_ahclkr_mux", "mcasp2_ahclkr_mux"), + DT_CLK(NULL, "mcasp2_ahclkx_mux", "mcasp2_ahclkx_mux"), + DT_CLK(NULL, "mcasp2_aux_gfclk_mux", "mcasp2_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp3_ahclkx_mux", "mcasp3_ahclkx_mux"), + DT_CLK(NULL, "mcasp3_aux_gfclk_mux", "mcasp3_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp4_ahclkx_mux", "mcasp4_ahclkx_mux"), + DT_CLK(NULL, "mcasp4_aux_gfclk_mux", "mcasp4_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp5_ahclkx_mux", "mcasp5_ahclkx_mux"), + DT_CLK(NULL, "mcasp5_aux_gfclk_mux", "mcasp5_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp6_ahclkx_mux", "mcasp6_ahclkx_mux"), + DT_CLK(NULL, "mcasp6_aux_gfclk_mux", "mcasp6_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp7_ahclkx_mux", "mcasp7_ahclkx_mux"), + DT_CLK(NULL, "mcasp7_aux_gfclk_mux", "mcasp7_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp8_ahclk_mux", "mcasp8_ahclk_mux"), + DT_CLK(NULL, "mcasp8_aux_gfclk_mux", "mcasp8_aux_gfclk_mux"), + DT_CLK(NULL, "mmc1_fclk_mux", "mmc1_fclk_mux"), + DT_CLK(NULL, "mmc1_fclk_div", "mmc1_fclk_div"), + DT_CLK(NULL, "mmc2_fclk_mux", "mmc2_fclk_mux"), + DT_CLK(NULL, "mmc2_fclk_div", "mmc2_fclk_div"), + DT_CLK(NULL, "mmc3_gfclk_mux", "mmc3_gfclk_mux"), + DT_CLK(NULL, "mmc3_gfclk_div", "mmc3_gfclk_div"), + DT_CLK(NULL, "mmc4_gfclk_mux", "mmc4_gfclk_mux"), + DT_CLK(NULL, "mmc4_gfclk_div", "mmc4_gfclk_div"), + DT_CLK(NULL, "qspi_gfclk_mux", "qspi_gfclk_mux"), + DT_CLK(NULL, "qspi_gfclk_div", "qspi_gfclk_div"), + DT_CLK(NULL, "timer10_gfclk_mux", "timer10_gfclk_mux"), + DT_CLK(NULL, "timer11_gfclk_mux", "timer11_gfclk_mux"), + DT_CLK(NULL, "timer13_gfclk_mux", "timer13_gfclk_mux"), + DT_CLK(NULL, "timer14_gfclk_mux", "timer14_gfclk_mux"), + DT_CLK(NULL, "timer15_gfclk_mux", "timer15_gfclk_mux"), + DT_CLK(NULL, "timer16_gfclk_mux", "timer16_gfclk_mux"), + DT_CLK(NULL, "timer1_gfclk_mux", "timer1_gfclk_mux"), + DT_CLK(NULL, "timer2_gfclk_mux", "timer2_gfclk_mux"), + DT_CLK(NULL, "timer3_gfclk_mux", "timer3_gfclk_mux"), + DT_CLK(NULL, "timer4_gfclk_mux", "timer4_gfclk_mux"), + DT_CLK(NULL, "timer5_gfclk_mux", "timer5_gfclk_mux"), + DT_CLK(NULL, "timer6_gfclk_mux", "timer6_gfclk_mux"), + DT_CLK(NULL, "timer7_gfclk_mux", "timer7_gfclk_mux"), + DT_CLK(NULL, "timer8_gfclk_mux", "timer8_gfclk_mux"), + DT_CLK(NULL, "timer9_gfclk_mux", "timer9_gfclk_mux"), + DT_CLK(NULL, "uart10_gfclk_mux", "uart10_gfclk_mux"), + DT_CLK(NULL, "uart1_gfclk_mux", "uart1_gfclk_mux"), + DT_CLK(NULL, "uart2_gfclk_mux", "uart2_gfclk_mux"), + DT_CLK(NULL, "uart3_gfclk_mux", "uart3_gfclk_mux"), + DT_CLK(NULL, "uart4_gfclk_mux", "uart4_gfclk_mux"), + DT_CLK(NULL, "uart5_gfclk_mux", "uart5_gfclk_mux"), + DT_CLK(NULL, "uart6_gfclk_mux", "uart6_gfclk_mux"), + DT_CLK(NULL, "uart7_gfclk_mux", "uart7_gfclk_mux"), + DT_CLK(NULL, "uart8_gfclk_mux", "uart8_gfclk_mux"), + DT_CLK(NULL, "uart9_gfclk_mux", "uart9_gfclk_mux"), + DT_CLK(NULL, "vip1_gclk_mux", "vip1_gclk_mux"), + DT_CLK(NULL, "vip2_gclk_mux", "vip2_gclk_mux"), + DT_CLK(NULL, "vip3_gclk_mux", "vip3_gclk_mux"), + DT_CLK(NULL, "gpmc_ck", "dummy_ck"), + DT_CLK("omap_i2c.1", "ick", "dummy_ck"), + DT_CLK("omap_i2c.2", "ick", "dummy_ck"), + DT_CLK("omap_i2c.3", "ick", "dummy_ck"), + DT_CLK("omap_i2c.4", "ick", "dummy_ck"), + DT_CLK(NULL, "mailboxes_ick", "dummy_ck"), + DT_CLK("omap_hsmmc.0", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.1", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.2", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.3", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.4", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.1", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.2", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.3", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.4", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.1", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.2", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.3", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.4", "ick", "dummy_ck"), + DT_CLK(NULL, "uart1_ick", "dummy_ck"), + DT_CLK(NULL, "uart2_ick", "dummy_ck"), + DT_CLK(NULL, "uart3_ick", "dummy_ck"), + DT_CLK(NULL, "uart4_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbhost_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"), + DT_CLK("omap_wdt", "ick", "dummy_ck"), + DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"), + DT_CLK("4ae18000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48032000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48034000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48036000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("4803e000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48086000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48088000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48820000.timer", "timer_sys_ck", "timer_sys_clk_div"), + DT_CLK("48822000.timer", "timer_sys_ck", "timer_sys_clk_div"), + DT_CLK("48824000.timer", "timer_sys_ck", "timer_sys_clk_div"), + DT_CLK("48826000.timer", "timer_sys_ck", "timer_sys_clk_div"), + DT_CLK(NULL, "sys_clkin", "sys_clkin1"), + { .node_name = NULL }, +}; + +int __init dra7xx_dt_clk_init(void) +{ + int rc; + struct clk *abe_dpll_mux, *sys_clkin2, *dpll_ck; + + ti_dt_clocks_register(dra7xx_clks); + + omap2_clk_disable_autoidle_all(); + + abe_dpll_mux = clk_get_sys(NULL, "abe_dpll_sys_clk_mux"); + sys_clkin2 = clk_get_sys(NULL, "sys_clkin2"); + dpll_ck = clk_get_sys(NULL, "dpll_abe_ck"); + + rc = clk_set_parent(abe_dpll_mux, sys_clkin2); + if (!rc) + rc = clk_set_rate(dpll_ck, DRA7_DPLL_ABE_DEFFREQ); + if (rc) + pr_err("%s: failed to configure ABE DPLL!\n", __func__); + + dpll_ck = clk_get_sys(NULL, "dpll_gmac_ck"); + rc = clk_set_rate(dpll_ck, DRA7_DPLL_GMAC_DEFFREQ); + if (rc) + pr_err("%s: failed to configure GMAC DPLL!\n", __func__); + + return rc; +} diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c new file mode 100644 index 00000000000000..b1a6f7144f3fcb --- /dev/null +++ b/drivers/clk/ti/clk.c @@ -0,0 +1,167 @@ +/* + * TI clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo + * + * 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 "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +static int ti_dt_clk_memmap_index; +struct ti_clk_ll_ops *ti_clk_ll_ops; + +/** + * ti_dt_clocks_register - register DT alias clocks during boot + * @oclks: list of clocks to register + * + * Register alias or non-standard DT clock entries during boot. By + * default, DT clocks are found based on their node name. If any + * additional con-id / dev-id -> clock mapping is required, use this + * function to list these. + */ +void __init ti_dt_clocks_register(struct ti_dt_clk oclks[]) +{ + struct ti_dt_clk *c; + struct device_node *node; + struct clk *clk; + struct of_phandle_args clkspec; + + for (c = oclks; c->node_name != NULL; c++) { + node = of_find_node_by_name(NULL, c->node_name); + clkspec.np = node; + clk = of_clk_get_from_provider(&clkspec); + + if (!IS_ERR(clk)) { + c->lk.clk = clk; + clkdev_add(&c->lk); + } else { + pr_warn("failed to lookup clock node %s\n", + c->node_name); + } + } +} + +struct clk_init_item { + struct device_node *node; + struct clk_hw *hw; + ti_of_clk_init_cb_t func; + struct list_head link; +}; + +static LIST_HEAD(retry_list); + +/** + * ti_clk_retry_init - retries a failed clock init at later phase + * @node: device not for the clock + * @hw: partially initialized clk_hw struct for the clock + * @func: init function to be called for the clock + * + * Adds a failed clock init to the retry list. The retry list is parsed + * once all the other clocks have been initialized. + */ +int __init ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, + ti_of_clk_init_cb_t func) +{ + struct clk_init_item *retry; + + pr_debug("%s: adding to retry list...\n", node->name); + retry = kzalloc(sizeof(*retry), GFP_KERNEL); + if (!retry) + return -ENOMEM; + + retry->node = node; + retry->func = func; + retry->hw = hw; + list_add(&retry->link, &retry_list); + + return 0; +} + +/** + * ti_clk_get_reg_addr - get register address for a clock register + * @node: device node for the clock + * @index: register index from the clock node + * + * Builds clock register address from device tree information. This + * is a struct of type clk_omap_reg. + */ +void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index) +{ + struct clk_omap_reg *reg; + u32 val; + u32 tmp; + + reg = (struct clk_omap_reg *)&tmp; + reg->index = ti_dt_clk_memmap_index; + + if (of_property_read_u32_index(node, "reg", index, &val)) { + pr_err("%s must have reg[%d]!\n", node->name, index); + return NULL; + } + + reg->offset = val; + + return (void __iomem *)tmp; +} + +/** + * ti_dt_clk_init_provider - init master clock provider + * @parent: master node + * @index: internal index for clk_reg_ops + * + * Initializes a master clock IP block and its child clock nodes. + * Regmap is provided for accessing the register space for the + * IP block and all the clocks under it. + */ +void ti_dt_clk_init_provider(struct device_node *parent, int index) +{ + const struct of_device_id *match; + struct device_node *np; + struct device_node *clocks; + of_clk_init_cb_t clk_init_cb; + struct clk_init_item *retry; + struct clk_init_item *tmp; + + ti_dt_clk_memmap_index = index; + + /* get clocks for this parent */ + clocks = of_get_child_by_name(parent, "clocks"); + if (!clocks) { + pr_err("%s missing 'clocks' child node.\n", parent->name); + return; + } + + for_each_child_of_node(clocks, np) { + match = of_match_node(&__clk_of_table, np); + if (!match) + continue; + clk_init_cb = (of_clk_init_cb_t)match->data; + pr_debug("%s: initializing: %s\n", __func__, np->name); + clk_init_cb(np); + } + + list_for_each_entry_safe(retry, tmp, &retry_list, link) { + pr_debug("retry-init: %s\n", retry->node->name); + retry->func(retry->hw, retry->node); + list_del(&retry->link); + kfree(retry); + } +} diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c new file mode 100644 index 00000000000000..f1e0038d76acd3 --- /dev/null +++ b/drivers/clk/ti/clockdomain.c @@ -0,0 +1,70 @@ +/* + * OMAP clockdomain support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo + * + * 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 "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +static void __init of_ti_clockdomain_setup(struct device_node *node) +{ + struct clk *clk; + struct clk_hw *clk_hw; + const char *clkdm_name = node->name; + int i; + int num_clks; + + num_clks = of_count_phandle_with_args(node, "clocks", "#clock-cells"); + + for (i = 0; i < num_clks; i++) { + clk = of_clk_get(node, i); + if (__clk_get_flags(clk) & CLK_IS_BASIC) { + pr_warn("can't setup clkdm for basic clk %s\n", + __clk_get_name(clk)); + continue; + } + clk_hw = __clk_get_hw(clk); + to_clk_hw_omap(clk_hw)->clkdm_name = clkdm_name; + omap2_init_clk_clkdm(clk_hw); + } +} + +static struct of_device_id ti_clkdm_match_table[] __initdata = { + { .compatible = "ti,clockdomain" }, + { } +}; + +/** + * ti_dt_clockdomains_setup - setup device tree clockdomains + * + * Initializes clockdomain nodes for a SoC. This parses through all the + * nodes with compatible = "ti,clockdomain", and add the clockdomain + * info for all the clocks listed under these. This function shall be + * called after rest of the DT clock init has completed and all + * clock nodes have been registered. + */ +void __init ti_dt_clockdomains_setup(void) +{ + struct device_node *np; + for_each_matching_node(np, ti_clkdm_match_table) { + of_ti_clockdomain_setup(np); + } +} diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c new file mode 100644 index 00000000000000..19d8980ba458ef --- /dev/null +++ b/drivers/clk/ti/composite.c @@ -0,0 +1,269 @@ +/* + * TI composite clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo + * + * 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 "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) + +static unsigned long ti_composite_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return ti_clk_divider_ops.recalc_rate(hw, parent_rate); +} + +static long ti_composite_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + return -EINVAL; +} + +static int ti_composite_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + return -EINVAL; +} + +static const struct clk_ops ti_composite_divider_ops = { + .recalc_rate = &ti_composite_recalc_rate, + .round_rate = &ti_composite_round_rate, + .set_rate = &ti_composite_set_rate, +}; + +static const struct clk_ops ti_composite_gate_ops = { + .enable = &omap2_dflt_clk_enable, + .disable = &omap2_dflt_clk_disable, + .is_enabled = &omap2_dflt_clk_is_enabled, +}; + +struct component_clk { + int num_parents; + const char **parent_names; + struct device_node *node; + int type; + struct clk_hw *hw; + struct list_head link; +}; + +static const char * __initconst component_clk_types[] = { + "gate", "divider", "mux" +}; + +static LIST_HEAD(component_clks); + +static struct device_node *_get_component_node(struct device_node *node, int i) +{ + int rc; + struct of_phandle_args clkspec; + + rc = of_parse_phandle_with_args(node, "clocks", "#clock-cells", i, + &clkspec); + if (rc) + return NULL; + + return clkspec.np; +} + +static struct component_clk *_lookup_component(struct device_node *node) +{ + struct component_clk *comp; + + list_for_each_entry(comp, &component_clks, link) { + if (comp->node == node) + return comp; + } + return NULL; +} + +struct clk_hw_omap_comp { + struct clk_hw hw; + struct device_node *comp_nodes[CLK_COMPONENT_TYPE_MAX]; + struct component_clk *comp_clks[CLK_COMPONENT_TYPE_MAX]; +}; + +static inline struct clk_hw *_get_hw(struct clk_hw_omap_comp *clk, int idx) +{ + if (!clk) + return NULL; + + if (!clk->comp_clks[idx]) + return NULL; + + return clk->comp_clks[idx]->hw; +} + +#define to_clk_hw_comp(_hw) container_of(_hw, struct clk_hw_omap_comp, hw) + +static void __init ti_clk_register_composite(struct clk_hw *hw, + struct device_node *node) +{ + struct clk *clk; + struct clk_hw_omap_comp *cclk = to_clk_hw_comp(hw); + struct component_clk *comp; + int num_parents = 0; + const char **parent_names = NULL; + int i; + + /* Check for presence of each component clock */ + for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) { + if (!cclk->comp_nodes[i]) + continue; + + comp = _lookup_component(cclk->comp_nodes[i]); + if (!comp) { + pr_debug("component %s not ready for %s, retry\n", + cclk->comp_nodes[i]->name, node->name); + if (!ti_clk_retry_init(node, hw, + ti_clk_register_composite)) + return; + + goto cleanup; + } + if (cclk->comp_clks[comp->type] != NULL) { + pr_err("duplicate component types for %s (%s)!\n", + node->name, component_clk_types[comp->type]); + goto cleanup; + } + + cclk->comp_clks[comp->type] = comp; + + /* Mark this node as found */ + cclk->comp_nodes[i] = NULL; + } + + /* All components exists, proceed with registration */ + for (i = CLK_COMPONENT_TYPE_MAX - 1; i >= 0; i--) { + comp = cclk->comp_clks[i]; + if (!comp) + continue; + if (comp->num_parents) { + num_parents = comp->num_parents; + parent_names = comp->parent_names; + break; + } + } + + if (!num_parents) { + pr_err("%s: no parents found for %s!\n", __func__, node->name); + goto cleanup; + } + + clk = clk_register_composite(NULL, node->name, + parent_names, num_parents, + _get_hw(cclk, CLK_COMPONENT_TYPE_MUX), + &ti_clk_mux_ops, + _get_hw(cclk, CLK_COMPONENT_TYPE_DIVIDER), + &ti_composite_divider_ops, + _get_hw(cclk, CLK_COMPONENT_TYPE_GATE), + &ti_composite_gate_ops, 0); + + if (!IS_ERR(clk)) + of_clk_add_provider(node, of_clk_src_simple_get, clk); + +cleanup: + /* Free component clock list entries */ + for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) { + if (!cclk->comp_clks[i]) + continue; + list_del(&cclk->comp_clks[i]->link); + kfree(cclk->comp_clks[i]); + } + + kfree(cclk); +} + +static void __init of_ti_composite_clk_setup(struct device_node *node) +{ + int num_clks; + int i; + struct clk_hw_omap_comp *cclk; + + /* Number of component clocks to be put inside this clock */ + num_clks = of_clk_get_parent_count(node); + + if (num_clks < 1) { + pr_err("composite clk %s must have component(s)\n", node->name); + return; + } + + cclk = kzalloc(sizeof(*cclk), GFP_KERNEL); + if (!cclk) + return; + + /* Get device node pointers for each component clock */ + for (i = 0; i < num_clks; i++) + cclk->comp_nodes[i] = _get_component_node(node, i); + + ti_clk_register_composite(&cclk->hw, node); +} +CLK_OF_DECLARE(ti_composite_clock, "ti,composite-clock", + of_ti_composite_clk_setup); + +/** + * ti_clk_add_component - add a component clock to the pool + * @node: device node of the component clock + * @hw: hardware clock definition for the component clock + * @type: type of the component clock + * + * Adds a component clock to the list of available components, so that + * it can be registered by a composite clock. + */ +int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw, + int type) +{ + int num_parents; + const char **parent_names; + struct component_clk *clk; + int i; + + num_parents = of_clk_get_parent_count(node); + + if (num_parents < 1) { + pr_err("component-clock %s must have parent(s)\n", node->name); + return -EINVAL; + } + + parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL); + if (!parent_names) + return -ENOMEM; + + for (i = 0; i < num_parents; i++) + parent_names[i] = of_clk_get_parent_name(node, i); + + clk = kzalloc(sizeof(*clk), GFP_KERNEL); + if (!clk) { + kfree(parent_names); + return -ENOMEM; + } + + clk->num_parents = num_parents; + clk->parent_names = parent_names; + clk->hw = hw; + clk->node = node; + clk->type = type; + list_add(&clk->link, &component_clks); + + return 0; +} diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c new file mode 100644 index 00000000000000..a15e445570b288 --- /dev/null +++ b/drivers/clk/ti/divider.c @@ -0,0 +1,487 @@ +/* + * TI Divider Clock + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo + * + * 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 "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) + +#define div_mask(d) ((1 << ((d)->width)) - 1) + +static unsigned int _get_table_maxdiv(const struct clk_div_table *table) +{ + unsigned int maxdiv = 0; + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div > maxdiv) + maxdiv = clkt->div; + return maxdiv; +} + +static unsigned int _get_maxdiv(struct clk_divider *divider) +{ + if (divider->flags & CLK_DIVIDER_ONE_BASED) + return div_mask(divider); + if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) + return 1 << div_mask(divider); + if (divider->table) + return _get_table_maxdiv(divider->table); + return div_mask(divider) + 1; +} + +static unsigned int _get_table_div(const struct clk_div_table *table, + unsigned int val) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->val == val) + return clkt->div; + return 0; +} + +static unsigned int _get_div(struct clk_divider *divider, unsigned int val) +{ + if (divider->flags & CLK_DIVIDER_ONE_BASED) + return val; + if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) + return 1 << val; + if (divider->table) + return _get_table_div(divider->table, val); + return val + 1; +} + +static unsigned int _get_table_val(const struct clk_div_table *table, + unsigned int div) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div == div) + return clkt->val; + return 0; +} + +static unsigned int _get_val(struct clk_divider *divider, u8 div) +{ + if (divider->flags & CLK_DIVIDER_ONE_BASED) + return div; + if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) + return __ffs(div); + if (divider->table) + return _get_table_val(divider->table, div); + return div - 1; +} + +static unsigned long ti_clk_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned int div, val; + + val = ti_clk_ll_ops->clk_readl(divider->reg) >> divider->shift; + val &= div_mask(divider); + + div = _get_div(divider, val); + if (!div) { + WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO), + "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", + __clk_get_name(hw->clk)); + return parent_rate; + } + + return parent_rate / div; +} + +/* + * The reverse of DIV_ROUND_UP: The maximum number which + * divided by m is r + */ +#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1) + +static bool _is_valid_table_div(const struct clk_div_table *table, + unsigned int div) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div == div) + return true; + return false; +} + +static bool _is_valid_div(struct clk_divider *divider, unsigned int div) +{ + if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) + return is_power_of_2(div); + if (divider->table) + return _is_valid_table_div(divider->table, div); + return true; +} + +static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + int i, bestdiv = 0; + unsigned long parent_rate, best = 0, now, maxdiv; + unsigned long parent_rate_saved = *best_parent_rate; + + if (!rate) + rate = 1; + + maxdiv = _get_maxdiv(divider); + + if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { + parent_rate = *best_parent_rate; + bestdiv = DIV_ROUND_UP(parent_rate, rate); + bestdiv = bestdiv == 0 ? 1 : bestdiv; + bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; + return bestdiv; + } + + /* + * The maximum divider we can use without overflowing + * unsigned long in rate * i below + */ + maxdiv = min(ULONG_MAX / rate, maxdiv); + + for (i = 1; i <= maxdiv; i++) { + if (!_is_valid_div(divider, i)) + continue; + if (rate * i == parent_rate_saved) { + /* + * It's the most ideal case if the requested rate can be + * divided from parent clock without needing to change + * parent rate, so return the divider immediately. + */ + *best_parent_rate = parent_rate_saved; + return i; + } + parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), + MULT_ROUND_UP(rate, i)); + now = parent_rate / i; + if (now <= rate && now > best) { + bestdiv = i; + best = now; + *best_parent_rate = parent_rate; + } + } + + if (!bestdiv) { + bestdiv = _get_maxdiv(divider); + *best_parent_rate = + __clk_round_rate(__clk_get_parent(hw->clk), 1); + } + + return bestdiv; +} + +static long ti_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int div; + div = ti_clk_divider_bestdiv(hw, rate, prate); + + return *prate / div; +} + +static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned int div, value; + unsigned long flags = 0; + u32 val; + + div = parent_rate / rate; + value = _get_val(divider, div); + + if (value > div_mask(divider)) + value = div_mask(divider); + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + + if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { + val = div_mask(divider) << (divider->shift + 16); + } else { + val = ti_clk_ll_ops->clk_readl(divider->reg); + val &= ~(div_mask(divider) << divider->shift); + } + val |= value << divider->shift; + ti_clk_ll_ops->clk_writel(val, divider->reg); + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + + return 0; +} + +const struct clk_ops ti_clk_divider_ops = { + .recalc_rate = ti_clk_divider_recalc_rate, + .round_rate = ti_clk_divider_round_rate, + .set_rate = ti_clk_divider_set_rate, +}; + +static struct clk *_register_divider(struct device *dev, const char *name, + const char *parent_name, + unsigned long flags, void __iomem *reg, + u8 shift, u8 width, u8 clk_divider_flags, + const struct clk_div_table *table, + spinlock_t *lock) +{ + struct clk_divider *div; + struct clk *clk; + struct clk_init_data init; + + if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) { + if (width + shift > 16) { + pr_warn("divider value exceeds LOWORD field\n"); + return ERR_PTR(-EINVAL); + } + } + + /* allocate the divider */ + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) { + pr_err("%s: could not allocate divider clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &ti_clk_divider_ops; + init.flags = flags | CLK_IS_BASIC; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + /* struct clk_divider assignments */ + div->reg = reg; + div->shift = shift; + div->width = width; + div->flags = clk_divider_flags; + div->lock = lock; + div->hw.init = &init; + div->table = table; + + /* register the clock */ + clk = clk_register(dev, &div->hw); + + if (IS_ERR(clk)) + kfree(div); + + return clk; +} + +static struct clk_div_table +__init *ti_clk_get_div_table(struct device_node *node) +{ + struct clk_div_table *table; + const __be32 *divspec; + u32 val; + u32 num_div; + u32 valid_div; + int i; + + divspec = of_get_property(node, "ti,dividers", &num_div); + + if (!divspec) + return NULL; + + num_div /= 4; + + valid_div = 0; + + /* Determine required size for divider table */ + for (i = 0; i < num_div; i++) { + of_property_read_u32_index(node, "ti,dividers", i, &val); + if (val) + valid_div++; + } + + if (!valid_div) { + pr_err("no valid dividers for %s table\n", node->name); + return ERR_PTR(-EINVAL); + } + + table = kzalloc(sizeof(*table) * (valid_div + 1), GFP_KERNEL); + + if (!table) + return ERR_PTR(-ENOMEM); + + valid_div = 0; + + for (i = 0; i < num_div; i++) { + of_property_read_u32_index(node, "ti,dividers", i, &val); + if (val) { + table[valid_div].div = val; + table[valid_div].val = i; + valid_div++; + } + } + + return table; +} + +static int _get_divider_width(struct device_node *node, + const struct clk_div_table *table, + u8 flags) +{ + u32 min_div; + u32 max_div; + u32 val = 0; + u32 div; + + if (!table) { + /* Clk divider table not provided, determine min/max divs */ + if (of_property_read_u32(node, "ti,min-div", &min_div)) + min_div = 1; + + if (of_property_read_u32(node, "ti,max-div", &max_div)) { + pr_err("no max-div for %s!\n", node->name); + return -EINVAL; + } + + /* Determine bit width for the field */ + if (flags & CLK_DIVIDER_ONE_BASED) + val = 1; + + div = min_div; + + while (div < max_div) { + if (flags & CLK_DIVIDER_POWER_OF_TWO) + div <<= 1; + else + div++; + val++; + } + } else { + div = 0; + + while (table[div].div) { + val = table[div].val; + div++; + } + } + + return fls(val); +} + +static int __init ti_clk_divider_populate(struct device_node *node, + void __iomem **reg, const struct clk_div_table **table, + u32 *flags, u8 *div_flags, u8 *width, u8 *shift) +{ + u32 val; + + *reg = ti_clk_get_reg_addr(node, 0); + if (!*reg) + return -EINVAL; + + if (!of_property_read_u32(node, "ti,bit-shift", &val)) + *shift = val; + else + *shift = 0; + + *flags = 0; + *div_flags = 0; + + if (of_property_read_bool(node, "ti,index-starts-at-one")) + *div_flags |= CLK_DIVIDER_ONE_BASED; + + if (of_property_read_bool(node, "ti,index-power-of-two")) + *div_flags |= CLK_DIVIDER_POWER_OF_TWO; + + if (of_property_read_bool(node, "ti,set-rate-parent")) + *flags |= CLK_SET_RATE_PARENT; + + *table = ti_clk_get_div_table(node); + + if (IS_ERR(*table)) + return PTR_ERR(*table); + + *width = _get_divider_width(node, *table, *div_flags); + + return 0; +} + +/** + * of_ti_divider_clk_setup - Setup function for simple div rate clock + * @node: device node for this clock + * + * Sets up a basic divider clock. + */ +static void __init of_ti_divider_clk_setup(struct device_node *node) +{ + struct clk *clk; + const char *parent_name; + void __iomem *reg; + u8 clk_divider_flags = 0; + u8 width = 0; + u8 shift = 0; + const struct clk_div_table *table = NULL; + u32 flags = 0; + + parent_name = of_clk_get_parent_name(node, 0); + + if (ti_clk_divider_populate(node, ®, &table, &flags, + &clk_divider_flags, &width, &shift)) + goto cleanup; + + clk = _register_divider(NULL, node->name, parent_name, flags, reg, + shift, width, clk_divider_flags, table, NULL); + + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + of_ti_clk_autoidle_setup(node); + return; + } + +cleanup: + kfree(table); +} +CLK_OF_DECLARE(divider_clk, "ti,divider-clock", of_ti_divider_clk_setup); + +static void __init of_ti_composite_divider_clk_setup(struct device_node *node) +{ + struct clk_divider *div; + u32 val; + + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) + return; + + if (ti_clk_divider_populate(node, &div->reg, &div->table, &val, + &div->flags, &div->width, &div->shift) < 0) + goto cleanup; + + if (!ti_clk_add_component(node, &div->hw, CLK_COMPONENT_TYPE_DIVIDER)) + return; + +cleanup: + kfree(div->table); + kfree(div); +} +CLK_OF_DECLARE(ti_composite_divider_clk, "ti,composite-divider-clock", + of_ti_composite_divider_clk_setup); diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c new file mode 100644 index 00000000000000..7e498a44f97dea --- /dev/null +++ b/drivers/clk/ti/dpll.c @@ -0,0 +1,558 @@ +/* + * OMAP DPLL clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo + * + * 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 "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#define DPLL_HAS_AUTOIDLE 0x1 + +#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ + defined(CONFIG_SOC_DRA7XX) +static const struct clk_ops dpll_m4xen_ck_ops = { + .enable = &omap3_noncore_dpll_enable, + .disable = &omap3_noncore_dpll_disable, + .recalc_rate = &omap4_dpll_regm4xen_recalc, + .round_rate = &omap4_dpll_regm4xen_round_rate, + .set_rate = &omap3_noncore_dpll_set_rate, + .get_parent = &omap2_init_dpll_parent, +}; +#endif + +static const struct clk_ops dpll_core_ck_ops = { + .recalc_rate = &omap3_dpll_recalc, + .get_parent = &omap2_init_dpll_parent, +}; + +#ifdef CONFIG_ARCH_OMAP3 +static const struct clk_ops omap3_dpll_core_ck_ops = { + .get_parent = &omap2_init_dpll_parent, + .recalc_rate = &omap3_dpll_recalc, + .round_rate = &omap2_dpll_round_rate, +}; +#endif + +static const struct clk_ops dpll_ck_ops = { + .enable = &omap3_noncore_dpll_enable, + .disable = &omap3_noncore_dpll_disable, + .recalc_rate = &omap3_dpll_recalc, + .round_rate = &omap2_dpll_round_rate, + .set_rate = &omap3_noncore_dpll_set_rate, + .get_parent = &omap2_init_dpll_parent, +}; + +static const struct clk_ops dpll_no_gate_ck_ops = { + .recalc_rate = &omap3_dpll_recalc, + .get_parent = &omap2_init_dpll_parent, + .round_rate = &omap2_dpll_round_rate, + .set_rate = &omap3_noncore_dpll_set_rate, +}; + +#ifdef CONFIG_ARCH_OMAP3 +static const struct clk_ops omap3_dpll_ck_ops = { + .enable = &omap3_noncore_dpll_enable, + .disable = &omap3_noncore_dpll_disable, + .get_parent = &omap2_init_dpll_parent, + .recalc_rate = &omap3_dpll_recalc, + .set_rate = &omap3_noncore_dpll_set_rate, + .round_rate = &omap2_dpll_round_rate, +}; + +static const struct clk_ops omap3_dpll_per_ck_ops = { + .enable = &omap3_noncore_dpll_enable, + .disable = &omap3_noncore_dpll_disable, + .get_parent = &omap2_init_dpll_parent, + .recalc_rate = &omap3_dpll_recalc, + .set_rate = &omap3_dpll4_set_rate, + .round_rate = &omap2_dpll_round_rate, +}; +#endif + +static const struct clk_ops dpll_x2_ck_ops = { + .recalc_rate = &omap3_clkoutx2_recalc, +}; + +/** + * ti_clk_register_dpll - low level registration of a DPLL clock + * @hw: hardware clock definition for the clock + * @node: device node for the clock + * + * Finalizes DPLL registration process. In case a failure (clk-ref or + * clk-bypass is missing), the clock is added to retry list and + * the initialization is retried on later stage. + */ +static void __init ti_clk_register_dpll(struct clk_hw *hw, + struct device_node *node) +{ + struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw); + struct dpll_data *dd = clk_hw->dpll_data; + struct clk *clk; + + dd->clk_ref = of_clk_get(node, 0); + dd->clk_bypass = of_clk_get(node, 1); + + if (IS_ERR(dd->clk_ref) || IS_ERR(dd->clk_bypass)) { + pr_debug("clk-ref or clk-bypass missing for %s, retry later\n", + node->name); + if (!ti_clk_retry_init(node, hw, ti_clk_register_dpll)) + return; + + goto cleanup; + } + + /* register the clock */ + clk = clk_register(NULL, &clk_hw->hw); + + if (!IS_ERR(clk)) { + omap2_init_clk_hw_omap_clocks(clk); + of_clk_add_provider(node, of_clk_src_simple_get, clk); + kfree(clk_hw->hw.init->parent_names); + kfree(clk_hw->hw.init); + return; + } + +cleanup: + kfree(clk_hw->dpll_data); + kfree(clk_hw->hw.init->parent_names); + kfree(clk_hw->hw.init); + kfree(clk_hw); +} + +#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ + defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM33XX) +/** + * ti_clk_register_dpll_x2 - Registers a DPLLx2 clock + * @node: device node for this clock + * @ops: clk_ops for this clock + * @hw_ops: clk_hw_ops for this clock + * + * Initializes a DPLL x 2 clock from device tree data. + */ +static void ti_clk_register_dpll_x2(struct device_node *node, + const struct clk_ops *ops, + const struct clk_hw_omap_ops *hw_ops) +{ + struct clk *clk; + struct clk_init_data init = { NULL }; + struct clk_hw_omap *clk_hw; + const char *name = node->name; + const char *parent_name; + + parent_name = of_clk_get_parent_name(node, 0); + if (!parent_name) { + pr_err("%s must have parent\n", node->name); + return; + } + + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + if (!clk_hw) + return; + + clk_hw->ops = hw_ops; + clk_hw->hw.init = &init; + + init.name = name; + init.ops = ops; + init.parent_names = &parent_name; + init.num_parents = 1; + + /* register the clock */ + clk = clk_register(NULL, &clk_hw->hw); + + if (IS_ERR(clk)) { + kfree(clk_hw); + } else { + omap2_init_clk_hw_omap_clocks(clk); + of_clk_add_provider(node, of_clk_src_simple_get, clk); + } +} +#endif + +/** + * of_ti_dpll_setup - Setup function for OMAP DPLL clocks + * @node: device node containing the DPLL info + * @ops: ops for the DPLL + * @ddt: DPLL data template to use + * @init_flags: flags for controlling init types + * + * Initializes a DPLL clock from device tree data. + */ +static void __init of_ti_dpll_setup(struct device_node *node, + const struct clk_ops *ops, + const struct dpll_data *ddt, + u8 init_flags) +{ + struct clk_hw_omap *clk_hw = NULL; + struct clk_init_data *init = NULL; + const char **parent_names = NULL; + struct dpll_data *dd = NULL; + int i; + u8 dpll_mode = 0; + + dd = kzalloc(sizeof(*dd), GFP_KERNEL); + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + init = kzalloc(sizeof(*init), GFP_KERNEL); + if (!dd || !clk_hw || !init) + goto cleanup; + + memcpy(dd, ddt, sizeof(*dd)); + + clk_hw->dpll_data = dd; + clk_hw->ops = &clkhwops_omap3_dpll; + clk_hw->hw.init = init; + clk_hw->flags = MEMMAP_ADDRESSING; + + init->name = node->name; + init->ops = ops; + + init->num_parents = of_clk_get_parent_count(node); + if (init->num_parents < 1) { + pr_err("%s must have parent(s)\n", node->name); + goto cleanup; + } + + parent_names = kzalloc(sizeof(char *) * init->num_parents, GFP_KERNEL); + if (!parent_names) + goto cleanup; + + for (i = 0; i < init->num_parents; i++) + parent_names[i] = of_clk_get_parent_name(node, i); + + init->parent_names = parent_names; + + dd->control_reg = ti_clk_get_reg_addr(node, 0); + dd->idlest_reg = ti_clk_get_reg_addr(node, 1); + dd->mult_div1_reg = ti_clk_get_reg_addr(node, 2); + + if (!dd->control_reg || !dd->idlest_reg || !dd->mult_div1_reg) + goto cleanup; + + if (init_flags & DPLL_HAS_AUTOIDLE) { + dd->autoidle_reg = ti_clk_get_reg_addr(node, 3); + if (!dd->autoidle_reg) + goto cleanup; + } + + if (of_property_read_bool(node, "ti,low-power-stop")) + dpll_mode |= 1 << DPLL_LOW_POWER_STOP; + + if (of_property_read_bool(node, "ti,low-power-bypass")) + dpll_mode |= 1 << DPLL_LOW_POWER_BYPASS; + + if (of_property_read_bool(node, "ti,lock")) + dpll_mode |= 1 << DPLL_LOCKED; + + if (dpll_mode) + dd->modes = dpll_mode; + + ti_clk_register_dpll(&clk_hw->hw, node); + return; + +cleanup: + kfree(dd); + kfree(parent_names); + kfree(init); + kfree(clk_hw); +} + +#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ + defined(CONFIG_SOC_DRA7XX) +static void __init of_ti_omap4_dpll_x2_setup(struct device_node *node) +{ + ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, &clkhwops_omap4_dpllmx); +} +CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock", + of_ti_omap4_dpll_x2_setup); +#endif + +#ifdef CONFIG_SOC_AM33XX +static void __init of_ti_am3_dpll_x2_setup(struct device_node *node) +{ + ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, NULL); +} +CLK_OF_DECLARE(ti_am3_dpll_x2_clock, "ti,am3-dpll-x2-clock", + of_ti_am3_dpll_x2_setup); +#endif + +#ifdef CONFIG_ARCH_OMAP3 +static void __init of_ti_omap3_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .freqsel_mask = 0xf0, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &omap3_dpll_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap3_dpll_clock, "ti,omap3-dpll-clock", + of_ti_omap3_dpll_setup); + +static void __init of_ti_omap3_core_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 16, + .div1_mask = 0x7f << 8, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .freqsel_mask = 0xf0, + }; + + of_ti_dpll_setup(node, &omap3_dpll_core_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap3_core_dpll_clock, "ti,omap3-dpll-core-clock", + of_ti_omap3_core_dpll_setup); + +static void __init of_ti_omap3_per_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1 << 1, + .enable_mask = 0x7 << 16, + .autoidle_mask = 0x7 << 3, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .freqsel_mask = 0xf00000, + .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap3_per_dpll_clock, "ti,omap3-dpll-per-clock", + of_ti_omap3_per_dpll_setup); + +static void __init of_ti_omap3_per_jtype_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1 << 1, + .enable_mask = 0x7 << 16, + .autoidle_mask = 0x7 << 3, + .mult_mask = 0xfff << 8, + .div1_mask = 0x7f, + .max_multiplier = 4095, + .max_divider = 128, + .min_divider = 1, + .sddiv_mask = 0xff << 24, + .dco_mask = 0xe << 20, + .flags = DPLL_J_TYPE, + .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap3_per_jtype_dpll_clock, "ti,omap3-dpll-per-j-type-clock", + of_ti_omap3_per_jtype_dpll_setup); +#endif + +static void __init of_ti_omap4_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap4_dpll_clock, "ti,omap4-dpll-clock", + of_ti_omap4_dpll_setup); + +static void __init of_ti_omap4_core_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap4_core_dpll_clock, "ti,omap4-dpll-core-clock", + of_ti_omap4_core_dpll_setup); + +#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ + defined(CONFIG_SOC_DRA7XX) +static void __init of_ti_omap4_m4xen_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .m4xen_mask = 0x800, + .lpmode_mask = 1 << 10, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap4_m4xen_dpll_clock, "ti,omap4-dpll-m4xen-clock", + of_ti_omap4_m4xen_dpll_setup); + +static void __init of_ti_omap4_jtype_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0xfff << 8, + .div1_mask = 0xff, + .max_multiplier = 4095, + .max_divider = 256, + .min_divider = 1, + .sddiv_mask = 0xff << 24, + .flags = DPLL_J_TYPE, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap4_jtype_dpll_clock, "ti,omap4-dpll-j-type-clock", + of_ti_omap4_jtype_dpll_setup); +#endif + +static void __init of_ti_am3_no_gate_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd, 0); +} +CLK_OF_DECLARE(ti_am3_no_gate_dpll_clock, "ti,am3-dpll-no-gate-clock", + of_ti_am3_no_gate_dpll_setup); + +static void __init of_ti_am3_jtype_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 4095, + .max_divider = 256, + .min_divider = 2, + .flags = DPLL_J_TYPE, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_ck_ops, &dd, 0); +} +CLK_OF_DECLARE(ti_am3_jtype_dpll_clock, "ti,am3-dpll-j-type-clock", + of_ti_am3_jtype_dpll_setup); + +static void __init of_ti_am3_no_gate_jtype_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .flags = DPLL_J_TYPE, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd, 0); +} +CLK_OF_DECLARE(ti_am3_no_gate_jtype_dpll_clock, + "ti,am3-dpll-no-gate-j-type-clock", + of_ti_am3_no_gate_jtype_dpll_setup); + +static void __init of_ti_am3_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_ck_ops, &dd, 0); +} +CLK_OF_DECLARE(ti_am3_dpll_clock, "ti,am3-dpll-clock", of_ti_am3_dpll_setup); + +static void __init of_ti_am3_core_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd, 0); +} +CLK_OF_DECLARE(ti_am3_core_dpll_clock, "ti,am3-dpll-core-clock", + of_ti_am3_core_dpll_setup); diff --git a/drivers/clk/ti/fixed-factor.c b/drivers/clk/ti/fixed-factor.c new file mode 100644 index 00000000000000..c2c8a287408c91 --- /dev/null +++ b/drivers/clk/ti/fixed-factor.c @@ -0,0 +1,66 @@ +/* + * TI Fixed Factor Clock + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo + * + * 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 "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +/** + * of_ti_fixed_factor_clk_setup - Setup function for TI fixed factor clock + * @node: device node for this clock + * + * Sets up a simple fixed factor clock based on device tree info. + */ +static void __init of_ti_fixed_factor_clk_setup(struct device_node *node) +{ + struct clk *clk; + const char *clk_name = node->name; + const char *parent_name; + u32 div, mult; + u32 flags = 0; + + if (of_property_read_u32(node, "ti,clock-div", &div)) { + pr_err("%s must have a clock-div property\n", node->name); + return; + } + + if (of_property_read_u32(node, "ti,clock-mult", &mult)) { + pr_err("%s must have a clock-mult property\n", node->name); + return; + } + + if (of_property_read_bool(node, "ti,set-rate-parent")) + flags |= CLK_SET_RATE_PARENT; + + parent_name = of_clk_get_parent_name(node, 0); + + clk = clk_register_fixed_factor(NULL, clk_name, parent_name, flags, + mult, div); + + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + of_ti_clk_autoidle_setup(node); + } +} +CLK_OF_DECLARE(ti_fixed_factor_clk, "ti,fixed-factor-clock", + of_ti_fixed_factor_clk_setup); diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c new file mode 100644 index 00000000000000..3e2999d11d15c1 --- /dev/null +++ b/drivers/clk/ti/gate.c @@ -0,0 +1,249 @@ +/* + * OMAP gate clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo + * + * 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 "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk); + +static const struct clk_ops omap_gate_clkdm_clk_ops = { + .init = &omap2_init_clk_clkdm, + .enable = &omap2_clkops_enable_clkdm, + .disable = &omap2_clkops_disable_clkdm, +}; + +static const struct clk_ops omap_gate_clk_ops = { + .init = &omap2_init_clk_clkdm, + .enable = &omap2_dflt_clk_enable, + .disable = &omap2_dflt_clk_disable, + .is_enabled = &omap2_dflt_clk_is_enabled, +}; + +static const struct clk_ops omap_gate_clk_hsdiv_restore_ops = { + .init = &omap2_init_clk_clkdm, + .enable = &omap36xx_gate_clk_enable_with_hsdiv_restore, + .disable = &omap2_dflt_clk_disable, + .is_enabled = &omap2_dflt_clk_is_enabled, +}; + +/** + * omap36xx_gate_clk_enable_with_hsdiv_restore - enable clocks suffering + * from HSDivider PWRDN problem Implements Errata ID: i556. + * @clk: DPLL output struct clk + * + * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck, + * dpll4_m5_ck & dpll4_m6_ck dividers gets loaded with reset + * valueafter their respective PWRDN bits are set. Any dummy write + * (Any other value different from the Read value) to the + * corresponding CM_CLKSEL register will refresh the dividers. + */ +static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk) +{ + struct clk_divider *parent; + struct clk_hw *parent_hw; + u32 dummy_v, orig_v; + int ret; + + /* Clear PWRDN bit of HSDIVIDER */ + ret = omap2_dflt_clk_enable(clk); + + /* Parent is the x2 node, get parent of parent for the m2 div */ + parent_hw = __clk_get_hw(__clk_get_parent(__clk_get_parent(clk->clk))); + parent = to_clk_divider(parent_hw); + + /* Restore the dividers */ + if (!ret) { + orig_v = ti_clk_ll_ops->clk_readl(parent->reg); + dummy_v = orig_v; + + /* Write any other value different from the Read value */ + dummy_v ^= (1 << parent->shift); + ti_clk_ll_ops->clk_writel(dummy_v, parent->reg); + + /* Write the original divider */ + ti_clk_ll_ops->clk_writel(orig_v, parent->reg); + } + + return ret; +} + +static void __init _of_ti_gate_clk_setup(struct device_node *node, + const struct clk_ops *ops, + const struct clk_hw_omap_ops *hw_ops) +{ + struct clk *clk; + struct clk_init_data init = { NULL }; + struct clk_hw_omap *clk_hw; + const char *clk_name = node->name; + const char *parent_name; + u32 val; + + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + if (!clk_hw) + return; + + clk_hw->hw.init = &init; + + init.name = clk_name; + init.ops = ops; + + if (ops != &omap_gate_clkdm_clk_ops) { + clk_hw->enable_reg = ti_clk_get_reg_addr(node, 0); + if (!clk_hw->enable_reg) + goto cleanup; + + if (!of_property_read_u32(node, "ti,bit-shift", &val)) + clk_hw->enable_bit = val; + } + + clk_hw->ops = hw_ops; + + clk_hw->flags = MEMMAP_ADDRESSING; + + if (of_clk_get_parent_count(node) != 1) { + pr_err("%s must have 1 parent\n", clk_name); + goto cleanup; + } + + parent_name = of_clk_get_parent_name(node, 0); + init.parent_names = &parent_name; + init.num_parents = 1; + + if (of_property_read_bool(node, "ti,set-rate-parent")) + init.flags |= CLK_SET_RATE_PARENT; + + if (of_property_read_bool(node, "ti,set-bit-to-disable")) + clk_hw->flags |= INVERT_ENABLE; + + clk = clk_register(NULL, &clk_hw->hw); + + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + return; + } + +cleanup: + kfree(clk_hw); +} + +static void __init +_of_ti_composite_gate_clk_setup(struct device_node *node, + const struct clk_hw_omap_ops *hw_ops) +{ + struct clk_hw_omap *gate; + u32 val = 0; + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + return; + + gate->enable_reg = ti_clk_get_reg_addr(node, 0); + if (!gate->enable_reg) + goto cleanup; + + of_property_read_u32(node, "ti,bit-shift", &val); + + gate->enable_bit = val; + gate->ops = hw_ops; + gate->flags = MEMMAP_ADDRESSING; + + if (!ti_clk_add_component(node, &gate->hw, CLK_COMPONENT_TYPE_GATE)) + return; + +cleanup: + kfree(gate); +} + +static void __init +of_ti_composite_no_wait_gate_clk_setup(struct device_node *node) +{ + _of_ti_composite_gate_clk_setup(node, NULL); +} +CLK_OF_DECLARE(ti_composite_no_wait_gate_clk, "ti,composite-no-wait-gate-clock", + of_ti_composite_no_wait_gate_clk_setup); + +#ifdef CONFIG_ARCH_OMAP3 +static void __init of_ti_composite_interface_clk_setup(struct device_node *node) +{ + _of_ti_composite_gate_clk_setup(node, &clkhwops_iclk_wait); +} +CLK_OF_DECLARE(ti_composite_interface_clk, "ti,composite-interface-clock", + of_ti_composite_interface_clk_setup); +#endif + +static void __init of_ti_composite_gate_clk_setup(struct device_node *node) +{ + _of_ti_composite_gate_clk_setup(node, &clkhwops_wait); +} +CLK_OF_DECLARE(ti_composite_gate_clk, "ti,composite-gate-clock", + of_ti_composite_gate_clk_setup); + + +static void __init of_ti_clkdm_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clkdm_clk_ops, NULL); +} +CLK_OF_DECLARE(ti_clkdm_gate_clk, "ti,clkdm-gate-clock", + of_ti_clkdm_gate_clk_setup); + +static void __init of_ti_hsdiv_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clk_hsdiv_restore_ops, + &clkhwops_wait); +} +CLK_OF_DECLARE(ti_hsdiv_gate_clk, "ti,hsdiv-gate-clock", + of_ti_hsdiv_gate_clk_setup); + +static void __init of_ti_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, NULL); +} +CLK_OF_DECLARE(ti_gate_clk, "ti,gate-clock", of_ti_gate_clk_setup) + +static void __init of_ti_wait_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, &clkhwops_wait); +} +CLK_OF_DECLARE(ti_wait_gate_clk, "ti,wait-gate-clock", + of_ti_wait_gate_clk_setup); + +#ifdef CONFIG_ARCH_OMAP3 +static void __init of_ti_am35xx_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, + &clkhwops_am35xx_ipss_module_wait); +} +CLK_OF_DECLARE(ti_am35xx_gate_clk, "ti,am35xx-gate-clock", + of_ti_am35xx_gate_clk_setup); + +static void __init of_ti_dss_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, + &clkhwops_omap3430es2_dss_usbhost_wait); +} +CLK_OF_DECLARE(ti_dss_gate_clk, "ti,dss-gate-clock", + of_ti_dss_gate_clk_setup); +#endif diff --git a/drivers/clk/ti/interface.c b/drivers/clk/ti/interface.c new file mode 100644 index 00000000000000..320a2b168bb20f --- /dev/null +++ b/drivers/clk/ti/interface.c @@ -0,0 +1,125 @@ +/* + * OMAP interface clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo + * + * 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 "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +static const struct clk_ops ti_interface_clk_ops = { + .init = &omap2_init_clk_clkdm, + .enable = &omap2_dflt_clk_enable, + .disable = &omap2_dflt_clk_disable, + .is_enabled = &omap2_dflt_clk_is_enabled, +}; + +static void __init _of_ti_interface_clk_setup(struct device_node *node, + const struct clk_hw_omap_ops *ops) +{ + struct clk *clk; + struct clk_init_data init = { NULL }; + struct clk_hw_omap *clk_hw; + const char *parent_name; + u32 val; + + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + if (!clk_hw) + return; + + clk_hw->hw.init = &init; + clk_hw->ops = ops; + clk_hw->flags = MEMMAP_ADDRESSING; + + clk_hw->enable_reg = ti_clk_get_reg_addr(node, 0); + if (!clk_hw->enable_reg) + goto cleanup; + + if (!of_property_read_u32(node, "ti,bit-shift", &val)) + clk_hw->enable_bit = val; + + init.name = node->name; + init.ops = &ti_interface_clk_ops; + init.flags = 0; + + parent_name = of_clk_get_parent_name(node, 0); + if (!parent_name) { + pr_err("%s must have a parent\n", node->name); + goto cleanup; + } + + init.num_parents = 1; + init.parent_names = &parent_name; + + clk = clk_register(NULL, &clk_hw->hw); + + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + omap2_init_clk_hw_omap_clocks(clk); + return; + } + +cleanup: + kfree(clk_hw); +} + +static void __init of_ti_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, &clkhwops_iclk_wait); +} +CLK_OF_DECLARE(ti_interface_clk, "ti,omap3-interface-clock", + of_ti_interface_clk_setup); + +static void __init of_ti_no_wait_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, &clkhwops_iclk); +} +CLK_OF_DECLARE(ti_no_wait_interface_clk, "ti,omap3-no-wait-interface-clock", + of_ti_no_wait_interface_clk_setup); + +static void __init of_ti_hsotgusb_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, + &clkhwops_omap3430es2_iclk_hsotgusb_wait); +} +CLK_OF_DECLARE(ti_hsotgusb_interface_clk, "ti,omap3-hsotgusb-interface-clock", + of_ti_hsotgusb_interface_clk_setup); + +static void __init of_ti_dss_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, + &clkhwops_omap3430es2_iclk_dss_usbhost_wait); +} +CLK_OF_DECLARE(ti_dss_interface_clk, "ti,omap3-dss-interface-clock", + of_ti_dss_interface_clk_setup); + +static void __init of_ti_ssi_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, &clkhwops_omap3430es2_iclk_ssi_wait); +} +CLK_OF_DECLARE(ti_ssi_interface_clk, "ti,omap3-ssi-interface-clock", + of_ti_ssi_interface_clk_setup); + +static void __init of_ti_am35xx_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, &clkhwops_am35xx_ipss_wait); +} +CLK_OF_DECLARE(ti_am35xx_interface_clk, "ti,am35xx-interface-clock", + of_ti_am35xx_interface_clk_setup); diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c new file mode 100644 index 00000000000000..0197a478720ce9 --- /dev/null +++ b/drivers/clk/ti/mux.c @@ -0,0 +1,246 @@ +/* + * TI Multiplexer Clock + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo + * + * 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 "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) + +static u8 ti_clk_mux_get_parent(struct clk_hw *hw) +{ + struct clk_mux *mux = to_clk_mux(hw); + int num_parents = __clk_get_num_parents(hw->clk); + u32 val; + + /* + * FIXME need a mux-specific flag to determine if val is bitwise or + * numeric. e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges + * from 0x1 to 0x7 (index starts at one) + * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so + * val = 0x4 really means "bit 2, index starts at bit 0" + */ + val = ti_clk_ll_ops->clk_readl(mux->reg) >> mux->shift; + val &= mux->mask; + + if (mux->table) { + int i; + + for (i = 0; i < num_parents; i++) + if (mux->table[i] == val) + return i; + return -EINVAL; + } + + if (val && (mux->flags & CLK_MUX_INDEX_BIT)) + val = ffs(val) - 1; + + if (val && (mux->flags & CLK_MUX_INDEX_ONE)) + val--; + + if (val >= num_parents) + return -EINVAL; + + return val; +} + +static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_mux *mux = to_clk_mux(hw); + u32 val; + unsigned long flags = 0; + + if (mux->table) { + index = mux->table[index]; + } else { + if (mux->flags & CLK_MUX_INDEX_BIT) + index = (1 << ffs(index)); + + if (mux->flags & CLK_MUX_INDEX_ONE) + index++; + } + + if (mux->lock) + spin_lock_irqsave(mux->lock, flags); + + if (mux->flags & CLK_MUX_HIWORD_MASK) { + val = mux->mask << (mux->shift + 16); + } else { + val = ti_clk_ll_ops->clk_readl(mux->reg); + val &= ~(mux->mask << mux->shift); + } + val |= index << mux->shift; + ti_clk_ll_ops->clk_writel(val, mux->reg); + + if (mux->lock) + spin_unlock_irqrestore(mux->lock, flags); + + return 0; +} + +const struct clk_ops ti_clk_mux_ops = { + .get_parent = ti_clk_mux_get_parent, + .set_parent = ti_clk_mux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; + +static struct clk *_register_mux(struct device *dev, const char *name, + const char **parent_names, u8 num_parents, + unsigned long flags, void __iomem *reg, + u8 shift, u32 mask, u8 clk_mux_flags, + u32 *table, spinlock_t *lock) +{ + struct clk_mux *mux; + struct clk *clk; + struct clk_init_data init; + + /* allocate the mux */ + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) { + pr_err("%s: could not allocate mux clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &ti_clk_mux_ops; + init.flags = flags | CLK_IS_BASIC; + init.parent_names = parent_names; + init.num_parents = num_parents; + + /* struct clk_mux assignments */ + mux->reg = reg; + mux->shift = shift; + mux->mask = mask; + mux->flags = clk_mux_flags; + mux->lock = lock; + mux->table = table; + mux->hw.init = &init; + + clk = clk_register(dev, &mux->hw); + + if (IS_ERR(clk)) + kfree(mux); + + return clk; +} + +/** + * of_mux_clk_setup - Setup function for simple mux rate clock + * @node: DT node for the clock + * + * Sets up a basic clock multiplexer. + */ +static void of_mux_clk_setup(struct device_node *node) +{ + struct clk *clk; + void __iomem *reg; + int num_parents; + const char **parent_names; + int i; + u8 clk_mux_flags = 0; + u32 mask = 0; + u32 shift = 0; + u32 flags = 0; + + num_parents = of_clk_get_parent_count(node); + if (num_parents < 2) { + pr_err("mux-clock %s must have parents\n", node->name); + return; + } + parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL); + if (!parent_names) + goto cleanup; + + for (i = 0; i < num_parents; i++) + parent_names[i] = of_clk_get_parent_name(node, i); + + reg = ti_clk_get_reg_addr(node, 0); + + if (!reg) + goto cleanup; + + of_property_read_u32(node, "ti,bit-shift", &shift); + + if (of_property_read_bool(node, "ti,index-starts-at-one")) + clk_mux_flags |= CLK_MUX_INDEX_ONE; + + if (of_property_read_bool(node, "ti,set-rate-parent")) + flags |= CLK_SET_RATE_PARENT; + + /* Generate bit-mask based on parent info */ + mask = num_parents; + if (!(clk_mux_flags & CLK_MUX_INDEX_ONE)) + mask--; + + mask = (1 << fls(mask)) - 1; + + clk = _register_mux(NULL, node->name, parent_names, num_parents, flags, + reg, shift, mask, clk_mux_flags, NULL, NULL); + + if (!IS_ERR(clk)) + of_clk_add_provider(node, of_clk_src_simple_get, clk); + +cleanup: + kfree(parent_names); +} +CLK_OF_DECLARE(mux_clk, "ti,mux-clock", of_mux_clk_setup); + +static void __init of_ti_composite_mux_clk_setup(struct device_node *node) +{ + struct clk_mux *mux; + int num_parents; + u32 val; + + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return; + + mux->reg = ti_clk_get_reg_addr(node, 0); + + if (!mux->reg) + goto cleanup; + + if (!of_property_read_u32(node, "ti,bit-shift", &val)) + mux->shift = val; + + if (of_property_read_bool(node, "ti,index-starts-at-one")) + mux->flags |= CLK_MUX_INDEX_ONE; + + num_parents = of_clk_get_parent_count(node); + + if (num_parents < 2) { + pr_err("%s must have parents\n", node->name); + goto cleanup; + } + + mux->mask = num_parents - 1; + mux->mask = (1 << fls(mux->mask)) - 1; + + if (!ti_clk_add_component(node, &mux->hw, CLK_COMPONENT_TYPE_MUX)) + return; + +cleanup: + kfree(mux); +} +CLK_OF_DECLARE(ti_composite_mux_clk_setup, "ti,composite-mux-clock", + of_ti_composite_mux_clk_setup); diff --git a/drivers/clocksource/bcm_kona_timer.c b/drivers/clocksource/bcm_kona_timer.c index 5176e761166b27..0595dc6c453e6e 100644 --- a/drivers/clocksource/bcm_kona_timer.c +++ b/drivers/clocksource/bcm_kona_timer.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -98,24 +99,6 @@ kona_timer_get_counter(void *timer_base, uint32_t *msw, uint32_t *lsw) return; } -static void __init kona_timers_init(struct device_node *node) -{ - u32 freq; - - if (!of_property_read_u32(node, "clock-frequency", &freq)) - arch_timer_rate = freq; - else - panic("clock-frequency not set in the .dts file"); - - /* Setup IRQ numbers */ - timers.tmr_irq = irq_of_parse_and_map(node, 0); - - /* Setup IO addresses */ - timers.tmr_regs = of_iomap(node, 0); - - kona_timer_disable_and_clear(timers.tmr_regs); -} - static int kona_timer_set_next_event(unsigned long clc, struct clock_event_device *unused) { @@ -190,7 +173,34 @@ static struct irqaction kona_timer_irq = { static void __init kona_timer_init(struct device_node *node) { - kona_timers_init(node); + u32 freq; + struct clk *external_clk; + + if (!of_device_is_available(node)) { + pr_info("Kona Timer v1 marked as disabled in device tree\n"); + return; + } + + external_clk = of_clk_get_by_name(node, NULL); + + if (!IS_ERR(external_clk)) { + arch_timer_rate = clk_get_rate(external_clk); + clk_prepare_enable(external_clk); + } else if (!of_property_read_u32(node, "clock-frequency", &freq)) { + arch_timer_rate = freq; + } else { + pr_err("Kona Timer v1 unable to determine clock-frequency"); + return; + } + + /* Setup IRQ numbers */ + timers.tmr_irq = irq_of_parse_and_map(node, 0); + + /* Setup IO addresses */ + timers.tmr_regs = of_iomap(node, 0); + + kona_timer_disable_and_clear(timers.tmr_regs); + kona_timer_clockevents_init(); setup_irq(timers.tmr_irq, &kona_timer_irq); kona_timer_set_next_event((arch_timer_rate / HZ), NULL); diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 79e5608e71b587..18448a7e9f8654 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -919,7 +919,7 @@ static void __init acpi_cpufreq_boost_init(void) } } -static void __exit acpi_cpufreq_boost_exit(void) +static void acpi_cpufreq_boost_exit(void) { if (msrs) { unregister_cpu_notifier(&boost_nb); @@ -969,9 +969,10 @@ static int __init acpi_cpufreq_init(void) acpi_cpufreq_boost_init(); ret = cpufreq_register_driver(&acpi_cpufreq_driver); - if (ret) + if (ret) { free_acpi_perf_data(); - + acpi_cpufreq_boost_exit(); + } return ret; } diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 08ca8c9f41cdeb..cb003a6b72c86f 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1323,8 +1323,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev, up_read(&policy->rwsem); if (cpu != policy->cpu) { - if (!frozen) - sysfs_remove_link(&dev->kobj, "cpufreq"); + sysfs_remove_link(&dev->kobj, "cpufreq"); } else if (cpus > 1) { new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu); if (new_cpu >= 0) { diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 7e257b2336025c..e908161059216b 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -34,8 +34,10 @@ #define SAMPLE_COUNT 3 -#define BYT_RATIOS 0x66a -#define BYT_VIDS 0x66b +#define BYT_RATIOS 0x66a +#define BYT_VIDS 0x66b +#define BYT_TURBO_RATIOS 0x66c + #define FRAC_BITS 8 #define int_tofp(X) ((int64_t)(X) << FRAC_BITS) @@ -51,12 +53,11 @@ static inline int32_t div_fp(int32_t x, int32_t y) return div_s64((int64_t)x << FRAC_BITS, (int64_t)y); } -static u64 energy_divisor; - struct sample { int32_t core_pct_busy; u64 aperf; u64 mperf; + unsigned long long tsc; int freq; }; @@ -96,6 +97,7 @@ struct cpudata { u64 prev_aperf; u64 prev_mperf; + unsigned long long prev_tsc; int sample_ptr; struct sample samples[SAMPLE_COUNT]; }; @@ -357,7 +359,7 @@ static int byt_get_min_pstate(void) { u64 value; rdmsrl(BYT_RATIOS, value); - return value & 0xFF; + return (value >> 8) & 0xFF; } static int byt_get_max_pstate(void) @@ -367,6 +369,13 @@ static int byt_get_max_pstate(void) return (value >> 16) & 0xFF; } +static int byt_get_turbo_pstate(void) +{ + u64 value; + rdmsrl(BYT_TURBO_RATIOS, value); + return value & 0x3F; +} + static void byt_set_pstate(struct cpudata *cpudata, int pstate) { u64 val; @@ -469,7 +478,7 @@ static struct cpu_defaults byt_params = { .funcs = { .get_max = byt_get_max_pstate, .get_min = byt_get_min_pstate, - .get_turbo = byt_get_max_pstate, + .get_turbo = byt_get_turbo_pstate, .set = byt_set_pstate, .get_vid = byt_get_vid, }, @@ -548,30 +557,41 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu, struct sample *sample) { u64 core_pct; - core_pct = div64_u64(int_tofp(sample->aperf * 100), - sample->mperf); - sample->freq = fp_toint(cpu->pstate.max_pstate * core_pct * 1000); + u64 c0_pct; + + core_pct = div64_u64(sample->aperf * 100, sample->mperf); - sample->core_pct_busy = core_pct; + c0_pct = div64_u64(sample->mperf * 100, sample->tsc); + sample->freq = fp_toint( + mul_fp(int_tofp(cpu->pstate.max_pstate), + int_tofp(core_pct * 1000))); + + sample->core_pct_busy = mul_fp(int_tofp(core_pct), + div_fp(int_tofp(c0_pct + 1), int_tofp(100))); } static inline void intel_pstate_sample(struct cpudata *cpu) { u64 aperf, mperf; + unsigned long long tsc; rdmsrl(MSR_IA32_APERF, aperf); rdmsrl(MSR_IA32_MPERF, mperf); + tsc = native_read_tsc(); cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT; cpu->samples[cpu->sample_ptr].aperf = aperf; cpu->samples[cpu->sample_ptr].mperf = mperf; + cpu->samples[cpu->sample_ptr].tsc = tsc; cpu->samples[cpu->sample_ptr].aperf -= cpu->prev_aperf; cpu->samples[cpu->sample_ptr].mperf -= cpu->prev_mperf; + cpu->samples[cpu->sample_ptr].tsc -= cpu->prev_tsc; intel_pstate_calc_busy(cpu, &cpu->samples[cpu->sample_ptr]); cpu->prev_aperf = aperf; cpu->prev_mperf = mperf; + cpu->prev_tsc = tsc; } static inline void intel_pstate_set_sample_time(struct cpudata *cpu) @@ -617,12 +637,10 @@ static void intel_pstate_timer_func(unsigned long __data) { struct cpudata *cpu = (struct cpudata *) __data; struct sample *sample; - u64 energy; intel_pstate_sample(cpu); sample = &cpu->samples[cpu->sample_ptr]; - rdmsrl(MSR_PKG_ENERGY_STATUS, energy); intel_pstate_adjust_busy_pstate(cpu); @@ -631,7 +649,6 @@ static void intel_pstate_timer_func(unsigned long __data) cpu->pstate.current_pstate, sample->mperf, sample->aperf, - div64_u64(energy, energy_divisor), sample->freq); intel_pstate_set_sample_time(cpu); @@ -913,7 +930,6 @@ static int __init intel_pstate_init(void) int cpu, rc = 0; const struct x86_cpu_id *id; struct cpu_defaults *cpu_info; - u64 units; if (no_load) return -ENODEV; @@ -947,9 +963,6 @@ static int __init intel_pstate_init(void) if (rc) goto out; - rdmsrl(MSR_RAPL_POWER_UNIT, units); - energy_divisor = 1 << ((units >> 8) & 0x1f); /* bits{12:8} */ - intel_pstate_debug_expose_params(); intel_pstate_sysfs_expose_params(); diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index e10b646634d77f..6684e034279251 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -1076,7 +1076,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol) { struct powernow_k8_data *data; struct init_on_cpu init_on_cpu; - int rc; + int rc, cpu; smp_call_function_single(pol->cpu, check_supported_cpu, &rc, 1); if (rc) @@ -1140,7 +1140,9 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol) pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n", data->currfid, data->currvid); - per_cpu(powernow_data, pol->cpu) = data; + /* Point all the CPUs in this policy to the same data */ + for_each_cpu(cpu, pol->cpus) + per_cpu(powernow_data, cpu) = data; return 0; @@ -1155,6 +1157,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol) static int powernowk8_cpu_exit(struct cpufreq_policy *pol) { struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); + int cpu; if (!data) return -EINVAL; @@ -1165,7 +1168,8 @@ static int powernowk8_cpu_exit(struct cpufreq_policy *pol) kfree(data->powernow_table); kfree(data); - per_cpu(powernow_data, pol->cpu) = NULL; + for_each_cpu(cpu, pol->cpus) + per_cpu(powernow_data, cpu) = NULL; return 0; } diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index b3fb81d7cf0410..f04e25f6c98d5f 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig @@ -35,6 +35,11 @@ depends on ARM source "drivers/cpuidle/Kconfig.arm" endmenu +menu "POWERPC CPU Idle Drivers" +depends on PPC +source "drivers/cpuidle/Kconfig.powerpc" +endmenu + endif config ARCH_NEEDS_CPU_IDLE_COUPLED diff --git a/drivers/cpuidle/Kconfig.powerpc b/drivers/cpuidle/Kconfig.powerpc new file mode 100644 index 00000000000000..66c3a09574e978 --- /dev/null +++ b/drivers/cpuidle/Kconfig.powerpc @@ -0,0 +1,20 @@ +# +# POWERPC CPU Idle Drivers +# +config PSERIES_CPUIDLE + bool "Cpuidle driver for pSeries platforms" + depends on CPU_IDLE + depends on PPC_PSERIES + default y + help + Select this option to enable processor idle state management + through cpuidle subsystem. + +config POWERNV_CPUIDLE + bool "Cpuidle driver for powernv platforms" + depends on CPU_IDLE + depends on PPC_POWERNV + default y + help + Select this option to enable processor idle state management + through cpuidle subsystem. diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index 527be28e5c1e4e..f71ae1b373c5e8 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile @@ -13,3 +13,8 @@ obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE) += cpuidle-kirkwood.o obj-$(CONFIG_ARM_ZYNQ_CPUIDLE) += cpuidle-zynq.o obj-$(CONFIG_ARM_U8500_CPUIDLE) += cpuidle-ux500.o obj-$(CONFIG_ARM_AT91_CPUIDLE) += cpuidle-at91.o + +############################################################################### +# POWERPC drivers +obj-$(CONFIG_PSERIES_CPUIDLE) += cpuidle-pseries.o +obj-$(CONFIG_POWERNV_CPUIDLE) += cpuidle-powernv.o diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c new file mode 100644 index 00000000000000..78fd174c57e86d --- /dev/null +++ b/drivers/cpuidle/cpuidle-powernv.c @@ -0,0 +1,169 @@ +/* + * cpuidle-powernv - idle state cpuidle driver. + * Adapted from drivers/cpuidle/cpuidle-pseries + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct cpuidle_driver powernv_idle_driver = { + .name = "powernv_idle", + .owner = THIS_MODULE, +}; + +static int max_idle_state; +static struct cpuidle_state *cpuidle_state_table; + +static int snooze_loop(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + local_irq_enable(); + set_thread_flag(TIF_POLLING_NRFLAG); + + while (!need_resched()) { + HMT_low(); + HMT_very_low(); + } + + HMT_medium(); + clear_thread_flag(TIF_POLLING_NRFLAG); + smp_mb(); + return index; +} + +static int nap_loop(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + power7_idle(); + return index; +} + +/* + * States for dedicated partition case. + */ +static struct cpuidle_state powernv_states[] = { + { /* Snooze */ + .name = "snooze", + .desc = "snooze", + .flags = CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 0, + .target_residency = 0, + .enter = &snooze_loop }, + { /* NAP */ + .name = "NAP", + .desc = "NAP", + .flags = CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 10, + .target_residency = 100, + .enter = &nap_loop }, +}; + +static int powernv_cpuidle_add_cpu_notifier(struct notifier_block *n, + unsigned long action, void *hcpu) +{ + int hotcpu = (unsigned long)hcpu; + struct cpuidle_device *dev = + per_cpu(cpuidle_devices, hotcpu); + + if (dev && cpuidle_get_driver()) { + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + cpuidle_pause_and_lock(); + cpuidle_enable_device(dev); + cpuidle_resume_and_unlock(); + break; + + case CPU_DEAD: + case CPU_DEAD_FROZEN: + cpuidle_pause_and_lock(); + cpuidle_disable_device(dev); + cpuidle_resume_and_unlock(); + break; + + default: + return NOTIFY_DONE; + } + } + return NOTIFY_OK; +} + +static struct notifier_block setup_hotplug_notifier = { + .notifier_call = powernv_cpuidle_add_cpu_notifier, +}; + +/* + * powernv_cpuidle_driver_init() + */ +static int powernv_cpuidle_driver_init(void) +{ + int idle_state; + struct cpuidle_driver *drv = &powernv_idle_driver; + + drv->state_count = 0; + + for (idle_state = 0; idle_state < max_idle_state; ++idle_state) { + /* Is the state not enabled? */ + if (cpuidle_state_table[idle_state].enter == NULL) + continue; + + drv->states[drv->state_count] = /* structure copy */ + cpuidle_state_table[idle_state]; + + drv->state_count += 1; + } + + return 0; +} + +/* + * powernv_idle_probe() + * Choose state table for shared versus dedicated partition + */ +static int powernv_idle_probe(void) +{ + + if (cpuidle_disable != IDLE_NO_OVERRIDE) + return -ENODEV; + + if (firmware_has_feature(FW_FEATURE_OPALv3)) { + cpuidle_state_table = powernv_states; + max_idle_state = ARRAY_SIZE(powernv_states); + } else + return -ENODEV; + + return 0; +} + +static int __init powernv_processor_idle_init(void) +{ + int retval; + + retval = powernv_idle_probe(); + if (retval) + return retval; + + powernv_cpuidle_driver_init(); + retval = cpuidle_register(&powernv_idle_driver, NULL); + if (retval) { + printk(KERN_DEBUG "Registration of powernv driver failed.\n"); + return retval; + } + + register_cpu_notifier(&setup_hotplug_notifier); + printk(KERN_DEBUG "powernv_idle_driver registered\n"); + return 0; +} + +device_initcall(powernv_processor_idle_init); diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/drivers/cpuidle/cpuidle-pseries.c similarity index 74% rename from arch/powerpc/platforms/pseries/processor_idle.c rename to drivers/cpuidle/cpuidle-pseries.c index 94134a5aecaac8..7ab564aa0b1c8c 100644 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ b/drivers/cpuidle/cpuidle-pseries.c @@ -1,5 +1,5 @@ /* - * processor_idle - idle state cpuidle driver. + * cpuidle-pseries - idle state cpuidle driver. * Adapted from drivers/idle/intel_idle.c and * drivers/acpi/processor_idle.c * @@ -17,7 +17,6 @@ #include #include #include -#include #include struct cpuidle_driver pseries_idle_driver = { @@ -25,9 +24,7 @@ struct cpuidle_driver pseries_idle_driver = { .owner = THIS_MODULE, }; -#define MAX_IDLE_STATE_COUNT 2 - -static int max_idle_state = MAX_IDLE_STATE_COUNT - 1; +static int max_idle_state; static struct cpuidle_state *cpuidle_state_table; static inline void idle_loop_prolog(unsigned long *in_purr) @@ -55,14 +52,12 @@ static int snooze_loop(struct cpuidle_device *dev, int index) { unsigned long in_purr; - int cpu = dev->cpu; idle_loop_prolog(&in_purr); local_irq_enable(); set_thread_flag(TIF_POLLING_NRFLAG); - while ((!need_resched()) && cpu_online(cpu)) { - ppc64_runlatch_off(); + while (!need_resched()) { HMT_low(); HMT_very_low(); } @@ -102,7 +97,6 @@ static int dedicated_cede_loop(struct cpuidle_device *dev, idle_loop_prolog(&in_purr); get_lppaca()->donate_dedicated_cpu = 1; - ppc64_runlatch_off(); HMT_medium(); check_and_cede_processor(); @@ -138,7 +132,7 @@ static int shared_cede_loop(struct cpuidle_device *dev, /* * States for dedicated partition case. */ -static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = { +static struct cpuidle_state dedicated_states[] = { { /* Snooze */ .name = "snooze", .desc = "snooze", @@ -158,7 +152,7 @@ static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = { /* * States for shared partition case. */ -static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = { +static struct cpuidle_state shared_states[] = { { /* Shared Cede */ .name = "Shared Cede", .desc = "Shared Cede", @@ -168,29 +162,12 @@ static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = { .enter = &shared_cede_loop }, }; -void update_smt_snooze_delay(int cpu, int residency) -{ - struct cpuidle_driver *drv = cpuidle_get_driver(); - struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu); - - if (cpuidle_state_table != dedicated_states) - return; - - if (residency < 0) { - /* Disable the Nap state on that cpu */ - if (dev) - dev->states_usage[1].disable = 1; - } else - if (drv) - drv->states[1].target_residency = residency; -} - static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n, unsigned long action, void *hcpu) { int hotcpu = (unsigned long)hcpu; struct cpuidle_device *dev = - per_cpu_ptr(cpuidle_devices, hotcpu); + per_cpu(cpuidle_devices, hotcpu); if (dev && cpuidle_get_driver()) { switch (action) { @@ -229,12 +206,8 @@ static int pseries_cpuidle_driver_init(void) drv->state_count = 0; - for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; ++idle_state) { - - if (idle_state > max_idle_state) - break; - - /* is the state not enabled? */ + for (idle_state = 0; idle_state < max_idle_state; ++idle_state) { + /* Is the state not enabled? */ if (cpuidle_state_table[idle_state].enter == NULL) continue; @@ -254,21 +227,19 @@ static int pseries_cpuidle_driver_init(void) static int pseries_idle_probe(void) { - if (!firmware_has_feature(FW_FEATURE_SPLPAR)) - return -ENODEV; - if (cpuidle_disable != IDLE_NO_OVERRIDE) return -ENODEV; - if (max_idle_state == 0) { - printk(KERN_DEBUG "pseries processor idle disabled.\n"); - return -EPERM; - } - - if (lppaca_shared_proc(get_lppaca())) - cpuidle_state_table = shared_states; - else - cpuidle_state_table = dedicated_states; + if (firmware_has_feature(FW_FEATURE_SPLPAR)) { + if (lppaca_shared_proc(get_lppaca())) { + cpuidle_state_table = shared_states; + max_idle_state = ARRAY_SIZE(shared_states); + } else { + cpuidle_state_table = dedicated_states; + max_idle_state = ARRAY_SIZE(dedicated_states); + } + } else + return -ENODEV; return 0; } @@ -290,22 +261,7 @@ static int __init pseries_processor_idle_init(void) register_cpu_notifier(&setup_hotplug_notifier); printk(KERN_DEBUG "pseries_idle_driver registered\n"); - return 0; } -static void __exit pseries_processor_idle_exit(void) -{ - - unregister_cpu_notifier(&setup_hotplug_notifier); - cpuidle_unregister(&pseries_idle_driver); - - return; -} - -module_init(pseries_processor_idle_init); -module_exit(pseries_processor_idle_exit); - -MODULE_AUTHOR("Deepthi Dharwar "); -MODULE_DESCRIPTION("Cpuidle driver for POWER"); -MODULE_LICENSE("GPL"); +device_initcall(pseries_processor_idle_init); diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c index 6c4c000671c50d..1e5481d88a262c 100644 --- a/drivers/crypto/nx/nx-842.c +++ b/drivers/crypto/nx/nx-842.c @@ -158,6 +158,15 @@ static inline unsigned long nx842_get_scatterlist_size( return sl->entry_nr * sizeof(struct nx842_slentry); } +static inline unsigned long nx842_get_pa(void *addr) +{ + if (is_vmalloc_addr(addr)) + return page_to_phys(vmalloc_to_page(addr)) + + offset_in_page(addr); + else + return __pa(addr); +} + static int nx842_build_scatterlist(unsigned long buf, int len, struct nx842_scatterlist *sl) { @@ -168,7 +177,7 @@ static int nx842_build_scatterlist(unsigned long buf, int len, entry = sl->entries; while (len) { - entry->ptr = __pa(buf); + entry->ptr = nx842_get_pa((void *)buf); nextpage = ALIGN(buf + 1, NX842_HW_PAGE_SIZE); if (nextpage < buf + len) { /* we aren't at the end yet */ @@ -370,8 +379,8 @@ int nx842_compress(const unsigned char *in, unsigned int inlen, op.flags = NX842_OP_COMPRESS; csbcpb = &workmem->csbcpb; memset(csbcpb, 0, sizeof(*csbcpb)); - op.csbcpb = __pa(csbcpb); - op.out = __pa(slout.entries); + op.csbcpb = nx842_get_pa(csbcpb); + op.out = nx842_get_pa(slout.entries); for (i = 0; i < hdr->blocks_nr; i++) { /* @@ -401,13 +410,13 @@ int nx842_compress(const unsigned char *in, unsigned int inlen, */ if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) { /* Create direct DDE */ - op.in = __pa(inbuf); + op.in = nx842_get_pa((void *)inbuf); op.inlen = max_sync_size; } else { /* Create indirect DDE (scatterlist) */ nx842_build_scatterlist(inbuf, max_sync_size, &slin); - op.in = __pa(slin.entries); + op.in = nx842_get_pa(slin.entries); op.inlen = -nx842_get_scatterlist_size(&slin); } @@ -565,7 +574,7 @@ int nx842_decompress(const unsigned char *in, unsigned int inlen, op.flags = NX842_OP_DECOMPRESS; csbcpb = &workmem->csbcpb; memset(csbcpb, 0, sizeof(*csbcpb)); - op.csbcpb = __pa(csbcpb); + op.csbcpb = nx842_get_pa(csbcpb); /* * max_sync_size may have changed since compression, @@ -597,12 +606,12 @@ int nx842_decompress(const unsigned char *in, unsigned int inlen, if (likely((inbuf & NX842_HW_PAGE_MASK) == ((inbuf + hdr->sizes[i] - 1) & NX842_HW_PAGE_MASK))) { /* Create direct DDE */ - op.in = __pa(inbuf); + op.in = nx842_get_pa((void *)inbuf); op.inlen = hdr->sizes[i]; } else { /* Create indirect DDE (scatterlist) */ nx842_build_scatterlist(inbuf, hdr->sizes[i] , &slin); - op.in = __pa(slin.entries); + op.in = nx842_get_pa(slin.entries); op.inlen = -nx842_get_scatterlist_size(&slin); } @@ -613,12 +622,12 @@ int nx842_decompress(const unsigned char *in, unsigned int inlen, */ if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) { /* Create direct DDE */ - op.out = __pa(outbuf); + op.out = nx842_get_pa((void *)outbuf); op.outlen = max_sync_size; } else { /* Create indirect DDE (scatterlist) */ nx842_build_scatterlist(outbuf, max_sync_size, &slout); - op.out = __pa(slout.entries); + op.out = nx842_get_pa(slout.entries); op.outlen = -nx842_get_scatterlist_size(&slout); } diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index 31f3adba4cf3f1..7d2f4355070059 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -67,7 +67,7 @@ comment "DEVFREQ Drivers" config ARM_EXYNOS4_BUS_DEVFREQ bool "ARM Exynos4210/4212/4412 Memory Bus DEVFREQ Driver" - depends on CPU_EXYNOS4210 || SOC_EXYNOS4212 || SOC_EXYNOS4412 + depends on (CPU_EXYNOS4210 || SOC_EXYNOS4212 || SOC_EXYNOS4412) && !ARCH_MULTIPLATFORM select ARCH_HAS_OPP select DEVFREQ_GOV_SIMPLE_ONDEMAND help diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index c10eb89a3c1bdd..605b016bcea49d 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -306,6 +306,12 @@ config DMA_OMAP select DMA_ENGINE select DMA_VIRTUAL_CHANNELS +config DMA_BCM2835 + tristate "BCM2835 DMA engine support" + depends on (ARCH_BCM2835 || MACH_BCM2708) + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + config TI_CPPI41 tristate "AM33xx CPPI41 DMA support" depends on ARCH_OMAP @@ -336,6 +342,15 @@ config K3_DMA Support the DMA engine for Hisilicon K3 platform devices. +config MOXART_DMA + tristate "MOXART DMA support" + depends on ARCH_MOXART + select DMA_ENGINE + select DMA_OF + select DMA_VIRTUAL_CHANNELS + help + Enable support for the MOXA ART SoC DMA controller. + config DMA_ENGINE bool diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 0ce2da97e42972..a029d0f4a1be80 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -38,7 +38,9 @@ obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o obj-$(CONFIG_DMA_OMAP) += omap-dma.o +obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o obj-$(CONFIG_TI_CPPI41) += cppi41.o obj-$(CONFIG_K3_DMA) += k3dma.o +obj-$(CONFIG_MOXART_DMA) += moxart-dma.o diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c index e69b03c0fa50cf..1e506afa33f5e5 100644 --- a/drivers/dma/acpi-dma.c +++ b/drivers/dma/acpi-dma.c @@ -30,11 +30,12 @@ static DEFINE_MUTEX(acpi_dma_lock); * @adev: ACPI device to match with * @adma: struct acpi_dma of the given DMA controller * - * Returns 1 on success, 0 when no information is available, or appropriate - * errno value on error. - * * In order to match a device from DSDT table to the corresponding CSRT device * we use MMIO address and IRQ. + * + * Return: + * 1 on success, 0 when no information is available, or appropriate errno value + * on error. */ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp, struct acpi_device *adev, struct acpi_dma *adma) @@ -101,7 +102,6 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp, * * We are using this table to get the request line range of the specific DMA * controller to be used later. - * */ static void acpi_dma_parse_csrt(struct acpi_device *adev, struct acpi_dma *adma) { @@ -141,10 +141,11 @@ static void acpi_dma_parse_csrt(struct acpi_device *adev, struct acpi_dma *adma) * @data pointer to controller specific data to be used by * translation function * - * Returns 0 on success or appropriate errno value on error. - * * Allocated memory should be freed with appropriate acpi_dma_controller_free() * call. + * + * Return: + * 0 on success or appropriate errno value on error. */ int acpi_dma_controller_register(struct device *dev, struct dma_chan *(*acpi_dma_xlate) @@ -188,6 +189,9 @@ EXPORT_SYMBOL_GPL(acpi_dma_controller_register); * @dev: struct device of DMA controller * * Memory allocated by acpi_dma_controller_register() is freed here. + * + * Return: + * 0 on success or appropriate errno value on error. */ int acpi_dma_controller_free(struct device *dev) { @@ -225,6 +229,9 @@ static void devm_acpi_dma_release(struct device *dev, void *res) * Managed acpi_dma_controller_register(). DMA controller registered by this * function are automatically freed on driver detach. See * acpi_dma_controller_register() for more information. + * + * Return: + * 0 on success or appropriate errno value on error. */ int devm_acpi_dma_controller_register(struct device *dev, struct dma_chan *(*acpi_dma_xlate) @@ -267,8 +274,6 @@ EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free); * @adma: struct acpi_dma of DMA controller * @dma_spec: dma specifier to update * - * Returns 0, if no information is avaiable, -1 on mismatch, and 1 otherwise. - * * Accordingly to ACPI 5.0 Specification Table 6-170 "Fixed DMA Resource * Descriptor": * DMA Request Line bits is a platform-relative number uniquely @@ -276,6 +281,9 @@ EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free); * mapping is done in a controller-specific OS driver. * That's why we can safely adjust slave_id when the appropriate controller is * found. + * + * Return: + * 0, if no information is avaiable, -1 on mismatch, and 1 otherwise. */ static int acpi_dma_update_dma_spec(struct acpi_dma *adma, struct acpi_dma_spec *dma_spec) @@ -334,7 +342,8 @@ static int acpi_dma_parse_fixed_dma(struct acpi_resource *res, void *data) * @dev: struct device to get DMA request from * @index: index of FixedDMA descriptor for @dev * - * Returns pointer to appropriate dma channel on success or NULL on error. + * Return: + * Pointer to appropriate dma channel on success or NULL on error. */ struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev, size_t index) @@ -403,7 +412,8 @@ EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_index); * translate the names "tx" and "rx" here based on the most common case where * the first FixedDMA descriptor is TX and second is RX. * - * Returns pointer to appropriate dma channel on success or NULL on error. + * Return: + * Pointer to appropriate dma channel on success or NULL on error. */ struct dma_chan *acpi_dma_request_slave_chan_by_name(struct device *dev, const char *name) @@ -427,8 +437,10 @@ EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_name); * @adma: pointer to ACPI DMA controller data * * A simple translation function for ACPI based devices. Passes &struct - * dma_spec to the DMA controller driver provided filter function. Returns - * pointer to the channel if found or %NULL otherwise. + * dma_spec to the DMA controller driver provided filter function. + * + * Return: + * Pointer to the channel if found or %NULL otherwise. */ struct dma_chan *acpi_dma_simple_xlate(struct acpi_dma_spec *dma_spec, struct acpi_dma *adma) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index ec4ee5c1fe9dc2..8114731a1c62d6 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -83,6 +83,7 @@ #include #include #include +#include #include #include #include @@ -1771,6 +1772,7 @@ bool pl08x_filter_id(struct dma_chan *chan, void *chan_id) return false; } +EXPORT_SYMBOL_GPL(pl08x_filter_id); /* * Just check that the device is there and active @@ -2167,7 +2169,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) /* Register slave channels */ ret = pl08x_dma_init_virtual_channels(pl08x, &pl08x->slave, pl08x->pd->num_slave_channels, true); - if (ret <= 0) { + if (ret < 0) { dev_warn(&pl08x->adev->dev, "%s failed to enumerate slave channels - %d\n", __func__, ret); diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c new file mode 100644 index 00000000000000..a03602164e3e1a --- /dev/null +++ b/drivers/dma/bcm2835-dma.c @@ -0,0 +1,707 @@ +/* + * BCM2835 DMA engine support + * + * This driver only supports cyclic DMA transfers + * as needed for the I2S module. + * + * Author: Florian Meier + * Copyright 2013 + * + * Based on + * OMAP DMAengine support by Russell King + * + * BCM2708 DMA Driver + * Copyright (C) 2010 Broadcom + * + * Raspberry Pi PCM I2S ALSA Driver + * Copyright (c) by Phil Poole 2013 + * + * MARVELL MMP Peripheral DMA Driver + * Copyright 2012 Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "virt-dma.h" + +struct bcm2835_dmadev { + struct dma_device ddev; + spinlock_t lock; + void __iomem *base; + struct device_dma_parameters dma_parms; +}; + +struct bcm2835_dma_cb { + uint32_t info; + uint32_t src; + uint32_t dst; + uint32_t length; + uint32_t stride; + uint32_t next; + uint32_t pad[2]; +}; + +struct bcm2835_chan { + struct virt_dma_chan vc; + struct list_head node; + + struct dma_slave_config cfg; + bool cyclic; + unsigned int dreq; + + int ch; + struct bcm2835_desc *desc; + + void __iomem *chan_base; + int irq_number; +}; + +struct bcm2835_desc { + struct virt_dma_desc vd; + enum dma_transfer_direction dir; + + unsigned int control_block_size; + struct bcm2835_dma_cb *control_block_base; + dma_addr_t control_block_base_phys; + + unsigned int frames; + size_t size; +}; + +#define BCM2835_DMA_CS 0x00 +#define BCM2835_DMA_ADDR 0x04 +#define BCM2835_DMA_SOURCE_AD 0x0c +#define BCM2835_DMA_DEST_AD 0x10 +#define BCM2835_DMA_NEXTCB 0x1C + +/* DMA CS Control and Status bits */ +#define BCM2835_DMA_ACTIVE BIT(0) +#define BCM2835_DMA_INT BIT(2) +#define BCM2835_DMA_ISPAUSED BIT(4) /* Pause requested or not active */ +#define BCM2835_DMA_ISHELD BIT(5) /* Is held by DREQ flow control */ +#define BCM2835_DMA_ERR BIT(8) +#define BCM2835_DMA_ABORT BIT(30) /* Stop current CB, go to next, WO */ +#define BCM2835_DMA_RESET BIT(31) /* WO, self clearing */ + +#define BCM2835_DMA_INT_EN BIT(0) +#define BCM2835_DMA_D_INC BIT(4) +#define BCM2835_DMA_D_DREQ BIT(6) +#define BCM2835_DMA_S_INC BIT(8) +#define BCM2835_DMA_S_DREQ BIT(10) + +#define BCM2835_DMA_PER_MAP(x) ((x) << 16) + +#define BCM2835_DMA_DATA_TYPE_S8 1 +#define BCM2835_DMA_DATA_TYPE_S16 2 +#define BCM2835_DMA_DATA_TYPE_S32 4 +#define BCM2835_DMA_DATA_TYPE_S128 16 + +#define BCM2835_DMA_BULK_MASK BIT(0) +#define BCM2835_DMA_FIQ_MASK (BIT(2) | BIT(3)) + +/* Valid only for channels 0 - 14, 15 has its own base address */ +#define BCM2835_DMA_CHAN(n) ((n) << 8) /* Base address */ +#define BCM2835_DMA_CHANIO(base, n) ((base) + BCM2835_DMA_CHAN(n)) + +static inline struct bcm2835_dmadev *to_bcm2835_dma_dev(struct dma_device *d) +{ + return container_of(d, struct bcm2835_dmadev, ddev); +} + +static inline struct bcm2835_chan *to_bcm2835_dma_chan(struct dma_chan *c) +{ + return container_of(c, struct bcm2835_chan, vc.chan); +} + +static inline struct bcm2835_desc *to_bcm2835_dma_desc( + struct dma_async_tx_descriptor *t) +{ + return container_of(t, struct bcm2835_desc, vd.tx); +} + +static void bcm2835_dma_desc_free(struct virt_dma_desc *vd) +{ + struct bcm2835_desc *desc = container_of(vd, struct bcm2835_desc, vd); + dma_free_coherent(desc->vd.tx.chan->device->dev, + desc->control_block_size, + desc->control_block_base, + desc->control_block_base_phys); + kfree(desc); +} + +static int bcm2835_dma_abort(void __iomem *chan_base) +{ + unsigned long cs; + long int timeout = 10000; + + cs = readl(chan_base + BCM2835_DMA_CS); + if (!(cs & BCM2835_DMA_ACTIVE)) + return 0; + + /* Write 0 to the active bit - Pause the DMA */ + writel(0, chan_base + BCM2835_DMA_CS); + + /* Wait for any current AXI transfer to complete */ + while ((cs & BCM2835_DMA_ISPAUSED) && --timeout) { + cpu_relax(); + cs = readl(chan_base + BCM2835_DMA_CS); + } + + /* We'll un-pause when we set of our next DMA */ + if (!timeout) + return -ETIMEDOUT; + + if (!(cs & BCM2835_DMA_ACTIVE)) + return 0; + + /* Terminate the control block chain */ + writel(0, chan_base + BCM2835_DMA_NEXTCB); + + /* Abort the whole DMA */ + writel(BCM2835_DMA_ABORT | BCM2835_DMA_ACTIVE, + chan_base + BCM2835_DMA_CS); + + return 0; +} + +static void bcm2835_dma_start_desc(struct bcm2835_chan *c) +{ + struct virt_dma_desc *vd = vchan_next_desc(&c->vc); + struct bcm2835_desc *d; + + if (!vd) { + c->desc = NULL; + return; + } + + list_del(&vd->node); + + c->desc = d = to_bcm2835_dma_desc(&vd->tx); + + writel(d->control_block_base_phys, c->chan_base + BCM2835_DMA_ADDR); + writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS); +} + +static irqreturn_t bcm2835_dma_callback(int irq, void *data) +{ + struct bcm2835_chan *c = data; + struct bcm2835_desc *d; + unsigned long flags; + + spin_lock_irqsave(&c->vc.lock, flags); + + /* Acknowledge interrupt */ + writel(BCM2835_DMA_INT, c->chan_base + BCM2835_DMA_CS); + + d = c->desc; + + if (d) { + /* TODO Only works for cyclic DMA */ + vchan_cyclic_callback(&d->vd); + } + + /* Keep the DMA engine running */ + writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS); + + spin_unlock_irqrestore(&c->vc.lock, flags); + + return IRQ_HANDLED; +} + +static int bcm2835_dma_alloc_chan_resources(struct dma_chan *chan) +{ + struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); + + dev_dbg(c->vc.chan.device->dev, + "Allocating DMA channel %d\n", c->ch); + + return request_irq(c->irq_number, + bcm2835_dma_callback, 0, "DMA IRQ", c); +} + +static void bcm2835_dma_free_chan_resources(struct dma_chan *chan) +{ + struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); + + vchan_free_chan_resources(&c->vc); + free_irq(c->irq_number, c); + + dev_dbg(c->vc.chan.device->dev, "Freeing DMA channel %u\n", c->ch); +} + +static size_t bcm2835_dma_desc_size(struct bcm2835_desc *d) +{ + return d->size; +} + +static size_t bcm2835_dma_desc_size_pos(struct bcm2835_desc *d, dma_addr_t addr) +{ + unsigned int i; + size_t size; + + for (size = i = 0; i < d->frames; i++) { + struct bcm2835_dma_cb *control_block = + &d->control_block_base[i]; + size_t this_size = control_block->length; + dma_addr_t dma; + + if (d->dir == DMA_DEV_TO_MEM) + dma = control_block->dst; + else + dma = control_block->src; + + if (size) + size += this_size; + else if (addr >= dma && addr < dma + this_size) + size += dma + this_size - addr; + } + + return size; +} + +static enum dma_status bcm2835_dma_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *txstate) +{ + struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); + struct virt_dma_desc *vd; + enum dma_status ret; + unsigned long flags; + + ret = dma_cookie_status(chan, cookie, txstate); + if (ret == DMA_COMPLETE || !txstate) + return ret; + + spin_lock_irqsave(&c->vc.lock, flags); + vd = vchan_find_desc(&c->vc, cookie); + if (vd) { + txstate->residue = + bcm2835_dma_desc_size(to_bcm2835_dma_desc(&vd->tx)); + } else if (c->desc && c->desc->vd.tx.cookie == cookie) { + struct bcm2835_desc *d = c->desc; + dma_addr_t pos; + + if (d->dir == DMA_MEM_TO_DEV) + pos = readl(c->chan_base + BCM2835_DMA_SOURCE_AD); + else if (d->dir == DMA_DEV_TO_MEM) + pos = readl(c->chan_base + BCM2835_DMA_DEST_AD); + else + pos = 0; + + txstate->residue = bcm2835_dma_desc_size_pos(d, pos); + } else { + txstate->residue = 0; + } + + spin_unlock_irqrestore(&c->vc.lock, flags); + + return ret; +} + +static void bcm2835_dma_issue_pending(struct dma_chan *chan) +{ + struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); + unsigned long flags; + + c->cyclic = true; /* Nothing else is implemented */ + + spin_lock_irqsave(&c->vc.lock, flags); + if (vchan_issue_pending(&c->vc) && !c->desc) + bcm2835_dma_start_desc(c); + + spin_unlock_irqrestore(&c->vc.lock, flags); +} + +static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( + struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, + size_t period_len, enum dma_transfer_direction direction, + unsigned long flags, void *context) +{ + struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); + enum dma_slave_buswidth dev_width; + struct bcm2835_desc *d; + dma_addr_t dev_addr; + unsigned int es, sync_type; + unsigned int frame; + + /* Grab configuration */ + if (!is_slave_direction(direction)) { + dev_err(chan->device->dev, "%s: bad direction?\n", __func__); + return NULL; + } + + if (direction == DMA_DEV_TO_MEM) { + dev_addr = c->cfg.src_addr; + dev_width = c->cfg.src_addr_width; + sync_type = BCM2835_DMA_S_DREQ; + } else { + dev_addr = c->cfg.dst_addr; + dev_width = c->cfg.dst_addr_width; + sync_type = BCM2835_DMA_D_DREQ; + } + + /* Bus width translates to the element size (ES) */ + switch (dev_width) { + case DMA_SLAVE_BUSWIDTH_4_BYTES: + es = BCM2835_DMA_DATA_TYPE_S32; + break; + default: + return NULL; + } + + /* Now allocate and setup the descriptor. */ + d = kzalloc(sizeof(*d), GFP_NOWAIT); + if (!d) + return NULL; + + d->dir = direction; + d->frames = buf_len / period_len; + + /* Allocate memory for control blocks */ + d->control_block_size = d->frames * sizeof(struct bcm2835_dma_cb); + d->control_block_base = dma_zalloc_coherent(chan->device->dev, + d->control_block_size, &d->control_block_base_phys, + GFP_NOWAIT); + + if (!d->control_block_base) { + kfree(d); + return NULL; + } + + /* + * Iterate over all frames, create a control block + * for each frame and link them together. + */ + for (frame = 0; frame < d->frames; frame++) { + struct bcm2835_dma_cb *control_block = + &d->control_block_base[frame]; + + /* Setup adresses */ + if (d->dir == DMA_DEV_TO_MEM) { + control_block->info = BCM2835_DMA_D_INC; + control_block->src = dev_addr; + control_block->dst = buf_addr + frame * period_len; + } else { + control_block->info = BCM2835_DMA_S_INC; + control_block->src = buf_addr + frame * period_len; + control_block->dst = dev_addr; + } + + /* Enable interrupt */ + control_block->info |= BCM2835_DMA_INT_EN; + + /* Setup synchronization */ + if (sync_type != 0) + control_block->info |= sync_type; + + /* Setup DREQ channel */ + if (c->dreq != 0) + control_block->info |= + BCM2835_DMA_PER_MAP(c->dreq); + + /* Length of a frame */ + control_block->length = period_len; + d->size += control_block->length; + + /* + * Next block is the next frame. + * This DMA engine driver currently only supports cyclic DMA. + * Therefore, wrap around at number of frames. + */ + control_block->next = d->control_block_base_phys + + sizeof(struct bcm2835_dma_cb) + * ((frame + 1) % d->frames); + } + + return vchan_tx_prep(&c->vc, &d->vd, flags); +} + +static int bcm2835_dma_slave_config(struct bcm2835_chan *c, + struct dma_slave_config *cfg) +{ + if ((cfg->direction == DMA_DEV_TO_MEM && + cfg->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) || + (cfg->direction == DMA_MEM_TO_DEV && + cfg->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) || + !is_slave_direction(cfg->direction)) { + return -EINVAL; + } + + c->cfg = *cfg; + + return 0; +} + +static int bcm2835_dma_terminate_all(struct bcm2835_chan *c) +{ + struct bcm2835_dmadev *d = to_bcm2835_dma_dev(c->vc.chan.device); + unsigned long flags; + int timeout = 10000; + LIST_HEAD(head); + + spin_lock_irqsave(&c->vc.lock, flags); + + /* Prevent this channel being scheduled */ + spin_lock(&d->lock); + list_del_init(&c->node); + spin_unlock(&d->lock); + + /* + * Stop DMA activity: we assume the callback will not be called + * after bcm_dma_abort() returns (even if it does, it will see + * c->desc is NULL and exit.) + */ + if (c->desc) { + c->desc = NULL; + bcm2835_dma_abort(c->chan_base); + + /* Wait for stopping */ + while (--timeout) { + if (!(readl(c->chan_base + BCM2835_DMA_CS) & + BCM2835_DMA_ACTIVE)) + break; + + cpu_relax(); + } + + if (!timeout) + dev_err(d->ddev.dev, "DMA transfer could not be terminated\n"); + } + + vchan_get_all_descriptors(&c->vc, &head); + spin_unlock_irqrestore(&c->vc.lock, flags); + vchan_dma_desc_free_list(&c->vc, &head); + + return 0; +} + +static int bcm2835_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) +{ + struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); + + switch (cmd) { + case DMA_SLAVE_CONFIG: + return bcm2835_dma_slave_config(c, + (struct dma_slave_config *)arg); + + case DMA_TERMINATE_ALL: + return bcm2835_dma_terminate_all(c); + + default: + return -ENXIO; + } +} + +static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq) +{ + struct bcm2835_chan *c; + + c = devm_kzalloc(d->ddev.dev, sizeof(*c), GFP_KERNEL); + if (!c) + return -ENOMEM; + + c->vc.desc_free = bcm2835_dma_desc_free; + vchan_init(&c->vc, &d->ddev); + INIT_LIST_HEAD(&c->node); + + d->ddev.chancnt++; + + c->chan_base = BCM2835_DMA_CHANIO(d->base, chan_id); + c->ch = chan_id; + c->irq_number = irq; + + return 0; +} + +static void bcm2835_dma_free(struct bcm2835_dmadev *od) +{ + struct bcm2835_chan *c, *next; + + list_for_each_entry_safe(c, next, &od->ddev.channels, + vc.chan.device_node) { + list_del(&c->vc.chan.device_node); + tasklet_kill(&c->vc.task); + } +} + +static const struct of_device_id bcm2835_dma_of_match[] = { + { .compatible = "brcm,bcm2835-dma", }, + {}, +}; +MODULE_DEVICE_TABLE(of, bcm2835_dma_of_match); + +static struct dma_chan *bcm2835_dma_xlate(struct of_phandle_args *spec, + struct of_dma *ofdma) +{ + struct bcm2835_dmadev *d = ofdma->of_dma_data; + struct dma_chan *chan; + + chan = dma_get_any_slave_channel(&d->ddev); + if (!chan) + return NULL; + + /* Set DREQ from param */ + to_bcm2835_dma_chan(chan)->dreq = spec->args[0]; + + return chan; +} + +static int bcm2835_dma_device_slave_caps(struct dma_chan *dchan, + struct dma_slave_caps *caps) +{ + caps->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); + caps->dstn_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); + caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + caps->cmd_pause = false; + caps->cmd_terminate = true; + + return 0; +} + +static int bcm2835_dma_probe(struct platform_device *pdev) +{ + struct bcm2835_dmadev *od; + struct resource *res; + void __iomem *base; + int rc; + int i; + int irq; + uint32_t chans_available; + + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (rc) + return rc; + + od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL); + if (!od) + return -ENOMEM; + + pdev->dev.dma_parms = &od->dma_parms; + dma_set_max_seg_size(&pdev->dev, 0x3FFFFFFF); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + od->base = base; + + dma_cap_set(DMA_SLAVE, od->ddev.cap_mask); + dma_cap_set(DMA_PRIVATE, od->ddev.cap_mask); + dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask); + od->ddev.device_alloc_chan_resources = bcm2835_dma_alloc_chan_resources; + od->ddev.device_free_chan_resources = bcm2835_dma_free_chan_resources; + od->ddev.device_tx_status = bcm2835_dma_tx_status; + od->ddev.device_issue_pending = bcm2835_dma_issue_pending; + od->ddev.device_slave_caps = bcm2835_dma_device_slave_caps; + od->ddev.device_prep_dma_cyclic = bcm2835_dma_prep_dma_cyclic; + od->ddev.device_control = bcm2835_dma_control; + od->ddev.dev = &pdev->dev; + INIT_LIST_HEAD(&od->ddev.channels); + spin_lock_init(&od->lock); + + platform_set_drvdata(pdev, od); + + /* Request DMA channel mask from device tree */ + if (of_property_read_u32(pdev->dev.of_node, + "brcm,dma-channel-mask", + &chans_available)) { + dev_err(&pdev->dev, "Failed to get channel mask\n"); + rc = -EINVAL; + goto err_no_dma; + } + + /* + * Do not use the FIQ and BULK channels, + * because they are used by the GPU. + */ + chans_available &= ~(BCM2835_DMA_FIQ_MASK | BCM2835_DMA_BULK_MASK); + + for (i = 0; i < pdev->num_resources; i++) { + irq = platform_get_irq(pdev, i); + if (irq < 0) + break; + + if (chans_available & (1 << i)) { + rc = bcm2835_dma_chan_init(od, i, irq); + if (rc) + goto err_no_dma; + } + } + + dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", i); + + /* Device-tree DMA controller registration */ + rc = of_dma_controller_register(pdev->dev.of_node, + bcm2835_dma_xlate, od); + if (rc) { + dev_err(&pdev->dev, "Failed to register DMA controller\n"); + goto err_no_dma; + } + + rc = dma_async_device_register(&od->ddev); + if (rc) { + dev_err(&pdev->dev, + "Failed to register slave DMA engine device: %d\n", rc); + goto err_no_dma; + } + + dev_dbg(&pdev->dev, "Load BCM2835 DMA engine driver\n"); + + return 0; + +err_no_dma: + bcm2835_dma_free(od); + return rc; +} + +static int bcm2835_dma_remove(struct platform_device *pdev) +{ + struct bcm2835_dmadev *od = platform_get_drvdata(pdev); + + dma_async_device_unregister(&od->ddev); + bcm2835_dma_free(od); + + return 0; +} + +static struct platform_driver bcm2835_dma_driver = { + .probe = bcm2835_dma_probe, + .remove = bcm2835_dma_remove, + .driver = { + .name = "bcm2835-dma", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(bcm2835_dma_of_match), + }, +}; + +module_platform_driver(bcm2835_dma_driver); + +MODULE_ALIAS("platform:bcm2835-dma"); +MODULE_DESCRIPTION("BCM2835 DMA engine driver"); +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c index c29dacff66fa95..c18aebf7d5aa9a 100644 --- a/drivers/dma/cppi41.c +++ b/drivers/dma/cppi41.c @@ -972,8 +972,10 @@ static int cppi41_dma_probe(struct platform_device *pdev) goto err_chans; irq = irq_of_parse_and_map(dev->of_node, 0); - if (!irq) + if (!irq) { + ret = -EINVAL; goto err_irq; + } cppi_writel(USBSS_IRQ_PD_COMP, cdd->usbss_mem + USBSS_IRQ_ENABLER); diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 9dfcaf5c12888d..05b6dea770a407 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -31,7 +31,7 @@ module_param_string(channel, test_channel, sizeof(test_channel), S_IRUGO | S_IWUSR); MODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)"); -static char test_device[20]; +static char test_device[32]; module_param_string(device, test_device, sizeof(test_device), S_IRUGO | S_IWUSR); MODULE_PARM_DESC(device, "Bus ID of the DMA Engine to test (default: any)"); @@ -89,7 +89,7 @@ MODULE_PARM_DESC(verbose, "Enable \"success\" result messages (default: off)"); struct dmatest_params { unsigned int buf_size; char channel[20]; - char device[20]; + char device[32]; unsigned int threads_per_chan; unsigned int max_channels; unsigned int iterations; diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 7516be4677cf7e..13ac3f240e7963 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -218,8 +218,10 @@ static inline void dwc_do_single_block(struct dw_dma_chan *dwc, struct dw_dma *dw = to_dw_dma(dwc->chan.device); u32 ctllo; - /* Software emulation of LLP mode relies on interrupts to continue - * multi block transfer. */ + /* + * Software emulation of LLP mode relies on interrupts to continue + * multi block transfer. + */ ctllo = desc->lli.ctllo | DWC_CTLL_INT_EN; channel_writel(dwc, SAR, desc->lli.sar); @@ -253,8 +255,7 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first) &dwc->flags); if (was_soft_llp) { dev_err(chan2dev(&dwc->chan), - "BUG: Attempted to start new LLP transfer " - "inside ongoing one\n"); + "BUG: Attempted to start new LLP transfer inside ongoing one\n"); return; } @@ -420,8 +421,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc) return; } - dev_vdbg(chan2dev(&dwc->chan), "%s: llp=0x%llx\n", __func__, - (unsigned long long)llp); + dev_vdbg(chan2dev(&dwc->chan), "%s: llp=%pad\n", __func__, &llp); list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) { /* Initial residue value */ @@ -567,9 +567,9 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc, unlikely(status_xfer & dwc->mask)) { int i; - dev_err(chan2dev(&dwc->chan), "cyclic DMA unexpected %s " - "interrupt, stopping DMA transfer\n", - status_xfer ? "xfer" : "error"); + dev_err(chan2dev(&dwc->chan), + "cyclic DMA unexpected %s interrupt, stopping DMA transfer\n", + status_xfer ? "xfer" : "error"); spin_lock_irqsave(&dwc->lock, flags); @@ -711,9 +711,8 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, u32 ctllo; dev_vdbg(chan2dev(chan), - "%s: d0x%llx s0x%llx l0x%zx f0x%lx\n", __func__, - (unsigned long long)dest, (unsigned long long)src, - len, flags); + "%s: d%pad s%pad l0x%zx f0x%lx\n", __func__, + &dest, &src, len, flags); if (unlikely(!len)) { dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__); @@ -1401,9 +1400,9 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, /* Let's make a cyclic list */ last->lli.llp = cdesc->desc[0]->txd.phys; - dev_dbg(chan2dev(&dwc->chan), "cyclic prepared buf 0x%llx len %zu " - "period %zu periods %d\n", (unsigned long long)buf_addr, - buf_len, period_len, periods); + dev_dbg(chan2dev(&dwc->chan), + "cyclic prepared buf %pad len %zu period %zu periods %d\n", + &buf_addr, buf_len, period_len, periods); cdesc->periods = periods; dwc->cdesc = cdesc; @@ -1603,9 +1602,11 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata) dev_dbg(chip->dev, "DWC_PARAMS[%d]: 0x%08x\n", i, dwc_params); - /* Decode maximum block size for given channel. The + /* + * Decode maximum block size for given channel. The * stored 4 bit value represents blocks from 0x00 for 3 - * up to 0x0a for 4095. */ + * up to 0x0a for 4095. + */ dwc->block_size = (4 << ((max_blk_size >> 4 * i) & 0xf)) - 1; dwc->nollp = diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index 2539ea0cbc6394..cd8da451d1995f 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -699,8 +699,8 @@ static int edma_alloc_chan_resources(struct dma_chan *chan) echan->alloced = true; echan->slot[0] = echan->ch_num; - dev_info(dev, "allocated channel for %u:%u\n", - EDMA_CTLR(echan->ch_num), EDMA_CHAN_SLOT(echan->ch_num)); + dev_dbg(dev, "allocated channel for %u:%u\n", + EDMA_CTLR(echan->ch_num), EDMA_CHAN_SLOT(echan->ch_num)); return 0; @@ -736,7 +736,7 @@ static void edma_free_chan_resources(struct dma_chan *chan) echan->alloced = false; } - dev_info(dev, "freeing channel for %u\n", echan->ch_num); + dev_dbg(dev, "freeing channel for %u\n", echan->ch_num); } /* Send pending descriptor to hardware */ diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h index 1ffc24484d23cd..d56e83599825b1 100644 --- a/drivers/dma/fsldma.h +++ b/drivers/dma/fsldma.h @@ -41,7 +41,7 @@ * channel is allowed to transfer before the DMA engine pauses * the current channel and switches to the next channel */ -#define FSL_DMA_MR_BWC 0x08000000 +#define FSL_DMA_MR_BWC 0x0A000000 /* Special MR definition for MPC8349 */ #define FSL_DMA_MR_EOTIE 0x00000080 diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index c75679d420286c..4e7918339b1263 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -323,6 +323,7 @@ struct sdma_engine { struct clk *clk_ipg; struct clk *clk_ahb; spinlock_t channel_0_lock; + u32 script_number; struct sdma_script_start_addrs *script_addrs; const struct sdma_driver_data *drvdata; }; @@ -724,6 +725,10 @@ static void sdma_get_pc(struct sdma_channel *sdmac, per_2_emi = sdma->script_addrs->app_2_mcu_addr; emi_2_per = sdma->script_addrs->mcu_2_app_addr; break; + case IMX_DMATYPE_SSI_DUAL: + per_2_emi = sdma->script_addrs->ssish_2_mcu_addr; + emi_2_per = sdma->script_addrs->mcu_2_ssish_addr; + break; case IMX_DMATYPE_SSI_SP: case IMX_DMATYPE_MMC: case IMX_DMATYPE_SDHC: @@ -1238,6 +1243,7 @@ static void sdma_issue_pending(struct dma_chan *chan) } #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34 +#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2 38 static void sdma_add_scripts(struct sdma_engine *sdma, const struct sdma_script_start_addrs *addr) @@ -1246,7 +1252,11 @@ static void sdma_add_scripts(struct sdma_engine *sdma, s32 *saddr_arr = (u32 *)sdma->script_addrs; int i; - for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++) + /* use the default firmware in ROM if missing external firmware */ + if (!sdma->script_number) + sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; + + for (i = 0; i < sdma->script_number; i++) if (addr_arr[i] > 0) saddr_arr[i] = addr_arr[i]; } @@ -1272,6 +1282,17 @@ static void sdma_load_firmware(const struct firmware *fw, void *context) goto err_firmware; if (header->ram_code_start + header->ram_code_size > fw->size) goto err_firmware; + switch (header->version_major) { + case 1: + sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; + break; + case 2: + sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2; + break; + default: + dev_err(sdma->dev, "unknown firmware version\n"); + goto err_firmware; + } addr = (void *)header + header->script_addrs_start; ram_code = (void *)header + header->ram_code_start; diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index e26075408e9b95..a1f911aaf220e0 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -477,7 +477,7 @@ static struct dma_async_tx_descriptor *k3_dma_prep_slave_sg( dma_addr_t addr, src = 0, dst = 0; int num = sglen, i; - if (sgl == 0) + if (sgl == NULL) return NULL; for_each_sg(sgl, sg, sglen, i) { @@ -817,7 +817,7 @@ static int k3_dma_resume(struct device *dev) return 0; } -SIMPLE_DEV_PM_OPS(k3_dma_pmops, k3_dma_suspend, k3_dma_resume); +static SIMPLE_DEV_PM_OPS(k3_dma_pmops, k3_dma_suspend, k3_dma_resume); static struct platform_driver k3_pdma_driver = { .driver = { diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index c6a01ea8bc591c..b439679f4126e9 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -5,6 +5,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + #include #include #include @@ -32,38 +33,37 @@ #define DTADR 0x0208 #define DCMD 0x020c -#define DCSR_RUN (1 << 31) /* Run Bit (read / write) */ -#define DCSR_NODESC (1 << 30) /* No-Descriptor Fetch (read / write) */ -#define DCSR_STOPIRQEN (1 << 29) /* Stop Interrupt Enable (read / write) */ -#define DCSR_REQPEND (1 << 8) /* Request Pending (read-only) */ -#define DCSR_STOPSTATE (1 << 3) /* Stop State (read-only) */ -#define DCSR_ENDINTR (1 << 2) /* End Interrupt (read / write) */ -#define DCSR_STARTINTR (1 << 1) /* Start Interrupt (read / write) */ -#define DCSR_BUSERR (1 << 0) /* Bus Error Interrupt (read / write) */ - -#define DCSR_EORIRQEN (1 << 28) /* End of Receive Interrupt Enable (R/W) */ -#define DCSR_EORJMPEN (1 << 27) /* Jump to next descriptor on EOR */ -#define DCSR_EORSTOPEN (1 << 26) /* STOP on an EOR */ -#define DCSR_SETCMPST (1 << 25) /* Set Descriptor Compare Status */ -#define DCSR_CLRCMPST (1 << 24) /* Clear Descriptor Compare Status */ -#define DCSR_CMPST (1 << 10) /* The Descriptor Compare Status */ -#define DCSR_EORINTR (1 << 9) /* The end of Receive */ - -#define DRCMR(n) ((((n) < 64) ? 0x0100 : 0x1100) + \ - (((n) & 0x3f) << 2)) -#define DRCMR_MAPVLD (1 << 7) /* Map Valid (read / write) */ -#define DRCMR_CHLNUM 0x1f /* mask for Channel Number (read / write) */ +#define DCSR_RUN BIT(31) /* Run Bit (read / write) */ +#define DCSR_NODESC BIT(30) /* No-Descriptor Fetch (read / write) */ +#define DCSR_STOPIRQEN BIT(29) /* Stop Interrupt Enable (read / write) */ +#define DCSR_REQPEND BIT(8) /* Request Pending (read-only) */ +#define DCSR_STOPSTATE BIT(3) /* Stop State (read-only) */ +#define DCSR_ENDINTR BIT(2) /* End Interrupt (read / write) */ +#define DCSR_STARTINTR BIT(1) /* Start Interrupt (read / write) */ +#define DCSR_BUSERR BIT(0) /* Bus Error Interrupt (read / write) */ + +#define DCSR_EORIRQEN BIT(28) /* End of Receive Interrupt Enable (R/W) */ +#define DCSR_EORJMPEN BIT(27) /* Jump to next descriptor on EOR */ +#define DCSR_EORSTOPEN BIT(26) /* STOP on an EOR */ +#define DCSR_SETCMPST BIT(25) /* Set Descriptor Compare Status */ +#define DCSR_CLRCMPST BIT(24) /* Clear Descriptor Compare Status */ +#define DCSR_CMPST BIT(10) /* The Descriptor Compare Status */ +#define DCSR_EORINTR BIT(9) /* The end of Receive */ + +#define DRCMR(n) ((((n) < 64) ? 0x0100 : 0x1100) + (((n) & 0x3f) << 2)) +#define DRCMR_MAPVLD BIT(7) /* Map Valid (read / write) */ +#define DRCMR_CHLNUM 0x1f /* mask for Channel Number (read / write) */ #define DDADR_DESCADDR 0xfffffff0 /* Address of next descriptor (mask) */ -#define DDADR_STOP (1 << 0) /* Stop (read / write) */ - -#define DCMD_INCSRCADDR (1 << 31) /* Source Address Increment Setting. */ -#define DCMD_INCTRGADDR (1 << 30) /* Target Address Increment Setting. */ -#define DCMD_FLOWSRC (1 << 29) /* Flow Control by the source. */ -#define DCMD_FLOWTRG (1 << 28) /* Flow Control by the target. */ -#define DCMD_STARTIRQEN (1 << 22) /* Start Interrupt Enable */ -#define DCMD_ENDIRQEN (1 << 21) /* End Interrupt Enable */ -#define DCMD_ENDIAN (1 << 18) /* Device Endian-ness. */ +#define DDADR_STOP BIT(0) /* Stop (read / write) */ + +#define DCMD_INCSRCADDR BIT(31) /* Source Address Increment Setting. */ +#define DCMD_INCTRGADDR BIT(30) /* Target Address Increment Setting. */ +#define DCMD_FLOWSRC BIT(29) /* Flow Control by the source. */ +#define DCMD_FLOWTRG BIT(28) /* Flow Control by the target. */ +#define DCMD_STARTIRQEN BIT(22) /* Start Interrupt Enable */ +#define DCMD_ENDIRQEN BIT(21) /* End Interrupt Enable */ +#define DCMD_ENDIAN BIT(18) /* Device Endian-ness. */ #define DCMD_BURST8 (1 << 16) /* 8 byte burst */ #define DCMD_BURST16 (2 << 16) /* 16 byte burst */ #define DCMD_BURST32 (3 << 16) /* 32 byte burst */ @@ -132,10 +132,14 @@ struct mmp_pdma_device { spinlock_t phy_lock; /* protect alloc/free phy channels */ }; -#define tx_to_mmp_pdma_desc(tx) container_of(tx, struct mmp_pdma_desc_sw, async_tx) -#define to_mmp_pdma_desc(lh) container_of(lh, struct mmp_pdma_desc_sw, node) -#define to_mmp_pdma_chan(dchan) container_of(dchan, struct mmp_pdma_chan, chan) -#define to_mmp_pdma_dev(dmadev) container_of(dmadev, struct mmp_pdma_device, device) +#define tx_to_mmp_pdma_desc(tx) \ + container_of(tx, struct mmp_pdma_desc_sw, async_tx) +#define to_mmp_pdma_desc(lh) \ + container_of(lh, struct mmp_pdma_desc_sw, node) +#define to_mmp_pdma_chan(dchan) \ + container_of(dchan, struct mmp_pdma_chan, chan) +#define to_mmp_pdma_dev(dmadev) \ + container_of(dmadev, struct mmp_pdma_device, device) static void set_desc(struct mmp_pdma_phy *phy, dma_addr_t addr) { @@ -162,19 +166,18 @@ static void enable_chan(struct mmp_pdma_phy *phy) writel(dalgn, phy->base + DALGN); reg = (phy->idx << 2) + DCSR; - writel(readl(phy->base + reg) | DCSR_RUN, - phy->base + reg); + writel(readl(phy->base + reg) | DCSR_RUN, phy->base + reg); } static void disable_chan(struct mmp_pdma_phy *phy) { u32 reg; - if (phy) { - reg = (phy->idx << 2) + DCSR; - writel(readl(phy->base + reg) & ~DCSR_RUN, - phy->base + reg); - } + if (!phy) + return; + + reg = (phy->idx << 2) + DCSR; + writel(readl(phy->base + reg) & ~DCSR_RUN, phy->base + reg); } static int clear_chan_irq(struct mmp_pdma_phy *phy) @@ -183,26 +186,27 @@ static int clear_chan_irq(struct mmp_pdma_phy *phy) u32 dint = readl(phy->base + DINT); u32 reg = (phy->idx << 2) + DCSR; - if (dint & BIT(phy->idx)) { - /* clear irq */ - dcsr = readl(phy->base + reg); - writel(dcsr, phy->base + reg); - if ((dcsr & DCSR_BUSERR) && (phy->vchan)) - dev_warn(phy->vchan->dev, "DCSR_BUSERR\n"); - return 0; - } - return -EAGAIN; + if (!(dint & BIT(phy->idx))) + return -EAGAIN; + + /* clear irq */ + dcsr = readl(phy->base + reg); + writel(dcsr, phy->base + reg); + if ((dcsr & DCSR_BUSERR) && (phy->vchan)) + dev_warn(phy->vchan->dev, "DCSR_BUSERR\n"); + + return 0; } static irqreturn_t mmp_pdma_chan_handler(int irq, void *dev_id) { struct mmp_pdma_phy *phy = dev_id; - if (clear_chan_irq(phy) == 0) { - tasklet_schedule(&phy->vchan->tasklet); - return IRQ_HANDLED; - } else + if (clear_chan_irq(phy) != 0) return IRQ_NONE; + + tasklet_schedule(&phy->vchan->tasklet); + return IRQ_HANDLED; } static irqreturn_t mmp_pdma_int_handler(int irq, void *dev_id) @@ -224,8 +228,8 @@ static irqreturn_t mmp_pdma_int_handler(int irq, void *dev_id) if (irq_num) return IRQ_HANDLED; - else - return IRQ_NONE; + + return IRQ_NONE; } /* lookup free phy channel as descending priority */ @@ -245,9 +249,9 @@ static struct mmp_pdma_phy *lookup_phy(struct mmp_pdma_chan *pchan) */ spin_lock_irqsave(&pdev->phy_lock, flags); - for (prio = 0; prio <= (((pdev->dma_channels - 1) & 0xf) >> 2); prio++) { + for (prio = 0; prio <= ((pdev->dma_channels - 1) & 0xf) >> 2; prio++) { for (i = 0; i < pdev->dma_channels; i++) { - if (prio != ((i & 0xf) >> 2)) + if (prio != (i & 0xf) >> 2) continue; phy = &pdev->phy[i]; if (!phy->vchan) { @@ -389,14 +393,16 @@ static int mmp_pdma_alloc_chan_resources(struct dma_chan *dchan) if (chan->desc_pool) return 1; - chan->desc_pool = - dma_pool_create(dev_name(&dchan->dev->device), chan->dev, - sizeof(struct mmp_pdma_desc_sw), - __alignof__(struct mmp_pdma_desc_sw), 0); + chan->desc_pool = dma_pool_create(dev_name(&dchan->dev->device), + chan->dev, + sizeof(struct mmp_pdma_desc_sw), + __alignof__(struct mmp_pdma_desc_sw), + 0); if (!chan->desc_pool) { dev_err(chan->dev, "unable to allocate descriptor pool\n"); return -ENOMEM; } + mmp_pdma_free_phy(chan); chan->idle = true; chan->dev_addr = 0; @@ -404,7 +410,7 @@ static int mmp_pdma_alloc_chan_resources(struct dma_chan *dchan) } static void mmp_pdma_free_desc_list(struct mmp_pdma_chan *chan, - struct list_head *list) + struct list_head *list) { struct mmp_pdma_desc_sw *desc, *_desc; @@ -434,8 +440,8 @@ static void mmp_pdma_free_chan_resources(struct dma_chan *dchan) static struct dma_async_tx_descriptor * mmp_pdma_prep_memcpy(struct dma_chan *dchan, - dma_addr_t dma_dst, dma_addr_t dma_src, - size_t len, unsigned long flags) + dma_addr_t dma_dst, dma_addr_t dma_src, + size_t len, unsigned long flags) { struct mmp_pdma_chan *chan; struct mmp_pdma_desc_sw *first = NULL, *prev = NULL, *new; @@ -515,8 +521,8 @@ mmp_pdma_prep_memcpy(struct dma_chan *dchan, static struct dma_async_tx_descriptor * mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_transfer_direction dir, - unsigned long flags, void *context) + unsigned int sg_len, enum dma_transfer_direction dir, + unsigned long flags, void *context) { struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan); struct mmp_pdma_desc_sw *first = NULL, *prev = NULL, *new = NULL; @@ -591,10 +597,11 @@ mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl, return NULL; } -static struct dma_async_tx_descriptor *mmp_pdma_prep_dma_cyclic( - struct dma_chan *dchan, dma_addr_t buf_addr, size_t len, - size_t period_len, enum dma_transfer_direction direction, - unsigned long flags, void *context) +static struct dma_async_tx_descriptor * +mmp_pdma_prep_dma_cyclic(struct dma_chan *dchan, + dma_addr_t buf_addr, size_t len, size_t period_len, + enum dma_transfer_direction direction, + unsigned long flags, void *context) { struct mmp_pdma_chan *chan; struct mmp_pdma_desc_sw *first = NULL, *prev = NULL, *new; @@ -636,8 +643,8 @@ static struct dma_async_tx_descriptor *mmp_pdma_prep_dma_cyclic( goto fail; } - new->desc.dcmd = chan->dcmd | DCMD_ENDIRQEN | - (DCMD_LENGTH & period_len); + new->desc.dcmd = (chan->dcmd | DCMD_ENDIRQEN | + (DCMD_LENGTH & period_len)); new->desc.dsadr = dma_src; new->desc.dtadr = dma_dst; @@ -677,12 +684,11 @@ static struct dma_async_tx_descriptor *mmp_pdma_prep_dma_cyclic( } static int mmp_pdma_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd, - unsigned long arg) + unsigned long arg) { struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan); struct dma_slave_config *cfg = (void *)arg; unsigned long flags; - int ret = 0; u32 maxburst = 0, addr = 0; enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED; @@ -739,11 +745,12 @@ static int mmp_pdma_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd, return -ENOSYS; } - return ret; + return 0; } static enum dma_status mmp_pdma_tx_status(struct dma_chan *dchan, - dma_cookie_t cookie, struct dma_tx_state *txstate) + dma_cookie_t cookie, + struct dma_tx_state *txstate) { return dma_cookie_status(dchan, cookie, txstate); } @@ -845,15 +852,14 @@ static int mmp_pdma_remove(struct platform_device *op) return 0; } -static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev, - int idx, int irq) +static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev, int idx, int irq) { struct mmp_pdma_phy *phy = &pdev->phy[idx]; struct mmp_pdma_chan *chan; int ret; - chan = devm_kzalloc(pdev->dev, - sizeof(struct mmp_pdma_chan), GFP_KERNEL); + chan = devm_kzalloc(pdev->dev, sizeof(struct mmp_pdma_chan), + GFP_KERNEL); if (chan == NULL) return -ENOMEM; @@ -861,8 +867,8 @@ static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev, phy->base = pdev->base; if (irq) { - ret = devm_request_irq(pdev->dev, irq, - mmp_pdma_chan_handler, 0, "pdma", phy); + ret = devm_request_irq(pdev->dev, irq, mmp_pdma_chan_handler, 0, + "pdma", phy); if (ret) { dev_err(pdev->dev, "channel request irq fail!\n"); return ret; @@ -877,8 +883,7 @@ static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev, INIT_LIST_HEAD(&chan->chain_running); /* register virt channel to dma engine */ - list_add_tail(&chan->chan.device_node, - &pdev->device.channels); + list_add_tail(&chan->chan.device_node, &pdev->device.channels); return 0; } @@ -894,14 +899,12 @@ static struct dma_chan *mmp_pdma_dma_xlate(struct of_phandle_args *dma_spec, { struct mmp_pdma_device *d = ofdma->of_dma_data; struct dma_chan *chan; - struct mmp_pdma_chan *c; chan = dma_get_any_slave_channel(&d->device); if (!chan) return NULL; - c = to_mmp_pdma_chan(chan); - c->drcmr = dma_spec->args[0]; + to_mmp_pdma_chan(chan)->drcmr = dma_spec->args[0]; return chan; } @@ -918,6 +921,7 @@ static int mmp_pdma_probe(struct platform_device *op) pdev = devm_kzalloc(&op->dev, sizeof(*pdev), GFP_KERNEL); if (!pdev) return -ENOMEM; + pdev->dev = &op->dev; spin_lock_init(&pdev->phy_lock); @@ -929,8 +933,8 @@ static int mmp_pdma_probe(struct platform_device *op) of_id = of_match_device(mmp_pdma_dt_ids, pdev->dev); if (of_id) - of_property_read_u32(pdev->dev->of_node, - "#dma-channels", &dma_channels); + of_property_read_u32(pdev->dev->of_node, "#dma-channels", + &dma_channels); else if (pdata && pdata->dma_channels) dma_channels = pdata->dma_channels; else @@ -942,8 +946,9 @@ static int mmp_pdma_probe(struct platform_device *op) irq_num++; } - pdev->phy = devm_kzalloc(pdev->dev, - dma_channels * sizeof(struct mmp_pdma_chan), GFP_KERNEL); + pdev->phy = devm_kcalloc(pdev->dev, + dma_channels, sizeof(struct mmp_pdma_chan), + GFP_KERNEL); if (pdev->phy == NULL) return -ENOMEM; @@ -952,8 +957,8 @@ static int mmp_pdma_probe(struct platform_device *op) if (irq_num != dma_channels) { /* all chan share one irq, demux inside */ irq = platform_get_irq(op, 0); - ret = devm_request_irq(pdev->dev, irq, - mmp_pdma_int_handler, 0, "pdma", pdev); + ret = devm_request_irq(pdev->dev, irq, mmp_pdma_int_handler, 0, + "pdma", pdev); if (ret) return ret; } @@ -1029,7 +1034,7 @@ bool mmp_pdma_filter_fn(struct dma_chan *chan, void *param) if (chan->device->dev->driver != &mmp_pdma_driver.driver) return false; - c->drcmr = *(unsigned int *) param; + c->drcmr = *(unsigned int *)param; return true; } @@ -1037,6 +1042,6 @@ EXPORT_SYMBOL_GPL(mmp_pdma_filter_fn); module_platform_driver(mmp_pdma_driver); -MODULE_DESCRIPTION("MARVELL MMP Periphera DMA Driver"); +MODULE_DESCRIPTION("MARVELL MMP Peripheral DMA Driver"); MODULE_AUTHOR("Marvell International Ltd."); MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c index 3ddacc14a73666..33f96aaa80c759 100644 --- a/drivers/dma/mmp_tdma.c +++ b/drivers/dma/mmp_tdma.c @@ -121,11 +121,13 @@ struct mmp_tdma_chan { int idx; enum mmp_tdma_type type; int irq; - unsigned long reg_base; + void __iomem *reg_base; size_t buf_len; size_t period_len; size_t pos; + + struct gen_pool *pool; }; #define TDMA_CHANNEL_NUM 2 @@ -182,7 +184,7 @@ static void mmp_tdma_pause_chan(struct mmp_tdma_chan *tdmac) static int mmp_tdma_config_chan(struct mmp_tdma_chan *tdmac) { - unsigned int tdcr; + unsigned int tdcr = 0; mmp_tdma_disable_chan(tdmac); @@ -324,7 +326,7 @@ static void mmp_tdma_free_descriptor(struct mmp_tdma_chan *tdmac) struct gen_pool *gpool; int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc); - gpool = sram_get_gpool("asram"); + gpool = tdmac->pool; if (tdmac->desc_arr) gen_pool_free(gpool, (unsigned long)tdmac->desc_arr, size); @@ -374,7 +376,7 @@ struct mmp_tdma_desc *mmp_tdma_alloc_descriptor(struct mmp_tdma_chan *tdmac) struct gen_pool *gpool; int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc); - gpool = sram_get_gpool("asram"); + gpool = tdmac->pool; if (!gpool) return NULL; @@ -505,7 +507,8 @@ static int mmp_tdma_remove(struct platform_device *pdev) } static int mmp_tdma_chan_init(struct mmp_tdma_device *tdev, - int idx, int irq, int type) + int idx, int irq, + int type, struct gen_pool *pool) { struct mmp_tdma_chan *tdmac; @@ -526,7 +529,8 @@ static int mmp_tdma_chan_init(struct mmp_tdma_device *tdev, tdmac->chan.device = &tdev->device; tdmac->idx = idx; tdmac->type = type; - tdmac->reg_base = (unsigned long)tdev->base + idx * 4; + tdmac->reg_base = tdev->base + idx * 4; + tdmac->pool = pool; tdmac->status = DMA_COMPLETE; tdev->tdmac[tdmac->idx] = tdmac; tasklet_init(&tdmac->tasklet, dma_do_tasklet, (unsigned long)tdmac); @@ -553,6 +557,7 @@ static int mmp_tdma_probe(struct platform_device *pdev) int i, ret; int irq = 0, irq_num = 0; int chan_num = TDMA_CHANNEL_NUM; + struct gen_pool *pool; of_id = of_match_device(mmp_tdma_dt_ids, &pdev->dev); if (of_id) @@ -579,6 +584,15 @@ static int mmp_tdma_probe(struct platform_device *pdev) INIT_LIST_HEAD(&tdev->device.channels); + if (pdev->dev.of_node) + pool = of_get_named_gen_pool(pdev->dev.of_node, "asram", 0); + else + pool = sram_get_gpool("asram"); + if (!pool) { + dev_err(&pdev->dev, "asram pool not available\n"); + return -ENOMEM; + } + if (irq_num != chan_num) { irq = platform_get_irq(pdev, 0); ret = devm_request_irq(&pdev->dev, irq, @@ -590,7 +604,7 @@ static int mmp_tdma_probe(struct platform_device *pdev) /* initialize channel parameters */ for (i = 0; i < chan_num; i++) { irq = (irq_num != chan_num) ? 0 : platform_get_irq(pdev, i); - ret = mmp_tdma_chan_init(tdev, i, irq, type); + ret = mmp_tdma_chan_init(tdev, i, irq, type, pool); if (ret) return ret; } diff --git a/drivers/dma/moxart-dma.c b/drivers/dma/moxart-dma.c new file mode 100644 index 00000000000000..3258e484e4f647 --- /dev/null +++ b/drivers/dma/moxart-dma.c @@ -0,0 +1,699 @@ +/* + * MOXA ART SoCs DMA Engine support. + * + * Copyright (C) 2013 Jonas Jensen + * + * Jonas Jensen + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "dmaengine.h" +#include "virt-dma.h" + +#define APB_DMA_MAX_CHANNEL 4 + +#define REG_OFF_ADDRESS_SOURCE 0 +#define REG_OFF_ADDRESS_DEST 4 +#define REG_OFF_CYCLES 8 +#define REG_OFF_CTRL 12 +#define REG_OFF_CHAN_SIZE 16 + +#define APB_DMA_ENABLE BIT(0) +#define APB_DMA_FIN_INT_STS BIT(1) +#define APB_DMA_FIN_INT_EN BIT(2) +#define APB_DMA_BURST_MODE BIT(3) +#define APB_DMA_ERR_INT_STS BIT(4) +#define APB_DMA_ERR_INT_EN BIT(5) + +/* + * Unset: APB + * Set: AHB + */ +#define APB_DMA_SOURCE_SELECT 0x40 +#define APB_DMA_DEST_SELECT 0x80 + +#define APB_DMA_SOURCE 0x100 +#define APB_DMA_DEST 0x1000 + +#define APB_DMA_SOURCE_MASK 0x700 +#define APB_DMA_DEST_MASK 0x7000 + +/* + * 000: No increment + * 001: +1 (Burst=0), +4 (Burst=1) + * 010: +2 (Burst=0), +8 (Burst=1) + * 011: +4 (Burst=0), +16 (Burst=1) + * 101: -1 (Burst=0), -4 (Burst=1) + * 110: -2 (Burst=0), -8 (Burst=1) + * 111: -4 (Burst=0), -16 (Burst=1) + */ +#define APB_DMA_SOURCE_INC_0 0 +#define APB_DMA_SOURCE_INC_1_4 0x100 +#define APB_DMA_SOURCE_INC_2_8 0x200 +#define APB_DMA_SOURCE_INC_4_16 0x300 +#define APB_DMA_SOURCE_DEC_1_4 0x500 +#define APB_DMA_SOURCE_DEC_2_8 0x600 +#define APB_DMA_SOURCE_DEC_4_16 0x700 +#define APB_DMA_DEST_INC_0 0 +#define APB_DMA_DEST_INC_1_4 0x1000 +#define APB_DMA_DEST_INC_2_8 0x2000 +#define APB_DMA_DEST_INC_4_16 0x3000 +#define APB_DMA_DEST_DEC_1_4 0x5000 +#define APB_DMA_DEST_DEC_2_8 0x6000 +#define APB_DMA_DEST_DEC_4_16 0x7000 + +/* + * Request signal select source/destination address for DMA hardware handshake. + * + * The request line number is a property of the DMA controller itself, + * e.g. MMC must always request channels where dma_slave_config->slave_id is 5. + * + * 0: No request / Grant signal + * 1-15: Request / Grant signal + */ +#define APB_DMA_SOURCE_REQ_NO 0x1000000 +#define APB_DMA_SOURCE_REQ_NO_MASK 0xf000000 +#define APB_DMA_DEST_REQ_NO 0x10000 +#define APB_DMA_DEST_REQ_NO_MASK 0xf0000 + +#define APB_DMA_DATA_WIDTH 0x100000 +#define APB_DMA_DATA_WIDTH_MASK 0x300000 +/* + * Data width of transfer: + * + * 00: Word + * 01: Half + * 10: Byte + */ +#define APB_DMA_DATA_WIDTH_4 0 +#define APB_DMA_DATA_WIDTH_2 0x100000 +#define APB_DMA_DATA_WIDTH_1 0x200000 + +#define APB_DMA_CYCLES_MASK 0x00ffffff + +#define MOXART_DMA_DATA_TYPE_S8 0x00 +#define MOXART_DMA_DATA_TYPE_S16 0x01 +#define MOXART_DMA_DATA_TYPE_S32 0x02 + +struct moxart_sg { + dma_addr_t addr; + uint32_t len; +}; + +struct moxart_desc { + enum dma_transfer_direction dma_dir; + dma_addr_t dev_addr; + unsigned int sglen; + unsigned int dma_cycles; + struct virt_dma_desc vd; + uint8_t es; + struct moxart_sg sg[0]; +}; + +struct moxart_chan { + struct virt_dma_chan vc; + + void __iomem *base; + struct moxart_desc *desc; + + struct dma_slave_config cfg; + + bool allocated; + bool error; + int ch_num; + unsigned int line_reqno; + unsigned int sgidx; +}; + +struct moxart_dmadev { + struct dma_device dma_slave; + struct moxart_chan slave_chans[APB_DMA_MAX_CHANNEL]; +}; + +struct moxart_filter_data { + struct moxart_dmadev *mdc; + struct of_phandle_args *dma_spec; +}; + +static const unsigned int es_bytes[] = { + [MOXART_DMA_DATA_TYPE_S8] = 1, + [MOXART_DMA_DATA_TYPE_S16] = 2, + [MOXART_DMA_DATA_TYPE_S32] = 4, +}; + +static struct device *chan2dev(struct dma_chan *chan) +{ + return &chan->dev->device; +} + +static inline struct moxart_chan *to_moxart_dma_chan(struct dma_chan *c) +{ + return container_of(c, struct moxart_chan, vc.chan); +} + +static inline struct moxart_desc *to_moxart_dma_desc( + struct dma_async_tx_descriptor *t) +{ + return container_of(t, struct moxart_desc, vd.tx); +} + +static void moxart_dma_desc_free(struct virt_dma_desc *vd) +{ + kfree(container_of(vd, struct moxart_desc, vd)); +} + +static int moxart_terminate_all(struct dma_chan *chan) +{ + struct moxart_chan *ch = to_moxart_dma_chan(chan); + unsigned long flags; + LIST_HEAD(head); + u32 ctrl; + + dev_dbg(chan2dev(chan), "%s: ch=%p\n", __func__, ch); + + spin_lock_irqsave(&ch->vc.lock, flags); + + if (ch->desc) + ch->desc = NULL; + + ctrl = readl(ch->base + REG_OFF_CTRL); + ctrl &= ~(APB_DMA_ENABLE | APB_DMA_FIN_INT_EN | APB_DMA_ERR_INT_EN); + writel(ctrl, ch->base + REG_OFF_CTRL); + + vchan_get_all_descriptors(&ch->vc, &head); + spin_unlock_irqrestore(&ch->vc.lock, flags); + vchan_dma_desc_free_list(&ch->vc, &head); + + return 0; +} + +static int moxart_slave_config(struct dma_chan *chan, + struct dma_slave_config *cfg) +{ + struct moxart_chan *ch = to_moxart_dma_chan(chan); + u32 ctrl; + + ch->cfg = *cfg; + + ctrl = readl(ch->base + REG_OFF_CTRL); + ctrl |= APB_DMA_BURST_MODE; + ctrl &= ~(APB_DMA_DEST_MASK | APB_DMA_SOURCE_MASK); + ctrl &= ~(APB_DMA_DEST_REQ_NO_MASK | APB_DMA_SOURCE_REQ_NO_MASK); + + switch (ch->cfg.src_addr_width) { + case DMA_SLAVE_BUSWIDTH_1_BYTE: + ctrl |= APB_DMA_DATA_WIDTH_1; + if (ch->cfg.direction != DMA_MEM_TO_DEV) + ctrl |= APB_DMA_DEST_INC_1_4; + else + ctrl |= APB_DMA_SOURCE_INC_1_4; + break; + case DMA_SLAVE_BUSWIDTH_2_BYTES: + ctrl |= APB_DMA_DATA_WIDTH_2; + if (ch->cfg.direction != DMA_MEM_TO_DEV) + ctrl |= APB_DMA_DEST_INC_2_8; + else + ctrl |= APB_DMA_SOURCE_INC_2_8; + break; + case DMA_SLAVE_BUSWIDTH_4_BYTES: + ctrl &= ~APB_DMA_DATA_WIDTH; + if (ch->cfg.direction != DMA_MEM_TO_DEV) + ctrl |= APB_DMA_DEST_INC_4_16; + else + ctrl |= APB_DMA_SOURCE_INC_4_16; + break; + default: + return -EINVAL; + } + + if (ch->cfg.direction == DMA_MEM_TO_DEV) { + ctrl &= ~APB_DMA_DEST_SELECT; + ctrl |= APB_DMA_SOURCE_SELECT; + ctrl |= (ch->line_reqno << 16 & + APB_DMA_DEST_REQ_NO_MASK); + } else { + ctrl |= APB_DMA_DEST_SELECT; + ctrl &= ~APB_DMA_SOURCE_SELECT; + ctrl |= (ch->line_reqno << 24 & + APB_DMA_SOURCE_REQ_NO_MASK); + } + + writel(ctrl, ch->base + REG_OFF_CTRL); + + return 0; +} + +static int moxart_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) +{ + int ret = 0; + + switch (cmd) { + case DMA_PAUSE: + case DMA_RESUME: + return -EINVAL; + case DMA_TERMINATE_ALL: + moxart_terminate_all(chan); + break; + case DMA_SLAVE_CONFIG: + ret = moxart_slave_config(chan, (struct dma_slave_config *)arg); + break; + default: + ret = -ENOSYS; + } + + return ret; +} + +static struct dma_async_tx_descriptor *moxart_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, + unsigned int sg_len, enum dma_transfer_direction dir, + unsigned long tx_flags, void *context) +{ + struct moxart_chan *ch = to_moxart_dma_chan(chan); + struct moxart_desc *d; + enum dma_slave_buswidth dev_width; + dma_addr_t dev_addr; + struct scatterlist *sgent; + unsigned int es; + unsigned int i; + + if (!is_slave_direction(dir)) { + dev_err(chan2dev(chan), "%s: invalid DMA direction\n", + __func__); + return NULL; + } + + if (dir == DMA_DEV_TO_MEM) { + dev_addr = ch->cfg.src_addr; + dev_width = ch->cfg.src_addr_width; + } else { + dev_addr = ch->cfg.dst_addr; + dev_width = ch->cfg.dst_addr_width; + } + + switch (dev_width) { + case DMA_SLAVE_BUSWIDTH_1_BYTE: + es = MOXART_DMA_DATA_TYPE_S8; + break; + case DMA_SLAVE_BUSWIDTH_2_BYTES: + es = MOXART_DMA_DATA_TYPE_S16; + break; + case DMA_SLAVE_BUSWIDTH_4_BYTES: + es = MOXART_DMA_DATA_TYPE_S32; + break; + default: + dev_err(chan2dev(chan), "%s: unsupported data width (%u)\n", + __func__, dev_width); + return NULL; + } + + d = kzalloc(sizeof(*d) + sg_len * sizeof(d->sg[0]), GFP_ATOMIC); + if (!d) + return NULL; + + d->dma_dir = dir; + d->dev_addr = dev_addr; + d->es = es; + + for_each_sg(sgl, sgent, sg_len, i) { + d->sg[i].addr = sg_dma_address(sgent); + d->sg[i].len = sg_dma_len(sgent); + } + + d->sglen = sg_len; + + ch->error = 0; + + return vchan_tx_prep(&ch->vc, &d->vd, tx_flags); +} + +static struct dma_chan *moxart_of_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct moxart_dmadev *mdc = ofdma->of_dma_data; + struct dma_chan *chan; + struct moxart_chan *ch; + + chan = dma_get_any_slave_channel(&mdc->dma_slave); + if (!chan) + return NULL; + + ch = to_moxart_dma_chan(chan); + ch->line_reqno = dma_spec->args[0]; + + return chan; +} + +static int moxart_alloc_chan_resources(struct dma_chan *chan) +{ + struct moxart_chan *ch = to_moxart_dma_chan(chan); + + dev_dbg(chan2dev(chan), "%s: allocating channel #%u\n", + __func__, ch->ch_num); + ch->allocated = 1; + + return 0; +} + +static void moxart_free_chan_resources(struct dma_chan *chan) +{ + struct moxart_chan *ch = to_moxart_dma_chan(chan); + + vchan_free_chan_resources(&ch->vc); + + dev_dbg(chan2dev(chan), "%s: freeing channel #%u\n", + __func__, ch->ch_num); + ch->allocated = 0; +} + +static void moxart_dma_set_params(struct moxart_chan *ch, dma_addr_t src_addr, + dma_addr_t dst_addr) +{ + writel(src_addr, ch->base + REG_OFF_ADDRESS_SOURCE); + writel(dst_addr, ch->base + REG_OFF_ADDRESS_DEST); +} + +static void moxart_set_transfer_params(struct moxart_chan *ch, unsigned int len) +{ + struct moxart_desc *d = ch->desc; + unsigned int sglen_div = es_bytes[d->es]; + + d->dma_cycles = len >> sglen_div; + + /* + * There are 4 cycles on 64 bytes copied, i.e. one cycle copies 16 + * bytes ( when width is APB_DMAB_DATA_WIDTH_4 ). + */ + writel(d->dma_cycles, ch->base + REG_OFF_CYCLES); + + dev_dbg(chan2dev(&ch->vc.chan), "%s: set %u DMA cycles (len=%u)\n", + __func__, d->dma_cycles, len); +} + +static void moxart_start_dma(struct moxart_chan *ch) +{ + u32 ctrl; + + ctrl = readl(ch->base + REG_OFF_CTRL); + ctrl |= (APB_DMA_ENABLE | APB_DMA_FIN_INT_EN | APB_DMA_ERR_INT_EN); + writel(ctrl, ch->base + REG_OFF_CTRL); +} + +static void moxart_dma_start_sg(struct moxart_chan *ch, unsigned int idx) +{ + struct moxart_desc *d = ch->desc; + struct moxart_sg *sg = ch->desc->sg + idx; + + if (ch->desc->dma_dir == DMA_MEM_TO_DEV) + moxart_dma_set_params(ch, sg->addr, d->dev_addr); + else if (ch->desc->dma_dir == DMA_DEV_TO_MEM) + moxart_dma_set_params(ch, d->dev_addr, sg->addr); + + moxart_set_transfer_params(ch, sg->len); + + moxart_start_dma(ch); +} + +static void moxart_dma_start_desc(struct dma_chan *chan) +{ + struct moxart_chan *ch = to_moxart_dma_chan(chan); + struct virt_dma_desc *vd; + + vd = vchan_next_desc(&ch->vc); + + if (!vd) { + ch->desc = NULL; + return; + } + + list_del(&vd->node); + + ch->desc = to_moxart_dma_desc(&vd->tx); + ch->sgidx = 0; + + moxart_dma_start_sg(ch, 0); +} + +static void moxart_issue_pending(struct dma_chan *chan) +{ + struct moxart_chan *ch = to_moxart_dma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&ch->vc.lock, flags); + if (vchan_issue_pending(&ch->vc) && !ch->desc) + moxart_dma_start_desc(chan); + spin_unlock_irqrestore(&ch->vc.lock, flags); +} + +static size_t moxart_dma_desc_size(struct moxart_desc *d, + unsigned int completed_sgs) +{ + unsigned int i; + size_t size; + + for (size = i = completed_sgs; i < d->sglen; i++) + size += d->sg[i].len; + + return size; +} + +static size_t moxart_dma_desc_size_in_flight(struct moxart_chan *ch) +{ + size_t size; + unsigned int completed_cycles, cycles; + + size = moxart_dma_desc_size(ch->desc, ch->sgidx); + cycles = readl(ch->base + REG_OFF_CYCLES); + completed_cycles = (ch->desc->dma_cycles - cycles); + size -= completed_cycles << es_bytes[ch->desc->es]; + + dev_dbg(chan2dev(&ch->vc.chan), "%s: size=%zu\n", __func__, size); + + return size; +} + +static enum dma_status moxart_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, + struct dma_tx_state *txstate) +{ + struct moxart_chan *ch = to_moxart_dma_chan(chan); + struct virt_dma_desc *vd; + struct moxart_desc *d; + enum dma_status ret; + unsigned long flags; + + /* + * dma_cookie_status() assigns initial residue value. + */ + ret = dma_cookie_status(chan, cookie, txstate); + + spin_lock_irqsave(&ch->vc.lock, flags); + vd = vchan_find_desc(&ch->vc, cookie); + if (vd) { + d = to_moxart_dma_desc(&vd->tx); + txstate->residue = moxart_dma_desc_size(d, 0); + } else if (ch->desc && ch->desc->vd.tx.cookie == cookie) { + txstate->residue = moxart_dma_desc_size_in_flight(ch); + } + spin_unlock_irqrestore(&ch->vc.lock, flags); + + if (ch->error) + return DMA_ERROR; + + return ret; +} + +static void moxart_dma_init(struct dma_device *dma, struct device *dev) +{ + dma->device_prep_slave_sg = moxart_prep_slave_sg; + dma->device_alloc_chan_resources = moxart_alloc_chan_resources; + dma->device_free_chan_resources = moxart_free_chan_resources; + dma->device_issue_pending = moxart_issue_pending; + dma->device_tx_status = moxart_tx_status; + dma->device_control = moxart_control; + dma->dev = dev; + + INIT_LIST_HEAD(&dma->channels); +} + +static irqreturn_t moxart_dma_interrupt(int irq, void *devid) +{ + struct moxart_dmadev *mc = devid; + struct moxart_chan *ch = &mc->slave_chans[0]; + unsigned int i; + unsigned long flags; + u32 ctrl; + + dev_dbg(chan2dev(&ch->vc.chan), "%s\n", __func__); + + for (i = 0; i < APB_DMA_MAX_CHANNEL; i++, ch++) { + if (!ch->allocated) + continue; + + ctrl = readl(ch->base + REG_OFF_CTRL); + + dev_dbg(chan2dev(&ch->vc.chan), "%s: ch=%p ch->base=%p ctrl=%x\n", + __func__, ch, ch->base, ctrl); + + if (ctrl & APB_DMA_FIN_INT_STS) { + ctrl &= ~APB_DMA_FIN_INT_STS; + if (ch->desc) { + spin_lock_irqsave(&ch->vc.lock, flags); + if (++ch->sgidx < ch->desc->sglen) { + moxart_dma_start_sg(ch, ch->sgidx); + } else { + vchan_cookie_complete(&ch->desc->vd); + moxart_dma_start_desc(&ch->vc.chan); + } + spin_unlock_irqrestore(&ch->vc.lock, flags); + } + } + + if (ctrl & APB_DMA_ERR_INT_STS) { + ctrl &= ~APB_DMA_ERR_INT_STS; + ch->error = 1; + } + + writel(ctrl, ch->base + REG_OFF_CTRL); + } + + return IRQ_HANDLED; +} + +static int moxart_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct resource *res; + static void __iomem *dma_base_addr; + int ret, i; + unsigned int irq; + struct moxart_chan *ch; + struct moxart_dmadev *mdc; + + mdc = devm_kzalloc(dev, sizeof(*mdc), GFP_KERNEL); + if (!mdc) { + dev_err(dev, "can't allocate DMA container\n"); + return -ENOMEM; + } + + irq = irq_of_parse_and_map(node, 0); + if (irq == NO_IRQ) { + dev_err(dev, "no IRQ resource\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dma_base_addr = devm_ioremap_resource(dev, res); + if (IS_ERR(dma_base_addr)) + return PTR_ERR(dma_base_addr); + + dma_cap_zero(mdc->dma_slave.cap_mask); + dma_cap_set(DMA_SLAVE, mdc->dma_slave.cap_mask); + dma_cap_set(DMA_PRIVATE, mdc->dma_slave.cap_mask); + + moxart_dma_init(&mdc->dma_slave, dev); + + ch = &mdc->slave_chans[0]; + for (i = 0; i < APB_DMA_MAX_CHANNEL; i++, ch++) { + ch->ch_num = i; + ch->base = dma_base_addr + i * REG_OFF_CHAN_SIZE; + ch->allocated = 0; + + ch->vc.desc_free = moxart_dma_desc_free; + vchan_init(&ch->vc, &mdc->dma_slave); + + dev_dbg(dev, "%s: chs[%d]: ch->ch_num=%u ch->base=%p\n", + __func__, i, ch->ch_num, ch->base); + } + + platform_set_drvdata(pdev, mdc); + + ret = devm_request_irq(dev, irq, moxart_dma_interrupt, 0, + "moxart-dma-engine", mdc); + if (ret) { + dev_err(dev, "devm_request_irq failed\n"); + return ret; + } + + ret = dma_async_device_register(&mdc->dma_slave); + if (ret) { + dev_err(dev, "dma_async_device_register failed\n"); + return ret; + } + + ret = of_dma_controller_register(node, moxart_of_xlate, mdc); + if (ret) { + dev_err(dev, "of_dma_controller_register failed\n"); + dma_async_device_unregister(&mdc->dma_slave); + return ret; + } + + dev_dbg(dev, "%s: IRQ=%u\n", __func__, irq); + + return 0; +} + +static int moxart_remove(struct platform_device *pdev) +{ + struct moxart_dmadev *m = platform_get_drvdata(pdev); + + dma_async_device_unregister(&m->dma_slave); + + if (pdev->dev.of_node) + of_dma_controller_free(pdev->dev.of_node); + + return 0; +} + +static const struct of_device_id moxart_dma_match[] = { + { .compatible = "moxa,moxart-dma" }, + { } +}; + +static struct platform_driver moxart_driver = { + .probe = moxart_probe, + .remove = moxart_remove, + .driver = { + .name = "moxart-dma-engine", + .owner = THIS_MODULE, + .of_match_table = moxart_dma_match, + }, +}; + +static int moxart_init(void) +{ + return platform_driver_register(&moxart_driver); +} +subsys_initcall(moxart_init); + +static void __exit moxart_exit(void) +{ + platform_driver_unregister(&moxart_driver); +} +module_exit(moxart_exit); + +MODULE_AUTHOR("Jonas Jensen "); +MODULE_DESCRIPTION("MOXART DMA engine driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 53fb0c8365b0b2..766b68ed505c4d 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -497,8 +497,8 @@ mv_xor_tx_submit(struct dma_async_tx_descriptor *tx) if (!mv_can_chain(grp_start)) goto submit_done; - dev_dbg(mv_chan_to_devp(mv_chan), "Append to last desc %x\n", - old_chain_tail->async_tx.phys); + dev_dbg(mv_chan_to_devp(mv_chan), "Append to last desc %pa\n", + &old_chain_tail->async_tx.phys); /* fix up the hardware chain */ mv_desc_set_next_desc(old_chain_tail, grp_start->async_tx.phys); @@ -527,7 +527,8 @@ mv_xor_tx_submit(struct dma_async_tx_descriptor *tx) /* returns the number of allocated descriptors */ static int mv_xor_alloc_chan_resources(struct dma_chan *chan) { - char *hw_desc; + void *virt_desc; + dma_addr_t dma_desc; int idx; struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan); struct mv_xor_desc_slot *slot = NULL; @@ -542,17 +543,16 @@ static int mv_xor_alloc_chan_resources(struct dma_chan *chan) " %d descriptor slots", idx); break; } - hw_desc = (char *) mv_chan->dma_desc_pool_virt; - slot->hw_desc = (void *) &hw_desc[idx * MV_XOR_SLOT_SIZE]; + virt_desc = mv_chan->dma_desc_pool_virt; + slot->hw_desc = virt_desc + idx * MV_XOR_SLOT_SIZE; dma_async_tx_descriptor_init(&slot->async_tx, chan); slot->async_tx.tx_submit = mv_xor_tx_submit; INIT_LIST_HEAD(&slot->chain_node); INIT_LIST_HEAD(&slot->slot_node); INIT_LIST_HEAD(&slot->tx_list); - hw_desc = (char *) mv_chan->dma_desc_pool; - slot->async_tx.phys = - (dma_addr_t) &hw_desc[idx * MV_XOR_SLOT_SIZE]; + dma_desc = mv_chan->dma_desc_pool; + slot->async_tx.phys = dma_desc + idx * MV_XOR_SLOT_SIZE; slot->idx = idx++; spin_lock_bh(&mv_chan->lock); @@ -582,8 +582,8 @@ mv_xor_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, int slot_cnt; dev_dbg(mv_chan_to_devp(mv_chan), - "%s dest: %x src %x len: %u flags: %ld\n", - __func__, dest, src, len, flags); + "%s dest: %pad src %pad len: %u flags: %ld\n", + __func__, &dest, &src, len, flags); if (unlikely(len < MV_XOR_MIN_BYTE_COUNT)) return NULL; @@ -626,8 +626,8 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src, BUG_ON(len > MV_XOR_MAX_BYTE_COUNT); dev_dbg(mv_chan_to_devp(mv_chan), - "%s src_cnt: %d len: dest %x %u flags: %ld\n", - __func__, src_cnt, len, dest, flags); + "%s src_cnt: %d len: %u dest %pad flags: %ld\n", + __func__, src_cnt, len, &dest, flags); spin_lock_bh(&mv_chan->lock); slot_cnt = mv_chan_xor_slot_count(len, src_cnt); diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index 2f66cf4e54fe36..362e7c49f2e1ad 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -190,7 +190,7 @@ static int omap_dma_alloc_chan_resources(struct dma_chan *chan) { struct omap_chan *c = to_omap_dma_chan(chan); - dev_info(c->vc.chan.device->dev, "allocating channel for %u\n", c->dma_sig); + dev_dbg(c->vc.chan.device->dev, "allocating channel for %u\n", c->dma_sig); return omap_request_dma(c->dma_sig, "DMA engine", omap_dma_callback, c, &c->dma_ch); @@ -203,7 +203,7 @@ static void omap_dma_free_chan_resources(struct dma_chan *chan) vchan_free_chan_resources(&c->vc); omap_free_dma(c->dma_ch); - dev_info(c->vc.chan.device->dev, "freeing channel for %u\n", c->dma_sig); + dev_dbg(c->vc.chan.device->dev, "freeing channel for %u\n", c->dma_sig); } static size_t omap_dma_sg_size(struct omap_sg *sg) diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index c90edecee4633c..73fa9b7a10ab36 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -543,7 +543,9 @@ struct dma_pl330_chan { /* DMA-Engine Channel */ struct dma_chan chan; - /* List of to be xfered descriptors */ + /* List of submitted descriptors */ + struct list_head submitted_list; + /* List of issued descriptors */ struct list_head work_list; /* List of completed descriptors */ struct list_head completed_list; @@ -578,12 +580,16 @@ struct dma_pl330_dmac { /* DMA-Engine Device */ struct dma_device ddma; + /* Holds info about sg limitations */ + struct device_dma_parameters dma_parms; + /* Pool of descriptors available for the DMAC's channels */ struct list_head desc_pool; /* To protect desc_pool manipulation */ spinlock_t pool_lock; /* Peripheral channels connected to this DMAC */ + unsigned int num_peripherals; struct dma_pl330_chan *peripherals; /* keep at end */ }; @@ -606,11 +612,6 @@ struct dma_pl330_desc { struct dma_pl330_chan *pchan; }; -struct dma_pl330_filter_args { - struct dma_pl330_dmac *pdmac; - unsigned int chan_id; -}; - static inline void _callback(struct pl330_req *r, enum pl330_op_err err) { if (r && r->xfer_cb) @@ -2298,16 +2299,6 @@ static void dma_pl330_rqcb(void *token, enum pl330_op_err err) tasklet_schedule(&pch->task); } -static bool pl330_dt_filter(struct dma_chan *chan, void *param) -{ - struct dma_pl330_filter_args *fargs = param; - - if (chan->device != &fargs->pdmac->ddma) - return false; - - return (chan->chan_id == fargs->chan_id); -} - bool pl330_filter(struct dma_chan *chan, void *param) { u8 *peri_id; @@ -2325,23 +2316,16 @@ static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec, { int count = dma_spec->args_count; struct dma_pl330_dmac *pdmac = ofdma->of_dma_data; - struct dma_pl330_filter_args fargs; - dma_cap_mask_t cap; - - if (!pdmac) - return NULL; + unsigned int chan_id; if (count != 1) return NULL; - fargs.pdmac = pdmac; - fargs.chan_id = dma_spec->args[0]; - - dma_cap_zero(cap); - dma_cap_set(DMA_SLAVE, cap); - dma_cap_set(DMA_CYCLIC, cap); + chan_id = dma_spec->args[0]; + if (chan_id >= pdmac->num_peripherals) + return NULL; - return dma_request_channel(cap, pl330_dt_filter, &fargs); + return dma_get_slave_channel(&pdmac->peripherals[chan_id].chan); } static int pl330_alloc_chan_resources(struct dma_chan *chan) @@ -2385,6 +2369,11 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH); /* Mark all desc done */ + list_for_each_entry(desc, &pch->submitted_list, node) { + desc->status = FREE; + dma_cookie_complete(&desc->txd); + } + list_for_each_entry(desc, &pch->work_list , node) { desc->status = FREE; dma_cookie_complete(&desc->txd); @@ -2395,6 +2384,7 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned dma_cookie_complete(&desc->txd); } + list_splice_tail_init(&pch->submitted_list, &pdmac->desc_pool); list_splice_tail_init(&pch->work_list, &pdmac->desc_pool); list_splice_tail_init(&pch->completed_list, &pdmac->desc_pool); spin_unlock_irqrestore(&pch->lock, flags); @@ -2453,7 +2443,14 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie, static void pl330_issue_pending(struct dma_chan *chan) { - pl330_tasklet((unsigned long) to_pchan(chan)); + struct dma_pl330_chan *pch = to_pchan(chan); + unsigned long flags; + + spin_lock_irqsave(&pch->lock, flags); + list_splice_tail_init(&pch->submitted_list, &pch->work_list); + spin_unlock_irqrestore(&pch->lock, flags); + + pl330_tasklet((unsigned long)pch); } /* @@ -2480,11 +2477,11 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx) dma_cookie_assign(&desc->txd); - list_move_tail(&desc->node, &pch->work_list); + list_move_tail(&desc->node, &pch->submitted_list); } cookie = dma_cookie_assign(&last->txd); - list_add_tail(&last->node, &pch->work_list); + list_add_tail(&last->node, &pch->submitted_list); spin_unlock_irqrestore(&pch->lock, flags); return cookie; @@ -2960,6 +2957,8 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) else num_chan = max_t(int, pi->pcfg.num_peri, pi->pcfg.num_chan); + pdmac->num_peripherals = num_chan; + pdmac->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL); if (!pdmac->peripherals) { ret = -ENOMEM; @@ -2974,6 +2973,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) else pch->chan.private = adev->dev.of_node; + INIT_LIST_HEAD(&pch->submitted_list); INIT_LIST_HEAD(&pch->work_list); INIT_LIST_HEAD(&pch->completed_list); spin_lock_init(&pch->lock); @@ -3021,6 +3021,9 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) "unable to register DMA to the generic DT DMA helpers\n"); } } + + adev->dev.dma_parms = &pdmac->dma_parms; + /* * This is the limit for transfers with a buswidth of 1, larger * buswidths will have larger limits. diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c index 8bba298535b098..ce7a8d7564ba6f 100644 --- a/drivers/dma/ppc4xx/adma.c +++ b/drivers/dma/ppc4xx/adma.c @@ -4114,6 +4114,7 @@ static int ppc440spe_adma_probe(struct platform_device *ofdev) regs = ioremap(res.start, resource_size(&res)); if (!regs) { dev_err(&ofdev->dev, "failed to ioremap regs!\n"); + ret = -ENOMEM; goto err_regs_alloc; } diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c index 6aec3ad814d37f..d4d3a3109b163f 100644 --- a/drivers/dma/sirf-dma.c +++ b/drivers/dma/sirf-dma.c @@ -640,6 +640,25 @@ bool sirfsoc_dma_filter_id(struct dma_chan *chan, void *chan_id) } EXPORT_SYMBOL(sirfsoc_dma_filter_id); +#define SIRFSOC_DMA_BUSWIDTHS \ + (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \ + BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)) + +static int sirfsoc_dma_device_slave_caps(struct dma_chan *dchan, + struct dma_slave_caps *caps) +{ + caps->src_addr_widths = SIRFSOC_DMA_BUSWIDTHS; + caps->dstn_addr_widths = SIRFSOC_DMA_BUSWIDTHS; + caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + caps->cmd_pause = true; + caps->cmd_terminate = true; + + return 0; +} + static int sirfsoc_dma_probe(struct platform_device *op) { struct device_node *dn = op->dev.of_node; @@ -712,6 +731,7 @@ static int sirfsoc_dma_probe(struct platform_device *op) dma->device_tx_status = sirfsoc_dma_tx_status; dma->device_prep_interleaved_dma = sirfsoc_dma_prep_interleaved; dma->device_prep_dma_cyclic = sirfsoc_dma_prep_cyclic; + dma->device_slave_caps = sirfsoc_dma_device_slave_caps; INIT_LIST_HEAD(&dma->channels); dma_cap_set(DMA_SLAVE, dma->cap_mask); diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index d11bb3620f2783..03ad64ecaaf043 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -100,6 +100,11 @@ #define TEGRA_APBDMA_APBSEQ_DATA_SWAP BIT(27) #define TEGRA_APBDMA_APBSEQ_WRAP_WORD_1 (1 << 16) +/* Tegra148 specific registers */ +#define TEGRA_APBDMA_CHAN_WCOUNT 0x20 + +#define TEGRA_APBDMA_CHAN_WORD_TRANSFER 0x24 + /* * If any burst is in flight and DMA paused then this is the time to complete * on-flight burst and update DMA status register. @@ -109,21 +114,22 @@ /* Channel base address offset from APBDMA base address */ #define TEGRA_APBDMA_CHANNEL_BASE_ADD_OFFSET 0x1000 -/* DMA channel register space size */ -#define TEGRA_APBDMA_CHANNEL_REGISTER_SIZE 0x20 - struct tegra_dma; /* * tegra_dma_chip_data Tegra chip specific DMA data * @nr_channels: Number of channels available in the controller. + * @channel_reg_size: Channel register size/stride. * @max_dma_count: Maximum DMA transfer count supported by DMA controller. * @support_channel_pause: Support channel wise pause of dma. + * @support_separate_wcount_reg: Support separate word count register. */ struct tegra_dma_chip_data { int nr_channels; + int channel_reg_size; int max_dma_count; bool support_channel_pause; + bool support_separate_wcount_reg; }; /* DMA channel registers */ @@ -133,6 +139,7 @@ struct tegra_dma_channel_regs { unsigned long apb_ptr; unsigned long ahb_seq; unsigned long apb_seq; + unsigned long wcount; }; /* @@ -426,6 +433,8 @@ static void tegra_dma_start(struct tegra_dma_channel *tdc, tdc_write(tdc, TEGRA_APBDMA_CHAN_APBPTR, ch_regs->apb_ptr); tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBSEQ, ch_regs->ahb_seq); tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBPTR, ch_regs->ahb_ptr); + if (tdc->tdma->chip_data->support_separate_wcount_reg) + tdc_write(tdc, TEGRA_APBDMA_CHAN_WCOUNT, ch_regs->wcount); /* Start DMA */ tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR, @@ -465,6 +474,9 @@ static void tegra_dma_configure_for_next(struct tegra_dma_channel *tdc, /* Safe to program new configuration */ tdc_write(tdc, TEGRA_APBDMA_CHAN_APBPTR, nsg_req->ch_regs.apb_ptr); tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBPTR, nsg_req->ch_regs.ahb_ptr); + if (tdc->tdma->chip_data->support_separate_wcount_reg) + tdc_write(tdc, TEGRA_APBDMA_CHAN_WCOUNT, + nsg_req->ch_regs.wcount); tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR, nsg_req->ch_regs.csr | TEGRA_APBDMA_CSR_ENB); nsg_req->configured = true; @@ -718,6 +730,7 @@ static void tegra_dma_terminate_all(struct dma_chan *dc) struct tegra_dma_desc *dma_desc; unsigned long flags; unsigned long status; + unsigned long wcount; bool was_busy; spin_lock_irqsave(&tdc->lock, flags); @@ -738,6 +751,10 @@ static void tegra_dma_terminate_all(struct dma_chan *dc) tdc->isr_handler(tdc, true); status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS); } + if (tdc->tdma->chip_data->support_separate_wcount_reg) + wcount = tdc_read(tdc, TEGRA_APBDMA_CHAN_WORD_TRANSFER); + else + wcount = status; was_busy = tdc->busy; tegra_dma_stop(tdc); @@ -746,7 +763,7 @@ static void tegra_dma_terminate_all(struct dma_chan *dc) sgreq = list_first_entry(&tdc->pending_sg_req, typeof(*sgreq), node); sgreq->dma_desc->bytes_transferred += - get_current_xferred_count(tdc, sgreq, status); + get_current_xferred_count(tdc, sgreq, wcount); } tegra_dma_resume(tdc); @@ -908,6 +925,17 @@ static int get_transfer_param(struct tegra_dma_channel *tdc, return -EINVAL; } +static void tegra_dma_prep_wcount(struct tegra_dma_channel *tdc, + struct tegra_dma_channel_regs *ch_regs, u32 len) +{ + u32 len_field = (len - 4) & 0xFFFC; + + if (tdc->tdma->chip_data->support_separate_wcount_reg) + ch_regs->wcount = len_field; + else + ch_regs->csr |= len_field; +} + static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg( struct dma_chan *dc, struct scatterlist *sgl, unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flags, @@ -991,7 +1019,8 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg( sg_req->ch_regs.apb_ptr = apb_ptr; sg_req->ch_regs.ahb_ptr = mem; - sg_req->ch_regs.csr = csr | ((len - 4) & 0xFFFC); + sg_req->ch_regs.csr = csr; + tegra_dma_prep_wcount(tdc, &sg_req->ch_regs, len); sg_req->ch_regs.apb_seq = apb_seq; sg_req->ch_regs.ahb_seq = ahb_seq; sg_req->configured = false; @@ -1120,7 +1149,8 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic( ahb_seq |= get_burst_size(tdc, burst_size, slave_bw, len); sg_req->ch_regs.apb_ptr = apb_ptr; sg_req->ch_regs.ahb_ptr = mem; - sg_req->ch_regs.csr = csr | ((len - 4) & 0xFFFC); + sg_req->ch_regs.csr = csr; + tegra_dma_prep_wcount(tdc, &sg_req->ch_regs, len); sg_req->ch_regs.apb_seq = apb_seq; sg_req->ch_regs.ahb_seq = ahb_seq; sg_req->configured = false; @@ -1234,27 +1264,45 @@ static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec, /* Tegra20 specific DMA controller information */ static const struct tegra_dma_chip_data tegra20_dma_chip_data = { .nr_channels = 16, + .channel_reg_size = 0x20, .max_dma_count = 1024UL * 64, .support_channel_pause = false, + .support_separate_wcount_reg = false, }; /* Tegra30 specific DMA controller information */ static const struct tegra_dma_chip_data tegra30_dma_chip_data = { .nr_channels = 32, + .channel_reg_size = 0x20, .max_dma_count = 1024UL * 64, .support_channel_pause = false, + .support_separate_wcount_reg = false, }; /* Tegra114 specific DMA controller information */ static const struct tegra_dma_chip_data tegra114_dma_chip_data = { .nr_channels = 32, + .channel_reg_size = 0x20, .max_dma_count = 1024UL * 64, .support_channel_pause = true, + .support_separate_wcount_reg = false, +}; + +/* Tegra148 specific DMA controller information */ +static const struct tegra_dma_chip_data tegra148_dma_chip_data = { + .nr_channels = 32, + .channel_reg_size = 0x40, + .max_dma_count = 1024UL * 64, + .support_channel_pause = true, + .support_separate_wcount_reg = true, }; static const struct of_device_id tegra_dma_of_match[] = { { + .compatible = "nvidia,tegra148-apbdma", + .data = &tegra148_dma_chip_data, + }, { .compatible = "nvidia,tegra114-apbdma", .data = &tegra114_dma_chip_data, }, { @@ -1348,7 +1396,7 @@ static int tegra_dma_probe(struct platform_device *pdev) struct tegra_dma_channel *tdc = &tdma->channels[i]; tdc->chan_base_offset = TEGRA_APBDMA_CHANNEL_BASE_ADD_OFFSET + - i * TEGRA_APBDMA_CHANNEL_REGISTER_SIZE; + i * cdata->channel_reg_size; res = platform_get_resource(pdev, IORESOURCE_IRQ, i); if (!res) { diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h index 85c19d63f9fbe9..181b95267866b6 100644 --- a/drivers/dma/virt-dma.h +++ b/drivers/dma/virt-dma.h @@ -84,10 +84,12 @@ static inline bool vchan_issue_pending(struct virt_dma_chan *vc) static inline void vchan_cookie_complete(struct virt_dma_desc *vd) { struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan); + dma_cookie_t cookie; + cookie = vd->tx.cookie; dma_cookie_complete(&vd->tx); dev_vdbg(vc->chan.device->dev, "txd %p[%x]: marked complete\n", - vd, vd->tx.cookie); + vd, cookie); list_add_tail(&vd->node, &vc->desc_completed); tasklet_schedule(&vc->task); diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index e8c9ef03495be4..33edd676634431 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -559,7 +559,8 @@ static void edac_mc_workq_function(struct work_struct *work_req) * * called with the mem_ctls_mutex held */ -static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec) +static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec, + bool init) { edac_dbg(0, "\n"); @@ -567,7 +568,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec) if (mci->op_state != OP_RUNNING_POLL) return; - INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function); + if (init) + INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function); + mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec)); } @@ -601,7 +604,7 @@ static void edac_mc_workq_teardown(struct mem_ctl_info *mci) * user space has updated our poll period value, need to * reset our workq delays */ -void edac_mc_reset_delay_period(int value) +void edac_mc_reset_delay_period(unsigned long value) { struct mem_ctl_info *mci; struct list_head *item; @@ -611,7 +614,7 @@ void edac_mc_reset_delay_period(int value) list_for_each(item, &mc_devices) { mci = list_entry(item, struct mem_ctl_info, link); - edac_mc_workq_setup(mci, (unsigned long) value); + edac_mc_workq_setup(mci, value, false); } mutex_unlock(&mem_ctls_mutex); @@ -782,7 +785,7 @@ int edac_mc_add_mc(struct mem_ctl_info *mci) /* This instance is NOW RUNNING */ mci->op_state = OP_RUNNING_POLL; - edac_mc_workq_setup(mci, edac_mc_get_poll_msec()); + edac_mc_workq_setup(mci, edac_mc_get_poll_msec(), true); } else { mci->op_state = OP_RUNNING_INTERRUPT; } diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 51c0362acf5c45..b335c6ab5efe02 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -52,18 +52,20 @@ int edac_mc_get_poll_msec(void) static int edac_set_poll_msec(const char *val, struct kernel_param *kp) { - long l; + unsigned long l; int ret; if (!val) return -EINVAL; - ret = kstrtol(val, 0, &l); + ret = kstrtoul(val, 0, &l); if (ret) return ret; - if ((int)l != l) + + if (l < 1000) return -EINVAL; - *((int *)kp->arg) = l; + + *((unsigned long *)kp->arg) = l; /* notify edac_mc engine to reset the poll period */ edac_mc_reset_delay_period(l); diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index 3d139c6e7fe325..f2118bfcf8dfbd 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h @@ -52,7 +52,7 @@ extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev); extern void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev, unsigned long value); -extern void edac_mc_reset_delay_period(int value); +extern void edac_mc_reset_delay_period(unsigned long value); extern void *edac_align_ptr(void **p, unsigned size, int n_elems); diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 0e799516a2ab99..eb6935c8ad9449 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -523,11 +523,11 @@ static DEFINE_SPINLOCK(address_handler_list_lock); static LIST_HEAD(address_handler_list); const struct fw_address_region fw_high_memory_region = - { .start = 0x000100000000ULL, .end = 0xffffe0000000ULL, }; + { .start = FW_MAX_PHYSICAL_RANGE, .end = 0xffffe0000000ULL, }; EXPORT_SYMBOL(fw_high_memory_region); static const struct fw_address_region low_memory_region = - { .start = 0x000000000000ULL, .end = 0x000100000000ULL, }; + { .start = 0x000000000000ULL, .end = FW_MAX_PHYSICAL_RANGE, }; #if 0 const struct fw_address_region fw_private_region = @@ -1217,7 +1217,7 @@ static void handle_low_memory(struct fw_card *card, struct fw_request *request, } static struct fw_address_handler low_memory = { - .length = 0x000100000000ULL, + .length = FW_MAX_PHYSICAL_RANGE, .address_callback = handle_low_memory, }; diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index 515a42c786d025..c98764aeeec611 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -237,6 +237,9 @@ static inline bool is_next_generation(int new_generation, int old_generation) #define LOCAL_BUS 0xffc0 +/* arbitrarily chosen maximum range for physical DMA: 128 TB */ +#define FW_MAX_PHYSICAL_RANGE (128ULL << 40) + void fw_core_handle_request(struct fw_card *card, struct fw_packet *request); void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet); int fw_get_response_length(struct fw_request *request); diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 6aa8a86cb83b33..6f74d8d3f70015 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -370,6 +370,10 @@ MODULE_PARM_DESC(debug, "Verbose logging (default = 0" ", busReset events = " __stringify(OHCI_PARAM_DEBUG_BUSRESETS) ", or a combination, or all = -1)"); +static bool param_remote_dma; +module_param_named(remote_dma, param_remote_dma, bool, 0444); +MODULE_PARM_DESC(remote_dma, "Enable unfiltered remote DMA (default = N)"); + static void log_irqs(struct fw_ohci *ohci, u32 evt) { if (likely(!(param_debug & @@ -2050,10 +2054,10 @@ static void bus_reset_work(struct work_struct *work) be32_to_cpu(ohci->next_header)); } -#ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA - reg_write(ohci, OHCI1394_PhyReqFilterHiSet, ~0); - reg_write(ohci, OHCI1394_PhyReqFilterLoSet, ~0); -#endif + if (param_remote_dma) { + reg_write(ohci, OHCI1394_PhyReqFilterHiSet, ~0); + reg_write(ohci, OHCI1394_PhyReqFilterLoSet, ~0); + } spin_unlock_irq(&ohci->lock); @@ -2363,7 +2367,7 @@ static int ohci_enable(struct fw_card *card, reg_write(ohci, OHCI1394_FairnessControl, 0); card->priority_budget_implemented = ohci->pri_req_max != 0; - reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000); + reg_write(ohci, OHCI1394_PhyUpperBound, FW_MAX_PHYSICAL_RANGE >> 16); reg_write(ohci, OHCI1394_IntEventClear, ~0); reg_write(ohci, OHCI1394_IntMaskClear, ~0); @@ -2587,13 +2591,13 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet) static int ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation) { -#ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA - return 0; -#else struct fw_ohci *ohci = fw_ohci(card); unsigned long flags; int n, ret = 0; + if (param_remote_dma) + return 0; + /* * FIXME: Make sure this bitmask is cleared when we clear the busReset * interrupt bit. Clear physReqResourceAllBuses on bus reset. @@ -2622,7 +2626,6 @@ static int ohci_enable_phys_dma(struct fw_card *card, spin_unlock_irqrestore(&ohci->lock, flags); return ret; -#endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */ } static u32 ohci_read_csr(struct fw_card *card, int csr_offset) @@ -3720,9 +3723,11 @@ static int pci_probe(struct pci_dev *dev, version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; ohci_notice(ohci, "added OHCI v%x.%x device as card %d, " - "%d IR + %d IT contexts, quirks 0x%x\n", + "%d IR + %d IT contexts, quirks 0x%x%s\n", version >> 16, version & 0xff, ohci->card.index, - ohci->n_ir, ohci->n_it, ohci->quirks); + ohci->n_ir, ohci->n_it, ohci->quirks, + reg_read(ohci, OHCI1394_PhyUpperBound) ? + ", >4 GB phys DMA" : ""); return 0; diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig index 2f21b0bfe6534c..29c8cdda82a11d 100644 --- a/drivers/firmware/google/Kconfig +++ b/drivers/firmware/google/Kconfig @@ -12,8 +12,7 @@ menu "Google Firmware Drivers" config GOOGLE_SMI tristate "SMI interface for Google platforms" - depends on ACPI && DMI - select EFI + depends on ACPI && DMI && EFI select EFI_VARS help Say Y here if you want to enable SMI callbacks for Google diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 697338772b6480..903f24d28ba065 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -403,6 +403,7 @@ config GPIO_GRGPIO config GPIO_TB10X bool + select GENERIC_IRQ_CHIP select OF_GPIO comment "I2C GPIO expanders:" diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 233d088ac59fd6..f32357e2d78d89 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2013 Broadcom Corporation + * Copyright (C) 2012-2014 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -657,6 +657,6 @@ static struct platform_driver bcm_kona_gpio_driver = { module_platform_driver(bcm_kona_gpio_driver); -MODULE_AUTHOR("Broadcom"); +MODULE_AUTHOR("Broadcom Corporation "); MODULE_DESCRIPTION("Broadcom Kona GPIO Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index d3550274b8f7e6..3c2ba2ad0ada7a 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -97,3 +97,4 @@ module_platform_driver(clps711x_gpio_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alexander Shiyan "); MODULE_DESCRIPTION("CLPS711X GPIO driver"); +MODULE_ALIAS("platform:clps711x-gpio"); diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c index d1b50ef5fab869..e585163f1ad552 100644 --- a/drivers/gpio/gpio-intel-mid.c +++ b/drivers/gpio/gpio-intel-mid.c @@ -394,8 +394,8 @@ static const struct irq_domain_ops intel_gpio_irq_ops = { static int intel_gpio_runtime_idle(struct device *dev) { - pm_schedule_suspend(dev, 500); - return -EBUSY; + int err = pm_schedule_suspend(dev, 500); + return err ?: -EBUSY; } static const struct dev_pm_ops intel_gpio_pm_ops = { diff --git a/drivers/gpio/gpio-xtensa.c b/drivers/gpio/gpio-xtensa.c index 1d136eceda62db..7081304d6797b4 100644 --- a/drivers/gpio/gpio-xtensa.c +++ b/drivers/gpio/gpio-xtensa.c @@ -40,6 +40,8 @@ #error GPIO32 option is not enabled for your xtensa core variant #endif +#if XCHAL_HAVE_CP + static inline unsigned long enable_cp(unsigned long *cpenable) { unsigned long flags; @@ -57,6 +59,20 @@ static inline void disable_cp(unsigned long flags, unsigned long cpenable) local_irq_restore(flags); } +#else + +static inline unsigned long enable_cp(unsigned long *cpenable) +{ + *cpenable = 0; /* avoid uninitialized value warning */ + return 0; +} + +static inline void disable_cp(unsigned long flags, unsigned long cpenable) +{ +} + +#endif /* XCHAL_HAVE_CP */ + static int xtensa_impwire_get_direction(struct gpio_chip *gc, unsigned offset) { return 1; /* input only */ diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index f8642759116770..8e7fa4dbaed867 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -20,6 +20,10 @@ menuconfig DRM details. You should also select and configure AGP (/dev/agpgart) support if it is available for your platform. +config DRM_MIPI_DSI + bool + depends on DRM + config DRM_USB tristate depends on DRM @@ -188,6 +192,10 @@ source "drivers/gpu/drm/tilcdc/Kconfig" source "drivers/gpu/drm/qxl/Kconfig" +source "drivers/gpu/drm/bochs/Kconfig" + source "drivers/gpu/drm/msm/Kconfig" source "drivers/gpu/drm/tegra/Kconfig" + +source "drivers/gpu/drm/panel/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index cc08b845f9655a..292a79d6414627 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -18,6 +18,7 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \ drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o drm-$(CONFIG_PCI) += ati_pcigart.o +drm-$(CONFIG_DRM_PANEL) += drm_panel.o drm-usb-y := drm_usb.o @@ -31,6 +32,7 @@ obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o CFLAGS_drm_trace_points.o := -I$(src) obj-$(CONFIG_DRM) += drm.o +obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o obj-$(CONFIG_DRM_USB) += drm_usb.o obj-$(CONFIG_DRM_TTM) += ttm/ obj-$(CONFIG_DRM_TDFX) += tdfx/ @@ -56,6 +58,8 @@ obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/ obj-$(CONFIG_DRM_OMAP) += omapdrm/ obj-$(CONFIG_DRM_TILCDC) += tilcdc/ obj-$(CONFIG_DRM_QXL) += qxl/ +obj-$(CONFIG_DRM_BOCHS) += bochs/ obj-$(CONFIG_DRM_MSM) += msm/ obj-$(CONFIG_DRM_TEGRA) += tegra/ obj-y += i2c/ +obj-y += panel/ diff --git a/drivers/gpu/drm/armada/Kconfig b/drivers/gpu/drm/armada/Kconfig index 40d371521fe19f..50ae88ad4d76fb 100644 --- a/drivers/gpu/drm/armada/Kconfig +++ b/drivers/gpu/drm/armada/Kconfig @@ -5,6 +5,7 @@ config DRM_ARMADA select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER help Support the "LCD" controllers found on the Marvell Armada 510 devices. There are two controllers on the device, each controller diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 62d0ff3efddf9b..acf3a36c9ebc45 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -128,6 +128,7 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags) return -ENOMEM; } + platform_set_drvdata(dev->platformdev, dev); dev->dev_private = priv; /* Get the implementation specific driver data. */ @@ -381,7 +382,7 @@ static int armada_drm_probe(struct platform_device *pdev) static int armada_drm_remove(struct platform_device *pdev) { - drm_platform_exit(&armada_drm_driver, pdev); + drm_put_dev(platform_get_drvdata(pdev)); return 0; } diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c index 7b33e14e44aa17..a28640f47c2749 100644 --- a/drivers/gpu/drm/ast/ast_fb.c +++ b/drivers/gpu/drm/ast/ast_fb.c @@ -65,7 +65,7 @@ static void ast_dirty_update(struct ast_fbdev *afbdev, * then the BO is being moved and we should * store up the damage until later. */ - if (!in_interrupt()) + if (drm_can_sleep()) ret = ast_bo_reserve(bo, true); if (ret) { if (ret != -EBUSY) diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index af0b868a9dfd6c..50535fd5a88d25 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -189,53 +189,6 @@ static int ast_get_dram_info(struct drm_device *dev) return 0; } -uint32_t ast_get_max_dclk(struct drm_device *dev, int bpp) -{ - struct ast_private *ast = dev->dev_private; - uint32_t dclk, jreg; - uint32_t dram_bus_width, mclk, dram_bandwidth, actual_dram_bandwidth, dram_efficency = 500; - - dram_bus_width = ast->dram_bus_width; - mclk = ast->mclk; - - if (ast->chip == AST2100 || - ast->chip == AST1100 || - ast->chip == AST2200 || - ast->chip == AST2150 || - ast->dram_bus_width == 16) - dram_efficency = 600; - else if (ast->chip == AST2300) - dram_efficency = 400; - - dram_bandwidth = mclk * dram_bus_width * 2 / 8; - actual_dram_bandwidth = dram_bandwidth * dram_efficency / 1000; - - if (ast->chip == AST1180) - dclk = actual_dram_bandwidth / ((bpp + 1) / 8); - else { - jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); - if ((jreg & 0x08) && (ast->chip == AST2000)) - dclk = actual_dram_bandwidth / ((bpp + 1 + 16) / 8); - else if ((jreg & 0x08) && (bpp == 8)) - dclk = actual_dram_bandwidth / ((bpp + 1 + 24) / 8); - else - dclk = actual_dram_bandwidth / ((bpp + 1) / 8); - } - - if (ast->chip == AST2100 || - ast->chip == AST2200 || - ast->chip == AST2300 || - ast->chip == AST1180) { - if (dclk > 200) - dclk = 200; - } else { - if (dclk > 165) - dclk = 165; - } - - return dclk; -} - static void ast_user_framebuffer_destroy(struct drm_framebuffer *fb) { struct ast_framebuffer *ast_fb = to_ast_framebuffer(fb); @@ -449,7 +402,7 @@ int ast_dumb_create(struct drm_file *file, return 0; } -void ast_bo_unref(struct ast_bo **bo) +static void ast_bo_unref(struct ast_bo **bo) { struct ttm_buffer_object *tbo; diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 7fc9f7272b56e7..cca063b110831a 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -404,7 +404,7 @@ static void ast_set_ext_reg(struct drm_crtc *crtc, struct drm_display_mode *mode } } -void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mode, +static void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mode, struct ast_vbios_mode_info *vbios_mode) { struct ast_private *ast = dev->dev_private; @@ -415,7 +415,7 @@ void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mode, ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, jreg); } -bool ast_set_dac_reg(struct drm_crtc *crtc, struct drm_display_mode *mode, +static bool ast_set_dac_reg(struct drm_crtc *crtc, struct drm_display_mode *mode, struct ast_vbios_mode_info *vbios_mode) { switch (crtc->fb->bits_per_pixel) { @@ -427,7 +427,7 @@ bool ast_set_dac_reg(struct drm_crtc *crtc, struct drm_display_mode *mode, return true; } -void ast_set_start_address_crt1(struct drm_crtc *crtc, unsigned offset) +static void ast_set_start_address_crt1(struct drm_crtc *crtc, unsigned offset) { struct ast_private *ast = crtc->dev->dev_private; u32 addr; @@ -623,7 +623,7 @@ static const struct drm_crtc_funcs ast_crtc_funcs = { .destroy = ast_crtc_destroy, }; -int ast_crtc_init(struct drm_device *dev) +static int ast_crtc_init(struct drm_device *dev) { struct ast_crtc *crtc; int i; @@ -710,7 +710,7 @@ static const struct drm_encoder_helper_funcs ast_enc_helper_funcs = { .mode_set = ast_encoder_mode_set, }; -int ast_encoder_init(struct drm_device *dev) +static int ast_encoder_init(struct drm_device *dev) { struct ast_encoder *ast_encoder; @@ -777,7 +777,7 @@ static const struct drm_connector_funcs ast_connector_funcs = { .destroy = ast_connector_destroy, }; -int ast_connector_init(struct drm_device *dev) +static int ast_connector_init(struct drm_device *dev) { struct ast_connector *ast_connector; struct drm_connector *connector; @@ -810,7 +810,7 @@ int ast_connector_init(struct drm_device *dev) } /* allocate cursor cache and pin at start of VRAM */ -int ast_cursor_init(struct drm_device *dev) +static int ast_cursor_init(struct drm_device *dev) { struct ast_private *ast = dev->dev_private; int size; @@ -847,7 +847,7 @@ int ast_cursor_init(struct drm_device *dev) return ret; } -void ast_cursor_fini(struct drm_device *dev) +static void ast_cursor_fini(struct drm_device *dev) { struct ast_private *ast = dev->dev_private; ttm_bo_kunmap(&ast->cache_kmap); @@ -965,7 +965,7 @@ static void ast_i2c_destroy(struct ast_i2c_chan *i2c) kfree(i2c); } -void ast_show_cursor(struct drm_crtc *crtc) +static void ast_show_cursor(struct drm_crtc *crtc) { struct ast_private *ast = crtc->dev->dev_private; u8 jreg; @@ -976,7 +976,7 @@ void ast_show_cursor(struct drm_crtc *crtc) ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, jreg); } -void ast_hide_cursor(struct drm_crtc *crtc) +static void ast_hide_cursor(struct drm_crtc *crtc) { struct ast_private *ast = crtc->dev->dev_private; ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, 0x00); diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c index 32aecb34dbced7..4ea9b17ac17a9c 100644 --- a/drivers/gpu/drm/ast/ast_ttm.c +++ b/drivers/gpu/drm/ast/ast_ttm.c @@ -80,7 +80,7 @@ static int ast_ttm_global_init(struct ast_private *ast) return 0; } -void +static void ast_ttm_global_release(struct ast_private *ast) { if (ast->ttm.mem_global_ref.release == NULL) @@ -102,7 +102,7 @@ static void ast_bo_ttm_destroy(struct ttm_buffer_object *tbo) kfree(bo); } -bool ast_ttm_bo_is_ast_bo(struct ttm_buffer_object *bo) +static bool ast_ttm_bo_is_ast_bo(struct ttm_buffer_object *bo) { if (bo->destroy == &ast_bo_ttm_destroy) return true; @@ -208,7 +208,7 @@ static struct ttm_backend_func ast_tt_backend_func = { }; -struct ttm_tt *ast_ttm_tt_create(struct ttm_bo_device *bdev, +static struct ttm_tt *ast_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size, uint32_t page_flags, struct page *dummy_read_page) { diff --git a/drivers/gpu/drm/bochs/Kconfig b/drivers/gpu/drm/bochs/Kconfig new file mode 100644 index 00000000000000..c8fcf12019f09c --- /dev/null +++ b/drivers/gpu/drm/bochs/Kconfig @@ -0,0 +1,11 @@ +config DRM_BOCHS + tristate "DRM Support for bochs dispi vga interface (qemu stdvga)" + depends on DRM && PCI + select DRM_KMS_HELPER + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select DRM_TTM + help + Choose this option for qemu. + If M is selected the module will be called bochs-drm. diff --git a/drivers/gpu/drm/bochs/Makefile b/drivers/gpu/drm/bochs/Makefile new file mode 100644 index 00000000000000..844a556149207d --- /dev/null +++ b/drivers/gpu/drm/bochs/Makefile @@ -0,0 +1,4 @@ +ccflags-y := -Iinclude/drm +bochs-drm-y := bochs_drv.o bochs_mm.o bochs_kms.o bochs_fbdev.o bochs_hw.o + +obj-$(CONFIG_DRM_BOCHS) += bochs-drm.o diff --git a/drivers/gpu/drm/bochs/bochs.h b/drivers/gpu/drm/bochs/bochs.h new file mode 100644 index 00000000000000..741965c001a687 --- /dev/null +++ b/drivers/gpu/drm/bochs/bochs.h @@ -0,0 +1,164 @@ +#include +#include + +#include +#include +#include +#include + +#include +#include + +/* ---------------------------------------------------------------------- */ + +#define VBE_DISPI_IOPORT_INDEX 0x01CE +#define VBE_DISPI_IOPORT_DATA 0x01CF + +#define VBE_DISPI_INDEX_ID 0x0 +#define VBE_DISPI_INDEX_XRES 0x1 +#define VBE_DISPI_INDEX_YRES 0x2 +#define VBE_DISPI_INDEX_BPP 0x3 +#define VBE_DISPI_INDEX_ENABLE 0x4 +#define VBE_DISPI_INDEX_BANK 0x5 +#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6 +#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 +#define VBE_DISPI_INDEX_X_OFFSET 0x8 +#define VBE_DISPI_INDEX_Y_OFFSET 0x9 +#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa + +#define VBE_DISPI_ID0 0xB0C0 +#define VBE_DISPI_ID1 0xB0C1 +#define VBE_DISPI_ID2 0xB0C2 +#define VBE_DISPI_ID3 0xB0C3 +#define VBE_DISPI_ID4 0xB0C4 +#define VBE_DISPI_ID5 0xB0C5 + +#define VBE_DISPI_DISABLED 0x00 +#define VBE_DISPI_ENABLED 0x01 +#define VBE_DISPI_GETCAPS 0x02 +#define VBE_DISPI_8BIT_DAC 0x20 +#define VBE_DISPI_LFB_ENABLED 0x40 +#define VBE_DISPI_NOCLEARMEM 0x80 + +/* ---------------------------------------------------------------------- */ + +enum bochs_types { + BOCHS_QEMU_STDVGA, + BOCHS_UNKNOWN, +}; + +struct bochs_framebuffer { + struct drm_framebuffer base; + struct drm_gem_object *obj; +}; + +struct bochs_device { + /* hw */ + void __iomem *mmio; + int ioports; + void __iomem *fb_map; + unsigned long fb_base; + unsigned long fb_size; + + /* mode */ + u16 xres; + u16 yres; + u16 yres_virtual; + u32 stride; + u32 bpp; + + /* drm */ + struct drm_device *dev; + struct drm_crtc crtc; + struct drm_encoder encoder; + struct drm_connector connector; + bool mode_config_initialized; + + /* ttm */ + struct { + struct drm_global_reference mem_global_ref; + struct ttm_bo_global_ref bo_global_ref; + struct ttm_bo_device bdev; + bool initialized; + } ttm; + + /* fbdev */ + struct { + struct bochs_framebuffer gfb; + struct drm_fb_helper helper; + int size; + int x1, y1, x2, y2; /* dirty rect */ + spinlock_t dirty_lock; + bool initialized; + } fb; +}; + +#define to_bochs_framebuffer(x) container_of(x, struct bochs_framebuffer, base) + +struct bochs_bo { + struct ttm_buffer_object bo; + struct ttm_placement placement; + struct ttm_bo_kmap_obj kmap; + struct drm_gem_object gem; + u32 placements[3]; + int pin_count; +}; + +static inline struct bochs_bo *bochs_bo(struct ttm_buffer_object *bo) +{ + return container_of(bo, struct bochs_bo, bo); +} + +static inline struct bochs_bo *gem_to_bochs_bo(struct drm_gem_object *gem) +{ + return container_of(gem, struct bochs_bo, gem); +} + +#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT) + +static inline u64 bochs_bo_mmap_offset(struct bochs_bo *bo) +{ + return drm_vma_node_offset_addr(&bo->bo.vma_node); +} + +/* ---------------------------------------------------------------------- */ + +/* bochs_hw.c */ +int bochs_hw_init(struct drm_device *dev, uint32_t flags); +void bochs_hw_fini(struct drm_device *dev); + +void bochs_hw_setmode(struct bochs_device *bochs, + struct drm_display_mode *mode); +void bochs_hw_setbase(struct bochs_device *bochs, + int x, int y, u64 addr); + +/* bochs_mm.c */ +int bochs_mm_init(struct bochs_device *bochs); +void bochs_mm_fini(struct bochs_device *bochs); +int bochs_mmap(struct file *filp, struct vm_area_struct *vma); + +int bochs_gem_create(struct drm_device *dev, u32 size, bool iskernel, + struct drm_gem_object **obj); +int bochs_gem_init_object(struct drm_gem_object *obj); +void bochs_gem_free_object(struct drm_gem_object *obj); +int bochs_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args); +int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, + uint32_t handle, uint64_t *offset); + +int bochs_framebuffer_init(struct drm_device *dev, + struct bochs_framebuffer *gfb, + struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_gem_object *obj); +int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr); +int bochs_bo_unpin(struct bochs_bo *bo); + +extern const struct drm_mode_config_funcs bochs_mode_funcs; + +/* bochs_kms.c */ +int bochs_kms_init(struct bochs_device *bochs); +void bochs_kms_fini(struct bochs_device *bochs); + +/* bochs_fbdev.c */ +int bochs_fbdev_init(struct bochs_device *bochs); +void bochs_fbdev_fini(struct bochs_device *bochs); diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c new file mode 100644 index 00000000000000..395bba261c9a6d --- /dev/null +++ b/drivers/gpu/drm/bochs/bochs_drv.c @@ -0,0 +1,178 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include + +#include "bochs.h" + +static bool enable_fbdev = true; +module_param_named(fbdev, enable_fbdev, bool, 0444); +MODULE_PARM_DESC(fbdev, "register fbdev device"); + +/* ---------------------------------------------------------------------- */ +/* drm interface */ + +static int bochs_unload(struct drm_device *dev) +{ + struct bochs_device *bochs = dev->dev_private; + + bochs_fbdev_fini(bochs); + bochs_kms_fini(bochs); + bochs_mm_fini(bochs); + bochs_hw_fini(dev); + kfree(bochs); + dev->dev_private = NULL; + return 0; +} + +static int bochs_load(struct drm_device *dev, unsigned long flags) +{ + struct bochs_device *bochs; + int ret; + + bochs = kzalloc(sizeof(*bochs), GFP_KERNEL); + if (bochs == NULL) + return -ENOMEM; + dev->dev_private = bochs; + bochs->dev = dev; + + ret = bochs_hw_init(dev, flags); + if (ret) + goto err; + + ret = bochs_mm_init(bochs); + if (ret) + goto err; + + ret = bochs_kms_init(bochs); + if (ret) + goto err; + + if (enable_fbdev) + bochs_fbdev_init(bochs); + + return 0; + +err: + bochs_unload(dev); + return ret; +} + +static const struct file_operations bochs_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .unlocked_ioctl = drm_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = drm_compat_ioctl, +#endif + .poll = drm_poll, + .read = drm_read, + .llseek = no_llseek, + .mmap = bochs_mmap, +}; + +static struct drm_driver bochs_driver = { + .driver_features = DRIVER_GEM | DRIVER_MODESET, + .load = bochs_load, + .unload = bochs_unload, + .fops = &bochs_fops, + .name = "bochs-drm", + .desc = "bochs dispi vga interface (qemu stdvga)", + .date = "20130925", + .major = 1, + .minor = 0, + .gem_free_object = bochs_gem_free_object, + .dumb_create = bochs_dumb_create, + .dumb_map_offset = bochs_dumb_mmap_offset, + .dumb_destroy = drm_gem_dumb_destroy, +}; + +/* ---------------------------------------------------------------------- */ +/* pci interface */ + +static int bochs_kick_out_firmware_fb(struct pci_dev *pdev) +{ + struct apertures_struct *ap; + + ap = alloc_apertures(1); + if (!ap) + return -ENOMEM; + + ap->ranges[0].base = pci_resource_start(pdev, 0); + ap->ranges[0].size = pci_resource_len(pdev, 0); + remove_conflicting_framebuffers(ap, "bochsdrmfb", false); + kfree(ap); + + return 0; +} + +static int bochs_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int ret; + + ret = bochs_kick_out_firmware_fb(pdev); + if (ret) + return ret; + + return drm_get_pci_dev(pdev, ent, &bochs_driver); +} + +static void bochs_pci_remove(struct pci_dev *pdev) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + + drm_put_dev(dev); +} + +static DEFINE_PCI_DEVICE_TABLE(bochs_pci_tbl) = { + { + .vendor = 0x1234, + .device = 0x1111, + .subvendor = 0x1af4, + .subdevice = 0x1100, + .driver_data = BOCHS_QEMU_STDVGA, + }, + { + .vendor = 0x1234, + .device = 0x1111, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = BOCHS_UNKNOWN, + }, + { /* end of list */ } +}; + +static struct pci_driver bochs_pci_driver = { + .name = "bochs-drm", + .id_table = bochs_pci_tbl, + .probe = bochs_pci_probe, + .remove = bochs_pci_remove, +}; + +/* ---------------------------------------------------------------------- */ +/* module init/exit */ + +static int __init bochs_init(void) +{ + return drm_pci_init(&bochs_driver, &bochs_pci_driver); +} + +static void __exit bochs_exit(void) +{ + drm_pci_exit(&bochs_driver, &bochs_pci_driver); +} + +module_init(bochs_init); +module_exit(bochs_exit); + +MODULE_DEVICE_TABLE(pci, bochs_pci_tbl); +MODULE_AUTHOR("Gerd Hoffmann "); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c new file mode 100644 index 00000000000000..4da5206b7cc975 --- /dev/null +++ b/drivers/gpu/drm/bochs/bochs_fbdev.c @@ -0,0 +1,215 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "bochs.h" + +/* ---------------------------------------------------------------------- */ + +static struct fb_ops bochsfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = drm_fb_helper_check_var, + .fb_set_par = drm_fb_helper_set_par, + .fb_fillrect = sys_fillrect, + .fb_copyarea = sys_copyarea, + .fb_imageblit = sys_imageblit, + .fb_pan_display = drm_fb_helper_pan_display, + .fb_blank = drm_fb_helper_blank, + .fb_setcmap = drm_fb_helper_setcmap, +}; + +static int bochsfb_create_object(struct bochs_device *bochs, + struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_gem_object **gobj_p) +{ + struct drm_device *dev = bochs->dev; + struct drm_gem_object *gobj; + u32 size; + int ret = 0; + + size = mode_cmd->pitches[0] * mode_cmd->height; + ret = bochs_gem_create(dev, size, true, &gobj); + if (ret) + return ret; + + *gobj_p = gobj; + return ret; +} + +static int bochsfb_create(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) +{ + struct bochs_device *bochs = + container_of(helper, struct bochs_device, fb.helper); + struct drm_device *dev = bochs->dev; + struct fb_info *info; + struct drm_framebuffer *fb; + struct drm_mode_fb_cmd2 mode_cmd; + struct device *device = &dev->pdev->dev; + struct drm_gem_object *gobj = NULL; + struct bochs_bo *bo = NULL; + int size, ret; + + if (sizes->surface_bpp != 32) + return -EINVAL; + + mode_cmd.width = sizes->surface_width; + mode_cmd.height = sizes->surface_height; + mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8); + mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, + sizes->surface_depth); + size = mode_cmd.pitches[0] * mode_cmd.height; + + /* alloc, pin & map bo */ + ret = bochsfb_create_object(bochs, &mode_cmd, &gobj); + if (ret) { + DRM_ERROR("failed to create fbcon backing object %d\n", ret); + return ret; + } + + bo = gem_to_bochs_bo(gobj); + + ret = ttm_bo_reserve(&bo->bo, true, false, false, 0); + if (ret) + return ret; + + ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL); + if (ret) { + DRM_ERROR("failed to pin fbcon\n"); + ttm_bo_unreserve(&bo->bo); + return ret; + } + + ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, + &bo->kmap); + if (ret) { + DRM_ERROR("failed to kmap fbcon\n"); + ttm_bo_unreserve(&bo->bo); + return ret; + } + + ttm_bo_unreserve(&bo->bo); + + /* init fb device */ + info = framebuffer_alloc(0, device); + if (info == NULL) + return -ENOMEM; + + info->par = &bochs->fb.helper; + + ret = bochs_framebuffer_init(bochs->dev, &bochs->fb.gfb, &mode_cmd, gobj); + if (ret) + return ret; + + bochs->fb.size = size; + + /* setup helper */ + fb = &bochs->fb.gfb.base; + bochs->fb.helper.fb = fb; + bochs->fb.helper.fbdev = info; + + strcpy(info->fix.id, "bochsdrmfb"); + + info->flags = FBINFO_DEFAULT; + info->fbops = &bochsfb_ops; + + drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); + drm_fb_helper_fill_var(info, &bochs->fb.helper, sizes->fb_width, + sizes->fb_height); + + info->screen_base = bo->kmap.virtual; + info->screen_size = size; + +#if 0 + /* FIXME: get this right for mmap(/dev/fb0) */ + info->fix.smem_start = bochs_bo_mmap_offset(bo); + info->fix.smem_len = size; +#endif + + ret = fb_alloc_cmap(&info->cmap, 256, 0); + if (ret) { + DRM_ERROR("%s: can't allocate color map\n", info->fix.id); + return -ENOMEM; + } + + return 0; +} + +static int bochs_fbdev_destroy(struct bochs_device *bochs) +{ + struct bochs_framebuffer *gfb = &bochs->fb.gfb; + struct fb_info *info; + + DRM_DEBUG_DRIVER("\n"); + + if (bochs->fb.helper.fbdev) { + info = bochs->fb.helper.fbdev; + + unregister_framebuffer(info); + if (info->cmap.len) + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); + } + + if (gfb->obj) { + drm_gem_object_unreference_unlocked(gfb->obj); + gfb->obj = NULL; + } + + drm_fb_helper_fini(&bochs->fb.helper); + drm_framebuffer_unregister_private(&gfb->base); + drm_framebuffer_cleanup(&gfb->base); + + return 0; +} + +void bochs_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, + u16 blue, int regno) +{ +} + +void bochs_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, + u16 *blue, int regno) +{ + *red = regno; + *green = regno; + *blue = regno; +} + +static struct drm_fb_helper_funcs bochs_fb_helper_funcs = { + .gamma_set = bochs_fb_gamma_set, + .gamma_get = bochs_fb_gamma_get, + .fb_probe = bochsfb_create, +}; + +int bochs_fbdev_init(struct bochs_device *bochs) +{ + int ret; + + bochs->fb.helper.funcs = &bochs_fb_helper_funcs; + spin_lock_init(&bochs->fb.dirty_lock); + + ret = drm_fb_helper_init(bochs->dev, &bochs->fb.helper, + 1, 1); + if (ret) + return ret; + + drm_fb_helper_single_add_all_connectors(&bochs->fb.helper); + drm_helper_disable_unused_functions(bochs->dev); + drm_fb_helper_initial_config(&bochs->fb.helper, 32); + + bochs->fb.initialized = true; + return 0; +} + +void bochs_fbdev_fini(struct bochs_device *bochs) +{ + if (!bochs->fb.initialized) + return; + + bochs_fbdev_destroy(bochs); + bochs->fb.initialized = false; +} diff --git a/drivers/gpu/drm/bochs/bochs_hw.c b/drivers/gpu/drm/bochs/bochs_hw.c new file mode 100644 index 00000000000000..dbe619e6aab4e2 --- /dev/null +++ b/drivers/gpu/drm/bochs/bochs_hw.c @@ -0,0 +1,177 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "bochs.h" + +/* ---------------------------------------------------------------------- */ + +static void bochs_vga_writeb(struct bochs_device *bochs, u16 ioport, u8 val) +{ + if (WARN_ON(ioport < 0x3c0 || ioport > 0x3df)) + return; + + if (bochs->mmio) { + int offset = ioport - 0x3c0 + 0x400; + writeb(val, bochs->mmio + offset); + } else { + outb(val, ioport); + } +} + +static u16 bochs_dispi_read(struct bochs_device *bochs, u16 reg) +{ + u16 ret = 0; + + if (bochs->mmio) { + int offset = 0x500 + (reg << 1); + ret = readw(bochs->mmio + offset); + } else { + outw(reg, VBE_DISPI_IOPORT_INDEX); + ret = inw(VBE_DISPI_IOPORT_DATA); + } + return ret; +} + +static void bochs_dispi_write(struct bochs_device *bochs, u16 reg, u16 val) +{ + if (bochs->mmio) { + int offset = 0x500 + (reg << 1); + writew(val, bochs->mmio + offset); + } else { + outw(reg, VBE_DISPI_IOPORT_INDEX); + outw(val, VBE_DISPI_IOPORT_DATA); + } +} + +int bochs_hw_init(struct drm_device *dev, uint32_t flags) +{ + struct bochs_device *bochs = dev->dev_private; + struct pci_dev *pdev = dev->pdev; + unsigned long addr, size, mem, ioaddr, iosize; + u16 id; + + if (/* (ent->driver_data == BOCHS_QEMU_STDVGA) && */ + (pdev->resource[2].flags & IORESOURCE_MEM)) { + /* mmio bar with vga and bochs registers present */ + if (pci_request_region(pdev, 2, "bochs-drm") != 0) { + DRM_ERROR("Cannot request mmio region\n"); + return -EBUSY; + } + ioaddr = pci_resource_start(pdev, 2); + iosize = pci_resource_len(pdev, 2); + bochs->mmio = ioremap(ioaddr, iosize); + if (bochs->mmio == NULL) { + DRM_ERROR("Cannot map mmio region\n"); + return -ENOMEM; + } + } else { + ioaddr = VBE_DISPI_IOPORT_INDEX; + iosize = 2; + if (!request_region(ioaddr, iosize, "bochs-drm")) { + DRM_ERROR("Cannot request ioports\n"); + return -EBUSY; + } + bochs->ioports = 1; + } + + id = bochs_dispi_read(bochs, VBE_DISPI_INDEX_ID); + mem = bochs_dispi_read(bochs, VBE_DISPI_INDEX_VIDEO_MEMORY_64K) + * 64 * 1024; + if ((id & 0xfff0) != VBE_DISPI_ID0) { + DRM_ERROR("ID mismatch\n"); + return -ENODEV; + } + + if ((pdev->resource[0].flags & IORESOURCE_MEM) == 0) + return -ENODEV; + addr = pci_resource_start(pdev, 0); + size = pci_resource_len(pdev, 0); + if (addr == 0) + return -ENODEV; + if (size != mem) { + DRM_ERROR("Size mismatch: pci=%ld, bochs=%ld\n", + size, mem); + size = min(size, mem); + } + + if (pci_request_region(pdev, 0, "bochs-drm") != 0) { + DRM_ERROR("Cannot request framebuffer\n"); + return -EBUSY; + } + + bochs->fb_map = ioremap(addr, size); + if (bochs->fb_map == NULL) { + DRM_ERROR("Cannot map framebuffer\n"); + return -ENOMEM; + } + bochs->fb_base = addr; + bochs->fb_size = size; + + DRM_INFO("Found bochs VGA, ID 0x%x.\n", id); + DRM_INFO("Framebuffer size %ld kB @ 0x%lx, %s @ 0x%lx.\n", + size / 1024, addr, + bochs->ioports ? "ioports" : "mmio", + ioaddr); + return 0; +} + +void bochs_hw_fini(struct drm_device *dev) +{ + struct bochs_device *bochs = dev->dev_private; + + if (bochs->mmio) + iounmap(bochs->mmio); + if (bochs->ioports) + release_region(VBE_DISPI_IOPORT_INDEX, 2); + if (bochs->fb_map) + iounmap(bochs->fb_map); + pci_release_regions(dev->pdev); +} + +void bochs_hw_setmode(struct bochs_device *bochs, + struct drm_display_mode *mode) +{ + bochs->xres = mode->hdisplay; + bochs->yres = mode->vdisplay; + bochs->bpp = 32; + bochs->stride = mode->hdisplay * (bochs->bpp / 8); + bochs->yres_virtual = bochs->fb_size / bochs->stride; + + DRM_DEBUG_DRIVER("%dx%d @ %d bpp, vy %d\n", + bochs->xres, bochs->yres, bochs->bpp, + bochs->yres_virtual); + + bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */ + + bochs_dispi_write(bochs, VBE_DISPI_INDEX_BPP, bochs->bpp); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_XRES, bochs->xres); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_YRES, bochs->yres); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_BANK, 0); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_WIDTH, bochs->xres); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_HEIGHT, + bochs->yres_virtual); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, 0); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, 0); + + bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE, + VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED); +} + +void bochs_hw_setbase(struct bochs_device *bochs, + int x, int y, u64 addr) +{ + unsigned long offset = (unsigned long)addr + + y * bochs->stride + + x * (bochs->bpp / 8); + int vy = offset / bochs->stride; + int vx = (offset % bochs->stride) * 8 / bochs->bpp; + + DRM_DEBUG_DRIVER("x %d, y %d, addr %llx -> offset %lx, vx %d, vy %d\n", + x, y, addr, offset, vx, vy); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, vx); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, vy); +} diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c new file mode 100644 index 00000000000000..62ec7d4b38161a --- /dev/null +++ b/drivers/gpu/drm/bochs/bochs_kms.c @@ -0,0 +1,294 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "bochs.h" + +static int defx = 1024; +static int defy = 768; + +module_param(defx, int, 0444); +module_param(defy, int, 0444); +MODULE_PARM_DESC(defx, "default x resolution"); +MODULE_PARM_DESC(defy, "default y resolution"); + +/* ---------------------------------------------------------------------- */ + +static void bochs_crtc_load_lut(struct drm_crtc *crtc) +{ +} + +static void bochs_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + switch (mode) { + case DRM_MODE_DPMS_ON: + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + default: + return; + } +} + +static bool bochs_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) +{ + struct bochs_device *bochs = + container_of(crtc, struct bochs_device, crtc); + struct bochs_framebuffer *bochs_fb; + struct bochs_bo *bo; + u64 gpu_addr = 0; + int ret; + + if (old_fb) { + bochs_fb = to_bochs_framebuffer(old_fb); + bo = gem_to_bochs_bo(bochs_fb->obj); + ret = ttm_bo_reserve(&bo->bo, true, false, false, 0); + if (ret) { + DRM_ERROR("failed to reserve old_fb bo\n"); + } else { + bochs_bo_unpin(bo); + ttm_bo_unreserve(&bo->bo); + } + } + + if (WARN_ON(crtc->fb == NULL)) + return -EINVAL; + + bochs_fb = to_bochs_framebuffer(crtc->fb); + bo = gem_to_bochs_bo(bochs_fb->obj); + ret = ttm_bo_reserve(&bo->bo, true, false, false, 0); + if (ret) + return ret; + + ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); + if (ret) { + ttm_bo_unreserve(&bo->bo); + return ret; + } + + ttm_bo_unreserve(&bo->bo); + bochs_hw_setbase(bochs, x, y, gpu_addr); + return 0; +} + +static int bochs_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, struct drm_framebuffer *old_fb) +{ + struct bochs_device *bochs = + container_of(crtc, struct bochs_device, crtc); + + bochs_hw_setmode(bochs, mode); + bochs_crtc_mode_set_base(crtc, x, y, old_fb); + return 0; +} + +static void bochs_crtc_prepare(struct drm_crtc *crtc) +{ +} + +static void bochs_crtc_commit(struct drm_crtc *crtc) +{ +} + +static void bochs_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, + u16 *blue, uint32_t start, uint32_t size) +{ +} + +/* These provide the minimum set of functions required to handle a CRTC */ +static const struct drm_crtc_funcs bochs_crtc_funcs = { + .gamma_set = bochs_crtc_gamma_set, + .set_config = drm_crtc_helper_set_config, + .destroy = drm_crtc_cleanup, +}; + +static const struct drm_crtc_helper_funcs bochs_helper_funcs = { + .dpms = bochs_crtc_dpms, + .mode_fixup = bochs_crtc_mode_fixup, + .mode_set = bochs_crtc_mode_set, + .mode_set_base = bochs_crtc_mode_set_base, + .prepare = bochs_crtc_prepare, + .commit = bochs_crtc_commit, + .load_lut = bochs_crtc_load_lut, +}; + +static void bochs_crtc_init(struct drm_device *dev) +{ + struct bochs_device *bochs = dev->dev_private; + struct drm_crtc *crtc = &bochs->crtc; + + drm_crtc_init(dev, crtc, &bochs_crtc_funcs); + drm_mode_crtc_set_gamma_size(crtc, 256); + drm_crtc_helper_add(crtc, &bochs_helper_funcs); +} + +static bool bochs_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void bochs_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ +} + +static void bochs_encoder_dpms(struct drm_encoder *encoder, int state) +{ +} + +static void bochs_encoder_prepare(struct drm_encoder *encoder) +{ +} + +static void bochs_encoder_commit(struct drm_encoder *encoder) +{ +} + +static const struct drm_encoder_helper_funcs bochs_encoder_helper_funcs = { + .dpms = bochs_encoder_dpms, + .mode_fixup = bochs_encoder_mode_fixup, + .mode_set = bochs_encoder_mode_set, + .prepare = bochs_encoder_prepare, + .commit = bochs_encoder_commit, +}; + +static const struct drm_encoder_funcs bochs_encoder_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static void bochs_encoder_init(struct drm_device *dev) +{ + struct bochs_device *bochs = dev->dev_private; + struct drm_encoder *encoder = &bochs->encoder; + + encoder->possible_crtcs = 0x1; + drm_encoder_init(dev, encoder, &bochs_encoder_encoder_funcs, + DRM_MODE_ENCODER_DAC); + drm_encoder_helper_add(encoder, &bochs_encoder_helper_funcs); +} + + +int bochs_connector_get_modes(struct drm_connector *connector) +{ + int count; + + count = drm_add_modes_noedid(connector, 8192, 8192); + drm_set_preferred_mode(connector, defx, defy); + return count; +} + +static int bochs_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct bochs_device *bochs = + container_of(connector, struct bochs_device, connector); + unsigned long size = mode->hdisplay * mode->vdisplay * 4; + + /* + * Make sure we can fit two framebuffers into video memory. + * This allows up to 1600x1200 with 16 MB (default size). + * If you want more try this: + * 'qemu -vga std -global VGA.vgamem_mb=32 $otherargs' + */ + if (size * 2 > bochs->fb_size) + return MODE_BAD; + + return MODE_OK; +} + +static struct drm_encoder * +bochs_connector_best_encoder(struct drm_connector *connector) +{ + int enc_id = connector->encoder_ids[0]; + struct drm_mode_object *obj; + struct drm_encoder *encoder; + + /* pick the encoder ids */ + if (enc_id) { + obj = drm_mode_object_find(connector->dev, enc_id, + DRM_MODE_OBJECT_ENCODER); + if (!obj) + return NULL; + encoder = obj_to_encoder(obj); + return encoder; + } + return NULL; +} + +static enum drm_connector_status bochs_connector_detect(struct drm_connector + *connector, bool force) +{ + return connector_status_connected; +} + +struct drm_connector_helper_funcs bochs_connector_connector_helper_funcs = { + .get_modes = bochs_connector_get_modes, + .mode_valid = bochs_connector_mode_valid, + .best_encoder = bochs_connector_best_encoder, +}; + +struct drm_connector_funcs bochs_connector_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .detect = bochs_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, +}; + +static void bochs_connector_init(struct drm_device *dev) +{ + struct bochs_device *bochs = dev->dev_private; + struct drm_connector *connector = &bochs->connector; + + drm_connector_init(dev, connector, &bochs_connector_connector_funcs, + DRM_MODE_CONNECTOR_VIRTUAL); + drm_connector_helper_add(connector, + &bochs_connector_connector_helper_funcs); +} + + +int bochs_kms_init(struct bochs_device *bochs) +{ + drm_mode_config_init(bochs->dev); + bochs->mode_config_initialized = true; + + bochs->dev->mode_config.max_width = 8192; + bochs->dev->mode_config.max_height = 8192; + + bochs->dev->mode_config.fb_base = bochs->fb_base; + bochs->dev->mode_config.preferred_depth = 24; + bochs->dev->mode_config.prefer_shadow = 0; + + bochs->dev->mode_config.funcs = (void *)&bochs_mode_funcs; + + bochs_crtc_init(bochs->dev); + bochs_encoder_init(bochs->dev); + bochs_connector_init(bochs->dev); + drm_mode_connector_attach_encoder(&bochs->connector, + &bochs->encoder); + + return 0; +} + +void bochs_kms_fini(struct bochs_device *bochs) +{ + if (bochs->mode_config_initialized) { + drm_mode_config_cleanup(bochs->dev); + bochs->mode_config_initialized = false; + } +} diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c new file mode 100644 index 00000000000000..ce6858765b378d --- /dev/null +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -0,0 +1,546 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "bochs.h" + +static void bochs_ttm_placement(struct bochs_bo *bo, int domain); + +/* ---------------------------------------------------------------------- */ + +static inline struct bochs_device *bochs_bdev(struct ttm_bo_device *bd) +{ + return container_of(bd, struct bochs_device, ttm.bdev); +} + +static int bochs_ttm_mem_global_init(struct drm_global_reference *ref) +{ + return ttm_mem_global_init(ref->object); +} + +static void bochs_ttm_mem_global_release(struct drm_global_reference *ref) +{ + ttm_mem_global_release(ref->object); +} + +static int bochs_ttm_global_init(struct bochs_device *bochs) +{ + struct drm_global_reference *global_ref; + int r; + + global_ref = &bochs->ttm.mem_global_ref; + global_ref->global_type = DRM_GLOBAL_TTM_MEM; + global_ref->size = sizeof(struct ttm_mem_global); + global_ref->init = &bochs_ttm_mem_global_init; + global_ref->release = &bochs_ttm_mem_global_release; + r = drm_global_item_ref(global_ref); + if (r != 0) { + DRM_ERROR("Failed setting up TTM memory accounting " + "subsystem.\n"); + return r; + } + + bochs->ttm.bo_global_ref.mem_glob = + bochs->ttm.mem_global_ref.object; + global_ref = &bochs->ttm.bo_global_ref.ref; + global_ref->global_type = DRM_GLOBAL_TTM_BO; + global_ref->size = sizeof(struct ttm_bo_global); + global_ref->init = &ttm_bo_global_init; + global_ref->release = &ttm_bo_global_release; + r = drm_global_item_ref(global_ref); + if (r != 0) { + DRM_ERROR("Failed setting up TTM BO subsystem.\n"); + drm_global_item_unref(&bochs->ttm.mem_global_ref); + return r; + } + + return 0; +} + +static void bochs_ttm_global_release(struct bochs_device *bochs) +{ + if (bochs->ttm.mem_global_ref.release == NULL) + return; + + drm_global_item_unref(&bochs->ttm.bo_global_ref.ref); + drm_global_item_unref(&bochs->ttm.mem_global_ref); + bochs->ttm.mem_global_ref.release = NULL; +} + + +static void bochs_bo_ttm_destroy(struct ttm_buffer_object *tbo) +{ + struct bochs_bo *bo; + + bo = container_of(tbo, struct bochs_bo, bo); + drm_gem_object_release(&bo->gem); + kfree(bo); +} + +static bool bochs_ttm_bo_is_bochs_bo(struct ttm_buffer_object *bo) +{ + if (bo->destroy == &bochs_bo_ttm_destroy) + return true; + return false; +} + +static int bochs_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, + struct ttm_mem_type_manager *man) +{ + switch (type) { + case TTM_PL_SYSTEM: + man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; + man->available_caching = TTM_PL_MASK_CACHING; + man->default_caching = TTM_PL_FLAG_CACHED; + break; + case TTM_PL_VRAM: + man->func = &ttm_bo_manager_func; + man->flags = TTM_MEMTYPE_FLAG_FIXED | + TTM_MEMTYPE_FLAG_MAPPABLE; + man->available_caching = TTM_PL_FLAG_UNCACHED | + TTM_PL_FLAG_WC; + man->default_caching = TTM_PL_FLAG_WC; + break; + default: + DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); + return -EINVAL; + } + return 0; +} + +static void +bochs_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) +{ + struct bochs_bo *bochsbo = bochs_bo(bo); + + if (!bochs_ttm_bo_is_bochs_bo(bo)) + return; + + bochs_ttm_placement(bochsbo, TTM_PL_FLAG_SYSTEM); + *pl = bochsbo->placement; +} + +static int bochs_bo_verify_access(struct ttm_buffer_object *bo, + struct file *filp) +{ + struct bochs_bo *bochsbo = bochs_bo(bo); + + return drm_vma_node_verify_access(&bochsbo->gem.vma_node, filp); +} + +static int bochs_ttm_io_mem_reserve(struct ttm_bo_device *bdev, + struct ttm_mem_reg *mem) +{ + struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; + struct bochs_device *bochs = bochs_bdev(bdev); + + mem->bus.addr = NULL; + mem->bus.offset = 0; + mem->bus.size = mem->num_pages << PAGE_SHIFT; + mem->bus.base = 0; + mem->bus.is_iomem = false; + if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) + return -EINVAL; + switch (mem->mem_type) { + case TTM_PL_SYSTEM: + /* system memory */ + return 0; + case TTM_PL_VRAM: + mem->bus.offset = mem->start << PAGE_SHIFT; + mem->bus.base = bochs->fb_base; + mem->bus.is_iomem = true; + break; + default: + return -EINVAL; + break; + } + return 0; +} + +static void bochs_ttm_io_mem_free(struct ttm_bo_device *bdev, + struct ttm_mem_reg *mem) +{ +} + +static int bochs_bo_move(struct ttm_buffer_object *bo, + bool evict, bool interruptible, + bool no_wait_gpu, + struct ttm_mem_reg *new_mem) +{ + return ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem); +} + + +static void bochs_ttm_backend_destroy(struct ttm_tt *tt) +{ + ttm_tt_fini(tt); + kfree(tt); +} + +static struct ttm_backend_func bochs_tt_backend_func = { + .destroy = &bochs_ttm_backend_destroy, +}; + +static struct ttm_tt *bochs_ttm_tt_create(struct ttm_bo_device *bdev, + unsigned long size, + uint32_t page_flags, + struct page *dummy_read_page) +{ + struct ttm_tt *tt; + + tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL); + if (tt == NULL) + return NULL; + tt->func = &bochs_tt_backend_func; + if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) { + kfree(tt); + return NULL; + } + return tt; +} + +struct ttm_bo_driver bochs_bo_driver = { + .ttm_tt_create = bochs_ttm_tt_create, + .ttm_tt_populate = ttm_pool_populate, + .ttm_tt_unpopulate = ttm_pool_unpopulate, + .init_mem_type = bochs_bo_init_mem_type, + .evict_flags = bochs_bo_evict_flags, + .move = bochs_bo_move, + .verify_access = bochs_bo_verify_access, + .io_mem_reserve = &bochs_ttm_io_mem_reserve, + .io_mem_free = &bochs_ttm_io_mem_free, +}; + +int bochs_mm_init(struct bochs_device *bochs) +{ + struct ttm_bo_device *bdev = &bochs->ttm.bdev; + int ret; + + ret = bochs_ttm_global_init(bochs); + if (ret) + return ret; + + ret = ttm_bo_device_init(&bochs->ttm.bdev, + bochs->ttm.bo_global_ref.ref.object, + &bochs_bo_driver, DRM_FILE_PAGE_OFFSET, + true); + if (ret) { + DRM_ERROR("Error initialising bo driver; %d\n", ret); + return ret; + } + + ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, + bochs->fb_size >> PAGE_SHIFT); + if (ret) { + DRM_ERROR("Failed ttm VRAM init: %d\n", ret); + return ret; + } + + bochs->ttm.initialized = true; + return 0; +} + +void bochs_mm_fini(struct bochs_device *bochs) +{ + if (!bochs->ttm.initialized) + return; + + ttm_bo_device_release(&bochs->ttm.bdev); + bochs_ttm_global_release(bochs); + bochs->ttm.initialized = false; +} + +static void bochs_ttm_placement(struct bochs_bo *bo, int domain) +{ + u32 c = 0; + bo->placement.fpfn = 0; + bo->placement.lpfn = 0; + bo->placement.placement = bo->placements; + bo->placement.busy_placement = bo->placements; + if (domain & TTM_PL_FLAG_VRAM) { + bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED + | TTM_PL_FLAG_VRAM; + } + if (domain & TTM_PL_FLAG_SYSTEM) { + bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + } + if (!c) { + bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + } + bo->placement.num_placement = c; + bo->placement.num_busy_placement = c; +} + +static inline u64 bochs_bo_gpu_offset(struct bochs_bo *bo) +{ + return bo->bo.offset; +} + +int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr) +{ + int i, ret; + + if (bo->pin_count) { + bo->pin_count++; + if (gpu_addr) + *gpu_addr = bochs_bo_gpu_offset(bo); + return 0; + } + + bochs_ttm_placement(bo, pl_flag); + for (i = 0; i < bo->placement.num_placement; i++) + bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; + ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); + if (ret) + return ret; + + bo->pin_count = 1; + if (gpu_addr) + *gpu_addr = bochs_bo_gpu_offset(bo); + return 0; +} + +int bochs_bo_unpin(struct bochs_bo *bo) +{ + int i, ret; + + if (!bo->pin_count) { + DRM_ERROR("unpin bad %p\n", bo); + return 0; + } + bo->pin_count--; + + if (bo->pin_count) + return 0; + + for (i = 0; i < bo->placement.num_placement; i++) + bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; + ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); + if (ret) + return ret; + + return 0; +} + +int bochs_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct drm_file *file_priv; + struct bochs_device *bochs; + + if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) + return drm_mmap(filp, vma); + + file_priv = filp->private_data; + bochs = file_priv->minor->dev->dev_private; + return ttm_bo_mmap(filp, vma, &bochs->ttm.bdev); +} + +/* ---------------------------------------------------------------------- */ + +static int bochs_bo_create(struct drm_device *dev, int size, int align, + uint32_t flags, struct bochs_bo **pbochsbo) +{ + struct bochs_device *bochs = dev->dev_private; + struct bochs_bo *bochsbo; + size_t acc_size; + int ret; + + bochsbo = kzalloc(sizeof(struct bochs_bo), GFP_KERNEL); + if (!bochsbo) + return -ENOMEM; + + ret = drm_gem_object_init(dev, &bochsbo->gem, size); + if (ret) { + kfree(bochsbo); + return ret; + } + + bochsbo->bo.bdev = &bochs->ttm.bdev; + bochsbo->bo.bdev->dev_mapping = dev->dev_mapping; + + bochs_ttm_placement(bochsbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); + + acc_size = ttm_bo_dma_acc_size(&bochs->ttm.bdev, size, + sizeof(struct bochs_bo)); + + ret = ttm_bo_init(&bochs->ttm.bdev, &bochsbo->bo, size, + ttm_bo_type_device, &bochsbo->placement, + align >> PAGE_SHIFT, false, NULL, acc_size, + NULL, bochs_bo_ttm_destroy); + if (ret) + return ret; + + *pbochsbo = bochsbo; + return 0; +} + +int bochs_gem_create(struct drm_device *dev, u32 size, bool iskernel, + struct drm_gem_object **obj) +{ + struct bochs_bo *bochsbo; + int ret; + + *obj = NULL; + + size = ALIGN(size, PAGE_SIZE); + if (size == 0) + return -EINVAL; + + ret = bochs_bo_create(dev, size, 0, 0, &bochsbo); + if (ret) { + if (ret != -ERESTARTSYS) + DRM_ERROR("failed to allocate GEM object\n"); + return ret; + } + *obj = &bochsbo->gem; + return 0; +} + +int bochs_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + struct drm_gem_object *gobj; + u32 handle; + int ret; + + args->pitch = args->width * ((args->bpp + 7) / 8); + args->size = args->pitch * args->height; + + ret = bochs_gem_create(dev, args->size, false, + &gobj); + if (ret) + return ret; + + ret = drm_gem_handle_create(file, gobj, &handle); + drm_gem_object_unreference_unlocked(gobj); + if (ret) + return ret; + + args->handle = handle; + return 0; +} + +static void bochs_bo_unref(struct bochs_bo **bo) +{ + struct ttm_buffer_object *tbo; + + if ((*bo) == NULL) + return; + + tbo = &((*bo)->bo); + ttm_bo_unref(&tbo); + if (tbo == NULL) + *bo = NULL; + +} + +void bochs_gem_free_object(struct drm_gem_object *obj) +{ + struct bochs_bo *bochs_bo = gem_to_bochs_bo(obj); + + if (!bochs_bo) + return; + bochs_bo_unref(&bochs_bo); +} + +int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, + uint32_t handle, uint64_t *offset) +{ + struct drm_gem_object *obj; + int ret; + struct bochs_bo *bo; + + mutex_lock(&dev->struct_mutex); + obj = drm_gem_object_lookup(dev, file, handle); + if (obj == NULL) { + ret = -ENOENT; + goto out_unlock; + } + + bo = gem_to_bochs_bo(obj); + *offset = bochs_bo_mmap_offset(bo); + + drm_gem_object_unreference(obj); + ret = 0; +out_unlock: + mutex_unlock(&dev->struct_mutex); + return ret; + +} + +/* ---------------------------------------------------------------------- */ + +static void bochs_user_framebuffer_destroy(struct drm_framebuffer *fb) +{ + struct bochs_framebuffer *bochs_fb = to_bochs_framebuffer(fb); + if (bochs_fb->obj) + drm_gem_object_unreference_unlocked(bochs_fb->obj); + drm_framebuffer_cleanup(fb); + kfree(fb); +} + +static const struct drm_framebuffer_funcs bochs_fb_funcs = { + .destroy = bochs_user_framebuffer_destroy, +}; + +int bochs_framebuffer_init(struct drm_device *dev, + struct bochs_framebuffer *gfb, + struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_gem_object *obj) +{ + int ret; + + drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd); + gfb->obj = obj; + ret = drm_framebuffer_init(dev, &gfb->base, &bochs_fb_funcs); + if (ret) { + DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); + return ret; + } + return 0; +} + +static struct drm_framebuffer * +bochs_user_framebuffer_create(struct drm_device *dev, + struct drm_file *filp, + struct drm_mode_fb_cmd2 *mode_cmd) +{ + struct drm_gem_object *obj; + struct bochs_framebuffer *bochs_fb; + int ret; + + DRM_DEBUG_DRIVER("%dx%d, format %c%c%c%c\n", + mode_cmd->width, mode_cmd->height, + (mode_cmd->pixel_format) & 0xff, + (mode_cmd->pixel_format >> 8) & 0xff, + (mode_cmd->pixel_format >> 16) & 0xff, + (mode_cmd->pixel_format >> 24) & 0xff); + + if (mode_cmd->pixel_format != DRM_FORMAT_XRGB8888) + return ERR_PTR(-ENOENT); + + obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]); + if (obj == NULL) + return ERR_PTR(-ENOENT); + + bochs_fb = kzalloc(sizeof(*bochs_fb), GFP_KERNEL); + if (!bochs_fb) { + drm_gem_object_unreference_unlocked(obj); + return ERR_PTR(-ENOMEM); + } + + ret = bochs_framebuffer_init(dev, bochs_fb, mode_cmd, obj); + if (ret) { + drm_gem_object_unreference_unlocked(obj); + kfree(bochs_fb); + return ERR_PTR(ret); + } + return &bochs_fb->base; +} + +const struct drm_mode_config_funcs bochs_mode_funcs = { + .fb_create = bochs_user_framebuffer_create, +}; diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h index b6aded73838bca..117d3eca5e3782 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.h +++ b/drivers/gpu/drm/cirrus/cirrus_drv.h @@ -222,7 +222,7 @@ void cirrus_fbdev_fini(struct cirrus_device *cdev); void cirrus_driver_irq_preinstall(struct drm_device *dev); int cirrus_driver_irq_postinstall(struct drm_device *dev); void cirrus_driver_irq_uninstall(struct drm_device *dev); -irqreturn_t cirrus_driver_irq_handler(DRM_IRQ_ARGS); +irqreturn_t cirrus_driver_irq_handler(int irq, void *arg); /* cirrus_kms.c */ int cirrus_driver_load(struct drm_device *dev, unsigned long flags); diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c index b27e95666fabf6..32bbba0a787bc9 100644 --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c @@ -39,7 +39,7 @@ static void cirrus_dirty_update(struct cirrus_fbdev *afbdev, * then the BO is being moved and we should * store up the damage until later. */ - if (!in_interrupt()) + if (drm_can_sleep()) ret = cirrus_bo_reserve(bo, true); if (ret) { if (ret != -EBUSY) @@ -233,6 +233,9 @@ static int cirrusfb_create(struct drm_fb_helper *helper, info->apertures->ranges[0].base = cdev->dev->mode_config.fb_base; info->apertures->ranges[0].size = cdev->mc.vram_size; + info->fix.smem_start = cdev->dev->mode_config.fb_base; + info->fix.smem_len = cdev->mc.vram_size; + info->screen_base = sysram; info->screen_size = size; diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c index 78e76f24343d17..4b0170cf53fd92 100644 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ b/drivers/gpu/drm/cirrus/cirrus_main.c @@ -255,7 +255,7 @@ int cirrus_dumb_create(struct drm_file *file, return 0; } -void cirrus_bo_unref(struct cirrus_bo **bo) +static void cirrus_bo_unref(struct cirrus_bo **bo) { struct ttm_buffer_object *tbo; diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c index adabc3daaa5b4f..530f78f84deed2 100644 --- a/drivers/gpu/drm/cirrus/cirrus_mode.c +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c @@ -102,7 +102,7 @@ static bool cirrus_crtc_mode_fixup(struct drm_crtc *crtc, return true; } -void cirrus_set_start_address(struct drm_crtc *crtc, unsigned offset) +static void cirrus_set_start_address(struct drm_crtc *crtc, unsigned offset) { struct cirrus_device *cdev = crtc->dev->dev_private; u32 addr; @@ -273,8 +273,8 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc, sr07 |= 0x11; break; case 16: - sr07 |= 0xc1; - hdr = 0xc0; + sr07 |= 0x17; + hdr = 0xc1; break; case 24: sr07 |= 0x15; @@ -453,7 +453,7 @@ static void cirrus_encoder_commit(struct drm_encoder *encoder) { } -void cirrus_encoder_destroy(struct drm_encoder *encoder) +static void cirrus_encoder_destroy(struct drm_encoder *encoder) { struct cirrus_encoder *cirrus_encoder = to_cirrus_encoder(encoder); drm_encoder_cleanup(encoder); @@ -492,7 +492,7 @@ static struct drm_encoder *cirrus_encoder_init(struct drm_device *dev) } -int cirrus_vga_get_modes(struct drm_connector *connector) +static int cirrus_vga_get_modes(struct drm_connector *connector) { int count; @@ -509,7 +509,7 @@ static int cirrus_vga_mode_valid(struct drm_connector *connector, return MODE_OK; } -struct drm_encoder *cirrus_connector_best_encoder(struct drm_connector +static struct drm_encoder *cirrus_connector_best_encoder(struct drm_connector *connector) { int enc_id = connector->encoder_ids[0]; diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c index 75becdeac07d71..8b37c25ff9bd00 100644 --- a/drivers/gpu/drm/cirrus/cirrus_ttm.c +++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c @@ -80,7 +80,7 @@ static int cirrus_ttm_global_init(struct cirrus_device *cirrus) return 0; } -void +static void cirrus_ttm_global_release(struct cirrus_device *cirrus) { if (cirrus->ttm.mem_global_ref.release == NULL) @@ -102,7 +102,7 @@ static void cirrus_bo_ttm_destroy(struct ttm_buffer_object *tbo) kfree(bo); } -bool cirrus_ttm_bo_is_cirrus_bo(struct ttm_buffer_object *bo) +static bool cirrus_ttm_bo_is_cirrus_bo(struct ttm_buffer_object *bo) { if (bo->destroy == &cirrus_bo_ttm_destroy) return true; @@ -208,7 +208,7 @@ static struct ttm_backend_func cirrus_tt_backend_func = { }; -struct ttm_tt *cirrus_ttm_tt_create(struct ttm_bo_device *bdev, +static struct ttm_tt *cirrus_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size, uint32_t page_flags, struct page *dummy_read_page) { @@ -375,26 +375,6 @@ int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr) return 0; } -int cirrus_bo_unpin(struct cirrus_bo *bo) -{ - int i, ret; - if (!bo->pin_count) { - DRM_ERROR("unpin bad %p\n", bo); - return 0; - } - bo->pin_count--; - if (bo->pin_count) - return 0; - - for (i = 0; i < bo->placement.num_placement ; i++) - bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; - ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); - if (ret) - return ret; - - return 0; -} - int cirrus_bo_push_sysram(struct cirrus_bo *bo) { int i, ret; diff --git a/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c index e301d653d97e42..dde205cef384c0 100644 --- a/drivers/gpu/drm/drm_agpsupport.c +++ b/drivers/gpu/drm/drm_agpsupport.c @@ -53,7 +53,7 @@ */ int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info) { - DRM_AGP_KERN *kern; + struct agp_kern_info *kern; if (!dev->agp || !dev->agp->acquired) return -EINVAL; @@ -198,17 +198,15 @@ int drm_agp_enable_ioctl(struct drm_device *dev, void *data, int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request) { struct drm_agp_mem *entry; - DRM_AGP_MEM *memory; + struct agp_memory *memory; unsigned long pages; u32 type; if (!dev->agp || !dev->agp->acquired) return -EINVAL; - if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL))) + if (!(entry = kzalloc(sizeof(*entry), GFP_KERNEL))) return -ENOMEM; - memset(entry, 0, sizeof(*entry)); - pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE; type = (u32) request->type; if (!(memory = agp_allocate_memory(dev->agp->bridge, pages, type))) { @@ -393,14 +391,16 @@ int drm_agp_free_ioctl(struct drm_device *dev, void *data, * Gets the drm_agp_t structure which is made available by the agpgart module * via the inter_module_* functions. Creates and initializes a drm_agp_head * structure. + * + * Note that final cleanup of the kmalloced structure is directly done in + * drm_pci_agp_destroy. */ struct drm_agp_head *drm_agp_init(struct drm_device *dev) { struct drm_agp_head *head = NULL; - if (!(head = kmalloc(sizeof(*head), GFP_KERNEL))) + if (!(head = kzalloc(sizeof(*head), GFP_KERNEL))) return NULL; - memset((void *)head, 0, sizeof(*head)); head->bridge = agp_find_bridge(dev->pdev); if (!head->bridge) { if (!(head->bridge = agp_backend_acquire(dev->pdev))) { @@ -439,7 +439,7 @@ void drm_agp_clear(struct drm_device *dev) { struct drm_agp_mem *entry, *tempe; - if (!drm_core_has_AGP(dev) || !dev->agp) + if (!dev->agp) return; if (drm_core_check_feature(dev, DRIVER_MODESET)) return; @@ -459,21 +459,6 @@ void drm_agp_clear(struct drm_device *dev) dev->agp->enabled = 0; } -/** - * drm_agp_destroy - Destroy AGP head - * @dev: DRM device - * - * Destroy resources that were previously allocated via drm_agp_initp. Caller - * must ensure to clean up all AGP resources before calling this. See - * drm_agp_clear(). - * - * Call this to destroy AGP heads allocated via drm_agp_init(). - */ -void drm_agp_destroy(struct drm_agp_head *agp) -{ - kfree(agp); -} - /** * Binds a collection of pages into AGP memory at the given offset, returning * the AGP memory structure containing them. @@ -481,14 +466,14 @@ void drm_agp_destroy(struct drm_agp_head *agp) * No reference is held on the pages during this time -- it is up to the * caller to handle that. */ -DRM_AGP_MEM * +struct agp_memory * drm_agp_bind_pages(struct drm_device *dev, struct page **pages, unsigned long num_pages, uint32_t gtt_offset, u32 type) { - DRM_AGP_MEM *mem; + struct agp_memory *mem; int ret, i; DRM_DEBUG("\n"); diff --git a/drivers/gpu/drm/drm_buffer.c b/drivers/gpu/drm/drm_buffer.c index 39a718340319ea..0406110f83edd2 100644 --- a/drivers/gpu/drm/drm_buffer.c +++ b/drivers/gpu/drm/drm_buffer.c @@ -114,7 +114,7 @@ int drm_buffer_copy_from_user(struct drm_buffer *buf, for (idx = 0; idx < nr_pages; ++idx) { - if (DRM_COPY_FROM_USER(buf->data[idx], + if (copy_from_user(buf->data[idx], user_data + idx * PAGE_SIZE, min(PAGE_SIZE, size - idx * PAGE_SIZE))) { DRM_ERROR("Failed to copy user data (%p) to drm buffer" diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index 471e051d295e38..edec31fe3fed86 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -261,7 +261,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, struct drm_agp_mem *entry; int valid = 0; - if (!drm_core_has_AGP(dev)) { + if (!dev->agp) { kfree(map); return -EINVAL; } @@ -303,9 +303,6 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, break; } - case _DRM_GEM: - DRM_ERROR("tried to addmap GEM object\n"); - break; case _DRM_SCATTER_GATHER: if (!dev->sg) { kfree(map); @@ -483,9 +480,6 @@ int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map) dmah.size = map->size; __drm_pci_free(dev, &dmah); break; - case _DRM_GEM: - DRM_ERROR("tried to rmmap GEM object\n"); - break; } kfree(map); @@ -1396,7 +1390,7 @@ int drm_mapbufs(struct drm_device *dev, void *data, spin_unlock(&dev->count_lock); if (request->count >= dma->buf_count) { - if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP)) + if ((dev->agp && (dma->flags & _DRM_DMA_USE_AGP)) || (drm_core_check_feature(dev, DRIVER_SG) && (dma->flags & _DRM_DMA_USE_SG))) { struct drm_local_map *map = dev->agp_buffer_map; diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index d6cf77c472e710..3b7d32da16046f 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -674,6 +674,29 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_crtc_cleanup); +/** + * drm_crtc_index - find the index of a registered CRTC + * @crtc: CRTC to find index for + * + * Given a registered CRTC, return the index of that CRTC within a DRM + * device's list of CRTCs. + */ +unsigned int drm_crtc_index(struct drm_crtc *crtc) +{ + unsigned int index = 0; + struct drm_crtc *tmp; + + list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { + if (tmp == crtc) + return index; + + index++; + } + + BUG(); +} +EXPORT_SYMBOL(drm_crtc_index); + /** * drm_mode_probed_add - add a mode to a connector's probed mode list * @connector: connector the new mode @@ -2767,10 +2790,8 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, } if (fb->funcs->dirty) { - drm_modeset_lock_all(dev); ret = fb->funcs->dirty(fb, file_priv, flags, r->color, clips, num_clips); - drm_modeset_unlock_all(dev); } else { ret = -ENOSYS; } diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 01361aba033b4a..ea92b827e787e3 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -324,35 +324,6 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) } EXPORT_SYMBOL(drm_helper_disable_unused_functions); -/** - * drm_encoder_crtc_ok - can a given crtc drive a given encoder? - * @encoder: encoder to test - * @crtc: crtc to test - * - * Return false if @encoder can't be driven by @crtc, true otherwise. - */ -static bool drm_encoder_crtc_ok(struct drm_encoder *encoder, - struct drm_crtc *crtc) -{ - struct drm_device *dev; - struct drm_crtc *tmp; - int crtc_mask = 1; - - WARN(!crtc, "checking null crtc?\n"); - - dev = crtc->dev; - - list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) { - if (tmp == crtc) - break; - crtc_mask <<= 1; - } - - if (encoder->possible_crtcs & crtc_mask) - return true; - return false; -} - /* * Check the CRTC we're going to map each output to vs. its current * CRTC. If they don't match, we have to disable the output and the CRTC @@ -536,7 +507,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, * are later needed by vblank and swap-completion * timestamping. They are derived from true hwmode. */ - drm_calc_timestamping_constants(crtc); + drm_calc_timestamping_constants(crtc, &crtc->hwmode); /* FIXME: add subpixel order */ done: diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index d9137e49c4e815..345be03c23db27 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -315,9 +315,6 @@ long drm_ioctl(struct file *filp, if (drm_device_is_unplugged(dev)) return -ENODEV; - atomic_inc(&dev->ioctl_count); - ++file_priv->ioctl_count; - if ((nr >= DRM_CORE_IOCTL_COUNT) && ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END))) goto err_i1; @@ -410,7 +407,6 @@ long drm_ioctl(struct file *filp, if (kdata != stack_kdata) kfree(kdata); - atomic_dec(&dev->ioctl_count); if (retcode) DRM_DEBUG("ret = %d\n", retcode); return retcode; diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 8835dcddfac3ab..b924306b84775f 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -605,347 +605,347 @@ static const struct drm_display_mode edid_cea_modes[] = { { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 2 - 720x480@60Hz */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 3 - 720x480@60Hz */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 4 - 1280x720@60Hz */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 5 - 1920x1080i@60Hz */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 6 - 1440x480i@60Hz */ { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 7 - 1440x480i@60Hz */ { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 8 - 1440x240@60Hz */ { DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_DBLCLK), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 9 - 1440x240@60Hz */ { DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_DBLCLK), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 10 - 2880x480i@60Hz */ { DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 11 - 2880x480i@60Hz */ { DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 12 - 2880x240@60Hz */ { DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 13 - 2880x240@60Hz */ { DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 14 - 1440x480@60Hz */ { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 15 - 1440x480@60Hz */ { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 16 - 1920x1080@60Hz */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 17 - 720x576@50Hz */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 18 - 720x576@50Hz */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 19 - 1280x720@50Hz */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 20 - 1920x1080i@50Hz */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 21 - 1440x576i@50Hz */ { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 22 - 1440x576i@50Hz */ { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 23 - 1440x288@50Hz */ { DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, 1590, 1728, 0, 288, 290, 293, 312, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_DBLCLK), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 24 - 1440x288@50Hz */ { DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, 1590, 1728, 0, 288, 290, 293, 312, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_DBLCLK), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 25 - 2880x576i@50Hz */ { DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 26 - 2880x576i@50Hz */ { DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 27 - 2880x288@50Hz */ { DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 28 - 2880x288@50Hz */ { DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 29 - 1440x576@50Hz */ { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 30 - 1440x576@50Hz */ { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 31 - 1920x1080@50Hz */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 32 - 1920x1080@24Hz */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558, 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 24, }, + .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 33 - 1920x1080@25Hz */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 25, }, + .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 34 - 1920x1080@30Hz */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 30, }, + .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 35 - 2880x480@60Hz */ { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 36 - 2880x480@60Hz */ { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 60, }, + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 37 - 2880x576@50Hz */ { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 38 - 2880x576@50Hz */ { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 39 - 1920x1080i@50Hz */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952, 2120, 2304, 0, 1080, 1126, 1136, 1250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE), - .vrefresh = 50, }, + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 40 - 1920x1080i@100Hz */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE), - .vrefresh = 100, }, + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 41 - 1280x720@100Hz */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 100, }, + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 42 - 720x576@100Hz */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 100, }, + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 43 - 720x576@100Hz */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 100, }, + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 44 - 1440x576i@100Hz */ { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_DBLCLK), - .vrefresh = 100, }, + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 45 - 1440x576i@100Hz */ { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_DBLCLK), - .vrefresh = 100, }, + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 46 - 1920x1080i@120Hz */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE), - .vrefresh = 120, }, + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 47 - 1280x720@120Hz */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 120, }, + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 48 - 720x480@120Hz */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 120, }, + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 49 - 720x480@120Hz */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 120, }, + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 50 - 1440x480i@120Hz */ { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), - .vrefresh = 120, }, + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 51 - 1440x480i@120Hz */ { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), - .vrefresh = 120, }, + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 52 - 720x576@200Hz */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 200, }, + .vrefresh = 200, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 53 - 720x576@200Hz */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 200, }, + .vrefresh = 200, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 54 - 1440x576i@200Hz */ { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), - .vrefresh = 200, }, + .vrefresh = 200, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 55 - 1440x576i@200Hz */ { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), - .vrefresh = 200, }, + .vrefresh = 200, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 56 - 720x480@240Hz */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 240, }, + .vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 57 - 720x480@240Hz */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), - .vrefresh = 240, }, + .vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 58 - 1440x480i@240 */ { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), - .vrefresh = 240, }, + .vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 59 - 1440x480i@240 */ { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), - .vrefresh = 240, }, + .vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 60 - 1280x720@24Hz */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 24, }, + .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 61 - 1280x720@25Hz */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700, 3740, 3960, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 25, }, + .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 62 - 1280x720@30Hz */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 30, }, + .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 63 - 1920x1080@120Hz */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 120, }, + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 64 - 1920x1080@100Hz */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 100, }, + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, }; /* @@ -2562,25 +2562,40 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid) return modes; } -static int -do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len) +static struct drm_display_mode * +drm_display_mode_from_vic_index(struct drm_connector *connector, + const u8 *video_db, u8 video_len, + u8 video_index) { struct drm_device *dev = connector->dev; - const u8 *mode; + struct drm_display_mode *newmode; u8 cea_mode; - int modes = 0; - for (mode = db; mode < db + len; mode++) { - cea_mode = (*mode & 127) - 1; /* CEA modes are numbered 1..127 */ - if (cea_mode < ARRAY_SIZE(edid_cea_modes)) { - struct drm_display_mode *newmode; - newmode = drm_mode_duplicate(dev, - &edid_cea_modes[cea_mode]); - if (newmode) { - newmode->vrefresh = 0; - drm_mode_probed_add(connector, newmode); - modes++; - } + if (video_db == NULL || video_index >= video_len) + return NULL; + + /* CEA modes are numbered 1..127 */ + cea_mode = (video_db[video_index] & 127) - 1; + if (cea_mode >= ARRAY_SIZE(edid_cea_modes)) + return NULL; + + newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); + newmode->vrefresh = 0; + + return newmode; +} + +static int +do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len) +{ + int i, modes = 0; + + for (i = 0; i < len; i++) { + struct drm_display_mode *mode; + mode = drm_display_mode_from_vic_index(connector, db, len, i); + if (mode) { + drm_mode_probed_add(connector, mode); + modes++; } } @@ -2674,21 +2689,13 @@ static int add_hdmi_mode(struct drm_connector *connector, u8 vic) static int add_3d_struct_modes(struct drm_connector *connector, u16 structure, const u8 *video_db, u8 video_len, u8 video_index) { - struct drm_device *dev = connector->dev; struct drm_display_mode *newmode; int modes = 0; - u8 cea_mode; - - if (video_db == NULL || video_index >= video_len) - return 0; - - /* CEA modes are numbered 1..127 */ - cea_mode = (video_db[video_index] & 127) - 1; - if (cea_mode >= ARRAY_SIZE(edid_cea_modes)) - return 0; if (structure & (1 << 0)) { - newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); + newmode = drm_display_mode_from_vic_index(connector, video_db, + video_len, + video_index); if (newmode) { newmode->flags |= DRM_MODE_FLAG_3D_FRAME_PACKING; drm_mode_probed_add(connector, newmode); @@ -2696,7 +2703,9 @@ static int add_3d_struct_modes(struct drm_connector *connector, u16 structure, } } if (structure & (1 << 6)) { - newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); + newmode = drm_display_mode_from_vic_index(connector, video_db, + video_len, + video_index); if (newmode) { newmode->flags |= DRM_MODE_FLAG_3D_TOP_AND_BOTTOM; drm_mode_probed_add(connector, newmode); @@ -2704,7 +2713,9 @@ static int add_3d_struct_modes(struct drm_connector *connector, u16 structure, } } if (structure & (1 << 8)) { - newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); + newmode = drm_display_mode_from_vic_index(connector, video_db, + video_len, + video_index); if (newmode) { newmode->flags |= DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF; drm_mode_probed_add(connector, newmode); @@ -2728,7 +2739,7 @@ static int do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, const u8 *video_db, u8 video_len) { - int modes = 0, offset = 0, i, multi_present = 0; + int modes = 0, offset = 0, i, multi_present = 0, multi_len; u8 vic_len, hdmi_3d_len = 0; u16 mask; u16 structure_all; @@ -2774,32 +2785,84 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, } offset += 1 + vic_len; - if (!(multi_present == 1 || multi_present == 2)) - goto out; + if (multi_present == 1) + multi_len = 2; + else if (multi_present == 2) + multi_len = 4; + else + multi_len = 0; - if ((multi_present == 1 && len < (9 + offset)) || - (multi_present == 2 && len < (11 + offset))) + if (len < (8 + offset + hdmi_3d_len - 1)) goto out; - if ((multi_present == 1 && hdmi_3d_len < 2) || - (multi_present == 2 && hdmi_3d_len < 4)) + if (hdmi_3d_len < multi_len) goto out; - /* 3D_Structure_ALL */ - structure_all = (db[8 + offset] << 8) | db[9 + offset]; + if (multi_present == 1 || multi_present == 2) { + /* 3D_Structure_ALL */ + structure_all = (db[8 + offset] << 8) | db[9 + offset]; - /* check if 3D_MASK is present */ - if (multi_present == 2) - mask = (db[10 + offset] << 8) | db[11 + offset]; - else - mask = 0xffff; - - for (i = 0; i < 16; i++) { - if (mask & (1 << i)) - modes += add_3d_struct_modes(connector, - structure_all, - video_db, - video_len, i); + /* check if 3D_MASK is present */ + if (multi_present == 2) + mask = (db[10 + offset] << 8) | db[11 + offset]; + else + mask = 0xffff; + + for (i = 0; i < 16; i++) { + if (mask & (1 << i)) + modes += add_3d_struct_modes(connector, + structure_all, + video_db, + video_len, i); + } + } + + offset += multi_len; + + for (i = 0; i < (hdmi_3d_len - multi_len); i++) { + int vic_index; + struct drm_display_mode *newmode = NULL; + unsigned int newflag = 0; + bool detail_present; + + detail_present = ((db[8 + offset + i] & 0x0f) > 7); + + if (detail_present && (i + 1 == hdmi_3d_len - multi_len)) + break; + + /* 2D_VIC_order_X */ + vic_index = db[8 + offset + i] >> 4; + + /* 3D_Structure_X */ + switch (db[8 + offset + i] & 0x0f) { + case 0: + newflag = DRM_MODE_FLAG_3D_FRAME_PACKING; + break; + case 6: + newflag = DRM_MODE_FLAG_3D_TOP_AND_BOTTOM; + break; + case 8: + /* 3D_Detail_X */ + if ((db[9 + offset + i] >> 4) == 1) + newflag = DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF; + break; + } + + if (newflag != 0) { + newmode = drm_display_mode_from_vic_index(connector, + video_db, + video_len, + vic_index); + + if (newmode) { + newmode->flags |= newflag; + drm_mode_probed_add(connector, newmode); + modes++; + } + } + + if (detail_present) + i++; } out: diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c index 9081172ef0573a..1b4c7a5442c5de 100644 --- a/drivers/gpu/drm/drm_edid_load.c +++ b/drivers/gpu/drm/drm_edid_load.c @@ -141,7 +141,7 @@ static int edid_size(const u8 *edid, int data_size) return (edid[0x7e] + 1) * EDID_LENGTH; } -static u8 *edid_load(struct drm_connector *connector, const char *name, +static void *edid_load(struct drm_connector *connector, const char *name, const char *connector_name) { const struct firmware *fw = NULL; @@ -263,7 +263,7 @@ int drm_load_edid_firmware(struct drm_connector *connector) if (*last == '\n') *last = '\0'; - edid = (struct edid *) edid_load(connector, edidname, connector_name); + edid = edid_load(connector, edidname, connector_name); if (IS_ERR_OR_NULL(edid)) return 0; diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 0a19401aff803b..98a03639b413d8 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -359,6 +359,11 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) struct drm_crtc *crtc; int bound = 0, crtcs_bound = 0; + /* Sometimes user space wants everything disabled, so don't steal the + * display if there's a master. */ + if (dev->primary->master) + return false; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (crtc->fb) crtcs_bound++; @@ -368,6 +373,7 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) if (bound < crtcs_bound) return false; + return true; } diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index c5b929c3f77ae6..7f2af9aca03895 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -232,7 +232,6 @@ static int drm_open_helper(struct inode *inode, struct file *filp, goto out_put_pid; } - priv->ioctl_count = 0; /* for compatibility root is always authenticated */ priv->always_authenticated = capable(CAP_SYS_ADMIN); priv->authenticated = priv->always_authenticated; @@ -392,9 +391,6 @@ static void drm_legacy_dev_reinit(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) return; - atomic_set(&dev->ioctl_count, 0); - atomic_set(&dev->vma_count, 0); - dev->sigdata.lock = NULL; dev->context_flag = 0; @@ -578,12 +574,7 @@ int drm_release(struct inode *inode, struct file *filp) */ if (!--dev->open_count) { - if (atomic_read(&dev->ioctl_count)) { - DRM_ERROR("Device busy: %d\n", - atomic_read(&dev->ioctl_count)); - retcode = -EBUSY; - } else - retcode = drm_lastclose(dev); + retcode = drm_lastclose(dev); if (drm_device_is_unplugged(dev)) drm_put_dev(dev); } diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 4761adedad2abe..5bbad873c798a8 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -91,19 +91,19 @@ int drm_gem_init(struct drm_device *dev) { - struct drm_gem_mm *mm; + struct drm_vma_offset_manager *vma_offset_manager; mutex_init(&dev->object_name_lock); idr_init(&dev->object_name_idr); - mm = kzalloc(sizeof(struct drm_gem_mm), GFP_KERNEL); - if (!mm) { + vma_offset_manager = kzalloc(sizeof(*vma_offset_manager), GFP_KERNEL); + if (!vma_offset_manager) { DRM_ERROR("out of memory\n"); return -ENOMEM; } - dev->mm_private = mm; - drm_vma_offset_manager_init(&mm->vma_manager, + dev->vma_offset_manager = vma_offset_manager; + drm_vma_offset_manager_init(vma_offset_manager, DRM_FILE_PAGE_OFFSET_START, DRM_FILE_PAGE_OFFSET_SIZE); @@ -113,11 +113,10 @@ drm_gem_init(struct drm_device *dev) void drm_gem_destroy(struct drm_device *dev) { - struct drm_gem_mm *mm = dev->mm_private; - drm_vma_offset_manager_destroy(&mm->vma_manager); - kfree(mm); - dev->mm_private = NULL; + drm_vma_offset_manager_destroy(dev->vma_offset_manager); + kfree(dev->vma_offset_manager); + dev->vma_offset_manager = NULL; } /** @@ -129,11 +128,12 @@ int drm_gem_object_init(struct drm_device *dev, { struct file *filp; + drm_gem_private_object_init(dev, obj, size); + filp = shmem_file_setup("drm mm object", size, VM_NORESERVE); if (IS_ERR(filp)) return PTR_ERR(filp); - drm_gem_private_object_init(dev, obj, size); obj->filp = filp; return 0; @@ -175,11 +175,6 @@ drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp) mutex_unlock(&filp->prime.lock); } -static void drm_gem_object_ref_bug(struct kref *list_kref) -{ - BUG(); -} - /** * Called after the last handle to the object has been closed * @@ -195,13 +190,6 @@ static void drm_gem_object_handle_free(struct drm_gem_object *obj) if (obj->name) { idr_remove(&dev->object_name_idr, obj->name); obj->name = 0; - /* - * The object name held a reference to this object, drop - * that now. - * - * This cannot be the last reference, since the handle holds one too. - */ - kref_put(&obj->refcount, drm_gem_object_ref_bug); } } @@ -374,9 +362,8 @@ void drm_gem_free_mmap_offset(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; - struct drm_gem_mm *mm = dev->mm_private; - drm_vma_offset_remove(&mm->vma_manager, &obj->vma_node); + drm_vma_offset_remove(dev->vma_offset_manager, &obj->vma_node); } EXPORT_SYMBOL(drm_gem_free_mmap_offset); @@ -398,9 +385,8 @@ int drm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size) { struct drm_device *dev = obj->dev; - struct drm_gem_mm *mm = dev->mm_private; - return drm_vma_offset_add(&mm->vma_manager, &obj->vma_node, + return drm_vma_offset_add(dev->vma_offset_manager, &obj->vma_node, size / PAGE_SIZE); } EXPORT_SYMBOL(drm_gem_create_mmap_offset_size); @@ -602,9 +588,6 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data, goto err; obj->name = ret; - - /* Allocate a reference for the name table. */ - drm_gem_object_reference(obj); } args->name = (uint64_t) obj->name; @@ -833,7 +816,6 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) { struct drm_file *priv = filp->private_data; struct drm_device *dev = priv->minor->dev; - struct drm_gem_mm *mm = dev->mm_private; struct drm_gem_object *obj; struct drm_vma_offset_node *node; int ret = 0; @@ -843,7 +825,8 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) mutex_lock(&dev->struct_mutex); - node = drm_vma_offset_exact_lookup(&mm->vma_manager, vma->vm_pgoff, + node = drm_vma_offset_exact_lookup(dev->vma_offset_manager, + vma->vm_pgoff, vma_pages(vma)); if (!node) { mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c index 7d5a152eeb0288..7473035dd28b78 100644 --- a/drivers/gpu/drm/drm_info.c +++ b/drivers/gpu/drm/drm_info.c @@ -186,14 +186,14 @@ int drm_clients_info(struct seq_file *m, void *data) struct drm_file *priv; mutex_lock(&dev->struct_mutex); - seq_printf(m, "a dev pid uid magic ioctls\n\n"); + seq_printf(m, "a dev pid uid magic\n\n"); list_for_each_entry(priv, &dev->filelist, lhead) { - seq_printf(m, "%c %3d %5d %5d %10u %10lu\n", + seq_printf(m, "%c %3d %5d %5d %10u\n", priv->authenticated ? 'y' : 'n', priv->minor->index, pid_vnr(priv->pid), from_kuid_munged(seq_user_ns(m), priv->uid), - priv->magic, priv->ioctl_count); + priv->magic); } mutex_unlock(&dev->struct_mutex); return 0; @@ -234,14 +234,18 @@ int drm_vma_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; struct drm_vma_entry *pt; struct vm_area_struct *vma; + unsigned long vma_count = 0; #if defined(__i386__) unsigned int pgprot; #endif mutex_lock(&dev->struct_mutex); - seq_printf(m, "vma use count: %d, high_memory = %pK, 0x%pK\n", - atomic_read(&dev->vma_count), - high_memory, (void *)(unsigned long)virt_to_phys(high_memory)); + list_for_each_entry(pt, &dev->vmalist, head) + vma_count++; + + seq_printf(m, "vma use count: %lu, high_memory = %pK, 0x%pK\n", + vma_count, high_memory, + (void *)(unsigned long)virt_to_phys(high_memory)); list_for_each_entry(pt, &dev->vmalist, head) { vma = pt->vma; diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index dffc836144cc96..f4dc9b7a3831f3 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -296,6 +296,18 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) case DRM_CAP_ASYNC_PAGE_FLIP: req->value = dev->mode_config.async_page_flip; break; + case DRM_CAP_CURSOR_WIDTH: + if (dev->mode_config.cursor_width) + req->value = dev->mode_config.cursor_width; + else + req->value = 64; + break; + case DRM_CAP_CURSOR_HEIGHT: + if (dev->mode_config.cursor_height) + req->value = dev->mode_config.cursor_height; + else + req->value = 64; + break; default: return -EINVAL; } diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 64c34d5876ffc7..c2676b5908d9f6 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -368,7 +368,7 @@ int drm_irq_uninstall(struct drm_device *dev) if (dev->num_crtcs) { spin_lock_irqsave(&dev->vbl_lock, irqflags); for (i = 0; i < dev->num_crtcs; i++) { - DRM_WAKEUP(&dev->vblank[i].queue); + wake_up(&dev->vblank[i].queue); dev->vblank[i].enabled = false; dev->vblank[i].last = dev->driver->get_vblank_counter(dev, i); @@ -436,45 +436,41 @@ int drm_control(struct drm_device *dev, void *data, } /** - * drm_calc_timestamping_constants - Calculate and - * store various constants which are later needed by - * vblank and swap-completion timestamping, e.g, by - * drm_calc_vbltimestamp_from_scanoutpos(). - * They are derived from crtc's true scanout timing, - * so they take things like panel scaling or other - * adjustments into account. + * drm_calc_timestamping_constants - Calculate vblank timestamp constants * * @crtc drm_crtc whose timestamp constants should be updated. + * @mode display mode containing the scanout timings * + * Calculate and store various constants which are later + * needed by vblank and swap-completion timestamping, e.g, + * by drm_calc_vbltimestamp_from_scanoutpos(). They are + * derived from crtc's true scanout timing, so they take + * things like panel scaling or other adjustments into account. */ -void drm_calc_timestamping_constants(struct drm_crtc *crtc) +void drm_calc_timestamping_constants(struct drm_crtc *crtc, + const struct drm_display_mode *mode) { - s64 linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0; - u64 dotclock; - - /* Dot clock in Hz: */ - dotclock = (u64) crtc->hwmode.clock * 1000; - - /* Fields of interlaced scanout modes are only half a frame duration. - * Double the dotclock to get half the frame-/line-/pixelduration. - */ - if (crtc->hwmode.flags & DRM_MODE_FLAG_INTERLACE) - dotclock *= 2; + int linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0; + int dotclock = mode->crtc_clock; /* Valid dotclock? */ if (dotclock > 0) { - int frame_size; - /* Convert scanline length in pixels and video dot clock to - * line duration, frame duration and pixel duration in - * nanoseconds: + int frame_size = mode->crtc_htotal * mode->crtc_vtotal; + + /* + * Convert scanline length in pixels and video + * dot clock to line duration, frame duration + * and pixel duration in nanoseconds: */ - pixeldur_ns = (s64) div64_u64(1000000000, dotclock); - linedur_ns = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal * - 1000000000), dotclock); - frame_size = crtc->hwmode.crtc_htotal * - crtc->hwmode.crtc_vtotal; - framedur_ns = (s64) div64_u64((u64) frame_size * 1000000000, - dotclock); + pixeldur_ns = 1000000 / dotclock; + linedur_ns = div_u64((u64) mode->crtc_htotal * 1000000, dotclock); + framedur_ns = div_u64((u64) frame_size * 1000000, dotclock); + + /* + * Fields of interlaced scanout modes are only half a frame duration. + */ + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + framedur_ns /= 2; } else DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n", crtc->base.id); @@ -484,11 +480,11 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc) crtc->framedur_ns = framedur_ns; DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n", - crtc->base.id, crtc->hwmode.crtc_htotal, - crtc->hwmode.crtc_vtotal, crtc->hwmode.crtc_vdisplay); + crtc->base.id, mode->crtc_htotal, + mode->crtc_vtotal, mode->crtc_vdisplay); DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n", - crtc->base.id, (int) dotclock/1000, (int) framedur_ns, - (int) linedur_ns, (int) pixeldur_ns); + crtc->base.id, dotclock, framedur_ns, + linedur_ns, pixeldur_ns); } EXPORT_SYMBOL(drm_calc_timestamping_constants); @@ -521,6 +517,7 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants); * 0 = Default. * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler. * @refcrtc: drm_crtc* of crtc which defines scanout timing. + * @mode: mode which defines the scanout timings * * Returns negative value on error, failure or if not supported in current * video mode: @@ -540,14 +537,14 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, int *max_error, struct timeval *vblank_time, unsigned flags, - struct drm_crtc *refcrtc) + const struct drm_crtc *refcrtc, + const struct drm_display_mode *mode) { ktime_t stime, etime, mono_time_offset; struct timeval tv_etime; - struct drm_display_mode *mode; - int vbl_status, vtotal, vdisplay; + int vbl_status; int vpos, hpos, i; - s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns; + int framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns; bool invbl; if (crtc < 0 || crtc >= dev->num_crtcs) { @@ -561,10 +558,6 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, return -EIO; } - mode = &refcrtc->hwmode; - vtotal = mode->crtc_vtotal; - vdisplay = mode->crtc_vdisplay; - /* Durations of frames, lines, pixels in nanoseconds. */ framedur_ns = refcrtc->framedur_ns; linedur_ns = refcrtc->linedur_ns; @@ -573,7 +566,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, /* If mode timing undefined, just return as no-op: * Happens during initial modesetting of a crtc. */ - if (vtotal <= 0 || vdisplay <= 0 || framedur_ns == 0) { + if (framedur_ns == 0) { DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc); return -EAGAIN; } @@ -590,7 +583,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, * Get vertical and horizontal scanout position vpos, hpos, * and bounding timestamps stime, etime, pre/post query. */ - vbl_status = dev->driver->get_scanout_position(dev, crtc, &vpos, + vbl_status = dev->driver->get_scanout_position(dev, crtc, flags, &vpos, &hpos, &stime, &etime); /* @@ -611,18 +604,18 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, duration_ns = ktime_to_ns(etime) - ktime_to_ns(stime); /* Accept result with < max_error nsecs timing uncertainty. */ - if (duration_ns <= (s64) *max_error) + if (duration_ns <= *max_error) break; } /* Noisy system timing? */ if (i == DRM_TIMESTAMP_MAXRETRIES) { DRM_DEBUG("crtc %d: Noisy timestamp %d us > %d us [%d reps].\n", - crtc, (int) duration_ns/1000, *max_error/1000, i); + crtc, duration_ns/1000, *max_error/1000, i); } /* Return upper bound of timestamp precision error. */ - *max_error = (int) duration_ns; + *max_error = duration_ns; /* Check if in vblank area: * vpos is >=0 in video scanout area, but negative @@ -635,25 +628,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, * since start of scanout at first display scanline. delta_ns * can be negative if start of scanout hasn't happened yet. */ - delta_ns = (s64) vpos * linedur_ns + (s64) hpos * pixeldur_ns; - - /* Is vpos outside nominal vblank area, but less than - * 1/100 of a frame height away from start of vblank? - * If so, assume this isn't a massively delayed vblank - * interrupt, but a vblank interrupt that fired a few - * microseconds before true start of vblank. Compensate - * by adding a full frame duration to the final timestamp. - * Happens, e.g., on ATI R500, R600. - * - * We only do this if DRM_CALLED_FROM_VBLIRQ. - */ - if ((flags & DRM_CALLED_FROM_VBLIRQ) && !invbl && - ((vdisplay - vpos) < vtotal / 100)) { - delta_ns = delta_ns - framedur_ns; - - /* Signal this correction as "applied". */ - vbl_status |= 0x8; - } + delta_ns = vpos * linedur_ns + hpos * pixeldur_ns; if (!drm_timestamp_monotonic) etime = ktime_sub(etime, mono_time_offset); @@ -673,7 +648,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, crtc, (int)vbl_status, hpos, vpos, (long)tv_etime.tv_sec, (long)tv_etime.tv_usec, (long)vblank_time->tv_sec, (long)vblank_time->tv_usec, - (int)duration_ns/1000, i); + duration_ns/1000, i); vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD; if (invbl) @@ -960,7 +935,7 @@ void drm_vblank_put(struct drm_device *dev, int crtc) if (atomic_dec_and_test(&dev->vblank[crtc].refcount) && (drm_vblank_offdelay > 0)) mod_timer(&dev->vblank_disable_timer, - jiffies + ((drm_vblank_offdelay * DRM_HZ)/1000)); + jiffies + ((drm_vblank_offdelay * HZ)/1000)); } EXPORT_SYMBOL(drm_vblank_put); @@ -980,7 +955,7 @@ void drm_vblank_off(struct drm_device *dev, int crtc) spin_lock_irqsave(&dev->vbl_lock, irqflags); vblank_disable_and_save(dev, crtc); - DRM_WAKEUP(&dev->vblank[crtc].queue); + wake_up(&dev->vblank[crtc].queue); /* Send any queued vblank events, lest the natives grow disquiet */ seq = drm_vblank_count_and_time(dev, crtc, &now); @@ -1244,7 +1219,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, DRM_DEBUG("waiting on vblank count %d, crtc %d\n", vblwait->request.sequence, crtc); dev->vblank[crtc].last_wait = vblwait->request.sequence; - DRM_WAIT_ON(ret, dev->vblank[crtc].queue, 3 * DRM_HZ, + DRM_WAIT_ON(ret, dev->vblank[crtc].queue, 3 * HZ, (((drm_vblank_count(dev, crtc) - vblwait->request.sequence) <= (1 << 23)) || !dev->irq_enabled)); @@ -1363,7 +1338,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) crtc, (int) diff_ns); } - DRM_WAKEUP(&dev->vblank[crtc].queue); + wake_up(&dev->vblank[crtc].queue); drm_handle_vblank_events(dev, crtc); spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c index 64e44fad8ae842..00c67c0f238127 100644 --- a/drivers/gpu/drm/drm_memory.c +++ b/drivers/gpu/drm/drm_memory.c @@ -82,19 +82,19 @@ static void *agp_remap(unsigned long offset, unsigned long size, } /** Wrapper around agp_free_memory() */ -void drm_free_agp(DRM_AGP_MEM * handle, int pages) +void drm_free_agp(struct agp_memory * handle, int pages) { agp_free_memory(handle); } /** Wrapper around agp_bind_memory() */ -int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start) +int drm_bind_agp(struct agp_memory * handle, unsigned int start) { return agp_bind_memory(handle, start); } /** Wrapper around agp_unbind_memory() */ -int drm_unbind_agp(DRM_AGP_MEM * handle) +int drm_unbind_agp(struct agp_memory * handle) { return agp_unbind_memory(handle); } @@ -110,8 +110,7 @@ static inline void *agp_remap(unsigned long offset, unsigned long size, void drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev) { - if (drm_core_has_AGP(dev) && - dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) + if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) map->handle = agp_remap(map->offset, map->size, dev); else map->handle = ioremap(map->offset, map->size); @@ -120,8 +119,7 @@ EXPORT_SYMBOL(drm_core_ioremap); void drm_core_ioremap_wc(struct drm_local_map *map, struct drm_device *dev) { - if (drm_core_has_AGP(dev) && - dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) + if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) map->handle = agp_remap(map->offset, map->size, dev); else map->handle = ioremap_wc(map->offset, map->size); @@ -133,8 +131,7 @@ void drm_core_ioremapfree(struct drm_local_map *map, struct drm_device *dev) if (!map->handle || !map->size) return; - if (drm_core_has_AGP(dev) && - dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) + if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) vunmap(map->handle); else iounmap(map->handle); diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c new file mode 100644 index 00000000000000..b155ee2ffa17a4 --- /dev/null +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -0,0 +1,315 @@ +/* + * MIPI DSI Bus + * + * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd. + * Andrzej Hajda + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include + +#include