]> Git Repo - linux.git/commitdiff
Merge tag 'devicetree-for-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/robh...
authorLinus Torvalds <[email protected]>
Fri, 20 May 2016 21:51:34 +0000 (14:51 -0700)
committerLinus Torvalds <[email protected]>
Fri, 20 May 2016 21:51:34 +0000 (14:51 -0700)
Pull devicetree updates from Rob Herring:

 - Rewrite of the unflattening code to avoid recursion and lessen the
   stack usage.

 - Rewrite of the phandle args parsing code to get rid of the fixed args
   size.  This is needed for IOMMU code.

 - Sync to latest dtc which adds more dts style checking.  These
   warnings are enabled with "W=1" compiles.

 - Tegra documentation updates related to the above warnings.

 - A bunch of spelling and other doc fixes.

 - Various vendor prefix additions.

* tag 'devicetree-for-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux: (52 commits)
  devicetree: Add Creative Technology vendor id
  gpio: dt-bindings: add ibm,ppc4xx-gpio binding
  of/unittest: Remove unnecessary module.h header inclusion
  drivers/of: Fix build warning in populate_node()
  drivers/of: Fix depth when unflattening devicetree
  of: dynamic: changeset prop-update revert fix
  drivers/of: Export of_detach_node()
  drivers/of: Return allocated memory from of_fdt_unflatten_tree()
  drivers/of: Specify parent node in of_fdt_unflatten_tree()
  drivers/of: Rename unflatten_dt_node()
  drivers/of: Avoid recursively calling unflatten_dt_node()
  drivers/of: Split unflatten_dt_node()
  of: include errno.h in of_graph.h
  of: document refcount incrementation of of_get_cpu_node()
  Documentation: dt: soc: fix spelling mistakes
  Documentation: dt: power: fix spelling mistake
  Documentation: dt: pinctrl: fix spelling mistake
  Documentation: dt: opp: fix spelling mistake
  Documentation: dt: net: fix spelling mistakes
  Documentation: dt: mtd: fix spelling mistake
  ...

1  2 
Documentation/devicetree/bindings/net/hisilicon-hns-nic.txt
Documentation/devicetree/bindings/net/stmmac.txt
Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
drivers/iommu/arm-smmu.c
drivers/of/base.c
drivers/of/unittest.c
include/linux/of.h

index b9ff4ba6454e49e98e89ca2f99d1f4d03f09e275,e911a635ce6e48c7db7f0f09457ca6e90e63b80d..f0421ee3c7149fe08419eda6e4657a25872771d2
@@@ -8,7 -8,7 +8,7 @@@ Required properties
    specifies a reference to the associating hardware driver node.
    see Documentation/devicetree/bindings/net/hisilicon-hns-dsaf.txt
  - port-id: is the index of port provided by DSAF (the accelerator). DSAF can
-   connect to 8 PHYs. Port 0 to 1 are both used for adminstration purpose. They
+   connect to 8 PHYs. Port 0 to 1 are both used for administration purpose. They
    are called debug ports.
  
    The remaining 6 PHYs are taken according to the mode of DSAF.
                         | | | | | |
                        external port
  
 +  This attribute is remained for compatible purpose. It is not recommended to
 +  use it in new code.
 +
 +- port-idx-in-ae: is the index of port provided by AE.
 +  In NIC mode of DSAF, all 6 PHYs of service DSAF are taken as ethernet ports
 +  to the CPU. The port-idx-in-ae can be 0 to 5. Here is the diagram:
 +            +-----+---------------+
 +            |            CPU      |
 +            +-+-+-+---+-+-+-+-+-+-+
 +              |    |   | | | | | |
 +           debug debug   service
 +           port  port     port
 +           (0)   (0)     (0-5)
 +
 +  In Switch mode of DSAF, all 6 PHYs of service DSAF are taken as physical
 +  ports connected to a LAN Switch while the CPU side assume itself have one
 +  single NIC connected to this switch. In this case, the port-idx-in-ae
 +  will be 0 only.
 +            +-----+-----+------+------+
 +            |                CPU      |
 +            +-+-+-+-+-+-+-+-+-+-+-+-+-+
 +              |    |     service| port(0)
 +            debug debug  +------------+
 +            port  port   |   switch   |
 +            (0)   (0)    +-+-+-+-+-+-++
 +                          | | | | | |
 +                         external port
 +
  - local-mac-address: mac addr of the ethernet interface
  
  Example:
@@@ -71,6 -43,6 +71,6 @@@
        ethernet@0{
                compatible = "hisilicon,hns-nic-v1";
                ae-handle = <&dsaf0>;
 -              port-id = <0>;
 +              port-idx-in-ae = <0>;
                local-mac-address = [a2 14 e4 4b 56 76];
        };
index 4d302db657c0bcb33039feb4fdd47e27d105e4c7,9651dfdced44059abafccb5c1cc781dd13d78632..95816c5fc589b971e924fba438a3e5e42f024670
@@@ -51,16 -51,14 +51,16 @@@ Optional properties
                           AXI register inside the DMA module:
        - snps,lpi_en: enable Low Power Interface
        - snps,xit_frm: unlock on WoL
-       - snps,wr_osr_lmt: max write oustanding req. limit
-       - snps,rd_osr_lmt: max read oustanding req. limit
+       - snps,wr_osr_lmt: max write outstanding req. limit
+       - snps,rd_osr_lmt: max read outstanding req. limit
        - snps,kbbe: do not cross 1KiB boundary.
        - snps,axi_all: align address
        - snps,blen: this is a vector of supported burst length.
        - snps,fb: fixed-burst
        - snps,mb: mixed-burst
        - snps,rb: rebuild INCRx Burst
 +      - snps,tso: this enables the TSO feature otherwise it will be managed by
 +          MAC HW capability register.
  - mdio: with compatible = "snps,dwmac-mdio", create and register mdio bus.
  
  Examples:
index 8a6223dbc143e26d96a20a47c3930eb9bb556933,9c8ddd547a9971e37fe2dfc9002a79c763445928..4048f43a9d29bfa96269fa4d87828dc313088a70
@@@ -1,12 -1,6 +1,12 @@@
  Device tree binding for NVIDIA Tegra XUSB pad controller
  ========================================================
  
 +NOTE: It turns out that this binding isn't an accurate description of the XUSB
 +pad controller. While the description is good enough for the functional subset
 +required for PCIe and SATA, it lacks the flexibility to represent the features
 +needed for USB. For the new binding, see ../phy/nvidia,tegra-xusb-padctl.txt.
 +The binding described in this file is deprecated and should not be used.
 +
  The Tegra XUSB pad controller manages a set of lanes, each of which can be
  assigned to one out of a set of different pads. Some of these pads have an
  associated PHY that must be powered up before the pad can be used.
@@@ -85,7 -79,7 +85,7 @@@ Example
  SoC file extract:
  -----------------
  
-       padctl@0,7009f000 {
+       padctl@7009f000 {
                compatible = "nvidia,tegra124-xusb-padctl";
                reg = <0x0 0x7009f000 0x0 0x1000>;
                resets = <&tegra_car 142>;
@@@ -97,7 -91,7 +97,7 @@@
  Board file extract:
  -------------------
  
-       pcie-controller@0,01003000 {
+       pcie-controller@01003000 {
                ...
  
                phys = <&padctl 0>;
  
        ...
  
-       padctl: padctl@0,7009f000 {
+       padctl: padctl@7009f000 {
                pinctrl-0 = <&padctl_default>;
                pinctrl-names = "default";
  
index 316412dc79135a472886a331caa9ff4a22932bfe,aba3a45184fc0e8008281cd6b37351c781fcc613..32f965807a07e42d0c1f47d2f7e6da7eceb5972c
@@@ -16,7 -16,6 +16,7 @@@ al    Annapurna Lab
  allwinner     Allwinner Technology Co., Ltd.
  alphascale    AlphaScale Integrated Circuits Systems, Inc.
  altr  Altera Corp.
 +amazon        Amazon.com, Inc.
  amcc  Applied Micro Circuits Corporation (APM, formally AMCC)
  amd   Advanced Micro Devices (AMD), Inc.
  amlogic       Amlogic, Inc.
@@@ -28,9 -27,9 +28,10 @@@ aptina       Aptina Imagin
  arasan        Arasan Chip Systems
  arm   ARM Ltd.
  armadeus      ARMadeus Systems SARL
+ arrow Arrow Electronics
  artesyn       Artesyn Embedded Technologies Inc.
  asahi-kasei   Asahi Kasei Corp.
 +aspeed        ASPEED Technology Inc.
  atlas Atlas Scientific LLC
  atmel Atmel Corporation
  auo   AU Optronics Corporation
@@@ -60,6 -59,7 +61,7 @@@ cnxt  Conexant Systems, Inc
  compulab      CompuLab Ltd.
  cortina       Cortina Systems, Inc.
  cosmic        Cosmic Circuits
+ creative      Creative Technology Ltd
  crystalfontz  Crystalfontz America, Inc.
  cubietech     Cubietech, Ltd.
  cypress       Cypress Semiconductor Corporation
@@@ -72,13 -72,12 +74,14 @@@ digilent   Diglent, Inc
  dlg   Dialog Semiconductor
  dlink D-Link Corporation
  dmo   Data Modul AG
 +dptechnics    DPTechnics
 +dragino       Dragino Technology Co., Limited
  ea    Embedded Artists AB
  ebv   EBV Elektronik
  edt   Emerging Display Technologies
  eeti  eGalax_eMPIA Technology Inc
  elan  Elan Microelectronic Corp.
+ embest        Shenzhen Embest Technology Co., Ltd.
  emmicro       EM Microelectronic
  energymicro   Silicon Laboratories (formerly Energy Micro AS)
  epcos EPCOS AG
@@@ -90,13 -89,11 +93,13 @@@ eukrea  EukrĂ©a Electromatiqu
  everest       Everest Semiconductor Co. Ltd.
  everspin      Everspin Technologies, Inc.
  excito        Excito
 +ezchip        EZchip Semiconductor
  fcs   Fairchild Semiconductor
  firefly       Firefly
  focaltech     FocalTech Systems Co.,Ltd
  fsl   Freescale Semiconductor
  ge    General Electric Company
 +geekbuying    GeekBuying
  GEFanuc       GE Fanuc Intelligent Platforms Embedded Systems, Inc.
  gef   GE Fanuc Intelligent Platforms Embedded Systems, Inc.
  geniatech     Geniatech, Inc.
@@@ -124,6 -121,7 +127,7 @@@ idt        Integrated Device Technologies, Inc
  ifi   Ingenieurburo Fur Ic-Technologie (I/F/I)
  iom   Iomega Corporation
  img   Imagination Technologies Ltd.
+ inforce       Inforce Computing
  ingenic       Ingenic Semiconductor
  innolux       Innolux Corporation
  intel Intel Corporation
@@@ -158,7 -156,6 +162,7 @@@ mitsubishi Mitsubishi Electric Corporat
  mosaixtech    Mosaix Technologies, Inc.
  moxa  Moxa
  mpl   MPL AG
 +mqmaker       mqmaker Inc.
  msi   Micro-Star International Co. Ltd.
  mti   Imagination Technologies Ltd. (formerly MIPS Technologies Inc.)
  mundoreader   Mundo Reader S.L.
@@@ -178,14 -175,12 +182,14 @@@ nvidia  NVIDI
  nxp   NXP Semiconductors
  okaya Okaya Electric America, Inc.
  olimex        OLIMEX Ltd.
 +onion Onion Corporation
  onnn  ON Semiconductor Corp.
  opencores     OpenCores.org
  option        Option NV
  ortustech     Ortus Technology Co., Ltd.
  ovti  OmniVision Technologies
  ORCL  Oracle Corporation
 +oxsemi        Oxford Semiconductor, Ltd.
  panasonic     Panasonic Corporation
  parade        Parade Technologies Inc.
  pericom       Pericom Technology Inc.
@@@ -259,7 -254,6 +263,7 @@@ tplink     TP-LINK Technologies Co., Ltd
  tronfy        Tronfy
  tronsmart     Tronsmart
  truly Truly Semiconductors Limited
 +tyan  Tyan Computer Corporation
  upisemi       uPI Semiconductor Corp.
  urt   United Radiant Technology Corporation
  usi   Universal Scientific Industrial Co., Ltd.
@@@ -269,7 -263,6 +273,7 @@@ via        VIA Technologies, Inc
  virtio        Virtual I/O Device Specification, developed by the OASIS consortium
  vivante       Vivante Corporation
  voipac        Voipac Technologies s.r.o.
 +wd    Western Digital Corp.
  wexler        Wexler
  winbond Winbond Electronics corp.
  wlf   Wolfson Microelectronics
diff --combined drivers/iommu/arm-smmu.c
index 0360919a5737afcdcca8d741b93f4cd087ac4a59,a1c965cdcfade905901d16b8984e69182e881896..e206ce7a4e4bdb7ed2fb1a7d60dd1ea90e15cb0c
@@@ -34,7 -34,6 +34,7 @@@
  #include <linux/err.h>
  #include <linux/interrupt.h>
  #include <linux/io.h>
 +#include <linux/io-64-nonatomic-hi-lo.h>
  #include <linux/iommu.h>
  #include <linux/iopoll.h>
  #include <linux/module.h>
@@@ -50,7 -49,7 +50,7 @@@
  #include "io-pgtable.h"
  
  /* Maximum number of stream IDs assigned to a single device */
- #define MAX_MASTER_STREAMIDS          MAX_PHANDLE_ARGS
+ #define MAX_MASTER_STREAMIDS          128
  
  /* Maximum number of context banks per SMMU */
  #define ARM_SMMU_MAX_CBS              128
                ((smmu->options & ARM_SMMU_OPT_SECURE_CFG_ACCESS)       \
                        ? 0x400 : 0))
  
 +/*
 + * Some 64-bit registers only make sense to write atomically, but in such
 + * cases all the data relevant to AArch32 formats lies within the lower word,
 + * therefore this actually makes more sense than it might first appear.
 + */
  #ifdef CONFIG_64BIT
 -#define smmu_writeq   writeq_relaxed
 +#define smmu_write_atomic_lq          writeq_relaxed
  #else
 -#define smmu_writeq(reg64, addr)                              \
 -      do {                                                    \
 -              u64 __val = (reg64);                            \
 -              void __iomem *__addr = (addr);                  \
 -              writel_relaxed(__val >> 32, __addr + 4);        \
 -              writel_relaxed(__val, __addr);                  \
 -      } while (0)
 +#define smmu_write_atomic_lq          writel_relaxed
  #endif
  
  /* Configuration registers */
  #define sCR0_VMIDPNE                  (1 << 11)
  #define sCR0_PTM                      (1 << 12)
  #define sCR0_FB                               (1 << 13)
 +#define sCR0_VMID16EN                 (1 << 31)
  #define sCR0_BSU_SHIFT                        14
  #define sCR0_BSU_MASK                 0x3
  
 +/* Auxiliary Configuration register */
 +#define ARM_SMMU_GR0_sACR             0x10
 +
  /* Identification registers */
  #define ARM_SMMU_GR0_ID0              0x20
  #define ARM_SMMU_GR0_ID1              0x24
  #define ID0_NTS                               (1 << 28)
  #define ID0_SMS                               (1 << 27)
  #define ID0_ATOSNS                    (1 << 26)
 +#define ID0_PTFS_NO_AARCH32           (1 << 25)
 +#define ID0_PTFS_NO_AARCH32S          (1 << 24)
  #define ID0_CTTW                      (1 << 14)
  #define ID0_NUMIRPT_SHIFT             16
  #define ID0_NUMIRPT_MASK              0xff
  #define ID2_PTFS_4K                   (1 << 12)
  #define ID2_PTFS_16K                  (1 << 13)
  #define ID2_PTFS_64K                  (1 << 14)
 +#define ID2_VMID16                    (1 << 15)
 +
 +#define ID7_MAJOR_SHIFT                       4
 +#define ID7_MAJOR_MASK                        0xf
  
  /* Global TLB invalidation */
  #define ARM_SMMU_GR0_TLBIVMID         0x64
  #define ARM_SMMU_GR1_CBA2R(n)         (0x800 + ((n) << 2))
  #define CBA2R_RW64_32BIT              (0 << 0)
  #define CBA2R_RW64_64BIT              (1 << 0)
 +#define CBA2R_VMID_SHIFT              16
 +#define CBA2R_VMID_MASK                       0xffff
  
  /* Translation context bank */
  #define ARM_SMMU_CB_BASE(smmu)                ((smmu)->base + ((smmu)->size >> 1))
  #define ARM_SMMU_CB(smmu, n)          ((n) * (1 << (smmu)->pgshift))
  
  #define ARM_SMMU_CB_SCTLR             0x0
 +#define ARM_SMMU_CB_ACTLR             0x4
  #define ARM_SMMU_CB_RESUME            0x8
  #define ARM_SMMU_CB_TTBCR2            0x10
  #define ARM_SMMU_CB_TTBR0             0x20
  #define ARM_SMMU_CB_TTBCR             0x30
  #define ARM_SMMU_CB_S1_MAIR0          0x38
  #define ARM_SMMU_CB_S1_MAIR1          0x3c
 -#define ARM_SMMU_CB_PAR_LO            0x50
 -#define ARM_SMMU_CB_PAR_HI            0x54
 +#define ARM_SMMU_CB_PAR                       0x50
  #define ARM_SMMU_CB_FSR                       0x58
 -#define ARM_SMMU_CB_FAR_LO            0x60
 -#define ARM_SMMU_CB_FAR_HI            0x64
 +#define ARM_SMMU_CB_FAR                       0x60
  #define ARM_SMMU_CB_FSYNR0            0x68
  #define ARM_SMMU_CB_S1_TLBIVA         0x600
  #define ARM_SMMU_CB_S1_TLBIASID               0x610
  #define SCTLR_M                               (1 << 0)
  #define SCTLR_EAE_SBOP                        (SCTLR_AFE | SCTLR_TRE)
  
 +#define ARM_MMU500_ACTLR_CPRE         (1 << 1)
 +
 +#define ARM_MMU500_ACR_CACHE_LOCK     (1 << 26)
 +
  #define CB_PAR_F                      (1 << 0)
  
  #define ATSR_ACTIVE                   (1 << 0)
@@@ -285,17 -270,10 +285,17 @@@ MODULE_PARM_DESC(disable_bypass
        "Disable bypass streams such that incoming transactions from devices that are not attached to an iommu domain will report an abort back to the device and will not be allowed to pass through the SMMU.");
  
  enum arm_smmu_arch_version {
 -      ARM_SMMU_V1 = 1,
 +      ARM_SMMU_V1,
 +      ARM_SMMU_V1_64K,
        ARM_SMMU_V2,
  };
  
 +enum arm_smmu_implementation {
 +      GENERIC_SMMU,
 +      ARM_MMU500,
 +      CAVIUM_SMMUV2,
 +};
 +
  struct arm_smmu_smr {
        u8                              idx;
        u16                             mask;
@@@ -327,18 -305,11 +327,18 @@@ struct arm_smmu_device 
  #define ARM_SMMU_FEAT_TRANS_S2                (1 << 3)
  #define ARM_SMMU_FEAT_TRANS_NESTED    (1 << 4)
  #define ARM_SMMU_FEAT_TRANS_OPS               (1 << 5)
 +#define ARM_SMMU_FEAT_VMID16          (1 << 6)
 +#define ARM_SMMU_FEAT_FMT_AARCH64_4K  (1 << 7)
 +#define ARM_SMMU_FEAT_FMT_AARCH64_16K (1 << 8)
 +#define ARM_SMMU_FEAT_FMT_AARCH64_64K (1 << 9)
 +#define ARM_SMMU_FEAT_FMT_AARCH32_L   (1 << 10)
 +#define ARM_SMMU_FEAT_FMT_AARCH32_S   (1 << 11)
        u32                             features;
  
  #define ARM_SMMU_OPT_SECURE_CFG_ACCESS (1 << 0)
        u32                             options;
        enum arm_smmu_arch_version      version;
 +      enum arm_smmu_implementation    model;
  
        u32                             num_context_banks;
        u32                             num_s2_context_banks;
        unsigned long                   va_size;
        unsigned long                   ipa_size;
        unsigned long                   pa_size;
 +      unsigned long                   pgsize_bitmap;
  
        u32                             num_global_irqs;
        u32                             num_context_irqs;
  
        struct list_head                list;
        struct rb_root                  masters;
 +
 +      u32                             cavium_id_base; /* Specific to Cavium */
 +};
 +
 +enum arm_smmu_context_fmt {
 +      ARM_SMMU_CTX_FMT_NONE,
 +      ARM_SMMU_CTX_FMT_AARCH64,
 +      ARM_SMMU_CTX_FMT_AARCH32_L,
 +      ARM_SMMU_CTX_FMT_AARCH32_S,
  };
  
  struct arm_smmu_cfg {
        u8                              cbndx;
        u8                              irptndx;
        u32                             cbar;
 +      enum arm_smmu_context_fmt       fmt;
  };
  #define INVALID_IRPTNDX                       0xff
  
 -#define ARM_SMMU_CB_ASID(cfg)         ((cfg)->cbndx)
 -#define ARM_SMMU_CB_VMID(cfg)         ((cfg)->cbndx + 1)
 +#define ARM_SMMU_CB_ASID(smmu, cfg) ((u16)(smmu)->cavium_id_base + (cfg)->cbndx)
 +#define ARM_SMMU_CB_VMID(smmu, cfg) ((u16)(smmu)->cavium_id_base + (cfg)->cbndx + 1)
  
  enum arm_smmu_domain_stage {
        ARM_SMMU_DOMAIN_S1 = 0,
@@@ -397,6 -357,14 +397,12 @@@ struct arm_smmu_domain 
        struct iommu_domain             domain;
  };
  
 -static struct iommu_ops arm_smmu_ops;
 -
+ struct arm_smmu_phandle_args {
+       struct device_node *np;
+       int args_count;
+       uint32_t args[MAX_MASTER_STREAMIDS];
+ };
  static DEFINE_SPINLOCK(arm_smmu_devices_lock);
  static LIST_HEAD(arm_smmu_devices);
  
@@@ -405,8 -373,6 +411,8 @@@ struct arm_smmu_option_prop 
        const char *prop;
  };
  
 +static atomic_t cavium_smmu_context_count = ATOMIC_INIT(0);
 +
  static struct arm_smmu_option_prop arm_smmu_options[] = {
        { ARM_SMMU_OPT_SECURE_CFG_ACCESS, "calxeda,smmu-secure-config-access" },
        { 0, NULL},
@@@ -506,7 -472,7 +512,7 @@@ static int insert_smmu_master(struct ar
  
  static int register_smmu_master(struct arm_smmu_device *smmu,
                                struct device *dev,
-                               struct of_phandle_args *masterspec)
+                               struct arm_smmu_phandle_args *masterspec)
  {
        int i;
        struct arm_smmu_master *master;
@@@ -618,11 -584,11 +624,11 @@@ static void arm_smmu_tlb_inv_context(vo
  
        if (stage1) {
                base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
 -              writel_relaxed(ARM_SMMU_CB_ASID(cfg),
 +              writel_relaxed(ARM_SMMU_CB_ASID(smmu, cfg),
                               base + ARM_SMMU_CB_S1_TLBIASID);
        } else {
                base = ARM_SMMU_GR0(smmu);
 -              writel_relaxed(ARM_SMMU_CB_VMID(cfg),
 +              writel_relaxed(ARM_SMMU_CB_VMID(smmu, cfg),
                               base + ARM_SMMU_GR0_TLBIVMID);
        }
  
@@@ -642,33 -608,37 +648,33 @@@ static void arm_smmu_tlb_inv_range_nosy
                reg = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
                reg += leaf ? ARM_SMMU_CB_S1_TLBIVAL : ARM_SMMU_CB_S1_TLBIVA;
  
 -              if (!IS_ENABLED(CONFIG_64BIT) || smmu->version == ARM_SMMU_V1) {
 +              if (cfg->fmt != ARM_SMMU_CTX_FMT_AARCH64) {
                        iova &= ~12UL;
 -                      iova |= ARM_SMMU_CB_ASID(cfg);
 +                      iova |= ARM_SMMU_CB_ASID(smmu, cfg);
                        do {
                                writel_relaxed(iova, reg);
                                iova += granule;
                        } while (size -= granule);
 -#ifdef CONFIG_64BIT
                } else {
                        iova >>= 12;
 -                      iova |= (u64)ARM_SMMU_CB_ASID(cfg) << 48;
 +                      iova |= (u64)ARM_SMMU_CB_ASID(smmu, cfg) << 48;
                        do {
                                writeq_relaxed(iova, reg);
                                iova += granule >> 12;
                        } while (size -= granule);
 -#endif
                }
 -#ifdef CONFIG_64BIT
        } else if (smmu->version == ARM_SMMU_V2) {
                reg = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
                reg += leaf ? ARM_SMMU_CB_S2_TLBIIPAS2L :
                              ARM_SMMU_CB_S2_TLBIIPAS2;
                iova >>= 12;
                do {
 -                      writeq_relaxed(iova, reg);
 +                      smmu_write_atomic_lq(iova, reg);
                        iova += granule >> 12;
                } while (size -= granule);
 -#endif
        } else {
                reg = ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_TLBIVMID;
 -              writel_relaxed(ARM_SMMU_CB_VMID(cfg), reg);
 +              writel_relaxed(ARM_SMMU_CB_VMID(smmu, cfg), reg);
        }
  }
  
@@@ -681,7 -651,7 +687,7 @@@ static struct iommu_gather_ops arm_smmu
  static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
  {
        int flags, ret;
 -      u32 fsr, far, fsynr, resume;
 +      u32 fsr, fsynr, resume;
        unsigned long iova;
        struct iommu_domain *domain = dev;
        struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
        fsynr = readl_relaxed(cb_base + ARM_SMMU_CB_FSYNR0);
        flags = fsynr & FSYNR0_WNR ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ;
  
 -      far = readl_relaxed(cb_base + ARM_SMMU_CB_FAR_LO);
 -      iova = far;
 -#ifdef CONFIG_64BIT
 -      far = readl_relaxed(cb_base + ARM_SMMU_CB_FAR_HI);
 -      iova |= ((unsigned long)far << 32);
 -#endif
 -
 +      iova = readq_relaxed(cb_base + ARM_SMMU_CB_FAR);
        if (!report_iommu_fault(domain, smmu->dev, iova, flags)) {
                ret = IRQ_HANDLED;
                resume = RESUME_RETRY;
@@@ -764,20 -740,22 +770,20 @@@ static void arm_smmu_init_context_bank(
        cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
  
        if (smmu->version > ARM_SMMU_V1) {
 -              /*
 -               * CBA2R.
 -               * *Must* be initialised before CBAR thanks to VMID16
 -               * architectural oversight affected some implementations.
 -               */
 -#ifdef CONFIG_64BIT
 -              reg = CBA2R_RW64_64BIT;
 -#else
 -              reg = CBA2R_RW64_32BIT;
 -#endif
 +              if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64)
 +                      reg = CBA2R_RW64_64BIT;
 +              else
 +                      reg = CBA2R_RW64_32BIT;
 +              /* 16-bit VMIDs live in CBA2R */
 +              if (smmu->features & ARM_SMMU_FEAT_VMID16)
 +                      reg |= ARM_SMMU_CB_VMID(smmu, cfg) << CBA2R_VMID_SHIFT;
 +
                writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBA2R(cfg->cbndx));
        }
  
        /* CBAR */
        reg = cfg->cbar;
 -      if (smmu->version == ARM_SMMU_V1)
 +      if (smmu->version < ARM_SMMU_V2)
                reg |= cfg->irptndx << CBAR_IRPTNDX_SHIFT;
  
        /*
        if (stage1) {
                reg |= (CBAR_S1_BPSHCFG_NSH << CBAR_S1_BPSHCFG_SHIFT) |
                        (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
 -      } else {
 -              reg |= ARM_SMMU_CB_VMID(cfg) << CBAR_VMID_SHIFT;
 +      } else if (!(smmu->features & ARM_SMMU_FEAT_VMID16)) {
 +              /* 8-bit VMIDs live in CBAR */
 +              reg |= ARM_SMMU_CB_VMID(smmu, cfg) << CBAR_VMID_SHIFT;
        }
        writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(cfg->cbndx));
  
        if (stage1) {
                reg64 = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0];
  
 -              reg64 |= ((u64)ARM_SMMU_CB_ASID(cfg)) << TTBRn_ASID_SHIFT;
 -              smmu_writeq(reg64, cb_base + ARM_SMMU_CB_TTBR0);
 +              reg64 |= ((u64)ARM_SMMU_CB_ASID(smmu, cfg)) << TTBRn_ASID_SHIFT;
 +              writeq_relaxed(reg64, cb_base + ARM_SMMU_CB_TTBR0);
  
                reg64 = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[1];
 -              reg64 |= ((u64)ARM_SMMU_CB_ASID(cfg)) << TTBRn_ASID_SHIFT;
 -              smmu_writeq(reg64, cb_base + ARM_SMMU_CB_TTBR1);
 +              reg64 |= ((u64)ARM_SMMU_CB_ASID(smmu, cfg)) << TTBRn_ASID_SHIFT;
 +              writeq_relaxed(reg64, cb_base + ARM_SMMU_CB_TTBR1);
        } else {
                reg64 = pgtbl_cfg->arm_lpae_s2_cfg.vttbr;
 -              smmu_writeq(reg64, cb_base + ARM_SMMU_CB_TTBR0);
 +              writeq_relaxed(reg64, cb_base + ARM_SMMU_CB_TTBR0);
        }
  
        /* TTBCR */
@@@ -855,12 -832,6 +861,12 @@@ static int arm_smmu_init_domain_context
        if (smmu_domain->smmu)
                goto out_unlock;
  
 +      /* We're bypassing these SIDs, so don't allocate an actual context */
 +      if (domain->type == IOMMU_DOMAIN_DMA) {
 +              smmu_domain->smmu = smmu;
 +              goto out_unlock;
 +      }
 +
        /*
         * Mapping the requested stage onto what we support is surprisingly
         * complicated, mainly because the spec allows S1+S2 SMMUs without
        if (!(smmu->features & ARM_SMMU_FEAT_TRANS_S2))
                smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
  
 +      /*
 +       * Choosing a suitable context format is even more fiddly. Until we
 +       * grow some way for the caller to express a preference, and/or move
 +       * the decision into the io-pgtable code where it arguably belongs,
 +       * just aim for the closest thing to the rest of the system, and hope
 +       * that the hardware isn't esoteric enough that we can't assume AArch64
 +       * support to be a superset of AArch32 support...
 +       */
 +      if (smmu->features & ARM_SMMU_FEAT_FMT_AARCH32_L)
 +              cfg->fmt = ARM_SMMU_CTX_FMT_AARCH32_L;
 +      if ((IS_ENABLED(CONFIG_64BIT) || cfg->fmt == ARM_SMMU_CTX_FMT_NONE) &&
 +          (smmu->features & (ARM_SMMU_FEAT_FMT_AARCH64_64K |
 +                             ARM_SMMU_FEAT_FMT_AARCH64_16K |
 +                             ARM_SMMU_FEAT_FMT_AARCH64_4K)))
 +              cfg->fmt = ARM_SMMU_CTX_FMT_AARCH64;
 +
 +      if (cfg->fmt == ARM_SMMU_CTX_FMT_NONE) {
 +              ret = -EINVAL;
 +              goto out_unlock;
 +      }
 +
        switch (smmu_domain->stage) {
        case ARM_SMMU_DOMAIN_S1:
                cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS;
                start = smmu->num_s2_context_banks;
                ias = smmu->va_size;
                oas = smmu->ipa_size;
 -              if (IS_ENABLED(CONFIG_64BIT))
 +              if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64) {
                        fmt = ARM_64_LPAE_S1;
 -              else
 +              } else {
                        fmt = ARM_32_LPAE_S1;
 +                      ias = min(ias, 32UL);
 +                      oas = min(oas, 40UL);
 +              }
                break;
        case ARM_SMMU_DOMAIN_NESTED:
                /*
                start = 0;
                ias = smmu->ipa_size;
                oas = smmu->pa_size;
 -              if (IS_ENABLED(CONFIG_64BIT))
 +              if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64) {
                        fmt = ARM_64_LPAE_S2;
 -              else
 +              } else {
                        fmt = ARM_32_LPAE_S2;
 +                      ias = min(ias, 40UL);
 +                      oas = min(oas, 40UL);
 +              }
                break;
        default:
                ret = -EINVAL;
                goto out_unlock;
  
        cfg->cbndx = ret;
 -      if (smmu->version == ARM_SMMU_V1) {
 +      if (smmu->version < ARM_SMMU_V2) {
                cfg->irptndx = atomic_inc_return(&smmu->irptndx);
                cfg->irptndx %= smmu->num_context_irqs;
        } else {
        }
  
        pgtbl_cfg = (struct io_pgtable_cfg) {
 -              .pgsize_bitmap  = arm_smmu_ops.pgsize_bitmap,
 +              .pgsize_bitmap  = smmu->pgsize_bitmap,
                .ias            = ias,
                .oas            = oas,
                .tlb            = &arm_smmu_gather_ops,
                goto out_clear_smmu;
        }
  
 -      /* Update our support page sizes to reflect the page table format */
 -      arm_smmu_ops.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
 +      /* Update the domain's page sizes to reflect the page table format */
 +      domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
  
        /* Initialise the context bank with our page table cfg */
        arm_smmu_init_context_bank(smmu_domain, &pgtbl_cfg);
@@@ -1010,7 -954,7 +1016,7 @@@ static void arm_smmu_destroy_domain_con
        void __iomem *cb_base;
        int irq;
  
 -      if (!smmu)
 +      if (!smmu || domain->type == IOMMU_DOMAIN_DMA)
                return;
  
        /*
@@@ -1151,20 -1095,18 +1157,20 @@@ static int arm_smmu_domain_add_master(s
        struct arm_smmu_device *smmu = smmu_domain->smmu;
        void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
  
 -      /* Devices in an IOMMU group may already be configured */
 -      ret = arm_smmu_master_configure_smrs(smmu, cfg);
 -      if (ret)
 -              return ret == -EEXIST ? 0 : ret;
 -
        /*
         * FIXME: This won't be needed once we have IOMMU-backed DMA ops
 -       * for all devices behind the SMMU.
 +       * for all devices behind the SMMU. Note that we need to take
 +       * care configuring SMRs for devices both a platform_device and
 +       * and a PCI device (i.e. a PCI host controller)
         */
        if (smmu_domain->domain.type == IOMMU_DOMAIN_DMA)
                return 0;
  
 +      /* Devices in an IOMMU group may already be configured */
 +      ret = arm_smmu_master_configure_smrs(smmu, cfg);
 +      if (ret)
 +              return ret == -EEXIST ? 0 : ret;
 +
        for (i = 0; i < cfg->num_streamids; ++i) {
                u32 idx, s2cr;
  
@@@ -1308,8 -1250,8 +1314,8 @@@ static phys_addr_t arm_smmu_iova_to_phy
        /* ATS1 registers can only be written atomically */
        va = iova & ~0xfffUL;
        if (smmu->version == ARM_SMMU_V2)
 -              smmu_writeq(va, cb_base + ARM_SMMU_CB_ATS1PR);
 -      else
 +              smmu_write_atomic_lq(va, cb_base + ARM_SMMU_CB_ATS1PR);
 +      else /* Register is only 32-bit in v1 */
                writel_relaxed(va, cb_base + ARM_SMMU_CB_ATS1PR);
  
        if (readl_poll_timeout_atomic(cb_base + ARM_SMMU_CB_ATSR, tmp,
                return ops->iova_to_phys(ops, iova);
        }
  
 -      phys = readl_relaxed(cb_base + ARM_SMMU_CB_PAR_LO);
 -      phys |= ((u64)readl_relaxed(cb_base + ARM_SMMU_CB_PAR_HI)) << 32;
 -
 +      phys = readq_relaxed(cb_base + ARM_SMMU_CB_PAR);
        if (phys & CB_PAR_F) {
                dev_err(dev, "translation fault!\n");
                dev_err(dev, "PAR = 0x%llx\n", phys);
@@@ -1546,7 -1490,7 +1552,7 @@@ static void arm_smmu_device_reset(struc
        void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
        void __iomem *cb_base;
        int i = 0;
 -      u32 reg;
 +      u32 reg, major;
  
        /* clear global FSR */
        reg = readl_relaxed(ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sGFSR);
                writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_S2CR(i));
        }
  
 +      /*
 +       * Before clearing ARM_MMU500_ACTLR_CPRE, need to
 +       * clear CACHE_LOCK bit of ACR first. And, CACHE_LOCK
 +       * bit is only present in MMU-500r2 onwards.
 +       */
 +      reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID7);
 +      major = (reg >> ID7_MAJOR_SHIFT) & ID7_MAJOR_MASK;
 +      if ((smmu->model == ARM_MMU500) && (major >= 2)) {
 +              reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_sACR);
 +              reg &= ~ARM_MMU500_ACR_CACHE_LOCK;
 +              writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_sACR);
 +      }
 +
        /* Make sure all context banks are disabled and clear CB_FSR  */
        for (i = 0; i < smmu->num_context_banks; ++i) {
                cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, i);
                writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR);
                writel_relaxed(FSR_FAULT, cb_base + ARM_SMMU_CB_FSR);
 +              /*
 +               * Disable MMU-500's not-particularly-beneficial next-page
 +               * prefetcher for the sake of errata #841119 and #826419.
 +               */
 +              if (smmu->model == ARM_MMU500) {
 +                      reg = readl_relaxed(cb_base + ARM_SMMU_CB_ACTLR);
 +                      reg &= ~ARM_MMU500_ACTLR_CPRE;
 +                      writel_relaxed(reg, cb_base + ARM_SMMU_CB_ACTLR);
 +              }
        }
  
        /* Invalidate the TLB, just in case */
        /* Don't upgrade barriers */
        reg &= ~(sCR0_BSU_MASK << sCR0_BSU_SHIFT);
  
 +      if (smmu->features & ARM_SMMU_FEAT_VMID16)
 +              reg |= sCR0_VMID16EN;
 +
        /* Push the button */
        __arm_smmu_tlb_sync(smmu);
        writel(reg, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0);
@@@ -1648,8 -1567,7 +1654,8 @@@ static int arm_smmu_device_cfg_probe(st
        bool cttw_dt, cttw_reg;
  
        dev_notice(smmu->dev, "probing hardware configuration...\n");
 -      dev_notice(smmu->dev, "SMMUv%d with:\n", smmu->version);
 +      dev_notice(smmu->dev, "SMMUv%d with:\n",
 +                      smmu->version == ARM_SMMU_V2 ? 2 : 1);
  
        /* ID0 */
        id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID0);
                return -ENODEV;
        }
  
 -      if ((id & ID0_S1TS) && ((smmu->version == 1) || !(id & ID0_ATOSNS))) {
 +      if ((id & ID0_S1TS) &&
 +              ((smmu->version < ARM_SMMU_V2) || !(id & ID0_ATOSNS))) {
                smmu->features |= ARM_SMMU_FEAT_TRANS_OPS;
                dev_notice(smmu->dev, "\taddress translation ops\n");
        }
                                           ID0_NUMSIDB_MASK;
        }
  
 +      if (smmu->version < ARM_SMMU_V2 || !(id & ID0_PTFS_NO_AARCH32)) {
 +              smmu->features |= ARM_SMMU_FEAT_FMT_AARCH32_L;
 +              if (!(id & ID0_PTFS_NO_AARCH32S))
 +                      smmu->features |= ARM_SMMU_FEAT_FMT_AARCH32_S;
 +      }
 +
        /* ID1 */
        id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID1);
        smmu->pgshift = (id & ID1_PAGESIZE) ? 16 : 12;
        }
        dev_notice(smmu->dev, "\t%u context banks (%u stage-2 only)\n",
                   smmu->num_context_banks, smmu->num_s2_context_banks);
 +      /*
 +       * Cavium CN88xx erratum #27704.
 +       * Ensure ASID and VMID allocation is unique across all SMMUs in
 +       * the system.
 +       */
 +      if (smmu->model == CAVIUM_SMMUV2) {
 +              smmu->cavium_id_base =
 +                      atomic_add_return(smmu->num_context_banks,
 +                                        &cavium_smmu_context_count);
 +              smmu->cavium_id_base -= smmu->num_context_banks;
 +      }
  
        /* ID2 */
        id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID2);
        size = arm_smmu_id_size_to_bits((id >> ID2_OAS_SHIFT) & ID2_OAS_MASK);
        smmu->pa_size = size;
  
 +      if (id & ID2_VMID16)
 +              smmu->features |= ARM_SMMU_FEAT_VMID16;
 +
        /*
         * What the page table walker can address actually depends on which
         * descriptor format is in use, but since a) we don't know that yet,
                dev_warn(smmu->dev,
                         "failed to set DMA mask for table walker\n");
  
 -      if (smmu->version == ARM_SMMU_V1) {
 +      if (smmu->version < ARM_SMMU_V2) {
                smmu->va_size = smmu->ipa_size;
 -              size = SZ_4K | SZ_2M | SZ_1G;
 +              if (smmu->version == ARM_SMMU_V1_64K)
 +                      smmu->features |= ARM_SMMU_FEAT_FMT_AARCH64_64K;
        } else {
                size = (id >> ID2_UBS_SHIFT) & ID2_UBS_MASK;
                smmu->va_size = arm_smmu_id_size_to_bits(size);
 -#ifndef CONFIG_64BIT
 -              smmu->va_size = min(32UL, smmu->va_size);
 -#endif
 -              size = 0;
                if (id & ID2_PTFS_4K)
 -                      size |= SZ_4K | SZ_2M | SZ_1G;
 +                      smmu->features |= ARM_SMMU_FEAT_FMT_AARCH64_4K;
                if (id & ID2_PTFS_16K)
 -                      size |= SZ_16K | SZ_32M;
 +                      smmu->features |= ARM_SMMU_FEAT_FMT_AARCH64_16K;
                if (id & ID2_PTFS_64K)
 -                      size |= SZ_64K | SZ_512M;
 +                      smmu->features |= ARM_SMMU_FEAT_FMT_AARCH64_64K;
        }
  
 -      arm_smmu_ops.pgsize_bitmap &= size;
 -      dev_notice(smmu->dev, "\tSupported page sizes: 0x%08lx\n", size);
 +      /* Now we've corralled the various formats, what'll it do? */
 +      if (smmu->features & ARM_SMMU_FEAT_FMT_AARCH32_S)
 +              smmu->pgsize_bitmap |= SZ_4K | SZ_64K | SZ_1M | SZ_16M;
 +      if (smmu->features &
 +          (ARM_SMMU_FEAT_FMT_AARCH32_L | ARM_SMMU_FEAT_FMT_AARCH64_4K))
 +              smmu->pgsize_bitmap |= SZ_4K | SZ_2M | SZ_1G;
 +      if (smmu->features & ARM_SMMU_FEAT_FMT_AARCH64_16K)
 +              smmu->pgsize_bitmap |= SZ_16K | SZ_32M;
 +      if (smmu->features & ARM_SMMU_FEAT_FMT_AARCH64_64K)
 +              smmu->pgsize_bitmap |= SZ_64K | SZ_512M;
 +
 +      if (arm_smmu_ops.pgsize_bitmap == -1UL)
 +              arm_smmu_ops.pgsize_bitmap = smmu->pgsize_bitmap;
 +      else
 +              arm_smmu_ops.pgsize_bitmap |= smmu->pgsize_bitmap;
 +      dev_notice(smmu->dev, "\tSupported page sizes: 0x%08lx\n",
 +                 smmu->pgsize_bitmap);
 +
  
        if (smmu->features & ARM_SMMU_FEAT_TRANS_S1)
                dev_notice(smmu->dev, "\tStage-1: %lu-bit VA -> %lu-bit IPA\n",
        return 0;
  }
  
 +struct arm_smmu_match_data {
 +      enum arm_smmu_arch_version version;
 +      enum arm_smmu_implementation model;
 +};
 +
 +#define ARM_SMMU_MATCH_DATA(name, ver, imp)   \
 +static struct arm_smmu_match_data name = { .version = ver, .model = imp }
 +
 +ARM_SMMU_MATCH_DATA(smmu_generic_v1, ARM_SMMU_V1, GENERIC_SMMU);
 +ARM_SMMU_MATCH_DATA(smmu_generic_v2, ARM_SMMU_V2, GENERIC_SMMU);
 +ARM_SMMU_MATCH_DATA(arm_mmu401, ARM_SMMU_V1_64K, GENERIC_SMMU);
 +ARM_SMMU_MATCH_DATA(arm_mmu500, ARM_SMMU_V2, ARM_MMU500);
 +ARM_SMMU_MATCH_DATA(cavium_smmuv2, ARM_SMMU_V2, CAVIUM_SMMUV2);
 +
  static const struct of_device_id arm_smmu_of_match[] = {
 -      { .compatible = "arm,smmu-v1", .data = (void *)ARM_SMMU_V1 },
 -      { .compatible = "arm,smmu-v2", .data = (void *)ARM_SMMU_V2 },
 -      { .compatible = "arm,mmu-400", .data = (void *)ARM_SMMU_V1 },
 -      { .compatible = "arm,mmu-401", .data = (void *)ARM_SMMU_V1 },
 -      { .compatible = "arm,mmu-500", .data = (void *)ARM_SMMU_V2 },
 +      { .compatible = "arm,smmu-v1", .data = &smmu_generic_v1 },
 +      { .compatible = "arm,smmu-v2", .data = &smmu_generic_v2 },
 +      { .compatible = "arm,mmu-400", .data = &smmu_generic_v1 },
 +      { .compatible = "arm,mmu-401", .data = &arm_mmu401 },
 +      { .compatible = "arm,mmu-500", .data = &arm_mmu500 },
 +      { .compatible = "cavium,smmu-v2", .data = &cavium_smmuv2 },
        { },
  };
  MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
  static int arm_smmu_device_dt_probe(struct platform_device *pdev)
  {
        const struct of_device_id *of_id;
 +      const struct arm_smmu_match_data *data;
        struct resource *res;
        struct arm_smmu_device *smmu;
        struct device *dev = &pdev->dev;
        struct rb_node *node;
-       struct of_phandle_args masterspec;
+       struct of_phandle_iterator it;
+       struct arm_smmu_phandle_args *masterspec;
        int num_irqs, i, err;
  
        smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
        smmu->dev = dev;
  
        of_id = of_match_node(arm_smmu_of_match, dev->of_node);
 -      smmu->version = (enum arm_smmu_arch_version)of_id->data;
 +      data = of_id->data;
 +      smmu->version = data->version;
 +      smmu->model = data->model;
  
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        smmu->base = devm_ioremap_resource(dev, res);
  
        i = 0;
        smmu->masters = RB_ROOT;
-       while (!of_parse_phandle_with_args(dev->of_node, "mmu-masters",
-                                          "#stream-id-cells", i,
-                                          &masterspec)) {
-               err = register_smmu_master(smmu, dev, &masterspec);
+       err = -ENOMEM;
+       /* No need to zero the memory for masterspec */
+       masterspec = kmalloc(sizeof(*masterspec), GFP_KERNEL);
+       if (!masterspec)
+               goto out_put_masters;
+       of_for_each_phandle(&it, err, dev->of_node,
+                           "mmu-masters", "#stream-id-cells", 0) {
+               int count = of_phandle_iterator_args(&it, masterspec->args,
+                                                    MAX_MASTER_STREAMIDS);
+               masterspec->np          = of_node_get(it.node);
+               masterspec->args_count  = count;
+               err = register_smmu_master(smmu, dev, masterspec);
                if (err) {
                        dev_err(dev, "failed to add master %s\n",
-                               masterspec.np->name);
+                               masterspec->np->name);
+                       kfree(masterspec);
                        goto out_put_masters;
                }
  
                i++;
        }
        dev_notice(dev, "registered %d master devices\n", i);
  
+       kfree(masterspec);
        parse_driver_options(smmu);
  
 -      if (smmu->version > ARM_SMMU_V1 &&
 +      if (smmu->version == ARM_SMMU_V2 &&
            smmu->num_context_banks != smmu->num_context_irqs) {
                dev_err(dev,
                        "found only %d context interrupt(s) but %d required\n",
diff --combined drivers/of/base.c
index 64018ebcc8618a967f7af26461e21b5e8075ce56,116666b088cc15da320fa07f901b2e397a604eea..ebf84e3b56d5a96b1ea4cb9879380e4daac29487
@@@ -394,7 -394,8 +394,8 @@@ bool __weak arch_find_n_match_cpu_physi
   * before booting secondary cores. This function uses arch_match_cpu_phys_id
   * which can be overridden by architecture specific implementation.
   *
-  * Returns a node pointer for the logical cpu if found, else NULL.
+  * Returns a node pointer for the logical cpu with refcount incremented, use
+  * of_node_put() on it when done. Returns NULL if not found.
   */
  struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
  {
@@@ -1440,106 -1441,155 +1441,155 @@@ void of_print_phandle_args(const char *
        printk("\n");
  }
  
static int __of_parse_phandle_with_args(const struct device_node *np,
-                                       const char *list_name,
-                                       const char *cells_name,
-                                       int cell_count, int index,
-                                       struct of_phandle_args *out_args)
int of_phandle_iterator_init(struct of_phandle_iterator *it,
+               const struct device_node *np,
+               const char *list_name,
+               const char *cells_name,
+               int cell_count)
  {
-       const __be32 *list, *list_end;
-       int rc = 0, size, cur_index = 0;
-       uint32_t count = 0;
-       struct device_node *node = NULL;
-       phandle phandle;
+       const __be32 *list;
+       int size;
+       memset(it, 0, sizeof(*it));
  
-       /* Retrieve the phandle list property */
        list = of_get_property(np, list_name, &size);
        if (!list)
                return -ENOENT;
-       list_end = list + size / sizeof(*list);
  
-       /* Loop over the phandles until all the requested entry is found */
-       while (list < list_end) {
-               rc = -EINVAL;
-               count = 0;
+       it->cells_name = cells_name;
+       it->cell_count = cell_count;
+       it->parent = np;
+       it->list_end = list + size / sizeof(*list);
+       it->phandle_end = list;
+       it->cur = list;
+       return 0;
+ }
+ int of_phandle_iterator_next(struct of_phandle_iterator *it)
+ {
+       uint32_t count = 0;
+       if (it->node) {
+               of_node_put(it->node);
+               it->node = NULL;
+       }
+       if (!it->cur || it->phandle_end >= it->list_end)
+               return -ENOENT;
+       it->cur = it->phandle_end;
+       /* If phandle is 0, then it is an empty entry with no arguments. */
+       it->phandle = be32_to_cpup(it->cur++);
+       if (it->phandle) {
  
                /*
-                * If phandle is 0, then it is an empty entry with no
-                * arguments.  Skip forward to the next entry.
+                * Find the provider node and parse the #*-cells property to
+                * determine the argument length.
                 */
-               phandle = be32_to_cpup(list++);
-               if (phandle) {
-                       /*
-                        * Find the provider node and parse the #*-cells
-                        * property to determine the argument length.
-                        *
-                        * This is not needed if the cell count is hard-coded
-                        * (i.e. cells_name not set, but cell_count is set),
-                        * except when we're going to return the found node
-                        * below.
-                        */
-                       if (cells_name || cur_index == index) {
-                               node = of_find_node_by_phandle(phandle);
-                               if (!node) {
-                                       pr_err("%s: could not find phandle\n",
-                                               np->full_name);
-                                       goto err;
-                               }
-                       }
+               it->node = of_find_node_by_phandle(it->phandle);
  
-                       if (cells_name) {
-                               if (of_property_read_u32(node, cells_name,
-                                                        &count)) {
-                                       pr_err("%s: could not get %s for %s\n",
-                                               np->full_name, cells_name,
-                                               node->full_name);
-                                       goto err;
-                               }
-                       } else {
-                               count = cell_count;
+               if (it->cells_name) {
+                       if (!it->node) {
+                               pr_err("%s: could not find phandle\n",
+                                      it->parent->full_name);
+                               goto err;
                        }
  
-                       /*
-                        * Make sure that the arguments actually fit in the
-                        * remaining property data length
-                        */
-                       if (list + count > list_end) {
-                               pr_err("%s: arguments longer than property\n",
-                                        np->full_name);
+                       if (of_property_read_u32(it->node, it->cells_name,
+                                                &count)) {
+                               pr_err("%s: could not get %s for %s\n",
+                                      it->parent->full_name,
+                                      it->cells_name,
+                                      it->node->full_name);
                                goto err;
                        }
+               } else {
+                       count = it->cell_count;
                }
  
                /*
-                * All of the error cases above bail out of the loop, so at
+                * Make sure that the arguments actually fit in the remaining
+                * property data length
+                */
+               if (it->cur + count > it->list_end) {
+                       pr_err("%s: arguments longer than property\n",
+                              it->parent->full_name);
+                       goto err;
+               }
+       }
+       it->phandle_end = it->cur + count;
+       it->cur_count = count;
+       return 0;
+ err:
+       if (it->node) {
+               of_node_put(it->node);
+               it->node = NULL;
+       }
+       return -EINVAL;
+ }
+ int of_phandle_iterator_args(struct of_phandle_iterator *it,
+                            uint32_t *args,
+                            int size)
+ {
+       int i, count;
+       count = it->cur_count;
+       if (WARN_ON(size < count))
+               count = size;
+       for (i = 0; i < count; i++)
+               args[i] = be32_to_cpup(it->cur++);
+       return count;
+ }
+ static int __of_parse_phandle_with_args(const struct device_node *np,
+                                       const char *list_name,
+                                       const char *cells_name,
+                                       int cell_count, int index,
+                                       struct of_phandle_args *out_args)
+ {
+       struct of_phandle_iterator it;
+       int rc, cur_index = 0;
+       /* Loop over the phandles until all the requested entry is found */
+       of_for_each_phandle(&it, rc, np, list_name, cells_name, cell_count) {
+               /*
+                * All of the error cases bail out of the loop, so at
                 * this point, the parsing is successful. If the requested
                 * index matches, then fill the out_args structure and return,
                 * or return -ENOENT for an empty entry.
                 */
                rc = -ENOENT;
                if (cur_index == index) {
-                       if (!phandle)
+                       if (!it.phandle)
                                goto err;
  
                        if (out_args) {
-                               int i;
-                               if (WARN_ON(count > MAX_PHANDLE_ARGS))
-                                       count = MAX_PHANDLE_ARGS;
-                               out_args->np = node;
-                               out_args->args_count = count;
-                               for (i = 0; i < count; i++)
-                                       out_args->args[i] = be32_to_cpup(list++);
+                               int c;
+                               c = of_phandle_iterator_args(&it,
+                                                            out_args->args,
+                                                            MAX_PHANDLE_ARGS);
+                               out_args->np = it.node;
+                               out_args->args_count = c;
                        } else {
-                               of_node_put(node);
+                               of_node_put(it.node);
                        }
  
                        /* Found it! return success */
                        return 0;
                }
  
-               of_node_put(node);
-               node = NULL;
-               list += count;
                cur_index++;
        }
  
         * Unlock node before returning result; will be one of:
         * -ENOENT : index is for empty phandle
         * -EINVAL : parsing error on data
-        * [1..n]  : Number of phandle (count mode; when index = -1)
         */
-       rc = index < 0 ? cur_index : -ENOENT;
   err:
-       if (node)
-               of_node_put(node);
+       if (it.node)
+               of_node_put(it.node);
        return rc;
  }
  
@@@ -1684,8 -1733,20 +1733,20 @@@ EXPORT_SYMBOL(of_parse_phandle_with_fix
  int of_count_phandle_with_args(const struct device_node *np, const char *list_name,
                                const char *cells_name)
  {
-       return __of_parse_phandle_with_args(np, list_name, cells_name, 0, -1,
-                                           NULL);
+       struct of_phandle_iterator it;
+       int rc, cur_index = 0;
+       rc = of_phandle_iterator_init(&it, np, list_name, cells_name, 0);
+       if (rc)
+               return rc;
+       while ((rc = of_phandle_iterator_next(&it)) == 0)
+               cur_index += 1;
+       if (rc != -ENOENT)
+               return rc;
+       return cur_index;
  }
  EXPORT_SYMBOL(of_count_phandle_with_args);
  
@@@ -1777,9 -1838,6 +1838,9 @@@ int of_remove_property(struct device_no
        unsigned long flags;
        int rc;
  
 +      if (!prop)
 +              return -ENODEV;
 +
        mutex_lock(&of_mutex);
  
        raw_spin_lock_irqsave(&devtree_lock, flags);
diff --combined drivers/of/unittest.c
index c1ebbfb794537b6bf553abeeff876bdbfe9ac670,3802be10d726b982445562200c8ab42a6d19c665..f34ed9310323cdb32e91e37bcf0404835edfd004
@@@ -8,7 -8,6 +8,6 @@@
  #include <linux/err.h>
  #include <linux/errno.h>
  #include <linux/hashtable.h>
- #include <linux/module.h>
  #include <linux/of.h>
  #include <linux/of_fdt.h>
  #include <linux/of_irq.h>
@@@ -921,7 -920,7 +920,7 @@@ static int __init unittest_data_add(voi
                        "not running tests\n", __func__);
                return -ENOMEM;
        }
-       of_fdt_unflatten_tree(unittest_data, &unittest_data_node);
+       of_fdt_unflatten_tree(unittest_data, NULL, &unittest_data_node);
        if (!unittest_data_node) {
                pr_warn("%s: No tree to attach; not running tests\n", __func__);
                return -ENODATA;
@@@ -1692,7 -1691,13 +1691,7 @@@ static struct i2c_driver unittest_i2c_d
  
  #if IS_BUILTIN(CONFIG_I2C_MUX)
  
 -struct unittest_i2c_mux_data {
 -      int nchans;
 -      struct i2c_adapter *adap[];
 -};
 -
 -static int unittest_i2c_mux_select_chan(struct i2c_adapter *adap,
 -                             void *client, u32 chan)
 +static int unittest_i2c_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
  {
        return 0;
  }
  static int unittest_i2c_mux_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
  {
 -      int ret, i, nchans, size;
 +      int ret, i, nchans;
        struct device *dev = &client->dev;
        struct i2c_adapter *adap = to_i2c_adapter(dev->parent);
        struct device_node *np = client->dev.of_node, *child;
 -      struct unittest_i2c_mux_data *stm;
 +      struct i2c_mux_core *muxc;
        u32 reg, max_reg;
  
        dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
                return -EINVAL;
        }
  
 -      size = offsetof(struct unittest_i2c_mux_data, adap[nchans]);
 -      stm = devm_kzalloc(dev, size, GFP_KERNEL);
 -      if (!stm) {
 -              dev_err(dev, "Out of memory\n");
 +      muxc = i2c_mux_alloc(adap, dev, nchans, 0, 0,
 +                           unittest_i2c_mux_select_chan, NULL);
 +      if (!muxc)
                return -ENOMEM;
 -      }
 -      stm->nchans = nchans;
        for (i = 0; i < nchans; i++) {
 -              stm->adap[i] = i2c_add_mux_adapter(adap, dev, client,
 -                              0, i, 0, unittest_i2c_mux_select_chan, NULL);
 -              if (!stm->adap[i]) {
 +              ret = i2c_mux_add_adapter(muxc, 0, i, 0);
 +              if (ret) {
                        dev_err(dev, "Failed to register mux #%d\n", i);
 -                      for (i--; i >= 0; i--)
 -                              i2c_del_mux_adapter(stm->adap[i]);
 +                      i2c_mux_del_adapters(muxc);
                        return -ENODEV;
                }
        }
  
 -      i2c_set_clientdata(client, stm);
 +      i2c_set_clientdata(client, muxc);
  
        return 0;
  };
@@@ -1750,10 -1760,12 +1749,10 @@@ static int unittest_i2c_mux_remove(stru
  {
        struct device *dev = &client->dev;
        struct device_node *np = client->dev.of_node;
 -      struct unittest_i2c_mux_data *stm = i2c_get_clientdata(client);
 -      int i;
 +      struct i2c_mux_core *muxc = i2c_get_clientdata(client);
  
        dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
 -      for (i = stm->nchans - 1; i >= 0; i--)
 -              i2c_del_mux_adapter(stm->adap[i]);
 +      i2c_mux_del_adapters(muxc);
        return 0;
  }
  
diff --combined include/linux/of.h
index 77ddace575e8f702ee5e4f49480b53cd14646814,71e1c35a59602be43b27533c5dd6600e40655cff..c7292e8ea080118b9d09542a875b95ebbddc31b3
@@@ -75,6 -75,23 +75,23 @@@ struct of_phandle_args 
        uint32_t args[MAX_PHANDLE_ARGS];
  };
  
+ struct of_phandle_iterator {
+       /* Common iterator information */
+       const char *cells_name;
+       int cell_count;
+       const struct device_node *parent;
+       /* List size information */
+       const __be32 *list_end;
+       const __be32 *phandle_end;
+       /* Current position state */
+       const __be32 *cur;
+       uint32_t cur_count;
+       phandle phandle;
+       struct device_node *node;
+ };
  struct of_reconfig_data {
        struct device_node      *dn;
        struct property         *prop;
@@@ -133,7 -150,7 +150,7 @@@ void of_core_init(void)
  
  static inline bool is_of_node(struct fwnode_handle *fwnode)
  {
 -      return fwnode && fwnode->type == FWNODE_OF;
 +      return !IS_ERR_OR_NULL(fwnode) && fwnode->type == FWNODE_OF;
  }
  
  static inline struct device_node *to_of_node(struct fwnode_handle *fwnode)
@@@ -334,6 -351,18 +351,18 @@@ extern int of_parse_phandle_with_fixed_
  extern int of_count_phandle_with_args(const struct device_node *np,
        const char *list_name, const char *cells_name);
  
+ /* phandle iterator functions */
+ extern int of_phandle_iterator_init(struct of_phandle_iterator *it,
+                                   const struct device_node *np,
+                                   const char *list_name,
+                                   const char *cells_name,
+                                   int cell_count);
+ extern int of_phandle_iterator_next(struct of_phandle_iterator *it);
+ extern int of_phandle_iterator_args(struct of_phandle_iterator *it,
+                                   uint32_t *args,
+                                   int size);
  extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align));
  extern int of_alias_get_id(struct device_node *np, const char *stem);
  extern int of_alias_get_highest_id(const char *stem);
@@@ -608,6 -637,27 +637,27 @@@ static inline int of_count_phandle_with
        return -ENOSYS;
  }
  
+ static inline int of_phandle_iterator_init(struct of_phandle_iterator *it,
+                                          const struct device_node *np,
+                                          const char *list_name,
+                                          const char *cells_name,
+                                          int cell_count)
+ {
+       return -ENOSYS;
+ }
+ static inline int of_phandle_iterator_next(struct of_phandle_iterator *it)
+ {
+       return -ENOSYS;
+ }
+ static inline int of_phandle_iterator_args(struct of_phandle_iterator *it,
+                                          uint32_t *args,
+                                          int size)
+ {
+       return 0;
+ }
  static inline int of_alias_get_id(struct device_node *np, const char *stem)
  {
        return -ENOSYS;
@@@ -685,15 -735,6 +735,15 @@@ static inline int of_node_to_nid(struc
  }
  #endif
  
 +#ifdef CONFIG_OF_NUMA
 +extern int of_numa_init(void);
 +#else
 +static inline int of_numa_init(void)
 +{
 +      return -ENOSYS;
 +}
 +#endif
 +
  static inline struct device_node *of_find_matching_node(
        struct device_node *from,
        const struct of_device_id *matches)
@@@ -877,6 -918,12 +927,12 @@@ static inline int of_property_read_s32(
        return of_property_read_u32(np, propname, (u32*) out_value);
  }
  
+ #define of_for_each_phandle(it, err, np, ln, cn, cc)                  \
+       for (of_phandle_iterator_init((it), (np), (ln), (cn), (cc)),    \
+            err = of_phandle_iterator_next(it);                        \
+            err == 0;                                                  \
+            err = of_phandle_iterator_next(it))
  #define of_property_for_each_u32(np, propname, prop, p, u)    \
        for (prop = of_find_property(np, propname, NULL),       \
                p = of_prop_next_u32(prop, NULL, &u);           \
This page took 0.199418 seconds and 4 git commands to generate.