diff options
Diffstat (limited to 'target/linux/layerscape/patches-4.9/704-fsl-mc-layerscape-support.patch')
-rw-r--r-- | target/linux/layerscape/patches-4.9/704-fsl-mc-layerscape-support.patch | 18672 |
1 files changed, 13709 insertions, 4963 deletions
diff --git a/target/linux/layerscape/patches-4.9/704-fsl-mc-layerscape-support.patch b/target/linux/layerscape/patches-4.9/704-fsl-mc-layerscape-support.patch index f6d515ada0..52c099203c 100644 --- a/target/linux/layerscape/patches-4.9/704-fsl-mc-layerscape-support.patch +++ b/target/linux/layerscape/patches-4.9/704-fsl-mc-layerscape-support.patch @@ -1,7 +1,7 @@ -From 667f0792b6f6d000c10f21c29c397c84cbe77f4a Mon Sep 17 00:00:00 2001 +From ab7b47676f9334bb55f80e0ac096c7aa289810e2 Mon Sep 17 00:00:00 2001 From: Yangbo Lu <yangbo.lu@nxp.com> -Date: Wed, 17 Jan 2018 15:11:45 +0800 -Subject: [PATCH 10/30] fsl-mc: layerscape support +Date: Thu, 5 Jul 2018 16:44:34 +0800 +Subject: [PATCH 10/32] fsl-mc: layerscape support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -19,187 +19,7533 @@ Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com> Signed-off-by: Horia Geantă <horia.geanta@nxp.com> Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> --- - drivers/staging/fsl-mc/bus/Kconfig | 41 +- - drivers/staging/fsl-mc/bus/Makefile | 10 +- - drivers/staging/fsl-mc/bus/dpbp-cmd.h | 80 ++ - drivers/staging/fsl-mc/bus/dpbp.c | 450 +-------- - drivers/staging/fsl-mc/bus/dpcon-cmd.h | 85 ++ - drivers/staging/fsl-mc/bus/dpcon.c | 317 ++++++ - drivers/staging/fsl-mc/bus/dpio/Makefile | 11 + - .../{include/dpcon-cmd.h => bus/dpio/dpio-cmd.h} | 73 +- - drivers/staging/fsl-mc/bus/dpio/dpio-driver.c | 296 ++++++ - drivers/staging/fsl-mc/bus/dpio/dpio-service.c | 693 +++++++++++++ - drivers/staging/fsl-mc/bus/dpio/dpio.c | 224 +++++ - drivers/staging/fsl-mc/bus/dpio/dpio.h | 109 ++ - drivers/staging/fsl-mc/bus/dpio/qbman-portal.c | 1049 ++++++++++++++++++++ - drivers/staging/fsl-mc/bus/dpio/qbman-portal.h | 662 ++++++++++++ - drivers/staging/fsl-mc/bus/dpio/qbman_debug.c | 853 ++++++++++++++++ - drivers/staging/fsl-mc/bus/dpio/qbman_debug.h | 136 +++ - drivers/staging/fsl-mc/bus/dpio/qbman_private.h | 171 ++++ - drivers/staging/fsl-mc/bus/dpmcp-cmd.h | 112 +-- - drivers/staging/fsl-mc/bus/dpmcp.c | 374 +------ - drivers/staging/fsl-mc/bus/dpmcp.h | 127 +-- - drivers/staging/fsl-mc/bus/dpmng-cmd.h | 14 +- - drivers/staging/fsl-mc/bus/dpmng.c | 37 +- - drivers/staging/fsl-mc/bus/dprc-cmd.h | 82 +- - drivers/staging/fsl-mc/bus/dprc-driver.c | 38 +- - drivers/staging/fsl-mc/bus/dprc.c | 629 +----------- - drivers/staging/fsl-mc/bus/fsl-mc-allocator.c | 78 +- - drivers/staging/fsl-mc/bus/fsl-mc-bus.c | 318 +++--- - drivers/staging/fsl-mc/bus/fsl-mc-iommu.c | 104 ++ - drivers/staging/fsl-mc/bus/fsl-mc-msi.c | 2 +- - drivers/staging/fsl-mc/bus/fsl-mc-private.h | 6 +- - .../staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c | 10 +- - drivers/staging/fsl-mc/bus/mc-io.c | 4 +- - drivers/staging/fsl-mc/bus/mc-ioctl.h | 22 + - drivers/staging/fsl-mc/bus/mc-restool.c | 405 ++++++++ - drivers/staging/fsl-mc/bus/mc-sys.c | 14 +- - drivers/staging/fsl-mc/include/dpaa2-fd.h | 706 +++++++++++++ - drivers/staging/fsl-mc/include/dpaa2-global.h | 202 ++++ - drivers/staging/fsl-mc/include/dpaa2-io.h | 190 ++++ - drivers/staging/fsl-mc/include/dpbp-cmd.h | 185 ---- - drivers/staging/fsl-mc/include/dpbp.h | 158 +-- - drivers/staging/fsl-mc/include/dpcon.h | 115 +++ - drivers/staging/fsl-mc/include/dpmng.h | 16 +- - drivers/staging/fsl-mc/include/dpopr.h | 110 ++ - drivers/staging/fsl-mc/include/dprc.h | 470 +++------ - drivers/staging/fsl-mc/include/mc-bus.h | 7 +- - drivers/staging/fsl-mc/include/mc-cmd.h | 44 +- - drivers/staging/fsl-mc/include/mc-sys.h | 3 +- - drivers/staging/fsl-mc/include/mc.h | 17 +- - 48 files changed, 7247 insertions(+), 2612 deletions(-) - create mode 100644 drivers/staging/fsl-mc/bus/dpbp-cmd.h - create mode 100644 drivers/staging/fsl-mc/bus/dpcon-cmd.h - create mode 100644 drivers/staging/fsl-mc/bus/dpcon.c + Documentation/ABI/stable/sysfs-bus-fsl-mc | 13 + + Documentation/ioctl/ioctl-number.txt | 1 + + Documentation/networking/dpaa2/index.rst | 8 + + Documentation/networking/dpaa2/overview.rst | 408 +++++ + MAINTAINERS | 11 +- + drivers/bus/Kconfig | 3 + + drivers/bus/Makefile | 4 + + drivers/bus/fsl-mc/Kconfig | 23 + + drivers/bus/fsl-mc/Makefile | 22 + + drivers/bus/fsl-mc/dpbp.c | 186 +++ + drivers/bus/fsl-mc/dpcon.c | 222 +++ + drivers/bus/fsl-mc/dpmcp.c | 99 ++ + .../fsl-mc/bus => bus/fsl-mc}/dprc-driver.c | 180 ++- + drivers/bus/fsl-mc/dprc.c | 575 +++++++ + .../bus => bus/fsl-mc}/fsl-mc-allocator.c | 195 ++- + .../fsl-mc/bus => bus/fsl-mc}/fsl-mc-bus.c | 523 +++++-- + drivers/bus/fsl-mc/fsl-mc-iommu.c | 78 + + .../fsl-mc/bus => bus/fsl-mc}/fsl-mc-msi.c | 34 +- + drivers/bus/fsl-mc/fsl-mc-private.h | 223 +++ + drivers/bus/fsl-mc/fsl-mc-restool.c | 219 +++ + .../fsl-mc/bus => bus/fsl-mc}/mc-io.c | 80 +- + .../fsl-mc/bus => bus/fsl-mc}/mc-sys.c | 105 +- + drivers/irqchip/Kconfig | 6 + + drivers/irqchip/Makefile | 1 + + .../irq-gic-v3-its-fsl-mc-msi.c | 52 +- + drivers/staging/fsl-mc/Kconfig | 1 + + drivers/staging/fsl-mc/Makefile | 1 + + drivers/staging/fsl-mc/TODO | 18 - + drivers/staging/fsl-mc/bus/Kconfig | 37 +- + drivers/staging/fsl-mc/bus/Makefile | 17 +- + drivers/staging/fsl-mc/bus/dpbp.c | 691 -------- + drivers/staging/fsl-mc/bus/dpio/Makefile | 8 + + drivers/staging/fsl-mc/bus/dpio/dpio-cmd.h | 50 + + drivers/staging/fsl-mc/bus/dpio/dpio-driver.c | 278 ++++ + .../staging/fsl-mc/bus/dpio/dpio-service.c | 780 +++++++++ + drivers/staging/fsl-mc/bus/dpio/dpio.c | 221 +++ + drivers/staging/fsl-mc/bus/dpio/dpio.h | 87 ++ + .../staging/fsl-mc/bus/dpio/qbman-portal.c | 1164 ++++++++++++++ + .../staging/fsl-mc/bus/dpio/qbman-portal.h | 505 ++++++ + drivers/staging/fsl-mc/bus/dpmcp-cmd.h | 140 -- + drivers/staging/fsl-mc/bus/dpmcp.c | 504 ------ + drivers/staging/fsl-mc/bus/dpmcp.h | 159 -- + drivers/staging/fsl-mc/bus/dpmng-cmd.h | 58 - + drivers/staging/fsl-mc/bus/dpmng.c | 107 -- + drivers/staging/fsl-mc/bus/dprc-cmd.h | 465 ------ + drivers/staging/fsl-mc/bus/dprc.c | 1388 ----------------- + drivers/staging/fsl-mc/bus/fsl-mc-private.h | 52 - + drivers/staging/fsl-mc/include/dpaa2-fd.h | 681 ++++++++ + drivers/staging/fsl-mc/include/dpaa2-global.h | 177 +++ + drivers/staging/fsl-mc/include/dpaa2-io.h | 178 +++ + drivers/staging/fsl-mc/include/dpbp-cmd.h | 185 --- + drivers/staging/fsl-mc/include/dpbp.h | 220 --- + drivers/staging/fsl-mc/include/dpcon-cmd.h | 62 - + drivers/staging/fsl-mc/include/dpmng.h | 69 - + drivers/staging/fsl-mc/include/dpopr.h | 112 ++ + drivers/staging/fsl-mc/include/dprc.h | 544 ------- + drivers/staging/fsl-mc/include/mc-bus.h | 111 -- + drivers/staging/fsl-mc/include/mc-cmd.h | 108 -- + drivers/staging/fsl-mc/include/mc-sys.h | 98 -- + drivers/staging/fsl-mc/include/mc.h | 201 --- + include/linux/fsl/mc.h | 1025 ++++++++++++ + include/uapi/linux/fsl_mc.h | 31 + + 62 files changed, 8068 insertions(+), 5736 deletions(-) + create mode 100644 Documentation/ABI/stable/sysfs-bus-fsl-mc + create mode 100644 Documentation/networking/dpaa2/index.rst + create mode 100644 Documentation/networking/dpaa2/overview.rst + create mode 100644 drivers/bus/fsl-mc/Kconfig + create mode 100644 drivers/bus/fsl-mc/Makefile + create mode 100644 drivers/bus/fsl-mc/dpbp.c + create mode 100644 drivers/bus/fsl-mc/dpcon.c + create mode 100644 drivers/bus/fsl-mc/dpmcp.c + rename drivers/{staging/fsl-mc/bus => bus/fsl-mc}/dprc-driver.c (84%) + create mode 100644 drivers/bus/fsl-mc/dprc.c + rename drivers/{staging/fsl-mc/bus => bus/fsl-mc}/fsl-mc-allocator.c (71%) + rename drivers/{staging/fsl-mc/bus => bus/fsl-mc}/fsl-mc-bus.c (64%) + create mode 100644 drivers/bus/fsl-mc/fsl-mc-iommu.c + rename drivers/{staging/fsl-mc/bus => bus/fsl-mc}/fsl-mc-msi.c (89%) + create mode 100644 drivers/bus/fsl-mc/fsl-mc-private.h + create mode 100644 drivers/bus/fsl-mc/fsl-mc-restool.c + rename drivers/{staging/fsl-mc/bus => bus/fsl-mc}/mc-io.c (68%) + rename drivers/{staging/fsl-mc/bus => bus/fsl-mc}/mc-sys.c (66%) + rename drivers/{staging/fsl-mc/bus => irqchip}/irq-gic-v3-its-fsl-mc-msi.c (60%) + delete mode 100644 drivers/staging/fsl-mc/TODO + delete mode 100644 drivers/staging/fsl-mc/bus/dpbp.c create mode 100644 drivers/staging/fsl-mc/bus/dpio/Makefile - rename drivers/staging/fsl-mc/{include/dpcon-cmd.h => bus/dpio/dpio-cmd.h} (64%) + create mode 100644 drivers/staging/fsl-mc/bus/dpio/dpio-cmd.h create mode 100644 drivers/staging/fsl-mc/bus/dpio/dpio-driver.c create mode 100644 drivers/staging/fsl-mc/bus/dpio/dpio-service.c create mode 100644 drivers/staging/fsl-mc/bus/dpio/dpio.c create mode 100644 drivers/staging/fsl-mc/bus/dpio/dpio.h create mode 100644 drivers/staging/fsl-mc/bus/dpio/qbman-portal.c create mode 100644 drivers/staging/fsl-mc/bus/dpio/qbman-portal.h - create mode 100644 drivers/staging/fsl-mc/bus/dpio/qbman_debug.c - create mode 100644 drivers/staging/fsl-mc/bus/dpio/qbman_debug.h - create mode 100644 drivers/staging/fsl-mc/bus/dpio/qbman_private.h - create mode 100644 drivers/staging/fsl-mc/bus/fsl-mc-iommu.c - create mode 100644 drivers/staging/fsl-mc/bus/mc-ioctl.h - create mode 100644 drivers/staging/fsl-mc/bus/mc-restool.c + delete mode 100644 drivers/staging/fsl-mc/bus/dpmcp-cmd.h + delete mode 100644 drivers/staging/fsl-mc/bus/dpmcp.c + delete mode 100644 drivers/staging/fsl-mc/bus/dpmcp.h + delete mode 100644 drivers/staging/fsl-mc/bus/dpmng-cmd.h + delete mode 100644 drivers/staging/fsl-mc/bus/dpmng.c + delete mode 100644 drivers/staging/fsl-mc/bus/dprc-cmd.h + delete mode 100644 drivers/staging/fsl-mc/bus/dprc.c + delete mode 100644 drivers/staging/fsl-mc/bus/fsl-mc-private.h create mode 100644 drivers/staging/fsl-mc/include/dpaa2-fd.h create mode 100644 drivers/staging/fsl-mc/include/dpaa2-global.h create mode 100644 drivers/staging/fsl-mc/include/dpaa2-io.h delete mode 100644 drivers/staging/fsl-mc/include/dpbp-cmd.h - create mode 100644 drivers/staging/fsl-mc/include/dpcon.h + delete mode 100644 drivers/staging/fsl-mc/include/dpbp.h + delete mode 100644 drivers/staging/fsl-mc/include/dpcon-cmd.h + delete mode 100644 drivers/staging/fsl-mc/include/dpmng.h create mode 100644 drivers/staging/fsl-mc/include/dpopr.h + delete mode 100644 drivers/staging/fsl-mc/include/dprc.h + delete mode 100644 drivers/staging/fsl-mc/include/mc-bus.h + delete mode 100644 drivers/staging/fsl-mc/include/mc-cmd.h + delete mode 100644 drivers/staging/fsl-mc/include/mc-sys.h + delete mode 100644 drivers/staging/fsl-mc/include/mc.h + create mode 100644 include/linux/fsl/mc.h + create mode 100644 include/uapi/linux/fsl_mc.h ---- a/drivers/staging/fsl-mc/bus/Kconfig -+++ b/drivers/staging/fsl-mc/bus/Kconfig -@@ -1,25 +1,40 @@ - # --# Freescale Management Complex (MC) bus drivers +--- /dev/null ++++ b/Documentation/ABI/stable/sysfs-bus-fsl-mc +@@ -0,0 +1,13 @@ ++What: /sys/bus/fsl-mc/devices/dprc.*/rescan ++Date: March. 2018 ++KernelVersion: 4.16 ++Contact: Ioana Ciornei <ioana.ciornei@nxp.com> ++Description: Root dprc rescan attribute ++Users: Userspace drivers and management tools ++ ++What: /sys/bus/fsl-mc/rescan ++Date: March. 2018 ++KernelVersion: 4.16 ++Contact: Ioana Ciornei <ioana.ciornei@nxp.com> ++Description: Bus rescan attribute ++Users: Userspace drivers and management tools +--- a/Documentation/ioctl/ioctl-number.txt ++++ b/Documentation/ioctl/ioctl-number.txt +@@ -170,6 +170,7 @@ Code Seq#(hex) Include File Comments + 'R' 00-1F linux/random.h conflict! + 'R' 01 linux/rfkill.h conflict! + 'R' C0-DF net/bluetooth/rfcomm.h ++'R' E0 uapi/linux/fsl_mc.h + 'S' all linux/cdrom.h conflict! + 'S' 80-81 scsi/scsi_ioctl.h conflict! + 'S' 82-FF scsi/scsi.h conflict! +--- /dev/null ++++ b/Documentation/networking/dpaa2/index.rst +@@ -0,0 +1,8 @@ ++=================== ++DPAA2 Documentation ++=================== ++ ++.. toctree:: ++ :maxdepth: 1 ++ ++ overview +--- /dev/null ++++ b/Documentation/networking/dpaa2/overview.rst +@@ -0,0 +1,408 @@ ++.. include:: <isonum.txt> ++ ++DPAA2 (Data Path Acceleration Architecture Gen2) Overview ++========================================================= ++ ++:Copyright: |copy| 2015 Freescale Semiconductor Inc. ++:Copyright: |copy| 2018 NXP ++ ++This document provides an overview of the Freescale DPAA2 architecture ++and how it is integrated into the Linux kernel. ++ ++Introduction ++============ ++ ++DPAA2 is a hardware architecture designed for high-speeed network ++packet processing. DPAA2 consists of sophisticated mechanisms for ++processing Ethernet packets, queue management, buffer management, ++autonomous L2 switching, virtual Ethernet bridging, and accelerator ++(e.g. crypto) sharing. ++ ++A DPAA2 hardware component called the Management Complex (or MC) manages the ++DPAA2 hardware resources. The MC provides an object-based abstraction for ++software drivers to use the DPAA2 hardware. ++The MC uses DPAA2 hardware resources such as queues, buffer pools, and ++network ports to create functional objects/devices such as network ++interfaces, an L2 switch, or accelerator instances. ++The MC provides memory-mapped I/O command interfaces (MC portals) ++which DPAA2 software drivers use to operate on DPAA2 objects. ++ ++The diagram below shows an overview of the DPAA2 resource management ++architecture:: ++ ++ +--------------------------------------+ ++ | OS | ++ | DPAA2 drivers | ++ | | | ++ +-----------------------------|--------+ ++ | ++ | (create,discover,connect ++ | config,use,destroy) ++ | ++ DPAA2 | ++ +------------------------| mc portal |-+ ++ | | | ++ | +- - - - - - - - - - - - -V- - -+ | ++ | | | | ++ | | Management Complex (MC) | | ++ | | | | ++ | +- - - - - - - - - - - - - - - -+ | ++ | | ++ | Hardware Hardware | ++ | Resources Objects | ++ | --------- ------- | ++ | -queues -DPRC | ++ | -buffer pools -DPMCP | ++ | -Eth MACs/ports -DPIO | ++ | -network interface -DPNI | ++ | profiles -DPMAC | ++ | -queue portals -DPBP | ++ | -MC portals ... | ++ | ... | ++ | | ++ +--------------------------------------+ ++ ++ ++The MC mediates operations such as create, discover, ++connect, configuration, and destroy. Fast-path operations ++on data, such as packet transmit/receive, are not mediated by ++the MC and are done directly using memory mapped regions in ++DPIO objects. ++ ++Overview of DPAA2 Objects ++========================= ++ ++The section provides a brief overview of some key DPAA2 objects. ++A simple scenario is described illustrating the objects involved ++in creating a network interfaces. ++ ++DPRC (Datapath Resource Container) ++---------------------------------- ++ ++A DPRC is a container object that holds all the other ++types of DPAA2 objects. In the example diagram below there ++are 8 objects of 5 types (DPMCP, DPIO, DPBP, DPNI, and DPMAC) ++in the container. ++ ++:: ++ ++ +---------------------------------------------------------+ ++ | DPRC | ++ | | ++ | +-------+ +-------+ +-------+ +-------+ +-------+ | ++ | | DPMCP | | DPIO | | DPBP | | DPNI | | DPMAC | | ++ | +-------+ +-------+ +-------+ +---+---+ +---+---+ | ++ | | DPMCP | | DPIO | | ++ | +-------+ +-------+ | ++ | | DPMCP | | ++ | +-------+ | ++ | | ++ +---------------------------------------------------------+ ++ ++From the point of view of an OS, a DPRC behaves similar to a plug and ++play bus, like PCI. DPRC commands can be used to enumerate the contents ++of the DPRC, discover the hardware objects present (including mappable ++regions and interrupts). ++ ++:: ++ ++ DPRC.1 (bus) ++ | ++ +--+--------+-------+-------+-------+ ++ | | | | | ++ DPMCP.1 DPIO.1 DPBP.1 DPNI.1 DPMAC.1 ++ DPMCP.2 DPIO.2 ++ DPMCP.3 ++ ++Hardware objects can be created and destroyed dynamically, providing ++the ability to hot plug/unplug objects in and out of the DPRC. ++ ++A DPRC has a mappable MMIO region (an MC portal) that can be used ++to send MC commands. It has an interrupt for status events (like ++hotplug). ++All objects in a container share the same hardware "isolation context". ++This means that with respect to an IOMMU the isolation granularity ++is at the DPRC (container) level, not at the individual object ++level. ++ ++DPRCs can be defined statically and populated with objects ++via a config file passed to the MC when firmware starts it. ++There is also a Linux user space tool called "restool" that can be ++used to create/destroy containers and objects dynamically. The latest ++version of restool can be found at: ++ https://github.com/qoriq-open-source/restool ++ ++DPAA2 Objects for an Ethernet Network Interface ++----------------------------------------------- ++ ++A typical Ethernet NIC is monolithic-- the NIC device contains TX/RX ++queuing mechanisms, configuration mechanisms, buffer management, ++physical ports, and interrupts. DPAA2 uses a more granular approach ++utilizing multiple hardware objects. Each object provides specialized ++functions. Groups of these objects are used by software to provide ++Ethernet network interface functionality. This approach provides ++efficient use of finite hardware resources, flexibility, and ++performance advantages. ++ ++The diagram below shows the objects needed for a simple ++network interface configuration on a system with 2 CPUs. ++ ++:: ++ ++ +---+---+ +---+---+ ++ CPU0 CPU1 ++ +---+---+ +---+---+ ++ | | ++ +---+---+ +---+---+ ++ DPIO DPIO ++ +---+---+ +---+---+ ++ \ / ++ \ / ++ \ / ++ +---+---+ ++ DPNI --- DPBP,DPMCP ++ +---+---+ ++ | ++ | ++ +---+---+ ++ DPMAC ++ +---+---+ ++ | ++ port/PHY ++ ++Below the objects are described. For each object a brief description ++is provided along with a summary of the kinds of operations the object ++supports and a summary of key resources of the object (MMIO regions ++and IRQs). ++ ++DPMAC (Datapath Ethernet MAC) ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++Represents an Ethernet MAC, a hardware device that connects to an Ethernet ++PHY and allows physical transmission and reception of Ethernet frames. ++ ++- MMIO regions: none ++- IRQs: DPNI link change ++- commands: set link up/down, link config, get stats, ++ IRQ config, enable, reset ++ ++DPNI (Datapath Network Interface) ++Contains TX/RX queues, network interface configuration, and RX buffer pool ++configuration mechanisms. The TX/RX queues are in memory and are identified ++by queue number. ++ ++- MMIO regions: none ++- IRQs: link state ++- commands: port config, offload config, queue config, ++ parse/classify config, IRQ config, enable, reset ++ ++DPIO (Datapath I/O) ++~~~~~~~~~~~~~~~~~~~ ++Provides interfaces to enqueue and dequeue ++packets and do hardware buffer pool management operations. The DPAA2 ++architecture separates the mechanism to access queues (the DPIO object) ++from the queues themselves. The DPIO provides an MMIO interface to ++enqueue/dequeue packets. To enqueue something a descriptor is written ++to the DPIO MMIO region, which includes the target queue number. ++There will typically be one DPIO assigned to each CPU. This allows all ++CPUs to simultaneously perform enqueue/dequeued operations. DPIOs are ++expected to be shared by different DPAA2 drivers. ++ ++- MMIO regions: queue operations, buffer management ++- IRQs: data availability, congestion notification, buffer ++ pool depletion ++- commands: IRQ config, enable, reset ++ ++DPBP (Datapath Buffer Pool) ++~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++Represents a hardware buffer pool. ++ ++- MMIO regions: none ++- IRQs: none ++- commands: enable, reset ++ ++DPMCP (Datapath MC Portal) ++~~~~~~~~~~~~~~~~~~~~~~~~~~ ++Provides an MC command portal. ++Used by drivers to send commands to the MC to manage ++objects. ++ ++- MMIO regions: MC command portal ++- IRQs: command completion ++- commands: IRQ config, enable, reset ++ ++Object Connections ++================== ++Some objects have explicit relationships that must ++be configured: ++ ++- DPNI <--> DPMAC ++- DPNI <--> DPNI ++- DPNI <--> L2-switch-port ++ ++ A DPNI must be connected to something such as a DPMAC, ++ another DPNI, or L2 switch port. The DPNI connection ++ is made via a DPRC command. ++ ++:: ++ ++ +-------+ +-------+ ++ | DPNI | | DPMAC | ++ +---+---+ +---+---+ ++ | | ++ +==========+ ++ ++- DPNI <--> DPBP ++ ++ A network interface requires a 'buffer pool' (DPBP ++ object) which provides a list of pointers to memory ++ where received Ethernet data is to be copied. The ++ Ethernet driver configures the DPBPs associated with ++ the network interface. ++ ++Interrupts ++========== ++All interrupts generated by DPAA2 objects are message ++interrupts. At the hardware level message interrupts ++generated by devices will normally have 3 components-- ++1) a non-spoofable 'device-id' expressed on the hardware ++bus, 2) an address, 3) a data value. ++ ++In the case of DPAA2 devices/objects, all objects in the ++same container/DPRC share the same 'device-id'. ++For ARM-based SoC this is the same as the stream ID. ++ ++ ++DPAA2 Linux Drivers Overview ++============================ ++ ++This section provides an overview of the Linux kernel drivers for ++DPAA2-- 1) the bus driver and associated "DPAA2 infrastructure" ++drivers and 2) functional object drivers (such as Ethernet). ++ ++As described previously, a DPRC is a container that holds the other ++types of DPAA2 objects. It is functionally similar to a plug-and-play ++bus controller. ++Each object in the DPRC is a Linux "device" and is bound to a driver. ++The diagram below shows the Linux drivers involved in a networking ++scenario and the objects bound to each driver. A brief description ++of each driver follows. ++ ++:: ++ ++ +------------+ ++ | OS Network | ++ | Stack | ++ +------------+ +------------+ ++ | Allocator |. . . . . . . | Ethernet | ++ |(DPMCP,DPBP)| | (DPNI) | ++ +-.----------+ +---+---+----+ ++ . . ^ | ++ . . <data avail, | | <enqueue, ++ . . tx confirm> | | dequeue> ++ +-------------+ . | | ++ | DPRC driver | . +---+---V----+ +---------+ ++ | (DPRC) | . . . . . .| DPIO driver| | MAC | ++ +----------+--+ | (DPIO) | | (DPMAC) | ++ | +------+-----+ +-----+---+ ++ |<dev add/remove> | | ++ | | | ++ +--------+----------+ | +--+---+ ++ | MC-bus driver | | | PHY | ++ | | | |driver| ++ | /bus/fsl-mc | | +--+---+ ++ +-------------------+ | | ++ | | ++ ========================= HARDWARE =========|=================|====== ++ DPIO | ++ | | ++ DPNI---DPBP | ++ | | ++ DPMAC | ++ | | ++ PHY ---------------+ ++ ============================================|======================== ++ ++A brief description of each driver is provided below. ++ ++MC-bus driver ++------------- ++The MC-bus driver is a platform driver and is probed from a ++node in the device tree (compatible "fsl,qoriq-mc") passed in by boot ++firmware. It is responsible for bootstrapping the DPAA2 kernel ++infrastructure. ++Key functions include: ++ ++- registering a new bus type named "fsl-mc" with the kernel, ++ and implementing bus call-backs (e.g. match/uevent/dev_groups) ++- implementing APIs for DPAA2 driver registration and for device ++ add/remove ++- creates an MSI IRQ domain ++- doing a 'device add' to expose the 'root' DPRC, in turn triggering ++ a bind of the root DPRC to the DPRC driver ++ ++The binding for the MC-bus device-tree node can be consulted at ++*Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt*. ++The sysfs bind/unbind interfaces for the MC-bus can be consulted at ++*Documentation/ABI/testing/sysfs-bus-fsl-mc*. ++ ++DPRC driver ++----------- ++The DPRC driver is bound to DPRC objects and does runtime management ++of a bus instance. It performs the initial bus scan of the DPRC ++and handles interrupts for container events such as hot plug by ++re-scanning the DPRC. ++ ++Allocator ++--------- ++Certain objects such as DPMCP and DPBP are generic and fungible, ++and are intended to be used by other drivers. For example, ++the DPAA2 Ethernet driver needs: ++ ++- DPMCPs to send MC commands, to configure network interfaces ++- DPBPs for network buffer pools ++ ++The allocator driver registers for these allocatable object types ++and those objects are bound to the allocator when the bus is probed. ++The allocator maintains a pool of objects that are available for ++allocation by other DPAA2 drivers. ++ ++DPIO driver ++----------- ++The DPIO driver is bound to DPIO objects and provides services that allow ++other drivers such as the Ethernet driver to enqueue and dequeue data for ++their respective objects. ++Key services include: ++ ++- data availability notifications ++- hardware queuing operations (enqueue and dequeue of data) ++- hardware buffer pool management ++ ++To transmit a packet the Ethernet driver puts data on a queue and ++invokes a DPIO API. For receive, the Ethernet driver registers ++a data availability notification callback. To dequeue a packet ++a DPIO API is used. ++There is typically one DPIO object per physical CPU for optimum ++performance, allowing different CPUs to simultaneously enqueue ++and dequeue data. ++ ++The DPIO driver operates on behalf of all DPAA2 drivers ++active in the kernel-- Ethernet, crypto, compression, ++etc. ++ ++Ethernet driver ++--------------- ++The Ethernet driver is bound to a DPNI and implements the kernel ++interfaces needed to connect the DPAA2 network interface to ++the network stack. ++Each DPNI corresponds to a Linux network interface. ++ ++MAC driver ++---------- ++An Ethernet PHY is an off-chip, board specific component and is managed ++by the appropriate PHY driver via an mdio bus. The MAC driver ++plays a role of being a proxy between the PHY driver and the ++MC. It does this proxy via the MC commands to a DPMAC object. ++If the PHY driver signals a link change, the MAC driver notifies ++the MC via a DPMAC command. If a network interface is brought ++up or down, the MC notifies the DPMAC driver via an interrupt and ++the driver can take appropriate action. +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -3980,6 +3980,12 @@ S: Maintained + F: drivers/char/dtlk.c + F: include/linux/dtlk.h + ++DPAA2 DATAPATH I/O (DPIO) DRIVER ++M: Roy Pledge <Roy.Pledge@nxp.com> ++L: linux-kernel@vger.kernel.org ++S: Maintained ++F: drivers/staging/fsl-mc/bus/dpio ++ + DPT_I2O SCSI RAID DRIVER + M: Adaptec OEM Raid Solutions <aacraid@adaptec.com> + L: linux-scsi@vger.kernel.org +@@ -5110,7 +5116,10 @@ M: "J. German Rivera" <German.Rivera@fre + M: Stuart Yoder <stuart.yoder@nxp.com> + L: linux-kernel@vger.kernel.org + S: Maintained +-F: drivers/staging/fsl-mc/ ++F: drivers/bus/fsl-mc/ ++F: Documentation/networking/dpaa2/overview.rst ++F: include/uapi/linux/fsl_mc.h ++F: Documentation/ABI/stable/sysfs-bus-fsl-mc + + FREEVXFS FILESYSTEM + M: Christoph Hellwig <hch@infradead.org> +--- a/drivers/bus/Kconfig ++++ b/drivers/bus/Kconfig +@@ -167,4 +167,7 @@ config VEXPRESS_CONFIG + help + Platform configuration infrastructure for the ARM Ltd. + Versatile Express. ++ ++source "drivers/bus/fsl-mc/Kconfig" ++ + endmenu +--- a/drivers/bus/Makefile ++++ b/drivers/bus/Makefile +@@ -7,6 +7,10 @@ obj-$(CONFIG_ARM_CCI) += arm-cci.o + obj-$(CONFIG_ARM_CCN) += arm-ccn.o + + obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o ++ +# DPAA2 fsl-mc bus - # --# Copyright (C) 2014 Freescale Semiconductor, Inc. ++obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/ ++ + obj-$(CONFIG_IMX_WEIM) += imx-weim.o + obj-$(CONFIG_MIPS_CDMM) += mips_cdmm.o + obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o +--- /dev/null ++++ b/drivers/bus/fsl-mc/Kconfig +@@ -0,0 +1,23 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# DPAA2 fsl-mc bus ++# +# Copyright (C) 2014-2016 Freescale Semiconductor, Inc. - # - # This file is released under the GPLv2 - # - - config FSL_MC_BUS -- bool "Freescale Management Complex (MC) bus driver" -- depends on OF && ARM64 ++# ++ ++config FSL_MC_BUS + bool "QorIQ DPAA2 fsl-mc bus driver" -+ depends on OF && ARCH_LAYERSCAPE - select GENERIC_MSI_IRQ_DOMAIN - help -- Driver to enable the bus infrastructure for the Freescale -- QorIQ Management Complex (fsl-mc). The fsl-mc is a hardware -- module of the QorIQ LS2 SoCs, that does resource management -- for hardware building-blocks in the SoC that can be used -- to dynamically create networking hardware objects such as -- network interfaces (NICs), crypto accelerator instances, -- or L2 switches. ++ depends on OF && (ARCH_LAYERSCAPE || (COMPILE_TEST && (ARM || ARM64 || X86 || PPC))) ++ select GENERIC_MSI_IRQ_DOMAIN ++ help + Driver to enable the bus infrastructure for the QorIQ DPAA2 + architecture. The fsl-mc bus driver handles discovery of + DPAA2 objects (which are represented as Linux devices) and + binding objects to drivers. - -- Only enable this option when building the kernel for -- Freescale QorQIQ LS2xxxx SoCs. -+config FSL_MC_DPIO -+ tristate "QorIQ DPAA2 DPIO driver" -+ depends on FSL_MC_BUS -+ help -+ Driver for the DPAA2 DPIO object. A DPIO provides queue and -+ buffer management facilities for software to interact with -+ other DPAA2 objects. This driver does not expose the DPIO -+ objects individually, but groups them under a service layer -+ API. - -+config FSL_QBMAN_DEBUG -+ tristate "Freescale QBMAN Debug APIs" -+ depends on FSL_MC_DPIO -+ help -+ QBMan debug assistant APIs. - ++ +config FSL_MC_RESTOOL -+ tristate "Freescale Management Complex (MC) restool driver" -+ depends on FSL_MC_BUS -+ help -+ Driver that provides kernel support for the Freescale Management -+ Complex resource manager user-space tool. ---- a/drivers/staging/fsl-mc/bus/Makefile -+++ b/drivers/staging/fsl-mc/bus/Makefile -@@ -17,4 +17,12 @@ mc-bus-driver-objs := fsl-mc-bus.o \ - fsl-mc-msi.o \ - irq-gic-v3-its-fsl-mc-msi.o \ - dpmcp.o \ -- dpbp.o ++ bool "Management Complex (MC) restool support" ++ depends on FSL_MC_BUS ++ help ++ Provides kernel support for the Management Complex resource ++ manager user-space tool - restool. +--- /dev/null ++++ b/drivers/bus/fsl-mc/Makefile +@@ -0,0 +1,22 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Freescale Management Complex (MC) bus drivers ++# ++# Copyright (C) 2014 Freescale Semiconductor, Inc. ++# ++obj-$(CONFIG_FSL_MC_BUS) += mc-bus-driver.o ++ ++mc-bus-driver-objs := fsl-mc-bus.o \ ++ mc-sys.o \ ++ mc-io.o \ + dpbp.o \ + dpcon.o \ ++ dprc.o \ ++ dprc-driver.o \ ++ fsl-mc-allocator.o \ ++ fsl-mc-msi.o \ ++ dpmcp.o \ + fsl-mc-iommu.o + -+# MC DPIO driver -+obj-$(CONFIG_FSL_MC_DPIO) += dpio/ -+ +# MC restool kernel support -+obj-$(CONFIG_FSL_MC_RESTOOL) += mc-restool.o ++obj-$(CONFIG_FSL_MC_RESTOOL) += fsl-mc-restool.o --- /dev/null -+++ b/drivers/staging/fsl-mc/bus/dpbp-cmd.h -@@ -0,0 +1,80 @@ ++++ b/drivers/bus/fsl-mc/dpbp.c +@@ -0,0 +1,186 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright 2013-2016 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 the above-listed copyright holders nor the -+ * names of any contributors may be used to endorse or promote products -+ * derived from this software without specific prior written permission. ++ */ ++#include <linux/kernel.h> ++#include <linux/fsl/mc.h> ++#include <linux/fsl/mc.h> ++ ++#include "fsl-mc-private.h" ++ ++/** ++ * dpbp_open() - Open a control session for the specified object. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @dpbp_id: DPBP unique ID ++ * @token: Returned token; use in subsequent API calls + * -+ * 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 function can be used to open a control session for an ++ * already created object; an object may have been declared in ++ * the DPL or by calling the dpbp_create function. ++ * This function returns a unique authentication token, ++ * associated with the specific object ID and the specific MC ++ * portal; this token must be used in all subsequent commands for ++ * this specific object + * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpbp_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpbp_id, ++ u16 *token) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dpbp_cmd_open *cmd_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPBP_CMDID_OPEN, ++ cmd_flags, 0); ++ cmd_params = (struct dpbp_cmd_open *)cmd.params; ++ cmd_params->dpbp_id = cpu_to_le32(dpbp_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *token = mc_cmd_hdr_read_token(&cmd); ++ ++ return err; ++} ++EXPORT_SYMBOL_GPL(dpbp_open); ++ ++/** ++ * dpbp_close() - Close the control session of the object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPBP object ++ * ++ * After this function is called, no further operations are ++ * allowed on the object without opening a new control session. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpbp_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPBP_CMDID_CLOSE, cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++EXPORT_SYMBOL_GPL(dpbp_close); ++ ++/** ++ * dpbp_enable() - Enable the DPBP. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPBP object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpbp_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPBP_CMDID_ENABLE, cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++EXPORT_SYMBOL_GPL(dpbp_enable); ++ ++/** ++ * dpbp_disable() - Disable the DPBP. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPBP object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpbp_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPBP_CMDID_DISABLE, ++ cmd_flags, token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++EXPORT_SYMBOL_GPL(dpbp_disable); ++ ++/** ++ * dpbp_reset() - Reset the DPBP, returns the object to initial state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPBP object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpbp_reset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPBP_CMDID_RESET, ++ cmd_flags, token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++EXPORT_SYMBOL_GPL(dpbp_reset); ++ ++/** ++ * dpbp_get_attributes - Retrieve DPBP attributes. ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPBP object ++ * @attr: Returned object's attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpbp_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpbp_attr *attr) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dpbp_rsp_get_attributes *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_ATTR, ++ cmd_flags, token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpbp_rsp_get_attributes *)cmd.params; ++ attr->bpid = le16_to_cpu(rsp_params->bpid); ++ attr->id = le32_to_cpu(rsp_params->id); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(dpbp_get_attributes); +--- /dev/null ++++ b/drivers/bus/fsl-mc/dpcon.c +@@ -0,0 +1,222 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ */ ++#include <linux/kernel.h> ++#include <linux/fsl/mc.h> ++#include <linux/fsl/mc.h> ++ ++#include "fsl-mc-private.h" ++ ++/** ++ * dpcon_open() - Open a control session for the specified object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @dpcon_id: DPCON unique ID ++ * @token: Returned token; use in subsequent API calls ++ * ++ * This function can be used to open a control session for an ++ * already created object; an object may have been declared in ++ * the DPL or by calling the dpcon_create() function. ++ * This function returns a unique authentication token, ++ * associated with the specific object ID and the specific MC ++ * portal; this token must be used in all subsequent commands for ++ * this specific object. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpcon_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpcon_id, ++ u16 *token) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dpcon_cmd_open *dpcon_cmd; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPCON_CMDID_OPEN, ++ cmd_flags, ++ 0); ++ dpcon_cmd = (struct dpcon_cmd_open *)cmd.params; ++ dpcon_cmd->dpcon_id = cpu_to_le32(dpcon_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *token = mc_cmd_hdr_read_token(&cmd); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(dpcon_open); ++ ++/** ++ * dpcon_close() - Close the control session of the object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPCON object ++ * ++ * After this function is called, no further operations are ++ * allowed on the object without opening a new control session. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpcon_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPCON_CMDID_CLOSE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++EXPORT_SYMBOL_GPL(dpcon_close); ++ ++/** ++ * dpcon_enable() - Enable the DPCON ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPCON object ++ * ++ * Return: '0' on Success; Error code otherwise ++ */ ++int dpcon_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPCON_CMDID_ENABLE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++EXPORT_SYMBOL_GPL(dpcon_enable); ++ ++/** ++ * dpcon_disable() - Disable the DPCON ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPCON object ++ * ++ * Return: '0' on Success; Error code otherwise ++ */ ++int dpcon_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPCON_CMDID_DISABLE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++EXPORT_SYMBOL_GPL(dpcon_disable); ++ ++/** ++ * dpcon_reset() - Reset the DPCON, returns the object to initial state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPCON object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpcon_reset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPCON_CMDID_RESET, ++ cmd_flags, token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++EXPORT_SYMBOL_GPL(dpcon_reset); ++ ++/** ++ * dpcon_get_attributes() - Retrieve DPCON attributes. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPCON object ++ * @attr: Object's attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpcon_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpcon_attr *attr) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dpcon_rsp_get_attr *dpcon_rsp; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPCON_CMDID_GET_ATTR, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ dpcon_rsp = (struct dpcon_rsp_get_attr *)cmd.params; ++ attr->id = le32_to_cpu(dpcon_rsp->id); ++ attr->qbman_ch_id = le16_to_cpu(dpcon_rsp->qbman_ch_id); ++ attr->num_priorities = dpcon_rsp->num_priorities; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(dpcon_get_attributes); ++ ++/** ++ * dpcon_set_notification() - Set DPCON notification destination ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPCON object ++ * @cfg: Notification parameters ++ * ++ * Return: '0' on Success; Error code otherwise ++ */ ++int dpcon_set_notification(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpcon_notification_cfg *cfg) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dpcon_cmd_set_notification *dpcon_cmd; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPCON_CMDID_SET_NOTIFICATION, ++ cmd_flags, ++ token); ++ dpcon_cmd = (struct dpcon_cmd_set_notification *)cmd.params; ++ dpcon_cmd->dpio_id = cpu_to_le32(cfg->dpio_id); ++ dpcon_cmd->priority = cfg->priority; ++ dpcon_cmd->user_ctx = cpu_to_le64(cfg->user_ctx); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++EXPORT_SYMBOL_GPL(dpcon_set_notification); +--- /dev/null ++++ b/drivers/bus/fsl-mc/dpmcp.c +@@ -0,0 +1,99 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ */ ++#include <linux/kernel.h> ++#include <linux/fsl/mc.h> ++ ++#include "fsl-mc-private.h" ++ ++/** ++ * dpmcp_open() - Open a control session for the specified object. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @dpmcp_id: DPMCP unique ID ++ * @token: Returned token; use in subsequent API calls ++ * ++ * This function can be used to open a control session for an ++ * already created object; an object may have been declared in ++ * the DPL or by calling the dpmcp_create function. ++ * This function returns a unique authentication token, ++ * associated with the specific object ID and the specific MC ++ * portal; this token must be used in all subsequent commands for ++ * this specific object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmcp_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpmcp_id, ++ u16 *token) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dpmcp_cmd_open *cmd_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMCP_CMDID_OPEN, ++ cmd_flags, 0); ++ cmd_params = (struct dpmcp_cmd_open *)cmd.params; ++ cmd_params->dpmcp_id = cpu_to_le32(dpmcp_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *token = mc_cmd_hdr_read_token(&cmd); ++ ++ return err; ++} ++ ++/** ++ * dpmcp_close() - Close the control session of the object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMCP object ++ * ++ * After this function is called, no further operations are ++ * allowed on the object without opening a new control session. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmcp_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMCP_CMDID_CLOSE, ++ cmd_flags, token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpmcp_reset() - Reset the DPMCP, returns the object to initial state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMCP object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmcp_reset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMCP_CMDID_RESET, ++ cmd_flags, token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} +--- a/drivers/staging/fsl-mc/bus/dprc-driver.c ++++ /dev/null +@@ -1,805 +0,0 @@ +-/* +- * Freescale data path resource container (DPRC) driver +- * +- * Copyright (C) 2014 Freescale Semiconductor, Inc. +- * Author: German Rivera <German.Rivera@freescale.com> +- * +- * 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 <linux/module.h> +-#include <linux/slab.h> +-#include <linux/interrupt.h> +-#include <linux/msi.h> +-#include "../include/mc-bus.h" +-#include "../include/mc-sys.h" +- +-#include "dprc-cmd.h" +-#include "fsl-mc-private.h" +- +-#define FSL_MC_DPRC_DRIVER_NAME "fsl_mc_dprc" +- +-#define FSL_MC_DEVICE_MATCH(_mc_dev, _obj_desc) \ +- (strcmp((_mc_dev)->obj_desc.type, (_obj_desc)->type) == 0 && \ +- (_mc_dev)->obj_desc.id == (_obj_desc)->id) +- +-struct dprc_child_objs { +- int child_count; +- struct dprc_obj_desc *child_array; +-}; +- +-static int __fsl_mc_device_remove_if_not_in_mc(struct device *dev, void *data) +-{ +- int i; +- struct dprc_child_objs *objs; +- struct fsl_mc_device *mc_dev; +- +- WARN_ON(!dev); +- WARN_ON(!data); +- mc_dev = to_fsl_mc_device(dev); +- objs = data; +- +- for (i = 0; i < objs->child_count; i++) { +- struct dprc_obj_desc *obj_desc = &objs->child_array[i]; +- +- if (strlen(obj_desc->type) != 0 && +- FSL_MC_DEVICE_MATCH(mc_dev, obj_desc)) +- break; +- } +- +- if (i == objs->child_count) +- fsl_mc_device_remove(mc_dev); +- +- return 0; +-} +- +-static int __fsl_mc_device_remove(struct device *dev, void *data) +-{ +- WARN_ON(!dev); +- WARN_ON(data); +- fsl_mc_device_remove(to_fsl_mc_device(dev)); +- return 0; +-} +- +-/** +- * dprc_remove_devices - Removes devices for objects removed from a DPRC +- * +- * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object +- * @obj_desc_array: array of object descriptors for child objects currently +- * present in the DPRC in the MC. +- * @num_child_objects_in_mc: number of entries in obj_desc_array +- * +- * Synchronizes the state of the Linux bus driver with the actual state of +- * the MC by removing devices that represent MC objects that have +- * been dynamically removed in the physical DPRC. +- */ +-static void dprc_remove_devices(struct fsl_mc_device *mc_bus_dev, +- struct dprc_obj_desc *obj_desc_array, +- int num_child_objects_in_mc) +-{ +- if (num_child_objects_in_mc != 0) { +- /* +- * Remove child objects that are in the DPRC in Linux, +- * but not in the MC: +- */ +- struct dprc_child_objs objs; +- +- objs.child_count = num_child_objects_in_mc; +- objs.child_array = obj_desc_array; +- device_for_each_child(&mc_bus_dev->dev, &objs, +- __fsl_mc_device_remove_if_not_in_mc); +- } else { +- /* +- * There are no child objects for this DPRC in the MC. +- * So, remove all the child devices from Linux: +- */ +- device_for_each_child(&mc_bus_dev->dev, NULL, +- __fsl_mc_device_remove); +- } +-} +- +-static int __fsl_mc_device_match(struct device *dev, void *data) +-{ +- struct dprc_obj_desc *obj_desc = data; +- struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); +- +- return FSL_MC_DEVICE_MATCH(mc_dev, obj_desc); +-} +- +-static struct fsl_mc_device *fsl_mc_device_lookup(struct dprc_obj_desc +- *obj_desc, +- struct fsl_mc_device +- *mc_bus_dev) +-{ +- struct device *dev; +- +- dev = device_find_child(&mc_bus_dev->dev, obj_desc, +- __fsl_mc_device_match); +- +- return dev ? to_fsl_mc_device(dev) : NULL; +-} +- +-/** +- * check_plugged_state_change - Check change in an MC object's plugged state +- * +- * @mc_dev: pointer to the fsl-mc device for a given MC object +- * @obj_desc: pointer to the MC object's descriptor in the MC +- * +- * If the plugged state has changed from unplugged to plugged, the fsl-mc +- * device is bound to the corresponding device driver. +- * If the plugged state has changed from plugged to unplugged, the fsl-mc +- * device is unbound from the corresponding device driver. +- */ +-static void check_plugged_state_change(struct fsl_mc_device *mc_dev, +- struct dprc_obj_desc *obj_desc) +-{ +- int error; +- u32 plugged_flag_at_mc = +- obj_desc->state & DPRC_OBJ_STATE_PLUGGED; +- +- if (plugged_flag_at_mc != +- (mc_dev->obj_desc.state & DPRC_OBJ_STATE_PLUGGED)) { +- if (plugged_flag_at_mc) { +- mc_dev->obj_desc.state |= DPRC_OBJ_STATE_PLUGGED; +- error = device_attach(&mc_dev->dev); +- if (error < 0) { +- dev_err(&mc_dev->dev, +- "device_attach() failed: %d\n", +- error); +- } +- } else { +- mc_dev->obj_desc.state &= ~DPRC_OBJ_STATE_PLUGGED; +- device_release_driver(&mc_dev->dev); +- } +- } +-} +- +-/** +- * dprc_add_new_devices - Adds devices to the logical bus for a DPRC +- * +- * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object +- * @obj_desc_array: array of device descriptors for child devices currently +- * present in the physical DPRC. +- * @num_child_objects_in_mc: number of entries in obj_desc_array +- * +- * Synchronizes the state of the Linux bus driver with the actual +- * state of the MC by adding objects that have been newly discovered +- * in the physical DPRC. +- */ +-static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev, +- struct dprc_obj_desc *obj_desc_array, +- int num_child_objects_in_mc) +-{ +- int error; +- int i; +- +- for (i = 0; i < num_child_objects_in_mc; i++) { +- struct fsl_mc_device *child_dev; +- struct dprc_obj_desc *obj_desc = &obj_desc_array[i]; +- +- if (strlen(obj_desc->type) == 0) +- continue; +- +- /* +- * Check if device is already known to Linux: +- */ +- child_dev = fsl_mc_device_lookup(obj_desc, mc_bus_dev); +- if (child_dev) { +- check_plugged_state_change(child_dev, obj_desc); +- continue; +- } +- +- error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev, +- &child_dev); +- if (error < 0) +- continue; +- } +-} +- +-/** +- * dprc_scan_objects - Discover objects in a DPRC +- * +- * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object +- * @total_irq_count: total number of IRQs needed by objects in the DPRC. +- * +- * Detects objects added and removed from a DPRC and synchronizes the +- * state of the Linux bus driver, MC by adding and removing +- * devices accordingly. +- * Two types of devices can be found in a DPRC: allocatable objects (e.g., +- * dpbp, dpmcp) and non-allocatable devices (e.g., dprc, dpni). +- * All allocatable devices needed to be probed before all non-allocatable +- * devices, to ensure that device drivers for non-allocatable +- * devices can allocate any type of allocatable devices. +- * That is, we need to ensure that the corresponding resource pools are +- * populated before they can get allocation requests from probe callbacks +- * of the device drivers for the non-allocatable devices. +- */ +-int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev, +- unsigned int *total_irq_count) +-{ +- int num_child_objects; +- int dprc_get_obj_failures; +- int error; +- unsigned int irq_count = mc_bus_dev->obj_desc.irq_count; +- struct dprc_obj_desc *child_obj_desc_array = NULL; +- +- error = dprc_get_obj_count(mc_bus_dev->mc_io, +- 0, +- mc_bus_dev->mc_handle, +- &num_child_objects); +- if (error < 0) { +- dev_err(&mc_bus_dev->dev, "dprc_get_obj_count() failed: %d\n", +- error); +- return error; +- } +- +- if (num_child_objects != 0) { +- int i; +- +- child_obj_desc_array = +- devm_kmalloc_array(&mc_bus_dev->dev, num_child_objects, +- sizeof(*child_obj_desc_array), +- GFP_KERNEL); +- if (!child_obj_desc_array) +- return -ENOMEM; +- +- /* +- * Discover objects currently present in the physical DPRC: +- */ +- dprc_get_obj_failures = 0; +- for (i = 0; i < num_child_objects; i++) { +- struct dprc_obj_desc *obj_desc = +- &child_obj_desc_array[i]; +- +- error = dprc_get_obj(mc_bus_dev->mc_io, +- 0, +- mc_bus_dev->mc_handle, +- i, obj_desc); +- if (error < 0) { +- dev_err(&mc_bus_dev->dev, +- "dprc_get_obj(i=%d) failed: %d\n", +- i, error); +- /* +- * Mark the obj entry as "invalid", by using the +- * empty string as obj type: +- */ +- obj_desc->type[0] = '\0'; +- obj_desc->id = error; +- dprc_get_obj_failures++; +- continue; +- } +- +- /* +- * add a quirk for all versions of dpsec < 4.0...none +- * are coherent regardless of what the MC reports. +- */ +- if ((strcmp(obj_desc->type, "dpseci") == 0) && +- (obj_desc->ver_major < 4)) +- obj_desc->flags |= +- DPRC_OBJ_FLAG_NO_MEM_SHAREABILITY; +- +- irq_count += obj_desc->irq_count; +- dev_dbg(&mc_bus_dev->dev, +- "Discovered object: type %s, id %d\n", +- obj_desc->type, obj_desc->id); +- } +- +- if (dprc_get_obj_failures != 0) { +- dev_err(&mc_bus_dev->dev, +- "%d out of %d devices could not be retrieved\n", +- dprc_get_obj_failures, num_child_objects); +- } +- } +- +- *total_irq_count = irq_count; +- dprc_remove_devices(mc_bus_dev, child_obj_desc_array, +- num_child_objects); +- +- dprc_add_new_devices(mc_bus_dev, child_obj_desc_array, +- num_child_objects); +- +- if (child_obj_desc_array) +- devm_kfree(&mc_bus_dev->dev, child_obj_desc_array); +- +- return 0; +-} +-EXPORT_SYMBOL_GPL(dprc_scan_objects); +- +-/** +- * dprc_scan_container - Scans a physical DPRC and synchronizes Linux bus state +- * +- * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object +- * +- * Scans the physical DPRC and synchronizes the state of the Linux +- * bus driver with the actual state of the MC by adding and removing +- * devices as appropriate. +- */ +-int dprc_scan_container(struct fsl_mc_device *mc_bus_dev) +-{ +- int error; +- unsigned int irq_count; +- struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); +- +- fsl_mc_init_all_resource_pools(mc_bus_dev); +- +- /* +- * Discover objects in the DPRC: +- */ +- mutex_lock(&mc_bus->scan_mutex); +- error = dprc_scan_objects(mc_bus_dev, &irq_count); +- mutex_unlock(&mc_bus->scan_mutex); +- if (error < 0) +- goto error; +- +- if (dev_get_msi_domain(&mc_bus_dev->dev) && !mc_bus->irq_resources) { +- if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) { +- dev_warn(&mc_bus_dev->dev, +- "IRQs needed (%u) exceed IRQs preallocated (%u)\n", +- irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); +- } +- +- error = fsl_mc_populate_irq_pool( +- mc_bus, +- FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); +- if (error < 0) +- goto error; +- } +- +- return 0; +-error: +- fsl_mc_cleanup_all_resource_pools(mc_bus_dev); +- return error; +-} +-EXPORT_SYMBOL_GPL(dprc_scan_container); +- +-/** +- * dprc_irq0_handler - Regular ISR for DPRC interrupt 0 +- * +- * @irq: IRQ number of the interrupt being handled +- * @arg: Pointer to device structure +- */ +-static irqreturn_t dprc_irq0_handler(int irq_num, void *arg) +-{ +- return IRQ_WAKE_THREAD; +-} +- +-/** +- * dprc_irq0_handler_thread - Handler thread function for DPRC interrupt 0 +- * +- * @irq: IRQ number of the interrupt being handled +- * @arg: Pointer to device structure +- */ +-static irqreturn_t dprc_irq0_handler_thread(int irq_num, void *arg) +-{ +- int error; +- u32 status; +- struct device *dev = arg; +- struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); +- struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); +- struct fsl_mc_io *mc_io = mc_dev->mc_io; +- struct msi_desc *msi_desc = mc_dev->irqs[0]->msi_desc; +- +- dev_dbg(dev, "DPRC IRQ %d triggered on CPU %u\n", +- irq_num, smp_processor_id()); +- +- if (WARN_ON(!(mc_dev->flags & FSL_MC_IS_DPRC))) +- return IRQ_HANDLED; +- +- mutex_lock(&mc_bus->scan_mutex); +- if (WARN_ON(!msi_desc || msi_desc->irq != (u32)irq_num)) +- goto out; +- +- status = 0; +- error = dprc_get_irq_status(mc_io, 0, mc_dev->mc_handle, 0, +- &status); +- if (error < 0) { +- dev_err(dev, +- "dprc_get_irq_status() failed: %d\n", error); +- goto out; +- } +- +- error = dprc_clear_irq_status(mc_io, 0, mc_dev->mc_handle, 0, +- status); +- if (error < 0) { +- dev_err(dev, +- "dprc_clear_irq_status() failed: %d\n", error); +- goto out; +- } +- +- if (status & (DPRC_IRQ_EVENT_OBJ_ADDED | +- DPRC_IRQ_EVENT_OBJ_REMOVED | +- DPRC_IRQ_EVENT_CONTAINER_DESTROYED | +- DPRC_IRQ_EVENT_OBJ_DESTROYED | +- DPRC_IRQ_EVENT_OBJ_CREATED)) { +- unsigned int irq_count; +- +- error = dprc_scan_objects(mc_dev, &irq_count); +- if (error < 0) { +- /* +- * If the error is -ENXIO, we ignore it, as it indicates +- * that the object scan was aborted, as we detected that +- * an object was removed from the DPRC in the MC, while +- * we were scanning the DPRC. +- */ +- if (error != -ENXIO) { +- dev_err(dev, "dprc_scan_objects() failed: %d\n", +- error); +- } +- +- goto out; +- } +- +- if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) { +- dev_warn(dev, +- "IRQs needed (%u) exceed IRQs preallocated (%u)\n", +- irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); +- } +- } +- +-out: +- mutex_unlock(&mc_bus->scan_mutex); +- return IRQ_HANDLED; +-} +- +-/* +- * Disable and clear interrupt for a given DPRC object +- */ +-static int disable_dprc_irq(struct fsl_mc_device *mc_dev) +-{ +- int error; +- struct fsl_mc_io *mc_io = mc_dev->mc_io; +- +- WARN_ON(mc_dev->obj_desc.irq_count != 1); +- +- /* +- * Disable generation of interrupt, while we configure it: +- */ +- error = dprc_set_irq_enable(mc_io, 0, mc_dev->mc_handle, 0, 0); +- if (error < 0) { +- dev_err(&mc_dev->dev, +- "Disabling DPRC IRQ failed: dprc_set_irq_enable() failed: %d\n", +- error); +- return error; +- } +- +- /* +- * Disable all interrupt causes for the interrupt: +- */ +- error = dprc_set_irq_mask(mc_io, 0, mc_dev->mc_handle, 0, 0x0); +- if (error < 0) { +- dev_err(&mc_dev->dev, +- "Disabling DPRC IRQ failed: dprc_set_irq_mask() failed: %d\n", +- error); +- return error; +- } +- +- /* +- * Clear any leftover interrupts: +- */ +- error = dprc_clear_irq_status(mc_io, 0, mc_dev->mc_handle, 0, ~0x0U); +- if (error < 0) { +- dev_err(&mc_dev->dev, +- "Disabling DPRC IRQ failed: dprc_clear_irq_status() failed: %d\n", +- error); +- return error; +- } +- +- return 0; +-} +- +-static int register_dprc_irq_handler(struct fsl_mc_device *mc_dev) +-{ +- int error; +- struct fsl_mc_device_irq *irq = mc_dev->irqs[0]; +- +- WARN_ON(mc_dev->obj_desc.irq_count != 1); +- +- /* +- * NOTE: devm_request_threaded_irq() invokes the device-specific +- * function that programs the MSI physically in the device +- */ +- error = devm_request_threaded_irq(&mc_dev->dev, +- irq->msi_desc->irq, +- dprc_irq0_handler, +- dprc_irq0_handler_thread, +- IRQF_NO_SUSPEND | IRQF_ONESHOT, +- "FSL MC DPRC irq0", +- &mc_dev->dev); +- if (error < 0) { +- dev_err(&mc_dev->dev, +- "devm_request_threaded_irq() failed: %d\n", +- error); +- return error; +- } +- +- return 0; +-} +- +-static int enable_dprc_irq(struct fsl_mc_device *mc_dev) +-{ +- int error; +- +- /* +- * Enable all interrupt causes for the interrupt: +- */ +- error = dprc_set_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle, 0, +- ~0x0u); +- if (error < 0) { +- dev_err(&mc_dev->dev, +- "Enabling DPRC IRQ failed: dprc_set_irq_mask() failed: %d\n", +- error); +- +- return error; +- } +- +- /* +- * Enable generation of the interrupt: +- */ +- error = dprc_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle, 0, 1); +- if (error < 0) { +- dev_err(&mc_dev->dev, +- "Enabling DPRC IRQ failed: dprc_set_irq_enable() failed: %d\n", +- error); +- +- return error; +- } +- +- return 0; +-} +- +-/* +- * Setup interrupt for a given DPRC device +- */ +-static int dprc_setup_irq(struct fsl_mc_device *mc_dev) +-{ +- int error; +- +- error = fsl_mc_allocate_irqs(mc_dev); +- if (error < 0) +- return error; +- +- error = disable_dprc_irq(mc_dev); +- if (error < 0) +- goto error_free_irqs; +- +- error = register_dprc_irq_handler(mc_dev); +- if (error < 0) +- goto error_free_irqs; +- +- error = enable_dprc_irq(mc_dev); +- if (error < 0) +- goto error_free_irqs; +- +- return 0; +- +-error_free_irqs: +- fsl_mc_free_irqs(mc_dev); +- return error; +-} +- +-/** +- * dprc_probe - callback invoked when a DPRC is being bound to this driver +- * +- * @mc_dev: Pointer to fsl-mc device representing a DPRC +- * +- * It opens the physical DPRC in the MC. +- * It scans the DPRC to discover the MC objects contained in it. +- * It creates the interrupt pool for the MC bus associated with the DPRC. +- * It configures the interrupts for the DPRC device itself. +- */ +-static int dprc_probe(struct fsl_mc_device *mc_dev) +-{ +- int error; +- size_t region_size; +- struct device *parent_dev = mc_dev->dev.parent; +- struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); +- bool mc_io_created = false; +- bool msi_domain_set = false; +- +- if (WARN_ON(strcmp(mc_dev->obj_desc.type, "dprc") != 0)) +- return -EINVAL; +- +- if (WARN_ON(dev_get_msi_domain(&mc_dev->dev))) +- return -EINVAL; +- +- if (!mc_dev->mc_io) { +- /* +- * This is a child DPRC: +- */ +- if (WARN_ON(!dev_is_fsl_mc(parent_dev))) +- return -EINVAL; +- +- if (WARN_ON(mc_dev->obj_desc.region_count == 0)) +- return -EINVAL; +- +- region_size = mc_dev->regions[0].end - +- mc_dev->regions[0].start + 1; +- +- error = fsl_create_mc_io(&mc_dev->dev, +- mc_dev->regions[0].start, +- region_size, +- NULL, +- FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, +- &mc_dev->mc_io); +- if (error < 0) +- return error; +- +- mc_io_created = true; +- +- /* +- * Inherit parent MSI domain: +- */ +- dev_set_msi_domain(&mc_dev->dev, +- dev_get_msi_domain(parent_dev)); +- msi_domain_set = true; +- } else { +- /* +- * This is a root DPRC +- */ +- struct irq_domain *mc_msi_domain; +- +- if (WARN_ON(dev_is_fsl_mc(parent_dev))) +- return -EINVAL; +- +- error = fsl_mc_find_msi_domain(parent_dev, +- &mc_msi_domain); +- if (error < 0) { +- dev_warn(&mc_dev->dev, +- "WARNING: MC bus without interrupt support\n"); +- } else { +- dev_set_msi_domain(&mc_dev->dev, mc_msi_domain); +- msi_domain_set = true; +- } +- } +- +- error = dprc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id, +- &mc_dev->mc_handle); +- if (error < 0) { +- dev_err(&mc_dev->dev, "dprc_open() failed: %d\n", error); +- goto error_cleanup_msi_domain; +- } +- +- error = dprc_get_attributes(mc_dev->mc_io, 0, mc_dev->mc_handle, +- &mc_bus->dprc_attr); +- if (error < 0) { +- dev_err(&mc_dev->dev, "dprc_get_attributes() failed: %d\n", +- error); +- goto error_cleanup_open; +- } +- +- if (mc_bus->dprc_attr.version.major < DPRC_MIN_VER_MAJOR || +- (mc_bus->dprc_attr.version.major == DPRC_MIN_VER_MAJOR && +- mc_bus->dprc_attr.version.minor < DPRC_MIN_VER_MINOR)) { +- dev_err(&mc_dev->dev, +- "ERROR: DPRC version %d.%d not supported\n", +- mc_bus->dprc_attr.version.major, +- mc_bus->dprc_attr.version.minor); +- error = -ENOTSUPP; +- goto error_cleanup_open; +- } +- +- mutex_init(&mc_bus->scan_mutex); +- +- /* +- * Discover MC objects in DPRC object: +- */ +- error = dprc_scan_container(mc_dev); +- if (error < 0) +- goto error_cleanup_open; +- +- /* +- * Configure interrupt for the DPRC object associated with this MC bus: +- */ +- error = dprc_setup_irq(mc_dev); +- if (error < 0) +- goto error_cleanup_open; +- +- dev_info(&mc_dev->dev, "DPRC device bound to driver"); +- return 0; +- +-error_cleanup_open: +- (void)dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); +- +-error_cleanup_msi_domain: +- if (msi_domain_set) +- dev_set_msi_domain(&mc_dev->dev, NULL); +- +- if (mc_io_created) { +- fsl_destroy_mc_io(mc_dev->mc_io); +- mc_dev->mc_io = NULL; +- } +- +- return error; +-} +- +-/* +- * Tear down interrupt for a given DPRC object +- */ +-static void dprc_teardown_irq(struct fsl_mc_device *mc_dev) +-{ +- struct fsl_mc_device_irq *irq = mc_dev->irqs[0]; +- +- (void)disable_dprc_irq(mc_dev); +- +- devm_free_irq(&mc_dev->dev, irq->msi_desc->irq, &mc_dev->dev); +- +- fsl_mc_free_irqs(mc_dev); +-} +- +-/** +- * dprc_remove - callback invoked when a DPRC is being unbound from this driver +- * +- * @mc_dev: Pointer to fsl-mc device representing the DPRC +- * +- * It removes the DPRC's child objects from Linux (not from the MC) and +- * closes the DPRC device in the MC. +- * It tears down the interrupts that were configured for the DPRC device. +- * It destroys the interrupt pool associated with this MC bus. +- */ +-static int dprc_remove(struct fsl_mc_device *mc_dev) +-{ +- int error; +- struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); +- +- if (WARN_ON(strcmp(mc_dev->obj_desc.type, "dprc") != 0)) +- return -EINVAL; +- if (WARN_ON(!mc_dev->mc_io)) +- return -EINVAL; +- +- if (WARN_ON(!mc_bus->irq_resources)) +- return -EINVAL; +- +- if (dev_get_msi_domain(&mc_dev->dev)) +- dprc_teardown_irq(mc_dev); +- +- device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove); +- +- if (dev_get_msi_domain(&mc_dev->dev)) { +- fsl_mc_cleanup_irq_pool(mc_bus); +- dev_set_msi_domain(&mc_dev->dev, NULL); +- } +- +- fsl_mc_cleanup_all_resource_pools(mc_dev); +- +- error = dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); +- if (error < 0) +- dev_err(&mc_dev->dev, "dprc_close() failed: %d\n", error); +- +- if (!fsl_mc_is_root_dprc(&mc_dev->dev)) { +- fsl_destroy_mc_io(mc_dev->mc_io); +- mc_dev->mc_io = NULL; +- } +- +- dev_info(&mc_dev->dev, "DPRC device unbound from driver"); +- return 0; +-} +- +-static const struct fsl_mc_device_id match_id_table[] = { +- { +- .vendor = FSL_MC_VENDOR_FREESCALE, +- .obj_type = "dprc"}, +- {.vendor = 0x0}, +-}; +- +-static struct fsl_mc_driver dprc_driver = { +- .driver = { +- .name = FSL_MC_DPRC_DRIVER_NAME, +- .owner = THIS_MODULE, +- .pm = NULL, +- }, +- .match_id_table = match_id_table, +- .probe = dprc_probe, +- .remove = dprc_remove, +-}; +- +-int __init dprc_driver_init(void) +-{ +- return fsl_mc_driver_register(&dprc_driver); +-} +- +-void dprc_driver_exit(void) +-{ +- fsl_mc_driver_unregister(&dprc_driver); +-} +--- /dev/null ++++ b/drivers/bus/fsl-mc/dprc-driver.c +@@ -0,0 +1,815 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Freescale data path resource container (DPRC) driver ++ * ++ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. ++ * Author: German Rivera <German.Rivera@freescale.com> ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/slab.h> ++#include <linux/interrupt.h> ++#include <linux/msi.h> ++#include <linux/fsl/mc.h> ++ ++#include "fsl-mc-private.h" ++ ++#define FSL_MC_DPRC_DRIVER_NAME "fsl_mc_dprc" ++ ++struct fsl_mc_child_objs { ++ int child_count; ++ struct fsl_mc_obj_desc *child_array; ++}; ++ ++static bool fsl_mc_device_match(struct fsl_mc_device *mc_dev, ++ struct fsl_mc_obj_desc *obj_desc) ++{ ++ return mc_dev->obj_desc.id == obj_desc->id && ++ strcmp(mc_dev->obj_desc.type, obj_desc->type) == 0; ++ ++} ++ ++static int __fsl_mc_device_remove_if_not_in_mc(struct device *dev, void *data) ++{ ++ int i; ++ struct fsl_mc_child_objs *objs; ++ struct fsl_mc_device *mc_dev; ++ ++ mc_dev = to_fsl_mc_device(dev); ++ objs = data; ++ ++ for (i = 0; i < objs->child_count; i++) { ++ struct fsl_mc_obj_desc *obj_desc = &objs->child_array[i]; ++ ++ if (strlen(obj_desc->type) != 0 && ++ fsl_mc_device_match(mc_dev, obj_desc)) ++ break; ++ } ++ ++ if (i == objs->child_count) ++ fsl_mc_device_remove(mc_dev); ++ ++ return 0; ++} ++ ++static int __fsl_mc_device_remove(struct device *dev, void *data) ++{ ++ fsl_mc_device_remove(to_fsl_mc_device(dev)); ++ return 0; ++} ++ ++/** ++ * dprc_remove_devices - Removes devices for objects removed from a DPRC ++ * ++ * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object ++ * @obj_desc_array: array of object descriptors for child objects currently ++ * present in the DPRC in the MC. ++ * @num_child_objects_in_mc: number of entries in obj_desc_array ++ * ++ * Synchronizes the state of the Linux bus driver with the actual state of ++ * the MC by removing devices that represent MC objects that have ++ * been dynamically removed in the physical DPRC. ++ */ ++static void dprc_remove_devices(struct fsl_mc_device *mc_bus_dev, ++ struct fsl_mc_obj_desc *obj_desc_array, ++ int num_child_objects_in_mc) ++{ ++ if (num_child_objects_in_mc != 0) { ++ /* ++ * Remove child objects that are in the DPRC in Linux, ++ * but not in the MC: ++ */ ++ struct fsl_mc_child_objs objs; ++ ++ objs.child_count = num_child_objects_in_mc; ++ objs.child_array = obj_desc_array; ++ device_for_each_child(&mc_bus_dev->dev, &objs, ++ __fsl_mc_device_remove_if_not_in_mc); ++ } else { ++ /* ++ * There are no child objects for this DPRC in the MC. ++ * So, remove all the child devices from Linux: ++ */ ++ device_for_each_child(&mc_bus_dev->dev, NULL, ++ __fsl_mc_device_remove); ++ } ++} ++ ++static int __fsl_mc_device_match(struct device *dev, void *data) ++{ ++ struct fsl_mc_obj_desc *obj_desc = data; ++ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); ++ ++ return fsl_mc_device_match(mc_dev, obj_desc); ++} ++ ++static struct fsl_mc_device *fsl_mc_device_lookup(struct fsl_mc_obj_desc ++ *obj_desc, ++ struct fsl_mc_device ++ *mc_bus_dev) ++{ ++ struct device *dev; ++ ++ dev = device_find_child(&mc_bus_dev->dev, obj_desc, ++ __fsl_mc_device_match); ++ ++ return dev ? to_fsl_mc_device(dev) : NULL; ++} ++ ++/** ++ * check_plugged_state_change - Check change in an MC object's plugged state ++ * ++ * @mc_dev: pointer to the fsl-mc device for a given MC object ++ * @obj_desc: pointer to the MC object's descriptor in the MC ++ * ++ * If the plugged state has changed from unplugged to plugged, the fsl-mc ++ * device is bound to the corresponding device driver. ++ * If the plugged state has changed from plugged to unplugged, the fsl-mc ++ * device is unbound from the corresponding device driver. ++ */ ++static void check_plugged_state_change(struct fsl_mc_device *mc_dev, ++ struct fsl_mc_obj_desc *obj_desc) ++{ ++ int error; ++ u32 plugged_flag_at_mc = ++ obj_desc->state & FSL_MC_OBJ_STATE_PLUGGED; ++ ++ if (plugged_flag_at_mc != ++ (mc_dev->obj_desc.state & FSL_MC_OBJ_STATE_PLUGGED)) { ++ if (plugged_flag_at_mc) { ++ mc_dev->obj_desc.state |= FSL_MC_OBJ_STATE_PLUGGED; ++ error = device_attach(&mc_dev->dev); ++ if (error < 0) { ++ dev_err(&mc_dev->dev, ++ "device_attach() failed: %d\n", ++ error); ++ } ++ } else { ++ mc_dev->obj_desc.state &= ~FSL_MC_OBJ_STATE_PLUGGED; ++ device_release_driver(&mc_dev->dev); ++ } ++ } ++} ++ ++/** ++ * dprc_add_new_devices - Adds devices to the logical bus for a DPRC ++ * ++ * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object ++ * @driver_override: driver override to apply to new objects found in the ++ * DPRC, or NULL, if none. ++ * @obj_desc_array: array of device descriptors for child devices currently ++ * present in the physical DPRC. ++ * @num_child_objects_in_mc: number of entries in obj_desc_array ++ * ++ * Synchronizes the state of the Linux bus driver with the actual ++ * state of the MC by adding objects that have been newly discovered ++ * in the physical DPRC. ++ */ ++static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev, ++ const char *driver_override, ++ struct fsl_mc_obj_desc *obj_desc_array, ++ int num_child_objects_in_mc) ++{ ++ int error; ++ int i; ++ ++ for (i = 0; i < num_child_objects_in_mc; i++) { ++ struct fsl_mc_device *child_dev; ++ struct fsl_mc_obj_desc *obj_desc = &obj_desc_array[i]; ++ ++ if (strlen(obj_desc->type) == 0) ++ continue; ++ ++ /* ++ * Check if device is already known to Linux: ++ */ ++ child_dev = fsl_mc_device_lookup(obj_desc, mc_bus_dev); ++ if (child_dev) { ++ check_plugged_state_change(child_dev, obj_desc); ++ put_device(&child_dev->dev); ++ continue; ++ } ++ ++ error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev, ++ driver_override, &child_dev); ++ if (error < 0) ++ continue; ++ } ++} ++ ++/** ++ * dprc_scan_objects - Discover objects in a DPRC ++ * ++ * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object ++ * @driver_override: driver override to apply to new objects found in the ++ * DPRC, or NULL, if none. ++ * @total_irq_count: If argument is provided the function populates the ++ * total number of IRQs created by objects in the DPRC. ++ * ++ * Detects objects added and removed from a DPRC and synchronizes the ++ * state of the Linux bus driver, MC by adding and removing ++ * devices accordingly. ++ * Two types of devices can be found in a DPRC: allocatable objects (e.g., ++ * dpbp, dpmcp) and non-allocatable devices (e.g., dprc, dpni). ++ * All allocatable devices needed to be probed before all non-allocatable ++ * devices, to ensure that device drivers for non-allocatable ++ * devices can allocate any type of allocatable devices. ++ * That is, we need to ensure that the corresponding resource pools are ++ * populated before they can get allocation requests from probe callbacks ++ * of the device drivers for the non-allocatable devices. ++ */ ++int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev, ++ const char *driver_override, ++ unsigned int *total_irq_count) ++{ ++ int num_child_objects; ++ int dprc_get_obj_failures; ++ int error; ++ unsigned int irq_count = mc_bus_dev->obj_desc.irq_count; ++ struct fsl_mc_obj_desc *child_obj_desc_array = NULL; ++ struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); ++ ++ error = dprc_get_obj_count(mc_bus_dev->mc_io, ++ 0, ++ mc_bus_dev->mc_handle, ++ &num_child_objects); ++ if (error < 0) { ++ dev_err(&mc_bus_dev->dev, "dprc_get_obj_count() failed: %d\n", ++ error); ++ return error; ++ } ++ ++ if (num_child_objects != 0) { ++ int i; ++ ++ child_obj_desc_array = ++ devm_kmalloc_array(&mc_bus_dev->dev, num_child_objects, ++ sizeof(*child_obj_desc_array), ++ GFP_KERNEL); ++ if (!child_obj_desc_array) ++ return -ENOMEM; ++ ++ /* ++ * Discover objects currently present in the physical DPRC: ++ */ ++ dprc_get_obj_failures = 0; ++ for (i = 0; i < num_child_objects; i++) { ++ struct fsl_mc_obj_desc *obj_desc = ++ &child_obj_desc_array[i]; ++ ++ error = dprc_get_obj(mc_bus_dev->mc_io, ++ 0, ++ mc_bus_dev->mc_handle, ++ i, obj_desc); ++ if (error < 0) { ++ dev_err(&mc_bus_dev->dev, ++ "dprc_get_obj(i=%d) failed: %d\n", ++ i, error); ++ /* ++ * Mark the obj entry as "invalid", by using the ++ * empty string as obj type: ++ */ ++ obj_desc->type[0] = '\0'; ++ obj_desc->id = error; ++ dprc_get_obj_failures++; ++ continue; ++ } ++ ++ /* ++ * add a quirk for all versions of dpsec < 4.0...none ++ * are coherent regardless of what the MC reports. ++ */ ++ if ((strcmp(obj_desc->type, "dpseci") == 0) && ++ (obj_desc->ver_major < 4)) ++ obj_desc->flags |= ++ FSL_MC_OBJ_FLAG_NO_MEM_SHAREABILITY; ++ ++ irq_count += obj_desc->irq_count; ++ dev_dbg(&mc_bus_dev->dev, ++ "Discovered object: type %s, id %d\n", ++ obj_desc->type, obj_desc->id); ++ } ++ ++ if (dprc_get_obj_failures != 0) { ++ dev_err(&mc_bus_dev->dev, ++ "%d out of %d devices could not be retrieved\n", ++ dprc_get_obj_failures, num_child_objects); ++ } ++ } ++ ++ /* ++ * Allocate IRQ's before binding the scanned devices with their ++ * respective drivers. ++ */ ++ if (dev_get_msi_domain(&mc_bus_dev->dev) && !mc_bus->irq_resources) { ++ if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) { ++ dev_warn(&mc_bus_dev->dev, ++ "IRQs needed (%u) exceed IRQs preallocated (%u)\n", ++ irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); ++ } ++ ++ error = fsl_mc_populate_irq_pool(mc_bus, ++ FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); ++ if (error < 0) ++ return error; ++ } ++ ++ if (total_irq_count) ++ *total_irq_count = irq_count; ++ ++ dprc_remove_devices(mc_bus_dev, child_obj_desc_array, ++ num_child_objects); ++ ++ dprc_add_new_devices(mc_bus_dev, driver_override, child_obj_desc_array, ++ num_child_objects); ++ ++ if (child_obj_desc_array) ++ devm_kfree(&mc_bus_dev->dev, child_obj_desc_array); ++ ++ return 0; ++} ++ ++/** ++ * dprc_scan_container - Scans a physical DPRC and synchronizes Linux bus state ++ * ++ * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object ++ * ++ * Scans the physical DPRC and synchronizes the state of the Linux ++ * bus driver with the actual state of the MC by adding and removing ++ * devices as appropriate. ++ */ ++static int dprc_scan_container(struct fsl_mc_device *mc_bus_dev) ++{ ++ int error; ++ struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); ++ ++ fsl_mc_init_all_resource_pools(mc_bus_dev); ++ ++ /* ++ * Discover objects in the DPRC: ++ */ ++ mutex_lock(&mc_bus->scan_mutex); ++ error = dprc_scan_objects(mc_bus_dev, NULL, NULL); ++ mutex_unlock(&mc_bus->scan_mutex); ++ if (error < 0) { ++ fsl_mc_cleanup_all_resource_pools(mc_bus_dev); ++ return error; ++ } ++ ++ return 0; ++} ++ ++/** ++ * dprc_irq0_handler - Regular ISR for DPRC interrupt 0 ++ * ++ * @irq: IRQ number of the interrupt being handled ++ * @arg: Pointer to device structure ++ */ ++static irqreturn_t dprc_irq0_handler(int irq_num, void *arg) ++{ ++ return IRQ_WAKE_THREAD; ++} ++ ++/** ++ * dprc_irq0_handler_thread - Handler thread function for DPRC interrupt 0 ++ * ++ * @irq: IRQ number of the interrupt being handled ++ * @arg: Pointer to device structure ++ */ ++static irqreturn_t dprc_irq0_handler_thread(int irq_num, void *arg) ++{ ++ int error; ++ u32 status; ++ struct device *dev = arg; ++ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); ++ struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); ++ struct fsl_mc_io *mc_io = mc_dev->mc_io; ++ struct msi_desc *msi_desc = mc_dev->irqs[0]->msi_desc; ++ ++ dev_dbg(dev, "DPRC IRQ %d triggered on CPU %u\n", ++ irq_num, smp_processor_id()); ++ ++ if (!(mc_dev->flags & FSL_MC_IS_DPRC)) ++ return IRQ_HANDLED; ++ ++ mutex_lock(&mc_bus->scan_mutex); ++ if (!msi_desc || msi_desc->irq != (u32)irq_num) ++ goto out; ++ ++ status = 0; ++ error = dprc_get_irq_status(mc_io, 0, mc_dev->mc_handle, 0, ++ &status); ++ if (error < 0) { ++ dev_err(dev, ++ "dprc_get_irq_status() failed: %d\n", error); ++ goto out; ++ } ++ ++ error = dprc_clear_irq_status(mc_io, 0, mc_dev->mc_handle, 0, ++ status); ++ if (error < 0) { ++ dev_err(dev, ++ "dprc_clear_irq_status() failed: %d\n", error); ++ goto out; ++ } ++ ++ if (status & (DPRC_IRQ_EVENT_OBJ_ADDED | ++ DPRC_IRQ_EVENT_OBJ_REMOVED | ++ DPRC_IRQ_EVENT_CONTAINER_DESTROYED | ++ DPRC_IRQ_EVENT_OBJ_DESTROYED | ++ DPRC_IRQ_EVENT_OBJ_CREATED)) { ++ unsigned int irq_count; ++ ++ error = dprc_scan_objects(mc_dev, NULL, &irq_count); ++ if (error < 0) { ++ /* ++ * If the error is -ENXIO, we ignore it, as it indicates ++ * that the object scan was aborted, as we detected that ++ * an object was removed from the DPRC in the MC, while ++ * we were scanning the DPRC. ++ */ ++ if (error != -ENXIO) { ++ dev_err(dev, "dprc_scan_objects() failed: %d\n", ++ error); ++ } ++ ++ goto out; ++ } ++ ++ if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) { ++ dev_warn(dev, ++ "IRQs needed (%u) exceed IRQs preallocated (%u)\n", ++ irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); ++ } ++ } ++ ++out: ++ mutex_unlock(&mc_bus->scan_mutex); ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Disable and clear interrupt for a given DPRC object ++ */ ++static int disable_dprc_irq(struct fsl_mc_device *mc_dev) ++{ ++ int error; ++ struct fsl_mc_io *mc_io = mc_dev->mc_io; ++ ++ /* ++ * Disable generation of interrupt, while we configure it: ++ */ ++ error = dprc_set_irq_enable(mc_io, 0, mc_dev->mc_handle, 0, 0); ++ if (error < 0) { ++ dev_err(&mc_dev->dev, ++ "Disabling DPRC IRQ failed: dprc_set_irq_enable() failed: %d\n", ++ error); ++ return error; ++ } ++ ++ /* ++ * Disable all interrupt causes for the interrupt: ++ */ ++ error = dprc_set_irq_mask(mc_io, 0, mc_dev->mc_handle, 0, 0x0); ++ if (error < 0) { ++ dev_err(&mc_dev->dev, ++ "Disabling DPRC IRQ failed: dprc_set_irq_mask() failed: %d\n", ++ error); ++ return error; ++ } ++ ++ /* ++ * Clear any leftover interrupts: ++ */ ++ error = dprc_clear_irq_status(mc_io, 0, mc_dev->mc_handle, 0, ~0x0U); ++ if (error < 0) { ++ dev_err(&mc_dev->dev, ++ "Disabling DPRC IRQ failed: dprc_clear_irq_status() failed: %d\n", ++ error); ++ return error; ++ } ++ ++ return 0; ++} ++ ++static int register_dprc_irq_handler(struct fsl_mc_device *mc_dev) ++{ ++ int error; ++ struct fsl_mc_device_irq *irq = mc_dev->irqs[0]; ++ ++ /* ++ * NOTE: devm_request_threaded_irq() invokes the device-specific ++ * function that programs the MSI physically in the device ++ */ ++ error = devm_request_threaded_irq(&mc_dev->dev, ++ irq->msi_desc->irq, ++ dprc_irq0_handler, ++ dprc_irq0_handler_thread, ++ IRQF_NO_SUSPEND | IRQF_ONESHOT, ++ dev_name(&mc_dev->dev), ++ &mc_dev->dev); ++ if (error < 0) { ++ dev_err(&mc_dev->dev, ++ "devm_request_threaded_irq() failed: %d\n", ++ error); ++ return error; ++ } ++ ++ return 0; ++} ++ ++static int enable_dprc_irq(struct fsl_mc_device *mc_dev) ++{ ++ int error; ++ ++ /* ++ * Enable all interrupt causes for the interrupt: ++ */ ++ error = dprc_set_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle, 0, ++ ~0x0u); ++ if (error < 0) { ++ dev_err(&mc_dev->dev, ++ "Enabling DPRC IRQ failed: dprc_set_irq_mask() failed: %d\n", ++ error); ++ ++ return error; ++ } ++ ++ /* ++ * Enable generation of the interrupt: ++ */ ++ error = dprc_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle, 0, 1); ++ if (error < 0) { ++ dev_err(&mc_dev->dev, ++ "Enabling DPRC IRQ failed: dprc_set_irq_enable() failed: %d\n", ++ error); ++ ++ return error; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Setup interrupt for a given DPRC device ++ */ ++static int dprc_setup_irq(struct fsl_mc_device *mc_dev) ++{ ++ int error; ++ ++ error = fsl_mc_allocate_irqs(mc_dev); ++ if (error < 0) ++ return error; ++ ++ error = disable_dprc_irq(mc_dev); ++ if (error < 0) ++ goto error_free_irqs; ++ ++ error = register_dprc_irq_handler(mc_dev); ++ if (error < 0) ++ goto error_free_irqs; ++ ++ error = enable_dprc_irq(mc_dev); ++ if (error < 0) ++ goto error_free_irqs; ++ ++ return 0; ++ ++error_free_irqs: ++ fsl_mc_free_irqs(mc_dev); ++ return error; ++} ++ ++/** ++ * dprc_probe - callback invoked when a DPRC is being bound to this driver ++ * ++ * @mc_dev: Pointer to fsl-mc device representing a DPRC ++ * ++ * It opens the physical DPRC in the MC. ++ * It scans the DPRC to discover the MC objects contained in it. ++ * It creates the interrupt pool for the MC bus associated with the DPRC. ++ * It configures the interrupts for the DPRC device itself. ++ */ ++static int dprc_probe(struct fsl_mc_device *mc_dev) ++{ ++ int error; ++ size_t region_size; ++ struct device *parent_dev = mc_dev->dev.parent; ++ struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); ++ bool mc_io_created = false; ++ bool msi_domain_set = false; ++ u16 major_ver, minor_ver; ++ ++ if (!is_fsl_mc_bus_dprc(mc_dev)) ++ return -EINVAL; ++ ++ if (dev_get_msi_domain(&mc_dev->dev)) ++ return -EINVAL; ++ ++ if (!mc_dev->mc_io) { ++ /* ++ * This is a child DPRC: ++ */ ++ if (!dev_is_fsl_mc(parent_dev)) ++ return -EINVAL; ++ ++ if (mc_dev->obj_desc.region_count == 0) ++ return -EINVAL; ++ ++ region_size = resource_size(mc_dev->regions); ++ ++ error = fsl_create_mc_io(&mc_dev->dev, ++ mc_dev->regions[0].start, ++ region_size, ++ NULL, ++ FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, ++ &mc_dev->mc_io); ++ if (error < 0) ++ return error; ++ ++ mc_io_created = true; ++ ++ /* ++ * Inherit parent MSI domain: ++ */ ++ dev_set_msi_domain(&mc_dev->dev, ++ dev_get_msi_domain(parent_dev)); ++ msi_domain_set = true; ++ } else { ++ /* ++ * This is a root DPRC ++ */ ++ struct irq_domain *mc_msi_domain; ++ ++ if (dev_is_fsl_mc(parent_dev)) ++ return -EINVAL; ++ ++ error = fsl_mc_find_msi_domain(parent_dev, ++ &mc_msi_domain); ++ if (error < 0) { ++ dev_warn(&mc_dev->dev, ++ "WARNING: MC bus without interrupt support\n"); ++ } else { ++ dev_set_msi_domain(&mc_dev->dev, mc_msi_domain); ++ msi_domain_set = true; ++ } ++ } ++ ++ error = dprc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id, ++ &mc_dev->mc_handle); ++ if (error < 0) { ++ dev_err(&mc_dev->dev, "dprc_open() failed: %d\n", error); ++ goto error_cleanup_msi_domain; ++ } ++ ++ error = dprc_get_attributes(mc_dev->mc_io, 0, mc_dev->mc_handle, ++ &mc_bus->dprc_attr); ++ if (error < 0) { ++ dev_err(&mc_dev->dev, "dprc_get_attributes() failed: %d\n", ++ error); ++ goto error_cleanup_open; ++ } ++ ++ error = dprc_get_api_version(mc_dev->mc_io, 0, ++ &major_ver, ++ &minor_ver); ++ if (error < 0) { ++ dev_err(&mc_dev->dev, "dprc_get_api_version() failed: %d\n", ++ error); ++ goto error_cleanup_open; ++ } ++ ++ if (major_ver < DPRC_MIN_VER_MAJOR || ++ (major_ver == DPRC_MIN_VER_MAJOR && ++ minor_ver < DPRC_MIN_VER_MINOR)) { ++ dev_err(&mc_dev->dev, ++ "ERROR: DPRC version %d.%d not supported\n", ++ major_ver, minor_ver); ++ error = -ENOTSUPP; ++ goto error_cleanup_open; ++ } ++ ++ mutex_init(&mc_bus->scan_mutex); ++ ++ /* ++ * Discover MC objects in DPRC object: ++ */ ++ error = dprc_scan_container(mc_dev); ++ if (error < 0) ++ goto error_cleanup_open; ++ ++ /* ++ * Configure interrupt for the DPRC object associated with this MC bus: ++ */ ++ error = dprc_setup_irq(mc_dev); ++ if (error < 0) ++ goto error_cleanup_open; ++ ++ dev_info(&mc_dev->dev, "DPRC device bound to driver"); ++ return 0; ++ ++error_cleanup_open: ++ (void)dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); ++ ++error_cleanup_msi_domain: ++ if (msi_domain_set) ++ dev_set_msi_domain(&mc_dev->dev, NULL); ++ ++ if (mc_io_created) { ++ fsl_destroy_mc_io(mc_dev->mc_io); ++ mc_dev->mc_io = NULL; ++ } ++ ++ return error; ++} ++ ++/* ++ * Tear down interrupt for a given DPRC object ++ */ ++static void dprc_teardown_irq(struct fsl_mc_device *mc_dev) ++{ ++ struct fsl_mc_device_irq *irq = mc_dev->irqs[0]; ++ ++ (void)disable_dprc_irq(mc_dev); ++ ++ devm_free_irq(&mc_dev->dev, irq->msi_desc->irq, &mc_dev->dev); ++ ++ fsl_mc_free_irqs(mc_dev); ++} ++ ++/** ++ * dprc_remove - callback invoked when a DPRC is being unbound from this driver ++ * ++ * @mc_dev: Pointer to fsl-mc device representing the DPRC ++ * ++ * It removes the DPRC's child objects from Linux (not from the MC) and ++ * closes the DPRC device in the MC. ++ * It tears down the interrupts that were configured for the DPRC device. ++ * It destroys the interrupt pool associated with this MC bus. ++ */ ++static int dprc_remove(struct fsl_mc_device *mc_dev) ++{ ++ int error; ++ struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); ++ ++ if (!is_fsl_mc_bus_dprc(mc_dev)) ++ return -EINVAL; ++ if (!mc_dev->mc_io) ++ return -EINVAL; ++ ++ if (!mc_bus->irq_resources) ++ return -EINVAL; ++ ++ if (dev_get_msi_domain(&mc_dev->dev)) ++ dprc_teardown_irq(mc_dev); ++ ++ device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove); ++ ++ if (dev_get_msi_domain(&mc_dev->dev)) { ++ fsl_mc_cleanup_irq_pool(mc_bus); ++ dev_set_msi_domain(&mc_dev->dev, NULL); ++ } ++ ++ fsl_mc_cleanup_all_resource_pools(mc_dev); ++ ++ error = dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); ++ if (error < 0) ++ dev_err(&mc_dev->dev, "dprc_close() failed: %d\n", error); ++ ++ if (!fsl_mc_is_root_dprc(&mc_dev->dev)) { ++ fsl_destroy_mc_io(mc_dev->mc_io); ++ mc_dev->mc_io = NULL; ++ } ++ ++ dev_info(&mc_dev->dev, "DPRC device unbound from driver"); ++ return 0; ++} ++ ++static const struct fsl_mc_device_id match_id_table[] = { ++ { ++ .vendor = FSL_MC_VENDOR_FREESCALE, ++ .obj_type = "dprc"}, ++ {.vendor = 0x0}, ++}; ++ ++static struct fsl_mc_driver dprc_driver = { ++ .driver = { ++ .name = FSL_MC_DPRC_DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .pm = NULL, ++ }, ++ .match_id_table = match_id_table, ++ .probe = dprc_probe, ++ .remove = dprc_remove, ++}; ++ ++int __init dprc_driver_init(void) ++{ ++ return fsl_mc_driver_register(&dprc_driver); ++} ++ ++void dprc_driver_exit(void) ++{ ++ fsl_mc_driver_unregister(&dprc_driver); ++} +--- /dev/null ++++ b/drivers/bus/fsl-mc/dprc.c +@@ -0,0 +1,575 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ */ ++#include <linux/kernel.h> ++#include <linux/fsl/mc.h> ++ ++#include "fsl-mc-private.h" ++ ++/** ++ * dprc_open() - Open DPRC object for use ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @container_id: Container ID to open ++ * @token: Returned token of DPRC object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ * ++ * @warning Required before any operation on the object. ++ */ ++int dprc_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int container_id, ++ u16 *token) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dprc_cmd_open *cmd_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRC_CMDID_OPEN, cmd_flags, ++ 0); ++ cmd_params = (struct dprc_cmd_open *)cmd.params; ++ cmd_params->container_id = cpu_to_le32(container_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *token = mc_cmd_hdr_read_token(&cmd); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(dprc_open); ++ ++/** ++ * dprc_close() - Close the control session of the object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRC object ++ * ++ * After this function is called, no further operations are ++ * allowed on the object without opening a new control session. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprc_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRC_CMDID_CLOSE, cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++EXPORT_SYMBOL_GPL(dprc_close); ++ ++/** ++ * dprc_reset_container - Reset child container. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRC object ++ * @child_container_id: ID of the container to reset ++ * ++ * In case a software context crashes or becomes non-responsive, the parent ++ * may wish to reset its resources container before the software context is ++ * restarted. ++ * ++ * This routine informs all objects assigned to the child container that the ++ * container is being reset, so they may perform any cleanup operations that are ++ * needed. All objects handles that were owned by the child container shall be ++ * closed. ++ * ++ * Note that such request may be submitted even if the child software context ++ * has not crashed, but the resulting object cleanup operations will not be ++ * aware of that. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprc_reset_container(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int child_container_id) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dprc_cmd_reset_container *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRC_CMDID_RESET_CONT, ++ cmd_flags, token); ++ cmd_params = (struct dprc_cmd_reset_container *)cmd.params; ++ cmd_params->child_container_id = cpu_to_le32(child_container_id); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++EXPORT_SYMBOL_GPL(dprc_reset_container); ++ ++/** ++ * dprc_set_irq() - Set IRQ information for the DPRC to trigger an interrupt. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRC object ++ * @irq_index: Identifies the interrupt index to configure ++ * @irq_cfg: IRQ configuration ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprc_set_irq(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ struct dprc_irq_cfg *irq_cfg) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dprc_cmd_set_irq *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_IRQ, ++ cmd_flags, ++ token); ++ cmd_params = (struct dprc_cmd_set_irq *)cmd.params; ++ cmd_params->irq_val = cpu_to_le32(irq_cfg->val); ++ cmd_params->irq_index = irq_index; ++ cmd_params->irq_addr = cpu_to_le64(irq_cfg->paddr); ++ cmd_params->irq_num = cpu_to_le32(irq_cfg->irq_num); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dprc_set_irq_enable() - Set overall interrupt state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRC object ++ * @irq_index: The interrupt index to configure ++ * @en: Interrupt state - enable = 1, disable = 0 ++ * ++ * Allows GPP software to control when interrupts are generated. ++ * Each interrupt can have up to 32 causes. The enable/disable control's the ++ * overall interrupt state. if the interrupt is disabled no causes will cause ++ * an interrupt. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprc_set_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 en) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dprc_cmd_set_irq_enable *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_IRQ_ENABLE, ++ cmd_flags, token); ++ cmd_params = (struct dprc_cmd_set_irq_enable *)cmd.params; ++ cmd_params->enable = en & DPRC_ENABLE; ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dprc_set_irq_mask() - Set interrupt mask. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRC object ++ * @irq_index: The interrupt index to configure ++ * @mask: event mask to trigger interrupt; ++ * each bit: ++ * 0 = ignore event ++ * 1 = consider event for asserting irq ++ * ++ * Every interrupt can have up to 32 causes and the interrupt model supports ++ * masking/unmasking each cause independently ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprc_set_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 mask) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dprc_cmd_set_irq_mask *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_IRQ_MASK, ++ cmd_flags, token); ++ cmd_params = (struct dprc_cmd_set_irq_mask *)cmd.params; ++ cmd_params->mask = cpu_to_le32(mask); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dprc_get_irq_status() - Get the current status of any pending interrupts. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRC object ++ * @irq_index: The interrupt index to configure ++ * @status: Returned interrupts status - one bit per cause: ++ * 0 = no interrupt pending ++ * 1 = interrupt pending ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprc_get_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *status) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dprc_cmd_get_irq_status *cmd_params; ++ struct dprc_rsp_get_irq_status *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_IRQ_STATUS, ++ cmd_flags, token); ++ cmd_params = (struct dprc_cmd_get_irq_status *)cmd.params; ++ cmd_params->status = cpu_to_le32(*status); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dprc_rsp_get_irq_status *)cmd.params; ++ *status = le32_to_cpu(rsp_params->status); ++ ++ return 0; ++} ++ ++/** ++ * dprc_clear_irq_status() - Clear a pending interrupt's status ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRC object ++ * @irq_index: The interrupt index to configure ++ * @status: bits to clear (W1C) - one bit per cause: ++ * 0 = don't change ++ * 1 = clear status bit ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprc_clear_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 status) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dprc_cmd_clear_irq_status *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRC_CMDID_CLEAR_IRQ_STATUS, ++ cmd_flags, token); ++ cmd_params = (struct dprc_cmd_clear_irq_status *)cmd.params; ++ cmd_params->status = cpu_to_le32(status); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dprc_get_attributes() - Obtains container attributes ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRC object ++ * @attributes Returned container attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprc_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dprc_attributes *attr) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dprc_rsp_get_attributes *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_ATTR, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dprc_rsp_get_attributes *)cmd.params; ++ attr->container_id = le32_to_cpu(rsp_params->container_id); ++ attr->icid = le32_to_cpu(rsp_params->icid); ++ attr->options = le32_to_cpu(rsp_params->options); ++ attr->portal_id = le32_to_cpu(rsp_params->portal_id); ++ ++ return 0; ++} ++ ++/** ++ * dprc_get_obj_count() - Obtains the number of objects in the DPRC ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRC object ++ * @obj_count: Number of objects assigned to the DPRC ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprc_get_obj_count(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int *obj_count) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dprc_rsp_get_obj_count *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_COUNT, ++ cmd_flags, token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dprc_rsp_get_obj_count *)cmd.params; ++ *obj_count = le32_to_cpu(rsp_params->obj_count); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(dprc_get_obj_count); ++ ++/** ++ * dprc_get_obj() - Get general information on an object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRC object ++ * @obj_index: Index of the object to be queried (< obj_count) ++ * @obj_desc: Returns the requested object descriptor ++ * ++ * The object descriptors are retrieved one by one by incrementing ++ * obj_index up to (not including) the value of obj_count returned ++ * from dprc_get_obj_count(). dprc_get_obj_count() must ++ * be called prior to dprc_get_obj(). ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprc_get_obj(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int obj_index, ++ struct fsl_mc_obj_desc *obj_desc) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dprc_cmd_get_obj *cmd_params; ++ struct dprc_rsp_get_obj *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ, ++ cmd_flags, ++ token); ++ cmd_params = (struct dprc_cmd_get_obj *)cmd.params; ++ cmd_params->obj_index = cpu_to_le32(obj_index); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dprc_rsp_get_obj *)cmd.params; ++ obj_desc->id = le32_to_cpu(rsp_params->id); ++ obj_desc->vendor = le16_to_cpu(rsp_params->vendor); ++ obj_desc->irq_count = rsp_params->irq_count; ++ obj_desc->region_count = rsp_params->region_count; ++ obj_desc->state = le32_to_cpu(rsp_params->state); ++ obj_desc->ver_major = le16_to_cpu(rsp_params->version_major); ++ obj_desc->ver_minor = le16_to_cpu(rsp_params->version_minor); ++ obj_desc->flags = le16_to_cpu(rsp_params->flags); ++ strncpy(obj_desc->type, rsp_params->type, 16); ++ obj_desc->type[15] = '\0'; ++ strncpy(obj_desc->label, rsp_params->label, 16); ++ obj_desc->label[15] = '\0'; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(dprc_get_obj); ++ ++/** ++ * dprc_set_obj_irq() - Set IRQ information for object to trigger an interrupt. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRC object ++ * @obj_type: Type of the object to set its IRQ ++ * @obj_id: ID of the object to set its IRQ ++ * @irq_index: The interrupt index to configure ++ * @irq_cfg: IRQ configuration ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprc_set_obj_irq(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ char *obj_type, ++ int obj_id, ++ u8 irq_index, ++ struct dprc_irq_cfg *irq_cfg) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dprc_cmd_set_obj_irq *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_OBJ_IRQ, ++ cmd_flags, ++ token); ++ cmd_params = (struct dprc_cmd_set_obj_irq *)cmd.params; ++ cmd_params->irq_val = cpu_to_le32(irq_cfg->val); ++ cmd_params->irq_index = irq_index; ++ cmd_params->irq_addr = cpu_to_le64(irq_cfg->paddr); ++ cmd_params->irq_num = cpu_to_le32(irq_cfg->irq_num); ++ cmd_params->obj_id = cpu_to_le32(obj_id); ++ strncpy(cmd_params->obj_type, obj_type, 16); ++ cmd_params->obj_type[15] = '\0'; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++EXPORT_SYMBOL_GPL(dprc_set_obj_irq); ++ ++/** ++ * dprc_get_obj_region() - Get region information for a specified object. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRC object ++ * @obj_type; Object type as returned in dprc_get_obj() ++ * @obj_id: Unique object instance as returned in dprc_get_obj() ++ * @region_index: The specific region to query ++ * @region_desc: Returns the requested region descriptor ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprc_get_obj_region(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ char *obj_type, ++ int obj_id, ++ u8 region_index, ++ struct dprc_region_desc *region_desc) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dprc_cmd_get_obj_region *cmd_params; ++ struct dprc_rsp_get_obj_region *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG, ++ cmd_flags, token); ++ cmd_params = (struct dprc_cmd_get_obj_region *)cmd.params; ++ cmd_params->obj_id = cpu_to_le32(obj_id); ++ cmd_params->region_index = region_index; ++ strncpy(cmd_params->obj_type, obj_type, 16); ++ cmd_params->obj_type[15] = '\0'; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dprc_rsp_get_obj_region *)cmd.params; ++ region_desc->base_offset = le32_to_cpu(rsp_params->base_addr); ++ region_desc->size = le32_to_cpu(rsp_params->size); ++ region_desc->type = rsp_params->type; ++ region_desc->flags = le32_to_cpu(rsp_params->flags); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(dprc_get_obj_region); ++ ++/** ++ * dprc_get_api_version - Get Data Path Resource Container API version ++ * @mc_io: Pointer to Mc portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @major_ver: Major version of Data Path Resource Container API ++ * @minor_ver: Minor version of Data Path Resource Container API ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprc_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_API_VERSION, ++ cmd_flags, 0); ++ ++ /* send command to mc */ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ mc_cmd_read_api_version(&cmd, major_ver, minor_ver); ++ ++ return 0; ++} ++ ++/** ++ * dprc_get_container_id - Get container ID associated with a given portal. ++ * @mc_io: Pointer to Mc portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @container_id: Requested container id ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprc_get_container_id(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int *container_id) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_CONT_ID, ++ cmd_flags, ++ 0); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *container_id = (int)mc_cmd_read_object_id(&cmd); ++ ++ return 0; ++} +--- a/drivers/staging/fsl-mc/bus/fsl-mc-allocator.c ++++ /dev/null +@@ -1,668 +0,0 @@ +-/* +- * Freescale MC object device allocator driver +- * +- * Copyright (C) 2013 Freescale Semiconductor, Inc. +- * +- * 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 <linux/module.h> +-#include <linux/msi.h> +-#include "../include/mc-bus.h" +-#include "../include/mc-sys.h" +-#include "../include/dpbp-cmd.h" +-#include "../include/dpcon-cmd.h" +- +-#include "fsl-mc-private.h" +- +-#define FSL_MC_IS_ALLOCATABLE(_obj_type) \ +- (strcmp(_obj_type, "dpbp") == 0 || \ +- strcmp(_obj_type, "dpmcp") == 0 || \ +- strcmp(_obj_type, "dpcon") == 0) +- +-/** +- * fsl_mc_resource_pool_add_device - add allocatable device to a resource +- * pool of a given MC bus +- * +- * @mc_bus: pointer to the MC bus +- * @pool_type: MC bus pool type +- * @mc_dev: Pointer to allocatable MC object device +- * +- * It adds an allocatable MC object device to a container's resource pool of +- * the given resource type +- */ +-static int __must_check fsl_mc_resource_pool_add_device(struct fsl_mc_bus +- *mc_bus, +- enum fsl_mc_pool_type +- pool_type, +- struct fsl_mc_device +- *mc_dev) +-{ +- struct fsl_mc_resource_pool *res_pool; +- struct fsl_mc_resource *resource; +- struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev; +- int error = -EINVAL; +- +- if (WARN_ON(pool_type < 0 || pool_type >= FSL_MC_NUM_POOL_TYPES)) +- goto out; +- if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type))) +- goto out; +- if (WARN_ON(mc_dev->resource)) +- goto out; +- +- res_pool = &mc_bus->resource_pools[pool_type]; +- if (WARN_ON(res_pool->type != pool_type)) +- goto out; +- if (WARN_ON(res_pool->mc_bus != mc_bus)) +- goto out; +- +- mutex_lock(&res_pool->mutex); +- +- if (WARN_ON(res_pool->max_count < 0)) +- goto out_unlock; +- if (WARN_ON(res_pool->free_count < 0 || +- res_pool->free_count > res_pool->max_count)) +- goto out_unlock; +- +- resource = devm_kzalloc(&mc_bus_dev->dev, sizeof(*resource), +- GFP_KERNEL); +- if (!resource) { +- error = -ENOMEM; +- dev_err(&mc_bus_dev->dev, +- "Failed to allocate memory for fsl_mc_resource\n"); +- goto out_unlock; +- } +- +- resource->type = pool_type; +- resource->id = mc_dev->obj_desc.id; +- resource->data = mc_dev; +- resource->parent_pool = res_pool; +- INIT_LIST_HEAD(&resource->node); +- list_add_tail(&resource->node, &res_pool->free_list); +- mc_dev->resource = resource; +- res_pool->free_count++; +- res_pool->max_count++; +- error = 0; +-out_unlock: +- mutex_unlock(&res_pool->mutex); +-out: +- return error; +-} +- +-/** +- * fsl_mc_resource_pool_remove_device - remove an allocatable device from a +- * resource pool +- * +- * @mc_dev: Pointer to allocatable MC object device +- * +- * It permanently removes an allocatable MC object device from the resource +- * pool, the device is currently in, as long as it is in the pool's free list. +- */ +-static int __must_check fsl_mc_resource_pool_remove_device(struct fsl_mc_device +- *mc_dev) +-{ +- struct fsl_mc_device *mc_bus_dev; +- struct fsl_mc_bus *mc_bus; +- struct fsl_mc_resource_pool *res_pool; +- struct fsl_mc_resource *resource; +- int error = -EINVAL; +- +- if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type))) +- goto out; +- +- resource = mc_dev->resource; +- if (WARN_ON(!resource || resource->data != mc_dev)) +- goto out; +- +- mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); +- mc_bus = to_fsl_mc_bus(mc_bus_dev); +- res_pool = resource->parent_pool; +- if (WARN_ON(res_pool != &mc_bus->resource_pools[resource->type])) +- goto out; +- +- mutex_lock(&res_pool->mutex); +- +- if (WARN_ON(res_pool->max_count <= 0)) +- goto out_unlock; +- if (WARN_ON(res_pool->free_count <= 0 || +- res_pool->free_count > res_pool->max_count)) +- goto out_unlock; +- +- /* +- * If the device is currently allocated, its resource is not +- * in the free list and thus, the device cannot be removed. +- */ +- if (list_empty(&resource->node)) { +- error = -EBUSY; +- dev_err(&mc_bus_dev->dev, +- "Device %s cannot be removed from resource pool\n", +- dev_name(&mc_dev->dev)); +- goto out_unlock; +- } +- +- list_del_init(&resource->node); +- res_pool->free_count--; +- res_pool->max_count--; +- +- devm_kfree(&mc_bus_dev->dev, resource); +- mc_dev->resource = NULL; +- error = 0; +-out_unlock: +- mutex_unlock(&res_pool->mutex); +-out: +- return error; +-} +- +-static const char *const fsl_mc_pool_type_strings[] = { +- [FSL_MC_POOL_DPMCP] = "dpmcp", +- [FSL_MC_POOL_DPBP] = "dpbp", +- [FSL_MC_POOL_DPCON] = "dpcon", +- [FSL_MC_POOL_IRQ] = "irq", +-}; +- +-static int __must_check object_type_to_pool_type(const char *object_type, +- enum fsl_mc_pool_type +- *pool_type) +-{ +- unsigned int i; +- +- for (i = 0; i < ARRAY_SIZE(fsl_mc_pool_type_strings); i++) { +- if (strcmp(object_type, fsl_mc_pool_type_strings[i]) == 0) { +- *pool_type = i; +- return 0; +- } +- } +- +- return -EINVAL; +-} +- +-int __must_check fsl_mc_resource_allocate(struct fsl_mc_bus *mc_bus, +- enum fsl_mc_pool_type pool_type, +- struct fsl_mc_resource **new_resource) +-{ +- struct fsl_mc_resource_pool *res_pool; +- struct fsl_mc_resource *resource; +- struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev; +- int error = -EINVAL; +- +- BUILD_BUG_ON(ARRAY_SIZE(fsl_mc_pool_type_strings) != +- FSL_MC_NUM_POOL_TYPES); +- +- *new_resource = NULL; +- if (WARN_ON(pool_type < 0 || pool_type >= FSL_MC_NUM_POOL_TYPES)) +- goto out; +- +- res_pool = &mc_bus->resource_pools[pool_type]; +- if (WARN_ON(res_pool->mc_bus != mc_bus)) +- goto out; +- +- mutex_lock(&res_pool->mutex); +- resource = list_first_entry_or_null(&res_pool->free_list, +- struct fsl_mc_resource, node); +- +- if (!resource) { +- WARN_ON(res_pool->free_count != 0); +- error = -ENXIO; +- dev_err(&mc_bus_dev->dev, +- "No more resources of type %s left\n", +- fsl_mc_pool_type_strings[pool_type]); +- goto out_unlock; +- } +- +- if (WARN_ON(resource->type != pool_type)) +- goto out_unlock; +- if (WARN_ON(resource->parent_pool != res_pool)) +- goto out_unlock; +- if (WARN_ON(res_pool->free_count <= 0 || +- res_pool->free_count > res_pool->max_count)) +- goto out_unlock; +- +- list_del_init(&resource->node); +- +- res_pool->free_count--; +- error = 0; +-out_unlock: +- mutex_unlock(&res_pool->mutex); +- *new_resource = resource; +-out: +- return error; +-} +-EXPORT_SYMBOL_GPL(fsl_mc_resource_allocate); +- +-void fsl_mc_resource_free(struct fsl_mc_resource *resource) +-{ +- struct fsl_mc_resource_pool *res_pool; +- +- res_pool = resource->parent_pool; +- if (WARN_ON(resource->type != res_pool->type)) +- return; +- +- mutex_lock(&res_pool->mutex); +- if (WARN_ON(res_pool->free_count < 0 || +- res_pool->free_count >= res_pool->max_count)) +- goto out_unlock; +- +- if (WARN_ON(!list_empty(&resource->node))) +- goto out_unlock; +- +- list_add_tail(&resource->node, &res_pool->free_list); +- res_pool->free_count++; +-out_unlock: +- mutex_unlock(&res_pool->mutex); +-} +-EXPORT_SYMBOL_GPL(fsl_mc_resource_free); +- +-/** +- * fsl_mc_object_allocate - Allocates a MC object device of the given +- * pool type from a given MC bus +- * +- * @mc_dev: MC device for which the MC object device is to be allocated +- * @pool_type: MC bus resource pool type +- * @new_mc_dev: Pointer to area where the pointer to the allocated +- * MC object device is to be returned +- * +- * This function allocates a MC object device from the device's parent DPRC, +- * from the corresponding MC bus' pool of allocatable MC object devices of +- * the given resource type. mc_dev cannot be a DPRC itself. +- * +- * NOTE: pool_type must be different from FSL_MC_POOL_MCP, since MC +- * portals are allocated using fsl_mc_portal_allocate(), instead of +- * this function. +- */ +-int __must_check fsl_mc_object_allocate(struct fsl_mc_device *mc_dev, +- enum fsl_mc_pool_type pool_type, +- struct fsl_mc_device **new_mc_adev) +-{ +- struct fsl_mc_device *mc_bus_dev; +- struct fsl_mc_bus *mc_bus; +- struct fsl_mc_device *mc_adev; +- int error = -EINVAL; +- struct fsl_mc_resource *resource = NULL; +- +- *new_mc_adev = NULL; +- if (WARN_ON(mc_dev->flags & FSL_MC_IS_DPRC)) +- goto error; +- +- if (WARN_ON(!dev_is_fsl_mc(mc_dev->dev.parent))) +- goto error; +- +- if (WARN_ON(pool_type == FSL_MC_POOL_DPMCP)) +- goto error; +- +- mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); +- mc_bus = to_fsl_mc_bus(mc_bus_dev); +- error = fsl_mc_resource_allocate(mc_bus, pool_type, &resource); +- if (error < 0) +- goto error; +- +- mc_adev = resource->data; +- if (WARN_ON(!mc_adev)) +- goto error; +- +- *new_mc_adev = mc_adev; +- return 0; +-error: +- if (resource) +- fsl_mc_resource_free(resource); +- +- return error; +-} +-EXPORT_SYMBOL_GPL(fsl_mc_object_allocate); +- +-/** +- * fsl_mc_object_free - Returns an allocatable MC object device to the +- * corresponding resource pool of a given MC bus. +- * +- * @mc_adev: Pointer to the MC object device +- */ +-void fsl_mc_object_free(struct fsl_mc_device *mc_adev) +-{ +- struct fsl_mc_resource *resource; +- +- resource = mc_adev->resource; +- if (WARN_ON(resource->type == FSL_MC_POOL_DPMCP)) +- return; +- if (WARN_ON(resource->data != mc_adev)) +- return; +- +- fsl_mc_resource_free(resource); +-} +-EXPORT_SYMBOL_GPL(fsl_mc_object_free); +- +-/* +- * Initialize the interrupt pool associated with a MC bus. +- * It allocates a block of IRQs from the GIC-ITS +- */ +-int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus, +- unsigned int irq_count) +-{ +- unsigned int i; +- struct msi_desc *msi_desc; +- struct fsl_mc_device_irq *irq_resources; +- struct fsl_mc_device_irq *mc_dev_irq; +- int error; +- struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev; +- struct fsl_mc_resource_pool *res_pool = +- &mc_bus->resource_pools[FSL_MC_POOL_IRQ]; +- +- if (WARN_ON(irq_count == 0 || +- irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS)) +- return -EINVAL; +- +- error = fsl_mc_msi_domain_alloc_irqs(&mc_bus_dev->dev, irq_count); +- if (error < 0) +- return error; +- +- irq_resources = devm_kzalloc(&mc_bus_dev->dev, +- sizeof(*irq_resources) * irq_count, +- GFP_KERNEL); +- if (!irq_resources) { +- error = -ENOMEM; +- goto cleanup_msi_irqs; +- } +- +- for (i = 0; i < irq_count; i++) { +- mc_dev_irq = &irq_resources[i]; +- +- /* +- * NOTE: This mc_dev_irq's MSI addr/value pair will be set +- * by the fsl_mc_msi_write_msg() callback +- */ +- mc_dev_irq->resource.type = res_pool->type; +- mc_dev_irq->resource.data = mc_dev_irq; +- mc_dev_irq->resource.parent_pool = res_pool; +- INIT_LIST_HEAD(&mc_dev_irq->resource.node); +- list_add_tail(&mc_dev_irq->resource.node, &res_pool->free_list); +- } +- +- for_each_msi_entry(msi_desc, &mc_bus_dev->dev) { +- mc_dev_irq = &irq_resources[msi_desc->fsl_mc.msi_index]; +- mc_dev_irq->msi_desc = msi_desc; +- mc_dev_irq->resource.id = msi_desc->irq; +- } +- +- res_pool->max_count = irq_count; +- res_pool->free_count = irq_count; +- mc_bus->irq_resources = irq_resources; +- return 0; +- +-cleanup_msi_irqs: +- fsl_mc_msi_domain_free_irqs(&mc_bus_dev->dev); +- return error; +-} +-EXPORT_SYMBOL_GPL(fsl_mc_populate_irq_pool); +- +-/** +- * Teardown the interrupt pool associated with an MC bus. +- * It frees the IRQs that were allocated to the pool, back to the GIC-ITS. +- */ +-void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus) +-{ +- struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev; +- struct fsl_mc_resource_pool *res_pool = +- &mc_bus->resource_pools[FSL_MC_POOL_IRQ]; +- +- if (WARN_ON(!mc_bus->irq_resources)) +- return; +- +- if (WARN_ON(res_pool->max_count == 0)) +- return; +- +- if (WARN_ON(res_pool->free_count != res_pool->max_count)) +- return; +- +- INIT_LIST_HEAD(&res_pool->free_list); +- res_pool->max_count = 0; +- res_pool->free_count = 0; +- mc_bus->irq_resources = NULL; +- fsl_mc_msi_domain_free_irqs(&mc_bus_dev->dev); +-} +-EXPORT_SYMBOL_GPL(fsl_mc_cleanup_irq_pool); +- +-/** +- * It allocates the IRQs required by a given MC object device. The +- * IRQs are allocated from the interrupt pool associated with the +- * MC bus that contains the device, if the device is not a DPRC device. +- * Otherwise, the IRQs are allocated from the interrupt pool associated +- * with the MC bus that represents the DPRC device itself. +- */ +-int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev) +-{ +- int i; +- int irq_count; +- int res_allocated_count = 0; +- int error = -EINVAL; +- struct fsl_mc_device_irq **irqs = NULL; +- struct fsl_mc_bus *mc_bus; +- struct fsl_mc_resource_pool *res_pool; +- +- if (WARN_ON(mc_dev->irqs)) +- return -EINVAL; +- +- irq_count = mc_dev->obj_desc.irq_count; +- if (WARN_ON(irq_count == 0)) +- return -EINVAL; +- +- if (strcmp(mc_dev->obj_desc.type, "dprc") == 0) +- mc_bus = to_fsl_mc_bus(mc_dev); +- else +- mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent)); +- +- if (WARN_ON(!mc_bus->irq_resources)) +- return -EINVAL; +- +- res_pool = &mc_bus->resource_pools[FSL_MC_POOL_IRQ]; +- if (res_pool->free_count < irq_count) { +- dev_err(&mc_dev->dev, +- "Not able to allocate %u irqs for device\n", irq_count); +- return -ENOSPC; +- } +- +- irqs = devm_kzalloc(&mc_dev->dev, irq_count * sizeof(irqs[0]), +- GFP_KERNEL); +- if (!irqs) +- return -ENOMEM; +- +- for (i = 0; i < irq_count; i++) { +- struct fsl_mc_resource *resource; +- +- error = fsl_mc_resource_allocate(mc_bus, FSL_MC_POOL_IRQ, +- &resource); +- if (error < 0) +- goto error_resource_alloc; +- +- irqs[i] = to_fsl_mc_irq(resource); +- res_allocated_count++; +- +- WARN_ON(irqs[i]->mc_dev); +- irqs[i]->mc_dev = mc_dev; +- irqs[i]->dev_irq_index = i; +- } +- +- mc_dev->irqs = irqs; +- return 0; +- +-error_resource_alloc: +- for (i = 0; i < res_allocated_count; i++) { +- irqs[i]->mc_dev = NULL; +- fsl_mc_resource_free(&irqs[i]->resource); +- } +- +- return error; +-} +-EXPORT_SYMBOL_GPL(fsl_mc_allocate_irqs); +- +-/* +- * It frees the IRQs that were allocated for a MC object device, by +- * returning them to the corresponding interrupt pool. +- */ +-void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev) +-{ +- int i; +- int irq_count; +- struct fsl_mc_bus *mc_bus; +- struct fsl_mc_device_irq **irqs = mc_dev->irqs; +- +- if (WARN_ON(!irqs)) +- return; +- +- irq_count = mc_dev->obj_desc.irq_count; +- +- if (strcmp(mc_dev->obj_desc.type, "dprc") == 0) +- mc_bus = to_fsl_mc_bus(mc_dev); +- else +- mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent)); +- +- if (WARN_ON(!mc_bus->irq_resources)) +- return; +- +- for (i = 0; i < irq_count; i++) { +- WARN_ON(!irqs[i]->mc_dev); +- irqs[i]->mc_dev = NULL; +- fsl_mc_resource_free(&irqs[i]->resource); +- } +- +- mc_dev->irqs = NULL; +-} +-EXPORT_SYMBOL_GPL(fsl_mc_free_irqs); +- +-void fsl_mc_init_all_resource_pools(struct fsl_mc_device *mc_bus_dev) +-{ +- int pool_type; +- struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); +- +- for (pool_type = 0; pool_type < FSL_MC_NUM_POOL_TYPES; pool_type++) { +- struct fsl_mc_resource_pool *res_pool = +- &mc_bus->resource_pools[pool_type]; +- +- res_pool->type = pool_type; +- res_pool->max_count = 0; +- res_pool->free_count = 0; +- res_pool->mc_bus = mc_bus; +- INIT_LIST_HEAD(&res_pool->free_list); +- mutex_init(&res_pool->mutex); +- } +-} +- +-static void fsl_mc_cleanup_resource_pool(struct fsl_mc_device *mc_bus_dev, +- enum fsl_mc_pool_type pool_type) +-{ +- struct fsl_mc_resource *resource; +- struct fsl_mc_resource *next; +- struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); +- struct fsl_mc_resource_pool *res_pool = +- &mc_bus->resource_pools[pool_type]; +- int free_count = 0; +- +- WARN_ON(res_pool->type != pool_type); +- WARN_ON(res_pool->free_count != res_pool->max_count); +- +- list_for_each_entry_safe(resource, next, &res_pool->free_list, node) { +- free_count++; +- WARN_ON(resource->type != res_pool->type); +- WARN_ON(resource->parent_pool != res_pool); +- devm_kfree(&mc_bus_dev->dev, resource); +- } +- +- WARN_ON(free_count != res_pool->free_count); +-} +- +-void fsl_mc_cleanup_all_resource_pools(struct fsl_mc_device *mc_bus_dev) +-{ +- int pool_type; +- +- for (pool_type = 0; pool_type < FSL_MC_NUM_POOL_TYPES; pool_type++) +- fsl_mc_cleanup_resource_pool(mc_bus_dev, pool_type); +-} +- +-/** +- * fsl_mc_allocator_probe - callback invoked when an allocatable device is +- * being added to the system +- */ +-static int fsl_mc_allocator_probe(struct fsl_mc_device *mc_dev) +-{ +- enum fsl_mc_pool_type pool_type; +- struct fsl_mc_device *mc_bus_dev; +- struct fsl_mc_bus *mc_bus; +- int error; +- +- if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type))) +- return -EINVAL; +- +- mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); +- if (WARN_ON(!dev_is_fsl_mc(&mc_bus_dev->dev))) +- return -EINVAL; +- +- mc_bus = to_fsl_mc_bus(mc_bus_dev); +- error = object_type_to_pool_type(mc_dev->obj_desc.type, &pool_type); +- if (error < 0) +- return error; +- +- error = fsl_mc_resource_pool_add_device(mc_bus, pool_type, mc_dev); +- if (error < 0) +- return error; +- +- dev_dbg(&mc_dev->dev, +- "Allocatable MC object device bound to fsl_mc_allocator driver"); +- return 0; +-} +- +-/** +- * fsl_mc_allocator_remove - callback invoked when an allocatable device is +- * being removed from the system +- */ +-static int fsl_mc_allocator_remove(struct fsl_mc_device *mc_dev) +-{ +- int error; +- +- if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type))) +- return -EINVAL; +- +- if (mc_dev->resource) { +- error = fsl_mc_resource_pool_remove_device(mc_dev); +- if (error < 0) +- return error; +- } +- +- dev_dbg(&mc_dev->dev, +- "Allocatable MC object device unbound from fsl_mc_allocator driver"); +- return 0; +-} +- +-static const struct fsl_mc_device_id match_id_table[] = { +- { +- .vendor = FSL_MC_VENDOR_FREESCALE, +- .obj_type = "dpbp", +- }, +- { +- .vendor = FSL_MC_VENDOR_FREESCALE, +- .obj_type = "dpmcp", +- }, +- { +- .vendor = FSL_MC_VENDOR_FREESCALE, +- .obj_type = "dpcon", +- }, +- {.vendor = 0x0}, +-}; +- +-static struct fsl_mc_driver fsl_mc_allocator_driver = { +- .driver = { +- .name = "fsl_mc_allocator", +- .pm = NULL, +- }, +- .match_id_table = match_id_table, +- .probe = fsl_mc_allocator_probe, +- .remove = fsl_mc_allocator_remove, +-}; +- +-int __init fsl_mc_allocator_driver_init(void) +-{ +- return fsl_mc_driver_register(&fsl_mc_allocator_driver); +-} +- +-void fsl_mc_allocator_driver_exit(void) +-{ +- fsl_mc_driver_unregister(&fsl_mc_allocator_driver); +-} +--- /dev/null ++++ b/drivers/bus/fsl-mc/fsl-mc-allocator.c +@@ -0,0 +1,655 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * fsl-mc object allocator driver ++ * ++ * Copyright (C) 2013-2016 Freescale Semiconductor, Inc. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/msi.h> ++#include <linux/fsl/mc.h> ++ ++#include "fsl-mc-private.h" ++ ++static bool __must_check fsl_mc_is_allocatable(struct fsl_mc_device *mc_dev) ++{ ++ return is_fsl_mc_bus_dpbp(mc_dev) || ++ is_fsl_mc_bus_dpmcp(mc_dev) || ++ is_fsl_mc_bus_dpcon(mc_dev); ++} ++ ++/** ++ * fsl_mc_resource_pool_add_device - add allocatable object to a resource ++ * pool of a given fsl-mc bus ++ * ++ * @mc_bus: pointer to the fsl-mc bus ++ * @pool_type: pool type ++ * @mc_dev: pointer to allocatable fsl-mc device ++ */ ++static int __must_check fsl_mc_resource_pool_add_device(struct fsl_mc_bus ++ *mc_bus, ++ enum fsl_mc_pool_type ++ pool_type, ++ struct fsl_mc_device ++ *mc_dev) ++{ ++ struct fsl_mc_resource_pool *res_pool; ++ struct fsl_mc_resource *resource; ++ struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev; ++ int error = -EINVAL; ++ ++ if (pool_type < 0 || pool_type >= FSL_MC_NUM_POOL_TYPES) ++ goto out; ++ if (!fsl_mc_is_allocatable(mc_dev)) ++ goto out; ++ if (mc_dev->resource) ++ goto out; ++ ++ res_pool = &mc_bus->resource_pools[pool_type]; ++ if (res_pool->type != pool_type) ++ goto out; ++ if (res_pool->mc_bus != mc_bus) ++ goto out; ++ ++ mutex_lock(&res_pool->mutex); ++ ++ if (res_pool->max_count < 0) ++ goto out_unlock; ++ if (res_pool->free_count < 0 || ++ res_pool->free_count > res_pool->max_count) ++ goto out_unlock; ++ ++ resource = devm_kzalloc(&mc_bus_dev->dev, sizeof(*resource), ++ GFP_KERNEL); ++ if (!resource) { ++ error = -ENOMEM; ++ dev_err(&mc_bus_dev->dev, ++ "Failed to allocate memory for fsl_mc_resource\n"); ++ goto out_unlock; ++ } ++ ++ resource->type = pool_type; ++ resource->id = mc_dev->obj_desc.id; ++ resource->data = mc_dev; ++ resource->parent_pool = res_pool; ++ INIT_LIST_HEAD(&resource->node); ++ list_add_tail(&resource->node, &res_pool->free_list); ++ mc_dev->resource = resource; ++ res_pool->free_count++; ++ res_pool->max_count++; ++ error = 0; ++out_unlock: ++ mutex_unlock(&res_pool->mutex); ++out: ++ return error; ++} ++ ++/** ++ * fsl_mc_resource_pool_remove_device - remove an allocatable device from a ++ * resource pool ++ * ++ * @mc_dev: pointer to allocatable fsl-mc device ++ * ++ * It permanently removes an allocatable fsl-mc device from the resource ++ * pool. It's an error if the device is in use. ++ */ ++static int __must_check fsl_mc_resource_pool_remove_device(struct fsl_mc_device ++ *mc_dev) ++{ ++ struct fsl_mc_device *mc_bus_dev; ++ struct fsl_mc_bus *mc_bus; ++ struct fsl_mc_resource_pool *res_pool; ++ struct fsl_mc_resource *resource; ++ int error = -EINVAL; ++ ++ if (!fsl_mc_is_allocatable(mc_dev)) ++ goto out; ++ ++ resource = mc_dev->resource; ++ if (!resource || resource->data != mc_dev) ++ goto out; ++ ++ mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); ++ mc_bus = to_fsl_mc_bus(mc_bus_dev); ++ res_pool = resource->parent_pool; ++ if (res_pool != &mc_bus->resource_pools[resource->type]) ++ goto out; ++ ++ mutex_lock(&res_pool->mutex); ++ ++ if (res_pool->max_count <= 0) ++ goto out_unlock; ++ if (res_pool->free_count <= 0 || ++ res_pool->free_count > res_pool->max_count) ++ goto out_unlock; ++ ++ /* ++ * If the device is currently allocated, its resource is not ++ * in the free list and thus, the device cannot be removed. ++ */ ++ if (list_empty(&resource->node)) { ++ error = -EBUSY; ++ dev_err(&mc_bus_dev->dev, ++ "Device %s cannot be removed from resource pool\n", ++ dev_name(&mc_dev->dev)); ++ goto out_unlock; ++ } ++ ++ list_del_init(&resource->node); ++ res_pool->free_count--; ++ res_pool->max_count--; ++ ++ devm_kfree(&mc_bus_dev->dev, resource); ++ mc_dev->resource = NULL; ++ error = 0; ++out_unlock: ++ mutex_unlock(&res_pool->mutex); ++out: ++ return error; ++} ++ ++static const char *const fsl_mc_pool_type_strings[] = { ++ [FSL_MC_POOL_DPMCP] = "dpmcp", ++ [FSL_MC_POOL_DPBP] = "dpbp", ++ [FSL_MC_POOL_DPCON] = "dpcon", ++ [FSL_MC_POOL_IRQ] = "irq", ++}; ++ ++static int __must_check object_type_to_pool_type(const char *object_type, ++ enum fsl_mc_pool_type ++ *pool_type) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(fsl_mc_pool_type_strings); i++) { ++ if (strcmp(object_type, fsl_mc_pool_type_strings[i]) == 0) { ++ *pool_type = i; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++int __must_check fsl_mc_resource_allocate(struct fsl_mc_bus *mc_bus, ++ enum fsl_mc_pool_type pool_type, ++ struct fsl_mc_resource **new_resource) ++{ ++ struct fsl_mc_resource_pool *res_pool; ++ struct fsl_mc_resource *resource; ++ struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev; ++ int error = -EINVAL; ++ ++ BUILD_BUG_ON(ARRAY_SIZE(fsl_mc_pool_type_strings) != ++ FSL_MC_NUM_POOL_TYPES); ++ ++ *new_resource = NULL; ++ if (pool_type < 0 || pool_type >= FSL_MC_NUM_POOL_TYPES) ++ goto out; ++ ++ res_pool = &mc_bus->resource_pools[pool_type]; ++ if (res_pool->mc_bus != mc_bus) ++ goto out; ++ ++ mutex_lock(&res_pool->mutex); ++ resource = list_first_entry_or_null(&res_pool->free_list, ++ struct fsl_mc_resource, node); ++ ++ if (!resource) { ++ error = -ENXIO; ++ dev_err(&mc_bus_dev->dev, ++ "No more resources of type %s left\n", ++ fsl_mc_pool_type_strings[pool_type]); ++ goto out_unlock; ++ } ++ ++ if (resource->type != pool_type) ++ goto out_unlock; ++ if (resource->parent_pool != res_pool) ++ goto out_unlock; ++ if (res_pool->free_count <= 0 || ++ res_pool->free_count > res_pool->max_count) ++ goto out_unlock; ++ ++ list_del_init(&resource->node); ++ ++ res_pool->free_count--; ++ error = 0; ++out_unlock: ++ mutex_unlock(&res_pool->mutex); ++ *new_resource = resource; ++out: ++ return error; ++} ++EXPORT_SYMBOL_GPL(fsl_mc_resource_allocate); ++ ++void fsl_mc_resource_free(struct fsl_mc_resource *resource) ++{ ++ struct fsl_mc_resource_pool *res_pool; ++ ++ res_pool = resource->parent_pool; ++ if (resource->type != res_pool->type) ++ return; ++ ++ mutex_lock(&res_pool->mutex); ++ if (res_pool->free_count < 0 || ++ res_pool->free_count >= res_pool->max_count) ++ goto out_unlock; ++ ++ if (!list_empty(&resource->node)) ++ goto out_unlock; ++ ++ list_add_tail(&resource->node, &res_pool->free_list); ++ res_pool->free_count++; ++out_unlock: ++ mutex_unlock(&res_pool->mutex); ++} ++EXPORT_SYMBOL_GPL(fsl_mc_resource_free); ++ ++/** ++ * fsl_mc_object_allocate - Allocates an fsl-mc object of the given ++ * pool type from a given fsl-mc bus instance ++ * ++ * @mc_dev: fsl-mc device which is used in conjunction with the ++ * allocated object ++ * @pool_type: pool type ++ * @new_mc_dev: pointer to area where the pointer to the allocated device ++ * is to be returned ++ * ++ * Allocatable objects are always used in conjunction with some functional ++ * device. This function allocates an object of the specified type from ++ * the DPRC containing the functional device. ++ * ++ * NOTE: pool_type must be different from FSL_MC_POOL_MCP, since MC ++ * portals are allocated using fsl_mc_portal_allocate(), instead of ++ * this function. ++ */ ++int __must_check fsl_mc_object_allocate(struct fsl_mc_device *mc_dev, ++ enum fsl_mc_pool_type pool_type, ++ struct fsl_mc_device **new_mc_adev) ++{ ++ struct fsl_mc_device *mc_bus_dev; ++ struct fsl_mc_bus *mc_bus; ++ struct fsl_mc_device *mc_adev; ++ int error = -EINVAL; ++ struct fsl_mc_resource *resource = NULL; ++ ++ *new_mc_adev = NULL; ++ if (mc_dev->flags & FSL_MC_IS_DPRC) ++ goto error; ++ ++ if (!dev_is_fsl_mc(mc_dev->dev.parent)) ++ goto error; ++ ++ if (pool_type == FSL_MC_POOL_DPMCP) ++ goto error; ++ ++ mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); ++ mc_bus = to_fsl_mc_bus(mc_bus_dev); ++ error = fsl_mc_resource_allocate(mc_bus, pool_type, &resource); ++ if (error < 0) ++ goto error; ++ ++ mc_adev = resource->data; ++ if (!mc_adev) ++ goto error; ++ ++ *new_mc_adev = mc_adev; ++ return 0; ++error: ++ if (resource) ++ fsl_mc_resource_free(resource); ++ ++ return error; ++} ++EXPORT_SYMBOL_GPL(fsl_mc_object_allocate); ++ ++/** ++ * fsl_mc_object_free - Returns an fsl-mc object to the resource ++ * pool where it came from. ++ * @mc_adev: Pointer to the fsl-mc device ++ */ ++void fsl_mc_object_free(struct fsl_mc_device *mc_adev) ++{ ++ struct fsl_mc_resource *resource; ++ ++ resource = mc_adev->resource; ++ if (resource->type == FSL_MC_POOL_DPMCP) ++ return; ++ if (resource->data != mc_adev) ++ return; ++ ++ fsl_mc_resource_free(resource); ++} ++EXPORT_SYMBOL_GPL(fsl_mc_object_free); ++ ++/* ++ * A DPRC and the devices in the DPRC all share the same GIC-ITS device ++ * ID. A block of IRQs is pre-allocated and maintained in a pool ++ * from which devices can allocate them when needed. ++ */ ++ ++/* ++ * Initialize the interrupt pool associated with an fsl-mc bus. ++ * It allocates a block of IRQs from the GIC-ITS. ++ */ ++int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus, ++ unsigned int irq_count) ++{ ++ unsigned int i; ++ struct msi_desc *msi_desc; ++ struct fsl_mc_device_irq *irq_resources; ++ struct fsl_mc_device_irq *mc_dev_irq; ++ int error; ++ struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev; ++ struct fsl_mc_resource_pool *res_pool = ++ &mc_bus->resource_pools[FSL_MC_POOL_IRQ]; ++ ++ if (irq_count == 0 || ++ irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) ++ return -EINVAL; ++ ++ error = fsl_mc_msi_domain_alloc_irqs(&mc_bus_dev->dev, irq_count); ++ if (error < 0) ++ return error; ++ ++ irq_resources = devm_kzalloc(&mc_bus_dev->dev, ++ sizeof(*irq_resources) * irq_count, ++ GFP_KERNEL); ++ if (!irq_resources) { ++ error = -ENOMEM; ++ goto cleanup_msi_irqs; ++ } ++ ++ for (i = 0; i < irq_count; i++) { ++ mc_dev_irq = &irq_resources[i]; ++ ++ /* ++ * NOTE: This mc_dev_irq's MSI addr/value pair will be set ++ * by the fsl_mc_msi_write_msg() callback ++ */ ++ mc_dev_irq->resource.type = res_pool->type; ++ mc_dev_irq->resource.data = mc_dev_irq; ++ mc_dev_irq->resource.parent_pool = res_pool; ++ INIT_LIST_HEAD(&mc_dev_irq->resource.node); ++ list_add_tail(&mc_dev_irq->resource.node, &res_pool->free_list); ++ } ++ ++ for_each_msi_entry(msi_desc, &mc_bus_dev->dev) { ++ mc_dev_irq = &irq_resources[msi_desc->fsl_mc.msi_index]; ++ mc_dev_irq->msi_desc = msi_desc; ++ mc_dev_irq->resource.id = msi_desc->irq; ++ } ++ ++ res_pool->max_count = irq_count; ++ res_pool->free_count = irq_count; ++ mc_bus->irq_resources = irq_resources; ++ return 0; ++ ++cleanup_msi_irqs: ++ fsl_mc_msi_domain_free_irqs(&mc_bus_dev->dev); ++ return error; ++} ++EXPORT_SYMBOL_GPL(fsl_mc_populate_irq_pool); ++ ++/** ++ * Teardown the interrupt pool associated with an fsl-mc bus. ++ * It frees the IRQs that were allocated to the pool, back to the GIC-ITS. ++ */ ++void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus) ++{ ++ struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev; ++ struct fsl_mc_resource_pool *res_pool = ++ &mc_bus->resource_pools[FSL_MC_POOL_IRQ]; ++ ++ if (!mc_bus->irq_resources) ++ return; ++ ++ if (res_pool->max_count == 0) ++ return; ++ ++ if (res_pool->free_count != res_pool->max_count) ++ return; ++ ++ INIT_LIST_HEAD(&res_pool->free_list); ++ res_pool->max_count = 0; ++ res_pool->free_count = 0; ++ mc_bus->irq_resources = NULL; ++ fsl_mc_msi_domain_free_irqs(&mc_bus_dev->dev); ++} ++EXPORT_SYMBOL_GPL(fsl_mc_cleanup_irq_pool); ++ ++/** ++ * Allocate the IRQs required by a given fsl-mc device. ++ */ ++int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev) ++{ ++ int i; ++ int irq_count; ++ int res_allocated_count = 0; ++ int error = -EINVAL; ++ struct fsl_mc_device_irq **irqs = NULL; ++ struct fsl_mc_bus *mc_bus; ++ struct fsl_mc_resource_pool *res_pool; ++ ++ if (mc_dev->irqs) ++ return -EINVAL; ++ ++ irq_count = mc_dev->obj_desc.irq_count; ++ if (irq_count == 0) ++ return -EINVAL; ++ ++ if (is_fsl_mc_bus_dprc(mc_dev)) ++ mc_bus = to_fsl_mc_bus(mc_dev); ++ else ++ mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent)); ++ ++ if (!mc_bus->irq_resources) ++ return -EINVAL; ++ ++ res_pool = &mc_bus->resource_pools[FSL_MC_POOL_IRQ]; ++ if (res_pool->free_count < irq_count) { ++ dev_err(&mc_dev->dev, ++ "Not able to allocate %u irqs for device\n", irq_count); ++ return -ENOSPC; ++ } ++ ++ irqs = devm_kzalloc(&mc_dev->dev, irq_count * sizeof(irqs[0]), ++ GFP_KERNEL); ++ if (!irqs) ++ return -ENOMEM; ++ ++ for (i = 0; i < irq_count; i++) { ++ struct fsl_mc_resource *resource; ++ ++ error = fsl_mc_resource_allocate(mc_bus, FSL_MC_POOL_IRQ, ++ &resource); ++ if (error < 0) ++ goto error_resource_alloc; ++ ++ irqs[i] = to_fsl_mc_irq(resource); ++ res_allocated_count++; ++ ++ irqs[i]->mc_dev = mc_dev; ++ irqs[i]->dev_irq_index = i; ++ } ++ ++ mc_dev->irqs = irqs; ++ return 0; ++ ++error_resource_alloc: ++ for (i = 0; i < res_allocated_count; i++) { ++ irqs[i]->mc_dev = NULL; ++ fsl_mc_resource_free(&irqs[i]->resource); ++ } ++ ++ return error; ++} ++EXPORT_SYMBOL_GPL(fsl_mc_allocate_irqs); ++ ++/* ++ * Frees the IRQs that were allocated for an fsl-mc device. ++ */ ++void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev) ++{ ++ int i; ++ int irq_count; ++ struct fsl_mc_bus *mc_bus; ++ struct fsl_mc_device_irq **irqs = mc_dev->irqs; ++ ++ if (!irqs) ++ return; ++ ++ irq_count = mc_dev->obj_desc.irq_count; ++ ++ if (is_fsl_mc_bus_dprc(mc_dev)) ++ mc_bus = to_fsl_mc_bus(mc_dev); ++ else ++ mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent)); ++ ++ if (!mc_bus->irq_resources) ++ return; ++ ++ for (i = 0; i < irq_count; i++) { ++ irqs[i]->mc_dev = NULL; ++ fsl_mc_resource_free(&irqs[i]->resource); ++ } ++ ++ mc_dev->irqs = NULL; ++} ++EXPORT_SYMBOL_GPL(fsl_mc_free_irqs); ++ ++void fsl_mc_init_all_resource_pools(struct fsl_mc_device *mc_bus_dev) ++{ ++ int pool_type; ++ struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); ++ ++ for (pool_type = 0; pool_type < FSL_MC_NUM_POOL_TYPES; pool_type++) { ++ struct fsl_mc_resource_pool *res_pool = ++ &mc_bus->resource_pools[pool_type]; ++ ++ res_pool->type = pool_type; ++ res_pool->max_count = 0; ++ res_pool->free_count = 0; ++ res_pool->mc_bus = mc_bus; ++ INIT_LIST_HEAD(&res_pool->free_list); ++ mutex_init(&res_pool->mutex); ++ } ++} ++EXPORT_SYMBOL_GPL(fsl_mc_init_all_resource_pools); ++ ++static void fsl_mc_cleanup_resource_pool(struct fsl_mc_device *mc_bus_dev, ++ enum fsl_mc_pool_type pool_type) ++{ ++ struct fsl_mc_resource *resource; ++ struct fsl_mc_resource *next; ++ struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); ++ struct fsl_mc_resource_pool *res_pool = ++ &mc_bus->resource_pools[pool_type]; ++ int free_count = 0; ++ ++ list_for_each_entry_safe(resource, next, &res_pool->free_list, node) { ++ free_count++; ++ devm_kfree(&mc_bus_dev->dev, resource); ++ } ++} ++ ++void fsl_mc_cleanup_all_resource_pools(struct fsl_mc_device *mc_bus_dev) ++{ ++ int pool_type; ++ ++ for (pool_type = 0; pool_type < FSL_MC_NUM_POOL_TYPES; pool_type++) ++ fsl_mc_cleanup_resource_pool(mc_bus_dev, pool_type); ++} ++EXPORT_SYMBOL_GPL(fsl_mc_cleanup_all_resource_pools); ++ ++/** ++ * fsl_mc_allocator_probe - callback invoked when an allocatable device is ++ * being added to the system ++ */ ++static int fsl_mc_allocator_probe(struct fsl_mc_device *mc_dev) ++{ ++ enum fsl_mc_pool_type pool_type; ++ struct fsl_mc_device *mc_bus_dev; ++ struct fsl_mc_bus *mc_bus; ++ int error; ++ ++ if (!fsl_mc_is_allocatable(mc_dev)) ++ return -EINVAL; ++ ++ mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); ++ if (!dev_is_fsl_mc(&mc_bus_dev->dev)) ++ return -EINVAL; ++ ++ mc_bus = to_fsl_mc_bus(mc_bus_dev); ++ error = object_type_to_pool_type(mc_dev->obj_desc.type, &pool_type); ++ if (error < 0) ++ return error; ++ ++ error = fsl_mc_resource_pool_add_device(mc_bus, pool_type, mc_dev); ++ if (error < 0) ++ return error; ++ ++ dev_dbg(&mc_dev->dev, ++ "Allocatable fsl-mc device bound to fsl_mc_allocator driver"); ++ return 0; ++} ++ ++/** ++ * fsl_mc_allocator_remove - callback invoked when an allocatable device is ++ * being removed from the system ++ */ ++static int fsl_mc_allocator_remove(struct fsl_mc_device *mc_dev) ++{ ++ int error; ++ ++ if (!fsl_mc_is_allocatable(mc_dev)) ++ return -EINVAL; ++ ++ if (mc_dev->resource) { ++ error = fsl_mc_resource_pool_remove_device(mc_dev); ++ if (error < 0) ++ return error; ++ } ++ ++ dev_dbg(&mc_dev->dev, ++ "Allocatable fsl-mc device unbound from fsl_mc_allocator driver"); ++ return 0; ++} ++ ++static const struct fsl_mc_device_id match_id_table[] = { ++ { ++ .vendor = FSL_MC_VENDOR_FREESCALE, ++ .obj_type = "dpbp", ++ }, ++ { ++ .vendor = FSL_MC_VENDOR_FREESCALE, ++ .obj_type = "dpmcp", ++ }, ++ { ++ .vendor = FSL_MC_VENDOR_FREESCALE, ++ .obj_type = "dpcon", ++ }, ++ {.vendor = 0x0}, ++}; ++ ++static struct fsl_mc_driver fsl_mc_allocator_driver = { ++ .driver = { ++ .name = "fsl_mc_allocator", ++ .pm = NULL, ++ }, ++ .match_id_table = match_id_table, ++ .probe = fsl_mc_allocator_probe, ++ .remove = fsl_mc_allocator_remove, ++}; ++ ++int __init fsl_mc_allocator_driver_init(void) ++{ ++ return fsl_mc_driver_register(&fsl_mc_allocator_driver); ++} ++ ++void fsl_mc_allocator_driver_exit(void) ++{ ++ fsl_mc_driver_unregister(&fsl_mc_allocator_driver); ++} +--- a/drivers/staging/fsl-mc/bus/fsl-mc-bus.c ++++ /dev/null +@@ -1,920 +0,0 @@ +-/* +- * Freescale Management Complex (MC) bus driver +- * +- * Copyright (C) 2014 Freescale Semiconductor, Inc. +- * Author: German Rivera <German.Rivera@freescale.com> +- * +- * 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 <linux/module.h> +-#include <linux/of_device.h> +-#include <linux/of_address.h> +-#include <linux/ioport.h> +-#include <linux/slab.h> +-#include <linux/limits.h> +-#include <linux/bitops.h> +-#include <linux/msi.h> +-#include <linux/dma-mapping.h> +-#include "../include/mc-bus.h" +-#include "../include/dpmng.h" +-#include "../include/mc-sys.h" +- +-#include "fsl-mc-private.h" +-#include "dprc-cmd.h" +- +-static struct kmem_cache *mc_dev_cache; +- +-/** +- * Default DMA mask for devices on a fsl-mc bus +- */ +-#define FSL_MC_DEFAULT_DMA_MASK (~0ULL) +- +-/** +- * struct fsl_mc - Private data of a "fsl,qoriq-mc" platform device +- * @root_mc_bus_dev: MC object device representing the root DPRC +- * @num_translation_ranges: number of entries in addr_translation_ranges +- * @translation_ranges: array of bus to system address translation ranges +- */ +-struct fsl_mc { +- struct fsl_mc_device *root_mc_bus_dev; +- u8 num_translation_ranges; +- struct fsl_mc_addr_translation_range *translation_ranges; +-}; +- +-/** +- * struct fsl_mc_addr_translation_range - bus to system address translation +- * range +- * @mc_region_type: Type of MC region for the range being translated +- * @start_mc_offset: Start MC offset of the range being translated +- * @end_mc_offset: MC offset of the first byte after the range (last MC +- * offset of the range is end_mc_offset - 1) +- * @start_phys_addr: system physical address corresponding to start_mc_addr +- */ +-struct fsl_mc_addr_translation_range { +- enum dprc_region_type mc_region_type; +- u64 start_mc_offset; +- u64 end_mc_offset; +- phys_addr_t start_phys_addr; +-}; +- +-/** +- * fsl_mc_bus_match - device to driver matching callback +- * @dev: the MC object device structure to match against +- * @drv: the device driver to search for matching MC object device id +- * structures +- * +- * Returns 1 on success, 0 otherwise. +- */ +-static int fsl_mc_bus_match(struct device *dev, struct device_driver *drv) +-{ +- const struct fsl_mc_device_id *id; +- struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); +- struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(drv); +- bool found = false; +- +- if (WARN_ON(!fsl_mc_bus_exists())) +- goto out; +- +- if (!mc_drv->match_id_table) +- goto out; +- +- /* +- * If the object is not 'plugged' don't match. +- * Only exception is the root DPRC, which is a special case. +- */ +- if ((mc_dev->obj_desc.state & DPRC_OBJ_STATE_PLUGGED) == 0 && +- !fsl_mc_is_root_dprc(&mc_dev->dev)) +- goto out; +- +- /* +- * Traverse the match_id table of the given driver, trying to find +- * a matching for the given MC object device. +- */ +- for (id = mc_drv->match_id_table; id->vendor != 0x0; id++) { +- if (id->vendor == mc_dev->obj_desc.vendor && +- strcmp(id->obj_type, mc_dev->obj_desc.type) == 0) { +- found = true; +- +- break; +- } +- } +- +-out: +- dev_dbg(dev, "%smatched\n", found ? "" : "not "); +- return found; +-} +- +-/** +- * fsl_mc_bus_uevent - callback invoked when a device is added +- */ +-static int fsl_mc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) +-{ +- struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); +- +- if (add_uevent_var(env, "MODALIAS=fsl-mc:v%08Xd%s", +- mc_dev->obj_desc.vendor, +- mc_dev->obj_desc.type)) +- return -ENOMEM; +- +- return 0; +-} +- +-static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, +- char *buf) +-{ +- struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); +- +- return sprintf(buf, "fsl-mc:v%08Xd%s\n", mc_dev->obj_desc.vendor, +- mc_dev->obj_desc.type); +-} +-static DEVICE_ATTR_RO(modalias); +- +-static struct attribute *fsl_mc_dev_attrs[] = { +- &dev_attr_modalias.attr, +- NULL, +-}; +- +-ATTRIBUTE_GROUPS(fsl_mc_dev); +- +-struct bus_type fsl_mc_bus_type = { +- .name = "fsl-mc", +- .match = fsl_mc_bus_match, +- .uevent = fsl_mc_bus_uevent, +- .dev_groups = fsl_mc_dev_groups, +-}; +-EXPORT_SYMBOL_GPL(fsl_mc_bus_type); +- +-static atomic_t root_dprc_count = ATOMIC_INIT(0); +- +-static int fsl_mc_driver_probe(struct device *dev) +-{ +- struct fsl_mc_driver *mc_drv; +- struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); +- int error; +- +- if (WARN_ON(!dev->driver)) +- return -EINVAL; +- +- mc_drv = to_fsl_mc_driver(dev->driver); +- if (WARN_ON(!mc_drv->probe)) +- return -EINVAL; +- +- error = mc_drv->probe(mc_dev); +- if (error < 0) { +- dev_err(dev, "MC object device probe callback failed: %d\n", +- error); +- return error; +- } +- +- return 0; +-} +- +-static int fsl_mc_driver_remove(struct device *dev) +-{ +- struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver); +- struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); +- int error; +- +- if (WARN_ON(!dev->driver)) +- return -EINVAL; +- +- error = mc_drv->remove(mc_dev); +- if (error < 0) { +- dev_err(dev, +- "MC object device remove callback failed: %d\n", +- error); +- return error; +- } +- +- return 0; +-} +- +-static void fsl_mc_driver_shutdown(struct device *dev) +-{ +- struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver); +- struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); +- +- mc_drv->shutdown(mc_dev); +-} +- +-/** +- * __fsl_mc_driver_register - registers a child device driver with the +- * MC bus +- * +- * This function is implicitly invoked from the registration function of +- * fsl_mc device drivers, which is generated by the +- * module_fsl_mc_driver() macro. +- */ +-int __fsl_mc_driver_register(struct fsl_mc_driver *mc_driver, +- struct module *owner) +-{ +- int error; +- +- mc_driver->driver.owner = owner; +- mc_driver->driver.bus = &fsl_mc_bus_type; +- +- if (mc_driver->probe) +- mc_driver->driver.probe = fsl_mc_driver_probe; +- +- if (mc_driver->remove) +- mc_driver->driver.remove = fsl_mc_driver_remove; +- +- if (mc_driver->shutdown) +- mc_driver->driver.shutdown = fsl_mc_driver_shutdown; +- +- error = driver_register(&mc_driver->driver); +- if (error < 0) { +- pr_err("driver_register() failed for %s: %d\n", +- mc_driver->driver.name, error); +- return error; +- } +- +- pr_info("MC object device driver %s registered\n", +- mc_driver->driver.name); +- return 0; +-} +-EXPORT_SYMBOL_GPL(__fsl_mc_driver_register); +- +-/** +- * fsl_mc_driver_unregister - unregisters a device driver from the +- * MC bus +- */ +-void fsl_mc_driver_unregister(struct fsl_mc_driver *mc_driver) +-{ +- driver_unregister(&mc_driver->driver); +-} +-EXPORT_SYMBOL_GPL(fsl_mc_driver_unregister); +- +-/** +- * fsl_mc_bus_exists - check if a root dprc exists +- */ +-bool fsl_mc_bus_exists(void) +-{ +- return atomic_read(&root_dprc_count) > 0; +-} +-EXPORT_SYMBOL_GPL(fsl_mc_bus_exists); +- +-/** +- * fsl_mc_get_root_dprc - function to traverse to the root dprc +- */ +-void fsl_mc_get_root_dprc(struct device *dev, +- struct device **root_dprc_dev) +-{ +- if (WARN_ON(!dev)) { +- *root_dprc_dev = NULL; +- } else if (WARN_ON(!dev_is_fsl_mc(dev))) { +- *root_dprc_dev = NULL; +- } else { +- *root_dprc_dev = dev; +- while (dev_is_fsl_mc((*root_dprc_dev)->parent)) +- *root_dprc_dev = (*root_dprc_dev)->parent; +- } +-} +-EXPORT_SYMBOL_GPL(fsl_mc_get_root_dprc); +- +-static int get_dprc_attr(struct fsl_mc_io *mc_io, +- int container_id, struct dprc_attributes *attr) +-{ +- u16 dprc_handle; +- int error; +- +- error = dprc_open(mc_io, 0, container_id, &dprc_handle); +- if (error < 0) { +- dev_err(mc_io->dev, "dprc_open() failed: %d\n", error); +- return error; +- } +- +- memset(attr, 0, sizeof(struct dprc_attributes)); +- error = dprc_get_attributes(mc_io, 0, dprc_handle, attr); +- if (error < 0) { +- dev_err(mc_io->dev, "dprc_get_attributes() failed: %d\n", +- error); +- goto common_cleanup; +- } +- +- error = 0; +- +-common_cleanup: +- (void)dprc_close(mc_io, 0, dprc_handle); +- return error; +-} +- +-static int get_dprc_icid(struct fsl_mc_io *mc_io, +- int container_id, u16 *icid) +-{ +- struct dprc_attributes attr; +- int error; +- +- error = get_dprc_attr(mc_io, container_id, &attr); +- if (error == 0) +- *icid = attr.icid; +- +- return error; +-} +- +-static int get_dprc_version(struct fsl_mc_io *mc_io, +- int container_id, u16 *major, u16 *minor) +-{ +- struct dprc_attributes attr; +- int error; +- +- error = get_dprc_attr(mc_io, container_id, &attr); +- if (error == 0) { +- *major = attr.version.major; +- *minor = attr.version.minor; +- } +- +- return error; +-} +- +-static int translate_mc_addr(struct fsl_mc_device *mc_dev, +- enum dprc_region_type mc_region_type, +- u64 mc_offset, phys_addr_t *phys_addr) +-{ +- int i; +- struct device *root_dprc_dev; +- struct fsl_mc *mc; +- +- fsl_mc_get_root_dprc(&mc_dev->dev, &root_dprc_dev); +- if (WARN_ON(!root_dprc_dev)) +- return -EINVAL; +- mc = dev_get_drvdata(root_dprc_dev->parent); +- +- if (mc->num_translation_ranges == 0) { +- /* +- * Do identity mapping: +- */ +- *phys_addr = mc_offset; +- return 0; +- } +- +- for (i = 0; i < mc->num_translation_ranges; i++) { +- struct fsl_mc_addr_translation_range *range = +- &mc->translation_ranges[i]; +- +- if (mc_region_type == range->mc_region_type && +- mc_offset >= range->start_mc_offset && +- mc_offset < range->end_mc_offset) { +- *phys_addr = range->start_phys_addr + +- (mc_offset - range->start_mc_offset); +- return 0; +- } +- } +- +- return -EFAULT; +-} +- +-static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev, +- struct fsl_mc_device *mc_bus_dev) +-{ +- int i; +- int error; +- struct resource *regions; +- struct dprc_obj_desc *obj_desc = &mc_dev->obj_desc; +- struct device *parent_dev = mc_dev->dev.parent; +- enum dprc_region_type mc_region_type; +- +- if (strcmp(obj_desc->type, "dprc") == 0 || +- strcmp(obj_desc->type, "dpmcp") == 0) { +- mc_region_type = DPRC_REGION_TYPE_MC_PORTAL; +- } else if (strcmp(obj_desc->type, "dpio") == 0) { +- mc_region_type = DPRC_REGION_TYPE_QBMAN_PORTAL; +- } else { +- /* +- * This function should not have been called for this MC object +- * type, as this object type is not supposed to have MMIO +- * regions +- */ +- WARN_ON(true); +- return -EINVAL; +- } +- +- regions = kmalloc_array(obj_desc->region_count, +- sizeof(regions[0]), GFP_KERNEL); +- if (!regions) +- return -ENOMEM; +- +- for (i = 0; i < obj_desc->region_count; i++) { +- struct dprc_region_desc region_desc; +- +- error = dprc_get_obj_region(mc_bus_dev->mc_io, +- 0, +- mc_bus_dev->mc_handle, +- obj_desc->type, +- obj_desc->id, i, ®ion_desc); +- if (error < 0) { +- dev_err(parent_dev, +- "dprc_get_obj_region() failed: %d\n", error); +- goto error_cleanup_regions; +- } +- +- WARN_ON(region_desc.size == 0); +- error = translate_mc_addr(mc_dev, mc_region_type, +- region_desc.base_offset, +- ®ions[i].start); +- if (error < 0) { +- dev_err(parent_dev, +- "Invalid MC offset: %#x (for %s.%d\'s region %d)\n", +- region_desc.base_offset, +- obj_desc->type, obj_desc->id, i); +- goto error_cleanup_regions; +- } +- +- regions[i].end = regions[i].start + region_desc.size - 1; +- regions[i].name = "fsl-mc object MMIO region"; +- regions[i].flags = IORESOURCE_IO; +- if (region_desc.flags & DPRC_REGION_CACHEABLE) +- regions[i].flags |= IORESOURCE_CACHEABLE; +- } +- +- mc_dev->regions = regions; +- return 0; +- +-error_cleanup_regions: +- kfree(regions); +- return error; +-} +- +-/** +- * fsl_mc_is_root_dprc - function to check if a given device is a root dprc +- */ +-bool fsl_mc_is_root_dprc(struct device *dev) +-{ +- struct device *root_dprc_dev; +- +- fsl_mc_get_root_dprc(dev, &root_dprc_dev); +- if (!root_dprc_dev) +- return false; +- return dev == root_dprc_dev; +-} +- +-/** +- * Add a newly discovered MC object device to be visible in Linux +- */ +-int fsl_mc_device_add(struct dprc_obj_desc *obj_desc, +- struct fsl_mc_io *mc_io, +- struct device *parent_dev, +- struct fsl_mc_device **new_mc_dev) +-{ +- int error; +- struct fsl_mc_device *mc_dev = NULL; +- struct fsl_mc_bus *mc_bus = NULL; +- struct fsl_mc_device *parent_mc_dev; +- +- if (dev_is_fsl_mc(parent_dev)) +- parent_mc_dev = to_fsl_mc_device(parent_dev); +- else +- parent_mc_dev = NULL; +- +- if (strcmp(obj_desc->type, "dprc") == 0) { +- /* +- * Allocate an MC bus device object: +- */ +- mc_bus = devm_kzalloc(parent_dev, sizeof(*mc_bus), GFP_KERNEL); +- if (!mc_bus) +- return -ENOMEM; +- +- mc_dev = &mc_bus->mc_dev; +- } else { +- /* +- * Allocate a regular fsl_mc_device object: +- */ +- mc_dev = kmem_cache_zalloc(mc_dev_cache, GFP_KERNEL); +- if (!mc_dev) +- return -ENOMEM; +- } +- +- mc_dev->obj_desc = *obj_desc; +- mc_dev->mc_io = mc_io; +- device_initialize(&mc_dev->dev); +- mc_dev->dev.parent = parent_dev; +- mc_dev->dev.bus = &fsl_mc_bus_type; +- dev_set_name(&mc_dev->dev, "%s.%d", obj_desc->type, obj_desc->id); +- +- if (strcmp(obj_desc->type, "dprc") == 0) { +- struct fsl_mc_io *mc_io2; +- +- mc_dev->flags |= FSL_MC_IS_DPRC; +- +- /* +- * To get the DPRC's ICID, we need to open the DPRC +- * in get_dprc_icid(). For child DPRCs, we do so using the +- * parent DPRC's MC portal instead of the child DPRC's MC +- * portal, in case the child DPRC is already opened with +- * its own portal (e.g., the DPRC used by AIOP). +- * +- * NOTE: There cannot be more than one active open for a +- * given MC object, using the same MC portal. +- */ +- if (parent_mc_dev) { +- /* +- * device being added is a child DPRC device +- */ +- mc_io2 = parent_mc_dev->mc_io; +- } else { +- /* +- * device being added is the root DPRC device +- */ +- if (WARN_ON(!mc_io)) { +- error = -EINVAL; +- goto error_cleanup_dev; +- } +- +- mc_io2 = mc_io; +- +- atomic_inc(&root_dprc_count); +- } +- +- error = get_dprc_icid(mc_io2, obj_desc->id, &mc_dev->icid); +- if (error < 0) +- goto error_cleanup_dev; +- } else { +- /* +- * A non-DPRC MC object device has to be a child of another +- * MC object (specifically a DPRC object) +- */ +- mc_dev->icid = parent_mc_dev->icid; +- mc_dev->dma_mask = FSL_MC_DEFAULT_DMA_MASK; +- mc_dev->dev.dma_mask = &mc_dev->dma_mask; +- dev_set_msi_domain(&mc_dev->dev, +- dev_get_msi_domain(&parent_mc_dev->dev)); +- } +- +- /* +- * Get MMIO regions for the device from the MC: +- * +- * NOTE: the root DPRC is a special case as its MMIO region is +- * obtained from the device tree +- */ +- if (parent_mc_dev && obj_desc->region_count != 0) { +- error = fsl_mc_device_get_mmio_regions(mc_dev, +- parent_mc_dev); +- if (error < 0) +- goto error_cleanup_dev; +- } +- +- /* Objects are coherent, unless 'no shareability' flag set. */ +- if (!(obj_desc->flags & DPRC_OBJ_FLAG_NO_MEM_SHAREABILITY)) +- arch_setup_dma_ops(&mc_dev->dev, 0, 0, NULL, true); +- +- /* +- * The device-specific probe callback will get invoked by device_add() +- */ +- error = device_add(&mc_dev->dev); +- if (error < 0) { +- dev_err(parent_dev, +- "device_add() failed for device %s: %d\n", +- dev_name(&mc_dev->dev), error); +- goto error_cleanup_dev; +- } +- +- (void)get_device(&mc_dev->dev); +- dev_dbg(parent_dev, "Added MC object device %s\n", +- dev_name(&mc_dev->dev)); +- +- *new_mc_dev = mc_dev; +- return 0; +- +-error_cleanup_dev: +- kfree(mc_dev->regions); +- if (mc_bus) +- devm_kfree(parent_dev, mc_bus); +- else +- kmem_cache_free(mc_dev_cache, mc_dev); +- +- return error; +-} +-EXPORT_SYMBOL_GPL(fsl_mc_device_add); +- +-/** +- * fsl_mc_device_remove - Remove a MC object device from being visible to +- * Linux +- * +- * @mc_dev: Pointer to a MC object device object +- */ +-void fsl_mc_device_remove(struct fsl_mc_device *mc_dev) +-{ +- struct fsl_mc_bus *mc_bus = NULL; +- +- kfree(mc_dev->regions); +- +- /* +- * The device-specific remove callback will get invoked by device_del() +- */ +- device_del(&mc_dev->dev); +- put_device(&mc_dev->dev); +- +- if (strcmp(mc_dev->obj_desc.type, "dprc") == 0) { +- mc_bus = to_fsl_mc_bus(mc_dev); +- +- if (fsl_mc_is_root_dprc(&mc_dev->dev)) { +- if (atomic_read(&root_dprc_count) > 0) +- atomic_dec(&root_dprc_count); +- else +- WARN_ON(1); +- } +- } +- +- if (mc_bus) +- devm_kfree(mc_dev->dev.parent, mc_bus); +- else +- kmem_cache_free(mc_dev_cache, mc_dev); +-} +-EXPORT_SYMBOL_GPL(fsl_mc_device_remove); +- +-static int parse_mc_ranges(struct device *dev, +- int *paddr_cells, +- int *mc_addr_cells, +- int *mc_size_cells, +- const __be32 **ranges_start, +- u8 *num_ranges) +-{ +- const __be32 *prop; +- int range_tuple_cell_count; +- int ranges_len; +- int tuple_len; +- struct device_node *mc_node = dev->of_node; +- +- *ranges_start = of_get_property(mc_node, "ranges", &ranges_len); +- if (!(*ranges_start) || !ranges_len) { +- dev_warn(dev, +- "missing or empty ranges property for device tree node '%s'\n", +- mc_node->name); +- +- *num_ranges = 0; +- return 0; +- } +- +- *paddr_cells = of_n_addr_cells(mc_node); +- +- prop = of_get_property(mc_node, "#address-cells", NULL); +- if (prop) +- *mc_addr_cells = be32_to_cpup(prop); +- else +- *mc_addr_cells = *paddr_cells; +- +- prop = of_get_property(mc_node, "#size-cells", NULL); +- if (prop) +- *mc_size_cells = be32_to_cpup(prop); +- else +- *mc_size_cells = of_n_size_cells(mc_node); +- +- range_tuple_cell_count = *paddr_cells + *mc_addr_cells + +- *mc_size_cells; +- +- tuple_len = range_tuple_cell_count * sizeof(__be32); +- if (ranges_len % tuple_len != 0) { +- dev_err(dev, "malformed ranges property '%s'\n", mc_node->name); +- return -EINVAL; +- } +- +- *num_ranges = ranges_len / tuple_len; +- return 0; +-} +- +-static int get_mc_addr_translation_ranges(struct device *dev, +- struct fsl_mc_addr_translation_range +- **ranges, +- u8 *num_ranges) +-{ +- int error; +- int paddr_cells; +- int mc_addr_cells; +- int mc_size_cells; +- int i; +- const __be32 *ranges_start; +- const __be32 *cell; +- +- error = parse_mc_ranges(dev, +- &paddr_cells, +- &mc_addr_cells, +- &mc_size_cells, +- &ranges_start, +- num_ranges); +- if (error < 0) +- return error; +- +- if (!(*num_ranges)) { +- /* +- * Missing or empty ranges property ("ranges;") for the +- * 'fsl,qoriq-mc' node. In this case, identity mapping +- * will be used. +- */ +- *ranges = NULL; +- return 0; +- } +- +- *ranges = devm_kcalloc(dev, *num_ranges, +- sizeof(struct fsl_mc_addr_translation_range), +- GFP_KERNEL); +- if (!(*ranges)) +- return -ENOMEM; +- +- cell = ranges_start; +- for (i = 0; i < *num_ranges; ++i) { +- struct fsl_mc_addr_translation_range *range = &(*ranges)[i]; +- +- range->mc_region_type = of_read_number(cell, 1); +- range->start_mc_offset = of_read_number(cell + 1, +- mc_addr_cells - 1); +- cell += mc_addr_cells; +- range->start_phys_addr = of_read_number(cell, paddr_cells); +- cell += paddr_cells; +- range->end_mc_offset = range->start_mc_offset + +- of_read_number(cell, mc_size_cells); +- +- cell += mc_size_cells; +- } +- +- return 0; +-} +- +-/** +- * fsl_mc_bus_probe - callback invoked when the root MC bus is being +- * added +- */ +-static int fsl_mc_bus_probe(struct platform_device *pdev) +-{ +- struct dprc_obj_desc obj_desc; +- int error; +- struct fsl_mc *mc; +- struct fsl_mc_device *mc_bus_dev = NULL; +- struct fsl_mc_io *mc_io = NULL; +- int container_id; +- phys_addr_t mc_portal_phys_addr; +- u32 mc_portal_size; +- struct mc_version mc_version; +- struct resource res; +- +- dev_info(&pdev->dev, "Root MC bus device probed"); +- +- mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL); +- if (!mc) +- return -ENOMEM; +- +- platform_set_drvdata(pdev, mc); +- +- /* +- * Get physical address of MC portal for the root DPRC: +- */ +- error = of_address_to_resource(pdev->dev.of_node, 0, &res); +- if (error < 0) { +- dev_err(&pdev->dev, +- "of_address_to_resource() failed for %s\n", +- pdev->dev.of_node->full_name); +- return error; +- } +- +- mc_portal_phys_addr = res.start; +- mc_portal_size = resource_size(&res); +- error = fsl_create_mc_io(&pdev->dev, mc_portal_phys_addr, +- mc_portal_size, NULL, +- FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, &mc_io); +- if (error < 0) +- return error; +- +- error = mc_get_version(mc_io, 0, &mc_version); +- if (error != 0) { +- dev_err(&pdev->dev, +- "mc_get_version() failed with error %d\n", error); +- goto error_cleanup_mc_io; +- } +- +- dev_info(&pdev->dev, +- "Freescale Management Complex Firmware version: %u.%u.%u\n", +- mc_version.major, mc_version.minor, mc_version.revision); +- +- error = get_mc_addr_translation_ranges(&pdev->dev, +- &mc->translation_ranges, +- &mc->num_translation_ranges); +- if (error < 0) +- goto error_cleanup_mc_io; +- +- error = dpmng_get_container_id(mc_io, 0, &container_id); +- if (error < 0) { +- dev_err(&pdev->dev, +- "dpmng_get_container_id() failed: %d\n", error); +- goto error_cleanup_mc_io; +- } +- +- memset(&obj_desc, 0, sizeof(struct dprc_obj_desc)); +- error = get_dprc_version(mc_io, container_id, +- &obj_desc.ver_major, &obj_desc.ver_minor); +- if (error < 0) +- goto error_cleanup_mc_io; +- +- obj_desc.vendor = FSL_MC_VENDOR_FREESCALE; +- strcpy(obj_desc.type, "dprc"); +- obj_desc.id = container_id; +- obj_desc.irq_count = 1; +- obj_desc.region_count = 0; +- +- error = fsl_mc_device_add(&obj_desc, mc_io, &pdev->dev, &mc_bus_dev); +- if (error < 0) +- goto error_cleanup_mc_io; +- +- mc->root_mc_bus_dev = mc_bus_dev; +- return 0; +- +-error_cleanup_mc_io: +- fsl_destroy_mc_io(mc_io); +- return error; +-} +- +-/** +- * fsl_mc_bus_remove - callback invoked when the root MC bus is being +- * removed +- */ +-static int fsl_mc_bus_remove(struct platform_device *pdev) +-{ +- struct fsl_mc *mc = platform_get_drvdata(pdev); +- +- if (WARN_ON(!fsl_mc_is_root_dprc(&mc->root_mc_bus_dev->dev))) +- return -EINVAL; +- +- fsl_mc_device_remove(mc->root_mc_bus_dev); +- +- fsl_destroy_mc_io(mc->root_mc_bus_dev->mc_io); +- mc->root_mc_bus_dev->mc_io = NULL; +- +- dev_info(&pdev->dev, "Root MC bus device removed"); +- return 0; +-} +- +-static const struct of_device_id fsl_mc_bus_match_table[] = { +- {.compatible = "fsl,qoriq-mc",}, +- {}, +-}; +- +-MODULE_DEVICE_TABLE(of, fsl_mc_bus_match_table); +- +-static struct platform_driver fsl_mc_bus_driver = { +- .driver = { +- .name = "fsl_mc_bus", +- .pm = NULL, +- .of_match_table = fsl_mc_bus_match_table, +- }, +- .probe = fsl_mc_bus_probe, +- .remove = fsl_mc_bus_remove, +-}; +- +-static int __init fsl_mc_bus_driver_init(void) +-{ +- int error; +- +- mc_dev_cache = kmem_cache_create("fsl_mc_device", +- sizeof(struct fsl_mc_device), 0, 0, +- NULL); +- if (!mc_dev_cache) { +- pr_err("Could not create fsl_mc_device cache\n"); +- return -ENOMEM; +- } +- +- error = bus_register(&fsl_mc_bus_type); +- if (error < 0) { +- pr_err("fsl-mc bus type registration failed: %d\n", error); +- goto error_cleanup_cache; +- } +- +- pr_info("fsl-mc bus type registered\n"); +- +- error = platform_driver_register(&fsl_mc_bus_driver); +- if (error < 0) { +- pr_err("platform_driver_register() failed: %d\n", error); +- goto error_cleanup_bus; +- } +- +- error = dprc_driver_init(); +- if (error < 0) +- goto error_cleanup_driver; +- +- error = fsl_mc_allocator_driver_init(); +- if (error < 0) +- goto error_cleanup_dprc_driver; +- +- error = its_fsl_mc_msi_init(); +- if (error < 0) +- goto error_cleanup_mc_allocator; +- +- return 0; +- +-error_cleanup_mc_allocator: +- fsl_mc_allocator_driver_exit(); +- +-error_cleanup_dprc_driver: +- dprc_driver_exit(); +- +-error_cleanup_driver: +- platform_driver_unregister(&fsl_mc_bus_driver); +- +-error_cleanup_bus: +- bus_unregister(&fsl_mc_bus_type); +- +-error_cleanup_cache: +- kmem_cache_destroy(mc_dev_cache); +- return error; +-} +-postcore_initcall(fsl_mc_bus_driver_init); +--- /dev/null ++++ b/drivers/bus/fsl-mc/fsl-mc-bus.c +@@ -0,0 +1,1151 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Freescale Management Complex (MC) bus driver ++ * ++ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. ++ * Author: German Rivera <German.Rivera@freescale.com> ++ * ++ */ ++ ++#define pr_fmt(fmt) "fsl-mc: " fmt ++ ++#include <linux/module.h> ++#include <linux/of_device.h> ++#include <linux/of_address.h> ++#include <linux/ioport.h> ++#include <linux/slab.h> ++#include <linux/limits.h> ++#include <linux/bitops.h> ++#include <linux/msi.h> ++#include <linux/dma-mapping.h> ++#include <linux/fsl/mc.h> ++ ++#include "fsl-mc-private.h" ++ ++/** ++ * Default DMA mask for devices on a fsl-mc bus ++ */ ++#define FSL_MC_DEFAULT_DMA_MASK (~0ULL) ++ ++/** ++ * struct fsl_mc - Private data of a "fsl,qoriq-mc" platform device ++ * @root_mc_bus_dev: fsl-mc device representing the root DPRC ++ * @num_translation_ranges: number of entries in addr_translation_ranges ++ * @translation_ranges: array of bus to system address translation ranges ++ */ ++struct fsl_mc { ++ struct fsl_mc_device *root_mc_bus_dev; ++ u8 num_translation_ranges; ++ struct fsl_mc_addr_translation_range *translation_ranges; ++}; ++ ++/** ++ * struct fsl_mc_addr_translation_range - bus to system address translation ++ * range ++ * @mc_region_type: Type of MC region for the range being translated ++ * @start_mc_offset: Start MC offset of the range being translated ++ * @end_mc_offset: MC offset of the first byte after the range (last MC ++ * offset of the range is end_mc_offset - 1) ++ * @start_phys_addr: system physical address corresponding to start_mc_addr ++ */ ++struct fsl_mc_addr_translation_range { ++ enum dprc_region_type mc_region_type; ++ u64 start_mc_offset; ++ u64 end_mc_offset; ++ phys_addr_t start_phys_addr; ++}; ++ ++/** ++ * struct mc_version ++ * @major: Major version number: incremented on API compatibility changes ++ * @minor: Minor version number: incremented on API additions (that are ++ * backward compatible); reset when major version is incremented ++ * @revision: Internal revision number: incremented on implementation changes ++ * and/or bug fixes that have no impact on API ++ */ ++struct mc_version { ++ u32 major; ++ u32 minor; ++ u32 revision; ++}; ++ ++/** ++ * fsl_mc_bus_match - device to driver matching callback ++ * @dev: the fsl-mc device to match against ++ * @drv: the device driver to search for matching fsl-mc object type ++ * structures ++ * ++ * Returns 1 on success, 0 otherwise. ++ */ ++static int fsl_mc_bus_match(struct device *dev, struct device_driver *drv) ++{ ++ const struct fsl_mc_device_id *id; ++ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); ++ struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(drv); ++ bool found = false; ++ ++ /* When driver_override is set, only bind to the matching driver */ ++ if (mc_dev->driver_override) { ++ found = !strcmp(mc_dev->driver_override, mc_drv->driver.name); ++ goto out; ++ } ++ ++ if (!mc_drv->match_id_table) ++ goto out; ++ ++ /* ++ * If the object is not 'plugged' don't match. ++ * Only exception is the root DPRC, which is a special case. ++ */ ++ if ((mc_dev->obj_desc.state & FSL_MC_OBJ_STATE_PLUGGED) == 0 && ++ !fsl_mc_is_root_dprc(&mc_dev->dev)) ++ goto out; ++ ++ /* ++ * Traverse the match_id table of the given driver, trying to find ++ * a matching for the given device. ++ */ ++ for (id = mc_drv->match_id_table; id->vendor != 0x0; id++) { ++ if (id->vendor == mc_dev->obj_desc.vendor && ++ strcmp(id->obj_type, mc_dev->obj_desc.type) == 0) { ++ found = true; ++ ++ break; ++ } ++ } ++ ++out: ++ dev_dbg(dev, "%smatched\n", found ? "" : "not "); ++ return found; ++} ++ ++/** ++ * fsl_mc_bus_uevent - callback invoked when a device is added ++ */ ++static int fsl_mc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) ++{ ++ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); ++ ++ if (add_uevent_var(env, "MODALIAS=fsl-mc:v%08Xd%s", ++ mc_dev->obj_desc.vendor, ++ mc_dev->obj_desc.type)) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); ++ ++ return sprintf(buf, "fsl-mc:v%08Xd%s\n", mc_dev->obj_desc.vendor, ++ mc_dev->obj_desc.type); ++} ++static DEVICE_ATTR_RO(modalias); ++ ++static ssize_t rescan_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct fsl_mc_device *root_mc_dev; ++ struct fsl_mc_bus *root_mc_bus; ++ unsigned long val; ++ ++ if (!fsl_mc_is_root_dprc(dev)) ++ return -EINVAL; ++ ++ root_mc_dev = to_fsl_mc_device(dev); ++ root_mc_bus = to_fsl_mc_bus(root_mc_dev); ++ ++ if (kstrtoul(buf, 0, &val) < 0) ++ return -EINVAL; ++ ++ if (val) { ++ mutex_lock(&root_mc_bus->scan_mutex); ++ dprc_scan_objects(root_mc_dev, NULL, NULL); ++ mutex_unlock(&root_mc_bus->scan_mutex); ++ } ++ ++ return count; ++} ++static DEVICE_ATTR_WO(rescan); ++ ++static ssize_t driver_override_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); ++ const char *driver_override, *old = mc_dev->driver_override; ++ char *cp; ++ ++ if (WARN_ON(dev->bus != &fsl_mc_bus_type)) ++ return -EINVAL; ++ ++ if (count >= (PAGE_SIZE - 1)) ++ return -EINVAL; ++ ++ driver_override = kstrndup(buf, count, GFP_KERNEL); ++ if (!driver_override) ++ return -ENOMEM; ++ ++ cp = strchr(driver_override, '\n'); ++ if (cp) ++ *cp = '\0'; ++ ++ if (strlen(driver_override)) { ++ mc_dev->driver_override = driver_override; ++ } else { ++ kfree(driver_override); ++ mc_dev->driver_override = NULL; ++ } ++ ++ kfree(old); ++ ++ return count; ++} ++ ++static ssize_t driver_override_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); ++ ++ return snprintf(buf, PAGE_SIZE, "%s\n", mc_dev->driver_override); ++} ++static DEVICE_ATTR_RW(driver_override); ++ ++static struct attribute *fsl_mc_dev_attrs[] = { ++ &dev_attr_modalias.attr, ++ &dev_attr_rescan.attr, ++ &dev_attr_driver_override.attr, ++ NULL, ++}; ++ ++ATTRIBUTE_GROUPS(fsl_mc_dev); ++ ++static int scan_fsl_mc_bus(struct device *dev, void *data) ++{ ++ struct fsl_mc_device *root_mc_dev; ++ struct fsl_mc_bus *root_mc_bus; ++ ++ if (!fsl_mc_is_root_dprc(dev)) ++ goto exit; ++ ++ root_mc_dev = to_fsl_mc_device(dev); ++ root_mc_bus = to_fsl_mc_bus(root_mc_dev); ++ mutex_lock(&root_mc_bus->scan_mutex); ++ dprc_scan_objects(root_mc_dev, NULL, NULL); ++ mutex_unlock(&root_mc_bus->scan_mutex); ++ ++exit: ++ return 0; ++} ++ ++static ssize_t bus_rescan_store(struct bus_type *bus, ++ const char *buf, size_t count) ++{ ++ unsigned long val; ++ ++ if (kstrtoul(buf, 0, &val) < 0) ++ return -EINVAL; ++ ++ if (val) ++ bus_for_each_dev(bus, NULL, NULL, scan_fsl_mc_bus); ++ ++ return count; ++} ++static BUS_ATTR(rescan, 0220, NULL, bus_rescan_store); ++ ++static struct attribute *fsl_mc_bus_attrs[] = { ++ &bus_attr_rescan.attr, ++ NULL, ++}; ++ ++static const struct attribute_group fsl_mc_bus_group = { ++ .attrs = fsl_mc_bus_attrs, ++}; ++ ++static const struct attribute_group *fsl_mc_bus_groups[] = { ++ &fsl_mc_bus_group, ++ NULL, ++}; ++ ++struct bus_type fsl_mc_bus_type = { ++ .name = "fsl-mc", ++ .match = fsl_mc_bus_match, ++ .uevent = fsl_mc_bus_uevent, ++ .dev_groups = fsl_mc_dev_groups, ++ .bus_groups = fsl_mc_bus_groups, ++}; ++EXPORT_SYMBOL_GPL(fsl_mc_bus_type); ++ ++struct device_type fsl_mc_bus_dprc_type = { ++ .name = "fsl_mc_bus_dprc" ++}; ++ ++struct device_type fsl_mc_bus_dpni_type = { ++ .name = "fsl_mc_bus_dpni" ++}; ++ ++struct device_type fsl_mc_bus_dpio_type = { ++ .name = "fsl_mc_bus_dpio" ++}; ++ ++struct device_type fsl_mc_bus_dpsw_type = { ++ .name = "fsl_mc_bus_dpsw" ++}; ++ ++struct device_type fsl_mc_bus_dpdmux_type = { ++ .name = "fsl_mc_bus_dpdmux" ++}; ++ ++struct device_type fsl_mc_bus_dpbp_type = { ++ .name = "fsl_mc_bus_dpbp" ++}; ++ ++struct device_type fsl_mc_bus_dpcon_type = { ++ .name = "fsl_mc_bus_dpcon" ++}; ++ ++struct device_type fsl_mc_bus_dpmcp_type = { ++ .name = "fsl_mc_bus_dpmcp" ++}; ++ ++struct device_type fsl_mc_bus_dpmac_type = { ++ .name = "fsl_mc_bus_dpmac" ++}; ++ ++struct device_type fsl_mc_bus_dprtc_type = { ++ .name = "fsl_mc_bus_dprtc" ++}; ++ ++struct device_type fsl_mc_bus_dpseci_type = { ++ .name = "fsl_mc_bus_dpseci" ++}; ++ ++struct device_type fsl_mc_bus_dpdcei_type = { ++ .name = "fsl_mc_bus_dpdcei" ++}; ++ ++struct device_type fsl_mc_bus_dpaiop_type = { ++ .name = "fsl_mc_bus_dpaiop" ++}; ++ ++struct device_type fsl_mc_bus_dpci_type = { ++ .name = "fsl_mc_bus_dpci" ++}; ++ ++struct device_type fsl_mc_bus_dpdmai_type = { ++ .name = "fsl_mc_bus_dpdmai" ++}; ++ ++static struct device_type *fsl_mc_get_device_type(const char *type) ++{ ++ static const struct { ++ struct device_type *dev_type; ++ const char *type; ++ } dev_types[] = { ++ { &fsl_mc_bus_dprc_type, "dprc" }, ++ { &fsl_mc_bus_dpni_type, "dpni" }, ++ { &fsl_mc_bus_dpio_type, "dpio" }, ++ { &fsl_mc_bus_dpsw_type, "dpsw" }, ++ { &fsl_mc_bus_dpdmux_type, "dpdmux" }, ++ { &fsl_mc_bus_dpbp_type, "dpbp" }, ++ { &fsl_mc_bus_dpcon_type, "dpcon" }, ++ { &fsl_mc_bus_dpmcp_type, "dpmcp" }, ++ { &fsl_mc_bus_dpmac_type, "dpmac" }, ++ { &fsl_mc_bus_dprtc_type, "dprtc" }, ++ { &fsl_mc_bus_dpseci_type, "dpseci" }, ++ { &fsl_mc_bus_dpdcei_type, "dpdcei" }, ++ { &fsl_mc_bus_dpaiop_type, "dpaiop" }, ++ { &fsl_mc_bus_dpci_type, "dpci" }, ++ { &fsl_mc_bus_dpdmai_type, "dpdmai" }, ++ { NULL, NULL } ++ }; ++ int i; ++ ++ for (i = 0; dev_types[i].dev_type; i++) ++ if (!strcmp(dev_types[i].type, type)) ++ return dev_types[i].dev_type; ++ ++ return NULL; ++} ++ ++static int fsl_mc_driver_probe(struct device *dev) ++{ ++ struct fsl_mc_driver *mc_drv; ++ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); ++ int error; ++ ++ mc_drv = to_fsl_mc_driver(dev->driver); ++ ++ error = mc_drv->probe(mc_dev); ++ if (error < 0) { ++ if (error != -EPROBE_DEFER) ++ dev_err(dev, "%s failed: %d\n", __func__, error); ++ return error; ++ } ++ ++ return 0; ++} ++ ++static int fsl_mc_driver_remove(struct device *dev) ++{ ++ struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver); ++ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); ++ int error; ++ ++ error = mc_drv->remove(mc_dev); ++ if (error < 0) { ++ dev_err(dev, "%s failed: %d\n", __func__, error); ++ return error; ++ } ++ ++ return 0; ++} ++ ++static void fsl_mc_driver_shutdown(struct device *dev) ++{ ++ struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver); ++ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); ++ ++ mc_drv->shutdown(mc_dev); ++} ++ ++/** ++ * __fsl_mc_driver_register - registers a child device driver with the ++ * MC bus ++ * ++ * This function is implicitly invoked from the registration function of ++ * fsl_mc device drivers, which is generated by the ++ * module_fsl_mc_driver() macro. ++ */ ++int __fsl_mc_driver_register(struct fsl_mc_driver *mc_driver, ++ struct module *owner) ++{ ++ int error; ++ ++ mc_driver->driver.owner = owner; ++ mc_driver->driver.bus = &fsl_mc_bus_type; ++ ++ if (mc_driver->probe) ++ mc_driver->driver.probe = fsl_mc_driver_probe; ++ ++ if (mc_driver->remove) ++ mc_driver->driver.remove = fsl_mc_driver_remove; ++ ++ if (mc_driver->shutdown) ++ mc_driver->driver.shutdown = fsl_mc_driver_shutdown; ++ ++ error = driver_register(&mc_driver->driver); ++ if (error < 0) { ++ pr_err("driver_register() failed for %s: %d\n", ++ mc_driver->driver.name, error); ++ return error; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(__fsl_mc_driver_register); ++ ++/** ++ * fsl_mc_driver_unregister - unregisters a device driver from the ++ * MC bus ++ */ ++void fsl_mc_driver_unregister(struct fsl_mc_driver *mc_driver) ++{ ++ driver_unregister(&mc_driver->driver); ++} ++EXPORT_SYMBOL_GPL(fsl_mc_driver_unregister); ++ ++/** ++ * mc_get_version() - Retrieves the Management Complex firmware ++ * version information ++ * @mc_io: Pointer to opaque I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @mc_ver_info: Returned version information structure ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++static int mc_get_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ struct mc_version *mc_ver_info) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ struct dpmng_rsp_get_version *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMNG_CMDID_GET_VERSION, ++ cmd_flags, ++ 0); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpmng_rsp_get_version *)cmd.params; ++ mc_ver_info->revision = le32_to_cpu(rsp_params->revision); ++ mc_ver_info->major = le32_to_cpu(rsp_params->version_major); ++ mc_ver_info->minor = le32_to_cpu(rsp_params->version_minor); ++ ++ return 0; ++} ++ ++/** ++ * fsl_mc_get_root_dprc - function to traverse to the root dprc ++ */ ++void fsl_mc_get_root_dprc(struct device *dev, ++ struct device **root_dprc_dev) ++{ ++ if (!dev) { ++ *root_dprc_dev = NULL; ++ } else if (!dev_is_fsl_mc(dev)) { ++ *root_dprc_dev = NULL; ++ } else { ++ *root_dprc_dev = dev; ++ while (dev_is_fsl_mc((*root_dprc_dev)->parent)) ++ *root_dprc_dev = (*root_dprc_dev)->parent; ++ } ++} ++EXPORT_SYMBOL_GPL(fsl_mc_get_root_dprc); ++ ++static int get_dprc_attr(struct fsl_mc_io *mc_io, ++ int container_id, struct dprc_attributes *attr) ++{ ++ u16 dprc_handle; ++ int error; ++ ++ error = dprc_open(mc_io, 0, container_id, &dprc_handle); ++ if (error < 0) { ++ dev_err(mc_io->dev, "dprc_open() failed: %d\n", error); ++ return error; ++ } ++ ++ memset(attr, 0, sizeof(struct dprc_attributes)); ++ error = dprc_get_attributes(mc_io, 0, dprc_handle, attr); ++ if (error < 0) { ++ dev_err(mc_io->dev, "dprc_get_attributes() failed: %d\n", ++ error); ++ goto common_cleanup; ++ } ++ ++ error = 0; ++ ++common_cleanup: ++ (void)dprc_close(mc_io, 0, dprc_handle); ++ return error; ++} ++ ++static int get_dprc_icid(struct fsl_mc_io *mc_io, ++ int container_id, u32 *icid) ++{ ++ struct dprc_attributes attr; ++ int error; ++ ++ error = get_dprc_attr(mc_io, container_id, &attr); ++ if (error == 0) ++ *icid = attr.icid; ++ ++ return error; ++} ++ ++static int translate_mc_addr(struct fsl_mc_device *mc_dev, ++ enum dprc_region_type mc_region_type, ++ u64 mc_offset, phys_addr_t *phys_addr) ++{ ++ int i; ++ struct device *root_dprc_dev; ++ struct fsl_mc *mc; ++ ++ fsl_mc_get_root_dprc(&mc_dev->dev, &root_dprc_dev); ++ mc = dev_get_drvdata(root_dprc_dev->parent); ++ ++ if (mc->num_translation_ranges == 0) { ++ /* ++ * Do identity mapping: ++ */ ++ *phys_addr = mc_offset; ++ return 0; ++ } ++ ++ for (i = 0; i < mc->num_translation_ranges; i++) { ++ struct fsl_mc_addr_translation_range *range = ++ &mc->translation_ranges[i]; ++ ++ if (mc_region_type == range->mc_region_type && ++ mc_offset >= range->start_mc_offset && ++ mc_offset < range->end_mc_offset) { ++ *phys_addr = range->start_phys_addr + ++ (mc_offset - range->start_mc_offset); ++ return 0; ++ } ++ } ++ ++ return -EFAULT; ++} ++ ++static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev, ++ struct fsl_mc_device *mc_bus_dev) ++{ ++ int i; ++ int error; ++ struct resource *regions; ++ struct fsl_mc_obj_desc *obj_desc = &mc_dev->obj_desc; ++ struct device *parent_dev = mc_dev->dev.parent; ++ enum dprc_region_type mc_region_type; ++ ++ if (is_fsl_mc_bus_dprc(mc_dev) || ++ is_fsl_mc_bus_dpmcp(mc_dev)) { ++ mc_region_type = DPRC_REGION_TYPE_MC_PORTAL; ++ } else if (is_fsl_mc_bus_dpio(mc_dev)) { ++ mc_region_type = DPRC_REGION_TYPE_QBMAN_PORTAL; ++ } else { ++ /* ++ * This function should not have been called for this MC object ++ * type, as this object type is not supposed to have MMIO ++ * regions ++ */ ++ return -EINVAL; ++ } ++ ++ regions = kmalloc_array(obj_desc->region_count, ++ sizeof(regions[0]), GFP_KERNEL); ++ if (!regions) ++ return -ENOMEM; ++ ++ for (i = 0; i < obj_desc->region_count; i++) { ++ struct dprc_region_desc region_desc; ++ ++ error = dprc_get_obj_region(mc_bus_dev->mc_io, ++ 0, ++ mc_bus_dev->mc_handle, ++ obj_desc->type, ++ obj_desc->id, i, ®ion_desc); ++ if (error < 0) { ++ dev_err(parent_dev, ++ "dprc_get_obj_region() failed: %d\n", error); ++ goto error_cleanup_regions; ++ } ++ ++ error = translate_mc_addr(mc_dev, mc_region_type, ++ region_desc.base_offset, ++ ®ions[i].start); ++ if (error < 0) { ++ dev_err(parent_dev, ++ "Invalid MC offset: %#x (for %s.%d\'s region %d)\n", ++ region_desc.base_offset, ++ obj_desc->type, obj_desc->id, i); ++ goto error_cleanup_regions; ++ } ++ ++ regions[i].end = regions[i].start + region_desc.size - 1; ++ regions[i].name = "fsl-mc object MMIO region"; ++ regions[i].flags = IORESOURCE_IO; ++ if (region_desc.flags & DPRC_REGION_CACHEABLE) ++ regions[i].flags |= IORESOURCE_CACHEABLE; ++ } ++ ++ mc_dev->regions = regions; ++ return 0; ++ ++error_cleanup_regions: ++ kfree(regions); ++ return error; ++} ++ ++/** ++ * fsl_mc_is_root_dprc - function to check if a given device is a root dprc ++ */ ++bool fsl_mc_is_root_dprc(struct device *dev) ++{ ++ struct device *root_dprc_dev; ++ ++ fsl_mc_get_root_dprc(dev, &root_dprc_dev); ++ if (!root_dprc_dev) ++ return false; ++ return dev == root_dprc_dev; ++} ++ ++static void fsl_mc_device_release(struct device *dev) ++{ ++ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); ++ ++ kfree(mc_dev->regions); ++ ++ if (is_fsl_mc_bus_dprc(mc_dev)) ++ kfree(to_fsl_mc_bus(mc_dev)); ++ else ++ kfree(mc_dev); ++} ++ ++/** ++ * Add a newly discovered fsl-mc device to be visible in Linux ++ */ ++int fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc, ++ struct fsl_mc_io *mc_io, ++ struct device *parent_dev, ++ const char *driver_override, ++ struct fsl_mc_device **new_mc_dev) ++{ ++ int error; ++ struct fsl_mc_device *mc_dev = NULL; ++ struct fsl_mc_bus *mc_bus = NULL; ++ struct fsl_mc_device *parent_mc_dev; ++ struct device *fsl_mc_platform_dev; ++ struct device_node *fsl_mc_platform_node; ++ ++ if (dev_is_fsl_mc(parent_dev)) ++ parent_mc_dev = to_fsl_mc_device(parent_dev); ++ else ++ parent_mc_dev = NULL; ++ ++ if (strcmp(obj_desc->type, "dprc") == 0) { ++ /* ++ * Allocate an MC bus device object: ++ */ ++ mc_bus = kzalloc(sizeof(*mc_bus), GFP_KERNEL); ++ if (!mc_bus) ++ return -ENOMEM; ++ ++ mc_dev = &mc_bus->mc_dev; ++ } else { ++ /* ++ * Allocate a regular fsl_mc_device object: ++ */ ++ mc_dev = kzalloc(sizeof(*mc_dev), GFP_KERNEL); ++ if (!mc_dev) ++ return -ENOMEM; ++ } ++ ++ mc_dev->obj_desc = *obj_desc; ++ mc_dev->mc_io = mc_io; ++ ++ if (driver_override) { ++ /* ++ * We trust driver_override, so we don't need to use ++ * kstrndup() here ++ */ ++ mc_dev->driver_override = kstrdup(driver_override, GFP_KERNEL); ++ if (!mc_dev->driver_override) { ++ error = -ENOMEM; ++ goto error_cleanup_dev; ++ } ++ } ++ ++ device_initialize(&mc_dev->dev); ++ mc_dev->dev.parent = parent_dev; ++ mc_dev->dev.bus = &fsl_mc_bus_type; ++ mc_dev->dev.release = fsl_mc_device_release; ++ mc_dev->dev.type = fsl_mc_get_device_type(obj_desc->type); ++ if (!mc_dev->dev.type) { ++ error = -ENODEV; ++ dev_err(parent_dev, "unknown device type %s\n", obj_desc->type); ++ goto error_cleanup_dev; ++ } ++ dev_set_name(&mc_dev->dev, "%s.%d", obj_desc->type, obj_desc->id); ++ ++ if (strcmp(obj_desc->type, "dprc") == 0) { ++ struct fsl_mc_io *mc_io2; ++ ++ mc_dev->flags |= FSL_MC_IS_DPRC; ++ ++ /* ++ * To get the DPRC's ICID, we need to open the DPRC ++ * in get_dprc_icid(). For child DPRCs, we do so using the ++ * parent DPRC's MC portal instead of the child DPRC's MC ++ * portal, in case the child DPRC is already opened with ++ * its own portal (e.g., the DPRC used by AIOP). ++ * ++ * NOTE: There cannot be more than one active open for a ++ * given MC object, using the same MC portal. ++ */ ++ if (parent_mc_dev) { ++ /* ++ * device being added is a child DPRC device ++ */ ++ mc_io2 = parent_mc_dev->mc_io; ++ } else { ++ /* ++ * device being added is the root DPRC device ++ */ ++ if (!mc_io) { ++ error = -EINVAL; ++ goto error_cleanup_dev; ++ } ++ ++ mc_io2 = mc_io; ++ } ++ ++ error = get_dprc_icid(mc_io2, obj_desc->id, &mc_dev->icid); ++ if (error < 0) ++ goto error_cleanup_dev; ++ } else { ++ /* ++ * A non-DPRC object has to be a child of a DPRC, use the ++ * parent's ICID and interrupt domain. ++ */ ++ mc_dev->icid = parent_mc_dev->icid; ++ mc_dev->dma_mask = FSL_MC_DEFAULT_DMA_MASK; ++ mc_dev->dev.dma_mask = &mc_dev->dma_mask; ++ mc_dev->dev.coherent_dma_mask = mc_dev->dma_mask; ++ dev_set_msi_domain(&mc_dev->dev, ++ dev_get_msi_domain(&parent_mc_dev->dev)); ++ } ++ ++ /* ++ * Get MMIO regions for the device from the MC: ++ * ++ * NOTE: the root DPRC is a special case as its MMIO region is ++ * obtained from the device tree ++ */ ++ if (parent_mc_dev && obj_desc->region_count != 0) { ++ error = fsl_mc_device_get_mmio_regions(mc_dev, ++ parent_mc_dev); ++ if (error < 0) ++ goto error_cleanup_dev; ++ } ++ ++ fsl_mc_platform_dev = &mc_dev->dev; ++ while (dev_is_fsl_mc(fsl_mc_platform_dev)) ++ fsl_mc_platform_dev = fsl_mc_platform_dev->parent; ++ fsl_mc_platform_node = fsl_mc_platform_dev->of_node; ++ ++ /* Set up the iommu configuration for the devices. */ ++ fsl_mc_dma_configure(mc_dev, fsl_mc_platform_node, ++ !(obj_desc->flags & DPRC_OBJ_FLAG_NO_MEM_SHAREABILITY)); ++ ++ /* ++ * The device-specific probe callback will get invoked by device_add() ++ */ ++ error = device_add(&mc_dev->dev); ++ if (error < 0) { ++ dev_err(parent_dev, ++ "device_add() failed for device %s: %d\n", ++ dev_name(&mc_dev->dev), error); ++ goto error_cleanup_dev; ++ } ++ ++ dev_dbg(parent_dev, "added %s\n", dev_name(&mc_dev->dev)); ++ ++ *new_mc_dev = mc_dev; ++ return 0; ++ ++error_cleanup_dev: ++ kfree(mc_dev->regions); ++ kfree(mc_bus); ++ kfree(mc_dev); ++ ++ return error; ++} ++EXPORT_SYMBOL_GPL(fsl_mc_device_add); ++ ++/** ++ * fsl_mc_device_remove - Remove an fsl-mc device from being visible to ++ * Linux ++ * ++ * @mc_dev: Pointer to an fsl-mc device ++ */ ++void fsl_mc_device_remove(struct fsl_mc_device *mc_dev) ++{ ++ kfree(mc_dev->driver_override); ++ mc_dev->driver_override = NULL; ++ ++ /* ++ * The device-specific remove callback will get invoked by device_del() ++ */ ++ device_del(&mc_dev->dev); ++ put_device(&mc_dev->dev); ++} ++EXPORT_SYMBOL_GPL(fsl_mc_device_remove); ++ ++static int parse_mc_ranges(struct device *dev, ++ int *paddr_cells, ++ int *mc_addr_cells, ++ int *mc_size_cells, ++ const __be32 **ranges_start) ++{ ++ const __be32 *prop; ++ int range_tuple_cell_count; ++ int ranges_len; ++ int tuple_len; ++ struct device_node *mc_node = dev->of_node; ++ ++ *ranges_start = of_get_property(mc_node, "ranges", &ranges_len); ++ if (!(*ranges_start) || !ranges_len) { ++ dev_warn(dev, ++ "missing or empty ranges property for device tree node '%s'\n", ++ mc_node->name); ++ return 0; ++ } ++ ++ *paddr_cells = of_n_addr_cells(mc_node); ++ ++ prop = of_get_property(mc_node, "#address-cells", NULL); ++ if (prop) ++ *mc_addr_cells = be32_to_cpup(prop); ++ else ++ *mc_addr_cells = *paddr_cells; ++ ++ prop = of_get_property(mc_node, "#size-cells", NULL); ++ if (prop) ++ *mc_size_cells = be32_to_cpup(prop); ++ else ++ *mc_size_cells = of_n_size_cells(mc_node); ++ ++ range_tuple_cell_count = *paddr_cells + *mc_addr_cells + ++ *mc_size_cells; ++ ++ tuple_len = range_tuple_cell_count * sizeof(__be32); ++ if (ranges_len % tuple_len != 0) { ++ dev_err(dev, "malformed ranges property '%s'\n", mc_node->name); ++ return -EINVAL; ++ } ++ ++ return ranges_len / tuple_len; ++} ++ ++static int get_mc_addr_translation_ranges(struct device *dev, ++ struct fsl_mc_addr_translation_range ++ **ranges, ++ u8 *num_ranges) ++{ ++ int ret; ++ int paddr_cells; ++ int mc_addr_cells; ++ int mc_size_cells; ++ int i; ++ const __be32 *ranges_start; ++ const __be32 *cell; ++ ++ ret = parse_mc_ranges(dev, ++ &paddr_cells, ++ &mc_addr_cells, ++ &mc_size_cells, ++ &ranges_start); ++ if (ret < 0) ++ return ret; ++ ++ *num_ranges = ret; ++ if (!ret) { ++ /* ++ * Missing or empty ranges property ("ranges;") for the ++ * 'fsl,qoriq-mc' node. In this case, identity mapping ++ * will be used. ++ */ ++ *ranges = NULL; ++ return 0; ++ } ++ ++ *ranges = devm_kcalloc(dev, *num_ranges, ++ sizeof(struct fsl_mc_addr_translation_range), ++ GFP_KERNEL); ++ if (!(*ranges)) ++ return -ENOMEM; ++ ++ cell = ranges_start; ++ for (i = 0; i < *num_ranges; ++i) { ++ struct fsl_mc_addr_translation_range *range = &(*ranges)[i]; ++ ++ range->mc_region_type = of_read_number(cell, 1); ++ range->start_mc_offset = of_read_number(cell + 1, ++ mc_addr_cells - 1); ++ cell += mc_addr_cells; ++ range->start_phys_addr = of_read_number(cell, paddr_cells); ++ cell += paddr_cells; ++ range->end_mc_offset = range->start_mc_offset + ++ of_read_number(cell, mc_size_cells); ++ ++ cell += mc_size_cells; ++ } ++ ++ return 0; ++} ++ ++/** ++ * fsl_mc_bus_probe - callback invoked when the root MC bus is being ++ * added ++ */ ++static int fsl_mc_bus_probe(struct platform_device *pdev) ++{ ++ struct fsl_mc_obj_desc obj_desc; ++ int error; ++ struct fsl_mc *mc; ++ struct fsl_mc_device *mc_bus_dev = NULL; ++ struct fsl_mc_io *mc_io = NULL; ++ struct fsl_mc_bus *mc_bus = NULL; ++ int container_id; ++ phys_addr_t mc_portal_phys_addr; ++ u32 mc_portal_size; ++ struct mc_version mc_version; ++ struct resource res; ++ ++ mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL); ++ if (!mc) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, mc); ++ ++ /* ++ * Get physical address of MC portal for the root DPRC: ++ */ ++ error = of_address_to_resource(pdev->dev.of_node, 0, &res); ++ if (error < 0) { ++ dev_err(&pdev->dev, ++ "of_address_to_resource() failed for %pOF\n", ++ pdev->dev.of_node); ++ return error; ++ } ++ ++ mc_portal_phys_addr = res.start; ++ mc_portal_size = resource_size(&res); ++ error = fsl_create_mc_io(&pdev->dev, mc_portal_phys_addr, ++ mc_portal_size, NULL, ++ FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, &mc_io); ++ if (error < 0) ++ return error; ++ ++ error = mc_get_version(mc_io, 0, &mc_version); ++ if (error != 0) { ++ dev_err(&pdev->dev, ++ "mc_get_version() failed with error %d\n", error); ++ goto error_cleanup_mc_io; ++ } ++ ++ dev_info(&pdev->dev, "MC firmware version: %u.%u.%u\n", ++ mc_version.major, mc_version.minor, mc_version.revision); ++ ++ error = get_mc_addr_translation_ranges(&pdev->dev, ++ &mc->translation_ranges, ++ &mc->num_translation_ranges); ++ if (error < 0) ++ goto error_cleanup_mc_io; ++ ++ error = dprc_get_container_id(mc_io, 0, &container_id); ++ if (error < 0) { ++ dev_err(&pdev->dev, ++ "dprc_get_container_id() failed: %d\n", error); ++ goto error_cleanup_mc_io; ++ } ++ ++ memset(&obj_desc, 0, sizeof(struct fsl_mc_obj_desc)); ++ error = dprc_get_api_version(mc_io, 0, ++ &obj_desc.ver_major, ++ &obj_desc.ver_minor); ++ if (error < 0) ++ goto error_cleanup_mc_io; ++ ++ obj_desc.vendor = FSL_MC_VENDOR_FREESCALE; ++ strcpy(obj_desc.type, "dprc"); ++ obj_desc.id = container_id; ++ obj_desc.irq_count = 1; ++ obj_desc.region_count = 0; ++ ++ error = fsl_mc_device_add(&obj_desc, mc_io, &pdev->dev, NULL, ++ &mc_bus_dev); ++ if (error < 0) ++ goto error_cleanup_mc_io; ++ ++ mc_bus = to_fsl_mc_bus(mc_bus_dev); ++ error = fsl_mc_restool_create_device_file(mc_bus); ++ if (error < 0) ++ goto error_cleanup_device; ++ ++ mc->root_mc_bus_dev = mc_bus_dev; ++ ++ return 0; ++ ++error_cleanup_device: ++ fsl_mc_device_remove(mc_bus_dev); ++ ++error_cleanup_mc_io: ++ fsl_destroy_mc_io(mc_io); ++ return error; ++} ++ ++/** ++ * fsl_mc_bus_remove - callback invoked when the root MC bus is being ++ * removed ++ */ ++static int fsl_mc_bus_remove(struct platform_device *pdev) ++{ ++ struct fsl_mc *mc = platform_get_drvdata(pdev); ++ struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc->root_mc_bus_dev); ++ ++ if (!fsl_mc_is_root_dprc(&mc->root_mc_bus_dev->dev)) ++ return -EINVAL; ++ ++ fsl_mc_restool_remove_device_file(mc_bus); ++ fsl_mc_device_remove(mc->root_mc_bus_dev); ++ ++ fsl_destroy_mc_io(mc->root_mc_bus_dev->mc_io); ++ mc->root_mc_bus_dev->mc_io = NULL; ++ ++ return 0; ++} ++ ++static const struct of_device_id fsl_mc_bus_match_table[] = { ++ {.compatible = "fsl,qoriq-mc",}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, fsl_mc_bus_match_table); ++ ++static struct platform_driver fsl_mc_bus_driver = { ++ .driver = { ++ .name = "fsl_mc_bus", ++ .pm = NULL, ++ .of_match_table = fsl_mc_bus_match_table, ++ }, ++ .probe = fsl_mc_bus_probe, ++ .remove = fsl_mc_bus_remove, ++}; ++ ++static int __init fsl_mc_bus_driver_init(void) ++{ ++ int error; ++ ++ error = bus_register(&fsl_mc_bus_type); ++ if (error < 0) { ++ pr_err("bus type registration failed: %d\n", error); ++ goto error_cleanup_cache; ++ } ++ ++ error = platform_driver_register(&fsl_mc_bus_driver); ++ if (error < 0) { ++ pr_err("platform_driver_register() failed: %d\n", error); ++ goto error_cleanup_bus; ++ } ++ ++ error = dprc_driver_init(); ++ if (error < 0) ++ goto error_cleanup_driver; ++ ++ error = fsl_mc_allocator_driver_init(); ++ if (error < 0) ++ goto error_cleanup_dprc_driver; ++ ++ error = fsl_mc_restool_init(); ++ if (error < 0) ++ goto error_cleanup_mc_allocator; ++ ++ return 0; ++ ++error_cleanup_mc_allocator: ++ fsl_mc_allocator_driver_exit(); ++ ++error_cleanup_dprc_driver: ++ dprc_driver_exit(); ++ ++error_cleanup_driver: ++ platform_driver_unregister(&fsl_mc_bus_driver); ++ ++error_cleanup_bus: ++ bus_unregister(&fsl_mc_bus_type); ++ ++error_cleanup_cache: ++ return error; ++} ++postcore_initcall(fsl_mc_bus_driver_init); +--- /dev/null ++++ b/drivers/bus/fsl-mc/fsl-mc-iommu.c +@@ -0,0 +1,78 @@ ++/* ++ * Copyright 2016 Freescale Semiconductor, Inc. ++ * Copyright 2017 NXP ++ * Author: Nipun Gupta <nipun.gupta@nxp.com> ++ * ++ * 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 <linux/iommu.h> ++#include <linux/of.h> ++#include <linux/of_iommu.h> ++#include <linux/fsl/mc.h> ++ ++/* Setup the IOMMU for the DPRC container */ ++static const struct iommu_ops ++*fsl_mc_iommu_configure(struct fsl_mc_device *mc_dev, ++ struct device_node *fsl_mc_platform_node) ++{ ++ struct of_phandle_args iommu_spec; ++ const struct iommu_ops *ops; ++ u32 iommu_phandle; ++ struct device_node *iommu_node; ++ const __be32 *map = NULL; ++ int iommu_cells, map_len, ret; ++ ++ map = of_get_property(fsl_mc_platform_node, "iommu-map", &map_len); ++ if (!map) ++ return NULL; ++ ++ ops = mc_dev->dev.bus->iommu_ops; ++ if (!ops || !ops->of_xlate) ++ return NULL; ++ ++ iommu_phandle = be32_to_cpup(map + 1); ++ iommu_node = of_find_node_by_phandle(iommu_phandle); ++ ++ if (of_property_read_u32(iommu_node, "#iommu-cells", &iommu_cells)) { ++ pr_err("%s: missing #iommu-cells property\n", iommu_node->name); ++ return NULL; ++ } ++ ++ /* Initialize the fwspec */ ++ ret = iommu_fwspec_init(&mc_dev->dev, &iommu_node->fwnode, ops); ++ if (ret) ++ return NULL; ++ ++ /* ++ * Fill in the required stream-id before calling the iommu's ++ * ops->xlate callback. ++ */ ++ iommu_spec.np = iommu_node; ++ iommu_spec.args[0] = mc_dev->icid; ++ iommu_spec.args_count = 1; ++ ++ ret = ops->of_xlate(&mc_dev->dev, &iommu_spec); ++ if (ret) ++ return NULL; ++ ++ of_node_put(iommu_spec.np); ++ ++ return ops; ++} ++ ++/* Set up DMA configuration for fsl-mc devices */ ++void fsl_mc_dma_configure(struct fsl_mc_device *mc_dev, ++ struct device_node *fsl_mc_platform_node, int coherent) ++{ ++ const struct iommu_ops *ops; ++ ++ ops = fsl_mc_iommu_configure(mc_dev, fsl_mc_platform_node); ++ ++ mc_dev->dev.coherent_dma_mask = DMA_BIT_MASK(48); ++ mc_dev->dev.dma_mask = &mc_dev->dev.coherent_dma_mask; ++ arch_setup_dma_ops(&mc_dev->dev, 0, ++ mc_dev->dev.coherent_dma_mask + 1, ops, coherent); ++} +--- a/drivers/staging/fsl-mc/bus/fsl-mc-msi.c ++++ /dev/null +@@ -1,285 +0,0 @@ +-/* +- * Freescale Management Complex (MC) bus driver MSI support +- * +- * Copyright (C) 2015 Freescale Semiconductor, Inc. +- * Author: German Rivera <German.Rivera@freescale.com> +- * +- * 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 <linux/of_device.h> +-#include <linux/of_address.h> +-#include <linux/irqchip/arm-gic-v3.h> +-#include <linux/of_irq.h> +-#include <linux/irq.h> +-#include <linux/irqdomain.h> +-#include <linux/msi.h> +-#include "../include/mc-bus.h" +-#include "fsl-mc-private.h" +- +-/* +- * Generate a unique ID identifying the interrupt (only used within the MSI +- * irqdomain. Combine the icid with the interrupt index. +- */ +-static irq_hw_number_t fsl_mc_domain_calc_hwirq(struct fsl_mc_device *dev, +- struct msi_desc *desc) +-{ +- /* +- * Make the base hwirq value for ICID*10000 so it is readable +- * as a decimal value in /proc/interrupts. +- */ +- return (irq_hw_number_t)(desc->fsl_mc.msi_index + (dev->icid * 10000)); +-} +- +-static void fsl_mc_msi_set_desc(msi_alloc_info_t *arg, +- struct msi_desc *desc) +-{ +- arg->desc = desc; +- arg->hwirq = fsl_mc_domain_calc_hwirq(to_fsl_mc_device(desc->dev), +- desc); +-} +- +-static void fsl_mc_msi_update_dom_ops(struct msi_domain_info *info) +-{ +- struct msi_domain_ops *ops = info->ops; +- +- if (WARN_ON(!ops)) +- return; +- +- /* +- * set_desc should not be set by the caller +- */ +- if (!ops->set_desc) +- ops->set_desc = fsl_mc_msi_set_desc; +-} +- +-static void __fsl_mc_msi_write_msg(struct fsl_mc_device *mc_bus_dev, +- struct fsl_mc_device_irq *mc_dev_irq) +-{ +- int error; +- struct fsl_mc_device *owner_mc_dev = mc_dev_irq->mc_dev; +- struct msi_desc *msi_desc = mc_dev_irq->msi_desc; +- struct dprc_irq_cfg irq_cfg; +- +- /* +- * msi_desc->msg.address is 0x0 when this function is invoked in +- * the free_irq() code path. In this case, for the MC, we don't +- * really need to "unprogram" the MSI, so we just return. +- */ +- if (msi_desc->msg.address_lo == 0x0 && msi_desc->msg.address_hi == 0x0) +- return; +- +- if (WARN_ON(!owner_mc_dev)) +- return; +- +- irq_cfg.paddr = ((u64)msi_desc->msg.address_hi << 32) | +- msi_desc->msg.address_lo; +- irq_cfg.val = msi_desc->msg.data; +- irq_cfg.irq_num = msi_desc->irq; +- +- if (owner_mc_dev == mc_bus_dev) { +- /* +- * IRQ is for the mc_bus_dev's DPRC itself +- */ +- error = dprc_set_irq(mc_bus_dev->mc_io, +- MC_CMD_FLAG_INTR_DIS | MC_CMD_FLAG_PRI, +- mc_bus_dev->mc_handle, +- mc_dev_irq->dev_irq_index, +- &irq_cfg); +- if (error < 0) { +- dev_err(&owner_mc_dev->dev, +- "dprc_set_irq() failed: %d\n", error); +- } +- } else { +- /* +- * IRQ is for for a child device of mc_bus_dev +- */ +- error = dprc_set_obj_irq(mc_bus_dev->mc_io, +- MC_CMD_FLAG_INTR_DIS | MC_CMD_FLAG_PRI, +- mc_bus_dev->mc_handle, +- owner_mc_dev->obj_desc.type, +- owner_mc_dev->obj_desc.id, +- mc_dev_irq->dev_irq_index, +- &irq_cfg); +- if (error < 0) { +- dev_err(&owner_mc_dev->dev, +- "dprc_obj_set_irq() failed: %d\n", error); +- } +- } +-} +- +-/* +- * NOTE: This function is invoked with interrupts disabled +- */ +-static void fsl_mc_msi_write_msg(struct irq_data *irq_data, +- struct msi_msg *msg) +-{ +- struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data); +- struct fsl_mc_device *mc_bus_dev = to_fsl_mc_device(msi_desc->dev); +- struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); +- struct fsl_mc_device_irq *mc_dev_irq = +- &mc_bus->irq_resources[msi_desc->fsl_mc.msi_index]; +- +- WARN_ON(mc_dev_irq->msi_desc != msi_desc); +- msi_desc->msg = *msg; +- +- /* +- * Program the MSI (paddr, value) pair in the device: +- */ +- __fsl_mc_msi_write_msg(mc_bus_dev, mc_dev_irq); +-} +- +-static void fsl_mc_msi_update_chip_ops(struct msi_domain_info *info) +-{ +- struct irq_chip *chip = info->chip; +- +- if (WARN_ON((!chip))) +- return; +- +- /* +- * irq_write_msi_msg should not be set by the caller +- */ +- if (!chip->irq_write_msi_msg) +- chip->irq_write_msi_msg = fsl_mc_msi_write_msg; +-} +- +-/** +- * fsl_mc_msi_create_irq_domain - Create a fsl-mc MSI interrupt domain +- * @np: Optional device-tree node of the interrupt controller +- * @info: MSI domain info +- * @parent: Parent irq domain +- * +- * Updates the domain and chip ops and creates a fsl-mc MSI +- * interrupt domain. +- * +- * Returns: +- * A domain pointer or NULL in case of failure. +- */ +-struct irq_domain *fsl_mc_msi_create_irq_domain(struct fwnode_handle *fwnode, +- struct msi_domain_info *info, +- struct irq_domain *parent) +-{ +- struct irq_domain *domain; +- +- if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS) +- fsl_mc_msi_update_dom_ops(info); +- if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS) +- fsl_mc_msi_update_chip_ops(info); +- +- domain = msi_create_irq_domain(fwnode, info, parent); +- if (domain) +- domain->bus_token = DOMAIN_BUS_FSL_MC_MSI; +- +- return domain; +-} +- +-int fsl_mc_find_msi_domain(struct device *mc_platform_dev, +- struct irq_domain **mc_msi_domain) +-{ +- struct irq_domain *msi_domain; +- struct device_node *mc_of_node = mc_platform_dev->of_node; +- +- msi_domain = of_msi_get_domain(mc_platform_dev, mc_of_node, +- DOMAIN_BUS_FSL_MC_MSI); +- if (!msi_domain) { +- pr_err("Unable to find fsl-mc MSI domain for %s\n", +- mc_of_node->full_name); +- +- return -ENOENT; +- } +- +- *mc_msi_domain = msi_domain; +- return 0; +-} +- +-static void fsl_mc_msi_free_descs(struct device *dev) +-{ +- struct msi_desc *desc, *tmp; +- +- list_for_each_entry_safe(desc, tmp, dev_to_msi_list(dev), list) { +- list_del(&desc->list); +- free_msi_entry(desc); +- } +-} +- +-static int fsl_mc_msi_alloc_descs(struct device *dev, unsigned int irq_count) +- +-{ +- unsigned int i; +- int error; +- struct msi_desc *msi_desc; +- +- for (i = 0; i < irq_count; i++) { +- msi_desc = alloc_msi_entry(dev, 1, NULL); +- if (!msi_desc) { +- dev_err(dev, "Failed to allocate msi entry\n"); +- error = -ENOMEM; +- goto cleanup_msi_descs; +- } +- +- msi_desc->fsl_mc.msi_index = i; +- INIT_LIST_HEAD(&msi_desc->list); +- list_add_tail(&msi_desc->list, dev_to_msi_list(dev)); +- } +- +- return 0; +- +-cleanup_msi_descs: +- fsl_mc_msi_free_descs(dev); +- return error; +-} +- +-int fsl_mc_msi_domain_alloc_irqs(struct device *dev, +- unsigned int irq_count) +-{ +- struct irq_domain *msi_domain; +- int error; +- +- if (WARN_ON(!list_empty(dev_to_msi_list(dev)))) +- return -EINVAL; +- +- error = fsl_mc_msi_alloc_descs(dev, irq_count); +- if (error < 0) +- return error; +- +- msi_domain = dev_get_msi_domain(dev); +- if (WARN_ON(!msi_domain)) { +- error = -EINVAL; +- goto cleanup_msi_descs; +- } +- +- /* +- * NOTE: Calling this function will trigger the invocation of the +- * its_fsl_mc_msi_prepare() callback +- */ +- error = msi_domain_alloc_irqs(msi_domain, dev, irq_count); +- +- if (error) { +- dev_err(dev, "Failed to allocate IRQs\n"); +- goto cleanup_msi_descs; +- } +- +- return 0; +- +-cleanup_msi_descs: +- fsl_mc_msi_free_descs(dev); +- return error; +-} +- +-void fsl_mc_msi_domain_free_irqs(struct device *dev) +-{ +- struct irq_domain *msi_domain; +- +- msi_domain = dev_get_msi_domain(dev); +- if (WARN_ON(!msi_domain)) +- return; +- +- msi_domain_free_irqs(msi_domain, dev); +- +- if (WARN_ON(list_empty(dev_to_msi_list(dev)))) +- return; +- +- fsl_mc_msi_free_descs(dev); +-} +--- /dev/null ++++ b/drivers/bus/fsl-mc/fsl-mc-msi.c +@@ -0,0 +1,285 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Freescale Management Complex (MC) bus driver MSI support ++ * ++ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. ++ * Author: German Rivera <German.Rivera@freescale.com> ++ * ++ */ ++ ++#include <linux/of_device.h> ++#include <linux/of_address.h> ++#include <linux/of_irq.h> ++#include <linux/irq.h> ++#include <linux/irqdomain.h> ++#include <linux/msi.h> ++ ++#include "fsl-mc-private.h" ++ ++#ifdef GENERIC_MSI_DOMAIN_OPS ++/* ++ * Generate a unique ID identifying the interrupt (only used within the MSI ++ * irqdomain. Combine the icid with the interrupt index. ++ */ ++static irq_hw_number_t fsl_mc_domain_calc_hwirq(struct fsl_mc_device *dev, ++ struct msi_desc *desc) ++{ ++ /* ++ * Make the base hwirq value for ICID*10000 so it is readable ++ * as a decimal value in /proc/interrupts. ++ */ ++ return (irq_hw_number_t)(desc->fsl_mc.msi_index + (dev->icid * 10000)); ++} ++ ++static void fsl_mc_msi_set_desc(msi_alloc_info_t *arg, ++ struct msi_desc *desc) ++{ ++ arg->desc = desc; ++ arg->hwirq = fsl_mc_domain_calc_hwirq(to_fsl_mc_device(desc->dev), ++ desc); ++} ++#else ++#define fsl_mc_msi_set_desc NULL ++#endif ++ ++static void fsl_mc_msi_update_dom_ops(struct msi_domain_info *info) ++{ ++ struct msi_domain_ops *ops = info->ops; ++ ++ if (!ops) ++ return; ++ ++ /* ++ * set_desc should not be set by the caller ++ */ ++ if (!ops->set_desc) ++ ops->set_desc = fsl_mc_msi_set_desc; ++} ++ ++static void __fsl_mc_msi_write_msg(struct fsl_mc_device *mc_bus_dev, ++ struct fsl_mc_device_irq *mc_dev_irq) ++{ ++ int error; ++ struct fsl_mc_device *owner_mc_dev = mc_dev_irq->mc_dev; ++ struct msi_desc *msi_desc = mc_dev_irq->msi_desc; ++ struct dprc_irq_cfg irq_cfg; ++ ++ /* ++ * msi_desc->msg.address is 0x0 when this function is invoked in ++ * the free_irq() code path. In this case, for the MC, we don't ++ * really need to "unprogram" the MSI, so we just return. ++ */ ++ if (msi_desc->msg.address_lo == 0x0 && msi_desc->msg.address_hi == 0x0) ++ return; ++ ++ if (!owner_mc_dev) ++ return; ++ ++ irq_cfg.paddr = ((u64)msi_desc->msg.address_hi << 32) | ++ msi_desc->msg.address_lo; ++ irq_cfg.val = msi_desc->msg.data; ++ irq_cfg.irq_num = msi_desc->irq; ++ ++ if (owner_mc_dev == mc_bus_dev) { ++ /* ++ * IRQ is for the mc_bus_dev's DPRC itself ++ */ ++ error = dprc_set_irq(mc_bus_dev->mc_io, ++ MC_CMD_FLAG_INTR_DIS | MC_CMD_FLAG_PRI, ++ mc_bus_dev->mc_handle, ++ mc_dev_irq->dev_irq_index, ++ &irq_cfg); ++ if (error < 0) { ++ dev_err(&owner_mc_dev->dev, ++ "dprc_set_irq() failed: %d\n", error); ++ } ++ } else { ++ /* ++ * IRQ is for for a child device of mc_bus_dev ++ */ ++ error = dprc_set_obj_irq(mc_bus_dev->mc_io, ++ MC_CMD_FLAG_INTR_DIS | MC_CMD_FLAG_PRI, ++ mc_bus_dev->mc_handle, ++ owner_mc_dev->obj_desc.type, ++ owner_mc_dev->obj_desc.id, ++ mc_dev_irq->dev_irq_index, ++ &irq_cfg); ++ if (error < 0) { ++ dev_err(&owner_mc_dev->dev, ++ "dprc_obj_set_irq() failed: %d\n", error); ++ } ++ } ++} ++ ++/* ++ * NOTE: This function is invoked with interrupts disabled ++ */ ++static void fsl_mc_msi_write_msg(struct irq_data *irq_data, ++ struct msi_msg *msg) ++{ ++ struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data); ++ struct fsl_mc_device *mc_bus_dev = to_fsl_mc_device(msi_desc->dev); ++ struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); ++ struct fsl_mc_device_irq *mc_dev_irq = ++ &mc_bus->irq_resources[msi_desc->fsl_mc.msi_index]; ++ ++ msi_desc->msg = *msg; ++ ++ /* ++ * Program the MSI (paddr, value) pair in the device: ++ */ ++ __fsl_mc_msi_write_msg(mc_bus_dev, mc_dev_irq); ++} ++ ++static void fsl_mc_msi_update_chip_ops(struct msi_domain_info *info) ++{ ++ struct irq_chip *chip = info->chip; ++ ++ if (!chip) ++ return; ++ ++ /* ++ * irq_write_msi_msg should not be set by the caller ++ */ ++ if (!chip->irq_write_msi_msg) ++ chip->irq_write_msi_msg = fsl_mc_msi_write_msg; ++} ++ ++/** ++ * fsl_mc_msi_create_irq_domain - Create a fsl-mc MSI interrupt domain ++ * @np: Optional device-tree node of the interrupt controller ++ * @info: MSI domain info ++ * @parent: Parent irq domain ++ * ++ * Updates the domain and chip ops and creates a fsl-mc MSI ++ * interrupt domain. ++ * ++ * Returns: ++ * A domain pointer or NULL in case of failure. ++ */ ++struct irq_domain *fsl_mc_msi_create_irq_domain(struct fwnode_handle *fwnode, ++ struct msi_domain_info *info, ++ struct irq_domain *parent) ++{ ++ struct irq_domain *domain; ++ ++ if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS) ++ fsl_mc_msi_update_dom_ops(info); ++ if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS) ++ fsl_mc_msi_update_chip_ops(info); ++ ++ domain = msi_create_irq_domain(fwnode, info, parent); ++ if (domain) ++ irq_domain_update_bus_token(domain, DOMAIN_BUS_FSL_MC_MSI); ++ ++ return domain; ++} ++ ++int fsl_mc_find_msi_domain(struct device *mc_platform_dev, ++ struct irq_domain **mc_msi_domain) ++{ ++ struct irq_domain *msi_domain; ++ struct device_node *mc_of_node = mc_platform_dev->of_node; ++ ++ msi_domain = of_msi_get_domain(mc_platform_dev, mc_of_node, ++ DOMAIN_BUS_FSL_MC_MSI); ++ if (!msi_domain) { ++ pr_err("Unable to find fsl-mc MSI domain for %pOF\n", ++ mc_of_node); ++ ++ return -ENOENT; ++ } ++ ++ *mc_msi_domain = msi_domain; ++ return 0; ++} ++ ++static void fsl_mc_msi_free_descs(struct device *dev) ++{ ++ struct msi_desc *desc, *tmp; ++ ++ list_for_each_entry_safe(desc, tmp, dev_to_msi_list(dev), list) { ++ list_del(&desc->list); ++ free_msi_entry(desc); ++ } ++} ++ ++static int fsl_mc_msi_alloc_descs(struct device *dev, unsigned int irq_count) ++ ++{ ++ unsigned int i; ++ int error; ++ struct msi_desc *msi_desc; ++ ++ for (i = 0; i < irq_count; i++) { ++ msi_desc = alloc_msi_entry(dev, 1, NULL); ++ if (!msi_desc) { ++ dev_err(dev, "Failed to allocate msi entry\n"); ++ error = -ENOMEM; ++ goto cleanup_msi_descs; ++ } ++ ++ msi_desc->fsl_mc.msi_index = i; ++ INIT_LIST_HEAD(&msi_desc->list); ++ list_add_tail(&msi_desc->list, dev_to_msi_list(dev)); ++ } ++ ++ return 0; ++ ++cleanup_msi_descs: ++ fsl_mc_msi_free_descs(dev); ++ return error; ++} ++ ++int fsl_mc_msi_domain_alloc_irqs(struct device *dev, ++ unsigned int irq_count) ++{ ++ struct irq_domain *msi_domain; ++ int error; ++ ++ if (!list_empty(dev_to_msi_list(dev))) ++ return -EINVAL; ++ ++ error = fsl_mc_msi_alloc_descs(dev, irq_count); ++ if (error < 0) ++ return error; ++ ++ msi_domain = dev_get_msi_domain(dev); ++ if (!msi_domain) { ++ error = -EINVAL; ++ goto cleanup_msi_descs; ++ } ++ ++ /* ++ * NOTE: Calling this function will trigger the invocation of the ++ * its_fsl_mc_msi_prepare() callback ++ */ ++ error = msi_domain_alloc_irqs(msi_domain, dev, irq_count); ++ ++ if (error) { ++ dev_err(dev, "Failed to allocate IRQs\n"); ++ goto cleanup_msi_descs; ++ } ++ ++ return 0; ++ ++cleanup_msi_descs: ++ fsl_mc_msi_free_descs(dev); ++ return error; ++} ++ ++void fsl_mc_msi_domain_free_irqs(struct device *dev) ++{ ++ struct irq_domain *msi_domain; ++ ++ msi_domain = dev_get_msi_domain(dev); ++ if (!msi_domain) ++ return; ++ ++ msi_domain_free_irqs(msi_domain, dev); ++ ++ if (list_empty(dev_to_msi_list(dev))) ++ return; ++ ++ fsl_mc_msi_free_descs(dev); ++} +--- /dev/null ++++ b/drivers/bus/fsl-mc/fsl-mc-private.h +@@ -0,0 +1,223 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Freescale Management Complex (MC) bus private declarations ++ * ++ * Copyright (C) 2016 Freescale Semiconductor, Inc. ++ * ++ */ ++#ifndef _FSL_MC_PRIVATE_H_ ++#define _FSL_MC_PRIVATE_H_ ++ ++#include <linux/fsl/mc.h> ++#include <linux/mutex.h> ++#include <linux/cdev.h> ++#include <linux/ioctl.h> ++ ++/* ++ * Data Path Management Complex (DPMNG) General API ++ */ ++ ++/* DPMNG command versioning */ ++#define DPMNG_CMD_BASE_VERSION 1 ++#define DPMNG_CMD_ID_OFFSET 4 ++ ++#define DPMNG_CMD(id) (((id) << DPMNG_CMD_ID_OFFSET) | DPMNG_CMD_BASE_VERSION) ++ ++/* DPMNG command IDs */ ++#define DPMNG_CMDID_GET_VERSION DPMNG_CMD(0x831) ++ ++struct dpmng_rsp_get_version { ++ __le32 revision; ++ __le32 version_major; ++ __le32 version_minor; ++}; ++ ++/* ++ * Data Path Management Command Portal (DPMCP) API ++ */ ++ ++/* Minimal supported DPMCP Version */ ++#define DPMCP_MIN_VER_MAJOR 3 ++#define DPMCP_MIN_VER_MINOR 0 ++ ++/* DPMCP command versioning */ ++#define DPMCP_CMD_BASE_VERSION 1 ++#define DPMCP_CMD_ID_OFFSET 4 ++ ++#define DPMCP_CMD(id) (((id) << DPMCP_CMD_ID_OFFSET) | DPMCP_CMD_BASE_VERSION) ++ ++/* DPMCP command IDs */ ++#define DPMCP_CMDID_CLOSE DPMCP_CMD(0x800) ++#define DPMCP_CMDID_OPEN DPMCP_CMD(0x80b) ++#define DPMCP_CMDID_RESET DPMCP_CMD(0x005) ++ ++struct dpmcp_cmd_open { ++ __le32 dpmcp_id; ++}; ++ ++/* ++ * Initialization and runtime control APIs for DPMCP ++ */ ++int dpmcp_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpmcp_id, ++ u16 *token); ++ ++int dpmcp_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpmcp_reset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++/* ++ * Data Path Buffer Pool (DPBP) API + */ -+#ifndef _FSL_DPBP_CMD_H -+#define _FSL_DPBP_CMD_H + +/* DPBP Version */ +#define DPBP_VER_MAJOR 3 @@ -209,33 +7555,23 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +#define DPBP_CMD_BASE_VERSION 1 +#define DPBP_CMD_ID_OFFSET 4 + -+#define DPBP_CMD(id) ((id << DPBP_CMD_ID_OFFSET) | DPBP_CMD_BASE_VERSION) ++#define DPBP_CMD(id) (((id) << DPBP_CMD_ID_OFFSET) | DPBP_CMD_BASE_VERSION) + +/* Command IDs */ +#define DPBP_CMDID_CLOSE DPBP_CMD(0x800) +#define DPBP_CMDID_OPEN DPBP_CMD(0x804) -+#define DPBP_CMDID_GET_API_VERSION DPBP_CMD(0xa04) + +#define DPBP_CMDID_ENABLE DPBP_CMD(0x002) +#define DPBP_CMDID_DISABLE DPBP_CMD(0x003) +#define DPBP_CMDID_GET_ATTR DPBP_CMD(0x004) +#define DPBP_CMDID_RESET DPBP_CMD(0x005) -+#define DPBP_CMDID_IS_ENABLED DPBP_CMD(0x006) + +struct dpbp_cmd_open { + __le32 dpbp_id; +}; + -+struct dpbp_cmd_destroy { -+ __le32 object_id; -+}; -+ +#define DPBP_ENABLE 0x1 + -+struct dpbp_rsp_is_enabled { -+ u8 enabled; -+}; -+ +struct dpbp_rsp_get_attributes { + /* response word 0 */ + __le16 pad; @@ -246,38 +7582,2020 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + __le16 version_minor; +}; + -+#endif /* _FSL_DPBP_CMD_H */ ---- a/drivers/staging/fsl-mc/bus/dpbp.c -+++ b/drivers/staging/fsl-mc/bus/dpbp.c -@@ -1,4 +1,5 @@ ++/* ++ * Data Path Concentrator (DPCON) API ++ */ ++ ++/* DPCON Version */ ++#define DPCON_VER_MAJOR 3 ++#define DPCON_VER_MINOR 2 ++ ++/* Command versioning */ ++#define DPCON_CMD_BASE_VERSION 1 ++#define DPCON_CMD_ID_OFFSET 4 ++ ++#define DPCON_CMD(id) (((id) << DPCON_CMD_ID_OFFSET) | DPCON_CMD_BASE_VERSION) ++ ++/* Command IDs */ ++#define DPCON_CMDID_CLOSE DPCON_CMD(0x800) ++#define DPCON_CMDID_OPEN DPCON_CMD(0x808) ++ ++#define DPCON_CMDID_ENABLE DPCON_CMD(0x002) ++#define DPCON_CMDID_DISABLE DPCON_CMD(0x003) ++#define DPCON_CMDID_GET_ATTR DPCON_CMD(0x004) ++#define DPCON_CMDID_RESET DPCON_CMD(0x005) ++ ++#define DPCON_CMDID_SET_NOTIFICATION DPCON_CMD(0x100) ++ ++struct dpcon_cmd_open { ++ __le32 dpcon_id; ++}; ++ ++#define DPCON_ENABLE 1 ++ ++struct dpcon_rsp_get_attr { ++ /* response word 0 */ ++ __le32 id; ++ __le16 qbman_ch_id; ++ u8 num_priorities; ++ u8 pad; ++}; ++ ++struct dpcon_cmd_set_notification { ++ /* cmd word 0 */ ++ __le32 dpio_id; ++ u8 priority; ++ u8 pad[3]; ++ /* cmd word 1 */ ++ __le64 user_ctx; ++}; ++ ++int __must_check fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc, ++ struct fsl_mc_io *mc_io, ++ struct device *parent_dev, ++ const char *driver_override, ++ struct fsl_mc_device **new_mc_dev); ++ ++int __init dprc_driver_init(void); ++ ++void dprc_driver_exit(void); ++ ++int __init fsl_mc_allocator_driver_init(void); ++ ++void fsl_mc_allocator_driver_exit(void); ++ ++int __must_check fsl_mc_resource_allocate(struct fsl_mc_bus *mc_bus, ++ enum fsl_mc_pool_type pool_type, ++ struct fsl_mc_resource ++ **new_resource); ++ ++void fsl_mc_resource_free(struct fsl_mc_resource *resource); ++ ++int fsl_mc_msi_domain_alloc_irqs(struct device *dev, ++ unsigned int irq_count); ++ ++void fsl_mc_msi_domain_free_irqs(struct device *dev); ++ ++int __must_check fsl_create_mc_io(struct device *dev, ++ phys_addr_t mc_portal_phys_addr, ++ u32 mc_portal_size, ++ struct fsl_mc_device *dpmcp_dev, ++ u32 flags, struct fsl_mc_io **new_mc_io); ++ ++void fsl_destroy_mc_io(struct fsl_mc_io *mc_io); ++ ++bool fsl_mc_is_root_dprc(struct device *dev); ++ ++#ifdef CONFIG_FSL_MC_RESTOOL ++ ++int fsl_mc_restool_create_device_file(struct fsl_mc_bus *mc_bus); ++ ++void fsl_mc_restool_remove_device_file(struct fsl_mc_bus *mc_bus); ++ ++int fsl_mc_restool_init(void); ++ ++#else ++ ++static inline int fsl_mc_restool_create_device_file(struct fsl_mc_bus *mc_bus) ++{ ++ return 0; ++} ++ ++static inline void fsl_mc_restool_remove_device_file(struct fsl_mc_bus *mc_bus) ++{ ++} ++ ++static inline int fsl_mc_restool_init(void) ++{ ++ return 0; ++} ++ ++#endif ++ ++#endif /* _FSL_MC_PRIVATE_H_ */ +--- /dev/null ++++ b/drivers/bus/fsl-mc/fsl-mc-restool.c +@@ -0,0 +1,219 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Management Complex (MC) restool support ++ * ++ * Copyright 2018 NXP ++ * ++ */ ++ ++#include <linux/slab.h> ++#include <linux/cdev.h> ++#include <linux/fs.h> ++#include <linux/uaccess.h> ++ ++#include "fsl-mc-private.h" ++ ++#define FSL_MC_BUS_MAX_MINORS 1 ++ ++static struct class *fsl_mc_bus_class; ++static int fsl_mc_bus_major; ++ ++static int fsl_mc_restool_send_command(unsigned long arg, ++ struct fsl_mc_io *mc_io) ++{ ++ struct fsl_mc_command mc_cmd; ++ int error; ++ ++ error = copy_from_user(&mc_cmd, (void __user *)arg, sizeof(mc_cmd)); ++ if (error) ++ return -EFAULT; ++ ++ error = mc_send_command(mc_io, &mc_cmd); ++ if (error) ++ return error; ++ ++ error = copy_to_user((void __user *)arg, &mc_cmd, sizeof(mc_cmd)); ++ if (error) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++int fsl_mc_restool_init(void) ++{ ++ dev_t dev; ++ int error; ++ ++ fsl_mc_bus_class = class_create(THIS_MODULE, "fsl_mc_bus"); ++ if (IS_ERR(fsl_mc_bus_class)) { ++ error = PTR_ERR(fsl_mc_bus_class); ++ return error; ++ } ++ ++ error = alloc_chrdev_region(&dev, 0, ++ FSL_MC_BUS_MAX_MINORS, ++ "fsl_mc_bus"); ++ if (error < 0) ++ return error; ++ ++ fsl_mc_bus_major = MAJOR(dev); ++ ++ return 0; ++} ++ ++static int fsl_mc_restool_dev_open(struct inode *inode, struct file *filep) ++{ ++ struct fsl_mc_device *root_mc_device; ++ struct fsl_mc_restool *mc_restool; ++ struct fsl_mc_bus *mc_bus; ++ struct fsl_mc_io *dynamic_mc_io; ++ int error; ++ ++ mc_restool = container_of(inode->i_cdev, struct fsl_mc_restool, cdev); ++ mc_bus = container_of(mc_restool, struct fsl_mc_bus, restool_misc); ++ root_mc_device = &mc_bus->mc_dev; ++ ++ mutex_lock(&mc_restool->mutex); ++ ++ if (!mc_restool->local_instance_in_use) { ++ filep->private_data = root_mc_device->mc_io; ++ mc_restool->local_instance_in_use = true; ++ } else { ++ dynamic_mc_io = kzalloc(sizeof(*dynamic_mc_io), GFP_KERNEL); ++ if (!dynamic_mc_io) { ++ error = -ENOMEM; ++ goto error_alloc_mc_io; ++ } ++ ++ error = fsl_mc_portal_allocate(root_mc_device, 0, ++ &dynamic_mc_io); ++ if (error) { ++ pr_err("Could not allocate MC portal\n"); ++ goto error_portal_allocate; ++ } ++ ++ mc_restool->dynamic_instance_count++; ++ filep->private_data = dynamic_mc_io; ++ } ++ ++ mutex_unlock(&mc_restool->mutex); ++ ++ return 0; ++ ++error_portal_allocate: ++ kfree(dynamic_mc_io); ++ ++error_alloc_mc_io: ++ mutex_unlock(&mc_restool->mutex); ++ ++ return error; ++} ++ ++static int fsl_mc_restool_dev_release(struct inode *inode, struct file *filep) ++{ ++ struct fsl_mc_device *root_mc_device; ++ struct fsl_mc_restool *mc_restool; ++ struct fsl_mc_bus *mc_bus; ++ struct fsl_mc_io *mc_io; ++ ++ mc_restool = container_of(inode->i_cdev, struct fsl_mc_restool, cdev); ++ mc_bus = container_of(mc_restool, struct fsl_mc_bus, restool_misc); ++ root_mc_device = &mc_bus->mc_dev; ++ mc_io = filep->private_data; ++ ++ mutex_lock(&mc_restool->mutex); ++ ++ if (WARN_ON(!mc_restool->local_instance_in_use && ++ mc_restool->dynamic_instance_count == 0)) { ++ mutex_unlock(&mc_restool->mutex); ++ return -EINVAL; ++ } ++ ++ if (filep->private_data == root_mc_device->mc_io) { ++ mc_restool->local_instance_in_use = false; ++ } else { ++ fsl_mc_portal_free(mc_io); ++ kfree(mc_io); ++ mc_restool->dynamic_instance_count--; ++ } ++ ++ filep->private_data = NULL; ++ mutex_unlock(&mc_restool->mutex); ++ ++ return 0; ++} ++ ++static long fsl_mc_restool_dev_ioctl(struct file *file, ++ unsigned int cmd, ++ unsigned long arg) ++{ ++ int error; ++ ++ switch (cmd) { ++ case RESTOOL_SEND_MC_COMMAND: ++ error = fsl_mc_restool_send_command(arg, file->private_data); ++ break; ++ default: ++ pr_err("%s: unexpected ioctl call number\n", __func__); ++ error = -EINVAL; ++ } ++ ++ return error; ++} ++ ++static const struct file_operations fsl_mc_restool_dev_fops = { ++ .owner = THIS_MODULE, ++ .open = fsl_mc_restool_dev_open, ++ .release = fsl_mc_restool_dev_release, ++ .unlocked_ioctl = fsl_mc_restool_dev_ioctl, ++}; ++ ++int fsl_mc_restool_create_device_file(struct fsl_mc_bus *mc_bus) ++{ ++ struct fsl_mc_device *mc_dev = &mc_bus->mc_dev; ++ struct fsl_mc_restool *mc_restool = &mc_bus->restool_misc; ++ int error; ++ ++ mc_restool = &mc_bus->restool_misc; ++ mc_restool->dev = MKDEV(fsl_mc_bus_major, 0); ++ cdev_init(&mc_restool->cdev, &fsl_mc_restool_dev_fops); ++ ++ error = cdev_add(&mc_restool->cdev, ++ mc_restool->dev, ++ FSL_MC_BUS_MAX_MINORS); ++ if (error) ++ return error; ++ ++ mc_restool->device = device_create(fsl_mc_bus_class, ++ NULL, ++ mc_restool->dev, ++ NULL, ++ "%s", ++ dev_name(&mc_dev->dev)); ++ if (IS_ERR(mc_restool->device)) { ++ error = PTR_ERR(mc_restool->device); ++ goto error_device_create; ++ } ++ ++ mutex_init(&mc_restool->mutex); ++ ++ return 0; ++ ++error_device_create: ++ cdev_del(&mc_restool->cdev); ++ ++ return error; ++} ++ ++void fsl_mc_restool_remove_device_file(struct fsl_mc_bus *mc_bus) ++{ ++ struct fsl_mc_restool *mc_restool = &mc_bus->restool_misc; ++ ++ if (WARN_ON(mc_restool->local_instance_in_use)) ++ return; ++ ++ if (WARN_ON(mc_restool->dynamic_instance_count != 0)) ++ return; ++ ++ cdev_del(&mc_restool->cdev); ++} +--- a/drivers/staging/fsl-mc/bus/mc-io.c ++++ /dev/null +@@ -1,320 +0,0 @@ -/* Copyright 2013-2016 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 the above-listed copyright holders nor the +- * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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 <linux/io.h> +-#include "../include/mc-bus.h" +-#include "../include/mc-sys.h" +- +-#include "fsl-mc-private.h" +-#include "dpmcp.h" +-#include "dpmcp-cmd.h" +- +-static int fsl_mc_io_set_dpmcp(struct fsl_mc_io *mc_io, +- struct fsl_mc_device *dpmcp_dev) +-{ +- int error; +- +- if (WARN_ON(!dpmcp_dev)) +- return -EINVAL; +- +- if (WARN_ON(mc_io->dpmcp_dev)) +- return -EINVAL; +- +- if (WARN_ON(dpmcp_dev->mc_io)) +- return -EINVAL; +- +- error = dpmcp_open(mc_io, +- 0, +- dpmcp_dev->obj_desc.id, +- &dpmcp_dev->mc_handle); +- if (error < 0) +- return error; +- +- mc_io->dpmcp_dev = dpmcp_dev; +- dpmcp_dev->mc_io = mc_io; +- return 0; +-} +- +-static void fsl_mc_io_unset_dpmcp(struct fsl_mc_io *mc_io) +-{ +- int error; +- struct fsl_mc_device *dpmcp_dev = mc_io->dpmcp_dev; +- +- if (WARN_ON(!dpmcp_dev)) +- return; +- +- if (WARN_ON(dpmcp_dev->mc_io != mc_io)) +- return; +- +- error = dpmcp_close(mc_io, +- 0, +- dpmcp_dev->mc_handle); +- if (error < 0) { +- dev_err(&dpmcp_dev->dev, "dpmcp_close() failed: %d\n", +- error); +- } +- +- mc_io->dpmcp_dev = NULL; +- dpmcp_dev->mc_io = NULL; +-} +- +-/** +- * Creates an MC I/O object +- * +- * @dev: device to be associated with the MC I/O object +- * @mc_portal_phys_addr: physical address of the MC portal to use +- * @mc_portal_size: size in bytes of the MC portal +- * @dpmcp-dev: Pointer to the DPMCP object associated with this MC I/O +- * object or NULL if none. +- * @flags: flags for the new MC I/O object +- * @new_mc_io: Area to return pointer to newly created MC I/O object +- * +- * Returns '0' on Success; Error code otherwise. +- */ +-int __must_check fsl_create_mc_io(struct device *dev, +- phys_addr_t mc_portal_phys_addr, +- u32 mc_portal_size, +- struct fsl_mc_device *dpmcp_dev, +- u32 flags, struct fsl_mc_io **new_mc_io) +-{ +- int error; +- struct fsl_mc_io *mc_io; +- void __iomem *mc_portal_virt_addr; +- struct resource *res; +- +- mc_io = devm_kzalloc(dev, sizeof(*mc_io), GFP_KERNEL); +- if (!mc_io) +- return -ENOMEM; +- +- mc_io->dev = dev; +- mc_io->flags = flags; +- mc_io->portal_phys_addr = mc_portal_phys_addr; +- mc_io->portal_size = mc_portal_size; +- if (flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL) +- spin_lock_init(&mc_io->spinlock); +- else +- mutex_init(&mc_io->mutex); +- +- res = devm_request_mem_region(dev, +- mc_portal_phys_addr, +- mc_portal_size, +- "mc_portal"); +- if (!res) { +- dev_err(dev, +- "devm_request_mem_region failed for MC portal %#llx\n", +- mc_portal_phys_addr); +- return -EBUSY; +- } +- +- mc_portal_virt_addr = devm_ioremap_nocache(dev, +- mc_portal_phys_addr, +- mc_portal_size); +- if (!mc_portal_virt_addr) { +- dev_err(dev, +- "devm_ioremap_nocache failed for MC portal %#llx\n", +- mc_portal_phys_addr); +- return -ENXIO; +- } +- +- mc_io->portal_virt_addr = mc_portal_virt_addr; +- if (dpmcp_dev) { +- error = fsl_mc_io_set_dpmcp(mc_io, dpmcp_dev); +- if (error < 0) +- goto error_destroy_mc_io; +- } +- +- *new_mc_io = mc_io; +- return 0; +- +-error_destroy_mc_io: +- fsl_destroy_mc_io(mc_io); +- return error; +-} +- +-/** +- * Destroys an MC I/O object +- * +- * @mc_io: MC I/O object to destroy +- */ +-void fsl_destroy_mc_io(struct fsl_mc_io *mc_io) +-{ +- struct fsl_mc_device *dpmcp_dev = mc_io->dpmcp_dev; +- +- if (dpmcp_dev) +- fsl_mc_io_unset_dpmcp(mc_io); +- +- devm_iounmap(mc_io->dev, mc_io->portal_virt_addr); +- devm_release_mem_region(mc_io->dev, +- mc_io->portal_phys_addr, +- mc_io->portal_size); +- +- mc_io->portal_virt_addr = NULL; +- devm_kfree(mc_io->dev, mc_io); +-} +- +-/** +- * fsl_mc_portal_allocate - Allocates an MC portal +- * +- * @mc_dev: MC device for which the MC portal is to be allocated +- * @mc_io_flags: Flags for the fsl_mc_io object that wraps the allocated +- * MC portal. +- * @new_mc_io: Pointer to area where the pointer to the fsl_mc_io object +- * that wraps the allocated MC portal is to be returned +- * +- * This function allocates an MC portal from the device's parent DPRC, +- * from the corresponding MC bus' pool of MC portals and wraps +- * it in a new fsl_mc_io object. If 'mc_dev' is a DPRC itself, the +- * portal is allocated from its own MC bus. +- */ +-int __must_check fsl_mc_portal_allocate(struct fsl_mc_device *mc_dev, +- u16 mc_io_flags, +- struct fsl_mc_io **new_mc_io) +-{ +- struct fsl_mc_device *mc_bus_dev; +- struct fsl_mc_bus *mc_bus; +- phys_addr_t mc_portal_phys_addr; +- size_t mc_portal_size; +- struct fsl_mc_device *dpmcp_dev; +- int error = -EINVAL; +- struct fsl_mc_resource *resource = NULL; +- struct fsl_mc_io *mc_io = NULL; +- +- if (mc_dev->flags & FSL_MC_IS_DPRC) { +- mc_bus_dev = mc_dev; +- } else { +- if (WARN_ON(!dev_is_fsl_mc(mc_dev->dev.parent))) +- return error; +- +- mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); +- } +- +- mc_bus = to_fsl_mc_bus(mc_bus_dev); +- *new_mc_io = NULL; +- error = fsl_mc_resource_allocate(mc_bus, FSL_MC_POOL_DPMCP, &resource); +- if (error < 0) +- return error; +- +- error = -EINVAL; +- dpmcp_dev = resource->data; +- if (WARN_ON(!dpmcp_dev)) +- goto error_cleanup_resource; +- +- if (dpmcp_dev->obj_desc.ver_major < DPMCP_MIN_VER_MAJOR || +- (dpmcp_dev->obj_desc.ver_major == DPMCP_MIN_VER_MAJOR && +- dpmcp_dev->obj_desc.ver_minor < DPMCP_MIN_VER_MINOR)) { +- dev_err(&dpmcp_dev->dev, +- "ERROR: Version %d.%d of DPMCP not supported.\n", +- dpmcp_dev->obj_desc.ver_major, +- dpmcp_dev->obj_desc.ver_minor); +- error = -ENOTSUPP; +- goto error_cleanup_resource; +- } +- +- if (WARN_ON(dpmcp_dev->obj_desc.region_count == 0)) +- goto error_cleanup_resource; +- +- mc_portal_phys_addr = dpmcp_dev->regions[0].start; +- mc_portal_size = dpmcp_dev->regions[0].end - +- dpmcp_dev->regions[0].start + 1; +- +- if (WARN_ON(mc_portal_size != mc_bus_dev->mc_io->portal_size)) +- goto error_cleanup_resource; +- +- error = fsl_create_mc_io(&mc_bus_dev->dev, +- mc_portal_phys_addr, +- mc_portal_size, dpmcp_dev, +- mc_io_flags, &mc_io); +- if (error < 0) +- goto error_cleanup_resource; +- +- *new_mc_io = mc_io; +- return 0; +- +-error_cleanup_resource: +- fsl_mc_resource_free(resource); +- return error; +-} +-EXPORT_SYMBOL_GPL(fsl_mc_portal_allocate); +- +-/** +- * fsl_mc_portal_free - Returns an MC portal to the pool of free MC portals +- * of a given MC bus +- * +- * @mc_io: Pointer to the fsl_mc_io object that wraps the MC portal to free +- */ +-void fsl_mc_portal_free(struct fsl_mc_io *mc_io) +-{ +- struct fsl_mc_device *dpmcp_dev; +- struct fsl_mc_resource *resource; +- +- /* +- * Every mc_io obtained by calling fsl_mc_portal_allocate() is supposed +- * to have a DPMCP object associated with. +- */ +- dpmcp_dev = mc_io->dpmcp_dev; +- if (WARN_ON(!dpmcp_dev)) +- return; +- +- resource = dpmcp_dev->resource; +- if (WARN_ON(!resource || resource->type != FSL_MC_POOL_DPMCP)) +- return; +- +- if (WARN_ON(resource->data != dpmcp_dev)) +- return; +- +- fsl_destroy_mc_io(mc_io); +- fsl_mc_resource_free(resource); +-} +-EXPORT_SYMBOL_GPL(fsl_mc_portal_free); +- +-/** +- * fsl_mc_portal_reset - Resets the dpmcp object for a given fsl_mc_io object +- * +- * @mc_io: Pointer to the fsl_mc_io object that wraps the MC portal to free +- */ +-int fsl_mc_portal_reset(struct fsl_mc_io *mc_io) +-{ +- int error; +- struct fsl_mc_device *dpmcp_dev = mc_io->dpmcp_dev; +- +- if (WARN_ON(!dpmcp_dev)) +- return -EINVAL; +- +- error = dpmcp_reset(mc_io, 0, dpmcp_dev->mc_handle); +- if (error < 0) { +- dev_err(&dpmcp_dev->dev, "dpmcp_reset() failed: %d\n", error); +- return error; +- } +- +- return 0; +-} +-EXPORT_SYMBOL_GPL(fsl_mc_portal_reset); +--- /dev/null ++++ b/drivers/bus/fsl-mc/mc-io.c +@@ -0,0 +1,268 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright 2013-2016 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: -@@ -11,7 +12,6 @@ - * names of any 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 -@@ -32,7 +32,8 @@ - #include "../include/mc-sys.h" - #include "../include/mc-cmd.h" - #include "../include/dpbp.h" --#include "../include/dpbp-cmd.h" ++ * ++ */ ++ ++#include <linux/io.h> ++#include <linux/fsl/mc.h> ++ ++#include "fsl-mc-private.h" ++ ++static int fsl_mc_io_set_dpmcp(struct fsl_mc_io *mc_io, ++ struct fsl_mc_device *dpmcp_dev) ++{ ++ int error; ++ ++ if (mc_io->dpmcp_dev) ++ return -EINVAL; ++ ++ if (dpmcp_dev->mc_io) ++ return -EINVAL; ++ ++ error = dpmcp_open(mc_io, ++ 0, ++ dpmcp_dev->obj_desc.id, ++ &dpmcp_dev->mc_handle); ++ if (error < 0) ++ return error; ++ ++ mc_io->dpmcp_dev = dpmcp_dev; ++ dpmcp_dev->mc_io = mc_io; ++ return 0; ++} ++ ++static void fsl_mc_io_unset_dpmcp(struct fsl_mc_io *mc_io) ++{ ++ int error; ++ struct fsl_mc_device *dpmcp_dev = mc_io->dpmcp_dev; ++ ++ error = dpmcp_close(mc_io, ++ 0, ++ dpmcp_dev->mc_handle); ++ if (error < 0) { ++ dev_err(&dpmcp_dev->dev, "dpmcp_close() failed: %d\n", ++ error); ++ } ++ ++ mc_io->dpmcp_dev = NULL; ++ dpmcp_dev->mc_io = NULL; ++} ++ ++/** ++ * Creates an MC I/O object ++ * ++ * @dev: device to be associated with the MC I/O object ++ * @mc_portal_phys_addr: physical address of the MC portal to use ++ * @mc_portal_size: size in bytes of the MC portal ++ * @dpmcp-dev: Pointer to the DPMCP object associated with this MC I/O ++ * object or NULL if none. ++ * @flags: flags for the new MC I/O object ++ * @new_mc_io: Area to return pointer to newly created MC I/O object ++ * ++ * Returns '0' on Success; Error code otherwise. ++ */ ++int __must_check fsl_create_mc_io(struct device *dev, ++ phys_addr_t mc_portal_phys_addr, ++ u32 mc_portal_size, ++ struct fsl_mc_device *dpmcp_dev, ++ u32 flags, struct fsl_mc_io **new_mc_io) ++{ ++ int error; ++ struct fsl_mc_io *mc_io; ++ void __iomem *mc_portal_virt_addr; ++ struct resource *res; ++ ++ mc_io = devm_kzalloc(dev, sizeof(*mc_io), GFP_KERNEL); ++ if (!mc_io) ++ return -ENOMEM; ++ ++ mc_io->dev = dev; ++ mc_io->flags = flags; ++ mc_io->portal_phys_addr = mc_portal_phys_addr; ++ mc_io->portal_size = mc_portal_size; ++ if (flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL) ++ spin_lock_init(&mc_io->spinlock); ++ else ++ mutex_init(&mc_io->mutex); ++ ++ res = devm_request_mem_region(dev, ++ mc_portal_phys_addr, ++ mc_portal_size, ++ "mc_portal"); ++ if (!res) { ++ dev_err(dev, ++ "devm_request_mem_region failed for MC portal %pa\n", ++ &mc_portal_phys_addr); ++ return -EBUSY; ++ } ++ ++ mc_portal_virt_addr = devm_ioremap_nocache(dev, ++ mc_portal_phys_addr, ++ mc_portal_size); ++ if (!mc_portal_virt_addr) { ++ dev_err(dev, ++ "devm_ioremap_nocache failed for MC portal %pa\n", ++ &mc_portal_phys_addr); ++ return -ENXIO; ++ } ++ ++ mc_io->portal_virt_addr = mc_portal_virt_addr; ++ if (dpmcp_dev) { ++ error = fsl_mc_io_set_dpmcp(mc_io, dpmcp_dev); ++ if (error < 0) ++ goto error_destroy_mc_io; ++ } ++ ++ *new_mc_io = mc_io; ++ return 0; ++ ++error_destroy_mc_io: ++ fsl_destroy_mc_io(mc_io); ++ return error; ++} ++ ++/** ++ * Destroys an MC I/O object ++ * ++ * @mc_io: MC I/O object to destroy ++ */ ++void fsl_destroy_mc_io(struct fsl_mc_io *mc_io) ++{ ++ struct fsl_mc_device *dpmcp_dev = mc_io->dpmcp_dev; ++ ++ if (dpmcp_dev) ++ fsl_mc_io_unset_dpmcp(mc_io); ++ ++ devm_iounmap(mc_io->dev, mc_io->portal_virt_addr); ++ devm_release_mem_region(mc_io->dev, ++ mc_io->portal_phys_addr, ++ mc_io->portal_size); ++ ++ mc_io->portal_virt_addr = NULL; ++ devm_kfree(mc_io->dev, mc_io); ++} ++ ++/** ++ * fsl_mc_portal_allocate - Allocates an MC portal ++ * ++ * @mc_dev: MC device for which the MC portal is to be allocated ++ * @mc_io_flags: Flags for the fsl_mc_io object that wraps the allocated ++ * MC portal. ++ * @new_mc_io: Pointer to area where the pointer to the fsl_mc_io object ++ * that wraps the allocated MC portal is to be returned ++ * ++ * This function allocates an MC portal from the device's parent DPRC, ++ * from the corresponding MC bus' pool of MC portals and wraps ++ * it in a new fsl_mc_io object. If 'mc_dev' is a DPRC itself, the ++ * portal is allocated from its own MC bus. ++ */ ++int __must_check fsl_mc_portal_allocate(struct fsl_mc_device *mc_dev, ++ u16 mc_io_flags, ++ struct fsl_mc_io **new_mc_io) ++{ ++ struct fsl_mc_device *mc_bus_dev; ++ struct fsl_mc_bus *mc_bus; ++ phys_addr_t mc_portal_phys_addr; ++ size_t mc_portal_size; ++ struct fsl_mc_device *dpmcp_dev; ++ int error = -EINVAL; ++ struct fsl_mc_resource *resource = NULL; ++ struct fsl_mc_io *mc_io = NULL; ++ ++ if (mc_dev->flags & FSL_MC_IS_DPRC) { ++ mc_bus_dev = mc_dev; ++ } else { ++ if (!dev_is_fsl_mc(mc_dev->dev.parent)) ++ return error; ++ ++ mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); ++ } ++ ++ mc_bus = to_fsl_mc_bus(mc_bus_dev); ++ *new_mc_io = NULL; ++ error = fsl_mc_resource_allocate(mc_bus, FSL_MC_POOL_DPMCP, &resource); ++ if (error < 0) ++ return error; ++ ++ error = -EINVAL; ++ dpmcp_dev = resource->data; ++ ++ if (dpmcp_dev->obj_desc.ver_major < DPMCP_MIN_VER_MAJOR || ++ (dpmcp_dev->obj_desc.ver_major == DPMCP_MIN_VER_MAJOR && ++ dpmcp_dev->obj_desc.ver_minor < DPMCP_MIN_VER_MINOR)) { ++ dev_err(&dpmcp_dev->dev, ++ "ERROR: Version %d.%d of DPMCP not supported.\n", ++ dpmcp_dev->obj_desc.ver_major, ++ dpmcp_dev->obj_desc.ver_minor); ++ error = -ENOTSUPP; ++ goto error_cleanup_resource; ++ } ++ ++ mc_portal_phys_addr = dpmcp_dev->regions[0].start; ++ mc_portal_size = resource_size(dpmcp_dev->regions); ++ ++ error = fsl_create_mc_io(&mc_bus_dev->dev, ++ mc_portal_phys_addr, ++ mc_portal_size, dpmcp_dev, ++ mc_io_flags, &mc_io); ++ if (error < 0) ++ goto error_cleanup_resource; ++ ++ *new_mc_io = mc_io; ++ return 0; ++ ++error_cleanup_resource: ++ fsl_mc_resource_free(resource); ++ return error; ++} ++EXPORT_SYMBOL_GPL(fsl_mc_portal_allocate); ++ ++/** ++ * fsl_mc_portal_free - Returns an MC portal to the pool of free MC portals ++ * of a given MC bus ++ * ++ * @mc_io: Pointer to the fsl_mc_io object that wraps the MC portal to free ++ */ ++void fsl_mc_portal_free(struct fsl_mc_io *mc_io) ++{ ++ struct fsl_mc_device *dpmcp_dev; ++ struct fsl_mc_resource *resource; ++ ++ /* ++ * Every mc_io obtained by calling fsl_mc_portal_allocate() is supposed ++ * to have a DPMCP object associated with. ++ */ ++ dpmcp_dev = mc_io->dpmcp_dev; ++ ++ resource = dpmcp_dev->resource; ++ if (!resource || resource->type != FSL_MC_POOL_DPMCP) ++ return; ++ ++ if (resource->data != dpmcp_dev) ++ return; ++ ++ fsl_destroy_mc_io(mc_io); ++ fsl_mc_resource_free(resource); ++} ++EXPORT_SYMBOL_GPL(fsl_mc_portal_free); ++ ++/** ++ * fsl_mc_portal_reset - Resets the dpmcp object for a given fsl_mc_io object ++ * ++ * @mc_io: Pointer to the fsl_mc_io object that wraps the MC portal to free ++ */ ++int fsl_mc_portal_reset(struct fsl_mc_io *mc_io) ++{ ++ int error; ++ struct fsl_mc_device *dpmcp_dev = mc_io->dpmcp_dev; ++ ++ error = dpmcp_reset(mc_io, 0, dpmcp_dev->mc_handle); ++ if (error < 0) { ++ dev_err(&dpmcp_dev->dev, "dpmcp_reset() failed: %d\n", error); ++ return error; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(fsl_mc_portal_reset); +--- a/drivers/staging/fsl-mc/bus/mc-sys.c ++++ /dev/null +@@ -1,317 +0,0 @@ +-/* Copyright 2013-2014 Freescale Semiconductor Inc. +- * +- * I/O services to send MC commands to the MC hardware +- * +- * 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 the above-listed copyright holders nor the +- * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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 <linux/delay.h> +-#include <linux/slab.h> +-#include <linux/ioport.h> +-#include <linux/device.h> +-#include <linux/io.h> +-#include "../include/mc-sys.h" +-#include "../include/mc-cmd.h" +-#include "../include/mc.h" +- +-#include "dpmcp.h" +- +-/** +- * Timeout in milliseconds to wait for the completion of an MC command +- */ +-#define MC_CMD_COMPLETION_TIMEOUT_MS 500 +- +-/* +- * usleep_range() min and max values used to throttle down polling +- * iterations while waiting for MC command completion +- */ +-#define MC_CMD_COMPLETION_POLLING_MIN_SLEEP_USECS 10 +-#define MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS 500 +- +-static enum mc_cmd_status mc_cmd_hdr_read_status(struct mc_command *cmd) +-{ +- struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header; +- +- return (enum mc_cmd_status)hdr->status; +-} +- +-static u16 mc_cmd_hdr_read_cmdid(struct mc_command *cmd) +-{ +- struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header; +- u16 cmd_id = le16_to_cpu(hdr->cmd_id); +- +- return (cmd_id & MC_CMD_HDR_CMDID_MASK) >> MC_CMD_HDR_CMDID_SHIFT; +-} +- +-static int mc_status_to_error(enum mc_cmd_status status) +-{ +- static const int mc_status_to_error_map[] = { +- [MC_CMD_STATUS_OK] = 0, +- [MC_CMD_STATUS_AUTH_ERR] = -EACCES, +- [MC_CMD_STATUS_NO_PRIVILEGE] = -EPERM, +- [MC_CMD_STATUS_DMA_ERR] = -EIO, +- [MC_CMD_STATUS_CONFIG_ERR] = -ENXIO, +- [MC_CMD_STATUS_TIMEOUT] = -ETIMEDOUT, +- [MC_CMD_STATUS_NO_RESOURCE] = -ENAVAIL, +- [MC_CMD_STATUS_NO_MEMORY] = -ENOMEM, +- [MC_CMD_STATUS_BUSY] = -EBUSY, +- [MC_CMD_STATUS_UNSUPPORTED_OP] = -ENOTSUPP, +- [MC_CMD_STATUS_INVALID_STATE] = -ENODEV, +- }; +- +- if (WARN_ON((u32)status >= ARRAY_SIZE(mc_status_to_error_map))) +- return -EINVAL; +- +- return mc_status_to_error_map[status]; +-} +- +-static const char *mc_status_to_string(enum mc_cmd_status status) +-{ +- static const char *const status_strings[] = { +- [MC_CMD_STATUS_OK] = "Command completed successfully", +- [MC_CMD_STATUS_READY] = "Command ready to be processed", +- [MC_CMD_STATUS_AUTH_ERR] = "Authentication error", +- [MC_CMD_STATUS_NO_PRIVILEGE] = "No privilege", +- [MC_CMD_STATUS_DMA_ERR] = "DMA or I/O error", +- [MC_CMD_STATUS_CONFIG_ERR] = "Configuration error", +- [MC_CMD_STATUS_TIMEOUT] = "Operation timed out", +- [MC_CMD_STATUS_NO_RESOURCE] = "No resources", +- [MC_CMD_STATUS_NO_MEMORY] = "No memory available", +- [MC_CMD_STATUS_BUSY] = "Device is busy", +- [MC_CMD_STATUS_UNSUPPORTED_OP] = "Unsupported operation", +- [MC_CMD_STATUS_INVALID_STATE] = "Invalid state" +- }; +- +- if ((unsigned int)status >= ARRAY_SIZE(status_strings)) +- return "Unknown MC error"; +- +- return status_strings[status]; +-} +- +-/** +- * mc_write_command - writes a command to a Management Complex (MC) portal +- * +- * @portal: pointer to an MC portal +- * @cmd: pointer to a filled command +- */ +-static inline void mc_write_command(struct mc_command __iomem *portal, +- struct mc_command *cmd) +-{ +- int i; +- +- /* copy command parameters into the portal */ +- for (i = 0; i < MC_CMD_NUM_OF_PARAMS; i++) +- __raw_writeq(cmd->params[i], &portal->params[i]); +- __iowmb(); +- +- /* submit the command by writing the header */ +- __raw_writeq(cmd->header, &portal->header); +-} +- +-/** +- * mc_read_response - reads the response for the last MC command from a +- * Management Complex (MC) portal +- * +- * @portal: pointer to an MC portal +- * @resp: pointer to command response buffer +- * +- * Returns MC_CMD_STATUS_OK on Success; Error code otherwise. +- */ +-static inline enum mc_cmd_status mc_read_response(struct mc_command __iomem * +- portal, +- struct mc_command *resp) +-{ +- int i; +- enum mc_cmd_status status; +- +- /* Copy command response header from MC portal: */ +- __iormb(); +- resp->header = __raw_readq(&portal->header); +- __iormb(); +- status = mc_cmd_hdr_read_status(resp); +- if (status != MC_CMD_STATUS_OK) +- return status; +- +- /* Copy command response data from MC portal: */ +- for (i = 0; i < MC_CMD_NUM_OF_PARAMS; i++) +- resp->params[i] = __raw_readq(&portal->params[i]); +- __iormb(); +- +- return status; +-} +- +-/** +- * Waits for the completion of an MC command doing preemptible polling. +- * uslepp_range() is called between polling iterations. +- * +- * @mc_io: MC I/O object to be used +- * @cmd: command buffer to receive MC response +- * @mc_status: MC command completion status +- */ +-static int mc_polling_wait_preemptible(struct fsl_mc_io *mc_io, +- struct mc_command *cmd, +- enum mc_cmd_status *mc_status) +-{ +- enum mc_cmd_status status; +- unsigned long jiffies_until_timeout = +- jiffies + msecs_to_jiffies(MC_CMD_COMPLETION_TIMEOUT_MS); +- +- /* +- * Wait for response from the MC hardware: +- */ +- for (;;) { +- status = mc_read_response(mc_io->portal_virt_addr, cmd); +- if (status != MC_CMD_STATUS_READY) +- break; +- +- /* +- * TODO: When MC command completion interrupts are supported +- * call wait function here instead of usleep_range() +- */ +- usleep_range(MC_CMD_COMPLETION_POLLING_MIN_SLEEP_USECS, +- MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS); +- +- if (time_after_eq(jiffies, jiffies_until_timeout)) { +- dev_dbg(mc_io->dev, +- "MC command timed out (portal: %#llx, obj handle: %#x, command: %#x)\n", +- mc_io->portal_phys_addr, +- (unsigned int)mc_cmd_hdr_read_token(cmd), +- (unsigned int)mc_cmd_hdr_read_cmdid(cmd)); +- +- return -ETIMEDOUT; +- } +- } +- +- *mc_status = status; +- return 0; +-} +- +-/** +- * Waits for the completion of an MC command doing atomic polling. +- * udelay() is called between polling iterations. +- * +- * @mc_io: MC I/O object to be used +- * @cmd: command buffer to receive MC response +- * @mc_status: MC command completion status +- */ +-static int mc_polling_wait_atomic(struct fsl_mc_io *mc_io, +- struct mc_command *cmd, +- enum mc_cmd_status *mc_status) +-{ +- enum mc_cmd_status status; +- unsigned long timeout_usecs = MC_CMD_COMPLETION_TIMEOUT_MS * 1000; +- +- BUILD_BUG_ON((MC_CMD_COMPLETION_TIMEOUT_MS * 1000) % +- MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS != 0); +- +- for (;;) { +- status = mc_read_response(mc_io->portal_virt_addr, cmd); +- if (status != MC_CMD_STATUS_READY) +- break; +- +- udelay(MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS); +- timeout_usecs -= MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS; +- if (timeout_usecs == 0) { +- dev_dbg(mc_io->dev, +- "MC command timed out (portal: %#llx, obj handle: %#x, command: %#x)\n", +- mc_io->portal_phys_addr, +- (unsigned int)mc_cmd_hdr_read_token(cmd), +- (unsigned int)mc_cmd_hdr_read_cmdid(cmd)); +- +- return -ETIMEDOUT; +- } +- } +- +- *mc_status = status; +- return 0; +-} +- +-/** +- * Sends a command to the MC device using the given MC I/O object +- * +- * @mc_io: MC I/O object to be used +- * @cmd: command to be sent +- * +- * Returns '0' on Success; Error code otherwise. +- */ +-int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd) +-{ +- int error; +- enum mc_cmd_status status; +- unsigned long irq_flags = 0; +- +- if (WARN_ON(in_irq() && +- !(mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL))) +- return -EINVAL; +- +- if (mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL) +- spin_lock_irqsave(&mc_io->spinlock, irq_flags); +- else +- mutex_lock(&mc_io->mutex); +- +- /* +- * Send command to the MC hardware: +- */ +- mc_write_command(mc_io->portal_virt_addr, cmd); +- +- /* +- * Wait for response from the MC hardware: +- */ +- if (!(mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)) +- error = mc_polling_wait_preemptible(mc_io, cmd, &status); +- else +- error = mc_polling_wait_atomic(mc_io, cmd, &status); +- +- if (error < 0) +- goto common_exit; +- +- if (status != MC_CMD_STATUS_OK) { +- dev_dbg(mc_io->dev, +- "MC command failed: portal: %#llx, obj handle: %#x, command: %#x, status: %s (%#x)\n", +- mc_io->portal_phys_addr, +- (unsigned int)mc_cmd_hdr_read_token(cmd), +- (unsigned int)mc_cmd_hdr_read_cmdid(cmd), +- mc_status_to_string(status), +- (unsigned int)status); +- +- error = mc_status_to_error(status); +- goto common_exit; +- } +- +- error = 0; +-common_exit: +- if (mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL) +- spin_unlock_irqrestore(&mc_io->spinlock, irq_flags); +- else +- mutex_unlock(&mc_io->mutex); +- +- return error; +-} +-EXPORT_SYMBOL(mc_send_command); +--- /dev/null ++++ b/drivers/bus/fsl-mc/mc-sys.c +@@ -0,0 +1,296 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ * I/O services to send MC commands to the MC hardware ++ * ++ */ ++ ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/ioport.h> ++#include <linux/device.h> ++#include <linux/io.h> ++#include <linux/io-64-nonatomic-hi-lo.h> ++#include <linux/fsl/mc.h> ++ ++#include "fsl-mc-private.h" ++ ++/** ++ * Timeout in milliseconds to wait for the completion of an MC command ++ */ ++#define MC_CMD_COMPLETION_TIMEOUT_MS 15000 + -+#include "dpbp-cmd.h" ++/* ++ * usleep_range() min and max values used to throttle down polling ++ * iterations while waiting for MC command completion ++ */ ++#define MC_CMD_COMPLETION_POLLING_MIN_SLEEP_USECS 10 ++#define MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS 500 ++ ++static enum mc_cmd_status mc_cmd_hdr_read_status(struct fsl_mc_command *cmd) ++{ ++ struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header; ++ ++ return (enum mc_cmd_status)hdr->status; ++} ++ ++static u16 mc_cmd_hdr_read_cmdid(struct fsl_mc_command *cmd) ++{ ++ struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header; ++ u16 cmd_id = le16_to_cpu(hdr->cmd_id); ++ ++ return cmd_id; ++} ++ ++static int mc_status_to_error(enum mc_cmd_status status) ++{ ++ static const int mc_status_to_error_map[] = { ++ [MC_CMD_STATUS_OK] = 0, ++ [MC_CMD_STATUS_AUTH_ERR] = -EACCES, ++ [MC_CMD_STATUS_NO_PRIVILEGE] = -EPERM, ++ [MC_CMD_STATUS_DMA_ERR] = -EIO, ++ [MC_CMD_STATUS_CONFIG_ERR] = -ENXIO, ++ [MC_CMD_STATUS_TIMEOUT] = -ETIMEDOUT, ++ [MC_CMD_STATUS_NO_RESOURCE] = -ENAVAIL, ++ [MC_CMD_STATUS_NO_MEMORY] = -ENOMEM, ++ [MC_CMD_STATUS_BUSY] = -EBUSY, ++ [MC_CMD_STATUS_UNSUPPORTED_OP] = -ENOTSUPP, ++ [MC_CMD_STATUS_INVALID_STATE] = -ENODEV, ++ }; ++ ++ if ((u32)status >= ARRAY_SIZE(mc_status_to_error_map)) ++ return -EINVAL; ++ ++ return mc_status_to_error_map[status]; ++} ++ ++static const char *mc_status_to_string(enum mc_cmd_status status) ++{ ++ static const char *const status_strings[] = { ++ [MC_CMD_STATUS_OK] = "Command completed successfully", ++ [MC_CMD_STATUS_READY] = "Command ready to be processed", ++ [MC_CMD_STATUS_AUTH_ERR] = "Authentication error", ++ [MC_CMD_STATUS_NO_PRIVILEGE] = "No privilege", ++ [MC_CMD_STATUS_DMA_ERR] = "DMA or I/O error", ++ [MC_CMD_STATUS_CONFIG_ERR] = "Configuration error", ++ [MC_CMD_STATUS_TIMEOUT] = "Operation timed out", ++ [MC_CMD_STATUS_NO_RESOURCE] = "No resources", ++ [MC_CMD_STATUS_NO_MEMORY] = "No memory available", ++ [MC_CMD_STATUS_BUSY] = "Device is busy", ++ [MC_CMD_STATUS_UNSUPPORTED_OP] = "Unsupported operation", ++ [MC_CMD_STATUS_INVALID_STATE] = "Invalid state" ++ }; ++ ++ if ((unsigned int)status >= ARRAY_SIZE(status_strings)) ++ return "Unknown MC error"; ++ ++ return status_strings[status]; ++} ++ ++/** ++ * mc_write_command - writes a command to a Management Complex (MC) portal ++ * ++ * @portal: pointer to an MC portal ++ * @cmd: pointer to a filled command ++ */ ++static inline void mc_write_command(struct fsl_mc_command __iomem *portal, ++ struct fsl_mc_command *cmd) ++{ ++ int i; ++ ++ /* copy command parameters into the portal */ ++ for (i = 0; i < MC_CMD_NUM_OF_PARAMS; i++) ++ /* ++ * Data is already in the expected LE byte-order. Do an ++ * extra LE -> CPU conversion so that the CPU -> LE done in ++ * the device io write api puts it back in the right order. ++ */ ++ writeq_relaxed(le64_to_cpu(cmd->params[i]), &portal->params[i]); ++ ++ /* submit the command by writing the header */ ++ writeq(le64_to_cpu(cmd->header), &portal->header); ++} ++ ++/** ++ * mc_read_response - reads the response for the last MC command from a ++ * Management Complex (MC) portal ++ * ++ * @portal: pointer to an MC portal ++ * @resp: pointer to command response buffer ++ * ++ * Returns MC_CMD_STATUS_OK on Success; Error code otherwise. ++ */ ++static inline enum mc_cmd_status mc_read_response(struct fsl_mc_command __iomem ++ *portal, ++ struct fsl_mc_command *resp) ++{ ++ int i; ++ enum mc_cmd_status status; ++ ++ /* Copy command response header from MC portal: */ ++ resp->header = cpu_to_le64(readq_relaxed(&portal->header)); ++ status = mc_cmd_hdr_read_status(resp); ++ if (status != MC_CMD_STATUS_OK) ++ return status; ++ ++ /* Copy command response data from MC portal: */ ++ for (i = 0; i < MC_CMD_NUM_OF_PARAMS; i++) ++ /* ++ * Data is expected to be in LE byte-order. Do an ++ * extra CPU -> LE to revert the LE -> CPU done in ++ * the device io read api. ++ */ ++ resp->params[i] = ++ cpu_to_le64(readq_relaxed(&portal->params[i])); ++ ++ return status; ++} ++ ++/** ++ * Waits for the completion of an MC command doing preemptible polling. ++ * uslepp_range() is called between polling iterations. ++ * ++ * @mc_io: MC I/O object to be used ++ * @cmd: command buffer to receive MC response ++ * @mc_status: MC command completion status ++ */ ++static int mc_polling_wait_preemptible(struct fsl_mc_io *mc_io, ++ struct fsl_mc_command *cmd, ++ enum mc_cmd_status *mc_status) ++{ ++ enum mc_cmd_status status; ++ unsigned long jiffies_until_timeout = ++ jiffies + msecs_to_jiffies(MC_CMD_COMPLETION_TIMEOUT_MS); ++ ++ /* ++ * Wait for response from the MC hardware: ++ */ ++ for (;;) { ++ status = mc_read_response(mc_io->portal_virt_addr, cmd); ++ if (status != MC_CMD_STATUS_READY) ++ break; ++ ++ /* ++ * TODO: When MC command completion interrupts are supported ++ * call wait function here instead of usleep_range() ++ */ ++ usleep_range(MC_CMD_COMPLETION_POLLING_MIN_SLEEP_USECS, ++ MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS); ++ ++ if (time_after_eq(jiffies, jiffies_until_timeout)) { ++ dev_dbg(mc_io->dev, ++ "MC command timed out (portal: %pa, dprc handle: %#x, command: %#x)\n", ++ &mc_io->portal_phys_addr, ++ (unsigned int)mc_cmd_hdr_read_token(cmd), ++ (unsigned int)mc_cmd_hdr_read_cmdid(cmd)); ++ ++ return -ETIMEDOUT; ++ } ++ } ++ ++ *mc_status = status; ++ return 0; ++} ++ ++/** ++ * Waits for the completion of an MC command doing atomic polling. ++ * udelay() is called between polling iterations. ++ * ++ * @mc_io: MC I/O object to be used ++ * @cmd: command buffer to receive MC response ++ * @mc_status: MC command completion status ++ */ ++static int mc_polling_wait_atomic(struct fsl_mc_io *mc_io, ++ struct fsl_mc_command *cmd, ++ enum mc_cmd_status *mc_status) ++{ ++ enum mc_cmd_status status; ++ unsigned long timeout_usecs = MC_CMD_COMPLETION_TIMEOUT_MS * 1000; ++ ++ BUILD_BUG_ON((MC_CMD_COMPLETION_TIMEOUT_MS * 1000) % ++ MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS != 0); ++ ++ for (;;) { ++ status = mc_read_response(mc_io->portal_virt_addr, cmd); ++ if (status != MC_CMD_STATUS_READY) ++ break; ++ ++ udelay(MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS); ++ timeout_usecs -= MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS; ++ if (timeout_usecs == 0) { ++ dev_dbg(mc_io->dev, ++ "MC command timed out (portal: %pa, dprc handle: %#x, command: %#x)\n", ++ &mc_io->portal_phys_addr, ++ (unsigned int)mc_cmd_hdr_read_token(cmd), ++ (unsigned int)mc_cmd_hdr_read_cmdid(cmd)); ++ ++ return -ETIMEDOUT; ++ } ++ } ++ ++ *mc_status = status; ++ return 0; ++} ++ ++/** ++ * Sends a command to the MC device using the given MC I/O object ++ * ++ * @mc_io: MC I/O object to be used ++ * @cmd: command to be sent ++ * ++ * Returns '0' on Success; Error code otherwise. ++ */ ++int mc_send_command(struct fsl_mc_io *mc_io, struct fsl_mc_command *cmd) ++{ ++ int error; ++ enum mc_cmd_status status; ++ unsigned long irq_flags = 0; ++ ++ if (in_irq() && !(mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)) ++ return -EINVAL; ++ ++ if (mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL) ++ spin_lock_irqsave(&mc_io->spinlock, irq_flags); ++ else ++ mutex_lock(&mc_io->mutex); ++ ++ /* ++ * Send command to the MC hardware: ++ */ ++ mc_write_command(mc_io->portal_virt_addr, cmd); ++ ++ /* ++ * Wait for response from the MC hardware: ++ */ ++ if (!(mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)) ++ error = mc_polling_wait_preemptible(mc_io, cmd, &status); ++ else ++ error = mc_polling_wait_atomic(mc_io, cmd, &status); ++ ++ if (error < 0) ++ goto common_exit; ++ ++ if (status != MC_CMD_STATUS_OK) { ++ dev_dbg(mc_io->dev, ++ "MC command failed: portal: %pa, dprc handle: %#x, command: %#x, status: %s (%#x)\n", ++ &mc_io->portal_phys_addr, ++ (unsigned int)mc_cmd_hdr_read_token(cmd), ++ (unsigned int)mc_cmd_hdr_read_cmdid(cmd), ++ mc_status_to_string(status), ++ (unsigned int)status); ++ ++ error = mc_status_to_error(status); ++ goto common_exit; ++ } ++ ++ error = 0; ++common_exit: ++ if (mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL) ++ spin_unlock_irqrestore(&mc_io->spinlock, irq_flags); ++ else ++ mutex_unlock(&mc_io->mutex); ++ ++ return error; ++} ++EXPORT_SYMBOL_GPL(mc_send_command); +--- a/drivers/irqchip/Kconfig ++++ b/drivers/irqchip/Kconfig +@@ -41,6 +41,12 @@ config ARM_GIC_V3_ITS + depends on PCI_MSI + select ACPI_IORT if ACPI - /** - * dpbp_open() - Open a control session for the specified object. -@@ -105,74 +106,6 @@ int dpbp_close(struct fsl_mc_io *mc_io, - EXPORT_SYMBOL(dpbp_close); ++config ARM_GIC_V3_ITS_FSL_MC ++ bool ++ depends on ARM_GIC_V3_ITS ++ depends on FSL_MC_BUS ++ default ARM_GIC_V3_ITS ++ + config ARM_NVIC + bool + select IRQ_DOMAIN +--- a/drivers/irqchip/Makefile ++++ b/drivers/irqchip/Makefile +@@ -29,6 +29,7 @@ obj-$(CONFIG_ARCH_REALVIEW) += irq-gic- + obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o + obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o + obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o ++obj-$(CONFIG_ARM_GIC_V3_ITS_FSL_MC) += irq-gic-v3-its-fsl-mc-msi.o + obj-$(CONFIG_PARTITION_PERCPU) += irq-partition-percpu.o + obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o + obj-$(CONFIG_ARM_NVIC) += irq-nvic.o +--- a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c ++++ /dev/null +@@ -1,126 +0,0 @@ +-/* +- * Freescale Management Complex (MC) bus driver MSI support +- * +- * Copyright (C) 2015 Freescale Semiconductor, Inc. +- * Author: German Rivera <German.Rivera@freescale.com> +- * +- * 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 <linux/of_device.h> +-#include <linux/of_address.h> +-#include <linux/irqchip/arm-gic-v3.h> +-#include <linux/irq.h> +-#include <linux/msi.h> +-#include <linux/of.h> +-#include <linux/of_irq.h> +-#include "../include/mc-bus.h" +-#include "fsl-mc-private.h" +- +-static struct irq_chip its_msi_irq_chip = { +- .name = "fsl-mc-bus-msi", +- .irq_mask = irq_chip_mask_parent, +- .irq_unmask = irq_chip_unmask_parent, +- .irq_eoi = irq_chip_eoi_parent, +- .irq_set_affinity = msi_domain_set_affinity +-}; +- +-static int its_fsl_mc_msi_prepare(struct irq_domain *msi_domain, +- struct device *dev, +- int nvec, msi_alloc_info_t *info) +-{ +- struct fsl_mc_device *mc_bus_dev; +- struct msi_domain_info *msi_info; +- +- if (WARN_ON(!dev_is_fsl_mc(dev))) +- return -EINVAL; +- +- mc_bus_dev = to_fsl_mc_device(dev); +- if (WARN_ON(!(mc_bus_dev->flags & FSL_MC_IS_DPRC))) +- return -EINVAL; +- +- /* +- * Set the device Id to be passed to the GIC-ITS: +- * +- * NOTE: This device id corresponds to the IOMMU stream ID +- * associated with the DPRC object (ICID). +- */ +- info->scratchpad[0].ul = mc_bus_dev->icid; +- msi_info = msi_get_domain_info(msi_domain->parent); +- return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info); +-} +- +-static struct msi_domain_ops its_fsl_mc_msi_ops = { +- .msi_prepare = its_fsl_mc_msi_prepare, +-}; +- +-static struct msi_domain_info its_fsl_mc_msi_domain_info = { +- .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), +- .ops = &its_fsl_mc_msi_ops, +- .chip = &its_msi_irq_chip, +-}; +- +-static const struct of_device_id its_device_id[] = { +- { .compatible = "arm,gic-v3-its", }, +- {}, +-}; +- +-int __init its_fsl_mc_msi_init(void) +-{ +- struct device_node *np; +- struct irq_domain *parent; +- struct irq_domain *mc_msi_domain; +- +- for (np = of_find_matching_node(NULL, its_device_id); np; +- np = of_find_matching_node(np, its_device_id)) { +- if (!of_device_is_available(np)) +- continue; +- if (!of_property_read_bool(np, "msi-controller")) +- continue; +- +- parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS); +- if (!parent || !msi_get_domain_info(parent)) { +- pr_err("%s: unable to locate ITS domain\n", +- np->full_name); +- continue; +- } +- +- mc_msi_domain = fsl_mc_msi_create_irq_domain( +- of_node_to_fwnode(np), +- &its_fsl_mc_msi_domain_info, +- parent); +- if (!mc_msi_domain) { +- pr_err("%s: unable to create fsl-mc domain\n", +- np->full_name); +- continue; +- } +- +- WARN_ON(mc_msi_domain-> +- host_data != &its_fsl_mc_msi_domain_info); +- +- pr_info("fsl-mc MSI: %s domain created\n", np->full_name); +- } +- +- return 0; +-} +- +-void its_fsl_mc_msi_cleanup(void) +-{ +- struct device_node *np; +- +- for (np = of_find_matching_node(NULL, its_device_id); np; +- np = of_find_matching_node(np, its_device_id)) { +- struct irq_domain *mc_msi_domain = irq_find_matching_host( +- np, +- DOMAIN_BUS_FSL_MC_MSI); +- +- if (!of_property_read_bool(np, "msi-controller")) +- continue; +- +- if (mc_msi_domain && +- mc_msi_domain->host_data == &its_fsl_mc_msi_domain_info) +- irq_domain_remove(mc_msi_domain); +- } +-} +--- /dev/null ++++ b/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c +@@ -0,0 +1,98 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Freescale Management Complex (MC) bus driver MSI support ++ * ++ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. ++ * Author: German Rivera <German.Rivera@freescale.com> ++ * ++ */ ++ ++#include <linux/of_device.h> ++#include <linux/of_address.h> ++#include <linux/irq.h> ++#include <linux/msi.h> ++#include <linux/of.h> ++#include <linux/of_irq.h> ++#include <linux/fsl/mc.h> ++ ++static struct irq_chip its_msi_irq_chip = { ++ .name = "ITS-fMSI", ++ .irq_mask = irq_chip_mask_parent, ++ .irq_unmask = irq_chip_unmask_parent, ++ .irq_eoi = irq_chip_eoi_parent, ++ .irq_set_affinity = msi_domain_set_affinity ++}; ++ ++static int its_fsl_mc_msi_prepare(struct irq_domain *msi_domain, ++ struct device *dev, ++ int nvec, msi_alloc_info_t *info) ++{ ++ struct fsl_mc_device *mc_bus_dev; ++ struct msi_domain_info *msi_info; ++ ++ if (!dev_is_fsl_mc(dev)) ++ return -EINVAL; ++ ++ mc_bus_dev = to_fsl_mc_device(dev); ++ if (!(mc_bus_dev->flags & FSL_MC_IS_DPRC)) ++ return -EINVAL; ++ ++ /* ++ * Set the device Id to be passed to the GIC-ITS: ++ * ++ * NOTE: This device id corresponds to the IOMMU stream ID ++ * associated with the DPRC object (ICID). ++ */ ++ info->scratchpad[0].ul = mc_bus_dev->icid; ++ msi_info = msi_get_domain_info(msi_domain->parent); ++ return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info); ++} ++ ++static struct msi_domain_ops its_fsl_mc_msi_ops __ro_after_init = { ++ .msi_prepare = its_fsl_mc_msi_prepare, ++}; ++ ++static struct msi_domain_info its_fsl_mc_msi_domain_info = { ++ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), ++ .ops = &its_fsl_mc_msi_ops, ++ .chip = &its_msi_irq_chip, ++}; ++ ++static const struct of_device_id its_device_id[] = { ++ { .compatible = "arm,gic-v3-its", }, ++ {}, ++}; ++ ++static int __init its_fsl_mc_msi_init(void) ++{ ++ struct device_node *np; ++ struct irq_domain *parent; ++ struct irq_domain *mc_msi_domain; ++ ++ for (np = of_find_matching_node(NULL, its_device_id); np; ++ np = of_find_matching_node(np, its_device_id)) { ++ if (!of_property_read_bool(np, "msi-controller")) ++ continue; ++ ++ parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS); ++ if (!parent || !msi_get_domain_info(parent)) { ++ pr_err("%pOF: unable to locate ITS domain\n", np); ++ continue; ++ } ++ ++ mc_msi_domain = fsl_mc_msi_create_irq_domain( ++ of_node_to_fwnode(np), ++ &its_fsl_mc_msi_domain_info, ++ parent); ++ if (!mc_msi_domain) { ++ pr_err("%pOF: unable to create fsl-mc domain\n", np); ++ continue; ++ } ++ ++ pr_info("fsl-mc MSI: %pOF domain created\n", np); ++ } ++ ++ return 0; ++} ++ ++early_initcall(its_fsl_mc_msi_init); +--- a/drivers/staging/fsl-mc/Kconfig ++++ b/drivers/staging/fsl-mc/Kconfig +@@ -1 +1,2 @@ ++# SPDX-License-Identifier: GPL-2.0 + source "drivers/staging/fsl-mc/bus/Kconfig" +--- a/drivers/staging/fsl-mc/Makefile ++++ b/drivers/staging/fsl-mc/Makefile +@@ -1,2 +1,3 @@ ++# SPDX-License-Identifier: GPL-2.0 + # Freescale Management Complex (MC) bus drivers + obj-$(CONFIG_FSL_MC_BUS) += bus/ +--- a/drivers/staging/fsl-mc/TODO ++++ /dev/null +@@ -1,18 +0,0 @@ +-* Add at least one device driver for a DPAA2 object (child device of the +- fsl-mc bus). Most likely candidate for this is adding DPAA2 Ethernet +- driver support, which depends on drivers for several objects: DPNI, +- DPIO, DPMAC. Other pre-requisites include: +- +- * MC firmware uprev. The MC firmware upon which the fsl-mc +- bus driver and DPAA2 object drivers are based is continuing +- to evolve, so minor updates are needed to keep in sync with binary +- interface changes to the MC. +- +-* Cleanup +- +-Please send any patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org>, +-german.rivera@freescale.com, devel@driverdev.osuosl.org, +-linux-kernel@vger.kernel.org +- +-[1] https://lkml.org/lkml/2015/7/9/93 +-[2] https://lkml.org/lkml/2015/7/7/712 +--- a/drivers/staging/fsl-mc/bus/Kconfig ++++ b/drivers/staging/fsl-mc/bus/Kconfig +@@ -1,25 +1,22 @@ ++# SPDX-License-Identifier: GPL-2.0 + # +-# Freescale Management Complex (MC) bus drivers ++# DPAA2 fsl-mc bus + # +-# Copyright (C) 2014 Freescale Semiconductor, Inc. ++# Copyright (C) 2014-2016 Freescale Semiconductor, Inc. + # +-# This file is released under the GPLv2 +-# +- +-config FSL_MC_BUS +- bool "Freescale Management Complex (MC) bus driver" +- depends on OF && ARM64 +- select GENERIC_MSI_IRQ_DOMAIN +- help +- Driver to enable the bus infrastructure for the Freescale +- QorIQ Management Complex (fsl-mc). The fsl-mc is a hardware +- module of the QorIQ LS2 SoCs, that does resource management +- for hardware building-blocks in the SoC that can be used +- to dynamically create networking hardware objects such as +- network interfaces (NICs), crypto accelerator instances, +- or L2 switches. +- +- Only enable this option when building the kernel for +- Freescale QorQIQ LS2xxxx SoCs. + ++config FSL_MC_DPIO ++ tristate "QorIQ DPAA2 DPIO driver" ++ depends on FSL_MC_BUS ++ help ++ Driver for the DPAA2 DPIO object. A DPIO provides queue and ++ buffer management facilities for software to interact with ++ other DPAA2 objects. This driver does not expose the DPIO ++ objects individually, but groups them under a service layer ++ API. + ++config FSL_QBMAN_DEBUG ++ tristate "Freescale QBMAN Debug APIs" ++ depends on FSL_MC_DPIO ++ help ++ QBMan debug assistant APIs. +--- a/drivers/staging/fsl-mc/bus/Makefile ++++ b/drivers/staging/fsl-mc/bus/Makefile +@@ -1,20 +1,9 @@ ++# SPDX-License-Identifier: GPL-2.0 + # + # Freescale Management Complex (MC) bus drivers + # + # Copyright (C) 2014 Freescale Semiconductor, Inc. + # +-# This file is released under the GPLv2 +-# +-obj-$(CONFIG_FSL_MC_BUS) += mc-bus-driver.o - /** +-mc-bus-driver-objs := fsl-mc-bus.o \ +- mc-sys.o \ +- mc-io.o \ +- dprc.o \ +- dpmng.o \ +- dprc-driver.o \ +- fsl-mc-allocator.o \ +- fsl-mc-msi.o \ +- irq-gic-v3-its-fsl-mc-msi.o \ +- dpmcp.o \ +- dpbp.o ++# MC DPIO driver ++obj-$(CONFIG_FSL_MC_DPIO) += dpio/ +--- a/drivers/staging/fsl-mc/bus/dpbp.c ++++ /dev/null +@@ -1,691 +0,0 @@ +-/* Copyright 2013-2016 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 the above-listed copyright holders nor the +- * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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/mc-sys.h" +-#include "../include/mc-cmd.h" +-#include "../include/dpbp.h" +-#include "../include/dpbp-cmd.h" +- +-/** +- * dpbp_open() - Open a control session for the specified object. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @dpbp_id: DPBP unique ID +- * @token: Returned token; use in subsequent API calls +- * +- * This function can be used to open a control session for an +- * already created object; an object may have been declared in +- * the DPL or by calling the dpbp_create function. +- * This function returns a unique authentication token, +- * associated with the specific object ID and the specific MC +- * portal; this token must be used in all subsequent commands for +- * this specific object +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpbp_open(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- int dpbp_id, +- u16 *token) +-{ +- struct mc_command cmd = { 0 }; +- struct dpbp_cmd_open *cmd_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_OPEN, +- cmd_flags, 0); +- cmd_params = (struct dpbp_cmd_open *)cmd.params; +- cmd_params->dpbp_id = cpu_to_le32(dpbp_id); +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- *token = mc_cmd_hdr_read_token(&cmd); +- +- return err; +-} +-EXPORT_SYMBOL(dpbp_open); +- +-/** +- * dpbp_close() - Close the control session of the object +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPBP object +- * +- * After this function is called, no further operations are +- * allowed on the object without opening a new control session. +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpbp_close(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token) +-{ +- struct mc_command cmd = { 0 }; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_CLOSE, cmd_flags, +- token); +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +-EXPORT_SYMBOL(dpbp_close); +- +-/** - * dpbp_create() - Create the DPBP object. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' @@ -346,21 +9664,105 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> -} - -/** - * dpbp_enable() - Enable the DPBP. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' -@@ -250,6 +183,7 @@ int dpbp_is_enabled(struct fsl_mc_io *mc - - return 0; - } -+EXPORT_SYMBOL(dpbp_is_enabled); - - /** - * dpbp_reset() - Reset the DPBP, returns the object to initial state. -@@ -272,310 +206,7 @@ int dpbp_reset(struct fsl_mc_io *mc_io, - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); - } +- * dpbp_enable() - Enable the DPBP. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPBP object +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpbp_enable(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token) +-{ +- struct mc_command cmd = { 0 }; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_ENABLE, cmd_flags, +- token); +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +-EXPORT_SYMBOL(dpbp_enable); +- +-/** +- * dpbp_disable() - Disable the DPBP. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPBP object +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpbp_disable(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token) +-{ +- struct mc_command cmd = { 0 }; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_DISABLE, +- cmd_flags, token); +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +-EXPORT_SYMBOL(dpbp_disable); +- +-/** +- * dpbp_is_enabled() - Check if the DPBP is enabled. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPBP object +- * @en: Returns '1' if object is enabled; '0' otherwise +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpbp_is_enabled(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int *en) +-{ +- struct mc_command cmd = { 0 }; +- struct dpbp_rsp_is_enabled *rsp_params; +- int err; +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_IS_ENABLED, cmd_flags, +- token); +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dpbp_rsp_is_enabled *)cmd.params; +- *en = rsp_params->enabled & DPBP_ENABLE; +- +- return 0; +-} +- +-/** +- * dpbp_reset() - Reset the DPBP, returns the object to initial state. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPBP object +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpbp_reset(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token) +-{ +- struct mc_command cmd = { 0 }; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_RESET, +- cmd_flags, token); +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} - -/** - * dpbp_set_irq() - Set IRQ information for the DPBP to trigger an interrupt. @@ -665,44 +10067,61 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} -+EXPORT_SYMBOL(dpbp_reset); - - /** - * dpbp_get_attributes - Retrieve DPBP attributes. -@@ -609,83 +240,40 @@ int dpbp_get_attributes(struct fsl_mc_io - rsp_params = (struct dpbp_rsp_get_attributes *)cmd.params; - attr->bpid = le16_to_cpu(rsp_params->bpid); - attr->id = le32_to_cpu(rsp_params->id); +- +-/** +- * dpbp_get_attributes - Retrieve DPBP attributes. +- * +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPBP object +- * @attr: Returned object's attributes +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpbp_get_attributes(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- struct dpbp_attr *attr) +-{ +- struct mc_command cmd = { 0 }; +- struct dpbp_rsp_get_attributes *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_ATTR, +- cmd_flags, token); +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dpbp_rsp_get_attributes *)cmd.params; +- attr->bpid = le16_to_cpu(rsp_params->bpid); +- attr->id = le32_to_cpu(rsp_params->id); - attr->version.major = le16_to_cpu(rsp_params->version_major); - attr->version.minor = le16_to_cpu(rsp_params->version_minor); - - return 0; - } - EXPORT_SYMBOL(dpbp_get_attributes); - - /** +- +- return 0; +-} +-EXPORT_SYMBOL(dpbp_get_attributes); +- +-/** - * dpbp_set_notifications() - Set notifications towards software - * @mc_io: Pointer to MC portal's I/O object -+ * dpbp_get_api_version - Get Data Path Buffer Pool API version -+ * @mc_io: Pointer to Mc portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPBP object - * @cfg: notifications configuration -+ * @major_ver: Major version of Buffer Pool API -+ * @minor_ver: Minor version of Buffer Pool API - * - * Return: '0' on Success; Error code otherwise. - */ +- * +- * Return: '0' on Success; Error code otherwise. +- */ -int dpbp_set_notifications(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - struct dpbp_notification_cfg *cfg) -+int dpbp_get_api_version(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 *major_ver, -+ u16 *minor_ver) - { - struct mc_command cmd = { 0 }; +-{ +- struct mc_command cmd = { 0 }; - struct dpbp_cmd_set_notifications *cmd_params; - - /* prepare command */ @@ -737,22 +10156,19 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> -{ - struct mc_command cmd = { 0 }; - struct dpbp_rsp_get_notifications *rsp_params; - int err; - - /* prepare command */ +- int err; +- +- /* prepare command */ - cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_NOTIFICATIONS, - cmd_flags, - token); -+ cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_API_VERSION, -+ cmd_flags, 0); - +- - /* send command to mc*/ -+ /* send command to mc */ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ - rsp_params = (struct dpbp_rsp_get_notifications *)cmd.params; - cfg->depletion_entry = le32_to_cpu(rsp_params->depletion_entry); - cfg->depletion_exit = le32_to_cpu(rsp_params->depletion_exit); @@ -761,532 +10177,28 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - cfg->options = le16_to_cpu(rsp_params->options); - cfg->message_ctx = le64_to_cpu(rsp_params->message_ctx); - cfg->message_iova = le64_to_cpu(rsp_params->message_iova); -+ mc_cmd_read_api_version(&cmd, major_ver, minor_ver); - - return 0; - } -+EXPORT_SYMBOL(dpbp_get_api_version); ---- /dev/null -+++ b/drivers/staging/fsl-mc/bus/dpcon-cmd.h -@@ -0,0 +1,85 @@ -+/* -+ * Copyright 2013-2016 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 the above-listed copyright holders nor the -+ * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. -+ */ -+#ifndef _FSL_DPCON_CMD_H -+#define _FSL_DPCON_CMD_H -+ -+/* DPCON Version */ -+#define DPCON_VER_MAJOR 3 -+#define DPCON_VER_MINOR 2 -+ -+/* Command versioning */ -+#define DPCON_CMD_BASE_VERSION 1 -+#define DPCON_CMD_ID_OFFSET 4 -+ -+#define DPCON_CMD(id) (((id) << DPCON_CMD_ID_OFFSET) | DPCON_CMD_BASE_VERSION) -+ -+/* Command IDs */ -+#define DPCON_CMDID_CLOSE DPCON_CMD(0x800) -+#define DPCON_CMDID_OPEN DPCON_CMD(0x808) -+#define DPCON_CMDID_GET_API_VERSION DPCON_CMD(0xa08) -+ -+#define DPCON_CMDID_ENABLE DPCON_CMD(0x002) -+#define DPCON_CMDID_DISABLE DPCON_CMD(0x003) -+#define DPCON_CMDID_GET_ATTR DPCON_CMD(0x004) -+#define DPCON_CMDID_RESET DPCON_CMD(0x005) -+#define DPCON_CMDID_IS_ENABLED DPCON_CMD(0x006) -+ -+#define DPCON_CMDID_SET_NOTIFICATION DPCON_CMD(0x100) -+ -+struct dpcon_cmd_open { -+ __le32 dpcon_id; -+}; -+ -+#define DPCON_ENABLE 1 -+ -+struct dpcon_rsp_is_enabled { -+ u8 enabled; -+}; -+ -+struct dpcon_rsp_get_attr { -+ /* response word 0 */ -+ __le32 id; -+ __le16 qbman_ch_id; -+ u8 num_priorities; -+ u8 pad; -+}; -+ -+struct dpcon_cmd_set_notification { -+ /* cmd word 0 */ -+ __le32 dpio_id; -+ u8 priority; -+ u8 pad[3]; -+ /* cmd word 1 */ -+ __le64 user_ctx; -+}; -+ -+#endif /* _FSL_DPCON_CMD_H */ ---- /dev/null -+++ b/drivers/staging/fsl-mc/bus/dpcon.c -@@ -0,0 +1,317 @@ -+/* Copyright 2013-2016 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 the above-listed copyright holders nor the -+ * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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/mc-sys.h" -+#include "../include/mc-cmd.h" -+#include "../include/dpcon.h" -+ -+#include "dpcon-cmd.h" -+ -+/** -+ * dpcon_open() - Open a control session for the specified object -+ * @mc_io: Pointer to MC portal's I/O object -+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' -+ * @dpcon_id: DPCON unique ID -+ * @token: Returned token; use in subsequent API calls -+ * -+ * This function can be used to open a control session for an -+ * already created object; an object may have been declared in -+ * the DPL or by calling the dpcon_create() function. -+ * This function returns a unique authentication token, -+ * associated with the specific object ID and the specific MC -+ * portal; this token must be used in all subsequent commands for -+ * this specific object. -+ * -+ * Return: '0' on Success; Error code otherwise. -+ */ -+int dpcon_open(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ int dpcon_id, -+ u16 *token) -+{ -+ struct mc_command cmd = { 0 }; -+ struct dpcon_cmd_open *dpcon_cmd; -+ int err; -+ -+ /* prepare command */ -+ cmd.header = mc_encode_cmd_header(DPCON_CMDID_OPEN, -+ cmd_flags, -+ 0); -+ dpcon_cmd = (struct dpcon_cmd_open *)cmd.params; -+ dpcon_cmd->dpcon_id = cpu_to_le32(dpcon_id); -+ -+ /* send command to mc*/ -+ err = mc_send_command(mc_io, &cmd); -+ if (err) -+ return err; -+ -+ /* retrieve response parameters */ -+ *token = mc_cmd_hdr_read_token(&cmd); -+ -+ return 0; -+} -+EXPORT_SYMBOL(dpcon_open); -+ -+/** -+ * dpcon_close() - Close the control session of the object -+ * @mc_io: Pointer to MC portal's I/O object -+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' -+ * @token: Token of DPCON object -+ * -+ * After this function is called, no further operations are -+ * allowed on the object without opening a new control session. -+ * -+ * Return: '0' on Success; Error code otherwise. -+ */ -+int dpcon_close(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token) -+{ -+ struct mc_command cmd = { 0 }; -+ -+ /* prepare command */ -+ cmd.header = mc_encode_cmd_header(DPCON_CMDID_CLOSE, -+ cmd_flags, -+ token); -+ -+ /* send command to mc*/ -+ return mc_send_command(mc_io, &cmd); -+} -+EXPORT_SYMBOL(dpcon_close); -+ -+/** -+ * dpcon_enable() - Enable the DPCON -+ * @mc_io: Pointer to MC portal's I/O object -+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' -+ * @token: Token of DPCON object -+ * -+ * Return: '0' on Success; Error code otherwise -+ */ -+int dpcon_enable(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token) -+{ -+ struct mc_command cmd = { 0 }; -+ -+ /* prepare command */ -+ cmd.header = mc_encode_cmd_header(DPCON_CMDID_ENABLE, -+ cmd_flags, -+ token); -+ -+ /* send command to mc*/ -+ return mc_send_command(mc_io, &cmd); -+} -+EXPORT_SYMBOL(dpcon_enable); -+ -+/** -+ * dpcon_disable() - Disable the DPCON -+ * @mc_io: Pointer to MC portal's I/O object -+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' -+ * @token: Token of DPCON object -+ * -+ * Return: '0' on Success; Error code otherwise -+ */ -+int dpcon_disable(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token) -+{ -+ struct mc_command cmd = { 0 }; -+ -+ /* prepare command */ -+ cmd.header = mc_encode_cmd_header(DPCON_CMDID_DISABLE, -+ cmd_flags, -+ token); -+ -+ /* send command to mc*/ -+ return mc_send_command(mc_io, &cmd); -+} -+EXPORT_SYMBOL(dpcon_disable); -+ -+/** -+ * dpcon_is_enabled() - Check if the DPCON is enabled. -+ * @mc_io: Pointer to MC portal's I/O object -+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' -+ * @token: Token of DPCON object -+ * @en: Returns '1' if object is enabled; '0' otherwise -+ * -+ * Return: '0' on Success; Error code otherwise. -+ */ -+int dpcon_is_enabled(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ int *en) -+{ -+ struct mc_command cmd = { 0 }; -+ struct dpcon_rsp_is_enabled *dpcon_rsp; -+ int err; -+ -+ /* prepare command */ -+ cmd.header = mc_encode_cmd_header(DPCON_CMDID_IS_ENABLED, -+ cmd_flags, -+ token); -+ -+ /* send command to mc*/ -+ err = mc_send_command(mc_io, &cmd); -+ if (err) -+ return err; -+ -+ /* retrieve response parameters */ -+ dpcon_rsp = (struct dpcon_rsp_is_enabled *)cmd.params; -+ *en = dpcon_rsp->enabled & DPCON_ENABLE; -+ -+ return 0; -+} -+EXPORT_SYMBOL(dpcon_is_enabled); -+ -+/** -+ * dpcon_reset() - Reset the DPCON, returns the object to initial state. -+ * @mc_io: Pointer to MC portal's I/O object -+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' -+ * @token: Token of DPCON object -+ * -+ * Return: '0' on Success; Error code otherwise. -+ */ -+int dpcon_reset(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token) -+{ -+ struct mc_command cmd = { 0 }; -+ -+ /* prepare command */ -+ cmd.header = mc_encode_cmd_header(DPCON_CMDID_RESET, -+ cmd_flags, token); -+ -+ /* send command to mc*/ -+ return mc_send_command(mc_io, &cmd); -+} -+EXPORT_SYMBOL(dpcon_reset); -+ -+/** -+ * dpcon_get_attributes() - Retrieve DPCON attributes. -+ * @mc_io: Pointer to MC portal's I/O object -+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' -+ * @token: Token of DPCON object -+ * @attr: Object's attributes -+ * -+ * Return: '0' on Success; Error code otherwise. -+ */ -+int dpcon_get_attributes(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ struct dpcon_attr *attr) -+{ -+ struct mc_command cmd = { 0 }; -+ struct dpcon_rsp_get_attr *dpcon_rsp; -+ int err; -+ -+ /* prepare command */ -+ cmd.header = mc_encode_cmd_header(DPCON_CMDID_GET_ATTR, -+ cmd_flags, -+ token); -+ -+ /* send command to mc*/ -+ err = mc_send_command(mc_io, &cmd); -+ if (err) -+ return err; -+ -+ /* retrieve response parameters */ -+ dpcon_rsp = (struct dpcon_rsp_get_attr *)cmd.params; -+ attr->id = le32_to_cpu(dpcon_rsp->id); -+ attr->qbman_ch_id = le16_to_cpu(dpcon_rsp->qbman_ch_id); -+ attr->num_priorities = dpcon_rsp->num_priorities; -+ -+ return 0; -+} -+EXPORT_SYMBOL(dpcon_get_attributes); -+ -+/** -+ * dpcon_set_notification() - Set DPCON notification destination -+ * @mc_io: Pointer to MC portal's I/O object -+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' -+ * @token: Token of DPCON object -+ * @cfg: Notification parameters -+ * -+ * Return: '0' on Success; Error code otherwise -+ */ -+int dpcon_set_notification(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ struct dpcon_notification_cfg *cfg) -+{ -+ struct mc_command cmd = { 0 }; -+ struct dpcon_cmd_set_notification *dpcon_cmd; -+ -+ /* prepare command */ -+ cmd.header = mc_encode_cmd_header(DPCON_CMDID_SET_NOTIFICATION, -+ cmd_flags, -+ token); -+ dpcon_cmd = (struct dpcon_cmd_set_notification *)cmd.params; -+ dpcon_cmd->dpio_id = cpu_to_le32(cfg->dpio_id); -+ dpcon_cmd->priority = cfg->priority; -+ dpcon_cmd->user_ctx = cpu_to_le64(cfg->user_ctx); -+ -+ /* send command to mc*/ -+ return mc_send_command(mc_io, &cmd); -+} -+EXPORT_SYMBOL(dpcon_set_notification); -+ -+/** -+ * dpcon_get_api_version - Get Data Path Concentrator API version -+ * @mc_io: Pointer to MC portal's DPCON object -+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' -+ * @major_ver: Major version of DPCON API -+ * @minor_ver: Minor version of DPCON API -+ * -+ * Return: '0' on Success; Error code otherwise -+ */ -+int dpcon_get_api_version(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 *major_ver, -+ u16 *minor_ver) -+{ -+ struct mc_command cmd = { 0 }; -+ int err; -+ -+ /* prepare command */ -+ cmd.header = mc_encode_cmd_header(DPCON_CMDID_GET_API_VERSION, -+ cmd_flags, 0); -+ -+ /* send command to mc */ -+ err = mc_send_command(mc_io, &cmd); -+ if (err) -+ return err; -+ -+ /* retrieve response parameters */ -+ mc_cmd_read_api_version(&cmd, major_ver, minor_ver); -+ -+ return 0; -+} -+EXPORT_SYMBOL(dpcon_get_api_version); +- +- return 0; +-} --- /dev/null +++ b/drivers/staging/fsl-mc/bus/dpio/Makefile -@@ -0,0 +1,11 @@ +@@ -0,0 +1,8 @@ ++# SPDX-License-Identifier: GPL-2.0 +# +# QorIQ DPAA2 DPIO driver +# + -+subdir-ccflags-y := -Werror -+ +obj-$(CONFIG_FSL_MC_DPIO) += fsl-mc-dpio.o + +fsl-mc-dpio-objs := dpio.o qbman-portal.o dpio-service.o dpio-driver.o -+ -+obj-$(CONFIG_FSL_QBMAN_DEBUG) += qbman_debug.o ---- a/drivers/staging/fsl-mc/include/dpcon-cmd.h -+++ /dev/null -@@ -1,62 +0,0 @@ --/* Copyright 2013-2015 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 the above-listed copyright holders nor the -- * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. -- */ --#ifndef _FSL_DPCON_CMD_H --#define _FSL_DPCON_CMD_H -- --/* DPCON Version */ --#define DPCON_VER_MAJOR 2 --#define DPCON_VER_MINOR 1 -- --/* Command IDs */ --#define DPCON_CMDID_CLOSE 0x800 --#define DPCON_CMDID_OPEN 0x808 --#define DPCON_CMDID_CREATE 0x908 --#define DPCON_CMDID_DESTROY 0x900 -- --#define DPCON_CMDID_ENABLE 0x002 --#define DPCON_CMDID_DISABLE 0x003 --#define DPCON_CMDID_GET_ATTR 0x004 --#define DPCON_CMDID_RESET 0x005 --#define DPCON_CMDID_IS_ENABLED 0x006 -- --#define DPCON_CMDID_SET_IRQ 0x010 --#define DPCON_CMDID_GET_IRQ 0x011 --#define DPCON_CMDID_SET_IRQ_ENABLE 0x012 --#define DPCON_CMDID_GET_IRQ_ENABLE 0x013 --#define DPCON_CMDID_SET_IRQ_MASK 0x014 --#define DPCON_CMDID_GET_IRQ_MASK 0x015 --#define DPCON_CMDID_GET_IRQ_STATUS 0x016 --#define DPCON_CMDID_CLEAR_IRQ_STATUS 0x017 -- --#define DPCON_CMDID_SET_NOTIFICATION 0x100 -- --#endif /* _FSL_DPCON_CMD_H */ --- /dev/null +++ b/drivers/staging/fsl-mc/bus/dpio/dpio-cmd.h -@@ -0,0 +1,75 @@ +@@ -0,0 +1,50 @@ ++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright 2013-2016 Freescale Semiconductor Inc. + * Copyright 2016 NXP + * -+ * 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 the above-listed copyright holders nor the -+ * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ +#ifndef _FSL_DPIO_CMD_H +#define _FSL_DPIO_CMD_H @@ -1309,6 +10221,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +#define DPIO_CMDID_ENABLE DPIO_CMD(0x002) +#define DPIO_CMDID_DISABLE DPIO_CMD(0x003) +#define DPIO_CMDID_GET_ATTR DPIO_CMD(0x004) ++#define DPIO_CMDID_RESET DPIO_CMD(0x005) + +struct dpio_cmd_open { + __le32 dpio_id; @@ -1333,37 +10246,12 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +#endif /* _FSL_DPIO_CMD_H */ --- /dev/null +++ b/drivers/staging/fsl-mc/bus/dpio/dpio-driver.c -@@ -0,0 +1,296 @@ +@@ -0,0 +1,278 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright 2014-2016 Freescale Semiconductor Inc. + * Copyright 2016 NXP + * -+ * 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 <linux/types.h> @@ -1375,7 +10263,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +#include <linux/dma-mapping.h> +#include <linux/delay.h> + -+#include "../../include/mc.h" ++#include <linux/fsl/mc.h> +#include "../../include/dpaa2-io.h" + +#include "qbman-portal.h" @@ -1471,6 +10359,12 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + goto err_open; + } + ++ err = dpio_reset(dpio_dev->mc_io, 0, dpio_dev->mc_handle); ++ if (err) { ++ dev_err(dev, "dpio_reset() failed\n"); ++ goto err_reset; ++ } ++ + err = dpio_get_attributes(dpio_dev->mc_io, 0, dpio_dev->mc_handle, + &dpio_attrs); + if (err) { @@ -1543,6 +10437,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +err_allocate_irqs: + dpio_disable(dpio_dev->mc_io, 0, dpio_dev->mc_handle); +err_get_attr: ++err_reset: + dpio_close(dpio_dev->mc_io, 0, dpio_dev->mc_handle); +err_open: + fsl_mc_portal_free(dpio_dev->mc_io); @@ -1632,40 +10527,15 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +module_exit(dpio_driver_exit); --- /dev/null +++ b/drivers/staging/fsl-mc/bus/dpio/dpio-service.c -@@ -0,0 +1,693 @@ +@@ -0,0 +1,780 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright 2014-2016 Freescale Semiconductor Inc. + * Copyright 2016 NXP + * -+ * 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 <linux/types.h> -+#include "../../include/mc.h" ++#include <linux/fsl/mc.h> +#include "../../include/dpaa2-io.h" +#include <linux/init.h> +#include <linux/module.h> @@ -1676,10 +10546,8 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + +#include "dpio.h" +#include "qbman-portal.h" -+#include "qbman_debug.h" + +struct dpaa2_io { -+ atomic_t refs; + struct dpaa2_io_desc dpio_desc; + struct qbman_swp_desc swp_desc; + struct qbman_swp *swp; @@ -1712,7 +10580,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + if (d) + return d; + -+ if (unlikely(cpu >= (int)num_possible_cpus())) ++ if (cpu != DPAA2_IO_ANY_CPU && cpu >= num_possible_cpus()) + return NULL; + + /* @@ -1745,6 +10613,23 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +} + +/** ++ * dpaa2_io_service_select() - return a dpaa2_io service affined to this cpu ++ * @cpu: the cpu id ++ * ++ * Return the affine dpaa2_io service, or NULL if there is no service affined ++ * to the specified cpu. If DPAA2_IO_ANY_CPU is used, return the next available ++ * service. ++ */ ++struct dpaa2_io *dpaa2_io_service_select(int cpu) ++{ ++ if (cpu == DPAA2_IO_ANY_CPU) ++ return service_select(NULL); ++ ++ return service_select_by_cpu(NULL, cpu); ++} ++EXPORT_SYMBOL_GPL(dpaa2_io_service_select); ++ ++/** + * dpaa2_io_create() - create a dpaa2_io object. + * @desc: the dpaa2_io descriptor + * @@ -1761,12 +10646,11 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + return NULL; + + /* check if CPU is out of range (-1 means any cpu) */ -+ if (desc->cpu >= (int)num_possible_cpus()) { ++ if (desc->cpu != DPAA2_IO_ANY_CPU && desc->cpu >= num_possible_cpus()) { + kfree(obj); + return NULL; + } + -+ atomic_set(&obj->refs, 1); + obj->dpio_desc = *desc; + obj->swp_desc.cena_bar = obj->dpio_desc.regs_cena; + obj->swp_desc.cinh_bar = obj->dpio_desc.regs_cinh; @@ -1798,7 +10682,6 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + + return obj; +} -+EXPORT_SYMBOL(dpaa2_io_create); + +/** + * dpaa2_io_down() - release the dpaa2_io object. @@ -1811,11 +10694,8 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + */ +void dpaa2_io_down(struct dpaa2_io *d) +{ -+ if (!atomic_dec_and_test(&d->refs)) -+ return; + kfree(d); +} -+EXPORT_SYMBOL(dpaa2_io_down); + +#define DPAA_POLL_MAX 32 + @@ -1846,7 +10726,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + u64 q64; + + q64 = qbman_result_SCN_ctx(dq); -+ ctx = (void *)q64; ++ ctx = (void *)(uintptr_t)q64; + ctx->cb(ctx); + } else { + pr_crit("fsl-mc-dpio: Unrecognised/ignored DQRR entry\n"); @@ -1862,7 +10742,6 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + qbman_swp_interrupt_set_inhibit(swp, 0); + return IRQ_HANDLED; +} -+EXPORT_SYMBOL(dpaa2_io_irq); + +/** + * dpaa2_io_service_register() - Prepare for servicing of FQDAN or CDAN @@ -1892,7 +10771,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + return -ENODEV; + + ctx->dpio_id = d->dpio_desc.dpio_id; -+ ctx->qman64 = (u64)ctx; ++ ctx->qman64 = (u64)(uintptr_t)ctx; + ctx->dpio_private = d; + spin_lock_irqsave(&d->lock_notifications, irqflags); + list_add(&ctx->node, &d->notifications); @@ -1900,12 +10779,12 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + + /* Enable the generation of CDAN notifications */ + if (ctx->is_cdan) -+ qbman_swp_CDAN_set_context_enable(d->swp, -+ (u16)ctx->id, -+ ctx->qman64); ++ return qbman_swp_CDAN_set_context_enable(d->swp, ++ (u16)ctx->id, ++ ctx->qman64); + return 0; +} -+EXPORT_SYMBOL(dpaa2_io_service_register); ++EXPORT_SYMBOL_GPL(dpaa2_io_service_register); + +/** + * dpaa2_io_service_deregister - The opposite of 'register'. @@ -1928,7 +10807,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + list_del(&ctx->node); + spin_unlock_irqrestore(&d->lock_notifications, irqflags); +} -+EXPORT_SYMBOL(dpaa2_io_service_deregister); ++EXPORT_SYMBOL_GPL(dpaa2_io_service_deregister); + +/** + * dpaa2_io_service_rearm() - Rearm the notification for the given DPIO service. @@ -1962,7 +10841,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + + return err; +} -+EXPORT_SYMBOL(dpaa2_io_service_rearm); ++EXPORT_SYMBOL_GPL(dpaa2_io_service_rearm); + +/** + * dpaa2_io_service_pull_fq() - pull dequeue functions from a fq. @@ -2025,7 +10904,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + + return err; +} -+EXPORT_SYMBOL(dpaa2_io_service_pull_channel); ++EXPORT_SYMBOL_GPL(dpaa2_io_service_pull_channel); + +/** + * dpaa2_io_service_enqueue_fq() - Enqueue a frame to a frame queue. @@ -2081,7 +10960,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + + return qbman_swp_enqueue(d->swp, &ed, fd); +} -+EXPORT_SYMBOL(dpaa2_io_service_enqueue_qd); ++EXPORT_SYMBOL_GPL(dpaa2_io_service_enqueue_qd); + +/** + * dpaa2_io_service_release() - Release buffers to a buffer pool. @@ -2108,7 +10987,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + + return qbman_swp_release(d->swp, &rd, buffers, num_buffers); +} -+EXPORT_SYMBOL(dpaa2_io_service_release); ++EXPORT_SYMBOL_GPL(dpaa2_io_service_release); + +/** + * dpaa2_io_service_acquire() - Acquire buffers from a buffer pool. @@ -2139,7 +11018,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + + return err; +} -+EXPORT_SYMBOL(dpaa2_io_service_acquire); ++EXPORT_SYMBOL_GPL(dpaa2_io_service_acquire); + +/* + * 'Stores' are reusable memory blocks for holding dequeue results, and to @@ -2193,7 +11072,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + + return ret; +} -+EXPORT_SYMBOL(dpaa2_io_store_create); ++EXPORT_SYMBOL_GPL(dpaa2_io_store_create); + +/** + * dpaa2_io_store_destroy() - Frees the dma memory storage for dequeue @@ -2207,7 +11086,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + kfree(s->alloced_addr); + kfree(s); +} -+EXPORT_SYMBOL(dpaa2_io_store_destroy); ++EXPORT_SYMBOL_GPL(dpaa2_io_store_destroy); + +/** + * dpaa2_io_store_next() - Determine when the next dequeue result is available. @@ -2255,9 +11134,8 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + + return ret; +} -+EXPORT_SYMBOL(dpaa2_io_store_next); ++EXPORT_SYMBOL_GPL(dpaa2_io_store_next); + -+#ifdef CONFIG_FSL_QBMAN_DEBUG +/** + * dpaa2_io_query_fq_count() - Get the frame and byte count for a given fq. + * @d: the given DPIO object. @@ -2270,10 +11148,10 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + * + * Return 0 for a successful query, and negative error code if query fails. + */ -+int dpaa2_io_query_fq_count(struct dpaa2_io *d, uint32_t fqid, ++int dpaa2_io_query_fq_count(struct dpaa2_io *d, u32 fqid, + u32 *fcnt, u32 *bcnt) +{ -+ struct qbman_attr state; ++ struct qbman_fq_query_np_rslt state; + struct qbman_swp *swp; + unsigned long irqflags; + int ret; @@ -2296,17 +11174,17 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +EXPORT_SYMBOL(dpaa2_io_query_fq_count); + +/** -+ * dpaa2_io_query_bp_count() - Query the number of buffers currenty in a ++ * dpaa2_io_query_bp_count() - Query the number of buffers currently in a + * buffer pool. + * @d: the given DPIO object. + * @bpid: the index of buffer pool to be queried. + * @num: the queried number of buffers in the buffer pool. + * -+ * Return 0 for a sucessful query, and negative error code if query fails. ++ * Return 0 for a successful query, and negative error code if query fails. + */ -+int dpaa2_io_query_bp_count(struct dpaa2_io *d, uint32_t bpid, u32 *num) ++int dpaa2_io_query_bp_count(struct dpaa2_io *d, u32 bpid, u32 *num) +{ -+ struct qbman_attr state; ++ struct qbman_bp_query_rslt state; + struct qbman_swp *swp; + unsigned long irqflags; + int ret; @@ -2325,44 +11203,122 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + return 0; +} +EXPORT_SYMBOL(dpaa2_io_query_bp_count); -+#endif ++ ++/** ++ * dpaa2_io_service_enqueue_orp_fq() - Enqueue a frame to a frame queue with ++ * order restoration ++ * @d: the given DPIO service. ++ * @fqid: the given frame queue id. ++ * @fd: the frame descriptor which is enqueued. ++ * @orpid: the order restoration point ID ++ * @seqnum: the order sequence number ++ * @last: must be set for the final frame if seqnum is shared (spilt frame) ++ * ++ * Performs an enqueue to a frame queue using the specified order restoration ++ * point. The QMan device will ensure the order of frames placed on the ++ * queue will be ordered as per the sequence number. ++ * ++ * In the case a frame is split it is possible to enqueue using the same ++ * sequence number more than once. The final frame in a shared sequence number ++ * most be indicated by setting last = 1. For non shared sequence numbers ++ * last = 1 must always be set. ++ * ++ * Return 0 for successful enqueue, or -EBUSY if the enqueue ring is not ready, ++ * or -ENODEV if there is no dpio service. ++ */ ++int dpaa2_io_service_enqueue_orp_fq(struct dpaa2_io *d, u32 fqid, ++ const struct dpaa2_fd *fd, u16 orpid, ++ u16 seqnum, int last) ++{ ++ struct qbman_eq_desc ed; ++ ++ d = service_select(d); ++ if (!d) ++ return -ENODEV; ++ qbman_eq_desc_clear(&ed); ++ qbman_eq_desc_set_orp(&ed, 0, orpid, seqnum, !last); ++ qbman_eq_desc_set_fq(&ed, fqid); ++ return qbman_swp_enqueue(d->swp, &ed, fd); ++} ++EXPORT_SYMBOL(dpaa2_io_service_enqueue_orp_fq); ++ ++/** ++ * dpaa2_io_service_enqueue_orp_qd() - Enqueue a frame to a queueing destination ++ * with order restoration ++ * @d: the given DPIO service. ++ * @qdid: the given queuing destination id. ++ * @fd: the frame descriptor which is enqueued. ++ * @orpid: the order restoration point ID ++ * @seqnum: the order sequence number ++ * @last: must be set for the final frame if seqnum is shared (spilt frame) ++ * ++ * Performs an enqueue to a frame queue using the specified order restoration ++ * point. The QMan device will ensure the order of frames placed on the ++ * queue will be ordered as per the sequence number. ++ * ++ * In the case a frame is split it is possible to enqueue using the same ++ * sequence number more than once. The final frame in a shared sequence number ++ * most be indicated by setting last = 1. For non shared sequence numbers ++ * last = 1 must always be set. ++ * ++ * Return 0 for successful enqueue, or -EBUSY if the enqueue ring is not ready, ++ * or -ENODEV if there is no dpio service. ++ */ ++int dpaa2_io_service_enqueue_orp_qd(struct dpaa2_io *d, u32 qdid, u8 prio, ++ u16 qdbin, const struct dpaa2_fd *fd, ++ u16 orpid, u16 seqnum, int last) ++{ ++ struct qbman_eq_desc ed; ++ ++ d = service_select(d); ++ if (!d) ++ return -ENODEV; ++ qbman_eq_desc_clear(&ed); ++ qbman_eq_desc_set_orp(&ed, 0, orpid, seqnum, !last); ++ qbman_eq_desc_set_qd(&ed, qdid, qdbin, prio); ++ return qbman_swp_enqueue(d->swp, &ed, fd); ++} ++EXPORT_SYMBOL_GPL(dpaa2_io_service_enqueue_orp_qd); ++ ++/** ++ * dpaa2_io_service_orp_seqnum_drop() - Remove a sequence number from ++ * an order restoration list ++ * @d: the given DPIO service. ++ * @orpid: Order restoration point to remove a sequence number from ++ * @seqnum: Sequence number to remove ++ * ++ * Removes a frames sequence number from an order restoration point without ++ * enqueing the frame. Used to indicate that the order restoration hardware ++ * should not expect to see this sequence number. Typically used to indicate ++ * a frame was terminated or dropped from a flow. ++ * ++ * Return 0 for successful enqueue, or -EBUSY if the enqueue ring is not ready, ++ * or -ENODEV if there is no dpio service. ++ */ ++int dpaa2_io_service_orp_seqnum_drop(struct dpaa2_io *d, u16 orpid, u16 seqnum) ++{ ++ struct qbman_eq_desc ed; ++ struct dpaa2_fd fd; ++ ++ d = service_select(d); ++ if (!d) ++ return -ENODEV; ++ qbman_eq_desc_clear(&ed); ++ qbman_eq_desc_set_orp_hole(&ed, orpid, seqnum); ++ return qbman_swp_enqueue(d->swp, &ed, &fd); ++} ++EXPORT_SYMBOL_GPL(dpaa2_io_service_orp_seqnum_drop); --- /dev/null +++ b/drivers/staging/fsl-mc/bus/dpio/dpio.c -@@ -0,0 +1,224 @@ +@@ -0,0 +1,221 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright 2013-2016 Freescale Semiconductor Inc. + * Copyright 2016 NXP + * -+ * 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 the above-listed copyright holders nor the -+ * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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/mc-sys.h" -+#include "../../include/mc-cmd.h" ++#include <linux/kernel.h> ++#include <linux/fsl/mc.h> + +#include "dpio.h" +#include "dpio-cmd.h" @@ -2394,7 +11350,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + int dpio_id, + u16 *token) +{ -+ struct mc_command cmd = { 0 }; ++ struct fsl_mc_command cmd = { 0 }; + struct dpio_cmd_open *dpio_cmd; + int err; + @@ -2427,7 +11383,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + u32 cmd_flags, + u16 token) +{ -+ struct mc_command cmd = { 0 }; ++ struct fsl_mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPIO_CMDID_CLOSE, @@ -2449,7 +11405,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + u32 cmd_flags, + u16 token) +{ -+ struct mc_command cmd = { 0 }; ++ struct fsl_mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPIO_CMDID_ENABLE, @@ -2471,7 +11427,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + u32 cmd_flags, + u16 token) +{ -+ struct mc_command cmd = { 0 }; ++ struct fsl_mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPIO_CMDID_DISABLE, @@ -2495,7 +11451,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + u16 token, + struct dpio_attr *attr) +{ -+ struct mc_command cmd = { 0 }; ++ struct fsl_mc_command cmd = { 0 }; + struct dpio_rsp_get_attr *dpio_rsp; + int err; + @@ -2537,7 +11493,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + u16 *major_ver, + u16 *minor_ver) +{ -+ struct mc_command cmd = { 0 }; ++ struct fsl_mc_command cmd = { 0 }; + int err; + + /* prepare command */ @@ -2553,40 +11509,37 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + + return 0; +} ++ ++/** ++ * dpio_reset() - Reset the DPIO, returns the object to initial state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPIO object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpio_reset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct fsl_mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPIO_CMDID_RESET, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} --- /dev/null +++ b/drivers/staging/fsl-mc/bus/dpio/dpio.h -@@ -0,0 +1,109 @@ +@@ -0,0 +1,87 @@ ++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright 2013-2016 Freescale Semiconductor Inc. + * Copyright 2016 NXP + * -+ * 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 the above-listed copyright holders nor the -+ * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ +#ifndef __FSL_DPIO_H +#define __FSL_DPIO_H @@ -2664,40 +11617,19 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + u16 *major_ver, + u16 *minor_ver); + ++int dpio_reset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ +#endif /* __FSL_DPIO_H */ --- /dev/null +++ b/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c -@@ -0,0 +1,1049 @@ +@@ -0,0 +1,1164 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * -+ * 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 <asm/cacheflush.h> @@ -2707,9 +11639,6 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + +#include "qbman-portal.h" + -+struct qb_attr_code code_generic_verb = QB_CODE(0, 0, 7); -+struct qb_attr_code code_generic_rslt = QB_CODE(0, 8, 8); -+ +#define QMAN_REV_4000 0x04000000 +#define QMAN_REV_4100 0x04010000 +#define QMAN_REV_4101 0x04010001 @@ -2817,18 +11746,18 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + u8 epm, int sd, int sp, int se, + int dp, int de, int ep) +{ -+ return cpu_to_le32 (max_fill << SWP_CFG_DQRR_MF_SHIFT | -+ est << SWP_CFG_EST_SHIFT | -+ wn << SWP_CFG_WN_SHIFT | -+ rpm << SWP_CFG_RPM_SHIFT | -+ dcm << SWP_CFG_DCM_SHIFT | -+ epm << SWP_CFG_EPM_SHIFT | -+ sd << SWP_CFG_SD_SHIFT | -+ sp << SWP_CFG_SP_SHIFT | -+ se << SWP_CFG_SE_SHIFT | -+ dp << SWP_CFG_DP_SHIFT | -+ de << SWP_CFG_DE_SHIFT | -+ ep << SWP_CFG_EP_SHIFT); ++ return (max_fill << SWP_CFG_DQRR_MF_SHIFT | ++ est << SWP_CFG_EST_SHIFT | ++ wn << SWP_CFG_WN_SHIFT | ++ rpm << SWP_CFG_RPM_SHIFT | ++ dcm << SWP_CFG_DCM_SHIFT | ++ epm << SWP_CFG_EPM_SHIFT | ++ sd << SWP_CFG_SD_SHIFT | ++ sp << SWP_CFG_SP_SHIFT | ++ se << SWP_CFG_SE_SHIFT | ++ dp << SWP_CFG_DP_SHIFT | ++ de << SWP_CFG_DE_SHIFT | ++ ep << SWP_CFG_EP_SHIFT); +} + +/** @@ -3053,6 +11982,43 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + d->verb |= enqueue_rejects_to_fq; +} + ++/** ++ * qbman_eq_desc_set_orp() - Set order-restoration in the enqueue descriptor ++ * @d: the enqueue descriptor. ++ * @response_success: 1 = enqueue with response always; 0 = enqueue with ++ * rejections returned on a FQ. ++ * @oprid: the order point record id. ++ * @seqnum: the order restoration sequence number. ++ * @incomplete: indicates whether this is the last fragments using the same ++ * sequence number. ++ */ ++void qbman_eq_desc_set_orp(struct qbman_eq_desc *d, int respond_success, ++ u16 oprid, u16 seqnum, int incomplete) ++{ ++ d->verb |= (1 << QB_ENQUEUE_CMD_ORP_ENABLE_SHIFT); ++ if (respond_success) ++ d->verb |= enqueue_response_always; ++ else ++ d->verb |= enqueue_rejects_to_fq; ++ d->orpid = cpu_to_le16(oprid); ++ d->seqnum = cpu_to_le16((!!incomplete << 14) | seqnum); ++} ++ ++/** ++ * qbman_eq_desc_set_orp_hole() - fill a hole in the order-restoration sequence ++ * without any enqueue ++ * @d: the enqueue descriptor. ++ * @oprid: the order point record id. ++ * @seqnum: the order restoration sequence number. ++ */ ++void qbman_eq_desc_set_orp_hole(struct qbman_eq_desc *d, u16 oprid, ++ u16 seqnum) ++{ ++ d->verb |= (1 << QB_ENQUEUE_CMD_ORP_ENABLE_SHIFT) | enqueue_empty; ++ d->orpid = cpu_to_le16(oprid); ++ d->seqnum = cpu_to_le16(seqnum); ++} ++ +/* + * Exactly one of the following descriptor "targets" should be set. (Calling any + * one of these will replace the effect of any prior call to one of these.) @@ -3112,7 +12078,17 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + return -EBUSY; + + p = qbman_get_cmd(s, QBMAN_CENA_SWP_EQCR(EQAR_IDX(eqar))); -+ memcpy(&p->dca, &d->dca, 31); ++ /* This is mapped as DEVICE type memory, writes are ++ * with address alignment: ++ * desc.dca address alignment = 1 ++ * desc.seqnum address alignment = 2 ++ * desc.orpid address alignment = 4 ++ * desc.tgtid address alignment = 8 ++ */ ++ p->dca = d->dca; ++ p->seqnum = d->seqnum; ++ p->orpid = d->orpid; ++ memcpy(&p->tgtid, &d->tgtid, 24); + memcpy(&p->fd, fd, sizeof(*fd)); + + /* Set the verb byte, have to substitute in the valid-bit */ @@ -3206,7 +12182,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + int stash) +{ + /* save the virtual address */ -+ d->rsp_addr_virt = (u64)storage; ++ d->rsp_addr_virt = (u64)(uintptr_t)storage; + + if (!storage) { + d->verb &= ~(1 << QB_VDQCR_VERB_RLS_SHIFT); @@ -3299,7 +12275,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + atomic_inc(&s->vdq.available); + return -EBUSY; + } -+ s->vdq.storage = (void *)d->rsp_addr_virt; ++ s->vdq.storage = (void *)(uintptr_t)d->rsp_addr_virt; + p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR); + p->numf = d->numf; + p->tok = QMAN_DQ_TOKEN_VALID; @@ -3539,7 +12515,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +struct qbman_acquire_desc { + u8 verb; + u8 reserved; -+ u16 bpid; ++ __le16 bpid; + u8 num; + u8 reserved2[59]; +}; @@ -3547,10 +12523,10 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +struct qbman_acquire_rslt { + u8 verb; + u8 rslt; -+ u16 reserved; ++ __le16 reserved; + u8 num; + u8 reserved2[3]; -+ u64 buf[7]; ++ __le64 buf[7]; +}; + +/** @@ -3613,7 +12589,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +struct qbman_alt_fq_state_desc { + u8 verb; + u8 reserved[3]; -+ u32 fqid; ++ __le32 fqid; + u8 reserved2[56]; +}; + @@ -3636,7 +12612,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + if (!p) + return -EBUSY; + -+ p->fqid = cpu_to_le32(fqid) & ALT_FQ_FQID_MASK; ++ p->fqid = cpu_to_le32(fqid & ALT_FQ_FQID_MASK); + + /* Complete the management command */ + r = qbman_swp_mc_complete(s, p, alt_fq_verb); @@ -3662,11 +12638,11 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +struct qbman_cdan_ctrl_desc { + u8 verb; + u8 reserved; -+ u16 ch; ++ __le16 ch; + u8 we; + u8 ctrl; -+ u16 reserved2; -+ u64 cdan_ctx; ++ __le16 reserved2; ++ __le64 cdan_ctx; + u8 reserved3[48]; + +}; @@ -3674,7 +12650,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +struct qbman_cdan_ctrl_rslt { + u8 verb; + u8 rslt; -+ u16 ch; ++ __le16 ch; + u8 reserved[60]; +}; + @@ -3717,44 +12693,114 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + + return 0; +} ++ ++#define QBMAN_RESPONSE_VERB_MASK 0x7f ++#define QBMAN_FQ_QUERY_NP 0x45 ++#define QBMAN_BP_QUERY 0x32 ++ ++struct qbman_fq_query_desc { ++ u8 verb; ++ u8 reserved[3]; ++ u32 fqid; ++ u8 reserved2[56]; ++}; ++ ++int qbman_fq_query_state(struct qbman_swp *s, u32 fqid, ++ struct qbman_fq_query_np_rslt *r) ++{ ++ struct qbman_fq_query_desc *p; ++ void *resp; ++ ++ p = (struct qbman_fq_query_desc *)qbman_swp_mc_start(s); ++ if (!p) ++ return -EBUSY; ++ ++ /* FQID is a 24 bit value */ ++ p->fqid = cpu_to_le32(fqid) & 0x00FFFFFF; ++ resp = qbman_swp_mc_complete(s, p, QBMAN_FQ_QUERY_NP); ++ if (!resp) { ++ pr_err("qbman: Query FQID %d NP fields failed, no response\n", ++ fqid); ++ return -EIO; ++ } ++ *r = *(struct qbman_fq_query_np_rslt *)resp; ++ /* Decode the outcome */ ++ WARN_ON((r->verb & QBMAN_RESPONSE_VERB_MASK) != QBMAN_FQ_QUERY_NP); ++ ++ /* Determine success or failure */ ++ if (r->rslt != QBMAN_MC_RSLT_OK) { ++ pr_err("Query NP fields of FQID 0x%x failed, code=0x%02x\n", ++ p->fqid, r->rslt); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++u32 qbman_fq_state_frame_count(const struct qbman_fq_query_np_rslt *r) ++{ ++ return (r->frm_cnt & 0x00FFFFFF); ++} ++ ++u32 qbman_fq_state_byte_count(const struct qbman_fq_query_np_rslt *r) ++{ ++ return r->byte_cnt; ++} ++ ++struct qbman_bp_query_desc { ++ u8 verb; ++ u8 reserved; ++ u16 bpid; ++ u8 reserved2[60]; ++}; ++ ++int qbman_bp_query(struct qbman_swp *s, u32 bpid, ++ struct qbman_bp_query_rslt *r) ++{ ++ struct qbman_bp_query_desc *p; ++ void *resp; ++ ++ p = (struct qbman_bp_query_desc *)qbman_swp_mc_start(s); ++ if (!p) ++ return -EBUSY; ++ ++ p->bpid = bpid; ++ resp = qbman_swp_mc_complete(s, p, QBMAN_BP_QUERY); ++ if (!resp) { ++ pr_err("qbman: Query BPID %d fields failed, no response\n", ++ bpid); ++ return -EIO; ++ } ++ *r = *(struct qbman_bp_query_rslt *)resp; ++ /* Decode the outcome */ ++ WARN_ON((r->verb & QBMAN_RESPONSE_VERB_MASK) != QBMAN_BP_QUERY); ++ ++ /* Determine success or failure */ ++ if (r->rslt != QBMAN_MC_RSLT_OK) { ++ pr_err("Query fields of BPID 0x%x failed, code=0x%02x\n", ++ bpid, r->rslt); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++u32 qbman_bp_info_num_free_bufs(struct qbman_bp_query_rslt *a) ++{ ++ return a->fill; ++} --- /dev/null +++ b/drivers/staging/fsl-mc/bus/dpio/qbman-portal.h -@@ -0,0 +1,662 @@ +@@ -0,0 +1,505 @@ ++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * -+ * 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. + */ +#ifndef __FSL_QBMAN_PORTAL_H +#define __FSL_QBMAN_PORTAL_H + -+#include "qbman_private.h" +#include "../../include/dpaa2-fd.h" + +struct dpaa2_dq; @@ -3780,8 +12826,8 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + u8 numf; + u8 tok; + u8 reserved; -+ u32 dq_src; -+ u64 rsp_addr; ++ __le32 dq_src; ++ __le64 rsp_addr; + u64 rsp_addr_virt; + u8 padding[40]; +}; @@ -3818,17 +12864,17 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +struct qbman_eq_desc { + u8 verb; + u8 dca; -+ u16 seqnum; -+ u16 orpid; -+ u16 reserved1; -+ u32 tgtid; -+ u32 tag; -+ u16 qdbin; ++ __le16 seqnum; ++ __le16 orpid; ++ __le16 reserved1; ++ __le32 tgtid; ++ __le32 tag; ++ __le16 qdbin; + u8 qpri; + u8 reserved[3]; + u8 wae; + u8 rspid; -+ u64 rsp_addr; ++ __le64 rsp_addr; + u8 fd[32]; +}; + @@ -3836,9 +12882,9 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +struct qbman_release_desc { + u8 verb; + u8 reserved; -+ u16 bpid; -+ u32 reserved2; -+ u64 buf[7]; ++ __le16 bpid; ++ __le32 reserved2; ++ __le64 buf[7]; +}; + +/* Management command result codes */ @@ -3910,6 +12956,9 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + +void qbman_eq_desc_clear(struct qbman_eq_desc *d); +void qbman_eq_desc_set_no_orp(struct qbman_eq_desc *d, int respond_success); ++void qbman_eq_desc_set_orp(struct qbman_eq_desc *d, int respond_success, ++ u16 oprid, u16 seqnum, int incomplete); ++void qbman_eq_desc_set_orp_hole(struct qbman_eq_desc *d, u16 oprid, u16 seqnum); +void qbman_eq_desc_set_token(struct qbman_eq_desc *d, u8 token); +void qbman_eq_desc_set_fq(struct qbman_eq_desc *d, u32 fqid); +void qbman_eq_desc_set_qd(struct qbman_eq_desc *d, u32 qdid, @@ -4189,1389 +13238,103 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + return cmd; +} + -+/* ------------ */ -+/* qb_attr_code */ -+/* ------------ */ -+ -+/* This struct locates a sub-field within a QBMan portal (CENA) cacheline which -+ * is either serving as a configuration command or a query result. The -+ * representation is inherently little-endian, as the indexing of the words is -+ * itself little-endian in nature and layerscape is little endian for anything -+ * that crosses a word boundary too (64-bit fields are the obvious examples). -+ */ -+struct qb_attr_code { -+ unsigned int word; /* which u32[] array member encodes the field */ -+ unsigned int lsoffset; /* encoding offset from ls-bit */ -+ unsigned int width; /* encoding width. (bool must be 1.) */ -+}; -+ -+/* Some pre-defined codes */ -+extern struct qb_attr_code code_generic_verb; -+extern struct qb_attr_code code_generic_rslt; -+ -+/* Macros to define codes */ -+#define QB_CODE(a, b, c) { a, b, c} -+#define QB_CODE_NULL \ -+ QB_CODE((unsigned int)-1, (unsigned int)-1, (unsigned int)-1) -+ -+/* Rotate a code "ms", meaning that it moves from less-significant bytes to -+ * more-significant, from less-significant words to more-significant, etc. The -+ * "ls" version does the inverse, from more-significant towards -+ * less-significant. -+ */ -+static inline void qb_attr_code_rotate_ms(struct qb_attr_code *code, -+ unsigned int bits) -+{ -+ code->lsoffset += bits; -+ while (code->lsoffset > 31) { -+ code->word++; -+ code->lsoffset -= 32; -+ } -+} -+ -+static inline void qb_attr_code_rotate_ls(struct qb_attr_code *code, -+ unsigned int bits) -+{ -+ /* Don't be fooled, this trick should work because the types are -+ * unsigned. So the case that interests the while loop (the rotate has -+ * gone too far and the word count needs to compensate for it), is -+ * manifested when lsoffset is negative. But that equates to a really -+ * large unsigned value, starting with lots of "F"s. As such, we can -+ * continue adding 32 back to it until it wraps back round above zero, -+ * to a value of 31 or less... -+ */ -+ code->lsoffset -= bits; -+ while (code->lsoffset > 31) { -+ code->word--; -+ code->lsoffset += 32; -+ } -+} -+ -+/* Implement a loop of code rotations until 'expr' evaluates to FALSE (0). */ -+#define qb_attr_code_for_ms(code, bits, expr) \ -+ for (; expr; qb_attr_code_rotate_ms(code, bits)) -+#define qb_attr_code_for_ls(code, bits, expr) \ -+ for (; expr; qb_attr_code_rotate_ls(code, bits)) -+ -+static inline void word_copy(void *d, const void *s, unsigned int cnt) -+{ -+ u32 *dd = d; -+ const u32 *ss = s; -+ -+ while (cnt--) -+ *(dd++) = *(ss++); -+} -+ -+/* -+ * Currently, the CENA support code expects each 32-bit word to be written in -+ * host order, and these are converted to hardware (little-endian) order on -+ * command submission. However, 64-bit quantities are must be written (and read) -+ * as two 32-bit words with the least-significant word first, irrespective of -+ * host endianness. -+ */ -+static inline void u64_to_le32_copy(void *d, const u64 *s, -+ unsigned int cnt) -+{ -+ u32 *dd = d; -+ const u32 *ss = (const u32 *)s; -+ -+ while (cnt--) { -+ /* -+ * TBD: the toolchain was choking on the use of 64-bit types up -+ * until recently so this works entirely with 32-bit variables. -+ * When 64-bit types become usable again, investigate better -+ * ways of doing this. -+ */ -+#if defined(__BIG_ENDIAN) -+ *(dd++) = ss[1]; -+ *(dd++) = ss[0]; -+ ss += 2; -+#else -+ *(dd++) = *(ss++); -+ *(dd++) = *(ss++); -+#endif -+ } -+} -+ -+static inline void u64_from_le32_copy(u64 *d, const void *s, -+ unsigned int cnt) -+{ -+ const u32 *ss = s; -+ u32 *dd = (u32 *)d; -+ -+ while (cnt--) { -+#if defined(__BIG_ENDIAN) -+ dd[1] = *(ss++); -+ dd[0] = *(ss++); -+ dd += 2; -+#else -+ *(dd++) = *(ss++); -+ *(dd++) = *(ss++); -+#endif -+ } -+} -+ -+/* decode a field from a cacheline */ -+static inline u32 qb_attr_code_decode(const struct qb_attr_code *code, -+ const u32 *cacheline) -+{ -+ return d32_u32(code->lsoffset, code->width, cacheline[code->word]); -+} -+ -+static inline u64 qb_attr_code_decode_64(const struct qb_attr_code *code, -+ const u64 *cacheline) -+{ -+ u64 res; -+ -+ u64_from_le32_copy(&res, &cacheline[code->word / 2], 1); -+ return res; -+} -+ -+/* encode a field to a cacheline */ -+static inline void qb_attr_code_encode(const struct qb_attr_code *code, -+ u32 *cacheline, u32 val) -+{ -+ cacheline[code->word] = -+ r32_u32(code->lsoffset, code->width, cacheline[code->word]) -+ | e32_u32(code->lsoffset, code->width, val); -+} -+ -+static inline void qb_attr_code_encode_64(const struct qb_attr_code *code, -+ u64 *cacheline, u64 val) -+{ -+ u64_to_le32_copy(&cacheline[code->word / 2], &val, 1); -+} -+ -+/* Small-width signed values (two's-complement) will decode into medium-width -+ * positives. (Eg. for an 8-bit signed field, which stores values from -128 to -+ * +127, a setting of -7 would appear to decode to the 32-bit unsigned value -+ * 249. Likewise -120 would decode as 136.) This function allows the caller to -+ * "re-sign" such fields to 32-bit signed. (Eg. -7, which was 249 with an 8-bit -+ * encoding, will become 0xfffffff9 if you cast the return value to u32). -+ */ -+static inline int32_t qb_attr_code_makesigned(const struct qb_attr_code *code, -+ u32 val) -+{ -+ WARN_ON(val >= (1 << code->width)); -+ /* If the high bit was set, it was encoding a negative */ -+ if (val >= (1 << (code->width - 1))) -+ return (int32_t)0 - (int32_t)(((u32)1 << code->width) - -+ val); -+ /* Otherwise, it was encoding a positive */ -+ return (int32_t)val; -+} -+ -+/* ---------------------- */ -+/* Descriptors/cachelines */ -+/* ---------------------- */ -+ -+/* To avoid needless dynamic allocation, the driver API often gives the caller -+ * a "descriptor" type that the caller can instantiate however they like. -+ * Ultimately though, it is just a cacheline of binary storage (or something -+ * smaller when it is known that the descriptor doesn't need all 64 bytes) for -+ * holding pre-formatted pieces of hardware commands. The performance-critical -+ * code can then copy these descriptors directly into hardware command -+ * registers more efficiently than trying to construct/format commands -+ * on-the-fly. The API user sees the descriptor as an array of 32-bit words in -+ * order for the compiler to know its size, but the internal details are not -+ * exposed. The following macro is used within the driver for converting *any* -+ * descriptor pointer to a usable array pointer. The use of a macro (instead of -+ * an inline) is necessary to work with different descriptor types and to work -+ * correctly with const and non-const inputs (and similarly-qualified outputs). -+ */ -+#define qb_cl(d) (&(d)->dont_manipulate_directly[0]) -+ -+#endif /* __FSL_QBMAN_PORTAL_H */ ---- /dev/null -+++ b/drivers/staging/fsl-mc/bus/dpio/qbman_debug.c -@@ -0,0 +1,853 @@ -+/* Copyright (C) 2015 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 <linux/errno.h> -+ -+#include "../../include/dpaa2-global.h" -+#include "qbman-portal.h" -+#include "qbman_debug.h" -+ -+/* QBMan portal management command code */ -+#define QBMAN_BP_QUERY 0x32 -+#define QBMAN_FQ_QUERY 0x44 -+#define QBMAN_FQ_QUERY_NP 0x45 -+#define QBMAN_CGR_QUERY 0x51 -+#define QBMAN_WRED_QUERY 0x54 -+#define QBMAN_CGR_STAT_QUERY 0x55 -+#define QBMAN_CGR_STAT_QUERY_CLR 0x56 -+ -+enum qbman_attr_usage_e { -+ qbman_attr_usage_fq, -+ qbman_attr_usage_bpool, -+ qbman_attr_usage_cgr, -+}; -+ -+struct int_qbman_attr { -+ u32 words[32]; -+ enum qbman_attr_usage_e usage; ++/* Query APIs */ ++struct qbman_fq_query_np_rslt { ++ u8 verb; ++ u8 rslt; ++ u8 st1; ++ u8 st2; ++ u8 reserved[2]; ++ u16 od1_sfdr; ++ u16 od2_sfdr; ++ u16 od3_sfdr; ++ u16 ra1_sfdr; ++ u16 ra2_sfdr; ++ u32 pfdr_hptr; ++ u32 pfdr_tptr; ++ u32 frm_cnt; ++ u32 byte_cnt; ++ u16 ics_surp; ++ u8 is; ++ u8 reserved2[29]; +}; + -+#define attr_type_set(a, e) \ -+{ \ -+ struct qbman_attr *__attr = a; \ -+ enum qbman_attr_usage_e __usage = e; \ -+ ((struct int_qbman_attr *)__attr)->usage = __usage; \ -+} -+ -+#define ATTR32(d) (&(d)->dont_manipulate_directly[0]) -+#define ATTR32_1(d) (&(d)->dont_manipulate_directly[16]) -+ -+static struct qb_attr_code code_bp_bpid = QB_CODE(0, 16, 16); -+static struct qb_attr_code code_bp_bdi = QB_CODE(1, 16, 1); -+static struct qb_attr_code code_bp_va = QB_CODE(1, 17, 1); -+static struct qb_attr_code code_bp_wae = QB_CODE(1, 18, 1); -+static struct qb_attr_code code_bp_swdet = QB_CODE(4, 0, 16); -+static struct qb_attr_code code_bp_swdxt = QB_CODE(4, 16, 16); -+static struct qb_attr_code code_bp_hwdet = QB_CODE(5, 0, 16); -+static struct qb_attr_code code_bp_hwdxt = QB_CODE(5, 16, 16); -+static struct qb_attr_code code_bp_swset = QB_CODE(6, 0, 16); -+static struct qb_attr_code code_bp_swsxt = QB_CODE(6, 16, 16); -+static struct qb_attr_code code_bp_vbpid = QB_CODE(7, 0, 14); -+static struct qb_attr_code code_bp_icid = QB_CODE(7, 16, 15); -+static struct qb_attr_code code_bp_pl = QB_CODE(7, 31, 1); -+static struct qb_attr_code code_bp_bpscn_addr_lo = QB_CODE(8, 0, 32); -+static struct qb_attr_code code_bp_bpscn_addr_hi = QB_CODE(9, 0, 32); -+static struct qb_attr_code code_bp_bpscn_ctx_lo = QB_CODE(10, 0, 32); -+static struct qb_attr_code code_bp_bpscn_ctx_hi = QB_CODE(11, 0, 32); -+static struct qb_attr_code code_bp_hw_targ = QB_CODE(12, 0, 16); -+static struct qb_attr_code code_bp_state = QB_CODE(1, 24, 3); -+static struct qb_attr_code code_bp_fill = QB_CODE(2, 0, 32); -+static struct qb_attr_code code_bp_hdptr = QB_CODE(3, 0, 32); -+static struct qb_attr_code code_bp_sdcnt = QB_CODE(13, 0, 8); -+static struct qb_attr_code code_bp_hdcnt = QB_CODE(13, 1, 8); -+static struct qb_attr_code code_bp_sscnt = QB_CODE(13, 2, 8); -+ -+void qbman_bp_attr_clear(struct qbman_attr *a) -+{ -+ memset(a, 0, sizeof(*a)); -+ attr_type_set(a, qbman_attr_usage_bpool); -+} -+ -+int qbman_bp_query(struct qbman_swp *s, u32 bpid, -+ struct qbman_attr *a) -+{ -+ u32 *p; -+ u32 verb, rslt; -+ u32 *attr = ATTR32(a); -+ -+ qbman_bp_attr_clear(a); -+ -+ /* Start the management command */ -+ p = qbman_swp_mc_start(s); -+ if (!p) -+ return -EBUSY; -+ -+ /* Encode the caller-provided attributes */ -+ qb_attr_code_encode(&code_bp_bpid, p, bpid); -+ -+ /* Complete the management command */ -+ p = qbman_swp_mc_complete(s, p, QBMAN_BP_QUERY); -+ -+ /* Decode the outcome */ -+ verb = qb_attr_code_decode(&code_generic_verb, p); -+ rslt = qb_attr_code_decode(&code_generic_rslt, p); -+ WARN_ON(verb != QBMAN_BP_QUERY); -+ -+ /* Determine success or failure */ -+ if (unlikely(rslt != QBMAN_MC_RSLT_OK)) { -+ pr_err("Query of BPID 0x%x failed, code=0x%02x\n", bpid, rslt); -+ return -EIO; -+ } -+ -+ /* For the query, word[0] of the result contains only the -+ * verb/rslt fields, so skip word[0]. -+ */ -+ word_copy(&attr[1], &p[1], 15); -+ return 0; -+} -+ -+void qbman_bp_attr_get_bdi(struct qbman_attr *a, int *bdi, int *va, int *wae) -+{ -+ u32 *p = ATTR32(a); -+ -+ *bdi = !!qb_attr_code_decode(&code_bp_bdi, p); -+ *va = !!qb_attr_code_decode(&code_bp_va, p); -+ *wae = !!qb_attr_code_decode(&code_bp_wae, p); -+} -+ -+static u32 qbman_bp_thresh_to_value(u32 val) -+{ -+ return (val & 0xff) << ((val & 0xf00) >> 8); -+} -+ -+void qbman_bp_attr_get_swdet(struct qbman_attr *a, u32 *swdet) -+{ -+ u32 *p = ATTR32(a); -+ -+ *swdet = qbman_bp_thresh_to_value(qb_attr_code_decode(&code_bp_swdet, -+ p)); -+} -+ -+void qbman_bp_attr_get_swdxt(struct qbman_attr *a, u32 *swdxt) -+{ -+ u32 *p = ATTR32(a); -+ -+ *swdxt = qbman_bp_thresh_to_value(qb_attr_code_decode(&code_bp_swdxt, -+ p)); -+} -+ -+void qbman_bp_attr_get_hwdet(struct qbman_attr *a, u32 *hwdet) -+{ -+ u32 *p = ATTR32(a); -+ -+ *hwdet = qbman_bp_thresh_to_value(qb_attr_code_decode(&code_bp_hwdet, -+ p)); -+} -+ -+void qbman_bp_attr_get_hwdxt(struct qbman_attr *a, u32 *hwdxt) -+{ -+ u32 *p = ATTR32(a); -+ -+ *hwdxt = qbman_bp_thresh_to_value(qb_attr_code_decode(&code_bp_hwdxt, -+ p)); -+} -+ -+void qbman_bp_attr_get_swset(struct qbman_attr *a, u32 *swset) -+{ -+ u32 *p = ATTR32(a); -+ -+ *swset = qbman_bp_thresh_to_value(qb_attr_code_decode(&code_bp_swset, -+ p)); -+} -+ -+void qbman_bp_attr_get_swsxt(struct qbman_attr *a, u32 *swsxt) -+{ -+ u32 *p = ATTR32(a); -+ -+ *swsxt = qbman_bp_thresh_to_value(qb_attr_code_decode(&code_bp_swsxt, -+ p)); -+} -+ -+void qbman_bp_attr_get_vbpid(struct qbman_attr *a, u32 *vbpid) -+{ -+ u32 *p = ATTR32(a); -+ -+ *vbpid = qb_attr_code_decode(&code_bp_vbpid, p); -+} -+ -+void qbman_bp_attr_get_icid(struct qbman_attr *a, u32 *icid, int *pl) -+{ -+ u32 *p = ATTR32(a); -+ -+ *icid = qb_attr_code_decode(&code_bp_icid, p); -+ *pl = !!qb_attr_code_decode(&code_bp_pl, p); -+} -+ -+void qbman_bp_attr_get_bpscn_addr(struct qbman_attr *a, u64 *bpscn_addr) -+{ -+ u32 *p = ATTR32(a); -+ -+ *bpscn_addr = ((u64)qb_attr_code_decode(&code_bp_bpscn_addr_hi, -+ p) << 32) | -+ (u64)qb_attr_code_decode(&code_bp_bpscn_addr_lo, -+ p); -+} -+ -+void qbman_bp_attr_get_bpscn_ctx(struct qbman_attr *a, u64 *bpscn_ctx) -+{ -+ u32 *p = ATTR32(a); -+ -+ *bpscn_ctx = ((u64)qb_attr_code_decode(&code_bp_bpscn_ctx_hi, p) -+ << 32) | -+ (u64)qb_attr_code_decode(&code_bp_bpscn_ctx_lo, -+ p); -+} -+ -+void qbman_bp_attr_get_hw_targ(struct qbman_attr *a, u32 *hw_targ) -+{ -+ u32 *p = ATTR32(a); -+ -+ *hw_targ = qb_attr_code_decode(&code_bp_hw_targ, p); -+} -+ -+int qbman_bp_info_has_free_bufs(struct qbman_attr *a) -+{ -+ u32 *p = ATTR32(a); -+ -+ return !(int)(qb_attr_code_decode(&code_bp_state, p) & 0x1); -+} -+ -+int qbman_bp_info_is_depleted(struct qbman_attr *a) -+{ -+ u32 *p = ATTR32(a); -+ -+ return (int)(qb_attr_code_decode(&code_bp_state, p) & 0x2); -+} -+ -+int qbman_bp_info_is_surplus(struct qbman_attr *a) -+{ -+ u32 *p = ATTR32(a); -+ -+ return (int)(qb_attr_code_decode(&code_bp_state, p) & 0x4); -+} -+ -+u32 qbman_bp_info_num_free_bufs(struct qbman_attr *a) -+{ -+ u32 *p = ATTR32(a); -+ -+ return qb_attr_code_decode(&code_bp_fill, p); -+} -+ -+u32 qbman_bp_info_hdptr(struct qbman_attr *a) -+{ -+ u32 *p = ATTR32(a); -+ -+ return qb_attr_code_decode(&code_bp_hdptr, p); -+} -+ -+u32 qbman_bp_info_sdcnt(struct qbman_attr *a) -+{ -+ u32 *p = ATTR32(a); -+ -+ return qb_attr_code_decode(&code_bp_sdcnt, p); -+} -+ -+u32 qbman_bp_info_hdcnt(struct qbman_attr *a) -+{ -+ u32 *p = ATTR32(a); -+ -+ return qb_attr_code_decode(&code_bp_hdcnt, p); -+} -+ -+u32 qbman_bp_info_sscnt(struct qbman_attr *a) -+{ -+ u32 *p = ATTR32(a); -+ -+ return qb_attr_code_decode(&code_bp_sscnt, p); -+} -+ -+static struct qb_attr_code code_fq_fqid = QB_CODE(1, 0, 24); -+static struct qb_attr_code code_fq_cgrid = QB_CODE(2, 16, 16); -+static struct qb_attr_code code_fq_destwq = QB_CODE(3, 0, 15); -+static struct qb_attr_code code_fq_fqctrl = QB_CODE(3, 24, 8); -+static struct qb_attr_code code_fq_icscred = QB_CODE(4, 0, 15); -+static struct qb_attr_code code_fq_tdthresh = QB_CODE(4, 16, 13); -+static struct qb_attr_code code_fq_oa_len = QB_CODE(5, 0, 12); -+static struct qb_attr_code code_fq_oa_ics = QB_CODE(5, 14, 1); -+static struct qb_attr_code code_fq_oa_cgr = QB_CODE(5, 15, 1); -+static struct qb_attr_code code_fq_mctl_bdi = QB_CODE(5, 24, 1); -+static struct qb_attr_code code_fq_mctl_ff = QB_CODE(5, 25, 1); -+static struct qb_attr_code code_fq_mctl_va = QB_CODE(5, 26, 1); -+static struct qb_attr_code code_fq_mctl_ps = QB_CODE(5, 27, 1); -+static struct qb_attr_code code_fq_ctx_lower32 = QB_CODE(6, 0, 32); -+static struct qb_attr_code code_fq_ctx_upper32 = QB_CODE(7, 0, 32); -+static struct qb_attr_code code_fq_icid = QB_CODE(8, 0, 15); -+static struct qb_attr_code code_fq_pl = QB_CODE(8, 15, 1); -+static struct qb_attr_code code_fq_vfqid = QB_CODE(9, 0, 24); -+static struct qb_attr_code code_fq_erfqid = QB_CODE(10, 0, 24); -+ -+void qbman_fq_attr_clear(struct qbman_attr *a) -+{ -+ memset(a, 0, sizeof(*a)); -+ attr_type_set(a, qbman_attr_usage_fq); -+} -+ -+/* FQ query function for programmable fields */ -+int qbman_fq_query(struct qbman_swp *s, u32 fqid, struct qbman_attr *desc) -+{ -+ u32 *p; -+ u32 verb, rslt; -+ u32 *d = ATTR32(desc); -+ -+ qbman_fq_attr_clear(desc); -+ -+ p = qbman_swp_mc_start(s); -+ if (!p) -+ return -EBUSY; -+ qb_attr_code_encode(&code_fq_fqid, p, fqid); -+ p = qbman_swp_mc_complete(s, p, QBMAN_FQ_QUERY); -+ -+ /* Decode the outcome */ -+ verb = qb_attr_code_decode(&code_generic_verb, p); -+ rslt = qb_attr_code_decode(&code_generic_rslt, p); -+ WARN_ON(verb != QBMAN_FQ_QUERY); -+ -+ /* Determine success or failure */ -+ if (unlikely(rslt != QBMAN_MC_RSLT_OK)) { -+ pr_err("Query of FQID 0x%x failed, code=0x%02x\n", -+ fqid, rslt); -+ return -EIO; -+ } -+ /* -+ * For the configure, word[0] of the command contains only the WE-mask. -+ * For the query, word[0] of the result contains only the verb/rslt -+ * fields. Skip word[0] in the latter case. -+ */ -+ word_copy(&d[1], &p[1], 15); -+ return 0; -+} -+ -+void qbman_fq_attr_get_fqctrl(struct qbman_attr *d, u32 *fqctrl) -+{ -+ u32 *p = ATTR32(d); -+ -+ *fqctrl = qb_attr_code_decode(&code_fq_fqctrl, p); -+} -+ -+void qbman_fq_attr_get_cgrid(struct qbman_attr *d, u32 *cgrid) -+{ -+ u32 *p = ATTR32(d); -+ -+ *cgrid = qb_attr_code_decode(&code_fq_cgrid, p); -+} -+ -+void qbman_fq_attr_get_destwq(struct qbman_attr *d, u32 *destwq) -+{ -+ u32 *p = ATTR32(d); -+ -+ *destwq = qb_attr_code_decode(&code_fq_destwq, p); -+} -+ -+void qbman_fq_attr_get_icscred(struct qbman_attr *d, u32 *icscred) -+{ -+ u32 *p = ATTR32(d); -+ -+ *icscred = qb_attr_code_decode(&code_fq_icscred, p); -+} -+ -+static struct qb_attr_code code_tdthresh_exp = QB_CODE(0, 0, 5); -+static struct qb_attr_code code_tdthresh_mant = QB_CODE(0, 5, 8); -+static u32 qbman_thresh_to_value(u32 val) -+{ -+ u32 m, e; -+ -+ m = qb_attr_code_decode(&code_tdthresh_mant, &val); -+ e = qb_attr_code_decode(&code_tdthresh_exp, &val); -+ return m << e; -+} -+ -+void qbman_fq_attr_get_tdthresh(struct qbman_attr *d, u32 *tdthresh) -+{ -+ u32 *p = ATTR32(d); -+ -+ *tdthresh = qbman_thresh_to_value(qb_attr_code_decode(&code_fq_tdthresh, -+ p)); -+} -+ -+void qbman_fq_attr_get_oa(struct qbman_attr *d, -+ int *oa_ics, int *oa_cgr, int32_t *oa_len) -+{ -+ u32 *p = ATTR32(d); -+ -+ *oa_ics = !!qb_attr_code_decode(&code_fq_oa_ics, p); -+ *oa_cgr = !!qb_attr_code_decode(&code_fq_oa_cgr, p); -+ *oa_len = qb_attr_code_makesigned(&code_fq_oa_len, -+ qb_attr_code_decode(&code_fq_oa_len, p)); -+} -+ -+void qbman_fq_attr_get_mctl(struct qbman_attr *d, -+ int *bdi, int *ff, int *va, int *ps) -+{ -+ u32 *p = ATTR32(d); -+ -+ *bdi = !!qb_attr_code_decode(&code_fq_mctl_bdi, p); -+ *ff = !!qb_attr_code_decode(&code_fq_mctl_ff, p); -+ *va = !!qb_attr_code_decode(&code_fq_mctl_va, p); -+ *ps = !!qb_attr_code_decode(&code_fq_mctl_ps, p); -+} -+ -+void qbman_fq_attr_get_ctx(struct qbman_attr *d, u32 *hi, u32 *lo) -+{ -+ u32 *p = ATTR32(d); -+ -+ *hi = qb_attr_code_decode(&code_fq_ctx_upper32, p); -+ *lo = qb_attr_code_decode(&code_fq_ctx_lower32, p); -+} -+ -+void qbman_fq_attr_get_icid(struct qbman_attr *d, u32 *icid, int *pl) -+{ -+ u32 *p = ATTR32(d); -+ -+ *icid = qb_attr_code_decode(&code_fq_icid, p); -+ *pl = !!qb_attr_code_decode(&code_fq_pl, p); -+} -+ -+void qbman_fq_attr_get_vfqid(struct qbman_attr *d, u32 *vfqid) -+{ -+ u32 *p = ATTR32(d); -+ -+ *vfqid = qb_attr_code_decode(&code_fq_vfqid, p); -+} -+ -+void qbman_fq_attr_get_erfqid(struct qbman_attr *d, u32 *erfqid) -+{ -+ u32 *p = ATTR32(d); -+ -+ *erfqid = qb_attr_code_decode(&code_fq_erfqid, p); -+} -+ -+/* Query FQ Non-Programmalbe Fields */ -+static struct qb_attr_code code_fq_np_state = QB_CODE(0, 16, 3); -+static struct qb_attr_code code_fq_np_fe = QB_CODE(0, 19, 1); -+static struct qb_attr_code code_fq_np_x = QB_CODE(0, 20, 1); -+static struct qb_attr_code code_fq_np_r = QB_CODE(0, 21, 1); -+static struct qb_attr_code code_fq_np_oe = QB_CODE(0, 22, 1); -+static struct qb_attr_code code_fq_np_frm_cnt = QB_CODE(6, 0, 24); -+static struct qb_attr_code code_fq_np_byte_cnt = QB_CODE(7, 0, 32); -+ +int qbman_fq_query_state(struct qbman_swp *s, u32 fqid, -+ struct qbman_attr *state) -+{ -+ u32 *p; -+ u32 verb, rslt; -+ u32 *d = ATTR32(state); -+ -+ qbman_fq_attr_clear(state); -+ -+ p = qbman_swp_mc_start(s); -+ if (!p) -+ return -EBUSY; -+ qb_attr_code_encode(&code_fq_fqid, p, fqid); -+ p = qbman_swp_mc_complete(s, p, QBMAN_FQ_QUERY_NP); -+ -+ /* Decode the outcome */ -+ verb = qb_attr_code_decode(&code_generic_verb, p); -+ rslt = qb_attr_code_decode(&code_generic_rslt, p); -+ WARN_ON(verb != QBMAN_FQ_QUERY_NP); -+ -+ /* Determine success or failure */ -+ if (unlikely(rslt != QBMAN_MC_RSLT_OK)) { -+ pr_err("Query NP fields of FQID 0x%x failed, code=0x%02x\n", -+ fqid, rslt); -+ return -EIO; -+ } -+ word_copy(&d[0], &p[0], 16); -+ return 0; -+} -+ -+u32 qbman_fq_state_schedstate(const struct qbman_attr *state) -+{ -+ const u32 *p = ATTR32(state); -+ -+ return qb_attr_code_decode(&code_fq_np_state, p); -+} -+ -+int qbman_fq_state_force_eligible(const struct qbman_attr *state) -+{ -+ const u32 *p = ATTR32(state); -+ -+ return !!qb_attr_code_decode(&code_fq_np_fe, p); -+} -+ -+int qbman_fq_state_xoff(const struct qbman_attr *state) -+{ -+ const u32 *p = ATTR32(state); -+ -+ return !!qb_attr_code_decode(&code_fq_np_x, p); -+} -+ -+int qbman_fq_state_retirement_pending(const struct qbman_attr *state) -+{ -+ const u32 *p = ATTR32(state); -+ -+ return !!qb_attr_code_decode(&code_fq_np_r, p); -+} -+ -+int qbman_fq_state_overflow_error(const struct qbman_attr *state) -+{ -+ const u32 *p = ATTR32(state); -+ -+ return !!qb_attr_code_decode(&code_fq_np_oe, p); -+} -+ -+u32 qbman_fq_state_frame_count(const struct qbman_attr *state) -+{ -+ const u32 *p = ATTR32(state); -+ -+ return qb_attr_code_decode(&code_fq_np_frm_cnt, p); -+} -+ -+u32 qbman_fq_state_byte_count(const struct qbman_attr *state) -+{ -+ const u32 *p = ATTR32(state); -+ -+ return qb_attr_code_decode(&code_fq_np_byte_cnt, p); -+} -+ -+/* Query CGR */ -+static struct qb_attr_code code_cgr_cgid = QB_CODE(0, 16, 16); -+static struct qb_attr_code code_cgr_cscn_wq_en_enter = QB_CODE(2, 0, 1); -+static struct qb_attr_code code_cgr_cscn_wq_en_exit = QB_CODE(2, 1, 1); -+static struct qb_attr_code code_cgr_cscn_wq_icd = QB_CODE(2, 2, 1); -+static struct qb_attr_code code_cgr_mode = QB_CODE(3, 16, 2); -+static struct qb_attr_code code_cgr_rej_cnt_mode = QB_CODE(3, 18, 1); -+static struct qb_attr_code code_cgr_cscn_bdi = QB_CODE(3, 19, 1); -+static struct qb_attr_code code_cgr_cscn_wr_en_enter = QB_CODE(3, 24, 1); -+static struct qb_attr_code code_cgr_cscn_wr_en_exit = QB_CODE(3, 25, 1); -+static struct qb_attr_code code_cgr_cg_wr_ae = QB_CODE(3, 26, 1); -+static struct qb_attr_code code_cgr_cscn_dcp_en = QB_CODE(3, 27, 1); -+static struct qb_attr_code code_cgr_cg_wr_va = QB_CODE(3, 28, 1); -+static struct qb_attr_code code_cgr_i_cnt_wr_en = QB_CODE(4, 0, 1); -+static struct qb_attr_code code_cgr_i_cnt_wr_bnd = QB_CODE(4, 1, 5); -+static struct qb_attr_code code_cgr_td_en = QB_CODE(4, 8, 1); -+static struct qb_attr_code code_cgr_cs_thres = QB_CODE(4, 16, 13); -+static struct qb_attr_code code_cgr_cs_thres_x = QB_CODE(5, 0, 13); -+static struct qb_attr_code code_cgr_td_thres = QB_CODE(5, 16, 13); -+static struct qb_attr_code code_cgr_cscn_tdcp = QB_CODE(6, 0, 16); -+static struct qb_attr_code code_cgr_cscn_wqid = QB_CODE(6, 16, 16); -+static struct qb_attr_code code_cgr_cscn_vcgid = QB_CODE(7, 0, 16); -+static struct qb_attr_code code_cgr_cg_icid = QB_CODE(7, 16, 15); -+static struct qb_attr_code code_cgr_cg_pl = QB_CODE(7, 31, 1); -+static struct qb_attr_code code_cgr_cg_wr_addr_lo = QB_CODE(8, 0, 32); -+static struct qb_attr_code code_cgr_cg_wr_addr_hi = QB_CODE(9, 0, 32); -+static struct qb_attr_code code_cgr_cscn_ctx_lo = QB_CODE(10, 0, 32); -+static struct qb_attr_code code_cgr_cscn_ctx_hi = QB_CODE(11, 0, 32); ++ struct qbman_fq_query_np_rslt *r); ++u32 qbman_fq_state_frame_count(const struct qbman_fq_query_np_rslt *r); ++u32 qbman_fq_state_byte_count(const struct qbman_fq_query_np_rslt *r); + -+void qbman_cgr_attr_clear(struct qbman_attr *a) -+{ -+ memset(a, 0, sizeof(*a)); -+ attr_type_set(a, qbman_attr_usage_cgr); -+} -+ -+int qbman_cgr_query(struct qbman_swp *s, u32 cgid, struct qbman_attr *attr) -+{ -+ u32 *p; -+ u32 verb, rslt; -+ u32 *d[2]; -+ int i; -+ u32 query_verb; -+ -+ d[0] = ATTR32(attr); -+ d[1] = ATTR32_1(attr); -+ -+ qbman_cgr_attr_clear(attr); -+ -+ for (i = 0; i < 2; i++) { -+ p = qbman_swp_mc_start(s); -+ if (!p) -+ return -EBUSY; -+ query_verb = i ? QBMAN_WRED_QUERY : QBMAN_CGR_QUERY; -+ -+ qb_attr_code_encode(&code_cgr_cgid, p, cgid); -+ p = qbman_swp_mc_complete(s, p, p[0] | query_verb); -+ -+ /* Decode the outcome */ -+ verb = qb_attr_code_decode(&code_generic_verb, p); -+ rslt = qb_attr_code_decode(&code_generic_rslt, p); -+ WARN_ON(verb != query_verb); -+ -+ /* Determine success or failure */ -+ if (unlikely(rslt != QBMAN_MC_RSLT_OK)) { -+ pr_err("Query CGID 0x%x failed,", cgid); -+ pr_err(" verb=0x%02x, code=0x%02x\n", verb, rslt); -+ return -EIO; -+ } -+ /* For the configure, word[0] of the command contains only the -+ * verb/cgid. For the query, word[0] of the result contains -+ * only the verb/rslt fields. Skip word[0] in the latter case. -+ */ -+ word_copy(&d[i][1], &p[1], 15); -+ } -+ return 0; -+} -+ -+void qbman_cgr_attr_get_ctl1(struct qbman_attr *d, int *cscn_wq_en_enter, -+ int *cscn_wq_en_exit, int *cscn_wq_icd) -+ { -+ u32 *p = ATTR32(d); -+ *cscn_wq_en_enter = !!qb_attr_code_decode(&code_cgr_cscn_wq_en_enter, -+ p); -+ *cscn_wq_en_exit = !!qb_attr_code_decode(&code_cgr_cscn_wq_en_exit, p); -+ *cscn_wq_icd = !!qb_attr_code_decode(&code_cgr_cscn_wq_icd, p); -+} -+ -+void qbman_cgr_attr_get_mode(struct qbman_attr *d, u32 *mode, -+ int *rej_cnt_mode, int *cscn_bdi) -+{ -+ u32 *p = ATTR32(d); -+ *mode = qb_attr_code_decode(&code_cgr_mode, p); -+ *rej_cnt_mode = !!qb_attr_code_decode(&code_cgr_rej_cnt_mode, p); -+ *cscn_bdi = !!qb_attr_code_decode(&code_cgr_cscn_bdi, p); -+} -+ -+void qbman_cgr_attr_get_ctl2(struct qbman_attr *d, int *cscn_wr_en_enter, -+ int *cscn_wr_en_exit, int *cg_wr_ae, -+ int *cscn_dcp_en, int *cg_wr_va) -+{ -+ u32 *p = ATTR32(d); -+ *cscn_wr_en_enter = !!qb_attr_code_decode(&code_cgr_cscn_wr_en_enter, -+ p); -+ *cscn_wr_en_exit = !!qb_attr_code_decode(&code_cgr_cscn_wr_en_exit, p); -+ *cg_wr_ae = !!qb_attr_code_decode(&code_cgr_cg_wr_ae, p); -+ *cscn_dcp_en = !!qb_attr_code_decode(&code_cgr_cscn_dcp_en, p); -+ *cg_wr_va = !!qb_attr_code_decode(&code_cgr_cg_wr_va, p); -+} -+ -+void qbman_cgr_attr_get_iwc(struct qbman_attr *d, int *i_cnt_wr_en, -+ u32 *i_cnt_wr_bnd) -+{ -+ u32 *p = ATTR32(d); -+ *i_cnt_wr_en = !!qb_attr_code_decode(&code_cgr_i_cnt_wr_en, p); -+ *i_cnt_wr_bnd = qb_attr_code_decode(&code_cgr_i_cnt_wr_bnd, p); -+} -+ -+void qbman_cgr_attr_get_tdc(struct qbman_attr *d, int *td_en) -+{ -+ u32 *p = ATTR32(d); -+ *td_en = !!qb_attr_code_decode(&code_cgr_td_en, p); -+} -+ -+void qbman_cgr_attr_get_cs_thres(struct qbman_attr *d, u32 *cs_thres) -+{ -+ u32 *p = ATTR32(d); -+ *cs_thres = qbman_thresh_to_value(qb_attr_code_decode( -+ &code_cgr_cs_thres, p)); -+} -+ -+void qbman_cgr_attr_get_cs_thres_x(struct qbman_attr *d, -+ u32 *cs_thres_x) -+{ -+ u32 *p = ATTR32(d); -+ *cs_thres_x = qbman_thresh_to_value(qb_attr_code_decode( -+ &code_cgr_cs_thres_x, p)); -+} -+ -+void qbman_cgr_attr_get_td_thres(struct qbman_attr *d, u32 *td_thres) -+{ -+ u32 *p = ATTR32(d); -+ *td_thres = qbman_thresh_to_value(qb_attr_code_decode( -+ &code_cgr_td_thres, p)); -+} -+ -+void qbman_cgr_attr_get_cscn_tdcp(struct qbman_attr *d, u32 *cscn_tdcp) -+{ -+ u32 *p = ATTR32(d); -+ *cscn_tdcp = qb_attr_code_decode(&code_cgr_cscn_tdcp, p); -+} -+ -+void qbman_cgr_attr_get_cscn_wqid(struct qbman_attr *d, u32 *cscn_wqid) -+{ -+ u32 *p = ATTR32(d); -+ *cscn_wqid = qb_attr_code_decode(&code_cgr_cscn_wqid, p); -+} -+ -+void qbman_cgr_attr_get_cscn_vcgid(struct qbman_attr *d, -+ u32 *cscn_vcgid) -+{ -+ u32 *p = ATTR32(d); -+ *cscn_vcgid = qb_attr_code_decode(&code_cgr_cscn_vcgid, p); -+} -+ -+void qbman_cgr_attr_get_cg_icid(struct qbman_attr *d, u32 *icid, -+ int *pl) -+{ -+ u32 *p = ATTR32(d); -+ *icid = qb_attr_code_decode(&code_cgr_cg_icid, p); -+ *pl = !!qb_attr_code_decode(&code_cgr_cg_pl, p); -+} -+ -+void qbman_cgr_attr_get_cg_wr_addr(struct qbman_attr *d, -+ u64 *cg_wr_addr) -+{ -+ u32 *p = ATTR32(d); -+ *cg_wr_addr = ((u64)qb_attr_code_decode(&code_cgr_cg_wr_addr_hi, -+ p) << 32) | -+ (u64)qb_attr_code_decode(&code_cgr_cg_wr_addr_lo, -+ p); -+} -+ -+void qbman_cgr_attr_get_cscn_ctx(struct qbman_attr *d, u64 *cscn_ctx) -+{ -+ u32 *p = ATTR32(d); -+ *cscn_ctx = ((u64)qb_attr_code_decode(&code_cgr_cscn_ctx_hi, p) -+ << 32) | -+ (u64)qb_attr_code_decode(&code_cgr_cscn_ctx_lo, p); -+} -+ -+#define WRED_EDP_WORD(n) (18 + (n) / 4) -+#define WRED_EDP_OFFSET(n) (8 * ((n) % 4)) -+#define WRED_PARM_DP_WORD(n) ((n) + 20) -+#define WRED_WE_EDP(n) (16 + (n) * 2) -+#define WRED_WE_PARM_DP(n) (17 + (n) * 2) -+void qbman_cgr_attr_wred_get_edp(struct qbman_attr *d, u32 idx, -+ int *edp) -+{ -+ u32 *p = ATTR32(d); -+ struct qb_attr_code code_wred_edp = QB_CODE(WRED_EDP_WORD(idx), -+ WRED_EDP_OFFSET(idx), 8); -+ *edp = (int)qb_attr_code_decode(&code_wred_edp, p); -+} -+ -+void qbman_cgr_attr_wred_dp_decompose(u32 dp, u64 *minth, -+ u64 *maxth, u8 *maxp) -+{ -+ u8 ma, mn, step_i, step_s, pn; -+ -+ ma = (u8)(dp >> 24); -+ mn = (u8)(dp >> 19) & 0x1f; -+ step_i = (u8)(dp >> 11); -+ step_s = (u8)(dp >> 6) & 0x1f; -+ pn = (u8)dp & 0x3f; -+ -+ *maxp = ((pn << 2) * 100) / 256; -+ -+ if (mn == 0) -+ *maxth = ma; -+ else -+ *maxth = ((ma + 256) * (1 << (mn - 1))); -+ -+ if (step_s == 0) -+ *minth = *maxth - step_i; -+ else -+ *minth = *maxth - (256 + step_i) * (1 << (step_s - 1)); -+} -+ -+void qbman_cgr_attr_wred_get_parm_dp(struct qbman_attr *d, u32 idx, -+ u32 *dp) -+{ -+ u32 *p = ATTR32(d); -+ struct qb_attr_code code_wred_parm_dp = QB_CODE(WRED_PARM_DP_WORD(idx), -+ 0, 8); -+ *dp = qb_attr_code_decode(&code_wred_parm_dp, p); -+} -+ -+/* Query CGR/CCGR/CQ statistics */ -+static struct qb_attr_code code_cgr_stat_ct = QB_CODE(4, 0, 32); -+static struct qb_attr_code code_cgr_stat_frame_cnt_lo = QB_CODE(4, 0, 32); -+static struct qb_attr_code code_cgr_stat_frame_cnt_hi = QB_CODE(5, 0, 8); -+static struct qb_attr_code code_cgr_stat_byte_cnt_lo = QB_CODE(6, 0, 32); -+static struct qb_attr_code code_cgr_stat_byte_cnt_hi = QB_CODE(7, 0, 16); -+static int qbman_cgr_statistics_query(struct qbman_swp *s, u32 cgid, -+ int clear, u32 command_type, -+ u64 *frame_cnt, u64 *byte_cnt) -+{ -+ u32 *p; -+ u32 verb, rslt; -+ u32 query_verb; -+ u32 hi, lo; -+ -+ p = qbman_swp_mc_start(s); -+ if (!p) -+ return -EBUSY; -+ -+ qb_attr_code_encode(&code_cgr_cgid, p, cgid); -+ if (command_type < 2) -+ qb_attr_code_encode(&code_cgr_stat_ct, p, command_type); -+ query_verb = clear ? -+ QBMAN_CGR_STAT_QUERY_CLR : QBMAN_CGR_STAT_QUERY; -+ p = qbman_swp_mc_complete(s, p, p[0] | query_verb); -+ -+ /* Decode the outcome */ -+ verb = qb_attr_code_decode(&code_generic_verb, p); -+ rslt = qb_attr_code_decode(&code_generic_rslt, p); -+ WARN_ON(verb != query_verb); -+ -+ /* Determine success or failure */ -+ if (unlikely(rslt != QBMAN_MC_RSLT_OK)) { -+ pr_err("Query statistics of CGID 0x%x failed,", cgid); -+ pr_err(" verb=0x%02x code=0x%02x\n", verb, rslt); -+ return -EIO; -+ } -+ -+ if (*frame_cnt) { -+ hi = qb_attr_code_decode(&code_cgr_stat_frame_cnt_hi, p); -+ lo = qb_attr_code_decode(&code_cgr_stat_frame_cnt_lo, p); -+ *frame_cnt = ((u64)hi << 32) | (u64)lo; -+ } -+ if (*byte_cnt) { -+ hi = qb_attr_code_decode(&code_cgr_stat_byte_cnt_hi, p); -+ lo = qb_attr_code_decode(&code_cgr_stat_byte_cnt_lo, p); -+ *byte_cnt = ((u64)hi << 32) | (u64)lo; -+ } -+ -+ return 0; -+} -+ -+int qbman_cgr_reject_statistics(struct qbman_swp *s, u32 cgid, int clear, -+ u64 *frame_cnt, u64 *byte_cnt) -+{ -+ return qbman_cgr_statistics_query(s, cgid, clear, 0xff, -+ frame_cnt, byte_cnt); -+} -+ -+int qbman_ccgr_reject_statistics(struct qbman_swp *s, u32 cgid, int clear, -+ u64 *frame_cnt, u64 *byte_cnt) -+{ -+ return qbman_cgr_statistics_query(s, cgid, clear, 1, -+ frame_cnt, byte_cnt); -+} -+ -+int qbman_cq_dequeue_statistics(struct qbman_swp *s, u32 cgid, int clear, -+ u64 *frame_cnt, u64 *byte_cnt) -+{ -+ return qbman_cgr_statistics_query(s, cgid, clear, 0, -+ frame_cnt, byte_cnt); -+} ---- /dev/null -+++ b/drivers/staging/fsl-mc/bus/dpio/qbman_debug.h -@@ -0,0 +1,136 @@ -+/* Copyright (C) 2015 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. -+ */ -+ -+struct qbman_attr { -+ u32 dont_manipulate_directly[40]; ++struct qbman_bp_query_rslt { ++ u8 verb; ++ u8 rslt; ++ u8 reserved[4]; ++ u8 bdi; ++ u8 state; ++ u32 fill; ++ u32 hdotr; ++ u16 swdet; ++ u16 swdxt; ++ u16 hwdet; ++ u16 hwdxt; ++ u16 swset; ++ u16 swsxt; ++ u16 vbpid; ++ u16 icid; ++ u64 bpscn_addr; ++ u64 bpscn_ctx; ++ u16 hw_targ; ++ u8 dbe; ++ u8 reserved2; ++ u8 sdcnt; ++ u8 hdcnt; ++ u8 sscnt; ++ u8 reserved3[9]; +}; + -+/* Buffer pool query commands */ +int qbman_bp_query(struct qbman_swp *s, u32 bpid, -+ struct qbman_attr *a); -+void qbman_bp_attr_get_bdi(struct qbman_attr *a, int *bdi, int *va, int *wae); -+void qbman_bp_attr_get_swdet(struct qbman_attr *a, u32 *swdet); -+void qbman_bp_attr_get_swdxt(struct qbman_attr *a, u32 *swdxt); -+void qbman_bp_attr_get_hwdet(struct qbman_attr *a, u32 *hwdet); -+void qbman_bp_attr_get_hwdxt(struct qbman_attr *a, u32 *hwdxt); -+void qbman_bp_attr_get_swset(struct qbman_attr *a, u32 *swset); -+void qbman_bp_attr_get_swsxt(struct qbman_attr *a, u32 *swsxt); -+void qbman_bp_attr_get_vbpid(struct qbman_attr *a, u32 *vbpid); -+void qbman_bp_attr_get_icid(struct qbman_attr *a, u32 *icid, int *pl); -+void qbman_bp_attr_get_bpscn_addr(struct qbman_attr *a, u64 *bpscn_addr); -+void qbman_bp_attr_get_bpscn_ctx(struct qbman_attr *a, u64 *bpscn_ctx); -+void qbman_bp_attr_get_hw_targ(struct qbman_attr *a, u32 *hw_targ); -+int qbman_bp_info_has_free_bufs(struct qbman_attr *a); -+int qbman_bp_info_is_depleted(struct qbman_attr *a); -+int qbman_bp_info_is_surplus(struct qbman_attr *a); -+u32 qbman_bp_info_num_free_bufs(struct qbman_attr *a); -+u32 qbman_bp_info_hdptr(struct qbman_attr *a); -+u32 qbman_bp_info_sdcnt(struct qbman_attr *a); -+u32 qbman_bp_info_hdcnt(struct qbman_attr *a); -+u32 qbman_bp_info_sscnt(struct qbman_attr *a); -+ -+/* FQ query function for programmable fields */ -+int qbman_fq_query(struct qbman_swp *s, u32 fqid, -+ struct qbman_attr *desc); -+void qbman_fq_attr_get_fqctrl(struct qbman_attr *d, u32 *fqctrl); -+void qbman_fq_attr_get_cgrid(struct qbman_attr *d, u32 *cgrid); -+void qbman_fq_attr_get_destwq(struct qbman_attr *d, u32 *destwq); -+void qbman_fq_attr_get_icscred(struct qbman_attr *d, u32 *icscred); -+void qbman_fq_attr_get_tdthresh(struct qbman_attr *d, u32 *tdthresh); -+void qbman_fq_attr_get_oa(struct qbman_attr *d, -+ int *oa_ics, int *oa_cgr, int32_t *oa_len); -+void qbman_fq_attr_get_mctl(struct qbman_attr *d, -+ int *bdi, int *ff, int *va, int *ps); -+void qbman_fq_attr_get_ctx(struct qbman_attr *d, u32 *hi, u32 *lo); -+void qbman_fq_attr_get_icid(struct qbman_attr *d, u32 *icid, int *pl); -+void qbman_fq_attr_get_vfqid(struct qbman_attr *d, u32 *vfqid); -+void qbman_fq_attr_get_erfqid(struct qbman_attr *d, u32 *erfqid); -+ -+/* FQ query command for non-programmable fields*/ -+enum qbman_fq_schedstate_e { -+ qbman_fq_schedstate_oos = 0, -+ qbman_fq_schedstate_retired, -+ qbman_fq_schedstate_tentatively_scheduled, -+ qbman_fq_schedstate_truly_scheduled, -+ qbman_fq_schedstate_parked, -+ qbman_fq_schedstate_held_active, -+}; ++ struct qbman_bp_query_rslt *r); + -+int qbman_fq_query_state(struct qbman_swp *s, u32 fqid, -+ struct qbman_attr *state); -+u32 qbman_fq_state_schedstate(const struct qbman_attr *state); -+int qbman_fq_state_force_eligible(const struct qbman_attr *state); -+int qbman_fq_state_xoff(const struct qbman_attr *state); -+int qbman_fq_state_retirement_pending(const struct qbman_attr *state); -+int qbman_fq_state_overflow_error(const struct qbman_attr *state); -+u32 qbman_fq_state_frame_count(const struct qbman_attr *state); -+u32 qbman_fq_state_byte_count(const struct qbman_attr *state); -+ -+/* CGR query */ -+int qbman_cgr_query(struct qbman_swp *s, u32 cgid, -+ struct qbman_attr *attr); -+void qbman_cgr_attr_get_ctl1(struct qbman_attr *d, int *cscn_wq_en_enter, -+ int *cscn_wq_en_exit, int *cscn_wq_icd); -+void qbman_cgr_attr_get_mode(struct qbman_attr *d, u32 *mode, -+ int *rej_cnt_mode, int *cscn_bdi); -+void qbman_cgr_attr_get_ctl2(struct qbman_attr *d, int *cscn_wr_en_enter, -+ int *cscn_wr_en_exit, int *cg_wr_ae, -+ int *cscn_dcp_en, int *cg_wr_va); -+void qbman_cgr_attr_get_iwc(struct qbman_attr *d, int *i_cnt_wr_en, -+ u32 *i_cnt_wr_bnd); -+void qbman_cgr_attr_get_tdc(struct qbman_attr *d, int *td_en); -+void qbman_cgr_attr_get_cs_thres(struct qbman_attr *d, u32 *cs_thres); -+void qbman_cgr_attr_get_cs_thres_x(struct qbman_attr *d, -+ u32 *cs_thres_x); -+void qbman_cgr_attr_get_td_thres(struct qbman_attr *d, u32 *td_thres); -+void qbman_cgr_attr_get_cscn_tdcp(struct qbman_attr *d, u32 *cscn_tdcp); -+void qbman_cgr_attr_get_cscn_wqid(struct qbman_attr *d, u32 *cscn_wqid); -+void qbman_cgr_attr_get_cscn_vcgid(struct qbman_attr *d, -+ u32 *cscn_vcgid); -+void qbman_cgr_attr_get_cg_icid(struct qbman_attr *d, u32 *icid, -+ int *pl); -+void qbman_cgr_attr_get_cg_wr_addr(struct qbman_attr *d, -+ u64 *cg_wr_addr); -+void qbman_cgr_attr_get_cscn_ctx(struct qbman_attr *d, u64 *cscn_ctx); -+void qbman_cgr_attr_wred_get_edp(struct qbman_attr *d, u32 idx, -+ int *edp); -+void qbman_cgr_attr_wred_dp_decompose(u32 dp, u64 *minth, -+ u64 *maxth, u8 *maxp); -+void qbman_cgr_attr_wred_get_parm_dp(struct qbman_attr *d, u32 idx, -+ u32 *dp); -+ -+/* CGR/CCGR/CQ statistics query */ -+int qbman_cgr_reject_statistics(struct qbman_swp *s, u32 cgid, int clear, -+ u64 *frame_cnt, u64 *byte_cnt); -+int qbman_ccgr_reject_statistics(struct qbman_swp *s, u32 cgid, int clear, -+ u64 *frame_cnt, u64 *byte_cnt); -+int qbman_cq_dequeue_statistics(struct qbman_swp *s, u32 cgid, int clear, -+ u64 *frame_cnt, u64 *byte_cnt); ---- /dev/null -+++ b/drivers/staging/fsl-mc/bus/dpio/qbman_private.h -@@ -0,0 +1,171 @@ -+/* Copyright (C) 2014 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. -+ */ ++u32 qbman_bp_info_num_free_bufs(struct qbman_bp_query_rslt *a); + -+/* Perform extra checking */ -+#define QBMAN_CHECKING -+ -+/* To maximise the amount of logic that is common between the Linux driver and -+ * other targets (such as the embedded MC firmware), we pivot here between the -+ * inclusion of two platform-specific headers. -+ * -+ * The first, qbman_sys_decl.h, includes any and all required system headers as -+ * well as providing any definitions for the purposes of compatibility. The -+ * second, qbman_sys.h, is where platform-specific routines go. -+ * -+ * The point of the split is that the platform-independent code (including this -+ * header) may depend on platform-specific declarations, yet other -+ * platform-specific routines may depend on platform-independent definitions. -+ */ -+ -+#define QMAN_REV_4000 0x04000000 -+#define QMAN_REV_4100 0x04010000 -+#define QMAN_REV_4101 0x04010001 -+ -+/* When things go wrong, it is a convenient trick to insert a few FOO() -+ * statements in the code to trace progress. TODO: remove this once we are -+ * hacking the code less actively. -+ */ -+#define FOO() fsl_os_print("FOO: %s:%d\n", __FILE__, __LINE__) -+ -+/* Any time there is a register interface which we poll on, this provides a -+ * "break after x iterations" scheme for it. It's handy for debugging, eg. -+ * where you don't want millions of lines of log output from a polling loop -+ * that won't, because such things tend to drown out the earlier log output -+ * that might explain what caused the problem. (NB: put ";" after each macro!) -+ * TODO: we should probably remove this once we're done sanitising the -+ * simulator... -+ */ -+#define DBG_POLL_START(loopvar) (loopvar = 1000) -+#define DBG_POLL_CHECK(loopvar) \ -+ do {if (!((loopvar)--)) WARN_ON(1); } while (0) -+ -+/* For CCSR or portal-CINH registers that contain fields at arbitrary offsets -+ * and widths, these macro-generated encode/decode/isolate/remove inlines can -+ * be used. -+ * -+ * Eg. to "d"ecode a 14-bit field out of a register (into a "u16" type), -+ * where the field is located 3 bits "up" from the least-significant bit of the -+ * register (ie. the field location within the 32-bit register corresponds to a -+ * mask of 0x0001fff8), you would do; -+ * u16 field = d32_u16(3, 14, reg_value); -+ * -+ * Or to "e"ncode a 1-bit boolean value (input type is "int", zero is FALSE, -+ * non-zero is TRUE, so must convert all non-zero inputs to 1, hence the "!!" -+ * operator) into a register at bit location 0x00080000 (19 bits "in" from the -+ * LS bit), do; -+ * reg_value |= e32_int(19, 1, !!field); -+ * -+ * If you wish to read-modify-write a register, such that you leave the 14-bit -+ * field as-is but have all other fields set to zero, then "i"solate the 14-bit -+ * value using; -+ * reg_value = i32_u16(3, 14, reg_value); -+ * -+ * Alternatively, you could "r"emove the 1-bit boolean field (setting it to -+ * zero) but leaving all other fields as-is; -+ * reg_val = r32_int(19, 1, reg_value); -+ * -+ */ -+#define MAKE_MASK32(width) (width == 32 ? 0xffffffff : \ -+ (u32)((1 << width) - 1)) -+#define DECLARE_CODEC32(t) \ -+static inline u32 e32_##t(u32 lsoffset, u32 width, t val) \ -+{ \ -+ WARN_ON(width > (sizeof(t) * 8)); \ -+ return ((u32)val & MAKE_MASK32(width)) << lsoffset; \ -+} \ -+static inline t d32_##t(u32 lsoffset, u32 width, u32 val) \ -+{ \ -+ WARN_ON(width > (sizeof(t) * 8)); \ -+ return (t)((val >> lsoffset) & MAKE_MASK32(width)); \ -+} \ -+static inline u32 i32_##t(u32 lsoffset, u32 width, \ -+ u32 val) \ -+{ \ -+ WARN_ON(width > (sizeof(t) * 8)); \ -+ return e32_##t(lsoffset, width, d32_##t(lsoffset, width, val)); \ -+} \ -+static inline u32 r32_##t(u32 lsoffset, u32 width, \ -+ u32 val) \ -+{ \ -+ WARN_ON(width > (sizeof(t) * 8)); \ -+ return ~(MAKE_MASK32(width) << lsoffset) & val; \ -+} -+DECLARE_CODEC32(u32) -+DECLARE_CODEC32(u16) -+DECLARE_CODEC32(u8) -+DECLARE_CODEC32(int) -+ -+ /*********************/ -+ /* Debugging assists */ -+ /*********************/ -+ -+static inline void __hexdump(unsigned long start, unsigned long end, -+ unsigned long p, size_t sz, -+ const unsigned char *c) -+{ -+ while (start < end) { -+ unsigned int pos = 0; -+ char buf[64]; -+ int nl = 0; -+ -+ pos += sprintf(buf + pos, "%08lx: ", start); -+ do { -+ if ((start < p) || (start >= (p + sz))) -+ pos += sprintf(buf + pos, ".."); -+ else -+ pos += sprintf(buf + pos, "%02x", *(c++)); -+ if (!(++start & 15)) { -+ buf[pos++] = '\n'; -+ nl = 1; -+ } else { -+ nl = 0; -+ if (!(start & 1)) -+ buf[pos++] = ' '; -+ if (!(start & 3)) -+ buf[pos++] = ' '; -+ } -+ } while (start & 15); -+ if (!nl) -+ buf[pos++] = '\n'; -+ buf[pos] = '\0'; -+ pr_info("%s", buf); -+ } -+} -+ -+static inline void hexdump(const void *ptr, size_t sz) -+{ -+ unsigned long p = (unsigned long)ptr; -+ unsigned long start = p & ~15ul; -+ unsigned long end = (p + sz + 15) & ~15ul; -+ const unsigned char *c = ptr; -+ -+ __hexdump(start, end, p, sz, c); -+} ++#endif /* __FSL_QBMAN_PORTAL_H */ --- a/drivers/staging/fsl-mc/bus/dpmcp-cmd.h -+++ b/drivers/staging/fsl-mc/bus/dpmcp-cmd.h -@@ -1,4 +1,5 @@ ++++ /dev/null +@@ -1,140 +0,0 @@ -/* Copyright 2013-2016 Freescale Semiconductor Inc. -+/* -+ * Copyright 2013-2016 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: -@@ -11,7 +12,6 @@ - * names of any 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 -@@ -33,108 +33,24 @@ - #define _FSL_DPMCP_CMD_H - - /* Minimal supported DPMCP Version */ +- * +- * 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 the above-listed copyright holders nor the +- * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. +- */ +-#ifndef _FSL_DPMCP_CMD_H +-#define _FSL_DPMCP_CMD_H +- +-/* Minimal supported DPMCP Version */ -#define DPMCP_MIN_VER_MAJOR 3 -#define DPMCP_MIN_VER_MINOR 0 - @@ -5626,21 +13389,15 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - __le32 irq_num; - __le32 type; -}; -+#define DPMCP_MIN_VER_MAJOR 3 -+#define DPMCP_MIN_VER_MINOR 0 - +- -#define DPMCP_ENABLE 0x1 -+/* Command versioning */ -+#define DPMCP_CMD_BASE_VERSION 1 -+#define DPMCP_CMD_ID_OFFSET 4 - +- -struct dpmcp_cmd_set_irq_enable { - u8 enable; - u8 pad[3]; - u8 irq_index; -}; -+#define DPMCP_CMD(id) ((id << DPMCP_CMD_ID_OFFSET) | DPMCP_CMD_BASE_VERSION) - +- -struct dpmcp_cmd_get_irq_enable { - __le32 pad; - u8 irq_index; @@ -5663,17 +13420,12 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> -struct dpmcp_rsp_get_irq_mask { - __le32 mask; -}; -+/* Command IDs */ -+#define DPMCP_CMDID_CLOSE DPMCP_CMD(0x800) -+#define DPMCP_CMDID_OPEN DPMCP_CMD(0x80b) -+#define DPMCP_CMDID_GET_API_VERSION DPMCP_CMD(0xa0b) - +- -struct dpmcp_cmd_get_irq_status { - __le32 status; - u8 irq_index; -}; -+#define DPMCP_CMDID_RESET DPMCP_CMD(0x005) - +- -struct dpmcp_rsp_get_irq_status { - __le32 status; -}; @@ -5685,32 +13437,118 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - /* response word 1 */ - __le16 version_major; - __le16 version_minor; -+struct dpmcp_cmd_open { -+ __le32 dpmcp_id; - }; - - #endif /* _FSL_DPMCP_CMD_H */ +-}; +- +-#endif /* _FSL_DPMCP_CMD_H */ --- a/drivers/staging/fsl-mc/bus/dpmcp.c -+++ b/drivers/staging/fsl-mc/bus/dpmcp.c -@@ -1,4 +1,5 @@ ++++ /dev/null +@@ -1,504 +0,0 @@ -/* Copyright 2013-2016 Freescale Semiconductor Inc. -+/* -+ * Copyright 2013-2016 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: -@@ -11,7 +12,6 @@ - * names of any 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 -@@ -104,76 +104,6 @@ int dpmcp_close(struct fsl_mc_io *mc_io, - } - - /** +- * +- * 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 the above-listed copyright holders nor the +- * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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/mc-sys.h" +-#include "../include/mc-cmd.h" +- +-#include "dpmcp.h" +-#include "dpmcp-cmd.h" +- +-/** +- * dpmcp_open() - Open a control session for the specified object. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @dpmcp_id: DPMCP unique ID +- * @token: Returned token; use in subsequent API calls +- * +- * This function can be used to open a control session for an +- * already created object; an object may have been declared in +- * the DPL or by calling the dpmcp_create function. +- * This function returns a unique authentication token, +- * associated with the specific object ID and the specific MC +- * portal; this token must be used in all subsequent commands for +- * this specific object +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpmcp_open(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- int dpmcp_id, +- u16 *token) +-{ +- struct mc_command cmd = { 0 }; +- struct dpmcp_cmd_open *cmd_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_OPEN, +- cmd_flags, 0); +- cmd_params = (struct dpmcp_cmd_open *)cmd.params; +- cmd_params->dpmcp_id = cpu_to_le32(dpmcp_id); +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- *token = mc_cmd_hdr_read_token(&cmd); +- +- return err; +-} +- +-/** +- * dpmcp_close() - Close the control session of the object +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPMCP object +- * +- * After this function is called, no further operations are +- * allowed on the object without opening a new control session. +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpmcp_close(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token) +-{ +- struct mc_command cmd = { 0 }; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_CLOSE, +- cmd_flags, token); +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** - * dpmcp_create() - Create the DPMCP object. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' @@ -5781,13 +13619,28 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> -} - -/** - * dpmcp_reset() - Reset the DPMCP, returns the object to initial state. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' -@@ -196,309 +126,33 @@ int dpmcp_reset(struct fsl_mc_io *mc_io, - } - - /** +- * dpmcp_reset() - Reset the DPMCP, returns the object to initial state. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPMCP object +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpmcp_reset(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token) +-{ +- struct mc_command cmd = { 0 }; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_RESET, +- cmd_flags, token); +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** - * dpmcp_set_irq() - Set IRQ information for the DPMCP to trigger an interrupt. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' @@ -5822,36 +13675,28 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> -/** - * dpmcp_get_irq() - Get IRQ information from the DPMCP. - * @mc_io: Pointer to MC portal's I/O object -+ * dpmcp_get_api_version - Get Data Path Management Command Portal API version -+ * @mc_io: Pointer to Mc portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPMCP object - * @irq_index: The interrupt index to configure - * @type: Interrupt type: 0 represents message interrupt - * type (both irq_addr and irq_val are valid) - * @irq_cfg: IRQ attributes -+ * @major_ver: Major version of Data Path Management Command Portal API -+ * @minor_ver: Minor version of Data Path Management Command Portal API - * - * Return: '0' on Success; Error code otherwise. - */ +- * +- * Return: '0' on Success; Error code otherwise. +- */ -int dpmcp_get_irq(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - int *type, - struct dpmcp_irq_cfg *irq_cfg) -+int dpmcp_get_api_version(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 *major_ver, -+ u16 *minor_ver) - { - struct mc_command cmd = { 0 }; +-{ +- struct mc_command cmd = { 0 }; - struct dpmcp_cmd_get_irq *cmd_params; - struct dpmcp_rsp_get_irq *rsp_params; - int err; - - /* prepare command */ +- int err; +- +- /* prepare command */ - cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_IRQ, - cmd_flags, token); - cmd_params = (struct dpmcp_cmd_get_irq *)cmd.params; @@ -6088,69 +13933,75 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_ATTR, - cmd_flags, token); -+ cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_API_VERSION, -+ cmd_flags, 0); - +- - /* send command to mc*/ -+ /* send command to mc */ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ - rsp_params = (struct dpmcp_rsp_get_attributes *)cmd.params; - attr->id = le32_to_cpu(rsp_params->id); - attr->version.major = le16_to_cpu(rsp_params->version_major); - attr->version.minor = le16_to_cpu(rsp_params->version_minor); -+ mc_cmd_read_api_version(&cmd, major_ver, minor_ver); - - return 0; - } +- +- return 0; +-} --- a/drivers/staging/fsl-mc/bus/dpmcp.h -+++ b/drivers/staging/fsl-mc/bus/dpmcp.h -@@ -1,4 +1,5 @@ ++++ /dev/null +@@ -1,159 +0,0 @@ -/* Copyright 2013-2015 Freescale Semiconductor Inc. -+/* -+ * Copyright 2013-2016 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: -@@ -11,7 +12,6 @@ - * names of any 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 -@@ -32,128 +32,29 @@ - #ifndef __FSL_DPMCP_H - #define __FSL_DPMCP_H - +- * +- * 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 the above-listed copyright holders nor the +- * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. +- */ +-#ifndef __FSL_DPMCP_H +-#define __FSL_DPMCP_H +- -/* Data Path Management Command Portal API -+/* -+ * Data Path Management Command Portal API - * Contains initialization APIs and runtime control APIs for DPMCP - */ - - struct fsl_mc_io; - - int dpmcp_open(struct fsl_mc_io *mc_io, +- * Contains initialization APIs and runtime control APIs for DPMCP +- */ +- +-struct fsl_mc_io; +- +-int dpmcp_open(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, -+ u32 cmd_flags, - int dpmcp_id, +- int dpmcp_id, - uint16_t *token); - -/* Get portal ID from pool */ -#define DPMCP_GET_PORTAL_ID_FROM_POOL (-1) -+ u16 *token); - - int dpmcp_close(struct fsl_mc_io *mc_io, +- +-int dpmcp_close(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token); -+ u32 cmd_flags, -+ u16 token); - +- -/** - * struct dpmcp_cfg - Structure representing DPMCP configuration - * @portal_id: Portal ID; 'DPMCP_GET_PORTAL_ID_FROM_POOL' to get the portal ID @@ -6168,12 +14019,8 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> -int dpmcp_destroy(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token); -+int dpmcp_get_api_version(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 *major_ver, -+ u16 *minor_ver); - - int dpmcp_reset(struct fsl_mc_io *mc_io, +- +-int dpmcp_reset(struct fsl_mc_io *mc_io, - uint32_t cmd_flags, - uint16_t token); - @@ -6260,62 +14107,146 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - uint32_t cmd_flags, - uint16_t token, - struct dpmcp_attr *attr); -+ u32 cmd_flags, -+ u16 token); - - #endif /* __FSL_DPMCP_H */ +- +-#endif /* __FSL_DPMCP_H */ --- a/drivers/staging/fsl-mc/bus/dpmng-cmd.h -+++ b/drivers/staging/fsl-mc/bus/dpmng-cmd.h -@@ -12,7 +12,6 @@ - * names of any 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 -@@ -41,13 +40,14 @@ - #ifndef __FSL_DPMNG_CMD_H - #define __FSL_DPMNG_CMD_H - ++++ /dev/null +@@ -1,58 +0,0 @@ +-/* +- * Copyright 2013-2016 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 the above-listed copyright holders nor the +- * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. +- */ +- +-/* +- * dpmng-cmd.h +- * +- * defines portal commands +- * +- */ +- +-#ifndef __FSL_DPMNG_CMD_H +-#define __FSL_DPMNG_CMD_H +- -/* Command IDs */ -#define DPMNG_CMDID_GET_CONT_ID 0x830 -#define DPMNG_CMDID_GET_VERSION 0x831 -+/* Command versioning */ -+#define DPMNG_CMD_BASE_VERSION 1 -+#define DPMNG_CMD_ID_OFFSET 4 - +- -struct dpmng_rsp_get_container_id { - __le32 container_id; -}; -+#define DPMNG_CMD(id) ((id << DPMNG_CMD_ID_OFFSET) | DPMNG_CMD_BASE_VERSION) -+ -+/* Command IDs */ -+#define DPMNG_CMDID_GET_VERSION DPMNG_CMD(0x831) - - struct dpmng_rsp_get_version { - __le32 revision; +- +-struct dpmng_rsp_get_version { +- __le32 revision; +- __le32 version_major; +- __le32 version_minor; +-}; +- +-#endif /* __FSL_DPMNG_CMD_H */ --- a/drivers/staging/fsl-mc/bus/dpmng.c -+++ b/drivers/staging/fsl-mc/bus/dpmng.c -@@ -1,4 +1,5 @@ ++++ /dev/null +@@ -1,107 +0,0 @@ -/* Copyright 2013-2016 Freescale Semiconductor Inc. -+/* -+ * Copyright 2013-2016 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: -@@ -11,7 +12,6 @@ - * names of any 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 -@@ -72,36 +72,3 @@ int mc_get_version(struct fsl_mc_io *mc_ - } - EXPORT_SYMBOL(mc_get_version); - +- * +- * 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 the above-listed copyright holders nor the +- * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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/mc-sys.h" +-#include "../include/mc-cmd.h" +-#include "../include/dpmng.h" +- +-#include "dpmng-cmd.h" +- +-/** +- * mc_get_version() - Retrieves the Management Complex firmware +- * version information +- * @mc_io: Pointer to opaque I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @mc_ver_info: Returned version information structure +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int mc_get_version(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- struct mc_version *mc_ver_info) +-{ +- struct mc_command cmd = { 0 }; +- struct dpmng_rsp_get_version *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPMNG_CMDID_GET_VERSION, +- cmd_flags, +- 0); +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dpmng_rsp_get_version *)cmd.params; +- mc_ver_info->revision = le32_to_cpu(rsp_params->revision); +- mc_ver_info->major = le32_to_cpu(rsp_params->version_major); +- mc_ver_info->minor = le32_to_cpu(rsp_params->version_minor); +- +- return 0; +-} +-EXPORT_SYMBOL(mc_get_version); +- -/** - * dpmng_get_container_id() - Get container ID associated with a given portal. - * @mc_io: Pointer to MC portal's I/O object @@ -6350,23 +14281,55 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> -} - --- a/drivers/staging/fsl-mc/bus/dprc-cmd.h -+++ b/drivers/staging/fsl-mc/bus/dprc-cmd.h -@@ -12,7 +12,6 @@ - * names of any 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 -@@ -42,48 +41,39 @@ - #define _FSL_DPRC_CMD_H - - /* Minimal supported DPRC Version */ ++++ /dev/null +@@ -1,465 +0,0 @@ +-/* +- * Copyright 2013-2016 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 the above-listed copyright holders nor the +- * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. +- */ +- +-/* +- * dprc-cmd.h +- * +- * defines dprc portal commands +- * +- */ +- +-#ifndef _FSL_DPRC_CMD_H +-#define _FSL_DPRC_CMD_H +- +-/* Minimal supported DPRC Version */ -#define DPRC_MIN_VER_MAJOR 5 -+#define DPRC_MIN_VER_MAJOR 6 - #define DPRC_MIN_VER_MINOR 0 - +-#define DPRC_MIN_VER_MINOR 0 +- -/* Command IDs */ -#define DPRC_CMDID_CLOSE 0x800 -#define DPRC_CMDID_OPEN 0x805 @@ -6404,220 +14367,492 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> -#define DPRC_CMDID_DISCONNECT 0x168 -#define DPRC_CMDID_GET_POOL 0x169 -#define DPRC_CMDID_GET_POOL_COUNT 0x16A -+/* Command versioning */ -+#define DPRC_CMD_BASE_VERSION 1 -+#define DPRC_CMD_ID_OFFSET 4 - +- -#define DPRC_CMDID_GET_CONNECTION 0x16C -+#define DPRC_CMD(id) ((id << DPRC_CMD_ID_OFFSET) | DPRC_CMD_BASE_VERSION) -+ -+/* Command IDs */ -+#define DPRC_CMDID_CLOSE DPRC_CMD(0x800) -+#define DPRC_CMDID_OPEN DPRC_CMD(0x805) -+#define DPRC_CMDID_GET_API_VERSION DPRC_CMD(0xa05) -+ -+#define DPRC_CMDID_GET_ATTR DPRC_CMD(0x004) -+#define DPRC_CMDID_RESET_CONT DPRC_CMD(0x005) -+ -+#define DPRC_CMDID_SET_IRQ DPRC_CMD(0x010) -+#define DPRC_CMDID_GET_IRQ DPRC_CMD(0x011) -+#define DPRC_CMDID_SET_IRQ_ENABLE DPRC_CMD(0x012) -+#define DPRC_CMDID_GET_IRQ_ENABLE DPRC_CMD(0x013) -+#define DPRC_CMDID_SET_IRQ_MASK DPRC_CMD(0x014) -+#define DPRC_CMDID_GET_IRQ_MASK DPRC_CMD(0x015) -+#define DPRC_CMDID_GET_IRQ_STATUS DPRC_CMD(0x016) -+#define DPRC_CMDID_CLEAR_IRQ_STATUS DPRC_CMD(0x017) -+ -+#define DPRC_CMDID_GET_CONT_ID DPRC_CMD(0x830) -+#define DPRC_CMDID_GET_OBJ_COUNT DPRC_CMD(0x159) -+#define DPRC_CMDID_GET_OBJ DPRC_CMD(0x15A) -+#define DPRC_CMDID_GET_RES_COUNT DPRC_CMD(0x15B) -+#define DPRC_CMDID_GET_OBJ_REG DPRC_CMD(0x15E) -+#define DPRC_CMDID_SET_OBJ_IRQ DPRC_CMD(0x15F) -+#define DPRC_CMDID_GET_OBJ_IRQ DPRC_CMD(0x160) - - struct dprc_cmd_open { - __le32 container_id; -@@ -199,9 +189,6 @@ struct dprc_rsp_get_attributes { - /* response word 1 */ - __le32 options; - __le32 portal_id; +- +-struct dprc_cmd_open { +- __le32 container_id; +-}; +- +-struct dprc_cmd_create_container { +- /* cmd word 0 */ +- __le32 options; +- __le16 icid; +- __le16 pad0; +- /* cmd word 1 */ +- __le32 pad1; +- __le32 portal_id; +- /* cmd words 2-3 */ +- u8 label[16]; +-}; +- +-struct dprc_rsp_create_container { +- /* response word 0 */ +- __le64 pad0; +- /* response word 1 */ +- __le32 child_container_id; +- __le32 pad1; +- /* response word 2 */ +- __le64 child_portal_addr; +-}; +- +-struct dprc_cmd_destroy_container { +- __le32 child_container_id; +-}; +- +-struct dprc_cmd_reset_container { +- __le32 child_container_id; +-}; +- +-struct dprc_cmd_set_irq { +- /* cmd word 0 */ +- __le32 irq_val; +- u8 irq_index; +- u8 pad[3]; +- /* cmd word 1 */ +- __le64 irq_addr; +- /* cmd word 2 */ +- __le32 irq_num; +-}; +- +-struct dprc_cmd_get_irq { +- __le32 pad; +- u8 irq_index; +-}; +- +-struct dprc_rsp_get_irq { +- /* response word 0 */ +- __le32 irq_val; +- __le32 pad; +- /* response word 1 */ +- __le64 irq_addr; +- /* response word 2 */ +- __le32 irq_num; +- __le32 type; +-}; +- +-#define DPRC_ENABLE 0x1 +- +-struct dprc_cmd_set_irq_enable { +- u8 enable; +- u8 pad[3]; +- u8 irq_index; +-}; +- +-struct dprc_cmd_get_irq_enable { +- __le32 pad; +- u8 irq_index; +-}; +- +-struct dprc_rsp_get_irq_enable { +- u8 enabled; +-}; +- +-struct dprc_cmd_set_irq_mask { +- __le32 mask; +- u8 irq_index; +-}; +- +-struct dprc_cmd_get_irq_mask { +- __le32 pad; +- u8 irq_index; +-}; +- +-struct dprc_rsp_get_irq_mask { +- __le32 mask; +-}; +- +-struct dprc_cmd_get_irq_status { +- __le32 status; +- u8 irq_index; +-}; +- +-struct dprc_rsp_get_irq_status { +- __le32 status; +-}; +- +-struct dprc_cmd_clear_irq_status { +- __le32 status; +- u8 irq_index; +-}; +- +-struct dprc_rsp_get_attributes { +- /* response word 0 */ +- __le32 container_id; +- __le16 icid; +- __le16 pad; +- /* response word 1 */ +- __le32 options; +- __le32 portal_id; - /* response word 2 */ - __le16 version_major; - __le16 version_minor; - }; - - struct dprc_cmd_set_res_quota { -@@ -367,11 +354,16 @@ struct dprc_cmd_get_obj_region { - - struct dprc_rsp_get_obj_region { - /* response word 0 */ +-}; +- +-struct dprc_cmd_set_res_quota { +- /* cmd word 0 */ +- __le32 child_container_id; +- __le16 quota; +- __le16 pad; +- /* cmd words 1-2 */ +- u8 type[16]; +-}; +- +-struct dprc_cmd_get_res_quota { +- /* cmd word 0 */ +- __le32 child_container_id; +- __le32 pad; +- /* cmd word 1-2 */ +- u8 type[16]; +-}; +- +-struct dprc_rsp_get_res_quota { +- __le32 pad; +- __le16 quota; +-}; +- +-struct dprc_cmd_assign { +- /* cmd word 0 */ +- __le32 container_id; +- __le32 options; +- /* cmd word 1 */ +- __le32 num; +- __le32 id_base_align; +- /* cmd word 2-3 */ +- u8 type[16]; +-}; +- +-struct dprc_cmd_unassign { +- /* cmd word 0 */ +- __le32 child_container_id; +- __le32 options; +- /* cmd word 1 */ +- __le32 num; +- __le32 id_base_align; +- /* cmd word 2-3 */ +- u8 type[16]; +-}; +- +-struct dprc_rsp_get_pool_count { +- __le32 pool_count; +-}; +- +-struct dprc_cmd_get_pool { +- __le32 pool_index; +-}; +- +-struct dprc_rsp_get_pool { +- /* response word 0 */ - __le64 pad; -+ __le64 pad0; - /* response word 1 */ +- /* response word 1-2 */ +- u8 type[16]; +-}; +- +-struct dprc_rsp_get_obj_count { +- __le32 pad; +- __le32 obj_count; +-}; +- +-struct dprc_cmd_get_obj { +- __le32 obj_index; +-}; +- +-struct dprc_rsp_get_obj { +- /* response word 0 */ +- __le32 pad0; +- __le32 id; +- /* response word 1 */ +- __le16 vendor; +- u8 irq_count; +- u8 region_count; +- __le32 state; +- /* response word 2 */ +- __le16 version_major; +- __le16 version_minor; +- __le16 flags; +- __le16 pad1; +- /* response word 3-4 */ +- u8 type[16]; +- /* response word 5-6 */ +- u8 label[16]; +-}; +- +-struct dprc_cmd_get_obj_desc { +- /* cmd word 0 */ +- __le32 obj_id; +- __le32 pad; +- /* cmd word 1-2 */ +- u8 type[16]; +-}; +- +-struct dprc_rsp_get_obj_desc { +- /* response word 0 */ +- __le32 pad0; +- __le32 id; +- /* response word 1 */ +- __le16 vendor; +- u8 irq_count; +- u8 region_count; +- __le32 state; +- /* response word 2 */ +- __le16 version_major; +- __le16 version_minor; +- __le16 flags; +- __le16 pad1; +- /* response word 3-4 */ +- u8 type[16]; +- /* response word 5-6 */ +- u8 label[16]; +-}; +- +-struct dprc_cmd_get_res_count { +- /* cmd word 0 */ +- __le64 pad; +- /* cmd word 1-2 */ +- u8 type[16]; +-}; +- +-struct dprc_rsp_get_res_count { +- __le32 res_count; +-}; +- +-struct dprc_cmd_get_res_ids { +- /* cmd word 0 */ +- u8 pad0[5]; +- u8 iter_status; +- __le16 pad1; +- /* cmd word 1 */ +- __le32 base_id; +- __le32 last_id; +- /* cmd word 2-3 */ +- u8 type[16]; +-}; +- +-struct dprc_rsp_get_res_ids { +- /* response word 0 */ +- u8 pad0[5]; +- u8 iter_status; +- __le16 pad1; +- /* response word 1 */ +- __le32 base_id; +- __le32 last_id; +-}; +- +-struct dprc_cmd_get_obj_region { +- /* cmd word 0 */ +- __le32 obj_id; +- __le16 pad0; +- u8 region_index; +- u8 pad1; +- /* cmd word 1-2 */ +- __le64 pad2[2]; +- /* cmd word 3-4 */ +- u8 obj_type[16]; +-}; +- +-struct dprc_rsp_get_obj_region { +- /* response word 0 */ +- __le64 pad; +- /* response word 1 */ - __le64 base_addr; -+ __le32 base_addr; -+ __le32 pad1; - /* response word 2 */ - __le32 size; -+ u8 type; -+ u8 pad2[3]; -+ /* response word 3 */ -+ __le32 flags; - }; - - struct dprc_cmd_set_obj_label { ---- a/drivers/staging/fsl-mc/bus/dprc-driver.c -+++ b/drivers/staging/fsl-mc/bus/dprc-driver.c -@@ -1,7 +1,7 @@ - /* - * Freescale data path resource container (DPRC) driver - * -- * Copyright (C) 2014 Freescale Semiconductor, Inc. -+ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. - * Author: German Rivera <German.Rivera@freescale.com> - * - * This file is licensed under the terms of the GNU General Public -@@ -160,6 +160,8 @@ static void check_plugged_state_change(s - * dprc_add_new_devices - Adds devices to the logical bus for a DPRC - * - * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object -+ * @driver_override: driver override to apply to new objects found in the -+ * DPRC, or NULL, if none. - * @obj_desc_array: array of device descriptors for child devices currently - * present in the physical DPRC. - * @num_child_objects_in_mc: number of entries in obj_desc_array -@@ -169,6 +171,7 @@ static void check_plugged_state_change(s - * in the physical DPRC. - */ - static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev, -+ const char *driver_override, - struct dprc_obj_desc *obj_desc_array, - int num_child_objects_in_mc) - { -@@ -188,11 +191,12 @@ static void dprc_add_new_devices(struct - child_dev = fsl_mc_device_lookup(obj_desc, mc_bus_dev); - if (child_dev) { - check_plugged_state_change(child_dev, obj_desc); -+ put_device(&child_dev->dev); - continue; - } - - error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev, -- &child_dev); -+ driver_override, &child_dev); - if (error < 0) - continue; - } -@@ -202,6 +206,8 @@ static void dprc_add_new_devices(struct - * dprc_scan_objects - Discover objects in a DPRC - * - * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object -+ * @driver_override: driver override to apply to new objects found in the -+ * DPRC, or NULL, if none. - * @total_irq_count: total number of IRQs needed by objects in the DPRC. - * - * Detects objects added and removed from a DPRC and synchronizes the -@@ -217,6 +223,7 @@ static void dprc_add_new_devices(struct - * of the device drivers for the non-allocatable devices. - */ - int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev, -+ const char *driver_override, - unsigned int *total_irq_count) - { - int num_child_objects; -@@ -297,7 +304,7 @@ int dprc_scan_objects(struct fsl_mc_devi - dprc_remove_devices(mc_bus_dev, child_obj_desc_array, - num_child_objects); - -- dprc_add_new_devices(mc_bus_dev, child_obj_desc_array, -+ dprc_add_new_devices(mc_bus_dev, driver_override, child_obj_desc_array, - num_child_objects); - - if (child_obj_desc_array) -@@ -328,7 +335,7 @@ int dprc_scan_container(struct fsl_mc_de - * Discover objects in the DPRC: - */ - mutex_lock(&mc_bus->scan_mutex); -- error = dprc_scan_objects(mc_bus_dev, &irq_count); -+ error = dprc_scan_objects(mc_bus_dev, NULL, &irq_count); - mutex_unlock(&mc_bus->scan_mutex); - if (error < 0) - goto error; -@@ -415,7 +422,7 @@ static irqreturn_t dprc_irq0_handler_thr - DPRC_IRQ_EVENT_OBJ_CREATED)) { - unsigned int irq_count; - -- error = dprc_scan_objects(mc_dev, &irq_count); -+ error = dprc_scan_objects(mc_dev, NULL, &irq_count); - if (error < 0) { - /* - * If the error is -ENXIO, we ignore it, as it indicates -@@ -505,7 +512,7 @@ static int register_dprc_irq_handler(str - dprc_irq0_handler, - dprc_irq0_handler_thread, - IRQF_NO_SUSPEND | IRQF_ONESHOT, -- "FSL MC DPRC irq0", -+ dev_name(&mc_dev->dev), - &mc_dev->dev); - if (error < 0) { - dev_err(&mc_dev->dev, -@@ -597,6 +604,7 @@ static int dprc_probe(struct fsl_mc_devi - struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); - bool mc_io_created = false; - bool msi_domain_set = false; -+ u16 major_ver, minor_ver; - - if (WARN_ON(strcmp(mc_dev->obj_desc.type, "dprc") != 0)) - return -EINVAL; -@@ -669,13 +677,21 @@ static int dprc_probe(struct fsl_mc_devi - goto error_cleanup_open; - } - -- if (mc_bus->dprc_attr.version.major < DPRC_MIN_VER_MAJOR || -- (mc_bus->dprc_attr.version.major == DPRC_MIN_VER_MAJOR && -- mc_bus->dprc_attr.version.minor < DPRC_MIN_VER_MINOR)) { -+ error = dprc_get_api_version(mc_dev->mc_io, 0, -+ &major_ver, -+ &minor_ver); -+ if (error < 0) { -+ dev_err(&mc_dev->dev, "dprc_get_api_version() failed: %d\n", -+ error); -+ goto error_cleanup_open; -+ } -+ -+ if (major_ver < DPRC_MIN_VER_MAJOR || -+ (major_ver == DPRC_MIN_VER_MAJOR && -+ minor_ver < DPRC_MIN_VER_MINOR)) { - dev_err(&mc_dev->dev, - "ERROR: DPRC version %d.%d not supported\n", -- mc_bus->dprc_attr.version.major, -- mc_bus->dprc_attr.version.minor); -+ major_ver, minor_ver); - error = -ENOTSUPP; - goto error_cleanup_open; - } +- /* response word 2 */ +- __le32 size; +-}; +- +-struct dprc_cmd_set_obj_label { +- /* cmd word 0 */ +- __le32 obj_id; +- __le32 pad; +- /* cmd word 1-2 */ +- u8 label[16]; +- /* cmd word 3-4 */ +- u8 obj_type[16]; +-}; +- +-struct dprc_cmd_set_obj_irq { +- /* cmd word 0 */ +- __le32 irq_val; +- u8 irq_index; +- u8 pad[3]; +- /* cmd word 1 */ +- __le64 irq_addr; +- /* cmd word 2 */ +- __le32 irq_num; +- __le32 obj_id; +- /* cmd word 3-4 */ +- u8 obj_type[16]; +-}; +- +-struct dprc_cmd_get_obj_irq { +- /* cmd word 0 */ +- __le32 obj_id; +- u8 irq_index; +- u8 pad[3]; +- /* cmd word 1-2 */ +- u8 obj_type[16]; +-}; +- +-struct dprc_rsp_get_obj_irq { +- /* response word 0 */ +- __le32 irq_val; +- __le32 pad; +- /* response word 1 */ +- __le64 irq_addr; +- /* response word 2 */ +- __le32 irq_num; +- __le32 type; +-}; +- +-struct dprc_cmd_connect { +- /* cmd word 0 */ +- __le32 ep1_id; +- __le32 ep1_interface_id; +- /* cmd word 1 */ +- __le32 ep2_id; +- __le32 ep2_interface_id; +- /* cmd word 2-3 */ +- u8 ep1_type[16]; +- /* cmd word 4 */ +- __le32 max_rate; +- __le32 committed_rate; +- /* cmd word 5-6 */ +- u8 ep2_type[16]; +-}; +- +-struct dprc_cmd_disconnect { +- /* cmd word 0 */ +- __le32 id; +- __le32 interface_id; +- /* cmd word 1-2 */ +- u8 type[16]; +-}; +- +-struct dprc_cmd_get_connection { +- /* cmd word 0 */ +- __le32 ep1_id; +- __le32 ep1_interface_id; +- /* cmd word 1-2 */ +- u8 ep1_type[16]; +-}; +- +-struct dprc_rsp_get_connection { +- /* response word 0-2 */ +- __le64 pad[3]; +- /* response word 3 */ +- __le32 ep2_id; +- __le32 ep2_interface_id; +- /* response word 4-5 */ +- u8 ep2_type[16]; +- /* response word 6 */ +- __le32 state; +-}; +- +-#endif /* _FSL_DPRC_CMD_H */ --- a/drivers/staging/fsl-mc/bus/dprc.c -+++ b/drivers/staging/fsl-mc/bus/dprc.c -@@ -1,4 +1,5 @@ ++++ /dev/null +@@ -1,1388 +0,0 @@ -/* Copyright 2013-2016 Freescale Semiconductor Inc. -+/* -+ * Copyright 2013-2016 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: -@@ -11,7 +12,6 @@ - * names of any 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 -@@ -100,93 +100,6 @@ int dprc_close(struct fsl_mc_io *mc_io, - EXPORT_SYMBOL(dprc_close); - - /** +- * +- * 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 the above-listed copyright holders nor the +- * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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/mc-sys.h" +-#include "../include/mc-cmd.h" +-#include "../include/dprc.h" +- +-#include "dprc-cmd.h" +- +-/** +- * dprc_open() - Open DPRC object for use +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @container_id: Container ID to open +- * @token: Returned token of DPRC object +- * +- * Return: '0' on Success; Error code otherwise. +- * +- * @warning Required before any operation on the object. +- */ +-int dprc_open(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- int container_id, +- u16 *token) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_open *cmd_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_OPEN, cmd_flags, +- 0); +- cmd_params = (struct dprc_cmd_open *)cmd.params; +- cmd_params->container_id = cpu_to_le32(container_id); +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- *token = mc_cmd_hdr_read_token(&cmd); +- +- return 0; +-} +-EXPORT_SYMBOL(dprc_open); +- +-/** +- * dprc_close() - Close the control session of the object +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * +- * After this function is called, no further operations are +- * allowed on the object without opening a new control session. +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_close(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token) +-{ +- struct mc_command cmd = { 0 }; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_CLOSE, cmd_flags, +- token); +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +-EXPORT_SYMBOL(dprc_close); +- +-/** - * dprc_create_container() - Create child container - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' @@ -6705,13 +14940,384 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> -} - -/** - * dprc_reset_container - Reset child container. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' -@@ -565,279 +478,6 @@ int dprc_get_attributes(struct fsl_mc_io - attr->icid = le16_to_cpu(rsp_params->icid); - attr->options = le32_to_cpu(rsp_params->options); - attr->portal_id = le32_to_cpu(rsp_params->portal_id); +- * dprc_reset_container - Reset child container. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @child_container_id: ID of the container to reset +- * +- * In case a software context crashes or becomes non-responsive, the parent +- * may wish to reset its resources container before the software context is +- * restarted. +- * +- * This routine informs all objects assigned to the child container that the +- * container is being reset, so they may perform any cleanup operations that are +- * needed. All objects handles that were owned by the child container shall be +- * closed. +- * +- * Note that such request may be submitted even if the child software context +- * has not crashed, but the resulting object cleanup operations will not be +- * aware of that. +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_reset_container(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int child_container_id) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_reset_container *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_RESET_CONT, +- cmd_flags, token); +- cmd_params = (struct dprc_cmd_reset_container *)cmd.params; +- cmd_params->child_container_id = cpu_to_le32(child_container_id); +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** +- * dprc_get_irq() - Get IRQ information from the DPRC. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @irq_index: The interrupt index to configure +- * @type: Interrupt type: 0 represents message interrupt +- * type (both irq_addr and irq_val are valid) +- * @irq_cfg: IRQ attributes +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_get_irq(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- int *type, +- struct dprc_irq_cfg *irq_cfg) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_get_irq *cmd_params; +- struct dprc_rsp_get_irq *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_IRQ, +- cmd_flags, +- token); +- cmd_params = (struct dprc_cmd_get_irq *)cmd.params; +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dprc_rsp_get_irq *)cmd.params; +- irq_cfg->val = le32_to_cpu(rsp_params->irq_val); +- irq_cfg->paddr = le64_to_cpu(rsp_params->irq_addr); +- irq_cfg->irq_num = le32_to_cpu(rsp_params->irq_num); +- *type = le32_to_cpu(rsp_params->type); +- +- return 0; +-} +- +-/** +- * dprc_set_irq() - Set IRQ information for the DPRC to trigger an interrupt. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @irq_index: Identifies the interrupt index to configure +- * @irq_cfg: IRQ configuration +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_set_irq(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- struct dprc_irq_cfg *irq_cfg) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_set_irq *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_IRQ, +- cmd_flags, +- token); +- cmd_params = (struct dprc_cmd_set_irq *)cmd.params; +- cmd_params->irq_val = cpu_to_le32(irq_cfg->val); +- cmd_params->irq_index = irq_index; +- cmd_params->irq_addr = cpu_to_le64(irq_cfg->paddr); +- cmd_params->irq_num = cpu_to_le32(irq_cfg->irq_num); +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** +- * dprc_get_irq_enable() - Get overall interrupt state. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @irq_index: The interrupt index to configure +- * @en: Returned interrupt state - enable = 1, disable = 0 +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_get_irq_enable(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u8 *en) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_get_irq_enable *cmd_params; +- struct dprc_rsp_get_irq_enable *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_IRQ_ENABLE, +- cmd_flags, token); +- cmd_params = (struct dprc_cmd_get_irq_enable *)cmd.params; +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dprc_rsp_get_irq_enable *)cmd.params; +- *en = rsp_params->enabled & DPRC_ENABLE; +- +- return 0; +-} +- +-/** +- * dprc_set_irq_enable() - Set overall interrupt state. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @irq_index: The interrupt index to configure +- * @en: Interrupt state - enable = 1, disable = 0 +- * +- * Allows GPP software to control when interrupts are generated. +- * Each interrupt can have up to 32 causes. The enable/disable control's the +- * overall interrupt state. if the interrupt is disabled no causes will cause +- * an interrupt. +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_set_irq_enable(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u8 en) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_set_irq_enable *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_IRQ_ENABLE, +- cmd_flags, token); +- cmd_params = (struct dprc_cmd_set_irq_enable *)cmd.params; +- cmd_params->enable = en & DPRC_ENABLE; +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** +- * dprc_get_irq_mask() - Get interrupt mask. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @irq_index: The interrupt index to configure +- * @mask: Returned event mask to trigger interrupt +- * +- * Every interrupt can have up to 32 causes and the interrupt model supports +- * masking/unmasking each cause independently +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_get_irq_mask(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 *mask) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_get_irq_mask *cmd_params; +- struct dprc_rsp_get_irq_mask *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_IRQ_MASK, +- cmd_flags, token); +- cmd_params = (struct dprc_cmd_get_irq_mask *)cmd.params; +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dprc_rsp_get_irq_mask *)cmd.params; +- *mask = le32_to_cpu(rsp_params->mask); +- +- return 0; +-} +- +-/** +- * dprc_set_irq_mask() - Set interrupt mask. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @irq_index: The interrupt index to configure +- * @mask: event mask to trigger interrupt; +- * each bit: +- * 0 = ignore event +- * 1 = consider event for asserting irq +- * +- * Every interrupt can have up to 32 causes and the interrupt model supports +- * masking/unmasking each cause independently +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_set_irq_mask(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 mask) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_set_irq_mask *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_IRQ_MASK, +- cmd_flags, token); +- cmd_params = (struct dprc_cmd_set_irq_mask *)cmd.params; +- cmd_params->mask = cpu_to_le32(mask); +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** +- * dprc_get_irq_status() - Get the current status of any pending interrupts. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @irq_index: The interrupt index to configure +- * @status: Returned interrupts status - one bit per cause: +- * 0 = no interrupt pending +- * 1 = interrupt pending +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_get_irq_status(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 *status) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_get_irq_status *cmd_params; +- struct dprc_rsp_get_irq_status *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_IRQ_STATUS, +- cmd_flags, token); +- cmd_params = (struct dprc_cmd_get_irq_status *)cmd.params; +- cmd_params->status = cpu_to_le32(*status); +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dprc_rsp_get_irq_status *)cmd.params; +- *status = le32_to_cpu(rsp_params->status); +- +- return 0; +-} +- +-/** +- * dprc_clear_irq_status() - Clear a pending interrupt's status +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @irq_index: The interrupt index to configure +- * @status: bits to clear (W1C) - one bit per cause: +- * 0 = don't change +- * 1 = clear status bit +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_clear_irq_status(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 status) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_clear_irq_status *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_CLEAR_IRQ_STATUS, +- cmd_flags, token); +- cmd_params = (struct dprc_cmd_clear_irq_status *)cmd.params; +- cmd_params->status = cpu_to_le32(status); +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** +- * dprc_get_attributes() - Obtains container attributes +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @attributes Returned container attributes +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_get_attributes(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- struct dprc_attributes *attr) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_rsp_get_attributes *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_ATTR, +- cmd_flags, +- token); +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dprc_rsp_get_attributes *)cmd.params; +- attr->container_id = le32_to_cpu(rsp_params->container_id); +- attr->icid = le16_to_cpu(rsp_params->icid); +- attr->options = le32_to_cpu(rsp_params->options); +- attr->portal_id = le32_to_cpu(rsp_params->portal_id); - attr->version.major = le16_to_cpu(rsp_params->version_major); - attr->version.minor = le16_to_cpu(rsp_params->version_minor); - @@ -6985,13 +15591,102 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - rsp_params = (struct dprc_rsp_get_pool *)cmd.params; - strncpy(type, rsp_params->type, 16); - type[15] = '\0'; - - return 0; - } -@@ -934,64 +574,6 @@ int dprc_get_obj(struct fsl_mc_io *mc_io - EXPORT_SYMBOL(dprc_get_obj); - - /** +- +- return 0; +-} +- +-/** +- * dprc_get_obj_count() - Obtains the number of objects in the DPRC +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @obj_count: Number of objects assigned to the DPRC +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_get_obj_count(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int *obj_count) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_rsp_get_obj_count *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_COUNT, +- cmd_flags, token); +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dprc_rsp_get_obj_count *)cmd.params; +- *obj_count = le32_to_cpu(rsp_params->obj_count); +- +- return 0; +-} +-EXPORT_SYMBOL(dprc_get_obj_count); +- +-/** +- * dprc_get_obj() - Get general information on an object +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @obj_index: Index of the object to be queried (< obj_count) +- * @obj_desc: Returns the requested object descriptor +- * +- * The object descriptors are retrieved one by one by incrementing +- * obj_index up to (not including) the value of obj_count returned +- * from dprc_get_obj_count(). dprc_get_obj_count() must +- * be called prior to dprc_get_obj(). +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_get_obj(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int obj_index, +- struct dprc_obj_desc *obj_desc) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_get_obj *cmd_params; +- struct dprc_rsp_get_obj *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ, +- cmd_flags, +- token); +- cmd_params = (struct dprc_cmd_get_obj *)cmd.params; +- cmd_params->obj_index = cpu_to_le32(obj_index); +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dprc_rsp_get_obj *)cmd.params; +- obj_desc->id = le32_to_cpu(rsp_params->id); +- obj_desc->vendor = le16_to_cpu(rsp_params->vendor); +- obj_desc->irq_count = rsp_params->irq_count; +- obj_desc->region_count = rsp_params->region_count; +- obj_desc->state = le32_to_cpu(rsp_params->state); +- obj_desc->ver_major = le16_to_cpu(rsp_params->version_major); +- obj_desc->ver_minor = le16_to_cpu(rsp_params->version_minor); +- obj_desc->flags = le16_to_cpu(rsp_params->flags); +- strncpy(obj_desc->type, rsp_params->type, 16); +- obj_desc->type[15] = '\0'; +- strncpy(obj_desc->label, rsp_params->label, 16); +- obj_desc->label[15] = '\0'; +- return 0; +-} +-EXPORT_SYMBOL(dprc_get_obj); +- +-/** - * dprc_get_obj_desc() - Get object descriptor. - * - * @mc_io: Pointer to MC portal's I/O object @@ -7050,13 +15745,144 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> -EXPORT_SYMBOL(dprc_get_obj_desc); - -/** - * dprc_set_obj_irq() - Set IRQ information for object to trigger an interrupt. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' -@@ -1130,52 +712,6 @@ int dprc_get_res_count(struct fsl_mc_io - EXPORT_SYMBOL(dprc_get_res_count); - - /** +- * dprc_set_obj_irq() - Set IRQ information for object to trigger an interrupt. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @obj_type: Type of the object to set its IRQ +- * @obj_id: ID of the object to set its IRQ +- * @irq_index: The interrupt index to configure +- * @irq_cfg: IRQ configuration +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_set_obj_irq(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- char *obj_type, +- int obj_id, +- u8 irq_index, +- struct dprc_irq_cfg *irq_cfg) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_set_obj_irq *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_OBJ_IRQ, +- cmd_flags, +- token); +- cmd_params = (struct dprc_cmd_set_obj_irq *)cmd.params; +- cmd_params->irq_val = cpu_to_le32(irq_cfg->val); +- cmd_params->irq_index = irq_index; +- cmd_params->irq_addr = cpu_to_le64(irq_cfg->paddr); +- cmd_params->irq_num = cpu_to_le32(irq_cfg->irq_num); +- cmd_params->obj_id = cpu_to_le32(obj_id); +- strncpy(cmd_params->obj_type, obj_type, 16); +- cmd_params->obj_type[15] = '\0'; +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +-EXPORT_SYMBOL(dprc_set_obj_irq); +- +-/** +- * dprc_get_obj_irq() - Get IRQ information from object. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @obj_type: Type od the object to get its IRQ +- * @obj_id: ID of the object to get its IRQ +- * @irq_index: The interrupt index to configure +- * @type: Interrupt type: 0 represents message interrupt +- * type (both irq_addr and irq_val are valid) +- * @irq_cfg: The returned IRQ attributes +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_get_obj_irq(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- char *obj_type, +- int obj_id, +- u8 irq_index, +- int *type, +- struct dprc_irq_cfg *irq_cfg) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_get_obj_irq *cmd_params; +- struct dprc_rsp_get_obj_irq *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_IRQ, +- cmd_flags, +- token); +- cmd_params = (struct dprc_cmd_get_obj_irq *)cmd.params; +- cmd_params->obj_id = cpu_to_le32(obj_id); +- cmd_params->irq_index = irq_index; +- strncpy(cmd_params->obj_type, obj_type, 16); +- cmd_params->obj_type[15] = '\0'; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dprc_rsp_get_obj_irq *)cmd.params; +- irq_cfg->val = le32_to_cpu(rsp_params->irq_val); +- irq_cfg->paddr = le64_to_cpu(rsp_params->irq_addr); +- irq_cfg->irq_num = le32_to_cpu(rsp_params->irq_num); +- *type = le32_to_cpu(rsp_params->type); +- +- return 0; +-} +-EXPORT_SYMBOL(dprc_get_obj_irq); +- +-/** +- * dprc_get_res_count() - Obtains the number of free resources that are assigned +- * to this container, by pool type +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @type: pool type +- * @res_count: Returned number of free resources of the given +- * resource type that are assigned to this DPRC +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_get_res_count(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- char *type, +- int *res_count) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_get_res_count *cmd_params; +- struct dprc_rsp_get_res_count *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_RES_COUNT, +- cmd_flags, token); +- cmd_params = (struct dprc_cmd_get_res_count *)cmd.params; +- strncpy(cmd_params->type, type, 16); +- cmd_params->type[15] = '\0'; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dprc_rsp_get_res_count *)cmd.params; +- *res_count = le32_to_cpu(rsp_params->res_count); +- +- return 0; +-} +-EXPORT_SYMBOL(dprc_get_res_count); +- +-/** - * dprc_get_res_ids() - Obtains IDs of free resources in the container - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' @@ -7103,54 +15929,75 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> -EXPORT_SYMBOL(dprc_get_res_ids); - -/** - * dprc_get_obj_region() - Get region information for a specified object. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' -@@ -1216,160 +752,66 @@ int dprc_get_obj_region(struct fsl_mc_io - - /* retrieve response parameters */ - rsp_params = (struct dprc_rsp_get_obj_region *)cmd.params; +- * dprc_get_obj_region() - Get region information for a specified object. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @obj_type; Object type as returned in dprc_get_obj() +- * @obj_id: Unique object instance as returned in dprc_get_obj() +- * @region_index: The specific region to query +- * @region_desc: Returns the requested region descriptor +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_get_obj_region(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- char *obj_type, +- int obj_id, +- u8 region_index, +- struct dprc_region_desc *region_desc) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_get_obj_region *cmd_params; +- struct dprc_rsp_get_obj_region *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG, +- cmd_flags, token); +- cmd_params = (struct dprc_cmd_get_obj_region *)cmd.params; +- cmd_params->obj_id = cpu_to_le32(obj_id); +- cmd_params->region_index = region_index; +- strncpy(cmd_params->obj_type, obj_type, 16); +- cmd_params->obj_type[15] = '\0'; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dprc_rsp_get_obj_region *)cmd.params; - region_desc->base_offset = le64_to_cpu(rsp_params->base_addr); -+ region_desc->base_offset = le32_to_cpu(rsp_params->base_addr); - region_desc->size = le32_to_cpu(rsp_params->size); -+ region_desc->type = rsp_params->type; -+ region_desc->flags = le32_to_cpu(rsp_params->flags); - - return 0; - } - EXPORT_SYMBOL(dprc_get_obj_region); - - /** +- region_desc->size = le32_to_cpu(rsp_params->size); +- +- return 0; +-} +-EXPORT_SYMBOL(dprc_get_obj_region); +- +-/** - * dprc_set_obj_label() - Set object label. - * @mc_io: Pointer to MC portal's I/O object -+ * dprc_get_api_version - Get Data Path Resource Container API version -+ * @mc_io: Pointer to Mc portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPRC object - * @obj_type: Object's type - * @obj_id: Object's ID - * @label: The required label. The maximum length is 16 chars. -+ * @major_ver: Major version of Data Path Resource Container API -+ * @minor_ver: Minor version of Data Path Resource Container API - * - * Return: '0' on Success; Error code otherwise. - */ +- * +- * Return: '0' on Success; Error code otherwise. +- */ -int dprc_set_obj_label(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - char *obj_type, - int obj_id, - char *label) -+int dprc_get_api_version(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 *major_ver, -+ u16 *minor_ver) - { - struct mc_command cmd = { 0 }; +-{ +- struct mc_command cmd = { 0 }; - struct dprc_cmd_set_obj_label *cmd_params; -+ int err; - - /* prepare command */ +- +- /* prepare command */ - cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_OBJ_LABEL, - cmd_flags, - token); @@ -7160,9 +16007,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - cmd_params->label[15] = '\0'; - strncpy(cmd_params->obj_type, obj_type, 16); - cmd_params->obj_type[15] = '\0'; -+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_API_VERSION, -+ cmd_flags, 0); - +- - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} @@ -7190,11 +16035,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> -{ - struct mc_command cmd = { 0 }; - struct dprc_cmd_connect *cmd_params; -+ /* send command to mc */ -+ err = mc_send_command(mc_io, &cmd); -+ if (err) -+ return err; - +- - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPRC_CMDID_CONNECT, - cmd_flags, @@ -7210,27 +16051,20 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - cmd_params->committed_rate = cpu_to_le32(cfg->committed_rate); - strncpy(cmd_params->ep2_type, endpoint2->type, 16); - cmd_params->ep2_type[15] = '\0'; -+ /* retrieve response parameters */ -+ mc_cmd_read_api_version(&cmd, major_ver, minor_ver); - +- - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -+ return 0; - } - - /** +-} +- +-/** - * dprc_disconnect() - Disconnect one endpoint to remove its network connection - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPRC object - * @endpoint: Endpoint configuration parameters -+ * dprc_get_container_id - Get container ID associated with a given portal. -+ * @mc_io: Pointer to Mc portal's I/O object -+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' -+ * @container_id: Requested container id - * - * Return: '0' on Success; Error code otherwise. - */ +- * +- * Return: '0' on Success; Error code otherwise. +- */ -int dprc_disconnect(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, @@ -7274,1555 +16108,100 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - const struct dprc_endpoint *endpoint1, - struct dprc_endpoint *endpoint2, - int *state) -+int dprc_get_container_id(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ int *container_id) - { - struct mc_command cmd = { 0 }; +-{ +- struct mc_command cmd = { 0 }; - struct dprc_cmd_get_connection *cmd_params; - struct dprc_rsp_get_connection *rsp_params; - int err; - - /* prepare command */ +- int err; +- +- /* prepare command */ - cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_CONNECTION, -+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_CONT_ID, - cmd_flags, +- cmd_flags, - token); - cmd_params = (struct dprc_cmd_get_connection *)cmd.params; - cmd_params->ep1_id = cpu_to_le32(endpoint1->id); - cmd_params->ep1_interface_id = cpu_to_le32(endpoint1->if_id); - strncpy(cmd_params->ep1_type, endpoint1->type, 16); - cmd_params->ep1_type[15] = '\0'; -+ 0); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); -@@ -1377,12 +819,7 @@ int dprc_get_connection(struct fsl_mc_io - return err; - - /* retrieve response parameters */ +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ - rsp_params = (struct dprc_rsp_get_connection *)cmd.params; - endpoint2->id = le32_to_cpu(rsp_params->ep2_id); - endpoint2->if_id = le32_to_cpu(rsp_params->ep2_interface_id); - strncpy(endpoint2->type, rsp_params->ep2_type, 16); - endpoint2->type[15] = '\0'; - *state = le32_to_cpu(rsp_params->state); -+ *container_id = (int)mc_cmd_read_object_id(&cmd); - - return 0; - } ---- a/drivers/staging/fsl-mc/bus/fsl-mc-allocator.c -+++ b/drivers/staging/fsl-mc/bus/fsl-mc-allocator.c -@@ -1,7 +1,7 @@ - /* -- * Freescale MC object device allocator driver -+ * fsl-mc object allocator driver - * -- * Copyright (C) 2013 Freescale Semiconductor, Inc. -+ * Copyright (C) 2013-2016 Freescale Semiconductor, Inc. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any -@@ -12,9 +12,9 @@ - #include <linux/msi.h> - #include "../include/mc-bus.h" - #include "../include/mc-sys.h" --#include "../include/dpbp-cmd.h" --#include "../include/dpcon-cmd.h" - -+#include "dpbp-cmd.h" -+#include "dpcon-cmd.h" - #include "fsl-mc-private.h" - - #define FSL_MC_IS_ALLOCATABLE(_obj_type) \ -@@ -23,15 +23,12 @@ - strcmp(_obj_type, "dpcon") == 0) - - /** -- * fsl_mc_resource_pool_add_device - add allocatable device to a resource -- * pool of a given MC bus -+ * fsl_mc_resource_pool_add_device - add allocatable object to a resource -+ * pool of a given fsl-mc bus - * -- * @mc_bus: pointer to the MC bus -- * @pool_type: MC bus pool type -- * @mc_dev: Pointer to allocatable MC object device +- +- return 0; +-} +--- a/drivers/staging/fsl-mc/bus/fsl-mc-private.h ++++ /dev/null +@@ -1,52 +0,0 @@ +-/* +- * Freescale Management Complex (MC) bus private declarations - * -- * It adds an allocatable MC object device to a container's resource pool of -- * the given resource type -+ * @mc_bus: pointer to the fsl-mc bus -+ * @pool_type: pool type -+ * @mc_dev: pointer to allocatable fsl-mc device - */ - static int __must_check fsl_mc_resource_pool_add_device(struct fsl_mc_bus - *mc_bus, -@@ -95,10 +92,10 @@ out: - * fsl_mc_resource_pool_remove_device - remove an allocatable device from a - * resource pool - * -- * @mc_dev: Pointer to allocatable MC object device -+ * @mc_dev: pointer to allocatable fsl-mc device - * -- * It permanently removes an allocatable MC object device from the resource -- * pool, the device is currently in, as long as it is in the pool's free list. -+ * It permanently removes an allocatable fsl-mc device from the resource -+ * pool. It's an error if the device is in use. - */ - static int __must_check fsl_mc_resource_pool_remove_device(struct fsl_mc_device - *mc_dev) -@@ -255,17 +252,18 @@ out_unlock: - EXPORT_SYMBOL_GPL(fsl_mc_resource_free); - - /** -- * fsl_mc_object_allocate - Allocates a MC object device of the given -- * pool type from a given MC bus -+ * fsl_mc_object_allocate - Allocates an fsl-mc object of the given -+ * pool type from a given fsl-mc bus instance - * -- * @mc_dev: MC device for which the MC object device is to be allocated -- * @pool_type: MC bus resource pool type -- * @new_mc_dev: Pointer to area where the pointer to the allocated -- * MC object device is to be returned -+ * @mc_dev: fsl-mc device which is used in conjunction with the -+ * allocated object -+ * @pool_type: pool type -+ * @new_mc_dev: pointer to area where the pointer to the allocated device -+ * is to be returned - * -- * This function allocates a MC object device from the device's parent DPRC, -- * from the corresponding MC bus' pool of allocatable MC object devices of -- * the given resource type. mc_dev cannot be a DPRC itself. -+ * Allocatable objects are always used in conjunction with some functional -+ * device. This function allocates an object of the specified type from -+ * the DPRC containing the functional device. - * - * NOTE: pool_type must be different from FSL_MC_POOL_MCP, since MC - * portals are allocated using fsl_mc_portal_allocate(), instead of -@@ -312,10 +310,9 @@ error: - EXPORT_SYMBOL_GPL(fsl_mc_object_allocate); - - /** -- * fsl_mc_object_free - Returns an allocatable MC object device to the -- * corresponding resource pool of a given MC bus. +- * Copyright (C) 2016 Freescale Semiconductor, Inc. - * -- * @mc_adev: Pointer to the MC object device -+ * fsl_mc_object_free - Returns an fsl-mc object to the resource -+ * pool where it came from. -+ * @mc_adev: Pointer to the fsl-mc device - */ - void fsl_mc_object_free(struct fsl_mc_device *mc_adev) - { -@@ -332,8 +329,14 @@ void fsl_mc_object_free(struct fsl_mc_de - EXPORT_SYMBOL_GPL(fsl_mc_object_free); - - /* -- * Initialize the interrupt pool associated with a MC bus. -- * It allocates a block of IRQs from the GIC-ITS -+ * A DPRC and the devices in the DPRC all share the same GIC-ITS device -+ * ID. A block of IRQs is pre-allocated and maintained in a pool -+ * from which devices can allocate them when needed. -+ */ -+ -+/* -+ * Initialize the interrupt pool associated with an fsl-mc bus. -+ * It allocates a block of IRQs from the GIC-ITS. - */ - int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus, - unsigned int irq_count) -@@ -395,7 +398,7 @@ cleanup_msi_irqs: - EXPORT_SYMBOL_GPL(fsl_mc_populate_irq_pool); - - /** -- * Teardown the interrupt pool associated with an MC bus. -+ * Teardown the interrupt pool associated with an fsl-mc bus. - * It frees the IRQs that were allocated to the pool, back to the GIC-ITS. - */ - void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus) -@@ -422,11 +425,7 @@ void fsl_mc_cleanup_irq_pool(struct fsl_ - EXPORT_SYMBOL_GPL(fsl_mc_cleanup_irq_pool); - - /** -- * It allocates the IRQs required by a given MC object device. The -- * IRQs are allocated from the interrupt pool associated with the -- * MC bus that contains the device, if the device is not a DPRC device. -- * Otherwise, the IRQs are allocated from the interrupt pool associated -- * with the MC bus that represents the DPRC device itself. -+ * Allocate the IRQs required by a given fsl-mc device. - */ - int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev) - { -@@ -495,8 +494,7 @@ error_resource_alloc: - EXPORT_SYMBOL_GPL(fsl_mc_allocate_irqs); - - /* -- * It frees the IRQs that were allocated for a MC object device, by -- * returning them to the corresponding interrupt pool. -+ * Frees the IRQs that were allocated for an fsl-mc device. - */ - void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev) - { -@@ -605,7 +603,7 @@ static int fsl_mc_allocator_probe(struct - return error; - - dev_dbg(&mc_dev->dev, -- "Allocatable MC object device bound to fsl_mc_allocator driver"); -+ "Allocatable fsl-mc device bound to fsl_mc_allocator driver"); - return 0; - } - -@@ -627,7 +625,7 @@ static int fsl_mc_allocator_remove(struc - } - - dev_dbg(&mc_dev->dev, -- "Allocatable MC object device unbound from fsl_mc_allocator driver"); -+ "Allocatable fsl-mc device unbound from fsl_mc_allocator driver"); - return 0; - } - ---- a/drivers/staging/fsl-mc/bus/fsl-mc-bus.c -+++ b/drivers/staging/fsl-mc/bus/fsl-mc-bus.c -@@ -1,7 +1,7 @@ - /* - * Freescale Management Complex (MC) bus driver - * -- * Copyright (C) 2014 Freescale Semiconductor, Inc. -+ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. - * Author: German Rivera <German.Rivera@freescale.com> - * - * This file is licensed under the terms of the GNU General Public -@@ -9,6 +9,8 @@ - * warranty of any kind, whether express or implied. - */ - -+#define pr_fmt(fmt) "fsl-mc: " fmt -+ - #include <linux/module.h> - #include <linux/of_device.h> - #include <linux/of_address.h> -@@ -25,8 +27,6 @@ - #include "fsl-mc-private.h" - #include "dprc-cmd.h" - --static struct kmem_cache *mc_dev_cache; +- * 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. +- */ +-#ifndef _FSL_MC_PRIVATE_H_ +-#define _FSL_MC_PRIVATE_H_ - - /** - * Default DMA mask for devices on a fsl-mc bus - */ -@@ -34,7 +34,7 @@ static struct kmem_cache *mc_dev_cache; - - /** - * struct fsl_mc - Private data of a "fsl,qoriq-mc" platform device -- * @root_mc_bus_dev: MC object device representing the root DPRC -+ * @root_mc_bus_dev: fsl-mc device representing the root DPRC - * @num_translation_ranges: number of entries in addr_translation_ranges - * @translation_ranges: array of bus to system address translation ranges - */ -@@ -62,8 +62,8 @@ struct fsl_mc_addr_translation_range { - - /** - * fsl_mc_bus_match - device to driver matching callback -- * @dev: the MC object device structure to match against -- * @drv: the device driver to search for matching MC object device id -+ * @dev: the fsl-mc device to match against -+ * @drv: the device driver to search for matching fsl-mc object type - * structures - * - * Returns 1 on success, 0 otherwise. -@@ -75,8 +75,11 @@ static int fsl_mc_bus_match(struct devic - struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(drv); - bool found = false; - -- if (WARN_ON(!fsl_mc_bus_exists())) -+ /* When driver_override is set, only bind to the matching driver */ -+ if (mc_dev->driver_override) { -+ found = !strcmp(mc_dev->driver_override, mc_drv->driver.name); - goto out; -+ } - - if (!mc_drv->match_id_table) - goto out; -@@ -91,7 +94,7 @@ static int fsl_mc_bus_match(struct devic - - /* - * Traverse the match_id table of the given driver, trying to find -- * a matching for the given MC object device. -+ * a matching for the given device. - */ - for (id = mc_drv->match_id_table; id->vendor != 0x0; id++) { - if (id->vendor == mc_dev->obj_desc.vendor && -@@ -132,23 +135,141 @@ static ssize_t modalias_show(struct devi - } - static DEVICE_ATTR_RO(modalias); - -+static ssize_t rescan_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ unsigned long val; -+ unsigned int irq_count; -+ struct fsl_mc_device *root_mc_dev; -+ struct fsl_mc_bus *root_mc_bus; -+ -+ if (!fsl_mc_is_root_dprc(dev)) -+ return -EINVAL; -+ -+ root_mc_dev = to_fsl_mc_device(dev); -+ root_mc_bus = to_fsl_mc_bus(root_mc_dev); -+ -+ if (kstrtoul(buf, 0, &val) < 0) -+ return -EINVAL; -+ -+ if (val) { -+ mutex_lock(&root_mc_bus->scan_mutex); -+ dprc_scan_objects(root_mc_dev, NULL, &irq_count); -+ mutex_unlock(&root_mc_bus->scan_mutex); -+ } -+ -+ return count; -+} -+static DEVICE_ATTR_WO(rescan); -+ -+static ssize_t driver_override_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); -+ const char *driver_override, *old = mc_dev->driver_override; -+ char *cp; -+ -+ if (WARN_ON(dev->bus != &fsl_mc_bus_type)) -+ return -EINVAL; -+ -+ if (count >= (PAGE_SIZE - 1)) -+ return -EINVAL; -+ -+ driver_override = kstrndup(buf, count, GFP_KERNEL); -+ if (!driver_override) -+ return -ENOMEM; -+ -+ cp = strchr(driver_override, '\n'); -+ if (cp) -+ *cp = '\0'; -+ -+ if (strlen(driver_override)) { -+ mc_dev->driver_override = driver_override; -+ } else { -+ kfree(driver_override); -+ mc_dev->driver_override = NULL; -+ } -+ -+ kfree(old); -+ -+ return count; -+} -+ -+static ssize_t driver_override_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); -+ -+ return snprintf(buf, PAGE_SIZE, "%s\n", mc_dev->driver_override); -+} -+static DEVICE_ATTR_RW(driver_override); -+ - static struct attribute *fsl_mc_dev_attrs[] = { - &dev_attr_modalias.attr, -+ &dev_attr_rescan.attr, -+ &dev_attr_driver_override.attr, - NULL, - }; - - ATTRIBUTE_GROUPS(fsl_mc_dev); - -+static int scan_fsl_mc_bus(struct device *dev, void *data) -+{ -+ unsigned int irq_count; -+ struct fsl_mc_device *root_mc_dev; -+ struct fsl_mc_bus *root_mc_bus; -+ -+ if (fsl_mc_is_root_dprc(dev)) { -+ root_mc_dev = to_fsl_mc_device(dev); -+ root_mc_bus = to_fsl_mc_bus(root_mc_dev); -+ mutex_lock(&root_mc_bus->scan_mutex); -+ dprc_scan_objects(root_mc_dev, NULL, &irq_count); -+ mutex_unlock(&root_mc_bus->scan_mutex); -+ } -+ -+ return 0; -+} -+ -+static ssize_t bus_rescan_store(struct bus_type *bus, -+ const char *buf, size_t count) -+{ -+ unsigned long val; -+ -+ if (kstrtoul(buf, 0, &val) < 0) -+ return -EINVAL; -+ -+ if (val) -+ bus_for_each_dev(bus, NULL, NULL, scan_fsl_mc_bus); -+ -+ return count; -+} -+static BUS_ATTR(rescan, (S_IWUSR | S_IWGRP), NULL, bus_rescan_store); -+ -+static struct attribute *fsl_mc_bus_attrs[] = { -+ &bus_attr_rescan.attr, -+ NULL, -+}; -+ -+static const struct attribute_group fsl_mc_bus_group = { -+ .attrs = fsl_mc_bus_attrs, -+}; -+ -+static const struct attribute_group *fsl_mc_bus_groups[] = { -+ &fsl_mc_bus_group, -+ NULL, -+}; -+ - struct bus_type fsl_mc_bus_type = { - .name = "fsl-mc", - .match = fsl_mc_bus_match, - .uevent = fsl_mc_bus_uevent, - .dev_groups = fsl_mc_dev_groups, -+ .bus_groups = fsl_mc_bus_groups, - }; - EXPORT_SYMBOL_GPL(fsl_mc_bus_type); - --static atomic_t root_dprc_count = ATOMIC_INIT(0); +-int __must_check fsl_mc_device_add(struct dprc_obj_desc *obj_desc, +- struct fsl_mc_io *mc_io, +- struct device *parent_dev, +- struct fsl_mc_device **new_mc_dev); - - static int fsl_mc_driver_probe(struct device *dev) - { - struct fsl_mc_driver *mc_drv; -@@ -164,8 +285,7 @@ static int fsl_mc_driver_probe(struct de - - error = mc_drv->probe(mc_dev); - if (error < 0) { -- dev_err(dev, "MC object device probe callback failed: %d\n", -- error); -+ dev_err(dev, "%s failed: %d\n", __func__, error); - return error; - } - -@@ -183,9 +303,7 @@ static int fsl_mc_driver_remove(struct d - - error = mc_drv->remove(mc_dev); - if (error < 0) { -- dev_err(dev, -- "MC object device remove callback failed: %d\n", -- error); -+ dev_err(dev, "%s failed: %d\n", __func__, error); - return error; - } - -@@ -232,8 +350,6 @@ int __fsl_mc_driver_register(struct fsl_ - return error; - } - -- pr_info("MC object device driver %s registered\n", -- mc_driver->driver.name); - return 0; - } - EXPORT_SYMBOL_GPL(__fsl_mc_driver_register); -@@ -249,15 +365,6 @@ void fsl_mc_driver_unregister(struct fsl - EXPORT_SYMBOL_GPL(fsl_mc_driver_unregister); - - /** -- * fsl_mc_bus_exists - check if a root dprc exists -- */ --bool fsl_mc_bus_exists(void) --{ -- return atomic_read(&root_dprc_count) > 0; --} --EXPORT_SYMBOL_GPL(fsl_mc_bus_exists); +-void fsl_mc_device_remove(struct fsl_mc_device *mc_dev); - --/** - * fsl_mc_get_root_dprc - function to traverse to the root dprc - */ - void fsl_mc_get_root_dprc(struct device *dev, -@@ -315,21 +422,6 @@ static int get_dprc_icid(struct fsl_mc_i - return error; - } - --static int get_dprc_version(struct fsl_mc_io *mc_io, -- int container_id, u16 *major, u16 *minor) --{ -- struct dprc_attributes attr; -- int error; +-int __init dprc_driver_init(void); - -- error = get_dprc_attr(mc_io, container_id, &attr); -- if (error == 0) { -- *major = attr.version.major; -- *minor = attr.version.minor; -- } +-void dprc_driver_exit(void); - -- return error; --} +-int __init fsl_mc_allocator_driver_init(void); - - static int translate_mc_addr(struct fsl_mc_device *mc_dev, - enum dprc_region_type mc_region_type, - u64 mc_offset, phys_addr_t *phys_addr) -@@ -451,18 +543,37 @@ bool fsl_mc_is_root_dprc(struct device * - return dev == root_dprc_dev; - } - -+static void fsl_mc_device_release(struct device *dev) -+{ -+ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); -+ struct fsl_mc_bus *mc_bus = NULL; -+ -+ kfree(mc_dev->regions); -+ -+ if (strcmp(mc_dev->obj_desc.type, "dprc") == 0) -+ mc_bus = to_fsl_mc_bus(mc_dev); -+ -+ if (mc_bus) -+ kfree(mc_bus); -+ else -+ kfree(mc_dev); -+} -+ - /** -- * Add a newly discovered MC object device to be visible in Linux -+ * Add a newly discovered fsl-mc device to be visible in Linux - */ - int fsl_mc_device_add(struct dprc_obj_desc *obj_desc, - struct fsl_mc_io *mc_io, - struct device *parent_dev, -+ const char *driver_override, - struct fsl_mc_device **new_mc_dev) - { - int error; - struct fsl_mc_device *mc_dev = NULL; - struct fsl_mc_bus *mc_bus = NULL; - struct fsl_mc_device *parent_mc_dev; -+ struct device *fsl_mc_platform_dev; -+ struct device_node *fsl_mc_platform_node; - - if (dev_is_fsl_mc(parent_dev)) - parent_mc_dev = to_fsl_mc_device(parent_dev); -@@ -473,7 +584,7 @@ int fsl_mc_device_add(struct dprc_obj_de - /* - * Allocate an MC bus device object: - */ -- mc_bus = devm_kzalloc(parent_dev, sizeof(*mc_bus), GFP_KERNEL); -+ mc_bus = kzalloc(sizeof(*mc_bus), GFP_KERNEL); - if (!mc_bus) - return -ENOMEM; - -@@ -482,16 +593,30 @@ int fsl_mc_device_add(struct dprc_obj_de - /* - * Allocate a regular fsl_mc_device object: - */ -- mc_dev = kmem_cache_zalloc(mc_dev_cache, GFP_KERNEL); -+ mc_dev = kzalloc(sizeof(*mc_dev), GFP_KERNEL); - if (!mc_dev) - return -ENOMEM; - } - - mc_dev->obj_desc = *obj_desc; - mc_dev->mc_io = mc_io; -+ -+ if (driver_override) { -+ /* -+ * We trust driver_override, so we don't need to use -+ * kstrndup() here -+ */ -+ mc_dev->driver_override = kstrdup(driver_override, GFP_KERNEL); -+ if (!mc_dev->driver_override) { -+ error = -ENOMEM; -+ goto error_cleanup_dev; -+ } -+ } -+ - device_initialize(&mc_dev->dev); - mc_dev->dev.parent = parent_dev; - mc_dev->dev.bus = &fsl_mc_bus_type; -+ mc_dev->dev.release = fsl_mc_device_release; - dev_set_name(&mc_dev->dev, "%s.%d", obj_desc->type, obj_desc->id); - - if (strcmp(obj_desc->type, "dprc") == 0) { -@@ -524,8 +649,6 @@ int fsl_mc_device_add(struct dprc_obj_de - } - - mc_io2 = mc_io; +-void fsl_mc_allocator_driver_exit(void); - -- atomic_inc(&root_dprc_count); - } - - error = get_dprc_icid(mc_io2, obj_desc->id, &mc_dev->icid); -@@ -533,8 +656,8 @@ int fsl_mc_device_add(struct dprc_obj_de - goto error_cleanup_dev; - } else { - /* -- * A non-DPRC MC object device has to be a child of another -- * MC object (specifically a DPRC object) -+ * A non-DPRC object has to be a child of a DPRC, use the -+ * parent's ICID and interrupt domain. - */ - mc_dev->icid = parent_mc_dev->icid; - mc_dev->dma_mask = FSL_MC_DEFAULT_DMA_MASK; -@@ -556,9 +679,14 @@ int fsl_mc_device_add(struct dprc_obj_de - goto error_cleanup_dev; - } - -- /* Objects are coherent, unless 'no shareability' flag set. */ -- if (!(obj_desc->flags & DPRC_OBJ_FLAG_NO_MEM_SHAREABILITY)) -- arch_setup_dma_ops(&mc_dev->dev, 0, 0, NULL, true); -+ fsl_mc_platform_dev = &mc_dev->dev; -+ while (dev_is_fsl_mc(fsl_mc_platform_dev)) -+ fsl_mc_platform_dev = fsl_mc_platform_dev->parent; -+ fsl_mc_platform_node = fsl_mc_platform_dev->of_node; -+ -+ /* Set up the iommu configuration for the devices. */ -+ fsl_mc_dma_configure(mc_dev, fsl_mc_platform_node, -+ !(obj_desc->flags & DPRC_OBJ_FLAG_NO_MEM_SHAREABILITY)); - - /* - * The device-specific probe callback will get invoked by device_add() -@@ -571,9 +699,7 @@ int fsl_mc_device_add(struct dprc_obj_de - goto error_cleanup_dev; - } - -- (void)get_device(&mc_dev->dev); -- dev_dbg(parent_dev, "Added MC object device %s\n", -- dev_name(&mc_dev->dev)); -+ dev_dbg(parent_dev, "added %s\n", dev_name(&mc_dev->dev)); - - *new_mc_dev = mc_dev; - return 0; -@@ -581,47 +707,34 @@ int fsl_mc_device_add(struct dprc_obj_de - error_cleanup_dev: - kfree(mc_dev->regions); - if (mc_bus) -- devm_kfree(parent_dev, mc_bus); -+ kfree(mc_bus); - else -- kmem_cache_free(mc_dev_cache, mc_dev); -+ kfree(mc_dev); - - return error; - } - EXPORT_SYMBOL_GPL(fsl_mc_device_add); - - /** -- * fsl_mc_device_remove - Remove a MC object device from being visible to -+ * fsl_mc_device_remove - Remove an fsl-mc device from being visible to - * Linux - * -- * @mc_dev: Pointer to a MC object device object -+ * @mc_dev: Pointer to an fsl-mc device - */ - void fsl_mc_device_remove(struct fsl_mc_device *mc_dev) - { -- struct fsl_mc_bus *mc_bus = NULL; +-int __must_check fsl_mc_resource_allocate(struct fsl_mc_bus *mc_bus, +- enum fsl_mc_pool_type pool_type, +- struct fsl_mc_resource +- **new_resource); - -- kfree(mc_dev->regions); -+ kfree(mc_dev->driver_override); -+ mc_dev->driver_override = NULL; - - /* - * The device-specific remove callback will get invoked by device_del() - */ - device_del(&mc_dev->dev); -- put_device(&mc_dev->dev); - -- if (strcmp(mc_dev->obj_desc.type, "dprc") == 0) { -- mc_bus = to_fsl_mc_bus(mc_dev); +-void fsl_mc_resource_free(struct fsl_mc_resource *resource); - -- if (fsl_mc_is_root_dprc(&mc_dev->dev)) { -- if (atomic_read(&root_dprc_count) > 0) -- atomic_dec(&root_dprc_count); -- else -- WARN_ON(1); -- } -- } -+ if (strcmp(mc_dev->obj_desc.type, "dprc") != 0) -+ mc_dev->dev.iommu_fwspec = NULL; - -- if (mc_bus) -- devm_kfree(mc_dev->dev.parent, mc_bus); -- else -- kmem_cache_free(mc_dev_cache, mc_dev); -+ put_device(&mc_dev->dev); - } - EXPORT_SYMBOL_GPL(fsl_mc_device_remove); - -@@ -629,8 +742,7 @@ static int parse_mc_ranges(struct device - int *paddr_cells, - int *mc_addr_cells, - int *mc_size_cells, -- const __be32 **ranges_start, -- u8 *num_ranges) -+ const __be32 **ranges_start) - { - const __be32 *prop; - int range_tuple_cell_count; -@@ -643,8 +755,6 @@ static int parse_mc_ranges(struct device - dev_warn(dev, - "missing or empty ranges property for device tree node '%s'\n", - mc_node->name); +-int fsl_mc_msi_domain_alloc_irqs(struct device *dev, +- unsigned int irq_count); - -- *num_ranges = 0; - return 0; - } - -@@ -671,8 +781,7 @@ static int parse_mc_ranges(struct device - return -EINVAL; - } - -- *num_ranges = ranges_len / tuple_len; -- return 0; -+ return ranges_len / tuple_len; - } - - static int get_mc_addr_translation_ranges(struct device *dev, -@@ -680,7 +789,7 @@ static int get_mc_addr_translation_range - **ranges, - u8 *num_ranges) - { -- int error; -+ int ret; - int paddr_cells; - int mc_addr_cells; - int mc_size_cells; -@@ -688,16 +797,16 @@ static int get_mc_addr_translation_range - const __be32 *ranges_start; - const __be32 *cell; - -- error = parse_mc_ranges(dev, -+ ret = parse_mc_ranges(dev, - &paddr_cells, - &mc_addr_cells, - &mc_size_cells, -- &ranges_start, -- num_ranges); -- if (error < 0) -- return error; -+ &ranges_start); -+ if (ret < 0) -+ return ret; - -- if (!(*num_ranges)) { -+ *num_ranges = ret; -+ if (!ret) { - /* - * Missing or empty ranges property ("ranges;") for the - * 'fsl,qoriq-mc' node. In this case, identity mapping -@@ -749,8 +858,6 @@ static int fsl_mc_bus_probe(struct platf - struct mc_version mc_version; - struct resource res; - -- dev_info(&pdev->dev, "Root MC bus device probed"); +-void fsl_mc_msi_domain_free_irqs(struct device *dev); - - mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL); - if (!mc) - return -ENOMEM; -@@ -783,8 +890,7 @@ static int fsl_mc_bus_probe(struct platf - goto error_cleanup_mc_io; - } - -- dev_info(&pdev->dev, -- "Freescale Management Complex Firmware version: %u.%u.%u\n", -+ dev_info(&pdev->dev, "MC firmware version: %u.%u.%u\n", - mc_version.major, mc_version.minor, mc_version.revision); - - error = get_mc_addr_translation_ranges(&pdev->dev, -@@ -793,16 +899,17 @@ static int fsl_mc_bus_probe(struct platf - if (error < 0) - goto error_cleanup_mc_io; - -- error = dpmng_get_container_id(mc_io, 0, &container_id); -+ error = dprc_get_container_id(mc_io, 0, &container_id); - if (error < 0) { - dev_err(&pdev->dev, -- "dpmng_get_container_id() failed: %d\n", error); -+ "dprc_get_container_id() failed: %d\n", error); - goto error_cleanup_mc_io; - } - - memset(&obj_desc, 0, sizeof(struct dprc_obj_desc)); -- error = get_dprc_version(mc_io, container_id, -- &obj_desc.ver_major, &obj_desc.ver_minor); -+ error = dprc_get_api_version(mc_io, 0, -+ &obj_desc.ver_major, -+ &obj_desc.ver_minor); - if (error < 0) - goto error_cleanup_mc_io; - -@@ -812,7 +919,8 @@ static int fsl_mc_bus_probe(struct platf - obj_desc.irq_count = 1; - obj_desc.region_count = 0; - -- error = fsl_mc_device_add(&obj_desc, mc_io, &pdev->dev, &mc_bus_dev); -+ error = fsl_mc_device_add(&obj_desc, mc_io, &pdev->dev, NULL, -+ &mc_bus_dev); - if (error < 0) - goto error_cleanup_mc_io; - -@@ -840,7 +948,6 @@ static int fsl_mc_bus_remove(struct plat - fsl_destroy_mc_io(mc->root_mc_bus_dev->mc_io); - mc->root_mc_bus_dev->mc_io = NULL; - -- dev_info(&pdev->dev, "Root MC bus device removed"); - return 0; - } - -@@ -865,22 +972,12 @@ static int __init fsl_mc_bus_driver_init - { - int error; - -- mc_dev_cache = kmem_cache_create("fsl_mc_device", -- sizeof(struct fsl_mc_device), 0, 0, -- NULL); -- if (!mc_dev_cache) { -- pr_err("Could not create fsl_mc_device cache\n"); -- return -ENOMEM; -- } +-int __init its_fsl_mc_msi_init(void); - - error = bus_register(&fsl_mc_bus_type); - if (error < 0) { -- pr_err("fsl-mc bus type registration failed: %d\n", error); -+ pr_err("bus type registration failed: %d\n", error); - goto error_cleanup_cache; - } - -- pr_info("fsl-mc bus type registered\n"); +-void its_fsl_mc_msi_cleanup(void); - - error = platform_driver_register(&fsl_mc_bus_driver); - if (error < 0) { - pr_err("platform_driver_register() failed: %d\n", error); -@@ -914,7 +1011,6 @@ error_cleanup_bus: - bus_unregister(&fsl_mc_bus_type); - - error_cleanup_cache: -- kmem_cache_destroy(mc_dev_cache); - return error; - } - postcore_initcall(fsl_mc_bus_driver_init); ---- /dev/null -+++ b/drivers/staging/fsl-mc/bus/fsl-mc-iommu.c -@@ -0,0 +1,104 @@ -+/* -+ * Copyright 2016-17 NXP -+ * Author: Nipun Gupta <nipun.gupta@nxp.com> -+ * -+ * 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 <linux/iommu.h> -+#include <linux/of.h> -+#include <linux/of_iommu.h> -+#include "../include/mc.h" -+ -+/* Setup the IOMMU for the DPRC container */ -+static const struct iommu_ops -+*fsl_mc_iommu_configure(struct fsl_mc_device *mc_dev, -+ struct device_node *fsl_mc_platform_node) -+{ -+ struct of_phandle_args iommu_spec; -+ const struct iommu_ops *ops; -+ u32 iommu_phandle; -+ struct device_node *iommu_node; -+ const __be32 *map = NULL; -+ int iommu_cells, map_len, ret; -+ -+ map = of_get_property(fsl_mc_platform_node, "iommu-map", &map_len); -+ if (!map) -+ return NULL; -+ -+ ops = mc_dev->dev.bus->iommu_ops; -+ if (!ops || !ops->of_xlate) -+ return NULL; -+ -+ iommu_phandle = be32_to_cpup(map + 1); -+ iommu_node = of_find_node_by_phandle(iommu_phandle); -+ -+ if (of_property_read_u32(iommu_node, "#iommu-cells", &iommu_cells)) { -+ pr_err("%s: missing #iommu-cells property\n", iommu_node->name); -+ return NULL; -+ } -+ -+ /* Initialize the fwspec */ -+ ret = iommu_fwspec_init(&mc_dev->dev, &iommu_node->fwnode, ops); -+ if (ret) -+ return NULL; -+ -+ /* -+ * Fill in the required stream-id before calling the iommu's -+ * ops->xlate callback. -+ */ -+ iommu_spec.np = iommu_node; -+ iommu_spec.args[0] = mc_dev->icid; -+ iommu_spec.args_count = 1; -+ -+ ret = ops->of_xlate(&mc_dev->dev, &iommu_spec); -+ if (ret) -+ return NULL; -+ -+ of_node_put(iommu_spec.np); -+ -+ return ops; -+} -+ -+/* Set up DMA configuration for fsl-mc devices */ -+void fsl_mc_dma_configure(struct fsl_mc_device *mc_dev, -+ struct device_node *fsl_mc_platform_node, int coherent) -+{ -+ const struct iommu_ops *ops; -+ -+ ops = fsl_mc_iommu_configure(mc_dev, fsl_mc_platform_node); -+ -+ mc_dev->dev.coherent_dma_mask = DMA_BIT_MASK(48); -+ mc_dev->dev.dma_mask = &mc_dev->dev.coherent_dma_mask; -+ arch_setup_dma_ops(&mc_dev->dev, 0, -+ mc_dev->dev.coherent_dma_mask + 1, ops, coherent); -+} -+ -+/* Macro to get the container device of a MC device */ -+#define fsl_mc_cont_dev(_dev) ((to_fsl_mc_device(_dev)->flags & \ -+ FSL_MC_IS_DPRC) ? (_dev) : ((_dev)->parent)) -+ -+/* Macro to check if a device is a container device */ -+#define is_cont_dev(_dev) (to_fsl_mc_device(_dev)->flags & FSL_MC_IS_DPRC) -+ -+/* Get the IOMMU group for device on fsl-mc bus */ -+struct iommu_group *fsl_mc_device_group(struct device *dev) -+{ -+ struct device *cont_dev = fsl_mc_cont_dev(dev); -+ struct iommu_group *group; -+ -+ /* Container device is responsible for creating the iommu group */ -+ if (is_cont_dev(dev)) { -+ group = iommu_group_alloc(); -+ if (IS_ERR(group)) -+ return NULL; -+ } else { -+ get_device(cont_dev); -+ group = iommu_group_get(cont_dev); -+ put_device(cont_dev); -+ } -+ -+ return group; -+} ---- a/drivers/staging/fsl-mc/bus/fsl-mc-msi.c -+++ b/drivers/staging/fsl-mc/bus/fsl-mc-msi.c -@@ -1,7 +1,7 @@ - /* - * Freescale Management Complex (MC) bus driver MSI support - * -- * Copyright (C) 2015 Freescale Semiconductor, Inc. -+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. - * Author: German Rivera <German.Rivera@freescale.com> - * - * This file is licensed under the terms of the GNU General Public ---- a/drivers/staging/fsl-mc/bus/fsl-mc-private.h -+++ b/drivers/staging/fsl-mc/bus/fsl-mc-private.h -@@ -10,13 +10,15 @@ - #ifndef _FSL_MC_PRIVATE_H_ - #define _FSL_MC_PRIVATE_H_ - -+#include "../include/mc.h" -+#include "../include/mc-bus.h" -+ - int __must_check fsl_mc_device_add(struct dprc_obj_desc *obj_desc, - struct fsl_mc_io *mc_io, - struct device *parent_dev, -+ const char *driver_override, - struct fsl_mc_device **new_mc_dev); - --void fsl_mc_device_remove(struct fsl_mc_device *mc_dev); +-int __must_check fsl_create_mc_io(struct device *dev, +- phys_addr_t mc_portal_phys_addr, +- u32 mc_portal_size, +- struct fsl_mc_device *dpmcp_dev, +- u32 flags, struct fsl_mc_io **new_mc_io); - - int __init dprc_driver_init(void); - - void dprc_driver_exit(void); ---- a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c -+++ b/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c -@@ -1,7 +1,7 @@ - /* - * Freescale Management Complex (MC) bus driver MSI support - * -- * Copyright (C) 2015 Freescale Semiconductor, Inc. -+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. - * Author: German Rivera <German.Rivera@freescale.com> - * - * This file is licensed under the terms of the GNU General Public -@@ -20,7 +20,7 @@ - #include "fsl-mc-private.h" - - static struct irq_chip its_msi_irq_chip = { -- .name = "fsl-mc-bus-msi", -+ .name = "ITS-fMSI", - .irq_mask = irq_chip_mask_parent, - .irq_unmask = irq_chip_unmask_parent, - .irq_eoi = irq_chip_eoi_parent, -@@ -52,7 +52,7 @@ static int its_fsl_mc_msi_prepare(struct - return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info); - } - --static struct msi_domain_ops its_fsl_mc_msi_ops = { -+static struct msi_domain_ops its_fsl_mc_msi_ops __ro_after_init = { - .msi_prepare = its_fsl_mc_msi_prepare, - }; - -@@ -97,8 +97,8 @@ int __init its_fsl_mc_msi_init(void) - continue; - } - -- WARN_ON(mc_msi_domain-> -- host_data != &its_fsl_mc_msi_domain_info); -+ WARN_ON(mc_msi_domain->host_data != -+ &its_fsl_mc_msi_domain_info); - - pr_info("fsl-mc MSI: %s domain created\n", np->full_name); - } ---- a/drivers/staging/fsl-mc/bus/mc-io.c -+++ b/drivers/staging/fsl-mc/bus/mc-io.c -@@ -1,4 +1,5 @@ --/* Copyright 2013-2016 Freescale Semiconductor Inc. -+/* -+ * Copyright 2013-2016 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: -@@ -11,7 +12,6 @@ - * names of any 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 ---- /dev/null -+++ b/drivers/staging/fsl-mc/bus/mc-ioctl.h -@@ -0,0 +1,22 @@ -+/* -+ * Freescale Management Complex (MC) ioclt interface -+ * -+ * Copyright (C) 2014 Freescale Semiconductor, Inc. -+ * Author: Lijun Pan <Lijun.Pan@freescale.com> -+ * -+ * 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. -+ */ -+#ifndef _FSL_MC_IOCTL_H_ -+#define _FSL_MC_IOCTL_H_ -+ -+#include <linux/ioctl.h> -+#include "../include/mc-sys.h" -+ -+#define RESTOOL_IOCTL_TYPE 'R' -+ -+#define RESTOOL_SEND_MC_COMMAND \ -+ _IOWR(RESTOOL_IOCTL_TYPE, 0xE0, struct mc_command) -+ -+#endif /* _FSL_MC_IOCTL_H_ */ ---- /dev/null -+++ b/drivers/staging/fsl-mc/bus/mc-restool.c -@@ -0,0 +1,405 @@ -+/* -+ * Freescale Management Complex (MC) restool driver -+ * -+ * Copyright (C) 2014 Freescale Semiconductor, Inc. -+ * Author: Lijun Pan <Lijun.Pan@freescale.com> -+ * -+ * 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/mc.h" -+#include <linux/module.h> -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <linux/mm.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+#include <linux/mutex.h> -+#include <linux/platform_device.h> -+#include "mc-ioctl.h" -+#include "../include/mc-sys.h" -+#include "../include/mc-bus.h" -+#include "../include/mc-cmd.h" -+#include "../include/dpmng.h" -+ -+/** -+ * Maximum number of DPRCs that can be opened at the same time -+ */ -+#define MAX_DPRC_HANDLES 64 -+ -+/** -+ * restool_misc - information associated with the newly added miscdevice -+ * @misc: newly created miscdevice associated with root dprc -+ * @miscdevt: device id of this miscdevice -+ * @list: a linked list node representing this miscdevcie -+ * @static_mc_io: pointer to the static MC I/O object used by the restool -+ * @dynamic_instance_count: number of dynamically created instances -+ * @static_instance_in_use: static instance is in use or not -+ * @mutex: mutex lock to serialze the open/release operations -+ * @dev: root dprc associated with this miscdevice -+ */ -+struct restool_misc { -+ struct miscdevice misc; -+ dev_t miscdevt; -+ struct list_head list; -+ struct fsl_mc_io *static_mc_io; -+ u32 dynamic_instance_count; -+ bool static_instance_in_use; -+ struct mutex mutex; /* serialze the open/release operations */ -+ struct device *dev; -+}; -+ -+/** -+ * struct fsl_mc - Private data of a "fsl,qoriq-mc" platform device -+ * @root_mc_bus_dev: fsl-mc device representing the root DPRC -+ * @num_translation_ranges: number of entries in addr_translation_ranges -+ * @translation_ranges: array of bus to system address translation ranges -+ */ -+struct fsl_mc { -+ struct fsl_mc_device *root_mc_bus_dev; -+ u8 num_translation_ranges; -+ struct fsl_mc_addr_translation_range *translation_ranges; -+}; -+ -+/* -+ * initialize a global list to link all -+ * the miscdevice nodes (struct restool_misc) -+ */ -+static LIST_HEAD(misc_list); -+static DEFINE_MUTEX(misc_list_mutex); -+ -+static int fsl_mc_restool_dev_open(struct inode *inode, struct file *filep) -+{ -+ struct fsl_mc_device *root_mc_dev; -+ int error; -+ struct fsl_mc_io *dynamic_mc_io = NULL; -+ struct restool_misc *restool_misc = NULL; -+ struct restool_misc *restool_misc_cursor; -+ -+ mutex_lock(&misc_list_mutex); -+ -+ list_for_each_entry(restool_misc_cursor, &misc_list, list) { -+ if (restool_misc_cursor->miscdevt == inode->i_rdev) { -+ restool_misc = restool_misc_cursor; -+ break; -+ } -+ } -+ -+ mutex_unlock(&misc_list_mutex); -+ -+ if (!restool_misc) -+ return -EINVAL; -+ -+ if (WARN_ON(!restool_misc->dev)) -+ return -EINVAL; -+ -+ mutex_lock(&restool_misc->mutex); -+ -+ if (!restool_misc->static_instance_in_use) { -+ restool_misc->static_instance_in_use = true; -+ filep->private_data = restool_misc->static_mc_io; -+ } else { -+ dynamic_mc_io = kzalloc(sizeof(*dynamic_mc_io), GFP_KERNEL); -+ if (!dynamic_mc_io) { -+ error = -ENOMEM; -+ goto err_unlock; -+ } -+ -+ root_mc_dev = to_fsl_mc_device(restool_misc->dev); -+ error = fsl_mc_portal_allocate(root_mc_dev, 0, &dynamic_mc_io); -+ if (error < 0) { -+ pr_err("Not able to allocate MC portal\n"); -+ goto free_dynamic_mc_io; -+ } -+ ++restool_misc->dynamic_instance_count; -+ filep->private_data = dynamic_mc_io; -+ } -+ -+ mutex_unlock(&restool_misc->mutex); -+ -+ return 0; -+ -+free_dynamic_mc_io: -+ kfree(dynamic_mc_io); -+err_unlock: -+ mutex_unlock(&restool_misc->mutex); -+ -+ return error; -+} -+ -+static int fsl_mc_restool_dev_release(struct inode *inode, struct file *filep) -+{ -+ struct fsl_mc_io *local_mc_io = filep->private_data; -+ struct restool_misc *restool_misc = NULL; -+ struct restool_misc *restool_misc_cursor; -+ -+ if (WARN_ON(!filep->private_data)) -+ return -EINVAL; -+ -+ mutex_lock(&misc_list_mutex); -+ -+ list_for_each_entry(restool_misc_cursor, &misc_list, list) { -+ if (restool_misc_cursor->miscdevt == inode->i_rdev) { -+ restool_misc = restool_misc_cursor; -+ break; -+ } -+ } -+ -+ mutex_unlock(&misc_list_mutex); -+ -+ if (!restool_misc) -+ return -EINVAL; -+ -+ mutex_lock(&restool_misc->mutex); -+ -+ if (WARN_ON(restool_misc->dynamic_instance_count == 0 && -+ !restool_misc->static_instance_in_use)) { -+ mutex_unlock(&restool_misc->mutex); -+ return -EINVAL; -+ } -+ -+ /* Globally clean up opened/untracked handles */ -+ fsl_mc_portal_reset(local_mc_io); -+ -+ /* -+ * must check -+ * whether local_mc_io is dynamic or static instance -+ * Otherwise it will free up the reserved portal by accident -+ * or even not free up the dynamic allocated portal -+ * if 2 or more instances running concurrently -+ */ -+ if (local_mc_io == restool_misc->static_mc_io) { -+ restool_misc->static_instance_in_use = false; -+ } else { -+ fsl_mc_portal_free(local_mc_io); -+ kfree(filep->private_data); -+ --restool_misc->dynamic_instance_count; -+ } -+ -+ filep->private_data = NULL; -+ mutex_unlock(&restool_misc->mutex); -+ -+ return 0; -+} -+ -+static int restool_send_mc_command(unsigned long arg, -+ struct fsl_mc_io *local_mc_io) -+{ -+ int error; -+ struct mc_command mc_cmd; -+ -+ if (copy_from_user(&mc_cmd, (void __user *)arg, sizeof(mc_cmd))) -+ return -EFAULT; -+ -+ /* -+ * Send MC command to the MC: -+ */ -+ error = mc_send_command(local_mc_io, &mc_cmd); -+ if (error < 0) -+ return error; -+ -+ if (copy_to_user((void __user *)arg, &mc_cmd, sizeof(mc_cmd))) -+ return -EFAULT; -+ -+ return 0; -+} -+ -+static long -+fsl_mc_restool_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ int error; -+ -+ switch (cmd) { -+ case RESTOOL_SEND_MC_COMMAND: -+ error = restool_send_mc_command(arg, file->private_data); -+ break; -+ default: -+ pr_err("%s: unexpected ioctl call number\n", __func__); -+ error = -EINVAL; -+ } -+ -+ return error; -+} -+ -+static const struct file_operations fsl_mc_restool_dev_fops = { -+ .owner = THIS_MODULE, -+ .open = fsl_mc_restool_dev_open, -+ .release = fsl_mc_restool_dev_release, -+ .unlocked_ioctl = fsl_mc_restool_dev_ioctl, -+}; -+ -+static int restool_add_device_file(struct device *dev) -+{ -+ u32 name1 = 0; -+ char name2[20] = {0}; -+ int error; -+ struct fsl_mc_device *root_mc_dev; -+ struct restool_misc *restool_misc; -+ -+ if (dev->bus == &platform_bus_type && dev->driver_data) { -+ if (sscanf(dev_name(dev), "%x.%s", &name1, name2) != 2) -+ return -EINVAL; -+ -+ if (strcmp(name2, "fsl-mc") == 0) -+ pr_debug("platform's root dprc name is: %s\n", -+ dev_name(&(((struct fsl_mc *) -+ (dev->driver_data))->root_mc_bus_dev->dev))); -+ } -+ -+ if (!fsl_mc_is_root_dprc(dev)) -+ return 0; -+ -+ restool_misc = kzalloc(sizeof(*restool_misc), GFP_KERNEL); -+ if (!restool_misc) -+ return -ENOMEM; -+ -+ restool_misc->dev = dev; -+ root_mc_dev = to_fsl_mc_device(dev); -+ error = fsl_mc_portal_allocate(root_mc_dev, 0, -+ &restool_misc->static_mc_io); -+ if (error < 0) { -+ pr_err("Not able to allocate MC portal\n"); -+ goto free_restool_misc; -+ } -+ -+ restool_misc->misc.minor = MISC_DYNAMIC_MINOR; -+ restool_misc->misc.name = dev_name(dev); -+ restool_misc->misc.fops = &fsl_mc_restool_dev_fops; -+ -+ error = misc_register(&restool_misc->misc); -+ if (error < 0) { -+ pr_err("misc_register() failed: %d\n", error); -+ goto free_portal; -+ } -+ -+ restool_misc->miscdevt = restool_misc->misc.this_device->devt; -+ mutex_init(&restool_misc->mutex); -+ mutex_lock(&misc_list_mutex); -+ list_add(&restool_misc->list, &misc_list); -+ mutex_unlock(&misc_list_mutex); -+ -+ pr_info("/dev/%s driver registered\n", dev_name(dev)); -+ -+ return 0; -+ -+free_portal: -+ fsl_mc_portal_free(restool_misc->static_mc_io); -+free_restool_misc: -+ kfree(restool_misc); -+ -+ return error; -+} -+ -+static int restool_bus_notifier(struct notifier_block *nb, -+ unsigned long action, void *data) -+{ -+ int error; -+ struct device *dev = data; -+ -+ switch (action) { -+ case BUS_NOTIFY_ADD_DEVICE: -+ error = restool_add_device_file(dev); -+ if (error) -+ return error; -+ break; -+ case BUS_NOTIFY_DEL_DEVICE: -+ case BUS_NOTIFY_REMOVED_DEVICE: -+ case BUS_NOTIFY_BIND_DRIVER: -+ case BUS_NOTIFY_BOUND_DRIVER: -+ case BUS_NOTIFY_UNBIND_DRIVER: -+ case BUS_NOTIFY_UNBOUND_DRIVER: -+ break; -+ default: -+ pr_err("%s: unrecognized device action from %s\n", __func__, -+ dev_name(dev)); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int add_to_restool(struct device *dev, void *data) -+{ -+ return restool_add_device_file(dev); -+} -+ -+static int __init fsl_mc_restool_driver_init(void) -+{ -+ int error; -+ struct notifier_block *nb; -+ -+ nb = kzalloc(sizeof(*nb), GFP_KERNEL); -+ if (!nb) -+ return -ENOMEM; -+ -+ nb->notifier_call = restool_bus_notifier; -+ error = bus_register_notifier(&fsl_mc_bus_type, nb); -+ if (error) -+ goto free_nb; -+ -+ /* -+ * This driver runs after fsl-mc bus driver runs. -+ * Hence, many of the root dprcs are already attached to fsl-mc bus -+ * In order to make sure we find all the root dprcs, -+ * we need to scan the fsl_mc_bus_type. -+ */ -+ error = bus_for_each_dev(&fsl_mc_bus_type, NULL, NULL, add_to_restool); -+ if (error) { -+ bus_unregister_notifier(&fsl_mc_bus_type, nb); -+ kfree(nb); -+ pr_err("restool driver registration failure\n"); -+ return error; -+ } -+ -+ return 0; -+ -+free_nb: -+ kfree(nb); -+ return error; -+} -+ -+module_init(fsl_mc_restool_driver_init); -+ -+static void __exit fsl_mc_restool_driver_exit(void) -+{ -+ struct restool_misc *restool_misc; -+ struct restool_misc *restool_misc_tmp; -+ char name1[20] = {0}; -+ u32 name2 = 0; -+ -+ list_for_each_entry_safe(restool_misc, restool_misc_tmp, -+ &misc_list, list) { -+ if (sscanf(restool_misc->misc.name, "%4s.%u", name1, &name2) -+ != 2) -+ continue; -+ -+ pr_debug("name1=%s,name2=%u\n", name1, name2); -+ pr_debug("misc-device: %s\n", restool_misc->misc.name); -+ if (strcmp(name1, "dprc") != 0) -+ continue; -+ -+ if (WARN_ON(!restool_misc->static_mc_io)) -+ return; -+ -+ if (WARN_ON(restool_misc->dynamic_instance_count != 0)) -+ return; -+ -+ if (WARN_ON(restool_misc->static_instance_in_use)) -+ return; -+ -+ misc_deregister(&restool_misc->misc); -+ pr_info("/dev/%s driver unregistered\n", -+ restool_misc->misc.name); -+ fsl_mc_portal_free(restool_misc->static_mc_io); -+ list_del(&restool_misc->list); -+ kfree(restool_misc); -+ } -+} -+ -+module_exit(fsl_mc_restool_driver_exit); -+ -+MODULE_AUTHOR("Freescale Semiconductor Inc."); -+MODULE_DESCRIPTION("Freescale's MC restool driver"); -+MODULE_LICENSE("GPL"); ---- a/drivers/staging/fsl-mc/bus/mc-sys.c -+++ b/drivers/staging/fsl-mc/bus/mc-sys.c -@@ -1,4 +1,5 @@ --/* Copyright 2013-2014 Freescale Semiconductor Inc. -+/* -+ * Copyright 2013-2016 Freescale Semiconductor Inc. - * - * I/O services to send MC commands to the MC hardware - * -@@ -13,7 +14,6 @@ - * names of any 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 -@@ -46,7 +46,7 @@ - /** - * Timeout in milliseconds to wait for the completion of an MC command - */ --#define MC_CMD_COMPLETION_TIMEOUT_MS 500 -+#define MC_CMD_COMPLETION_TIMEOUT_MS 15000 - - /* - * usleep_range() min and max values used to throttle down polling -@@ -67,7 +67,7 @@ static u16 mc_cmd_hdr_read_cmdid(struct - struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header; - u16 cmd_id = le16_to_cpu(hdr->cmd_id); - -- return (cmd_id & MC_CMD_HDR_CMDID_MASK) >> MC_CMD_HDR_CMDID_SHIFT; -+ return cmd_id; - } - - static int mc_status_to_error(enum mc_cmd_status status) -@@ -200,7 +200,7 @@ static int mc_polling_wait_preemptible(s - - if (time_after_eq(jiffies, jiffies_until_timeout)) { - dev_dbg(mc_io->dev, -- "MC command timed out (portal: %#llx, obj handle: %#x, command: %#x)\n", -+ "MC command timed out (portal: %#llx, dprc handle: %#x, command: %#x)\n", - mc_io->portal_phys_addr, - (unsigned int)mc_cmd_hdr_read_token(cmd), - (unsigned int)mc_cmd_hdr_read_cmdid(cmd)); -@@ -240,7 +240,7 @@ static int mc_polling_wait_atomic(struct - timeout_usecs -= MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS; - if (timeout_usecs == 0) { - dev_dbg(mc_io->dev, -- "MC command timed out (portal: %#llx, obj handle: %#x, command: %#x)\n", -+ "MC command timed out (portal: %#llx, dprc handle: %#x, command: %#x)\n", - mc_io->portal_phys_addr, - (unsigned int)mc_cmd_hdr_read_token(cmd), - (unsigned int)mc_cmd_hdr_read_cmdid(cmd)); -@@ -294,7 +294,7 @@ int mc_send_command(struct fsl_mc_io *mc - - if (status != MC_CMD_STATUS_OK) { - dev_dbg(mc_io->dev, -- "MC command failed: portal: %#llx, obj handle: %#x, command: %#x, status: %s (%#x)\n", -+ "MC command failed: portal: %#llx, dprc handle: %#x, command: %#x, status: %s (%#x)\n", - mc_io->portal_phys_addr, - (unsigned int)mc_cmd_hdr_read_token(cmd), - (unsigned int)mc_cmd_hdr_read_cmdid(cmd), +-void fsl_destroy_mc_io(struct fsl_mc_io *mc_io); +- +-#endif /* _FSL_MC_PRIVATE_H_ */ --- /dev/null +++ b/drivers/staging/fsl-mc/include/dpaa2-fd.h -@@ -0,0 +1,706 @@ +@@ -0,0 +1,681 @@ ++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright 2014-2016 Freescale Semiconductor Inc. + * Copyright 2016 NXP + * -+ * 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. + */ +#ifndef __FSL_DPAA2_FD_H +#define __FSL_DPAA2_FD_H @@ -9128,7 +16507,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + */ +static inline dma_addr_t dpaa2_sg_get_addr(const struct dpaa2_sg_entry *sg) +{ -+ return le64_to_cpu((dma_addr_t)sg->addr); ++ return (dma_addr_t)le64_to_cpu(sg->addr); +} + +/** @@ -9259,8 +16638,8 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + */ +static inline void dpaa2_sg_set_final(struct dpaa2_sg_entry *sg, bool final) +{ -+ sg->format_offset &= cpu_to_le16(~(SG_FINAL_FLAG_MASK -+ << SG_FINAL_FLAG_SHIFT)); ++ sg->format_offset &= cpu_to_le16((~(SG_FINAL_FLAG_MASK ++ << SG_FINAL_FLAG_SHIFT)) & 0xFFFF); + sg->format_offset |= cpu_to_le16(final << SG_FINAL_FLAG_SHIFT); +} + @@ -9501,37 +16880,12 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +#endif /* __FSL_DPAA2_FD_H */ --- /dev/null +++ b/drivers/staging/fsl-mc/include/dpaa2-global.h -@@ -0,0 +1,202 @@ +@@ -0,0 +1,177 @@ ++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright 2014-2016 Freescale Semiconductor Inc. + * Copyright 2016 NXP + * -+ * 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. + */ +#ifndef __FSL_DPAA2_GLOBAL_H +#define __FSL_DPAA2_GLOBAL_H @@ -9706,37 +17060,12 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +#endif /* __FSL_DPAA2_GLOBAL_H */ --- /dev/null +++ b/drivers/staging/fsl-mc/include/dpaa2-io.h -@@ -0,0 +1,190 @@ +@@ -0,0 +1,178 @@ ++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright 2014-2016 Freescale Semiconductor Inc. + * Copyright 2017 NXP + * -+ * 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. + */ +#ifndef __FSL_DPAA2_IO_H +#define __FSL_DPAA2_IO_H @@ -9762,6 +17091,8 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + * for dequeue. + */ + ++#define DPAA2_IO_ANY_CPU -1 ++ +/** + * struct dpaa2_io_desc - The DPIO descriptor + * @receives_notifications: Use notificaton mode. Non-zero if the DPIO @@ -9794,13 +17125,15 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + +irqreturn_t dpaa2_io_irq(struct dpaa2_io *obj); + ++struct dpaa2_io *dpaa2_io_service_select(int cpu); ++ +/** + * struct dpaa2_io_notification_ctx - The DPIO notification context structure + * @cb: The callback to be invoked when the notification arrives + * @is_cdan: Zero for FQDAN, non-zero for CDAN + * @id: FQID or channel ID, needed for rearm -+ * @desired_cpu: The cpu on which the notifications will show up. -1 means -+ * any CPU. ++ * @desired_cpu: The cpu on which the notifications will show up. Use ++ * DPAA2_IO_ANY_CPU if don't care + * @dpio_id: The dpio index + * @qman64: The 64-bit context value shows up in the FQDAN/CDAN. + * @node: The list node @@ -9809,7 +17142,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + * Used when a FQDAN/CDAN registration is made by drivers. + */ +struct dpaa2_io_notification_ctx { -+ void (*cb)(struct dpaa2_io_notification_ctx *); ++ void (*cb)(struct dpaa2_io_notification_ctx *ctx); + int is_cdan; + u32 id; + int desired_cpu; @@ -9845,13 +17178,17 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +void dpaa2_io_store_destroy(struct dpaa2_io_store *s); +struct dpaa2_dq *dpaa2_io_store_next(struct dpaa2_io_store *s, int *is_last); + -+#ifdef CONFIG_FSL_QBMAN_DEBUG -+int dpaa2_io_query_fq_count(struct dpaa2_io *d, uint32_t fqid, -+ uint32_t *fcnt, uint32_t *bcnt); -+int dpaa2_io_query_bp_count(struct dpaa2_io *d, uint32_t bpid, -+ uint32_t *num); -+#endif ++/* Order Restoration Support */ ++int dpaa2_io_service_enqueue_orp_fq(struct dpaa2_io *d, u32 fqid, ++ const struct dpaa2_fd *fd, u16 orpid, ++ u16 seqnum, int last); ++ ++int dpaa2_io_service_enqueue_orp_qd(struct dpaa2_io *d, u32 qdid, u8 prio, ++ u16 qdbin, const struct dpaa2_fd *fd, ++ u16 orpid, u16 seqnum, int last); + ++int dpaa2_io_service_orp_seqnum_drop(struct dpaa2_io *d, u16 orpid, ++ u16 seqnum); + +/***************/ +/* CSCN */ @@ -9896,6 +17233,11 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + return ((cscn->state & DPAA2_CSCN_STATE_MASK) == DPAA2_CSCN_CONGESTED); +} + ++int dpaa2_io_query_fq_count(struct dpaa2_io *d, u32 fqid, ++ u32 *fcnt, u32 *bcnt); ++int dpaa2_io_query_bp_count(struct dpaa2_io *d, u32 bpid, ++ u32 *num); ++ +#endif /* __FSL_DPAA2_IO_H */ --- a/drivers/staging/fsl-mc/include/dpbp-cmd.h +++ /dev/null @@ -10086,28 +17428,54 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - -#endif /* _FSL_DPBP_CMD_H */ --- a/drivers/staging/fsl-mc/include/dpbp.h -+++ b/drivers/staging/fsl-mc/include/dpbp.h -@@ -1,4 +1,5 @@ ++++ /dev/null +@@ -1,220 +0,0 @@ -/* Copyright 2013-2015 Freescale Semiconductor Inc. -+/* -+ * Copyright 2013-2016 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: -@@ -32,7 +33,8 @@ - #ifndef __FSL_DPBP_H - #define __FSL_DPBP_H - +- * +- * 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 the above-listed copyright holders nor the +- * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. +- */ +-#ifndef __FSL_DPBP_H +-#define __FSL_DPBP_H +- -/* Data Path Buffer Pool API -+/* -+ * Data Path Buffer Pool API - * Contains initialization APIs and runtime control APIs for DPBP - */ - -@@ -44,25 +46,8 @@ int dpbp_open(struct fsl_mc_io *mc_io, - u16 *token); - - int dpbp_close(struct fsl_mc_io *mc_io, +- * Contains initialization APIs and runtime control APIs for DPBP +- */ +- +-struct fsl_mc_io; +- +-int dpbp_open(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- int dpbp_id, +- u16 *token); +- +-int dpbp_close(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); - @@ -10127,15 +17495,25 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> -int dpbp_destroy(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); -+ u32 cmd_flags, -+ u16 token); - - int dpbp_enable(struct fsl_mc_io *mc_io, - u32 cmd_flags, -@@ -82,139 +67,24 @@ int dpbp_reset(struct fsl_mc_io *mc_io, - u16 token); - - /** +- +-int dpbp_enable(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token); +- +-int dpbp_disable(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token); +- +-int dpbp_is_enabled(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int *en); +- +-int dpbp_reset(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token); +- +-/** - * struct dpbp_irq_cfg - IRQ configuration - * @addr: Address that must be written to signal a message-based interrupt - * @val: Value to write into irq_addr address @@ -10197,14 +17575,14 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - u32 status); - -/** - * struct dpbp_attr - Structure representing DPBP attributes - * @id: DPBP object ID +- * struct dpbp_attr - Structure representing DPBP attributes +- * @id: DPBP object ID - * @version: DPBP version - * @bpid: Hardware buffer pool ID; should be used as an argument in - * acquire/release operations on buffers - */ - struct dpbp_attr { - int id; +- * @bpid: Hardware buffer pool ID; should be used as an argument in +- * acquire/release operations on buffers +- */ +-struct dpbp_attr { +- int id; - /** - * struct version - Structure representing DPBP version - * @major: DPBP major version @@ -10214,9 +17592,9 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - u16 major; - u16 minor; - } version; - u16 bpid; - }; - +- u16 bpid; +-}; +- -int dpbp_get_attributes(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, @@ -10270,158 +17648,136 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - struct dpbp_notification_cfg *cfg); - -/** @} */ -+int dpbp_get_attributes(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ struct dpbp_attr *attr); -+ -+int dpbp_get_api_version(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 *major_ver, -+ u16 *minor_ver); - - #endif /* __FSL_DPBP_H */ ---- /dev/null -+++ b/drivers/staging/fsl-mc/include/dpcon.h -@@ -0,0 +1,115 @@ -+/* Copyright 2013-2016 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 the above-listed copyright holders nor the -+ * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. -+ */ -+#ifndef __FSL_DPCON_H -+#define __FSL_DPCON_H -+ -+/* Data Path Concentrator API -+ * Contains initialization APIs and runtime control APIs for DPCON -+ */ -+ -+struct fsl_mc_io; -+ -+/** General DPCON macros */ -+ -+/** -+ * Use it to disable notifications; see dpcon_set_notification() -+ */ -+#define DPCON_INVALID_DPIO_ID (int)(-1) -+ -+int dpcon_open(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ int dpcon_id, -+ u16 *token); -+ -+int dpcon_close(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token); -+ -+int dpcon_enable(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token); -+ -+int dpcon_disable(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token); -+ -+int dpcon_is_enabled(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ int *en); -+ -+int dpcon_reset(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token); -+ -+/** -+ * struct dpcon_attr - Structure representing DPCON attributes -+ * @id: DPCON object ID -+ * @qbman_ch_id: Channel ID to be used by dequeue operation -+ * @num_priorities: Number of priorities for the DPCON channel (1-8) -+ */ -+struct dpcon_attr { -+ int id; -+ u16 qbman_ch_id; -+ u8 num_priorities; -+}; -+ -+int dpcon_get_attributes(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ struct dpcon_attr *attr); -+ -+/** -+ * struct dpcon_notification_cfg - Structure representing notification params -+ * @dpio_id: DPIO object ID; must be configured with a notification channel; -+ * to disable notifications set it to 'DPCON_INVALID_DPIO_ID'; -+ * @priority: Priority selection within the DPIO channel; valid values -+ * are 0-7, depending on the number of priorities in that channel -+ * @user_ctx: User context value provided with each CDAN message -+ */ -+struct dpcon_notification_cfg { -+ int dpio_id; -+ u8 priority; -+ u64 user_ctx; -+}; -+ -+int dpcon_set_notification(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ struct dpcon_notification_cfg *cfg); -+ -+int dpcon_get_api_version(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 *major_ver, -+ u16 *minor_ver); -+ -+#endif /* __FSL_DPCON_H */ +- +-#endif /* __FSL_DPBP_H */ +--- a/drivers/staging/fsl-mc/include/dpcon-cmd.h ++++ /dev/null +@@ -1,62 +0,0 @@ +-/* Copyright 2013-2015 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 the above-listed copyright holders nor the +- * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. +- */ +-#ifndef _FSL_DPCON_CMD_H +-#define _FSL_DPCON_CMD_H +- +-/* DPCON Version */ +-#define DPCON_VER_MAJOR 2 +-#define DPCON_VER_MINOR 1 +- +-/* Command IDs */ +-#define DPCON_CMDID_CLOSE 0x800 +-#define DPCON_CMDID_OPEN 0x808 +-#define DPCON_CMDID_CREATE 0x908 +-#define DPCON_CMDID_DESTROY 0x900 +- +-#define DPCON_CMDID_ENABLE 0x002 +-#define DPCON_CMDID_DISABLE 0x003 +-#define DPCON_CMDID_GET_ATTR 0x004 +-#define DPCON_CMDID_RESET 0x005 +-#define DPCON_CMDID_IS_ENABLED 0x006 +- +-#define DPCON_CMDID_SET_IRQ 0x010 +-#define DPCON_CMDID_GET_IRQ 0x011 +-#define DPCON_CMDID_SET_IRQ_ENABLE 0x012 +-#define DPCON_CMDID_GET_IRQ_ENABLE 0x013 +-#define DPCON_CMDID_SET_IRQ_MASK 0x014 +-#define DPCON_CMDID_GET_IRQ_MASK 0x015 +-#define DPCON_CMDID_GET_IRQ_STATUS 0x016 +-#define DPCON_CMDID_CLEAR_IRQ_STATUS 0x017 +- +-#define DPCON_CMDID_SET_NOTIFICATION 0x100 +- +-#endif /* _FSL_DPCON_CMD_H */ --- a/drivers/staging/fsl-mc/include/dpmng.h -+++ b/drivers/staging/fsl-mc/include/dpmng.h -@@ -1,4 +1,5 @@ ++++ /dev/null +@@ -1,69 +0,0 @@ -/* Copyright 2013-2015 Freescale Semiconductor Inc. -+/* -+ * Copyright 2013-2016 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: -@@ -32,7 +33,8 @@ - #ifndef __FSL_DPMNG_H - #define __FSL_DPMNG_H - +- * +- * 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 the above-listed copyright holders nor the +- * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. +- */ +-#ifndef __FSL_DPMNG_H +-#define __FSL_DPMNG_H +- -/* Management Complex General API -+/* -+ * Management Complex General API - * Contains general API for the Management Complex firmware - */ - -@@ -58,12 +60,8 @@ struct mc_version { - u32 revision; - }; - +- * Contains general API for the Management Complex firmware +- */ +- +-struct fsl_mc_io; +- +-/** +- * Management Complex firmware version information +- */ +-#define MC_VER_MAJOR 8 +-#define MC_VER_MINOR 0 +- +-/** +- * struct mc_version +- * @major: Major version number: incremented on API compatibility changes +- * @minor: Minor version number: incremented on API additions (that are +- * backward compatible); reset when major version is incremented +- * @revision: Internal revision number: incremented on implementation changes +- * and/or bug fixes that have no impact on API +- */ +-struct mc_version { +- u32 major; +- u32 minor; +- u32 revision; +-}; +- -int mc_get_version(struct fsl_mc_io *mc_io, - u32 cmd_flags, - struct mc_version *mc_ver_info); @@ -10429,14 +17785,11 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> -int dpmng_get_container_id(struct fsl_mc_io *mc_io, - u32 cmd_flags, - int *container_id); -+int mc_get_version(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ struct mc_version *mc_ver_info); - - #endif /* __FSL_DPMNG_H */ +- +-#endif /* __FSL_DPMNG_H */ --- /dev/null +++ b/drivers/staging/fsl-mc/include/dpopr.h -@@ -0,0 +1,110 @@ +@@ -0,0 +1,112 @@ +/* + * Copyright 2017 NXP + * @@ -10472,6 +17825,8 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +#ifndef __FSL_DPOPR_H_ +#define __FSL_DPOPR_H_ + ++#include <linux/types.h> ++ +/* Data Path Order Restoration API + * Contains initialization APIs and runtime APIs for the Order Restoration + */ @@ -10548,26 +17903,50 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + +#endif /* __FSL_DPOPR_H_ */ --- a/drivers/staging/fsl-mc/include/dprc.h -+++ b/drivers/staging/fsl-mc/include/dprc.h -@@ -1,4 +1,5 @@ ++++ /dev/null +@@ -1,544 +0,0 @@ -/* Copyright 2013-2015 Freescale Semiconductor Inc. -+/* -+ * Copyright 2013-2016 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: -@@ -34,26 +35,13 @@ - - #include "mc-cmd.h" - +- * +- * 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 the above-listed copyright holders nor the +- * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. +- */ +-#ifndef _FSL_DPRC_H +-#define _FSL_DPRC_H +- +-#include "mc-cmd.h" +- -/* Data Path Resource Container API -+/* -+ * Data Path Resource Container API - * Contains DPRC API for managing and querying DPAA resources - */ - - struct fsl_mc_io; - +- * Contains DPRC API for managing and querying DPAA resources +- */ +- +-struct fsl_mc_io; +- -/** - * Set this value as the icid value in dprc_cfg structure when creating a - * container, in case the ICID is not selected by the user and should be @@ -10582,13 +17961,15 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - */ -#define DPRC_GET_PORTAL_ID_FROM_POOL (int)(~(0)) - - int dprc_open(struct fsl_mc_io *mc_io, - u32 cmd_flags, - int container_id, -@@ -63,75 +51,6 @@ int dprc_close(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); - +-int dprc_open(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- int container_id, +- u16 *token); +- +-int dprc_close(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token); +- -/** - * Container general options - * @@ -10658,39 +18039,45 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - u32 cmd_flags, - u16 token, - int child_container_id); - - /* IRQ */ - -@@ -139,7 +58,7 @@ int dprc_reset_container(struct fsl_mc_i - #define DPRC_IRQ_INDEX 0 - - /* Number of dprc's IRQs */ +- +-/* IRQ */ +- +-/* IRQ index */ +-#define DPRC_IRQ_INDEX 0 +- +-/* Number of dprc's IRQs */ -#define DPRC_NUM_OF_IRQS 1 -+#define DPRC_NUM_OF_IRQS 1 - - /* DPRC IRQ events */ - -@@ -151,12 +70,14 @@ int dprc_reset_container(struct fsl_mc_i - #define DPRC_IRQ_EVENT_RES_ADDED 0x00000004 - /* IRQ event - Indicates that resources removed from the container */ - #define DPRC_IRQ_EVENT_RES_REMOVED 0x00000008 +- +-/* DPRC IRQ events */ +- +-/* IRQ event - Indicates that a new object added to the container */ +-#define DPRC_IRQ_EVENT_OBJ_ADDED 0x00000001 +-/* IRQ event - Indicates that an object was removed from the container */ +-#define DPRC_IRQ_EVENT_OBJ_REMOVED 0x00000002 +-/* IRQ event - Indicates that resources added to the container */ +-#define DPRC_IRQ_EVENT_RES_ADDED 0x00000004 +-/* IRQ event - Indicates that resources removed from the container */ +-#define DPRC_IRQ_EVENT_RES_REMOVED 0x00000008 -/* IRQ event - Indicates that one of the descendant containers that opened by -+/* -+ * IRQ event - Indicates that one of the descendant containers that opened by - * this container is destroyed - */ - #define DPRC_IRQ_EVENT_CONTAINER_DESTROYED 0x00000010 - +- * this container is destroyed +- */ +-#define DPRC_IRQ_EVENT_CONTAINER_DESTROYED 0x00000010 +- -/* IRQ event - Indicates that on one of the container's opened object is -+/* -+ * IRQ event - Indicates that on one of the container's opened object is - * destroyed - */ - #define DPRC_IRQ_EVENT_OBJ_DESTROYED 0x00000020 -@@ -171,59 +92,59 @@ int dprc_reset_container(struct fsl_mc_i - * @irq_num: A user defined number associated with this IRQ - */ - struct dprc_irq_cfg { +- * destroyed +- */ +-#define DPRC_IRQ_EVENT_OBJ_DESTROYED 0x00000020 +- +-/* Irq event - Indicates that object is created at the container */ +-#define DPRC_IRQ_EVENT_OBJ_CREATED 0x00000040 +- +-/** +- * struct dprc_irq_cfg - IRQ configuration +- * @paddr: Address that must be written to signal a message-based interrupt +- * @val: Value to write into irq_addr address +- * @irq_num: A user defined number associated with this IRQ +- */ +-struct dprc_irq_cfg { - phys_addr_t paddr; - u32 val; - int irq_num; @@ -10744,73 +18131,20 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - u16 token, - u8 irq_index, - u32 status); -+ phys_addr_t paddr; -+ u32 val; -+ int irq_num; -+}; -+ -+int dprc_set_irq(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ u8 irq_index, -+ struct dprc_irq_cfg *irq_cfg); -+ -+int dprc_get_irq(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ u8 irq_index, -+ int *type, -+ struct dprc_irq_cfg *irq_cfg); -+ -+int dprc_set_irq_enable(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ u8 irq_index, -+ u8 en); -+ -+int dprc_get_irq_enable(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ u8 irq_index, -+ u8 *en); -+ -+int dprc_set_irq_mask(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ u8 irq_index, -+ u32 mask); -+ -+int dprc_get_irq_mask(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ u8 irq_index, -+ u32 *mask); -+ -+int dprc_get_irq_status(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ u8 irq_index, -+ u32 *status); -+ -+int dprc_clear_irq_status(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ u8 irq_index, -+ u32 status); - - /** - * struct dprc_attributes - Container attributes -@@ -231,114 +152,23 @@ int dprc_clear_irq_status(struct fsl_mc_ - * @icid: Container's ICID - * @portal_id: Container's portal ID - * @options: Container's options as set at container's creation +- +-/** +- * struct dprc_attributes - Container attributes +- * @container_id: Container's ID +- * @icid: Container's ICID +- * @portal_id: Container's portal ID +- * @options: Container's options as set at container's creation - * @version: DPRC version - */ - struct dprc_attributes { - int container_id; - u16 icid; - int portal_id; - u64 options; +- */ +-struct dprc_attributes { +- int container_id; +- u16 icid; +- int portal_id; +- u64 options; - /** - * struct version - DPRC version - * @major: DPRC major version @@ -10820,8 +18154,8 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - u16 major; - u16 minor; - } version; - }; - +-}; +- -int dprc_get_attributes(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, @@ -10907,34 +18241,53 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - u16 token, - int pool_index, - char *type); -+int dprc_get_attributes(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ struct dprc_attributes *attributes); - - int dprc_get_obj_count(struct fsl_mc_io *mc_io, +- +-int dprc_get_obj_count(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - int *obj_count); -+ u32 cmd_flags, -+ u16 token, -+ int *obj_count); - - /* Objects Attributes Flags */ - -@@ -353,7 +183,7 @@ int dprc_get_obj_count(struct fsl_mc_io - * masters; - * user is responsible for proper memory handling through IOMMU configuration. - */ +- +-/* Objects Attributes Flags */ +- +-/* Opened state - Indicates that an object is open by at least one owner */ +-#define DPRC_OBJ_STATE_OPEN 0x00000001 +-/* Plugged state - Indicates that the object is plugged */ +-#define DPRC_OBJ_STATE_PLUGGED 0x00000002 +- +-/** +- * Shareability flag - Object flag indicating no memory shareability. +- * the object generates memory accesses that are non coherent with other +- * masters; +- * user is responsible for proper memory handling through IOMMU configuration. +- */ -#define DPRC_OBJ_FLAG_NO_MEM_SHAREABILITY 0x0001 -+#define DPRC_OBJ_FLAG_NO_MEM_SHAREABILITY 0x0001 - - /** - * struct dprc_obj_desc - Object descriptor, returned from dprc_get_obj() -@@ -381,41 +211,41 @@ struct dprc_obj_desc { - u16 flags; - }; - +- +-/** +- * struct dprc_obj_desc - Object descriptor, returned from dprc_get_obj() +- * @type: Type of object: NULL terminated string +- * @id: ID of logical object resource +- * @vendor: Object vendor identifier +- * @ver_major: Major version number +- * @ver_minor: Minor version number +- * @irq_count: Number of interrupts supported by the object +- * @region_count: Number of mappable regions supported by the object +- * @state: Object state: combination of DPRC_OBJ_STATE_ states +- * @label: Object label +- * @flags: Object's flags +- */ +-struct dprc_obj_desc { +- char type[16]; +- int id; +- u16 vendor; +- u16 ver_major; +- u16 ver_minor; +- u8 irq_count; +- u8 region_count; +- u32 state; +- char label[16]; +- u16 flags; +-}; +- -int dprc_get_obj(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, @@ -10970,48 +18323,19 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - u16 token, - char *type, - int *res_count); -+int dprc_get_obj(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ int obj_index, -+ struct dprc_obj_desc *obj_desc); -+ -+int dprc_get_obj_desc(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ char *obj_type, -+ int obj_id, -+ struct dprc_obj_desc *obj_desc); -+ -+int dprc_set_obj_irq(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ char *obj_type, -+ int obj_id, -+ u8 irq_index, -+ struct dprc_irq_cfg *irq_cfg); -+ -+int dprc_get_obj_irq(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ char *obj_type, -+ int obj_id, -+ u8 irq_index, -+ int *type, -+ struct dprc_irq_cfg *irq_cfg); -+ -+int dprc_get_res_count(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ char *type, -+ int *res_count); - - /** - * enum dprc_iter_status - Iteration status -@@ -429,27 +259,6 @@ enum dprc_iter_status { - DPRC_ITER_STATUS_LAST = 2 - }; - +- +-/** +- * enum dprc_iter_status - Iteration status +- * @DPRC_ITER_STATUS_FIRST: Perform first iteration +- * @DPRC_ITER_STATUS_MORE: Indicates more/next iteration is needed +- * @DPRC_ITER_STATUS_LAST: Indicates last iteration +- */ +-enum dprc_iter_status { +- DPRC_ITER_STATUS_FIRST = 0, +- DPRC_ITER_STATUS_MORE = 1, +- DPRC_ITER_STATUS_LAST = 2 +-}; +- -/** - * struct dprc_res_ids_range_desc - Resource ID range descriptor - * @base_id: Base resource ID of this range @@ -11033,13 +18357,37 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - char *type, - struct dprc_res_ids_range_desc *range_desc); - - /* Region flags */ - /* Cacheable - Indicates that region should be mapped as cacheable */ - #define DPRC_REGION_CACHEABLE 0x00000001 -@@ -481,64 +290,27 @@ struct dprc_region_desc { - enum dprc_region_type type; - }; - +-/* Region flags */ +-/* Cacheable - Indicates that region should be mapped as cacheable */ +-#define DPRC_REGION_CACHEABLE 0x00000001 +- +-/** +- * enum dprc_region_type - Region type +- * @DPRC_REGION_TYPE_MC_PORTAL: MC portal region +- * @DPRC_REGION_TYPE_QBMAN_PORTAL: Qbman portal region +- */ +-enum dprc_region_type { +- DPRC_REGION_TYPE_MC_PORTAL, +- DPRC_REGION_TYPE_QBMAN_PORTAL +-}; +- +-/** +- * struct dprc_region_desc - Mappable region descriptor +- * @base_offset: Region offset from region's base address. +- * For DPMCP and DPRC objects, region base is offset from SoC MC portals +- * base address; For DPIO, region base is offset from SoC QMan portals +- * base address +- * @size: Region size (in bytes) +- * @flags: Region attributes +- * @type: Portal region type +- */ +-struct dprc_region_desc { +- u32 base_offset; +- u32 size; +- u32 flags; +- enum dprc_region_type type; +-}; +- -int dprc_get_obj_region(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, @@ -11054,14 +18402,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - char *obj_type, - int obj_id, - char *label); -+int dprc_get_obj_region(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ char *obj_type, -+ int obj_id, -+ u8 region_index, -+ struct dprc_region_desc *region_desc); - +- -/** - * struct dprc_endpoint - Endpoint description for link connect/disconnect - * operations @@ -11075,11 +18416,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - int id; - int if_id; -}; -+int dprc_get_api_version(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 *major_ver, -+ u16 *minor_ver); - +- -/** - * struct dprc_connection_cfg - Connection configuration. - * Used for virtual connections only @@ -11090,10 +18427,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - u32 committed_rate; - u32 max_rate; -}; -+int dprc_get_container_id(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ int *container_id); - +- -int dprc_connect(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, @@ -11112,102 +18446,818 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> - const struct dprc_endpoint *endpoint1, - struct dprc_endpoint *endpoint2, - int *state); -+int dprc_reset_container(struct fsl_mc_io *mc_io, -+ u32 cmd_flags, -+ u16 token, -+ int child_container_id); - - #endif /* _FSL_DPRC_H */ - +- +-#endif /* _FSL_DPRC_H */ +- --- a/drivers/staging/fsl-mc/include/mc-bus.h -+++ b/drivers/staging/fsl-mc/include/mc-bus.h -@@ -1,7 +1,7 @@ - /* - * Freescale Management Complex (MC) bus declarations - * ++++ /dev/null +@@ -1,111 +0,0 @@ +-/* +- * Freescale Management Complex (MC) bus declarations +- * - * Copyright (C) 2014 Freescale Semiconductor, Inc. -+ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. - * Author: German Rivera <German.Rivera@freescale.com> - * - * This file is licensed under the terms of the GNU General Public -@@ -42,8 +42,8 @@ struct msi_domain_info; - */ - struct fsl_mc_resource_pool { - enum fsl_mc_pool_type type; +- * Author: German Rivera <German.Rivera@freescale.com> +- * +- * 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. +- */ +-#ifndef _FSL_MC_MCBUS_H_ +-#define _FSL_MC_MCBUS_H_ +- +-#include "../include/mc.h" +-#include <linux/mutex.h> +- +-struct irq_domain; +-struct msi_domain_info; +- +-/** +- * Maximum number of total IRQs that can be pre-allocated for an MC bus' +- * IRQ pool +- */ +-#define FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS 256 +- +-#ifdef CONFIG_FSL_MC_BUS +-#define dev_is_fsl_mc(_dev) ((_dev)->bus == &fsl_mc_bus_type) +-#else +-/* If fsl-mc bus is not present device cannot belong to fsl-mc bus */ +-#define dev_is_fsl_mc(_dev) (0) +-#endif +- +-/** +- * struct fsl_mc_resource_pool - Pool of MC resources of a given +- * type +- * @type: type of resources in the pool +- * @max_count: maximum number of resources in the pool +- * @free_count: number of free resources in the pool +- * @mutex: mutex to serialize access to the pool's free list +- * @free_list: anchor node of list of free resources in the pool +- * @mc_bus: pointer to the MC bus that owns this resource pool +- */ +-struct fsl_mc_resource_pool { +- enum fsl_mc_pool_type type; - int16_t max_count; - int16_t free_count; -+ int max_count; -+ int free_count; - struct mutex mutex; /* serializes access to free_list */ - struct list_head free_list; - struct fsl_mc_bus *mc_bus; -@@ -73,6 +73,7 @@ struct fsl_mc_bus { - int dprc_scan_container(struct fsl_mc_device *mc_bus_dev); - - int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev, -+ const char *driver_override, - unsigned int *total_irq_count); - - int __init dprc_driver_init(void); +- struct mutex mutex; /* serializes access to free_list */ +- struct list_head free_list; +- struct fsl_mc_bus *mc_bus; +-}; +- +-/** +- * struct fsl_mc_bus - logical bus that corresponds to a physical DPRC +- * @mc_dev: fsl-mc device for the bus device itself. +- * @resource_pools: array of resource pools (one pool per resource type) +- * for this MC bus. These resources represent allocatable entities +- * from the physical DPRC. +- * @irq_resources: Pointer to array of IRQ objects for the IRQ pool +- * @scan_mutex: Serializes bus scanning +- * @dprc_attr: DPRC attributes +- */ +-struct fsl_mc_bus { +- struct fsl_mc_device mc_dev; +- struct fsl_mc_resource_pool resource_pools[FSL_MC_NUM_POOL_TYPES]; +- struct fsl_mc_device_irq *irq_resources; +- struct mutex scan_mutex; /* serializes bus scanning */ +- struct dprc_attributes dprc_attr; +-}; +- +-#define to_fsl_mc_bus(_mc_dev) \ +- container_of(_mc_dev, struct fsl_mc_bus, mc_dev) +- +-int dprc_scan_container(struct fsl_mc_device *mc_bus_dev); +- +-int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev, +- unsigned int *total_irq_count); +- +-int __init dprc_driver_init(void); +- +-void dprc_driver_exit(void); +- +-int __init fsl_mc_allocator_driver_init(void); +- +-void fsl_mc_allocator_driver_exit(void); +- +-struct irq_domain *fsl_mc_msi_create_irq_domain(struct fwnode_handle *fwnode, +- struct msi_domain_info *info, +- struct irq_domain *parent); +- +-int fsl_mc_find_msi_domain(struct device *mc_platform_dev, +- struct irq_domain **mc_msi_domain); +- +-int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus, +- unsigned int irq_count); +- +-void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus); +- +-void fsl_mc_init_all_resource_pools(struct fsl_mc_device *mc_bus_dev); +- +-void fsl_mc_cleanup_all_resource_pools(struct fsl_mc_device *mc_bus_dev); +- +-bool fsl_mc_bus_exists(void); +- +-void fsl_mc_get_root_dprc(struct device *dev, +- struct device **root_dprc_dev); +- +-bool fsl_mc_is_root_dprc(struct device *dev); +- +-extern struct bus_type fsl_mc_bus_type; +- +-#endif /* _FSL_MC_MCBUS_H_ */ --- a/drivers/staging/fsl-mc/include/mc-cmd.h -+++ b/drivers/staging/fsl-mc/include/mc-cmd.h -@@ -1,4 +1,5 @@ ++++ /dev/null +@@ -1,108 +0,0 @@ -/* Copyright 2013-2015 Freescale Semiconductor Inc. -+/* -+ * Copyright 2013-2016 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: -@@ -48,6 +49,15 @@ struct mc_command { - u64 params[MC_CMD_NUM_OF_PARAMS]; - }; - -+struct mc_rsp_create { -+ __le32 object_id; -+}; -+ -+struct mc_rsp_api_ver { -+ __le16 major_ver; -+ __le16 minor_ver; -+}; -+ - enum mc_cmd_status { - MC_CMD_STATUS_OK = 0x0, /* Completed successfully */ - MC_CMD_STATUS_READY = 0x1, /* Ready to be processed */ -@@ -72,11 +82,6 @@ enum mc_cmd_status { - /* Command completion flag */ - #define MC_CMD_FLAG_INTR_DIS 0x01 - +- * +- * 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 the above-listed copyright holders nor the +- * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. +- */ +-#ifndef __FSL_MC_CMD_H +-#define __FSL_MC_CMD_H +- +-#define MC_CMD_NUM_OF_PARAMS 7 +- +-struct mc_cmd_header { +- u8 src_id; +- u8 flags_hw; +- u8 status; +- u8 flags_sw; +- __le16 token; +- __le16 cmd_id; +-}; +- +-struct mc_command { +- u64 header; +- u64 params[MC_CMD_NUM_OF_PARAMS]; +-}; +- +-enum mc_cmd_status { +- MC_CMD_STATUS_OK = 0x0, /* Completed successfully */ +- MC_CMD_STATUS_READY = 0x1, /* Ready to be processed */ +- MC_CMD_STATUS_AUTH_ERR = 0x3, /* Authentication error */ +- MC_CMD_STATUS_NO_PRIVILEGE = 0x4, /* No privilege */ +- MC_CMD_STATUS_DMA_ERR = 0x5, /* DMA or I/O error */ +- MC_CMD_STATUS_CONFIG_ERR = 0x6, /* Configuration error */ +- MC_CMD_STATUS_TIMEOUT = 0x7, /* Operation timed out */ +- MC_CMD_STATUS_NO_RESOURCE = 0x8, /* No resources */ +- MC_CMD_STATUS_NO_MEMORY = 0x9, /* No memory available */ +- MC_CMD_STATUS_BUSY = 0xA, /* Device is busy */ +- MC_CMD_STATUS_UNSUPPORTED_OP = 0xB, /* Unsupported operation */ +- MC_CMD_STATUS_INVALID_STATE = 0xC /* Invalid state */ +-}; +- +-/* +- * MC command flags +- */ +- +-/* High priority flag */ +-#define MC_CMD_FLAG_PRI 0x80 +-/* Command completion flag */ +-#define MC_CMD_FLAG_INTR_DIS 0x01 +- -#define MC_CMD_HDR_CMDID_MASK 0xFFF0 -#define MC_CMD_HDR_CMDID_SHIFT 4 -#define MC_CMD_HDR_TOKEN_MASK 0xFFC0 -#define MC_CMD_HDR_TOKEN_SHIFT 6 - - static inline u64 mc_encode_cmd_header(u16 cmd_id, - u32 cmd_flags, - u16 token) -@@ -84,10 +89,8 @@ static inline u64 mc_encode_cmd_header(u - u64 header = 0; - struct mc_cmd_header *hdr = (struct mc_cmd_header *)&header; - +-static inline u64 mc_encode_cmd_header(u16 cmd_id, +- u32 cmd_flags, +- u16 token) +-{ +- u64 header = 0; +- struct mc_cmd_header *hdr = (struct mc_cmd_header *)&header; +- - hdr->cmd_id = cpu_to_le16((cmd_id << MC_CMD_HDR_CMDID_SHIFT) & - MC_CMD_HDR_CMDID_MASK); - hdr->token = cpu_to_le16((token << MC_CMD_HDR_TOKEN_SHIFT) & - MC_CMD_HDR_TOKEN_MASK); +- hdr->status = MC_CMD_STATUS_READY; +- if (cmd_flags & MC_CMD_FLAG_PRI) +- hdr->flags_hw = MC_CMD_FLAG_PRI; +- if (cmd_flags & MC_CMD_FLAG_INTR_DIS) +- hdr->flags_sw = MC_CMD_FLAG_INTR_DIS; +- +- return header; +-} +- +-static inline u16 mc_cmd_hdr_read_token(struct mc_command *cmd) +-{ +- struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header; +- u16 token = le16_to_cpu(hdr->token); +- +- return (token & MC_CMD_HDR_TOKEN_MASK) >> MC_CMD_HDR_TOKEN_SHIFT; +-} +- +-#endif /* __FSL_MC_CMD_H */ +--- a/drivers/staging/fsl-mc/include/mc-sys.h ++++ /dev/null +@@ -1,98 +0,0 @@ +-/* Copyright 2013-2014 Freescale Semiconductor Inc. +- * +- * Interface of the I/O services to send MC commands to the MC hardware +- * +- * 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 the above-listed copyright holders nor the +- * names of any 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. +- */ +- +-#ifndef _FSL_MC_SYS_H +-#define _FSL_MC_SYS_H +- +-#include <linux/types.h> +-#include <linux/errno.h> +-#include <linux/mutex.h> +-#include <linux/spinlock.h> +- +-/** +- * Bit masks for a MC I/O object (struct fsl_mc_io) flags +- */ +-#define FSL_MC_IO_ATOMIC_CONTEXT_PORTAL 0x0001 +- +-struct fsl_mc_resource; +-struct mc_command; +- +-/** +- * struct fsl_mc_io - MC I/O object to be passed-in to mc_send_command() +- * @dev: device associated with this Mc I/O object +- * @flags: flags for mc_send_command() +- * @portal_size: MC command portal size in bytes +- * @portal_phys_addr: MC command portal physical address +- * @portal_virt_addr: MC command portal virtual address +- * @dpmcp_dev: pointer to the DPMCP device associated with the MC portal. +- * +- * Fields are only meaningful if the FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag is not +- * set: +- * @mutex: Mutex to serialize mc_send_command() calls that use the same MC +- * portal, if the fsl_mc_io object was created with the +- * FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag off. mc_send_command() calls for this +- * fsl_mc_io object must be made only from non-atomic context. +- * +- * Fields are only meaningful if the FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag is +- * set: +- * @spinlock: Spinlock to serialize mc_send_command() calls that use the same MC +- * portal, if the fsl_mc_io object was created with the +- * FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag on. mc_send_command() calls for this +- * fsl_mc_io object can be made from atomic or non-atomic context. +- */ +-struct fsl_mc_io { +- struct device *dev; +- u16 flags; +- u16 portal_size; +- phys_addr_t portal_phys_addr; +- void __iomem *portal_virt_addr; +- struct fsl_mc_device *dpmcp_dev; +- union { +- /* +- * This field is only meaningful if the +- * FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag is not set +- */ +- struct mutex mutex; /* serializes mc_send_command() */ +- +- /* +- * This field is only meaningful if the +- * FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag is set +- */ +- spinlock_t spinlock; /* serializes mc_send_command() */ +- }; +-}; +- +-int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd); +- +-#endif /* _FSL_MC_SYS_H */ +--- a/drivers/staging/fsl-mc/include/mc.h ++++ /dev/null +@@ -1,201 +0,0 @@ +-/* +- * Freescale Management Complex (MC) bus public interface +- * +- * Copyright (C) 2014 Freescale Semiconductor, Inc. +- * Author: German Rivera <German.Rivera@freescale.com> +- * +- * 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. +- */ +-#ifndef _FSL_MC_H_ +-#define _FSL_MC_H_ +- +-#include <linux/device.h> +-#include <linux/mod_devicetable.h> +-#include <linux/interrupt.h> +-#include "../include/dprc.h" +- +-#define FSL_MC_VENDOR_FREESCALE 0x1957 +- +-struct fsl_mc_device; +-struct fsl_mc_io; +- +-/** +- * struct fsl_mc_driver - MC object device driver object +- * @driver: Generic device driver +- * @match_id_table: table of supported device matching Ids +- * @probe: Function called when a device is added +- * @remove: Function called when a device is removed +- * @shutdown: Function called at shutdown time to quiesce the device +- * @suspend: Function called when a device is stopped +- * @resume: Function called when a device is resumed +- * +- * Generic DPAA device driver object for device drivers that are registered +- * with a DPRC bus. This structure is to be embedded in each device-specific +- * driver structure. +- */ +-struct fsl_mc_driver { +- struct device_driver driver; +- const struct fsl_mc_device_id *match_id_table; +- int (*probe)(struct fsl_mc_device *dev); +- int (*remove)(struct fsl_mc_device *dev); +- void (*shutdown)(struct fsl_mc_device *dev); +- int (*suspend)(struct fsl_mc_device *dev, pm_message_t state); +- int (*resume)(struct fsl_mc_device *dev); +-}; +- +-#define to_fsl_mc_driver(_drv) \ +- container_of(_drv, struct fsl_mc_driver, driver) +- +-/** +- * enum fsl_mc_pool_type - Types of allocatable MC bus resources +- * +- * Entries in these enum are used as indices in the array of resource +- * pools of an fsl_mc_bus object. +- */ +-enum fsl_mc_pool_type { +- FSL_MC_POOL_DPMCP = 0x0, /* corresponds to "dpmcp" in the MC */ +- FSL_MC_POOL_DPBP, /* corresponds to "dpbp" in the MC */ +- FSL_MC_POOL_DPCON, /* corresponds to "dpcon" in the MC */ +- FSL_MC_POOL_IRQ, +- +- /* +- * NOTE: New resource pool types must be added before this entry +- */ +- FSL_MC_NUM_POOL_TYPES +-}; +- +-/** +- * struct fsl_mc_resource - MC generic resource +- * @type: type of resource +- * @id: unique MC resource Id within the resources of the same type +- * @data: pointer to resource-specific data if the resource is currently +- * allocated, or NULL if the resource is not currently allocated. +- * @parent_pool: pointer to the parent resource pool from which this +- * resource is allocated from. +- * @node: Node in the free list of the corresponding resource pool +- * +- * NOTE: This structure is to be embedded as a field of specific +- * MC resource structures. +- */ +-struct fsl_mc_resource { +- enum fsl_mc_pool_type type; +- int32_t id; +- void *data; +- struct fsl_mc_resource_pool *parent_pool; +- struct list_head node; +-}; +- +-/** +- * struct fsl_mc_device_irq - MC object device message-based interrupt +- * @msi_desc: pointer to MSI descriptor allocated by fsl_mc_msi_alloc_descs() +- * @mc_dev: MC object device that owns this interrupt +- * @dev_irq_index: device-relative IRQ index +- * @resource: MC generic resource associated with the interrupt +- */ +-struct fsl_mc_device_irq { +- struct msi_desc *msi_desc; +- struct fsl_mc_device *mc_dev; +- u8 dev_irq_index; +- struct fsl_mc_resource resource; +-}; +- +-#define to_fsl_mc_irq(_mc_resource) \ +- container_of(_mc_resource, struct fsl_mc_device_irq, resource) +- +-/** +- * Bit masks for a MC object device (struct fsl_mc_device) flags +- */ +-#define FSL_MC_IS_DPRC 0x0001 +- +-/** +- * struct fsl_mc_device - MC object device object +- * @dev: Linux driver model device object +- * @dma_mask: Default DMA mask +- * @flags: MC object device flags +- * @icid: Isolation context ID for the device +- * @mc_handle: MC handle for the corresponding MC object opened +- * @mc_io: Pointer to MC IO object assigned to this device or +- * NULL if none. +- * @obj_desc: MC description of the DPAA device +- * @regions: pointer to array of MMIO region entries +- * @irqs: pointer to array of pointers to interrupts allocated to this device +- * @resource: generic resource associated with this MC object device, if any. +- * +- * Generic device object for MC object devices that are "attached" to a +- * MC bus. +- * +- * NOTES: +- * - For a non-DPRC object its icid is the same as its parent DPRC's icid. +- * - The SMMU notifier callback gets invoked after device_add() has been +- * called for an MC object device, but before the device-specific probe +- * callback gets called. +- * - DP_OBJ_DPRC objects are the only MC objects that have built-in MC +- * portals. For all other MC objects, their device drivers are responsible for +- * allocating MC portals for them by calling fsl_mc_portal_allocate(). +- * - Some types of MC objects (e.g., DP_OBJ_DPBP, DP_OBJ_DPCON) are +- * treated as resources that can be allocated/deallocated from the +- * corresponding resource pool in the object's parent DPRC, using the +- * fsl_mc_object_allocate()/fsl_mc_object_free() functions. These MC objects +- * are known as "allocatable" objects. For them, the corresponding +- * fsl_mc_device's 'resource' points to the associated resource object. +- * For MC objects that are not allocatable (e.g., DP_OBJ_DPRC, DP_OBJ_DPNI), +- * 'resource' is NULL. +- */ +-struct fsl_mc_device { +- struct device dev; +- u64 dma_mask; +- u16 flags; +- u16 icid; +- u16 mc_handle; +- struct fsl_mc_io *mc_io; +- struct dprc_obj_desc obj_desc; +- struct resource *regions; +- struct fsl_mc_device_irq **irqs; +- struct fsl_mc_resource *resource; +-}; +- +-#define to_fsl_mc_device(_dev) \ +- container_of(_dev, struct fsl_mc_device, dev) +- +-/* +- * module_fsl_mc_driver() - Helper macro for drivers that don't do +- * anything special in module init/exit. This eliminates a lot of +- * boilerplate. Each module may only use this macro once, and +- * calling it replaces module_init() and module_exit() +- */ +-#define module_fsl_mc_driver(__fsl_mc_driver) \ +- module_driver(__fsl_mc_driver, fsl_mc_driver_register, \ +- fsl_mc_driver_unregister) +- +-/* +- * Macro to avoid include chaining to get THIS_MODULE +- */ +-#define fsl_mc_driver_register(drv) \ +- __fsl_mc_driver_register(drv, THIS_MODULE) +- +-int __must_check __fsl_mc_driver_register(struct fsl_mc_driver *fsl_mc_driver, +- struct module *owner); +- +-void fsl_mc_driver_unregister(struct fsl_mc_driver *driver); +- +-int __must_check fsl_mc_portal_allocate(struct fsl_mc_device *mc_dev, +- u16 mc_io_flags, +- struct fsl_mc_io **new_mc_io); +- +-void fsl_mc_portal_free(struct fsl_mc_io *mc_io); +- +-int fsl_mc_portal_reset(struct fsl_mc_io *mc_io); +- +-int __must_check fsl_mc_object_allocate(struct fsl_mc_device *mc_dev, +- enum fsl_mc_pool_type pool_type, +- struct fsl_mc_device **new_mc_adev); +- +-void fsl_mc_object_free(struct fsl_mc_device *mc_adev); +- +-int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev); +- +-void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev); +- +-#endif /* _FSL_MC_H_ */ +--- /dev/null ++++ b/include/linux/fsl/mc.h +@@ -0,0 +1,1025 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Freescale Management Complex (MC) bus public interface ++ * ++ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. ++ * Author: German Rivera <German.Rivera@freescale.com> ++ * ++ */ ++#ifndef _FSL_MC_H_ ++#define _FSL_MC_H_ ++ ++#include <linux/device.h> ++#include <linux/mod_devicetable.h> ++#include <linux/interrupt.h> ++#include <linux/cdev.h> ++#include <uapi/linux/fsl_mc.h> ++ ++#define FSL_MC_VENDOR_FREESCALE 0x1957 ++ ++struct irq_domain; ++struct msi_domain_info; ++ ++struct fsl_mc_device; ++struct fsl_mc_io; ++ ++/** ++ * struct fsl_mc_driver - MC object device driver object ++ * @driver: Generic device driver ++ * @match_id_table: table of supported device matching Ids ++ * @probe: Function called when a device is added ++ * @remove: Function called when a device is removed ++ * @shutdown: Function called at shutdown time to quiesce the device ++ * @suspend: Function called when a device is stopped ++ * @resume: Function called when a device is resumed ++ * ++ * Generic DPAA device driver object for device drivers that are registered ++ * with a DPRC bus. This structure is to be embedded in each device-specific ++ * driver structure. ++ */ ++struct fsl_mc_driver { ++ struct device_driver driver; ++ const struct fsl_mc_device_id *match_id_table; ++ int (*probe)(struct fsl_mc_device *dev); ++ int (*remove)(struct fsl_mc_device *dev); ++ void (*shutdown)(struct fsl_mc_device *dev); ++ int (*suspend)(struct fsl_mc_device *dev, pm_message_t state); ++ int (*resume)(struct fsl_mc_device *dev); ++}; ++ ++#define to_fsl_mc_driver(_drv) \ ++ container_of(_drv, struct fsl_mc_driver, driver) ++ ++#define to_fsl_mc_bus(_mc_dev) \ ++ container_of(_mc_dev, struct fsl_mc_bus, mc_dev) ++ ++/** ++ * enum fsl_mc_pool_type - Types of allocatable MC bus resources ++ * ++ * Entries in these enum are used as indices in the array of resource ++ * pools of an fsl_mc_bus object. ++ */ ++enum fsl_mc_pool_type { ++ FSL_MC_POOL_DPMCP = 0x0, /* corresponds to "dpmcp" in the MC */ ++ FSL_MC_POOL_DPBP, /* corresponds to "dpbp" in the MC */ ++ FSL_MC_POOL_DPCON, /* corresponds to "dpcon" in the MC */ ++ FSL_MC_POOL_IRQ, ++ ++ /* ++ * NOTE: New resource pool types must be added before this entry ++ */ ++ FSL_MC_NUM_POOL_TYPES ++}; ++ ++/** ++ * struct fsl_mc_resource - MC generic resource ++ * @type: type of resource ++ * @id: unique MC resource Id within the resources of the same type ++ * @data: pointer to resource-specific data if the resource is currently ++ * allocated, or NULL if the resource is not currently allocated. ++ * @parent_pool: pointer to the parent resource pool from which this ++ * resource is allocated from. ++ * @node: Node in the free list of the corresponding resource pool ++ * ++ * NOTE: This structure is to be embedded as a field of specific ++ * MC resource structures. ++ */ ++struct fsl_mc_resource { ++ enum fsl_mc_pool_type type; ++ s32 id; ++ void *data; ++ struct fsl_mc_resource_pool *parent_pool; ++ struct list_head node; ++}; ++ ++/** ++ * struct fsl_mc_device_irq - MC object device message-based interrupt ++ * @msi_desc: pointer to MSI descriptor allocated by fsl_mc_msi_alloc_descs() ++ * @mc_dev: MC object device that owns this interrupt ++ * @dev_irq_index: device-relative IRQ index ++ * @resource: MC generic resource associated with the interrupt ++ */ ++struct fsl_mc_device_irq { ++ struct msi_desc *msi_desc; ++ struct fsl_mc_device *mc_dev; ++ u8 dev_irq_index; ++ struct fsl_mc_resource resource; ++}; ++ ++#define to_fsl_mc_irq(_mc_resource) \ ++ container_of(_mc_resource, struct fsl_mc_device_irq, resource) ++ ++/* Opened state - Indicates that an object is open by at least one owner */ ++#define FSL_MC_OBJ_STATE_OPEN 0x00000001 ++/* Plugged state - Indicates that the object is plugged */ ++#define FSL_MC_OBJ_STATE_PLUGGED 0x00000002 ++ ++/** ++ * Shareability flag - Object flag indicating no memory shareability. ++ * the object generates memory accesses that are non coherent with other ++ * masters; ++ * user is responsible for proper memory handling through IOMMU configuration. ++ */ ++#define FSL_MC_OBJ_FLAG_NO_MEM_SHAREABILITY 0x0001 ++ ++/** ++ * struct fsl_mc_obj_desc - Object descriptor ++ * @type: Type of object: NULL terminated string ++ * @id: ID of logical object resource ++ * @vendor: Object vendor identifier ++ * @ver_major: Major version number ++ * @ver_minor: Minor version number ++ * @irq_count: Number of interrupts supported by the object ++ * @region_count: Number of mappable regions supported by the object ++ * @state: Object state: combination of FSL_MC_OBJ_STATE_ states ++ * @label: Object label: NULL terminated string ++ * @flags: Object's flags ++ */ ++struct fsl_mc_obj_desc { ++ char type[16]; ++ int id; ++ u16 vendor; ++ u16 ver_major; ++ u16 ver_minor; ++ u8 irq_count; ++ u8 region_count; ++ u32 state; ++ char label[16]; ++ u16 flags; ++}; ++ ++/** ++ * Bit masks for a MC object device (struct fsl_mc_device) flags ++ */ ++#define FSL_MC_IS_DPRC 0x0001 ++ ++/** ++ * struct fsl_mc_device - MC object device object ++ * @dev: Linux driver model device object ++ * @dma_mask: Default DMA mask ++ * @flags: MC object device flags ++ * @icid: Isolation context ID for the device ++ * @mc_handle: MC handle for the corresponding MC object opened ++ * @mc_io: Pointer to MC IO object assigned to this device or ++ * NULL if none. ++ * @obj_desc: MC description of the DPAA device ++ * @regions: pointer to array of MMIO region entries ++ * @irqs: pointer to array of pointers to interrupts allocated to this device ++ * @resource: generic resource associated with this MC object device, if any. ++ * @driver_override: Driver name to force a match ++ * ++ * Generic device object for MC object devices that are "attached" to a ++ * MC bus. ++ * ++ * NOTES: ++ * - For a non-DPRC object its icid is the same as its parent DPRC's icid. ++ * - The SMMU notifier callback gets invoked after device_add() has been ++ * called for an MC object device, but before the device-specific probe ++ * callback gets called. ++ * - DP_OBJ_DPRC objects are the only MC objects that have built-in MC ++ * portals. For all other MC objects, their device drivers are responsible for ++ * allocating MC portals for them by calling fsl_mc_portal_allocate(). ++ * - Some types of MC objects (e.g., DP_OBJ_DPBP, DP_OBJ_DPCON) are ++ * treated as resources that can be allocated/deallocated from the ++ * corresponding resource pool in the object's parent DPRC, using the ++ * fsl_mc_object_allocate()/fsl_mc_object_free() functions. These MC objects ++ * are known as "allocatable" objects. For them, the corresponding ++ * fsl_mc_device's 'resource' points to the associated resource object. ++ * For MC objects that are not allocatable (e.g., DP_OBJ_DPRC, DP_OBJ_DPNI), ++ * 'resource' is NULL. ++ */ ++struct fsl_mc_device { ++ struct device dev; ++ u64 dma_mask; ++ u16 flags; ++ u32 icid; ++ u16 mc_handle; ++ struct fsl_mc_io *mc_io; ++ struct fsl_mc_obj_desc obj_desc; ++ struct resource *regions; ++ struct fsl_mc_device_irq **irqs; ++ struct fsl_mc_resource *resource; ++ const char *driver_override; ++}; ++ ++#define to_fsl_mc_device(_dev) \ ++ container_of(_dev, struct fsl_mc_device, dev) ++ ++struct mc_cmd_header { ++ u8 src_id; ++ u8 flags_hw; ++ u8 status; ++ u8 flags_sw; ++ __le16 token; ++ __le16 cmd_id; ++}; ++ ++enum mc_cmd_status { ++ MC_CMD_STATUS_OK = 0x0, /* Completed successfully */ ++ MC_CMD_STATUS_READY = 0x1, /* Ready to be processed */ ++ MC_CMD_STATUS_AUTH_ERR = 0x3, /* Authentication error */ ++ MC_CMD_STATUS_NO_PRIVILEGE = 0x4, /* No privilege */ ++ MC_CMD_STATUS_DMA_ERR = 0x5, /* DMA or I/O error */ ++ MC_CMD_STATUS_CONFIG_ERR = 0x6, /* Configuration error */ ++ MC_CMD_STATUS_TIMEOUT = 0x7, /* Operation timed out */ ++ MC_CMD_STATUS_NO_RESOURCE = 0x8, /* No resources */ ++ MC_CMD_STATUS_NO_MEMORY = 0x9, /* No memory available */ ++ MC_CMD_STATUS_BUSY = 0xA, /* Device is busy */ ++ MC_CMD_STATUS_UNSUPPORTED_OP = 0xB, /* Unsupported operation */ ++ MC_CMD_STATUS_INVALID_STATE = 0xC /* Invalid state */ ++}; ++ ++/* ++ * MC command flags ++ */ ++ ++/* High priority flag */ ++#define MC_CMD_FLAG_PRI 0x80 ++/* Command completion flag */ ++#define MC_CMD_FLAG_INTR_DIS 0x01 ++ ++static inline u64 mc_encode_cmd_header(u16 cmd_id, ++ u32 cmd_flags, ++ u16 token) ++{ ++ u64 header = 0; ++ struct mc_cmd_header *hdr = (struct mc_cmd_header *)&header; ++ + hdr->cmd_id = cpu_to_le16(cmd_id); + hdr->token = cpu_to_le16(token); - hdr->status = MC_CMD_STATUS_READY; - if (cmd_flags & MC_CMD_FLAG_PRI) - hdr->flags_hw = MC_CMD_FLAG_PRI; -@@ -102,7 +105,26 @@ static inline u16 mc_cmd_hdr_read_token( - struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header; - u16 token = le16_to_cpu(hdr->token); - -- return (token & MC_CMD_HDR_TOKEN_MASK) >> MC_CMD_HDR_TOKEN_SHIFT; ++ hdr->status = MC_CMD_STATUS_READY; ++ if (cmd_flags & MC_CMD_FLAG_PRI) ++ hdr->flags_hw = MC_CMD_FLAG_PRI; ++ if (cmd_flags & MC_CMD_FLAG_INTR_DIS) ++ hdr->flags_sw = MC_CMD_FLAG_INTR_DIS; ++ ++ return header; ++} ++ ++static inline u16 mc_cmd_hdr_read_token(struct fsl_mc_command *cmd) ++{ ++ struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header; ++ u16 token = le16_to_cpu(hdr->token); ++ + return token; +} + -+static inline u32 mc_cmd_read_object_id(struct mc_command *cmd) ++struct mc_rsp_create { ++ __le32 object_id; ++}; ++ ++struct mc_rsp_api_ver { ++ __le16 major_ver; ++ __le16 minor_ver; ++}; ++ ++static inline u32 mc_cmd_read_object_id(struct fsl_mc_command *cmd) +{ + struct mc_rsp_create *rsp_params; + @@ -11215,7 +19265,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + return le32_to_cpu(rsp_params->object_id); +} + -+static inline void mc_cmd_read_api_version(struct mc_command *cmd, ++static inline void mc_cmd_read_api_version(struct fsl_mc_command *cmd, + u16 *major_ver, + u16 *minor_ver) +{ @@ -11224,74 +19274,770 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + rsp_params = (struct mc_rsp_api_ver *)cmd->params; + *major_ver = le16_to_cpu(rsp_params->major_ver); + *minor_ver = le16_to_cpu(rsp_params->minor_ver); - } - - #endif /* __FSL_MC_CMD_H */ ---- a/drivers/staging/fsl-mc/include/mc-sys.h -+++ b/drivers/staging/fsl-mc/include/mc-sys.h -@@ -1,4 +1,5 @@ --/* Copyright 2013-2014 Freescale Semiconductor Inc. ++} ++ ++/** ++ * Bit masks for a MC I/O object (struct fsl_mc_io) flags ++ */ ++#define FSL_MC_IO_ATOMIC_CONTEXT_PORTAL 0x0001 ++ ++/** ++ * struct fsl_mc_io - MC I/O object to be passed-in to mc_send_command() ++ * @dev: device associated with this Mc I/O object ++ * @flags: flags for mc_send_command() ++ * @portal_size: MC command portal size in bytes ++ * @portal_phys_addr: MC command portal physical address ++ * @portal_virt_addr: MC command portal virtual address ++ * @dpmcp_dev: pointer to the DPMCP device associated with the MC portal. ++ * ++ * Fields are only meaningful if the FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag is not ++ * set: ++ * @mutex: Mutex to serialize mc_send_command() calls that use the same MC ++ * portal, if the fsl_mc_io object was created with the ++ * FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag off. mc_send_command() calls for this ++ * fsl_mc_io object must be made only from non-atomic context. ++ * ++ * Fields are only meaningful if the FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag is ++ * set: ++ * @spinlock: Spinlock to serialize mc_send_command() calls that use the same MC ++ * portal, if the fsl_mc_io object was created with the ++ * FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag on. mc_send_command() calls for this ++ * fsl_mc_io object can be made from atomic or non-atomic context. ++ */ ++struct fsl_mc_io { ++ struct device *dev; ++ u16 flags; ++ u32 portal_size; ++ phys_addr_t portal_phys_addr; ++ void __iomem *portal_virt_addr; ++ struct fsl_mc_device *dpmcp_dev; ++ union { ++ /* ++ * This field is only meaningful if the ++ * FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag is not set ++ */ ++ struct mutex mutex; /* serializes mc_send_command() */ ++ ++ /* ++ * This field is only meaningful if the ++ * FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag is set ++ */ ++ spinlock_t spinlock; /* serializes mc_send_command() */ ++ }; ++}; ++ ++int mc_send_command(struct fsl_mc_io *mc_io, struct fsl_mc_command *cmd); ++ ++#ifdef CONFIG_FSL_MC_BUS ++#define dev_is_fsl_mc(_dev) ((_dev)->bus == &fsl_mc_bus_type) ++#else ++/* If fsl-mc bus is not present device cannot belong to fsl-mc bus */ ++#define dev_is_fsl_mc(_dev) (0) ++#endif ++ ++/* Macro to check if a device is a container device */ ++#define fsl_mc_is_cont_dev(_dev) (to_fsl_mc_device(_dev)->flags & \ ++ FSL_MC_IS_DPRC) ++ ++/* Macro to get the container device of a MC device */ ++#define fsl_mc_cont_dev(_dev) (fsl_mc_is_cont_dev(_dev) ? \ ++ (_dev) : (_dev)->parent) ++ ++#define fsl_mc_is_dev_coherent(_dev) \ ++ (!((to_fsl_mc_device(_dev))->obj_desc.flags & \ ++ FSL_MC_OBJ_FLAG_NO_MEM_SHAREABILITY)) ++ +/* -+ * Copyright 2013-2016 Freescale Semiconductor Inc. - * - * Interface of the I/O services to send MC commands to the MC hardware - * ---- a/drivers/staging/fsl-mc/include/mc.h -+++ b/drivers/staging/fsl-mc/include/mc.h -@@ -1,7 +1,7 @@ - /* - * Freescale Management Complex (MC) bus public interface - * -- * Copyright (C) 2014 Freescale Semiconductor, Inc. -+ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. - * Author: German Rivera <German.Rivera@freescale.com> - * - * This file is licensed under the terms of the GNU General Public -@@ -81,7 +81,7 @@ enum fsl_mc_pool_type { - */ - struct fsl_mc_resource { - enum fsl_mc_pool_type type; -- int32_t id; -+ s32 id; - void *data; - struct fsl_mc_resource_pool *parent_pool; - struct list_head node; -@@ -122,6 +122,7 @@ struct fsl_mc_device_irq { - * @regions: pointer to array of MMIO region entries - * @irqs: pointer to array of pointers to interrupts allocated to this device - * @resource: generic resource associated with this MC object device, if any. -+ * @driver_override: Driver name to force a match - * - * Generic device object for MC object devices that are "attached" to a - * MC bus. -@@ -154,6 +155,7 @@ struct fsl_mc_device { - struct resource *regions; - struct fsl_mc_device_irq **irqs; - struct fsl_mc_resource *resource; -+ const char *driver_override; - }; - - #define to_fsl_mc_device(_dev) \ -@@ -175,6 +177,8 @@ struct fsl_mc_device { - #define fsl_mc_driver_register(drv) \ - __fsl_mc_driver_register(drv, THIS_MODULE) - ++ * module_fsl_mc_driver() - Helper macro for drivers that don't do ++ * anything special in module init/exit. This eliminates a lot of ++ * boilerplate. Each module may only use this macro once, and ++ * calling it replaces module_init() and module_exit() ++ */ ++#define module_fsl_mc_driver(__fsl_mc_driver) \ ++ module_driver(__fsl_mc_driver, fsl_mc_driver_register, \ ++ fsl_mc_driver_unregister) ++ +void fsl_mc_device_remove(struct fsl_mc_device *mc_dev); + - int __must_check __fsl_mc_driver_register(struct fsl_mc_driver *fsl_mc_driver, - struct module *owner); - -@@ -198,4 +202,13 @@ int __must_check fsl_mc_allocate_irqs(st - - void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev); - ++/* ++ * Macro to avoid include chaining to get THIS_MODULE ++ */ ++#define fsl_mc_driver_register(drv) \ ++ __fsl_mc_driver_register(drv, THIS_MODULE) ++ ++int __must_check __fsl_mc_driver_register(struct fsl_mc_driver *fsl_mc_driver, ++ struct module *owner); ++ ++void fsl_mc_driver_unregister(struct fsl_mc_driver *driver); ++ ++int __must_check fsl_mc_portal_allocate(struct fsl_mc_device *mc_dev, ++ u16 mc_io_flags, ++ struct fsl_mc_io **new_mc_io); ++ ++void fsl_mc_portal_free(struct fsl_mc_io *mc_io); ++ ++int fsl_mc_portal_reset(struct fsl_mc_io *mc_io); ++ ++int __must_check fsl_mc_object_allocate(struct fsl_mc_device *mc_dev, ++ enum fsl_mc_pool_type pool_type, ++ struct fsl_mc_device **new_mc_adev); ++ ++void fsl_mc_object_free(struct fsl_mc_device *mc_adev); ++ ++struct irq_domain *fsl_mc_msi_create_irq_domain(struct fwnode_handle *fwnode, ++ struct msi_domain_info *info, ++ struct irq_domain *parent); ++ ++int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev); ++ ++void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev); ++ +void fsl_mc_dma_configure(struct fsl_mc_device *mc_dev, + struct device_node *fsl_mc_platform_node, int coherent); + -+#ifdef CONFIG_FSL_MC_BUS -+struct iommu_group *fsl_mc_device_group(struct device *dev); -+#else -+#define fsl_mc_device_group(__dev) NULL -+#endif ++extern struct bus_type fsl_mc_bus_type; ++ ++extern struct device_type fsl_mc_bus_dprc_type; ++extern struct device_type fsl_mc_bus_dpni_type; ++extern struct device_type fsl_mc_bus_dpio_type; ++extern struct device_type fsl_mc_bus_dpsw_type; ++extern struct device_type fsl_mc_bus_dpdmux_type; ++extern struct device_type fsl_mc_bus_dpbp_type; ++extern struct device_type fsl_mc_bus_dpcon_type; ++extern struct device_type fsl_mc_bus_dpmcp_type; ++extern struct device_type fsl_mc_bus_dpmac_type; ++extern struct device_type fsl_mc_bus_dprtc_type; ++extern struct device_type fsl_mc_bus_dpseci_type; ++extern struct device_type fsl_mc_bus_dpdcei_type; ++extern struct device_type fsl_mc_bus_dpaiop_type; ++extern struct device_type fsl_mc_bus_dpci_type; ++extern struct device_type fsl_mc_bus_dpdmai_type; ++ ++static inline bool is_fsl_mc_bus_dprc(const struct fsl_mc_device *mc_dev) ++{ ++ return mc_dev->dev.type == &fsl_mc_bus_dprc_type; ++} ++ ++static inline bool is_fsl_mc_bus_dpni(const struct fsl_mc_device *mc_dev) ++{ ++ return mc_dev->dev.type == &fsl_mc_bus_dpni_type; ++} ++ ++static inline bool is_fsl_mc_bus_dpio(const struct fsl_mc_device *mc_dev) ++{ ++ return mc_dev->dev.type == &fsl_mc_bus_dpio_type; ++} ++ ++static inline bool is_fsl_mc_bus_dpsw(const struct fsl_mc_device *mc_dev) ++{ ++ return mc_dev->dev.type == &fsl_mc_bus_dpsw_type; ++} ++ ++static inline bool is_fsl_mc_bus_dpdmux(const struct fsl_mc_device *mc_dev) ++{ ++ return mc_dev->dev.type == &fsl_mc_bus_dpdmux_type; ++} ++ ++static inline bool is_fsl_mc_bus_dpbp(const struct fsl_mc_device *mc_dev) ++{ ++ return mc_dev->dev.type == &fsl_mc_bus_dpbp_type; ++} ++ ++static inline bool is_fsl_mc_bus_dpcon(const struct fsl_mc_device *mc_dev) ++{ ++ return mc_dev->dev.type == &fsl_mc_bus_dpcon_type; ++} ++ ++static inline bool is_fsl_mc_bus_dpmcp(const struct fsl_mc_device *mc_dev) ++{ ++ return mc_dev->dev.type == &fsl_mc_bus_dpmcp_type; ++} ++ ++static inline bool is_fsl_mc_bus_dpmac(const struct fsl_mc_device *mc_dev) ++{ ++ return mc_dev->dev.type == &fsl_mc_bus_dpmac_type; ++} ++ ++static inline bool is_fsl_mc_bus_dprtc(const struct fsl_mc_device *mc_dev) ++{ ++ return mc_dev->dev.type == &fsl_mc_bus_dprtc_type; ++} ++ ++static inline bool is_fsl_mc_bus_dpseci(const struct fsl_mc_device *mc_dev) ++{ ++ return mc_dev->dev.type == &fsl_mc_bus_dpseci_type; ++} ++ ++static inline bool is_fsl_mc_bus_dpdcei(const struct fsl_mc_device *mc_dev) ++{ ++ return mc_dev->dev.type == &fsl_mc_bus_dpdcei_type; ++} ++ ++static inline bool is_fsl_mc_bus_dpaiop(const struct fsl_mc_device *mc_dev) ++{ ++ return mc_dev->dev.type == &fsl_mc_bus_dpaiop_type; ++} ++ ++static inline bool is_fsl_mc_bus_dpci(const struct fsl_mc_device *mc_dev) ++{ ++ return mc_dev->dev.type == &fsl_mc_bus_dpci_type; ++} ++ ++static inline bool is_fsl_mc_bus_dpdmai(const struct fsl_mc_device *mc_dev) ++{ ++ return mc_dev->dev.type == &fsl_mc_bus_dpdmai_type; ++} ++ ++/* ++ * Data Path Resource Container (DPRC) API ++ */ ++ ++/* Minimal supported DPRC Version */ ++#define DPRC_MIN_VER_MAJOR 6 ++#define DPRC_MIN_VER_MINOR 0 ++ ++/* DPRC command versioning */ ++#define DPRC_CMD_BASE_VERSION 1 ++#define DPRC_CMD_ID_OFFSET 4 ++ ++#define DPRC_CMD(id) (((id) << DPRC_CMD_ID_OFFSET) | DPRC_CMD_BASE_VERSION) ++ ++/* DPRC command IDs */ ++#define DPRC_CMDID_CLOSE DPRC_CMD(0x800) ++#define DPRC_CMDID_OPEN DPRC_CMD(0x805) ++#define DPRC_CMDID_GET_API_VERSION DPRC_CMD(0xa05) ++ ++#define DPRC_CMDID_GET_ATTR DPRC_CMD(0x004) ++#define DPRC_CMDID_RESET_CONT DPRC_CMD(0x005) ++ ++#define DPRC_CMDID_SET_IRQ DPRC_CMD(0x010) ++#define DPRC_CMDID_SET_IRQ_ENABLE DPRC_CMD(0x012) ++#define DPRC_CMDID_SET_IRQ_MASK DPRC_CMD(0x014) ++#define DPRC_CMDID_GET_IRQ_STATUS DPRC_CMD(0x016) ++#define DPRC_CMDID_CLEAR_IRQ_STATUS DPRC_CMD(0x017) ++ ++#define DPRC_CMDID_GET_CONT_ID DPRC_CMD(0x830) ++#define DPRC_CMDID_GET_OBJ_COUNT DPRC_CMD(0x159) ++#define DPRC_CMDID_GET_OBJ DPRC_CMD(0x15A) ++#define DPRC_CMDID_GET_OBJ_REG DPRC_CMD(0x15E) ++#define DPRC_CMDID_SET_OBJ_IRQ DPRC_CMD(0x15F) ++ ++struct dprc_cmd_open { ++ __le32 container_id; ++}; ++ ++struct dprc_cmd_reset_container { ++ __le32 child_container_id; ++}; ++ ++struct dprc_cmd_set_irq { ++ /* cmd word 0 */ ++ __le32 irq_val; ++ u8 irq_index; ++ u8 pad[3]; ++ /* cmd word 1 */ ++ __le64 irq_addr; ++ /* cmd word 2 */ ++ __le32 irq_num; ++}; ++ ++#define DPRC_ENABLE 0x1 ++ ++struct dprc_cmd_set_irq_enable { ++ u8 enable; ++ u8 pad[3]; ++ u8 irq_index; ++}; ++ ++struct dprc_cmd_set_irq_mask { ++ __le32 mask; ++ u8 irq_index; ++}; ++ ++struct dprc_cmd_get_irq_status { ++ __le32 status; ++ u8 irq_index; ++}; ++ ++struct dprc_rsp_get_irq_status { ++ __le32 status; ++}; ++ ++struct dprc_cmd_clear_irq_status { ++ __le32 status; ++ u8 irq_index; ++}; ++ ++struct dprc_rsp_get_attributes { ++ /* response word 0 */ ++ __le32 container_id; ++ __le32 icid; ++ /* response word 1 */ ++ __le32 options; ++ __le32 portal_id; ++}; ++ ++struct dprc_rsp_get_obj_count { ++ __le32 pad; ++ __le32 obj_count; ++}; ++ ++struct dprc_cmd_get_obj { ++ __le32 obj_index; ++}; ++ ++struct dprc_rsp_get_obj { ++ /* response word 0 */ ++ __le32 pad0; ++ __le32 id; ++ /* response word 1 */ ++ __le16 vendor; ++ u8 irq_count; ++ u8 region_count; ++ __le32 state; ++ /* response word 2 */ ++ __le16 version_major; ++ __le16 version_minor; ++ __le16 flags; ++ __le16 pad1; ++ /* response word 3-4 */ ++ u8 type[16]; ++ /* response word 5-6 */ ++ u8 label[16]; ++}; ++ ++struct dprc_cmd_get_obj_region { ++ /* cmd word 0 */ ++ __le32 obj_id; ++ __le16 pad0; ++ u8 region_index; ++ u8 pad1; ++ /* cmd word 1-2 */ ++ __le64 pad2[2]; ++ /* cmd word 3-4 */ ++ u8 obj_type[16]; ++}; ++ ++struct dprc_rsp_get_obj_region { ++ /* response word 0 */ ++ __le64 pad0; ++ /* response word 1 */ ++ __le32 base_addr; ++ __le32 pad1; ++ /* response word 2 */ ++ __le32 size; ++ u8 type; ++ u8 pad2[3]; ++ /* response word 3 */ ++ __le32 flags; ++}; ++ ++struct dprc_cmd_set_obj_irq { ++ /* cmd word 0 */ ++ __le32 irq_val; ++ u8 irq_index; ++ u8 pad[3]; ++ /* cmd word 1 */ ++ __le64 irq_addr; ++ /* cmd word 2 */ ++ __le32 irq_num; ++ __le32 obj_id; ++ /* cmd word 3-4 */ ++ u8 obj_type[16]; ++}; ++ ++/* ++ * DPRC API for managing and querying DPAA resources ++ */ ++int dprc_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int container_id, ++ u16 *token); ++ ++int dprc_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++/* DPRC IRQ events */ ++ ++/* IRQ event - Indicates that a new object added to the container */ ++#define DPRC_IRQ_EVENT_OBJ_ADDED 0x00000001 ++/* IRQ event - Indicates that an object was removed from the container */ ++#define DPRC_IRQ_EVENT_OBJ_REMOVED 0x00000002 ++/* ++ * IRQ event - Indicates that one of the descendant containers that opened by ++ * this container is destroyed ++ */ ++#define DPRC_IRQ_EVENT_CONTAINER_DESTROYED 0x00000010 ++ ++/* ++ * IRQ event - Indicates that on one of the container's opened object is ++ * destroyed ++ */ ++#define DPRC_IRQ_EVENT_OBJ_DESTROYED 0x00000020 ++ ++/* Irq event - Indicates that object is created at the container */ ++#define DPRC_IRQ_EVENT_OBJ_CREATED 0x00000040 ++ ++/** ++ * struct dprc_irq_cfg - IRQ configuration ++ * @paddr: Address that must be written to signal a message-based interrupt ++ * @val: Value to write into irq_addr address ++ * @irq_num: A user defined number associated with this IRQ ++ */ ++struct dprc_irq_cfg { ++ phys_addr_t paddr; ++ u32 val; ++ int irq_num; ++}; ++ ++int dprc_set_irq(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ struct dprc_irq_cfg *irq_cfg); ++ ++int dprc_set_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 en); ++ ++int dprc_set_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 mask); ++ ++int dprc_get_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *status); ++ ++int dprc_clear_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 status); ++ ++/** ++ * struct dprc_attributes - Container attributes ++ * @container_id: Container's ID ++ * @icid: Container's ICID ++ * @portal_id: Container's portal ID ++ * @options: Container's options as set at container's creation ++ */ ++struct dprc_attributes { ++ int container_id; ++ u32 icid; ++ int portal_id; ++ u64 options; ++}; ++ ++int dprc_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dprc_attributes *attributes); ++ ++int dprc_get_obj_count(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int *obj_count); ++ ++int dprc_get_obj(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int obj_index, ++ struct fsl_mc_obj_desc *obj_desc); ++ ++int dprc_set_obj_irq(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ char *obj_type, ++ int obj_id, ++ u8 irq_index, ++ struct dprc_irq_cfg *irq_cfg); ++ ++/* Region flags */ ++/* Cacheable - Indicates that region should be mapped as cacheable */ ++#define DPRC_REGION_CACHEABLE 0x00000001 ++ ++/** ++ * enum dprc_region_type - Region type ++ * @DPRC_REGION_TYPE_MC_PORTAL: MC portal region ++ * @DPRC_REGION_TYPE_QBMAN_PORTAL: Qbman portal region ++ */ ++enum dprc_region_type { ++ DPRC_REGION_TYPE_MC_PORTAL, ++ DPRC_REGION_TYPE_QBMAN_PORTAL ++}; ++ ++#define DPRC_OBJ_FLAG_NO_MEM_SHAREABILITY 0x0001 ++ ++/** ++ * struct dprc_region_desc - Mappable region descriptor ++ * @base_offset: Region offset from region's base address. ++ * For DPMCP and DPRC objects, region base is offset from SoC MC portals ++ * base address; For DPIO, region base is offset from SoC QMan portals ++ * base address ++ * @size: Region size (in bytes) ++ * @flags: Region attributes ++ * @type: Portal region type ++ */ ++struct dprc_region_desc { ++ u32 base_offset; ++ u32 size; ++ u32 flags; ++ enum dprc_region_type type; ++}; ++ ++int dprc_get_obj_region(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ char *obj_type, ++ int obj_id, ++ u8 region_index, ++ struct dprc_region_desc *region_desc); ++ ++int dprc_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver); ++ ++int dprc_get_container_id(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int *container_id); ++ ++int dprc_reset_container(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int child_container_id); ++ ++/* ++ * Data Path Buffer Pool (DPBP) API ++ * Contains initialization APIs and runtime control APIs for DPBP ++ */ ++ ++int dpbp_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpbp_id, ++ u16 *token); ++ ++int dpbp_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpbp_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpbp_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpbp_reset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++/** ++ * struct dpbp_attr - Structure representing DPBP attributes ++ * @id: DPBP object ID ++ * @bpid: Hardware buffer pool ID; should be used as an argument in ++ * acquire/release operations on buffers ++ */ ++struct dpbp_attr { ++ int id; ++ u16 bpid; ++}; ++ ++int dpbp_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpbp_attr *attr); ++ ++/* Data Path Concentrator (DPCON) API ++ * Contains initialization APIs and runtime control APIs for DPCON ++ */ ++ ++/** ++ * Use it to disable notifications; see dpcon_set_notification() ++ */ ++#define DPCON_INVALID_DPIO_ID (int)(-1) ++ ++int dpcon_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpcon_id, ++ u16 *token); ++ ++int dpcon_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpcon_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpcon_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpcon_reset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++/** ++ * struct dpcon_attr - Structure representing DPCON attributes ++ * @id: DPCON object ID ++ * @qbman_ch_id: Channel ID to be used by dequeue operation ++ * @num_priorities: Number of priorities for the DPCON channel (1-8) ++ */ ++struct dpcon_attr { ++ int id; ++ u16 qbman_ch_id; ++ u8 num_priorities; ++}; ++ ++int dpcon_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpcon_attr *attr); ++ ++/** ++ * struct dpcon_notification_cfg - Structure representing notification params ++ * @dpio_id: DPIO object ID; must be configured with a notification channel; ++ * to disable notifications set it to 'DPCON_INVALID_DPIO_ID'; ++ * @priority: Priority selection within the DPIO channel; valid values ++ * are 0-7, depending on the number of priorities in that channel ++ * @user_ctx: User context value provided with each CDAN message ++ */ ++struct dpcon_notification_cfg { ++ int dpio_id; ++ u8 priority; ++ u64 user_ctx; ++}; ++ ++int dpcon_set_notification(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpcon_notification_cfg *cfg); ++ ++struct irq_domain; ++struct msi_domain_info; ++ ++/** ++ * Maximum number of total IRQs that can be pre-allocated for an MC bus' ++ * IRQ pool ++ */ ++#define FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS 256 ++ ++/** ++ * struct fsl_mc_resource_pool - Pool of MC resources of a given ++ * type ++ * @type: type of resources in the pool ++ * @max_count: maximum number of resources in the pool ++ * @free_count: number of free resources in the pool ++ * @mutex: mutex to serialize access to the pool's free list ++ * @free_list: anchor node of list of free resources in the pool ++ * @mc_bus: pointer to the MC bus that owns this resource pool ++ */ ++struct fsl_mc_resource_pool { ++ enum fsl_mc_pool_type type; ++ int max_count; ++ int free_count; ++ struct mutex mutex; /* serializes access to free_list */ ++ struct list_head free_list; ++ struct fsl_mc_bus *mc_bus; ++}; ++ ++/** ++ * struct fsl_mc_restool - information associated with a restool device file ++ * @cdev: struct char device linked to the root dprc ++ * @dev: dev_t for the char device to be added ++ * @device: newly created device in /dev ++ * @mutex: mutex lock to serialize the open/release operations ++ * @local_instance_in_use: local MC I/O instance in use or not ++ * @dynamic_instance_count: number of dynamically created MC I/O instances ++ */ ++struct fsl_mc_restool { ++ struct cdev cdev; ++ dev_t dev; ++ struct device *device; ++ struct mutex mutex; /* serialize open/release operations */ ++ bool local_instance_in_use; ++ u32 dynamic_instance_count; ++}; ++ ++/** ++ * struct fsl_mc_bus - logical bus that corresponds to a physical DPRC ++ * @mc_dev: fsl-mc device for the bus device itself. ++ * @resource_pools: array of resource pools (one pool per resource type) ++ * for this MC bus. These resources represent allocatable entities ++ * from the physical DPRC. ++ * @irq_resources: Pointer to array of IRQ objects for the IRQ pool ++ * @scan_mutex: Serializes bus scanning ++ * @dprc_attr: DPRC attributes ++ * @restool_misc: struct that abstracts the interaction with userspace restool ++ */ ++struct fsl_mc_bus { ++ struct fsl_mc_device mc_dev; ++ struct fsl_mc_resource_pool resource_pools[FSL_MC_NUM_POOL_TYPES]; ++ struct fsl_mc_device_irq *irq_resources; ++ struct mutex scan_mutex; /* serializes bus scanning */ ++ struct dprc_attributes dprc_attr; ++ struct fsl_mc_restool restool_misc; ++}; ++ ++int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev, ++ const char *driver_override, ++ unsigned int *total_irq_count); ++ ++int fsl_mc_find_msi_domain(struct device *mc_platform_dev, ++ struct irq_domain **mc_msi_domain); ++ ++int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus, ++ unsigned int irq_count); ++ ++void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus); ++ ++void fsl_mc_init_all_resource_pools(struct fsl_mc_device *mc_bus_dev); ++ ++void fsl_mc_cleanup_all_resource_pools(struct fsl_mc_device *mc_bus_dev); ++ ++void fsl_mc_get_root_dprc(struct device *dev, struct device **root_dprc_dev); ++ ++#endif /* _FSL_MC_H_ */ +--- /dev/null ++++ b/include/uapi/linux/fsl_mc.h +@@ -0,0 +1,31 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++/* ++ * Management Complex (MC) userspace public interface ++ * ++ * Copyright 2018 NXP ++ * ++ */ ++#ifndef _UAPI_FSL_MC_H_ ++#define _UAPI_FSL_MC_H_ ++ ++#define MC_CMD_NUM_OF_PARAMS 7 ++ ++/** ++ * struct fsl_mc_command - Management Complex (MC) command structure ++ * @header: MC command header ++ * @params: MC command parameters ++ * ++ * Used by RESTOOL_SEND_MC_COMMAND ++ */ ++struct fsl_mc_command { ++ __u64 header; ++ __u64 params[MC_CMD_NUM_OF_PARAMS]; ++}; ++ ++#define RESTOOL_IOCTL_TYPE 'R' ++#define RESTOOL_IOCTL_SEQ 0xE0 ++ ++#define RESTOOL_SEND_MC_COMMAND \ ++ _IOWR(RESTOOL_IOCTL_TYPE, RESTOOL_IOCTL_SEQ, struct fsl_mc_command) + - #endif /* _FSL_MC_H_ */ ++#endif /* _UAPI_FSL_MC_H_ */ |