All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH v12 00/17] dlb: introduce DLB device driver
@ 2021-12-21  6:50 Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver Mike Ximing Chen
                   ` (18 more replies)
  0 siblings, 19 replies; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

The Intel(r) Dynamic Load Balancer (Intel(r) DLB) is a PCIe device and hardware
accelerator that provides load-balanced, prioritized scheduling for event based
workloads across CPU cores. It can be used to save CPU resources in high
throughput pipelines by replacing software based distribution and synchronization
schemes. Using Intel DLB has been demonstrated to reduce CPU utilization up to
2-3 CPU cores per DLB device, while also improving packet processing pipeline
performance.

In many applications running on processors with a large number of cores,
workloads must be distributed (load-balanced) across a number of cores.
In packet processing applications, for example, streams of incoming packets can
exceed the capacity of any single core. So they have to be divided between
available worker cores. The workload can be split by either breaking the
processing flow into stages and places distinct stages on separate cores in a
daisy chain fashion (a pipeline), or spraying packets across multiple workers
that may be executing the same processing stage. Many systems employ a hybrid
approach whereby each packet encounters multiple pipelined stages with
distribution across multiple workers at each individual stage.

Intel DLB distribution schemes include "parallel" (packets are load-balanced
across multiple cores and processed in parallel), "ordered" (similar to
"parallel" but packets are reordered into ingress order by the device), and
"atomic" (packet flows are scheduled to a single core at a time such that
locks are not required to access per-flow data, and dynamically migrated to
ensure load-balance).

Intel DLB consists of queues and arbiters that connect producer
cores and consumer cores. The device implements load-balanced queueing
features including:
- Lock-free multi-producer/multi-consumer operation.
- Multiple priority levels for varying traffic types.
- 'Direct' traffic (i.e. multi-producer/single-consumer)
- Simple unordered load-balanced distribution.
- Atomic lock free load balancing across multiple consumers.
- Queue element reordering feature allowing ordered load-balanced
  distribution.

The fundamental unit of communication through the device is a queue element
(QE), which consists of 8B of data and 8B of metadata (destination queue,
priority, etc.). The data field can be any type that fits within 8B.

A core's interface to the device, a "port," consists of a memory-mappable
region through which the core enqueues a queue entry, and an in-memory
queue (the "consumer queue") to which the device schedules QEs. Each QE
is enqueued to a device-managed queue, and from there scheduled to a port.
Software specifies the "linking" of queues and ports; i.e. which ports the
device is allowed to schedule to for a given queue. The device uses a
credit scheme to prevent overflow of the on-device queue storage.

Applications can interface directly with the device by mapping the port's
memory and MMIO regions into the application's address space for enqueue
and dequeue operations, but call into the kernel driver for configuration
operations. An application can also be polling- or interrupt-driven;
Intel DLB supports both modes of operation.

Device resources -- i.e. ports, queues, and credits -- are contained within
a scheduling domain. Scheduling domains are isolated from one another; a
port can only enqueue to and dequeue from queues within its scheduling
domain. A scheduling domain's resources are configured through a configfs
interface. Please refer to Documentation/misc-devices/dlb.rst (in patch 01/17)
for a detailed description on the DLB configfs implementation.

Intel DLB supports SR-IOV and Scalable IOV, and allows for a flexible
division of its resources among the PF and its virtual devices. The virtual
devices are incapable of configuring the device directly; they use a
hardware mailbox to proxy configuration requests to the PF driver. This
driver supports both PF and virtual devices, as there is significant code
re-use between the two, with device-specific behavior handled through a
callback interface.  Virtualization support will be added in a later patch
set.

The DLB driver uses configfs and sysfs as its primary interface While the
DLB sysfs allows users to configure DLB at the device level, the configfs
lets users to create and control DLB scheduling domains, ports and queues.
Configfs supports operations on a scheduling domain's resources
(primarily resource configuration).  Scheduling domains are created
dynamically by user-space software.

[1] https://builders.intel.com/docs/networkbuilders/SKU-343247-001US-queue-management-and-load-balancing-on-intel-architecture.pdf
[2] https://doc.dpdk.org/guides/prog_guide/eventdev.html

This submission is still a work in progress. We have replaced ioctl interface
with configfs and made a few other changes based on earlier reviews (see
https://lore.kernel.org/all/BYAPR11MB30952BA538BB905331392A08D9119@BYAPR11MB3095.namprd11.prod.outlook.com/).
There are a couple of issues that we would like to get help and suggestions
from reviewers and community.

1. Before a scheduling domain is created/enabled, a set of parameters are
passed to the kernel driver via configfs attribute files in an configfs domain
directory (say $domain) created by user. Each attribute file corresponds to
a configuration parameter of the domain. After writing to all the attribute
files, user writes 1 to "create" attribute, which triggers an action (i.e.,
domain creation) in the kernel driver. Since multiple processes/users can
access the $domain directory, multiple users can write to the attribute files
at the same time.  How do we guarantee an atomic update/configuration of a
domain? In other words, if user A wants to set attributes 1 and 2, how can we
prevent user B from changing attribute 1 and 2 before user A writes 1 to
"create"? A configfs directory with individual attribute files seems to not
be able to provide atomic configuration in this case. One option to solve this
issue could be write a structured data (with a set of parameters) to a single
attribute file. This would guarantee the atomic configuration, but may not be
a conventional configfs operation.
 
2. When a user space dlb application exits, it needs to tell the kernel driver
to reset the scheduling domain and return the associated resources back to the
resource pool for a future use. The application does so by write 0 to "create"
attribute file, and it works fine with a normal program exit. However when an
application is killed (for example, kill -9) by user, we need to a way to reset
the domain in the driver. What would be the best approach for the tear down
process in this case? In our current implementation (see patch 06/17) we create
and open an anon file descriptor when a domain is created/enabled. Since the
file is closed automatically when the user application exits or is killed, we
use the file close() operation in the driver to reset and tear down the domain.
Would this approach be acceptable with the configfs implementation? 

Dan points out that configfs puts atomic update and configuration teardown
responsibilities in userspacer. We are looking for a direction check on these
issues before doing deeper reworks.

v12:
- Address Dan's following feedbacks on coding stylei issues.
-- Remove DLB_HW_ERR() and DLB_HW_DBG() macros. Use dev_err() and dev_dbg()
   directly.
-- Replace FIELD_SET() macro with direct coding.
-- Remove all refererences on virt_id/phys_id. They will be introduced in
   future patches.
-- Use list_move() instead of list_del() and list_add() whenever possible.
-- Remove device revision numbers.
-- Reverse the order of iosubmit_cmds512() and wmb().
-- Other cleanups based on Dan's comments.

- The following coding style changes suggested by Dan will be implemented
  in the next revision
-- Replace DLB_CSR_RD() and DLB_CSR_WR() with direct ioread32() and
   iowrite32() call.
-- Remove bitmap wrappers and use linux bitmap functions directly.
-- Use trace_event in configfs attribute file update.

v11:
- Change the user interface from ioctls to configfs. Provide configfs
  interface for create and configure scheduling domains, queues, ports,
  and link/unlink of queues and ports.
- Address all of Greg's feedback on v10, including
-- Consolidate header files. Merged dlb_main.h, dlb_hw_types.h,
   dlb_resources.h and dlb_bitmap.h into dlb_main.h.
-- Removed device ops callbacks. They will be added back to when
   VM support is introduced.
-- Use macros/fucntions provided by linux kernel. Replace BITS_GET()
   and BITS_SET() by the existing linux kernel macros FIELD_GET()
   and FIELD_PREP().
-- Revise the DLB overview document dlb.rst and provide detailed
   descriptions on how DLB works.
- Remove configurations for sequeuence number and class of services.
- Remove all VF and VDEV (specially in dlb_resource.c) related code. Will
  add them back in a later patches.
- Add dlb sysfs for device level control and configurtion.
- Move dynamic port and queueu linking and unlinking to future patch
  set. This reduces the total patches in this set to 17 from 20 in v10.
  Only static linking and unlinking is supported in this submission.

v10:
- Addressed an issue reported by kernel test robot <lkp@intel.com>
-- Add "WITH Linux-syscall-note" to the SPDX-License-Identifier in uapi
   header file dlb.h.

v9:
- Addressed all of Greg's feecback on v8, including
-- Remove function name (__func__) from dev_err() messages, that could spam log.
-- Replace list and function pointer calls in dlb_ioctl() with switch-case
   and real function calls for ioctl.
-- Drop the compat_ptr_ioctl in dlb_ops (struct file_operations).
-- Change ioctl magic number for DLB to unused 0x81 (from 'h').
-- Remove all placeholder/dummy functions in the patch set.
-- Re-arrange the comments in dlb.h so that the order is consistent with that
   of data structures referred.
-- Correct the comments on SPDX License and DLB versions in dlb.h.
-- Replace BIT_SET() and BITS_CLR() marcos with direct coding.   
-- Remove NULL pointer checking (f->private_data) in dlb_ioctl().
-- Use whole line whenever possible and not wrapping lines unnecessarily.
-- Remove __attribute__((unused)).
-- Merge dlb_ioctl.h and dlb_file.h into dlb_main.h

v8:
- Add a functional block diagram in dlb.rst 
- Modify change logs to reflect the links between patches and DPDK
  eventdev library.
- Add a check of power-of-2 for CQ depth.
- Move call to INIT_WORK() to dlb_open().
- Clean dlb workqueue by calling flush_scheduled_work().
- Add unmap_mapping_range() in dlb_port_close().

v7 (Intel internal version):
- Address all of Dan's feedback, including
-- Drop DLB 2.0 throughout the patch set, use DLB only.
-- Fix license and copyright statements
-- Use pcim_enable_device() and pcim_iomap_regions(), instead of
   unmanaged version.
-- Move cdev_add() to dlb_init() and add all devices at once.
-- Fix Makefile, using "+=" style.
-- Remove FLR description and mention movdir64/enqcmd usage in doc.
-- Make the permission for the domain same as that for device for
   ioctl access.
-- Use idr instead of ida.
-- Add a lock in dlb_close() to prevent driver unbinding while ioctl
   coomands are in progress.
-- Remove wrappers that are used for code sharing between kernel driver
   and DPDK. 
- Address Pierre-Louis' feedback, including
-- Clean the warinings from checkpatch
-- Fix the warnings from "make W=1"

v6 (Intel internal version):
- Change the module name to dlb(from dlb2), which currently supports Intel
  DLB 2.0 only.
- Address all of Pierre-Louis' feedback on v5, including
-- Consolidate the two near-identical for loops in dlb2_release_domain_memory().
-- Remove an unnecessary "port = NULL" initialization
-- Consistently use curly braces on the *_LIST_FOR macros
   when the for-loop contents spans multiple lines.
-- Add a comment to the definition of DLB2FS_MAGIC
-- Remove always true if statemnets
-- Move the get_cos_bw mutex unlock call earlier to shorten the critical
   section.
- Address all of Dan's feedbacks, including
-- Replace the unions for register bits access with bitmask and shifts
-- Centralize the "to/from" user memory copies for ioctl functions.
-- Review ioctl design against Documentation/process/botching-up-ioctls.rst
-- Remove wraper functions for memory barriers.
-- Use ilog() to simplify a switch code block.
-- Add base-commit to cover letter.

v5 (Intel internal version):
- Reduce the scope of the initial patch set (drop the last 8 patches)
- Further decompose some of the remaining patches into multiple patches.
- Address all of Pierre-Louis' feedback, including:
-- Move kerneldoc to *.c files
-- Fix SPDX comment style
-- Add BAR macros
-- Improve/clarify struct dlb2_dev and struct device variable naming
-- Add const where missing
-- Clarify existing comments and add new ones in various places
-- Remove unnecessary memsets and zero-initialization
-- Remove PM abstraction, fix missing pm_runtime_allow(), and don't
   update PM refcnt when port files are opened and closed.
-- Convert certain ternary operations into if-statements
-- Out-line the CQ depth valid check
-- De-duplicate the logic in dlb2_release_device_memory()
-- Limit use of devm functions to allocating/freeing struct dlb2
- Address Ira's comments on dlb2.rst and correct commit messages that
  don't use the imperative voice.

v4:
- Move PCI device ID definitions into dlb2_hw_types.h, drop the VF definition
- Remove dlb2_dev_list
- Remove open/close functions and fops structure (unused)
- Remove "(char *)" cast from PCI driver name
- Unwind init failures properly
- Remove ID alloc helper functions and call IDA interfaces directly instead

v3:
- Remove DLB2_PCI_REG_READ/WRITE macros

v2:
- Change driver license to GPLv2 only
- Expand Kconfig help text and remove unnecessary (R)s
- Remove unnecessary prints
- Add a new entry in ioctl-number.rst
- Convert the ioctl handler into a switch statement
- Correct some instances of IOWR that should have been IOR
- Align macro blocks
- Don't break ioctl ABI when introducing new commands
- Remove indirect pointers from ioctl data structures
- Remove the get-sched-domain-fd ioctl command

Mike Ximing Chen (17):
  dlb: add skeleton for DLB driver
  dlb: initialize DLB device
  dlb: add resource and device initialization
  dlb: add configfs interface and scheduling domain directory
  dlb: add scheduling domain configuration
  dlb: add domain software reset
  dlb: add low-level register reset operations
  dlb: add runtime power-management support
  dlb: add queue create, reset, get-depth configfs interface
  dlb: add register operations for queue management
  dlb: add configfs interface to configure ports
  dlb: add register operations for port management
  dlb: add port mmap support
  dlb: add start domain configfs attribute
  dlb: add queue map, unmap, and pending unmap
  dlb: add static queue map register operations
  dlb: add basic sysfs interfaces

 Documentation/ABI/testing/sysfs-driver-dlb |  116 +
 Documentation/misc-devices/dlb.rst         |  323 ++
 Documentation/misc-devices/index.rst       |    1 +
 MAINTAINERS                                |    7 +
 drivers/misc/Kconfig                       |    1 +
 drivers/misc/Makefile                      |    1 +
 drivers/misc/dlb/Kconfig                   |   18 +
 drivers/misc/dlb/Makefile                  |    7 +
 drivers/misc/dlb/dlb_args.h                |  372 ++
 drivers/misc/dlb/dlb_configfs.c            | 1225 ++++++
 drivers/misc/dlb/dlb_configfs.h            |  195 +
 drivers/misc/dlb/dlb_file.c                |  149 +
 drivers/misc/dlb/dlb_main.c                |  616 +++
 drivers/misc/dlb/dlb_main.h                |  653 ++++
 drivers/misc/dlb/dlb_pf_ops.c              |  299 ++
 drivers/misc/dlb/dlb_regs.h                | 3640 ++++++++++++++++++
 drivers/misc/dlb/dlb_resource.c            | 3960 ++++++++++++++++++++
 include/uapi/linux/dlb.h                   |   40 +
 18 files changed, 11623 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-driver-dlb
 create mode 100644 Documentation/misc-devices/dlb.rst
 create mode 100644 drivers/misc/dlb/Kconfig
 create mode 100644 drivers/misc/dlb/Makefile
 create mode 100644 drivers/misc/dlb/dlb_args.h
 create mode 100644 drivers/misc/dlb/dlb_configfs.c
 create mode 100644 drivers/misc/dlb/dlb_configfs.h
 create mode 100644 drivers/misc/dlb/dlb_file.c
 create mode 100644 drivers/misc/dlb/dlb_main.c
 create mode 100644 drivers/misc/dlb/dlb_main.h
 create mode 100644 drivers/misc/dlb/dlb_pf_ops.c
 create mode 100644 drivers/misc/dlb/dlb_regs.h
 create mode 100644 drivers/misc/dlb/dlb_resource.c
 create mode 100644 include/uapi/linux/dlb.h


base-commit: 519d81956ee277b4419c723adfb154603c2565ba
-- 
2.27.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
@ 2021-12-21  6:50 ` Mike Ximing Chen
  2021-12-21  7:00   ` Joe Perches
                     ` (2 more replies)
  2021-12-21  6:50 ` [RFC PATCH v12 02/17] dlb: initialize DLB device Mike Ximing Chen
                   ` (17 subsequent siblings)
  18 siblings, 3 replies; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

Add basic driver functionality (load, unload, probe, and remove callbacks)
for the DLB driver.

Add documentation which describes in detail the hardware, the user
interface, device interrupts, and the driver's power-management strategy.
For more details about the driver see the documentation in the patch.

Add a DLB entry to the MAINTAINERS file.

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
---
 Documentation/misc-devices/dlb.rst   | 323 +++++++++++++++++++++++++++
 Documentation/misc-devices/index.rst |   1 +
 MAINTAINERS                          |   7 +
 drivers/misc/Kconfig                 |   1 +
 drivers/misc/Makefile                |   1 +
 drivers/misc/dlb/Kconfig             |  18 ++
 drivers/misc/dlb/Makefile            |   5 +
 drivers/misc/dlb/dlb_main.c          | 156 +++++++++++++
 drivers/misc/dlb/dlb_main.h          |  64 ++++++
 9 files changed, 576 insertions(+)
 create mode 100644 Documentation/misc-devices/dlb.rst
 create mode 100644 drivers/misc/dlb/Kconfig
 create mode 100644 drivers/misc/dlb/Makefile
 create mode 100644 drivers/misc/dlb/dlb_main.c
 create mode 100644 drivers/misc/dlb/dlb_main.h

diff --git a/Documentation/misc-devices/dlb.rst b/Documentation/misc-devices/dlb.rst
new file mode 100644
index 000000000000..2e5f9ec155a5
--- /dev/null
+++ b/Documentation/misc-devices/dlb.rst
@@ -0,0 +1,323 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+
+===========================================
+Intel(R) Dynamic Load Balancer Overview
+===========================================
+
+:Authors: Gage Eads and Mike Ximing Chen
+
+Contents
+========
+
+- Introduction
+- Scheduling
+- Queue Entry
+- Port
+- Queue
+- Credits
+- Scheduling Domain
+- Interrupts
+- Power Management
+- User Interface
+- Reset
+
+Introduction
+============
+
+The Intel(r) Dynamic Load Balancer (Intel(r) DLB) is a PCIe device and hardware
+accelerator that provides load-balanced, prioritized scheduling for event based
+workloads across CPU cores. It can be used to save CPU resources in high
+throughput pipelines by replacing software based distribution and synchronization
+schemes. Using Intel DLB in place of software based methods has been
+demonstrated to reduce CPU utilization up to 2-3 CPU cores per DLB device,
+while also improving packet processing pipeline performance.
+
+In many applications running on processors with a large number of cores,
+workloads must be distributed (load-balanced) across a number of cores.
+In packet processing applications, for example, streams of incoming packets can
+exceed the capacity of any single core. So they have to be divided between
+available worker cores. The workload can be split by either breaking the
+processing flow into stages and places distinct stages on separate cores in a
+daisy chain fashion (a pipeline), or spraying packets across multiple workers
+that may be executing the same processing stage. Many systems employ a hybrid
+approach whereby each packet encounters multiple pipelined stages with
+distribution across multiple workers at each individual stage.
+
+The following diagram shows a typical packet processing pipeline with the Intel DLB.
+
+                              WC1              WC4
+ +-----+   +----+   +---+  /      \  +---+  /      \  +---+   +----+   +-----+
+ |NIC  |   |Rx  |   |DLB| /        \ |DLB| /        \ |DLB|   |Tx  |   |NIC  |
+ |Ports|---|Core|---|   |-----WC2----|   |-----WC5----|   |---|Core|---|Ports|
+ +-----+   -----+   +---+ \        / +---+ \        / +---+   +----+   ------+
+                           \      /         \      /
+                              WC3              WC6
+
+WCs are the worker cores which process packets distributed by DLB. Without
+hardware accelerators (such as DLB) the distribution and load balancing are normally
+carried out by software running on CPU cores. Using Intel DLB in this case not only
+saves the CPU resources but also improves the system performance.
+
+The Intel DLB consists of queues and arbiters that connect producer cores (which
+enqueues events to DLB) and consumer cores (which dequeue events from DLB). The
+device implements load-balanced queueing features including:
+
+- Lock-free multi-producer/multi-consumer operation.
+- Multiple priority levels for varying traffic types.
+- Direct traffic (i.e. multi-producer/single-consumer)
+- Simple unordered load-balanced distribution.
+- Atomic lock free load balancing across multiple consumers.
+- Queue element reordering feature allowing ordered load-balanced distribution.
+
+Note: this document uses 'DLB' when discussing the device hardware and 'dlb' when
+discussing the driver implementation.
+
+Following diagram illustrates the functional blocks of an Intel DLB device.
+
+                                       +----+
+                                       |    |
+                        +----------+   |    |   +-------+
+                       /|   IQ     |---|----|--/|       |
+                      / +----------+   |    | / |  CP   |
+                     /                 |    |/  +-------+
+        +--------+  /                  |    |
+        |        | /    +----------+   |   /|   +-------+
+        |  PP    |------|   IQ     |---|----|---|       |
+        +--------+ \    +----------+   | /  |   |  CP   |
+                    \                  |/   |   +-------+
+           ...       \     ...         |    |
+        +--------+    \               /|    |   +-------+
+        |        |     \+----------+ / |    |   |       |
+        |  PP    |------|   IQ     |/--|----|---|  CP   |
+        +--------+      +----------+   |    |   +-------+
+                                       |    |
+                                       +----+     ...
+PP: Producer Port                        |
+CP: Consumer Port                        |
+IQ: Internal Queue                   DLB Scheduler
+
+
+As shown in the diagram, the high-level Intel DLB data flow is as follows:
+ - Software threads interact with the hardware by enqueuing and dequeuing Queue
+   Elements (QEs).
+ - QEs are sent through a Producer Port (PP) to the Intel DLB internal QE
+   storage (internal queues), optionally being reordered along the way.
+ - The Intel DLB schedules QEs from internal queues to a consumer according to
+   a two-stage priority arbiter (DLB Scheduler).
+ - Once scheduled, the Intel DLB writes the QE to a memory-based Consumer Port
+   (CP), which the software thread reads and processes.
+
+
+Scheduling Types
+================
+
+Intel DLB supports four types of scheduling of 'events' (i.e., queue elements),
+where an event can represent any type of data (e.g. a network packet). The
+first, `directed`, is multi-producer/single-consumer style scheduling. The
+remaining three are multi-producer/multi-consumer, and support load-balancing
+across the consumers.
+
+- `Directed`: events are scheduled to a single consumer.
+
+- `Unordered`: events are load-balanced across consumers without any ordering
+                 guarantees.
+
+- `Ordered`: events are load-balanced across consumers, and the consumer can
+               re-enqueue its events so the device re-orders them into the
+               original order. This scheduling type allows software to
+               parallelize ordered event processing without the synchronization
+               cost of re-ordering packets.
+
+- `Atomic`: events are load-balanced across consumers, with the guarantee that
+              events from a particular 'flow' are only scheduled to a single
+              consumer at a time (but can migrate over time). This allows, for
+              example, packet processing applications to parallelize while
+              avoiding locks on per-flow data and maintaining ordering within a
+              flow.
+
+Intel DLB provides hierarchical priority scheduling, with eight priority
+levels within each. Each consumer selects up to eight queues to receive events
+from, and assigns a priority to each of these 'connected' queues. To schedule
+an event to a consumer, the device selects the highest priority non-empty queue
+of the (up to) eight connected queues. Within that queue, the device selects
+the highest priority event available (selecting a lower priority event for
+starvation avoidance 1% of the time, by default).
+
+The device also supports four load-balanced scheduler classes of service. Each
+class of service receives a (user-configurable) guaranteed percentage of the
+scheduler bandwidth, and any unreserved bandwidth is divided evenly among the
+four classes.
+
+Queue Element
+===========
+
+Each event is contained in a queue element (QE), the fundamental unit of
+communication through the device, which consists of 8B of data and 8B of
+metadata, as depicted below.
+
+QE structure format
+::
+    data     :64
+    opaque   :16
+    qid      :8
+    sched    :2
+    priority :3
+    msg_type :3
+    lock_id  :16
+    rsvd     :8
+    cmd      :8
+
+The `data` field can be any type that fits within 8B (pointer, integer,
+etc.); DLB merely copies this field from producer to consumer. The
+`opaque` and `msg_type` fields behave the same way.
+
+`qid` is set by the producer to specify to which DLB internal queue it wishes
+to enqueue this QE. The ID spaces for load-balanced and directed queues are both
+zero-based.
+
+`sched` controls the scheduling type: atomic, unordered, ordered, or
+directed. The first three scheduling types are only valid for load-balanced
+queues, and the directed scheduling type is only valid for directed queues.
+This field distinguishes whether `qid` is load-balanced or directed, since
+their ID spaces overlap.
+
+`priority` is the priority with which this QE should be scheduled.
+
+`lock_id`, used for atomic scheduling and ignored for ordered and unordered
+scheduling, identifies the atomic flow to which the QE belongs. When sending a
+directed event, `lock_id` is simply copied like the `data`, `opaque`, and
+`msg_type` fields.
+
+`cmd` specifies the operation, such as:
+- Enqueue a new QE
+- Forward a QE that was dequeued
+- Complete/terminate a QE that was dequeued
+- Return one or more consumer queue tokens.
+- Arm the port's consumer queue interrupt.
+
+Port
+====
+
+A core's interface to the DLB is called a "port", and consists of an MMIO
+region (producer port) through which the core enqueues a queue element, and an
+in-memory queue (the "consumer queue" or consumer port) to which the device
+schedules QEs. A core enqueues a QE to a device queue, then the device
+schedules the event to a port. Software specifies the connection of queues
+and ports; i.e. for each queue, to which ports the device is allowed to
+schedule its events. The device uses a credit scheme to prevent overflow of
+the on-device queue storage.
+
+Applications interface directly with the device by mapping the port's memory
+and MMIO regions into the application's address space for enqueue and dequeue
+operations, but call into the kernel driver for configuration operations. An
+application can be polling- or interrupt-driven; DLB supports both modes
+of operation.
+
+Internal Queue
+==============
+
+A DLB device supports an implementation specific and runtime discoverable
+number of load-balanced (i.e. capable of atomic, ordered, and unordered
+scheduling) and directed queues. Each internal queue supports a set of
+priority levels.
+
+A load-balanced queue is capable of scheduling its events to any combination
+of load-balanced ports, whereas each directed queue can only haveone-to-one
+mapping with any directed port. There is no restriction on port or queue types
+when a port enqueues an event to a queue; that is, a load-balanced port can
+enqueue to a directed queue and vice versa.
+
+Credits
+=======
+
+The Intel DLB uses a credit scheme to prevent overflow of the on-device
+queue storage, with separate credits for load-balanced and directed queues. A
+port spends one credit when it enqueues a QE, and one credit is replenished
+when a QE is dequeued from a consumer queue. Each scheduling domain has one pool
+of load-balanced credits and one pool of directed credits; software is
+responsible for managing the allocation and replenishment of these credits among
+the scheduling domain's ports.
+
+Scheduling Domain
+=================
+
+Device resources -- including ports, queues, and credits -- are contained
+within a scheduling domain. Scheduling domains are isolated from one another; a
+port can only enqueue to and dequeue from queues within its scheduling domain.
+
+The scheduling domain with a set of resources is created through configfs, and
+can be accessed/shared by multiple processes.
+
+Consumer Queue Interrupts
+=========================
+
+Each port has its own interrupt which fires, if armed, when the consumer queue
+depth becomes non-zero. Software arms an interrupt by enqueueing a special
+'interrupt arm' command to the device through the port's MMIO window.
+
+Power Management
+================
+
+The kernel driver keeps the device in D3Hot (power save mode) when not in use.
+The driver transitions the device to D0 when the first device file is opened,
+and keeps it there until there are no open device files or memory mappings.
+
+User Interface
+==============
+
+The dlb driver uses configfs and sysfs as its primary user interfaces. While
+the sysfs is used to configure and inquire device-wide operation and
+resources, the configfs provides domain/queue/port level configuration and
+resource management.
+
+The dlb device level sysfs files are created during driver probe and is located
+at /sys/class/dlb/dlb<N>/device, where N is the zero-based device ID. The
+configfs directories/files can be created by user applications at
+/sys/kernel/config/dlb/dlb<N> using 'mkdir'. For example, 'mkdir domain0' will
+create a /domain0 directory and associated files in the configfs. Within the
+domain directory, directories for queues and ports can be created. An example of
+a DLB configfs structure is shown in the following diagram.
+
+                              config
+                                |
+                               dlb
+                                |
+                        +------+------+------+---
+                        |      |      |      |
+                       dlb0   dlb1   dlb2   dlb3
+                        |
+                +-----------+--+--------+-------
+                |           |           |
+             domain0     domain1     domain2
+                |
+        +-------+-----+------------+---------------+------------+------------
+        |             |            |               |            |
+ num_ldb_queues     port0         port1   ...    queue0       queue1   ...
+ num_ldb_ports        |                            |
+ ...                is_ldb                   num_sequence_numbers
+ create             cq_depth                 num_qid_inflights
+ start              ...                      num_atomic_iflights
+                    enable                   ...
+                    create                   create
+
+
+To create a domain/queue/port in DLB, an application can configure the resources
+by writing to corresponding files, and then write '1' to the 'create' file to
+trigger the action in the driver.
+
+The driver also exports an mmap interface through port files, which are
+acquired through port configfs. This mmap interface is used to map
+a port's memory and MMIO window into the process's address space. Once the
+ports are mapped, applications may use 64-byte direct-store instructions such
+as movdir64b to enqueue the events for better performance.
+
+Reset
+=====
+
+The dlb driver currently supports scheduling domain reset.
+
+Scheduling domain reset occurs when an application stops using its domain.
+Specifically, when no more file references or memory mappings exist. At this
+time, the driver resets all the domain's resources (flushes its queues and
+ports) and puts them in their respective available-resource lists for later
+use.
diff --git a/Documentation/misc-devices/index.rst b/Documentation/misc-devices/index.rst
index 30ac58f81901..555257a1d45c 100644
--- a/Documentation/misc-devices/index.rst
+++ b/Documentation/misc-devices/index.rst
@@ -17,6 +17,7 @@ fit into other categories.
    ad525x_dpot
    apds990x
    bh1770glc
+   dlb
    eeprom
    c2port
    dw-xdata-pcie
diff --git a/MAINTAINERS b/MAINTAINERS
index 8d118d7957d2..8f4de91cd1fc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9335,6 +9335,13 @@ L:	linux-kernel@vger.kernel.org
 S:	Supported
 F:	arch/x86/include/asm/intel-family.h
 
+INTEL DYNAMIC LOAD BALANCER DRIVER
+M:	Mike Ximing Chen <mike.ximing.chen@intel.com>
+S:	Maintained
+F:	Documentation/ABI/testing/sysfs-driver-dlb
+F:	drivers/misc/dlb/
+F:	include/uapi/linux/dlb.h
+
 INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
 M:	Jani Nikula <jani.nikula@linux.intel.com>
 M:	Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 0f5a49fc7c9e..e97a1b52e023 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -487,4 +487,5 @@ source "drivers/misc/cardreader/Kconfig"
 source "drivers/misc/habanalabs/Kconfig"
 source "drivers/misc/uacce/Kconfig"
 source "drivers/misc/pvpanic/Kconfig"
+source "drivers/misc/dlb/Kconfig"
 endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index a086197af544..9b8f11190cdd 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -59,3 +59,4 @@ obj-$(CONFIG_UACCE)		+= uacce/
 obj-$(CONFIG_XILINX_SDFEC)	+= xilinx_sdfec.o
 obj-$(CONFIG_HISI_HIKEY_USB)	+= hisi_hikey_usb.o
 obj-$(CONFIG_HI6421V600_IRQ)	+= hi6421v600-irq.o
+obj-$(CONFIG_INTEL_DLB)		+= dlb/
diff --git a/drivers/misc/dlb/Kconfig b/drivers/misc/dlb/Kconfig
new file mode 100644
index 000000000000..cfa978c705bd
--- /dev/null
+++ b/drivers/misc/dlb/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config INTEL_DLB
+	tristate "Intel Dynamic Load Balancer Driver"
+	depends on 64BIT && PCI && X86
+	help
+	  This driver supports the Intel Dynamic Load Balancer (DLB), a
+	  PCIe device (PCI ID 8086:27xx) that provides load-balanced,
+	  prioritized scheduling of core-to-core communication and improves
+	  DPDK Event Device library performance.
+
+	  The user-space interface is described in
+	  include/uapi/linux/dlb_user.h
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called dlb.
+
+	  If unsure, select N.
diff --git a/drivers/misc/dlb/Makefile b/drivers/misc/dlb/Makefile
new file mode 100644
index 000000000000..a5cd3eec3304
--- /dev/null
+++ b/drivers/misc/dlb/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_INTEL_DLB) := dlb.o
+
+dlb-objs := dlb_main.o
diff --git a/drivers/misc/dlb/dlb_main.c b/drivers/misc/dlb/dlb_main.c
new file mode 100644
index 000000000000..12346ee8acf7
--- /dev/null
+++ b/drivers/misc/dlb/dlb_main.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(C) 2016-2020 Intel Corporation. All rights reserved. */
+
+#include <linux/aer.h>
+#include <linux/cdev.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/uaccess.h>
+
+#include "dlb_main.h"
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel(R) Dynamic Load Balancer (DLB) Driver");
+
+static struct class *dlb_class;
+static dev_t dlb_devt;
+static DEFINE_IDR(dlb_ids);
+static DEFINE_MUTEX(dlb_ids_lock);
+
+/**********************************/
+/****** PCI driver callbacks ******/
+/**********************************/
+
+static int dlb_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
+{
+	struct dlb *dlb;
+	int ret;
+
+	dlb = devm_kzalloc(&pdev->dev, sizeof(*dlb), GFP_KERNEL);
+	if (!dlb)
+		return -ENOMEM;
+
+	pci_set_drvdata(pdev, dlb);
+
+	dlb->pdev = pdev;
+
+	mutex_lock(&dlb_ids_lock);
+	dlb->id = idr_alloc(&dlb_ids, (void *)dlb, 0, DLB_MAX_NUM_DEVICES - 1,
+			    GFP_KERNEL);
+	mutex_unlock(&dlb_ids_lock);
+
+	if (dlb->id < 0) {
+		dev_err(&pdev->dev, "device ID allocation failed\n");
+
+		ret = dlb->id;
+		goto alloc_id_fail;
+	}
+
+	ret = pcim_enable_device(pdev);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "failed to enable: %d\n", ret);
+
+		goto pci_enable_device_fail;
+	}
+
+	ret = pcim_iomap_regions(pdev,
+				 (1U << DLB_CSR_BAR) | (1U << DLB_FUNC_BAR),
+				 "dlb");
+	if (ret != 0) {
+		dev_err(&pdev->dev, "failed to map: %d\n", ret);
+
+		goto pci_enable_device_fail;
+	}
+
+	pci_set_master(pdev);
+
+	ret = pci_enable_pcie_error_reporting(pdev);
+	if (ret != 0)
+		dev_info(&pdev->dev, "AER is not supported\n");
+
+	return 0;
+
+pci_enable_device_fail:
+	mutex_lock(&dlb_ids_lock);
+	idr_remove(&dlb_ids, dlb->id);
+	mutex_unlock(&dlb_ids_lock);
+alloc_id_fail:
+	return ret;
+}
+
+static void dlb_remove(struct pci_dev *pdev)
+{
+	struct dlb *dlb = pci_get_drvdata(pdev);
+
+	pci_disable_pcie_error_reporting(pdev);
+
+	mutex_lock(&dlb_ids_lock);
+	idr_remove(&dlb_ids, dlb->id);
+	mutex_unlock(&dlb_ids_lock);
+}
+
+static struct pci_device_id dlb_id_table[] = {
+	{ PCI_DEVICE_DATA(INTEL, DLB_PF, DLB_PF) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, dlb_id_table);
+
+static struct pci_driver dlb_pci_driver = {
+	.name		 = "dlb",
+	.id_table	 = dlb_id_table,
+	.probe		 = dlb_probe,
+	.remove		 = dlb_remove,
+};
+
+static int __init dlb_init_module(void)
+{
+	int err;
+
+	dlb_class = class_create(THIS_MODULE, "dlb");
+
+	if (IS_ERR(dlb_class)) {
+		pr_err("dlb: class_create() returned %ld\n",
+		       PTR_ERR(dlb_class));
+
+		return PTR_ERR(dlb_class);
+	}
+
+	err = alloc_chrdev_region(&dlb_devt, 0, DLB_MAX_NUM_DEVICES, "dlb");
+
+	if (err < 0) {
+		pr_err("dlb: alloc_chrdev_region() returned %d\n", err);
+
+		goto alloc_chrdev_fail;
+	}
+
+	err = pci_register_driver(&dlb_pci_driver);
+	if (err < 0) {
+		pr_err("dlb: pci_register_driver() returned %d\n", err);
+
+		goto pci_register_fail;
+	}
+
+	return 0;
+
+pci_register_fail:
+	unregister_chrdev_region(dlb_devt, DLB_MAX_NUM_DEVICES);
+alloc_chrdev_fail:
+	class_destroy(dlb_class);
+
+	return err;
+}
+
+static void __exit dlb_exit_module(void)
+{
+	pci_unregister_driver(&dlb_pci_driver);
+
+	unregister_chrdev_region(dlb_devt, DLB_MAX_NUM_DEVICES);
+
+	class_destroy(dlb_class);
+}
+
+module_init(dlb_init_module);
+module_exit(dlb_exit_module);
diff --git a/drivers/misc/dlb/dlb_main.h b/drivers/misc/dlb/dlb_main.h
new file mode 100644
index 000000000000..23f059ec86f1
--- /dev/null
+++ b/drivers/misc/dlb/dlb_main.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright(C) 2016-2020 Intel Corporation. All rights reserved. */
+
+#ifndef __DLB_MAIN_H
+#define __DLB_MAIN_H
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/ktime.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+
+/*
+ * Hardware related #defines and data structures.
+ *
+ */
+#define DLB_MAX_NUM_VDEVS			16
+#define DLB_MAX_NUM_DOMAINS			32
+#define DLB_MAX_NUM_LDB_QUEUES			32 /* LDB == load-balanced */
+#define DLB_MAX_NUM_DIR_QUEUES			64 /* DIR == directed */
+#define DLB_MAX_NUM_LDB_PORTS			64
+#define DLB_MAX_NUM_DIR_PORTS			DLB_MAX_NUM_DIR_QUEUES
+#define DLB_MAX_NUM_LDB_CREDITS			8192
+#define DLB_MAX_NUM_DIR_CREDITS			2048
+#define DLB_MAX_NUM_HIST_LIST_ENTRIES		2048
+#define DLB_MAX_NUM_AQED_ENTRIES		2048
+#define DLB_MAX_NUM_QIDS_PER_LDB_CQ		8
+#define DLB_MAX_NUM_SEQUENCE_NUMBER_GROUPS	2
+#define DLB_MAX_NUM_SEQUENCE_NUMBER_MODES	5
+#define DLB_QID_PRIORITIES			8
+#define DLB_NUM_ARB_WEIGHTS			8
+#define DLB_MAX_WEIGHT				255
+#define DLB_NUM_COS_DOMAINS			4
+#define DLB_MAX_CQ_COMP_CHECK_LOOPS		409600
+#define DLB_MAX_QID_EMPTY_CHECK_LOOPS		(32 * 64 * 1024 * (800 / 30))
+#define DLB_HZ					800000000
+#define DLB_FUNC_BAR				0
+#define DLB_CSR_BAR				2
+
+#define PCI_DEVICE_ID_INTEL_DLB_PF		0x2710
+
+/*
+ * The dlb driver uses a different minor number for each device file, of which
+ * there are:
+ * - 33 per device (PF or VF/VDEV): 1 for the device, 32 for scheduling domains
+ * - Up to 17 devices per PF: 1 PF and up to 16 VFs/VDEVs
+ * - Up to 16 PFs per system
+ */
+#define DLB_MAX_NUM_PFS	  16
+#define DLB_NUM_FUNCS_PER_DEVICE (1 + DLB_MAX_NUM_VDEVS)
+#define DLB_MAX_NUM_DEVICES	 (DLB_MAX_NUM_PFS * DLB_NUM_FUNCS_PER_DEVICE)
+
+enum dlb_device_type {
+	DLB_PF,
+};
+
+struct dlb {
+	struct pci_dev *pdev;
+	int id;
+};
+
+#endif /* __DLB_MAIN_H */
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [RFC PATCH v12 02/17] dlb: initialize DLB device
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver Mike Ximing Chen
@ 2021-12-21  6:50 ` Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 03/17] dlb: add resource and device initialization Mike Ximing Chen
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

Map the PCI BAR space, create a char device, and set the DMA API mask for
64-bit addressing. Add the corresponding undo/remove operations.

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
---
 drivers/misc/dlb/Makefile     |  1 +
 drivers/misc/dlb/dlb_main.c   | 57 +++++++++++++++++++++++++++++++++++
 drivers/misc/dlb/dlb_main.h   | 19 ++++++++++++
 drivers/misc/dlb/dlb_pf_ops.c | 33 ++++++++++++++++++++
 4 files changed, 110 insertions(+)
 create mode 100644 drivers/misc/dlb/dlb_pf_ops.c

diff --git a/drivers/misc/dlb/Makefile b/drivers/misc/dlb/Makefile
index a5cd3eec3304..027556fd3f1f 100644
--- a/drivers/misc/dlb/Makefile
+++ b/drivers/misc/dlb/Makefile
@@ -3,3 +3,4 @@
 obj-$(CONFIG_INTEL_DLB) := dlb.o
 
 dlb-objs := dlb_main.o
+dlb-objs += dlb_pf_ops.o
diff --git a/drivers/misc/dlb/dlb_main.c b/drivers/misc/dlb/dlb_main.c
index 12346ee8acf7..00f7949e4d95 100644
--- a/drivers/misc/dlb/dlb_main.c
+++ b/drivers/misc/dlb/dlb_main.c
@@ -16,10 +16,38 @@ MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Intel(R) Dynamic Load Balancer (DLB) Driver");
 
 static struct class *dlb_class;
+static struct cdev dlb_cdev;
 static dev_t dlb_devt;
 static DEFINE_IDR(dlb_ids);
 static DEFINE_MUTEX(dlb_ids_lock);
 
+static int dlb_device_create(struct dlb *dlb, struct pci_dev *pdev)
+{
+	/*
+	 * Create a new device in order to create a /dev/dlb node. This device
+	 * is a child of the DLB PCI device.
+	 */
+	dlb->dev_number = MKDEV(MAJOR(dlb_devt), dlb->id);
+	dlb->dev = device_create(dlb_class, &pdev->dev, dlb->dev_number, dlb,
+				 "dlb%d", dlb->id);
+	if (IS_ERR(dlb->dev)) {
+		dev_err(dlb->dev, "device_create() returned %ld\n",
+			PTR_ERR(dlb->dev));
+
+		return PTR_ERR(dlb->dev);
+	}
+
+	return 0;
+}
+
+/********************************/
+/****** Char dev callbacks ******/
+/********************************/
+
+static const struct file_operations dlb_fops = {
+	.owner   = THIS_MODULE,
+};
+
 /**********************************/
 /****** PCI driver callbacks ******/
 /**********************************/
@@ -71,8 +99,24 @@ static int dlb_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
 	if (ret != 0)
 		dev_info(&pdev->dev, "AER is not supported\n");
 
+	ret = dlb_pf_map_pci_bar_space(dlb, pdev);
+	if (ret)
+		goto map_pci_bar_fail;
+
+	ret = dlb_device_create(dlb, pdev);
+	if (ret)
+		goto map_pci_bar_fail;
+
+	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+	if (ret)
+		goto dma_set_mask_fail;
+
 	return 0;
 
+dma_set_mask_fail:
+	device_destroy(dlb_class, dlb->dev_number);
+map_pci_bar_fail:
+	pci_disable_pcie_error_reporting(pdev);
 pci_enable_device_fail:
 	mutex_lock(&dlb_ids_lock);
 	idr_remove(&dlb_ids, dlb->id);
@@ -85,6 +129,8 @@ static void dlb_remove(struct pci_dev *pdev)
 {
 	struct dlb *dlb = pci_get_drvdata(pdev);
 
+	device_destroy(dlb_class, dlb->dev_number);
+
 	pci_disable_pcie_error_reporting(pdev);
 
 	mutex_lock(&dlb_ids_lock);
@@ -107,6 +153,7 @@ static struct pci_driver dlb_pci_driver = {
 
 static int __init dlb_init_module(void)
 {
+	int dlb_major;
 	int err;
 
 	dlb_class = class_create(THIS_MODULE, "dlb");
@@ -126,6 +173,12 @@ static int __init dlb_init_module(void)
 		goto alloc_chrdev_fail;
 	}
 
+	dlb_major = MAJOR(dlb_devt);
+	cdev_init(&dlb_cdev, &dlb_fops);
+	err = cdev_add(&dlb_cdev, MKDEV(dlb_major, 0), DLB_MAX_NUM_DEVICES);
+	if (err)
+		goto cdev_add_fail;
+
 	err = pci_register_driver(&dlb_pci_driver);
 	if (err < 0) {
 		pr_err("dlb: pci_register_driver() returned %d\n", err);
@@ -136,6 +189,8 @@ static int __init dlb_init_module(void)
 	return 0;
 
 pci_register_fail:
+	cdev_del(&dlb_cdev);
+cdev_add_fail:
 	unregister_chrdev_region(dlb_devt, DLB_MAX_NUM_DEVICES);
 alloc_chrdev_fail:
 	class_destroy(dlb_class);
@@ -147,6 +202,8 @@ static void __exit dlb_exit_module(void)
 {
 	pci_unregister_driver(&dlb_pci_driver);
 
+	cdev_del(&dlb_cdev);
+
 	unregister_chrdev_region(dlb_devt, DLB_MAX_NUM_DEVICES);
 
 	class_destroy(dlb_class);
diff --git a/drivers/misc/dlb/dlb_main.h b/drivers/misc/dlb/dlb_main.h
index 23f059ec86f1..efe74ffcbf0c 100644
--- a/drivers/misc/dlb/dlb_main.h
+++ b/drivers/misc/dlb/dlb_main.h
@@ -16,6 +16,7 @@
  * Hardware related #defines and data structures.
  *
  */
+
 #define DLB_MAX_NUM_VDEVS			16
 #define DLB_MAX_NUM_DOMAINS			32
 #define DLB_MAX_NUM_LDB_QUEUES			32 /* LDB == load-balanced */
@@ -41,6 +42,15 @@
 
 #define PCI_DEVICE_ID_INTEL_DLB_PF		0x2710
 
+struct dlb_hw {
+	/* BAR 0 address */
+	void __iomem *csr_kva;
+	unsigned long csr_phys_addr;
+	/* BAR 2 address */
+	void __iomem *func_kva;
+	unsigned long func_phys_addr;
+};
+
 /*
  * The dlb driver uses a different minor number for each device file, of which
  * there are:
@@ -56,9 +66,18 @@ enum dlb_device_type {
 	DLB_PF,
 };
 
+struct dlb;
+
+int dlb_pf_map_pci_bar_space(struct dlb *dlb, struct pci_dev *pdev);
+void dlb_pf_unmap_pci_bar_space(struct dlb *dlb, struct pci_dev *pdev);
+
 struct dlb {
 	struct pci_dev *pdev;
+	struct dlb_hw hw;
+	struct device *dev;
+	enum dlb_device_type type;
 	int id;
+	dev_t dev_number;
 };
 
 #endif /* __DLB_MAIN_H */
diff --git a/drivers/misc/dlb/dlb_pf_ops.c b/drivers/misc/dlb/dlb_pf_ops.c
new file mode 100644
index 000000000000..77ca7bf2d961
--- /dev/null
+++ b/drivers/misc/dlb/dlb_pf_ops.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(C) 2016-2020 Intel Corporation. All rights reserved. */
+
+#include "dlb_main.h"
+
+/********************************/
+/****** PCI BAR management ******/
+/********************************/
+
+int dlb_pf_map_pci_bar_space(struct dlb *dlb, struct pci_dev *pdev)
+{
+	dlb->hw.func_kva = pcim_iomap_table(pdev)[DLB_FUNC_BAR];
+	dlb->hw.func_phys_addr = pci_resource_start(pdev, DLB_FUNC_BAR);
+
+	if (!dlb->hw.func_kva) {
+		dev_err(&pdev->dev, "Cannot iomap BAR 0 (size %llu)\n",
+			pci_resource_len(pdev, 0));
+
+		return -EIO;
+	}
+
+	dlb->hw.csr_kva = pcim_iomap_table(pdev)[DLB_CSR_BAR];
+	dlb->hw.csr_phys_addr = pci_resource_start(pdev, DLB_CSR_BAR);
+
+	if (!dlb->hw.csr_kva) {
+		dev_err(&pdev->dev, "Cannot iomap BAR 2 (size %llu)\n",
+			pci_resource_len(pdev, 2));
+
+		return -EIO;
+	}
+
+	return 0;
+}
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [RFC PATCH v12 03/17] dlb: add resource and device initialization
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 02/17] dlb: initialize DLB device Mike Ximing Chen
@ 2021-12-21  6:50 ` Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 04/17] dlb: add configfs interface and scheduling domain directory Mike Ximing Chen
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

Add the hardware resource data structures, functions for
their initialization/teardown, and a function for device power-on. In
subsequent commits, dlb_resource.c will be expanded to hold the dlb
resource-management and configuration logic (using the data structures
defined in dlb_main.h).

There is a resource data structure for each system level: device/function,
scheduling domain, port and queue. At the device/function level, this
data structure is struct dlb_function_resources, which holds used and
avialable domains/ports/queues/history lists for the device function
(either physical or virtual).

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
---
 drivers/misc/dlb/Makefile       |   2 +-
 drivers/misc/dlb/dlb_main.c     |  46 ++++++
 drivers/misc/dlb/dlb_main.h     | 249 ++++++++++++++++++++++++++++++++
 drivers/misc/dlb/dlb_pf_ops.c   |  56 +++++++
 drivers/misc/dlb/dlb_regs.h     | 119 +++++++++++++++
 drivers/misc/dlb/dlb_resource.c | 210 +++++++++++++++++++++++++++
 6 files changed, 681 insertions(+), 1 deletion(-)
 create mode 100644 drivers/misc/dlb/dlb_regs.h
 create mode 100644 drivers/misc/dlb/dlb_resource.c

diff --git a/drivers/misc/dlb/Makefile b/drivers/misc/dlb/Makefile
index 027556fd3f1f..66d885619e66 100644
--- a/drivers/misc/dlb/Makefile
+++ b/drivers/misc/dlb/Makefile
@@ -3,4 +3,4 @@
 obj-$(CONFIG_INTEL_DLB) := dlb.o
 
 dlb-objs := dlb_main.o
-dlb-objs += dlb_pf_ops.o
+dlb-objs += dlb_pf_ops.o dlb_resource.o
diff --git a/drivers/misc/dlb/dlb_main.c b/drivers/misc/dlb/dlb_main.c
index 00f7949e4d95..136e8b54ea2b 100644
--- a/drivers/misc/dlb/dlb_main.c
+++ b/drivers/misc/dlb/dlb_main.c
@@ -21,6 +21,23 @@ static dev_t dlb_devt;
 static DEFINE_IDR(dlb_ids);
 static DEFINE_MUTEX(dlb_ids_lock);
 
+static int dlb_reset_device(struct pci_dev *pdev)
+{
+	int ret;
+
+	ret = pci_save_state(pdev);
+	if (ret)
+		return ret;
+
+	ret = __pci_reset_function_locked(pdev);
+	if (ret)
+		return ret;
+
+	pci_restore_state(pdev);
+
+	return 0;
+}
+
 static int dlb_device_create(struct dlb *dlb, struct pci_dev *pdev)
 {
 	/*
@@ -111,8 +128,35 @@ static int dlb_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
 	if (ret)
 		goto dma_set_mask_fail;
 
+	/*
+	 * PM enable must be done before any other MMIO accesses, and this
+	 * setting is persistent across device reset.
+	 */
+	dlb_pf_enable_pm(dlb);
+
+	ret = dlb_pf_wait_for_device_ready(dlb, pdev);
+	if (ret)
+		goto wait_for_device_ready_fail;
+
+	ret = dlb_reset_device(pdev);
+	if (ret)
+		goto dlb_reset_fail;
+
+	ret = dlb_resource_init(&dlb->hw);
+	if (ret)
+		goto resource_init_fail;
+
+	ret = dlb_pf_init_driver_state(dlb);
+	if (ret)
+		goto init_driver_state_fail;
+
 	return 0;
 
+init_driver_state_fail:
+	dlb_resource_free(&dlb->hw);
+resource_init_fail:
+dlb_reset_fail:
+wait_for_device_ready_fail:
 dma_set_mask_fail:
 	device_destroy(dlb_class, dlb->dev_number);
 map_pci_bar_fail:
@@ -129,6 +173,8 @@ static void dlb_remove(struct pci_dev *pdev)
 {
 	struct dlb *dlb = pci_get_drvdata(pdev);
 
+	dlb_resource_free(&dlb->hw);
+
 	device_destroy(dlb_class, dlb->dev_number);
 
 	pci_disable_pcie_error_reporting(pdev);
diff --git a/drivers/misc/dlb/dlb_main.h b/drivers/misc/dlb/dlb_main.h
index efe74ffcbf0c..a65b12b75b4c 100644
--- a/drivers/misc/dlb/dlb_main.h
+++ b/drivers/misc/dlb/dlb_main.h
@@ -11,11 +11,23 @@
 #include <linux/mutex.h>
 #include <linux/pci.h>
 #include <linux/types.h>
+#include <linux/bitfield.h>
 
 /*
  * Hardware related #defines and data structures.
  *
  */
+/* Read/write register 'reg' in the CSR BAR space */
+#define DLB_CSR_REG_ADDR(a, reg)   ((a)->csr_kva + (reg))
+#define DLB_CSR_RD(hw, reg)	    ioread32(DLB_CSR_REG_ADDR((hw), (reg)))
+#define DLB_CSR_WR(hw, reg, value) iowrite32((value), \
+					      DLB_CSR_REG_ADDR((hw), (reg)))
+
+/* Read/write register 'reg' in the func BAR space */
+#define DLB_FUNC_REG_ADDR(a, reg)   ((a)->func_kva + (reg))
+#define DLB_FUNC_RD(hw, reg)	     ioread32(DLB_FUNC_REG_ADDR((hw), (reg)))
+#define DLB_FUNC_WR(hw, reg, value) iowrite32((value), \
+					       DLB_FUNC_REG_ADDR((hw), (reg)))
 
 #define DLB_MAX_NUM_VDEVS			16
 #define DLB_MAX_NUM_DOMAINS			32
@@ -42,6 +54,159 @@
 
 #define PCI_DEVICE_ID_INTEL_DLB_PF		0x2710
 
+struct dlb_ldb_queue {
+	struct list_head domain_list;
+	struct list_head func_list;
+	u32 id;
+	u32 domain_id;
+	u32 num_qid_inflights;
+	u32 aqed_limit;
+	u32 sn_group; /* sn == sequence number */
+	u32 sn_slot;
+	u32 num_mappings;
+	u8 sn_cfg_valid;
+	u8 num_pending_additions;
+	u8 owned;
+	u8 configured;
+};
+
+/*
+ * Directed ports and queues are paired by nature, so the driver tracks them
+ * with a single data structure.
+ */
+struct dlb_dir_pq_pair {
+	struct list_head domain_list;
+	struct list_head func_list;
+	u32 id;
+	u32 domain_id;
+	u32 ref_cnt;
+	u8 init_tkn_cnt;
+	u8 queue_configured;
+	u8 port_configured;
+	u8 owned;
+	u8 enabled;
+};
+
+enum dlb_qid_map_state {
+	/* The slot doesn't contain a valid queue mapping */
+	DLB_QUEUE_UNMAPPED,
+	/* The slot contains a valid queue mapping */
+	DLB_QUEUE_MAPPED,
+	/* The driver is mapping a queue into this slot */
+	DLB_QUEUE_MAP_IN_PROG,
+	/* The driver is unmapping a queue from this slot */
+	DLB_QUEUE_UNMAP_IN_PROG,
+	/*
+	 * The driver is unmapping a queue from this slot, and once complete
+	 * will replace it with another mapping.
+	 */
+	DLB_QUEUE_UNMAP_IN_PROG_PENDING_MAP,
+};
+
+struct dlb_ldb_port_qid_map {
+	enum dlb_qid_map_state state;
+	u16 qid;
+	u16 pending_qid;
+	u8 priority;
+	u8 pending_priority;
+};
+
+struct dlb_ldb_port {
+	struct list_head domain_list;
+	struct list_head func_list;
+	u32 id;
+	u32 domain_id;
+	/* The qid_map represents the hardware QID mapping state. */
+	struct dlb_ldb_port_qid_map qid_map[DLB_MAX_NUM_QIDS_PER_LDB_CQ];
+	u32 hist_list_entry_base;
+	u32 hist_list_entry_limit;
+	u32 ref_cnt;
+	u8 init_tkn_cnt;
+	u8 num_pending_removals;
+	u8 num_mappings;
+	u8 owned;
+	u8 enabled;
+	u8 configured;
+};
+
+struct dlb_sn_group {
+	u32 mode;
+	u32 sequence_numbers_per_queue;
+	u32 slot_use_bitmap;
+	u32 id;
+};
+
+/*
+ * Scheduling domain level resource data structure.
+ *
+ */
+struct dlb_hw_domain {
+	struct dlb_function_resources *parent_func;
+	struct list_head func_list;
+	struct list_head used_ldb_queues;
+	struct list_head used_ldb_ports[DLB_NUM_COS_DOMAINS];
+	struct list_head used_dir_pq_pairs;
+	struct list_head avail_ldb_queues;
+	struct list_head avail_ldb_ports[DLB_NUM_COS_DOMAINS];
+	struct list_head avail_dir_pq_pairs;
+	u32 total_hist_list_entries;
+	u32 avail_hist_list_entries;
+	u32 hist_list_entry_base;
+	u32 hist_list_entry_offset;
+	u32 num_ldb_credits;
+	u32 num_dir_credits;
+	u32 num_avail_aqed_entries;
+	u32 num_used_aqed_entries;
+	u32 id;
+	int num_pending_removals;
+	int num_pending_additions;
+	u8 configured;
+	u8 started;
+};
+
+/*
+ * Device function (either PF or VF) level resource data structure.
+ *
+ */
+struct dlb_function_resources {
+	struct list_head avail_domains;
+	struct list_head used_domains;
+	struct list_head avail_ldb_queues;
+	struct list_head avail_ldb_ports[DLB_NUM_COS_DOMAINS];
+	struct list_head avail_dir_pq_pairs;
+	struct dlb_bitmap *avail_hist_list_entries;
+	u32 num_avail_domains;
+	u32 num_avail_ldb_queues;
+	u32 num_avail_ldb_ports[DLB_NUM_COS_DOMAINS];
+	u32 num_avail_dir_pq_pairs;
+	u32 num_avail_qed_entries;
+	u32 num_avail_dqed_entries;
+	u32 num_avail_aqed_entries;
+	u8 locked; /* (VDEV only) */
+};
+
+/*
+ * After initialization, each resource in dlb_hw_resources is located in one
+ * of the following lists:
+ * -- The PF's available resources list. These are unconfigured resources owned
+ *	by the PF and not allocated to a dlb scheduling domain.
+ * -- A VDEV's available resources list. These are VDEV-owned unconfigured
+ *	resources not allocated to a dlb scheduling domain.
+ * -- A domain's available resources list. These are domain-owned unconfigured
+ *	resources.
+ * -- A domain's used resources list. These are domain-owned configured
+ *	resources.
+ *
+ * A resource moves to a new list when a VDEV or domain is created or destroyed,
+ * or when the resource is configured.
+ */
+struct dlb_hw_resources {
+	struct dlb_ldb_queue ldb_queues[DLB_MAX_NUM_LDB_QUEUES];
+	struct dlb_ldb_port ldb_ports[DLB_MAX_NUM_LDB_PORTS];
+	struct dlb_dir_pq_pair dir_pq_pairs[DLB_MAX_NUM_DIR_PORTS];
+	struct dlb_sn_group sn_groups[DLB_MAX_NUM_SEQUENCE_NUMBER_GROUPS];
+};
+
 struct dlb_hw {
 	/* BAR 0 address */
 	void __iomem *csr_kva;
@@ -49,6 +214,13 @@ struct dlb_hw {
 	/* BAR 2 address */
 	void __iomem *func_kva;
 	unsigned long func_phys_addr;
+
+	/* Resource tracking */
+	struct dlb_hw_resources rsrcs;
+	struct dlb_function_resources pf;
+	struct dlb_function_resources vdev[DLB_MAX_NUM_VDEVS];
+	struct dlb_hw_domain domains[DLB_MAX_NUM_DOMAINS];
+	u8 cos_reservation[DLB_NUM_COS_DOMAINS];
 };
 
 /*
@@ -70,14 +242,91 @@ struct dlb;
 
 int dlb_pf_map_pci_bar_space(struct dlb *dlb, struct pci_dev *pdev);
 void dlb_pf_unmap_pci_bar_space(struct dlb *dlb, struct pci_dev *pdev);
+int dlb_pf_init_driver_state(struct dlb *dlb);
+void dlb_pf_enable_pm(struct dlb *dlb);
+int dlb_pf_wait_for_device_ready(struct dlb *dlb, struct pci_dev *pdev);
 
 struct dlb {
 	struct pci_dev *pdev;
 	struct dlb_hw hw;
 	struct device *dev;
+	/*
+	 * The resource mutex serializes access to driver data structures and
+	 * hardware registers.
+	 */
+	struct mutex resource_mutex;
 	enum dlb_device_type type;
 	int id;
 	dev_t dev_number;
 };
 
+/*************************/
+/*** Bitmap operations ***/
+/*************************/
+struct dlb_bitmap {
+	unsigned long *map;
+	unsigned int len;
+};
+
+/**
+ * dlb_bitmap_alloc() - alloc a bitmap data structure
+ * @bitmap: pointer to dlb_bitmap structure pointer.
+ * @len: number of entries in the bitmap.
+ *
+ * This function allocates a bitmap and initializes it with length @len. All
+ * entries are initially zero.
+ *
+ * Return:
+ * Returns 0 upon success, < 0 otherwise.
+ *
+ * Errors:
+ * EINVAL - bitmap is NULL or len is 0.
+ * ENOMEM - could not allocate memory for the bitmap data structure.
+ */
+static inline int dlb_bitmap_alloc(struct dlb_bitmap **bitmap,
+				   unsigned int len)
+{
+	struct dlb_bitmap *bm;
+
+	if (!bitmap || len == 0)
+		return -EINVAL;
+
+	bm = kzalloc(sizeof(*bm), GFP_KERNEL);
+	if (!bm)
+		return -ENOMEM;
+
+	bm->map = bitmap_zalloc(len, GFP_KERNEL);
+	if (!bm->map) {
+		kfree(bm);
+		return -ENOMEM;
+	}
+
+	bm->len = len;
+
+	*bitmap = bm;
+
+	return 0;
+}
+
+/**
+ * dlb_bitmap_free() - free a previously allocated bitmap data structure
+ * @bitmap: pointer to dlb_bitmap structure.
+ *
+ * This function frees a bitmap that was allocated with dlb_bitmap_alloc().
+ */
+static inline void dlb_bitmap_free(struct dlb_bitmap *bitmap)
+{
+	if (!bitmap)
+		return;
+
+	bitmap_free(bitmap->map);
+
+	kfree(bitmap);
+}
+
+/* Prototypes for dlb_resource.c */
+int dlb_resource_init(struct dlb_hw *hw);
+void dlb_resource_free(struct dlb_hw *hw);
+void dlb_clr_pmcsr_disable(struct dlb_hw *hw);
+
 #endif /* __DLB_MAIN_H */
diff --git a/drivers/misc/dlb/dlb_pf_ops.c b/drivers/misc/dlb/dlb_pf_ops.c
index 77ca7bf2d961..8d179beb9d5b 100644
--- a/drivers/misc/dlb/dlb_pf_ops.c
+++ b/drivers/misc/dlb/dlb_pf_ops.c
@@ -1,7 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright(C) 2016-2020 Intel Corporation. All rights reserved. */
 
+#include <linux/delay.h>
+
 #include "dlb_main.h"
+#include "dlb_regs.h"
 
 /********************************/
 /****** PCI BAR management ******/
@@ -31,3 +34,56 @@ int dlb_pf_map_pci_bar_space(struct dlb *dlb, struct pci_dev *pdev)
 
 	return 0;
 }
+
+/*******************************/
+/****** Driver management ******/
+/*******************************/
+
+int dlb_pf_init_driver_state(struct dlb *dlb)
+{
+	mutex_init(&dlb->resource_mutex);
+
+	return 0;
+}
+
+void dlb_pf_enable_pm(struct dlb *dlb)
+{
+	/*
+	 * Clear the power-management-disable register to power on the bulk of
+	 * the device's hardware.
+	 */
+	dlb_clr_pmcsr_disable(&dlb->hw);
+}
+
+#define DLB_READY_RETRY_LIMIT 1000
+int dlb_pf_wait_for_device_ready(struct dlb *dlb, struct pci_dev *pdev)
+{
+	u32 retries = DLB_READY_RETRY_LIMIT;
+
+	/* Allow at least 1s for the device to become active after power-on */
+	do {
+		u32 idle, pm_st, addr;
+
+		addr = CM_CFG_PM_STATUS;
+
+		pm_st = DLB_CSR_RD(&dlb->hw, addr);
+
+		addr = CM_CFG_DIAGNOSTIC_IDLE_STATUS;
+
+		idle = DLB_CSR_RD(&dlb->hw, addr);
+
+		if (FIELD_GET(CM_CFG_PM_STATUS_PMSM, pm_st) == 1 &&
+		    FIELD_GET(CM_CFG_DIAGNOSTIC_IDLE_STATUS_DLB_FUNC_IDLE, idle)
+		    == 1)
+			break;
+
+		usleep_range(1000, 2000);
+	} while (--retries);
+
+	if (!retries) {
+		dev_err(&pdev->dev, "Device idle test failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
diff --git a/drivers/misc/dlb/dlb_regs.h b/drivers/misc/dlb/dlb_regs.h
new file mode 100644
index 000000000000..72f3cb22b933
--- /dev/null
+++ b/drivers/misc/dlb/dlb_regs.h
@@ -0,0 +1,119 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright(C) 2016-2020 Intel Corporation. All rights reserved. */
+
+#ifndef __DLB_REGS_H
+#define __DLB_REGS_H
+
+#include <linux/types.h>
+
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS 0xb4000004
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_RST 0x9d0fffff
+
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_CHP_PIPEIDLE		0x00000001
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_ROP_PIPEIDLE		0x00000002
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_LSP_PIPEIDLE		0x00000004
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_NALB_PIPEIDLE		0x00000008
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_AP_PIPEIDLE		0x00000010
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_DP_PIPEIDLE		0x00000020
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_QED_PIPEIDLE		0x00000040
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_DQED_PIPEIDLE		0x00000080
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_AQED_PIPEIDLE		0x00000100
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_SYS_PIPEIDLE		0x00000200
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_CHP_UNIT_IDLE		0x00000400
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_ROP_UNIT_IDLE		0x00000800
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_LSP_UNIT_IDLE		0x00001000
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_NALB_UNIT_IDLE		0x00002000
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_AP_UNIT_IDLE		0x00004000
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_DP_UNIT_IDLE		0x00008000
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_QED_UNIT_IDLE		0x00010000
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_DQED_UNIT_IDLE		0x00020000
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_AQED_UNIT_IDLE		0x00040000
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_SYS_UNIT_IDLE		0x00080000
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_RSVD1			0x00F00000
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_MSTR_CFG_RING_IDLE	0x01000000
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_MSTR_CFG_MSTR_IDLE	0x02000000
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_MSTR_FLR_CLKREQ_B		0x04000000
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_MSTR_PROC_IDLE		0x08000000
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_MSTR_PROC_IDLE_MASKED	0x10000000
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_RSVD0			0x60000000
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_DLB_FUNC_IDLE		0x80000000
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_CHP_PIPEIDLE_LOC		0
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_ROP_PIPEIDLE_LOC		1
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_LSP_PIPEIDLE_LOC		2
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_NALB_PIPEIDLE_LOC		3
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_AP_PIPEIDLE_LOC		4
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_DP_PIPEIDLE_LOC		5
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_QED_PIPEIDLE_LOC		6
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_DQED_PIPEIDLE_LOC		7
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_AQED_PIPEIDLE_LOC		8
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_SYS_PIPEIDLE_LOC		9
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_CHP_UNIT_IDLE_LOC		10
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_ROP_UNIT_IDLE_LOC		11
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_LSP_UNIT_IDLE_LOC		12
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_NALB_UNIT_IDLE_LOC	13
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_AP_UNIT_IDLE_LOC		14
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_DP_UNIT_IDLE_LOC		15
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_QED_UNIT_IDLE_LOC		16
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_DQED_UNIT_IDLE_LOC	17
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_AQED_UNIT_IDLE_LOC	18
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_SYS_UNIT_IDLE_LOC		19
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_RSVD1_LOC			20
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_MSTR_CFG_RING_IDLE_LOC	24
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_MSTR_CFG_MSTR_IDLE_LOC	25
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_MSTR_FLR_CLKREQ_B_LOC	26
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_MSTR_PROC_IDLE_LOC	27
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_MSTR_PROC_IDLE_MASKED_LOC	28
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_RSVD0_LOC			29
+#define CM_CFG_DIAGNOSTIC_IDLE_STATUS_DLB_FUNC_IDLE_LOC		31
+
+#define CM_CFG_PM_STATUS 0xb4000014
+#define CM_CFG_PM_STATUS_RST 0x100403e
+
+#define CM_CFG_PM_STATUS_PROCHOT		0x00000001
+#define CM_CFG_PM_STATUS_PGCB_DLB_IDLE		0x00000002
+#define CM_CFG_PM_STATUS_PGCB_DLB_PG_RDY_ACK_B	0x00000004
+#define CM_CFG_PM_STATUS_PMSM_PGCB_REQ_B	0x00000008
+#define CM_CFG_PM_STATUS_PGBC_PMC_PG_REQ_B	0x00000010
+#define CM_CFG_PM_STATUS_PMC_PGCB_PG_ACK_B	0x00000020
+#define CM_CFG_PM_STATUS_PMC_PGCB_FET_EN_B	0x00000040
+#define CM_CFG_PM_STATUS_PGCB_FET_EN_B		0x00000080
+#define CM_CFG_PM_STATUS_RSVZ0			0x00000100
+#define CM_CFG_PM_STATUS_RSVZ1			0x00000200
+#define CM_CFG_PM_STATUS_FUSE_FORCE_ON		0x00000400
+#define CM_CFG_PM_STATUS_FUSE_PROC_DISABLE	0x00000800
+#define CM_CFG_PM_STATUS_RSVZ2			0x00001000
+#define CM_CFG_PM_STATUS_RSVZ3			0x00002000
+#define CM_CFG_PM_STATUS_PM_FSM_D0TOD3_OK	0x00004000
+#define CM_CFG_PM_STATUS_PM_FSM_D3TOD0_OK	0x00008000
+#define CM_CFG_PM_STATUS_DLB_IN_D3		0x00010000
+#define CM_CFG_PM_STATUS_RSVZ4			0x00FE0000
+#define CM_CFG_PM_STATUS_PMSM			0xFF000000
+#define CM_CFG_PM_STATUS_PROCHOT_LOC			0
+#define CM_CFG_PM_STATUS_PGCB_DLB_IDLE_LOC		1
+#define CM_CFG_PM_STATUS_PGCB_DLB_PG_RDY_ACK_B_LOC	2
+#define CM_CFG_PM_STATUS_PMSM_PGCB_REQ_B_LOC		3
+#define CM_CFG_PM_STATUS_PGBC_PMC_PG_REQ_B_LOC		4
+#define CM_CFG_PM_STATUS_PMC_PGCB_PG_ACK_B_LOC		5
+#define CM_CFG_PM_STATUS_PMC_PGCB_FET_EN_B_LOC		6
+#define CM_CFG_PM_STATUS_PGCB_FET_EN_B_LOC		7
+#define CM_CFG_PM_STATUS_RSVZ0_LOC			8
+#define CM_CFG_PM_STATUS_RSVZ1_LOC			9
+#define CM_CFG_PM_STATUS_FUSE_FORCE_ON_LOC		10
+#define CM_CFG_PM_STATUS_FUSE_PROC_DISABLE_LOC		11
+#define CM_CFG_PM_STATUS_RSVZ2_LOC			12
+#define CM_CFG_PM_STATUS_RSVZ3_LOC			13
+#define CM_CFG_PM_STATUS_PM_FSM_D0TOD3_OK_LOC		14
+#define CM_CFG_PM_STATUS_PM_FSM_D3TOD0_OK_LOC		15
+#define CM_CFG_PM_STATUS_DLB_IN_D3_LOC			16
+#define CM_CFG_PM_STATUS_RSVZ4_LOC			17
+#define CM_CFG_PM_STATUS_PMSM_LOC			24
+
+#define CM_CFG_PM_PMCSR_DISABLE 0xb4000018
+#define CM_CFG_PM_PMCSR_DISABLE_RST 0x1
+
+#define CM_CFG_PM_PMCSR_DISABLE_DISABLE	0x00000001
+#define CM_CFG_PM_PMCSR_DISABLE_RSVZ0	0xFFFFFFFE
+#define CM_CFG_PM_PMCSR_DISABLE_DISABLE_LOC	0
+#define CM_CFG_PM_PMCSR_DISABLE_RSVZ0_LOC	1
+
+#endif /* __DLB_REGS_H */
diff --git a/drivers/misc/dlb/dlb_resource.c b/drivers/misc/dlb/dlb_resource.c
new file mode 100644
index 000000000000..c192d4fb8463
--- /dev/null
+++ b/drivers/misc/dlb/dlb_resource.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(C) 2016-2020 Intel Corporation. All rights reserved. */
+
+#include "dlb_regs.h"
+#include "dlb_main.h"
+
+static void dlb_init_fn_rsrc_lists(struct dlb_function_resources *rsrc)
+{
+	int i;
+
+	INIT_LIST_HEAD(&rsrc->avail_domains);
+	INIT_LIST_HEAD(&rsrc->used_domains);
+	INIT_LIST_HEAD(&rsrc->avail_ldb_queues);
+	INIT_LIST_HEAD(&rsrc->avail_dir_pq_pairs);
+
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++)
+		INIT_LIST_HEAD(&rsrc->avail_ldb_ports[i]);
+}
+
+static void dlb_init_domain_rsrc_lists(struct dlb_hw_domain *domain)
+{
+	int i;
+
+	INIT_LIST_HEAD(&domain->used_ldb_queues);
+	INIT_LIST_HEAD(&domain->used_dir_pq_pairs);
+	INIT_LIST_HEAD(&domain->avail_ldb_queues);
+	INIT_LIST_HEAD(&domain->avail_dir_pq_pairs);
+
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++)
+		INIT_LIST_HEAD(&domain->used_ldb_ports[i]);
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++)
+		INIT_LIST_HEAD(&domain->avail_ldb_ports[i]);
+}
+
+/**
+ * dlb_resource_free() - free device state memory
+ * @hw: dlb_hw handle for a particular device.
+ *
+ * This function frees software state pointed to by dlb_hw. This function
+ * should be called when resetting the device or unloading the driver.
+ */
+void dlb_resource_free(struct dlb_hw *hw)
+{
+	int i;
+
+	if (hw->pf.avail_hist_list_entries)
+		dlb_bitmap_free(hw->pf.avail_hist_list_entries);
+
+	for (i = 0; i < DLB_MAX_NUM_VDEVS; i++) {
+		if (hw->vdev[i].avail_hist_list_entries)
+			dlb_bitmap_free(hw->vdev[i].avail_hist_list_entries);
+	}
+}
+
+/**
+ * dlb_resource_init() - initialize the device
+ * @hw: pointer to struct dlb_hw.
+ *
+ * This function initializes the device's software state (pointed to by the hw
+ * argument) and programs global scheduling QoS registers. This function should
+ * be called during driver initialization, and the dlb_hw structure should
+ * be zero-initialized before calling the function.
+ *
+ * The dlb_hw struct must be unique per DLB 2.0 device and persist until the
+ * device is reset.
+ *
+ * Return:
+ * Returns 0 upon success, <0 otherwise.
+ */
+int dlb_resource_init(struct dlb_hw *hw)
+{
+	struct dlb_bitmap *map;
+	struct list_head *list;
+	unsigned int i;
+	int ret;
+
+	/*
+	 * For optimal load-balancing, ports that map to one or more QIDs in
+	 * common should not be in numerical sequence. The port->QID mapping is
+	 * application dependent, but the driver interleaves port IDs as much
+	 * as possible to reduce the likelihood of sequential ports mapping to
+	 * the same QID(s). This initial allocation of port IDs maximizes the
+	 * average distance between an ID and its immediate neighbors (i.e.
+	 * the distance from 1 to 0 and to 2, the distance from 2 to 1 and to
+	 * 3, etc.).
+	 */
+	const u8 init_ldb_port_allocation[DLB_MAX_NUM_LDB_PORTS] = {
+		0,  7,  14,  5, 12,  3, 10,  1,  8, 15,  6, 13,  4, 11,  2,  9,
+		16, 23, 30, 21, 28, 19, 26, 17, 24, 31, 22, 29, 20, 27, 18, 25,
+		32, 39, 46, 37, 44, 35, 42, 33, 40, 47, 38, 45, 36, 43, 34, 41,
+		48, 55, 62, 53, 60, 51, 58, 49, 56, 63, 54, 61, 52, 59, 50, 57,
+	};
+
+	dlb_init_fn_rsrc_lists(&hw->pf);
+
+	for (i = 0; i < DLB_MAX_NUM_VDEVS; i++)
+		dlb_init_fn_rsrc_lists(&hw->vdev[i]);
+
+	for (i = 0; i < DLB_MAX_NUM_DOMAINS; i++) {
+		dlb_init_domain_rsrc_lists(&hw->domains[i]);
+		hw->domains[i].parent_func = &hw->pf;
+	}
+
+	/* Give all resources to the PF driver */
+	hw->pf.num_avail_domains = DLB_MAX_NUM_DOMAINS;
+	for (i = 0; i < hw->pf.num_avail_domains; i++) {
+		list = &hw->domains[i].func_list;
+
+		list_add(list, &hw->pf.avail_domains);
+	}
+
+	hw->pf.num_avail_ldb_queues = DLB_MAX_NUM_LDB_QUEUES;
+	for (i = 0; i < hw->pf.num_avail_ldb_queues; i++) {
+		list = &hw->rsrcs.ldb_queues[i].func_list;
+
+		list_add(list, &hw->pf.avail_ldb_queues);
+	}
+
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++)
+		hw->pf.num_avail_ldb_ports[i] =
+			DLB_MAX_NUM_LDB_PORTS / DLB_NUM_COS_DOMAINS;
+
+	for (i = 0; i < DLB_MAX_NUM_LDB_PORTS; i++) {
+		int cos_id = i >> DLB_NUM_COS_DOMAINS;
+		struct dlb_ldb_port *port;
+
+		port = &hw->rsrcs.ldb_ports[init_ldb_port_allocation[i]];
+
+		list_add(&port->func_list, &hw->pf.avail_ldb_ports[cos_id]);
+	}
+
+	hw->pf.num_avail_dir_pq_pairs = DLB_MAX_NUM_DIR_PORTS;
+	for (i = 0; i < hw->pf.num_avail_dir_pq_pairs; i++) {
+		list = &hw->rsrcs.dir_pq_pairs[i].func_list;
+
+		list_add(list, &hw->pf.avail_dir_pq_pairs);
+	}
+
+	hw->pf.num_avail_qed_entries = DLB_MAX_NUM_LDB_CREDITS;
+	hw->pf.num_avail_dqed_entries = DLB_MAX_NUM_DIR_CREDITS;
+	hw->pf.num_avail_aqed_entries = DLB_MAX_NUM_AQED_ENTRIES;
+
+	ret = dlb_bitmap_alloc(&hw->pf.avail_hist_list_entries,
+			       DLB_MAX_NUM_HIST_LIST_ENTRIES);
+	if (ret)
+		goto unwind;
+
+	map = hw->pf.avail_hist_list_entries;
+	bitmap_fill(map->map, map->len);
+
+	for (i = 0; i < DLB_MAX_NUM_VDEVS; i++) {
+		ret = dlb_bitmap_alloc(&hw->vdev[i].avail_hist_list_entries,
+				       DLB_MAX_NUM_HIST_LIST_ENTRIES);
+		if (ret)
+			goto unwind;
+
+		map = hw->vdev[i].avail_hist_list_entries;
+		bitmap_zero(map->map, map->len);
+	}
+
+	/* Initialize the hardware resource IDs */
+	for (i = 0; i < DLB_MAX_NUM_DOMAINS; i++)
+		hw->domains[i].id = i;
+
+	for (i = 0; i < DLB_MAX_NUM_LDB_QUEUES; i++)
+		hw->rsrcs.ldb_queues[i].id = i;
+
+	for (i = 0; i < DLB_MAX_NUM_LDB_PORTS; i++)
+		hw->rsrcs.ldb_ports[i].id = i;
+
+	for (i = 0; i < DLB_MAX_NUM_DIR_PORTS; i++)
+		hw->rsrcs.dir_pq_pairs[i].id = i;
+
+	for (i = 0; i < DLB_MAX_NUM_SEQUENCE_NUMBER_GROUPS; i++) {
+		hw->rsrcs.sn_groups[i].id = i;
+		/* Default mode (0) is 64 sequence numbers per queue */
+		hw->rsrcs.sn_groups[i].mode = 0;
+		hw->rsrcs.sn_groups[i].sequence_numbers_per_queue = 64;
+		hw->rsrcs.sn_groups[i].slot_use_bitmap = 0;
+	}
+
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++)
+		hw->cos_reservation[i] = 100 / DLB_NUM_COS_DOMAINS;
+
+	return 0;
+
+unwind:
+	dlb_resource_free(hw);
+
+	return ret;
+}
+
+/**
+ * dlb_clr_pmcsr_disable() - power on bulk of DLB 2.0 logic
+ * @hw: dlb_hw handle for a particular device.
+ *
+ * Clearing the PMCSR must be done at initialization to make the device fully
+ * operational.
+ */
+void dlb_clr_pmcsr_disable(struct dlb_hw *hw)
+{
+	u32 pmcsr_dis;
+
+	pmcsr_dis = DLB_CSR_RD(hw, CM_CFG_PM_PMCSR_DISABLE);
+
+	/* Clear register bits */
+	pmcsr_dis &= ~CM_CFG_PM_PMCSR_DISABLE_DISABLE;
+
+	DLB_CSR_WR(hw, CM_CFG_PM_PMCSR_DISABLE, pmcsr_dis);
+}
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [RFC PATCH v12 04/17] dlb: add configfs interface and scheduling domain directory
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
                   ` (2 preceding siblings ...)
  2021-12-21  6:50 ` [RFC PATCH v12 03/17] dlb: add resource and device initialization Mike Ximing Chen
@ 2021-12-21  6:50 ` Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 05/17] dlb: add scheduling domain configuration Mike Ximing Chen
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

Introduce the dlb device level configfs interface. Each dlb device has a
configfs node at /sys/kernel/config/dlb/dlb%N, which is used to control
and configure the device.

Also add the scheduling domain directory in the device node of configfs.
A scheduling domain serves as a HW container of DLB resources -- e.g.
ports, queues, and credits -- with the property that a port can only
enqueue to and dequeue from queues within its domain. A scheduling domain
is created on-demand by a user-space application, whose request includes
the DLB resource allocation.

To create a HW scheduling domain, a user creates a domain directory using
"mkdir" in the configfs, and configure the resources needed (such as number
of ports and queues, and credits, etc)  by writing to the attribute files
in the directory. A final write of "1" to "create" file triggers creation
of a scheduling domain in DLB.

The hardware operation for scheduling domain creation will be added in a
subsequent commit.

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
---
 drivers/misc/dlb/Makefile       |   2 +-
 drivers/misc/dlb/dlb_args.h     |  60 +++++++
 drivers/misc/dlb/dlb_configfs.c | 299 ++++++++++++++++++++++++++++++++
 drivers/misc/dlb/dlb_configfs.h |  39 +++++
 drivers/misc/dlb/dlb_main.c     |   9 +
 drivers/misc/dlb/dlb_main.h     |  10 ++
 drivers/misc/dlb/dlb_resource.c |  10 ++
 7 files changed, 428 insertions(+), 1 deletion(-)
 create mode 100644 drivers/misc/dlb/dlb_args.h
 create mode 100644 drivers/misc/dlb/dlb_configfs.c
 create mode 100644 drivers/misc/dlb/dlb_configfs.h

diff --git a/drivers/misc/dlb/Makefile b/drivers/misc/dlb/Makefile
index 66d885619e66..1567bfdfc7a7 100644
--- a/drivers/misc/dlb/Makefile
+++ b/drivers/misc/dlb/Makefile
@@ -3,4 +3,4 @@
 obj-$(CONFIG_INTEL_DLB) := dlb.o
 
 dlb-objs := dlb_main.o
-dlb-objs += dlb_pf_ops.o dlb_resource.o
+dlb-objs += dlb_pf_ops.o dlb_resource.o dlb_configfs.o
diff --git a/drivers/misc/dlb/dlb_args.h b/drivers/misc/dlb/dlb_args.h
new file mode 100644
index 000000000000..a7541a6b0ebe
--- /dev/null
+++ b/drivers/misc/dlb/dlb_args.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright(C) 2016-2020 Intel Corporation. All rights reserved. */
+
+#ifndef __DLB_ARGS_H
+#define __DLB_ARGS_H
+
+struct dlb_cmd_response {
+	__u32 status; /* Interpret using enum dlb_error */
+	__u32 id;
+};
+
+#define DLB_DEVICE_VERSION(x) (((x) >> 8) & 0xFF)
+#define DLB_DEVICE_REVISION(x) ((x) & 0xFF)
+
+/*****************************************************/
+/* 'dlb' device level control/access data structures */
+/*****************************************************/
+
+/*
+ * dlb_create_sched_domain_args: Used to create a DLB 2.0 scheduling domain
+ *	and reserve its hardware resources.
+ *
+ * Output parameters:
+ * @response.status: Detailed error code. In certain cases, such as if the
+ *	request arg is invalid, the driver won't set status.
+ * @response.id: domain ID.
+ * @domain_fd: file descriptor for performing the domain's reset operation.
+ *
+ * Input parameters:
+ * @num_ldb_queues: Number of load-balanced queues.
+ * @num_ldb_ports: Number of load-balanced ports that can be allocated from
+ *	any class-of-service with available ports.
+ * @num_dir_ports: Number of directed ports. A directed port has one directed
+ *	queue, so no num_dir_queues argument is necessary.
+ * @num_atomic_inflights: This specifies the amount of temporary atomic QE
+ *	storage for the domain. This storage is divided among the domain's
+ *	load-balanced queues that are configured for atomic scheduling.
+ * @num_hist_list_entries: Amount of history list storage. This is divided
+ *	among the domain's CQs.
+ * @num_ldb_credits: Amount of load-balanced QE storage (QED). QEs occupy this
+ *	space until they are scheduled to a load-balanced CQ. One credit
+ *	represents the storage for one QE.
+ * @num_dir_credits: Amount of directed QE storage (DQED). QEs occupy this
+ *	space until they are scheduled to a directed CQ. One credit represents
+ *	the storage for one QE.
+ */
+struct dlb_create_sched_domain_args {
+	/* Output parameters */
+	struct dlb_cmd_response response;
+	__u32 domain_fd;
+	/* Input parameters */
+	__u32 num_ldb_queues;
+	__u32 num_ldb_ports;
+	__u32 num_dir_ports;
+	__u32 num_atomic_inflights;
+	__u32 num_hist_list_entries;
+	__u32 num_ldb_credits;
+	__u32 num_dir_credits;
+};
+#endif /* DLB_ARGS_H */
diff --git a/drivers/misc/dlb/dlb_configfs.c b/drivers/misc/dlb/dlb_configfs.c
new file mode 100644
index 000000000000..bdabf3c6444f
--- /dev/null
+++ b/drivers/misc/dlb/dlb_configfs.c
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright(c) 2017-2020 Intel Corporation
+
+#include <linux/configfs.h>
+#include "dlb_configfs.h"
+
+struct dlb_device_configfs dlb_dev_configfs[16];
+
+static int dlb_configfs_create_sched_domain(struct dlb *dlb,
+					    void *karg)
+{
+	struct dlb_create_sched_domain_args *arg = karg;
+	struct dlb_cmd_response response = {0};
+	int ret;
+
+	mutex_lock(&dlb->resource_mutex);
+
+	ret = dlb_hw_create_sched_domain(&dlb->hw, arg, &response);
+
+	mutex_unlock(&dlb->resource_mutex);
+
+	memcpy(karg, &response, sizeof(response));
+
+	return ret;
+}
+
+/*
+ * Configfs directory structure for dlb driver implementation:
+ *
+ *                             config
+ *                                |
+ *                               dlb
+ *                                |
+ *                        +------+------+------+------
+ *                        |      |      |      |
+ *                       dlb0   dlb1   dlb2   dlb3  ...
+ *                        |
+ *                +-----------+--+--------+-------
+ *                |           |           |
+ *             domain0     domain1     domain2   ...
+ *                |
+ *        +-------+-----+------------+---------------+------------+----------
+ *        |             |            |               |            |
+ * num_ldb_queues     port0         port1   ...    queue0       queue1   ...
+ * num_ldb_ports        |		             |
+ * ...                is_ldb                   num_sequence_numbers
+ * create             cq_depth                 num_qid_inflights
+ * start              ...                      num_atomic_iflights
+ *                    enable                   ...
+ *                    ...
+ */
+
+/*
+ * ------ Configfs for dlb domains---------
+ *
+ * These are the templates for show and store functions in domain
+ * groups/directories, which minimizes replication of boilerplate
+ * code to copy arguments. Most attributes, use the simple template.
+ * "name" is the attribute name in the group.
+ */
+#define DLB_CONFIGFS_DOMAIN_SHOW(name)				\
+static ssize_t dlb_cfs_domain_##name##_show(			\
+	struct config_item *item,				\
+	char *page)						\
+{								\
+	return sprintf(page, "%u\n",				\
+		       to_dlb_cfs_domain(item)->name);		\
+}								\
+
+#define DLB_CONFIGFS_DOMAIN_STORE(name)				\
+static ssize_t dlb_cfs_domain_##name##_store(			\
+	struct config_item *item,				\
+	const char *page,					\
+	size_t count)						\
+{								\
+	int ret;						\
+	struct dlb_cfs_domain *dlb_cfs_domain =			\
+				to_dlb_cfs_domain(item);	\
+								\
+	ret = kstrtoint(page, 10, &dlb_cfs_domain->name);	\
+	if (ret)						\
+		return ret;					\
+								\
+	return count;						\
+}								\
+
+DLB_CONFIGFS_DOMAIN_SHOW(status)
+DLB_CONFIGFS_DOMAIN_SHOW(domain_id)
+DLB_CONFIGFS_DOMAIN_SHOW(num_ldb_queues)
+DLB_CONFIGFS_DOMAIN_SHOW(num_ldb_ports)
+DLB_CONFIGFS_DOMAIN_SHOW(num_dir_ports)
+DLB_CONFIGFS_DOMAIN_SHOW(num_atomic_inflights)
+DLB_CONFIGFS_DOMAIN_SHOW(num_hist_list_entries)
+DLB_CONFIGFS_DOMAIN_SHOW(num_ldb_credits)
+DLB_CONFIGFS_DOMAIN_SHOW(num_dir_credits)
+DLB_CONFIGFS_DOMAIN_SHOW(create)
+
+DLB_CONFIGFS_DOMAIN_STORE(num_ldb_queues)
+DLB_CONFIGFS_DOMAIN_STORE(num_ldb_ports)
+DLB_CONFIGFS_DOMAIN_STORE(num_dir_ports)
+DLB_CONFIGFS_DOMAIN_STORE(num_atomic_inflights)
+DLB_CONFIGFS_DOMAIN_STORE(num_hist_list_entries)
+DLB_CONFIGFS_DOMAIN_STORE(num_ldb_credits)
+DLB_CONFIGFS_DOMAIN_STORE(num_dir_credits)
+
+static ssize_t dlb_cfs_domain_create_store(struct config_item *item,
+					   const char *page, size_t count)
+{
+	struct dlb_cfs_domain *dlb_cfs_domain = to_dlb_cfs_domain(item);
+	struct dlb_device_configfs *dlb_dev_configfs;
+	struct dlb *dlb;
+	int ret, create_in;
+
+	dlb_dev_configfs = container_of(dlb_cfs_domain->dev_grp,
+					struct dlb_device_configfs,
+					dev_group);
+	dlb = dlb_dev_configfs->dlb;
+	if (!dlb)
+		return -EINVAL;
+
+	ret = kstrtoint(page, 10, &create_in);
+	if (ret)
+		return ret;
+
+	/* Writing 1 to the 'create' triggers scheduling domain creation */
+	if (create_in == 1 && dlb_cfs_domain->create == 0) {
+		struct dlb_create_sched_domain_args args = {0};
+
+		memcpy(&args.response, &dlb_cfs_domain->status,
+		       sizeof(struct dlb_create_sched_domain_args));
+
+		dev_dbg(dlb->dev,
+			"Create domain: %s\n",
+			dlb_cfs_domain->group.cg_item.ci_namebuf);
+
+		ret = dlb_configfs_create_sched_domain(dlb, &args);
+
+		dlb_cfs_domain->status = args.response.status;
+		dlb_cfs_domain->domain_id = args.response.id;
+
+		if (ret) {
+			dev_err(dlb->dev,
+				"create sched domain failed: ret=%d\n", ret);
+			return ret;
+		}
+
+		dlb_cfs_domain->create = 1;
+	}
+
+	return count;
+}
+
+CONFIGFS_ATTR_RO(dlb_cfs_domain_, status);
+CONFIGFS_ATTR_RO(dlb_cfs_domain_, domain_id);
+CONFIGFS_ATTR(dlb_cfs_domain_, num_ldb_queues);
+CONFIGFS_ATTR(dlb_cfs_domain_, num_ldb_ports);
+CONFIGFS_ATTR(dlb_cfs_domain_, num_dir_ports);
+CONFIGFS_ATTR(dlb_cfs_domain_, num_atomic_inflights);
+CONFIGFS_ATTR(dlb_cfs_domain_, num_hist_list_entries);
+CONFIGFS_ATTR(dlb_cfs_domain_, num_ldb_credits);
+CONFIGFS_ATTR(dlb_cfs_domain_, num_dir_credits);
+CONFIGFS_ATTR(dlb_cfs_domain_, create);
+
+static struct configfs_attribute *dlb_cfs_domain_attrs[] = {
+	&dlb_cfs_domain_attr_status,
+	&dlb_cfs_domain_attr_domain_id,
+	&dlb_cfs_domain_attr_num_ldb_queues,
+	&dlb_cfs_domain_attr_num_ldb_ports,
+	&dlb_cfs_domain_attr_num_dir_ports,
+	&dlb_cfs_domain_attr_num_atomic_inflights,
+	&dlb_cfs_domain_attr_num_hist_list_entries,
+	&dlb_cfs_domain_attr_num_ldb_credits,
+	&dlb_cfs_domain_attr_num_dir_credits,
+	&dlb_cfs_domain_attr_create,
+
+	NULL,
+};
+
+static void dlb_cfs_domain_release(struct config_item *item)
+{
+	kfree(to_dlb_cfs_domain(item));
+}
+
+static struct configfs_item_operations dlb_cfs_domain_item_ops = {
+	.release	= dlb_cfs_domain_release,
+};
+
+static const struct config_item_type dlb_cfs_domain_type = {
+	.ct_item_ops	= &dlb_cfs_domain_item_ops,
+	.ct_attrs	= dlb_cfs_domain_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+/*
+ *--------- dlb device level configfs -----------
+ *
+ * Scheduling domains are created in the device-level configfs driectory.
+ */
+static struct config_group *dlb_cfs_device_make_domain(struct config_group *group,
+						       const char *name)
+{
+	struct dlb_cfs_domain *dlb_cfs_domain;
+
+	dlb_cfs_domain = kzalloc(sizeof(*dlb_cfs_domain), GFP_KERNEL);
+	if (!dlb_cfs_domain)
+		return ERR_PTR(-ENOMEM);
+
+	dlb_cfs_domain->dev_grp = group;
+
+	config_group_init_type_name(&dlb_cfs_domain->group, name,
+				    &dlb_cfs_domain_type);
+
+	return &dlb_cfs_domain->group;
+}
+
+static struct configfs_group_operations dlb_cfs_device_group_ops = {
+	.make_group     = dlb_cfs_device_make_domain,
+};
+
+static const struct config_item_type dlb_cfs_device_type = {
+	/* No need for _item_ops() at the device-level, and default
+	 * attribute.
+	 * .ct_item_ops	= &dlb_cfs_device_item_ops,
+	 * .ct_attrs	= dlb_cfs_device_attrs,
+	 */
+
+	.ct_group_ops	= &dlb_cfs_device_group_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+/*------------------- dlb group subsystem for configfs ----------------
+ *
+ * we only need a simple configfs item type here that does not let
+ * user to create new entry. The group for each dlb device will be
+ * generated when the device is detected in dlb_probe().
+ */
+
+static const struct config_item_type dlb_device_group_type = {
+	.ct_owner	= THIS_MODULE,
+};
+
+/* dlb group subsys in configfs */
+static struct configfs_subsystem dlb_device_group_subsys = {
+	.su_group = {
+		.cg_item = {
+			.ci_namebuf = "dlb",
+			.ci_type = &dlb_device_group_type,
+		},
+	},
+};
+
+/* Create a configfs directory dlbN for each dlb device probed
+ * in dlb_probe()
+ */
+int dlb_configfs_create_device(struct dlb *dlb)
+{
+	struct config_group *parent_group, *dev_grp;
+	char device_name[16];
+	int ret = 0;
+
+	snprintf(device_name, 6, "dlb%d", dlb->id);
+	parent_group = &dlb_device_group_subsys.su_group;
+
+	dev_grp = &dlb_dev_configfs[dlb->id].dev_group;
+	config_group_init_type_name(dev_grp,
+				    device_name,
+				    &dlb_cfs_device_type);
+	ret = configfs_register_group(parent_group, dev_grp);
+
+	if (ret)
+		return ret;
+
+	dlb_dev_configfs[dlb->id].dlb = dlb;
+
+	return ret;
+}
+
+int configfs_dlb_init(void)
+{
+	struct configfs_subsystem *subsys;
+	int ret;
+
+	/* set up and register configfs subsystem for dlb */
+	subsys = &dlb_device_group_subsys;
+	config_group_init(&subsys->su_group);
+	mutex_init(&subsys->su_mutex);
+	ret = configfs_register_subsystem(subsys);
+	if (ret) {
+		pr_err("Error %d while registering subsystem %s\n",
+		       ret, subsys->su_group.cg_item.ci_namebuf);
+	}
+
+	return ret;
+}
+
+void configfs_dlb_exit(void)
+{
+	configfs_unregister_subsystem(&dlb_device_group_subsys);
+}
diff --git a/drivers/misc/dlb/dlb_configfs.h b/drivers/misc/dlb/dlb_configfs.h
new file mode 100644
index 000000000000..03019e046429
--- /dev/null
+++ b/drivers/misc/dlb/dlb_configfs.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright(C) 2016-2020 Intel Corporation. All rights reserved. */
+
+#ifndef __DLB_CONFIGFS_H
+#define __DLB_CONFIGFS_H
+
+#include "dlb_main.h"
+
+struct dlb_device_configfs {
+	struct config_group dev_group;
+	struct dlb *dlb;
+};
+
+struct dlb_cfs_domain {
+	struct config_group group;
+	struct config_group *dev_grp;
+	unsigned int status;
+	unsigned int domain_id;
+	/* Input parameters */
+	unsigned int domain_fd;
+	unsigned int num_ldb_queues;
+	unsigned int num_ldb_ports;
+	unsigned int num_dir_ports;
+	unsigned int num_atomic_inflights;
+	unsigned int num_hist_list_entries;
+	unsigned int num_ldb_credits;
+	unsigned int num_dir_credits;
+	unsigned int create;
+
+};
+
+static inline
+struct dlb_cfs_domain *to_dlb_cfs_domain(struct config_item *item)
+{
+	return container_of(to_config_group(item),
+			    struct dlb_cfs_domain, group);
+}
+
+#endif /* DLB_CONFIGFS_H */
diff --git a/drivers/misc/dlb/dlb_main.c b/drivers/misc/dlb/dlb_main.c
index 136e8b54ea2b..1bd9ca7772a9 100644
--- a/drivers/misc/dlb/dlb_main.c
+++ b/drivers/misc/dlb/dlb_main.c
@@ -128,6 +128,10 @@ static int dlb_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
 	if (ret)
 		goto dma_set_mask_fail;
 
+	ret = dlb_configfs_create_device(dlb);
+	if (ret)
+		goto configfs_create_fail;
+
 	/*
 	 * PM enable must be done before any other MMIO accesses, and this
 	 * setting is persistent across device reset.
@@ -157,6 +161,7 @@ static int dlb_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
 resource_init_fail:
 dlb_reset_fail:
 wait_for_device_ready_fail:
+configfs_create_fail:
 dma_set_mask_fail:
 	device_destroy(dlb_class, dlb->dev_number);
 map_pci_bar_fail:
@@ -225,6 +230,8 @@ static int __init dlb_init_module(void)
 	if (err)
 		goto cdev_add_fail;
 
+	configfs_dlb_init();
+
 	err = pci_register_driver(&dlb_pci_driver);
 	if (err < 0) {
 		pr_err("dlb: pci_register_driver() returned %d\n", err);
@@ -248,6 +255,8 @@ static void __exit dlb_exit_module(void)
 {
 	pci_unregister_driver(&dlb_pci_driver);
 
+	configfs_dlb_exit();
+
 	cdev_del(&dlb_cdev);
 
 	unregister_chrdev_region(dlb_devt, DLB_MAX_NUM_DEVICES);
diff --git a/drivers/misc/dlb/dlb_main.h b/drivers/misc/dlb/dlb_main.h
index a65b12b75b4c..4921333a6ec3 100644
--- a/drivers/misc/dlb/dlb_main.h
+++ b/drivers/misc/dlb/dlb_main.h
@@ -13,6 +13,8 @@
 #include <linux/types.h>
 #include <linux/bitfield.h>
 
+#include "dlb_args.h"
+
 /*
  * Hardware related #defines and data structures.
  *
@@ -327,6 +329,14 @@ static inline void dlb_bitmap_free(struct dlb_bitmap *bitmap)
 /* Prototypes for dlb_resource.c */
 int dlb_resource_init(struct dlb_hw *hw);
 void dlb_resource_free(struct dlb_hw *hw);
+int dlb_hw_create_sched_domain(struct dlb_hw *hw,
+			       struct dlb_create_sched_domain_args *args,
+			       struct dlb_cmd_response *resp);
 void dlb_clr_pmcsr_disable(struct dlb_hw *hw);
 
+/* Prototypes for dlb_configfs.c */
+int dlb_configfs_create_device(struct dlb *dlb);
+int configfs_dlb_init(void);
+void configfs_dlb_exit(void);
+
 #endif /* __DLB_MAIN_H */
diff --git a/drivers/misc/dlb/dlb_resource.c b/drivers/misc/dlb/dlb_resource.c
index c192d4fb8463..7d7ebf3db292 100644
--- a/drivers/misc/dlb/dlb_resource.c
+++ b/drivers/misc/dlb/dlb_resource.c
@@ -190,6 +190,16 @@ int dlb_resource_init(struct dlb_hw *hw)
 	return ret;
 }
 
+int dlb_hw_create_sched_domain(struct dlb_hw *hw,
+			       struct dlb_create_sched_domain_args *args,
+			       struct dlb_cmd_response *resp)
+{
+	resp->id = 0;
+	resp->status = 0;
+
+	return 0;
+}
+
 /**
  * dlb_clr_pmcsr_disable() - power on bulk of DLB 2.0 logic
  * @hw: dlb_hw handle for a particular device.
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [RFC PATCH v12 05/17] dlb: add scheduling domain configuration
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
                   ` (3 preceding siblings ...)
  2021-12-21  6:50 ` [RFC PATCH v12 04/17] dlb: add configfs interface and scheduling domain directory Mike Ximing Chen
@ 2021-12-21  6:50 ` Mike Ximing Chen
  2021-12-21 12:18   ` kernel test robot
  2021-12-21  6:50 ` [RFC PATCH v12 06/17] dlb: add domain software reset Mike Ximing Chen
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

Add support for configuring a scheduling domain, creating the domain fd,
and reserving the domain's resources.

When a user requests to create a scheduling domain via configfs, the
requested resources are validated against the number currently available,
and then reserved for the scheduling domain. An anonymous file descriptor
for the domain is created and installed in the calling process's file
descriptor table.

The driver maintains a reference count for each scheduling domain,
incrementing it each time user-space requests a file descriptor for a dlb
port access and decrementing it in the file's release callback.

When the reference count transitions from 1->0 the driver automatically
resets the scheduling domain's resources and makes them available for use
by future applications. This ensures that applications that crash without
explicitly cleaning up do not orphan device resources. The code to perform
the domain reset will be added in subsequent commits.

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
---
 drivers/misc/dlb/dlb_configfs.c |  46 ++-
 drivers/misc/dlb/dlb_main.c     |  68 ++++
 drivers/misc/dlb/dlb_main.h     | 128 ++++++++
 drivers/misc/dlb/dlb_regs.h     |  18 ++
 drivers/misc/dlb/dlb_resource.c | 528 +++++++++++++++++++++++++++++++-
 include/uapi/linux/dlb.h        |  22 ++
 6 files changed, 808 insertions(+), 2 deletions(-)
 create mode 100644 include/uapi/linux/dlb.h

diff --git a/drivers/misc/dlb/dlb_configfs.c b/drivers/misc/dlb/dlb_configfs.c
index bdabf3c6444f..7e5db0390a6a 100644
--- a/drivers/misc/dlb/dlb_configfs.c
+++ b/drivers/misc/dlb/dlb_configfs.c
@@ -1,7 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0-only
 // Copyright(c) 2017-2020 Intel Corporation
 
+#include <linux/anon_inodes.h>
+#include <linux/version.h>
 #include <linux/configfs.h>
+#include <linux/fdtable.h>
 #include "dlb_configfs.h"
 
 struct dlb_device_configfs dlb_dev_configfs[16];
@@ -11,12 +14,38 @@ static int dlb_configfs_create_sched_domain(struct dlb *dlb,
 {
 	struct dlb_create_sched_domain_args *arg = karg;
 	struct dlb_cmd_response response = {0};
-	int ret;
+	struct dlb_domain *domain;
+	u32 flags = O_RDONLY;
+	int ret, fd;
 
 	mutex_lock(&dlb->resource_mutex);
 
 	ret = dlb_hw_create_sched_domain(&dlb->hw, arg, &response);
+	if (ret)
+		goto unlock;
+
+	ret = dlb_init_domain(dlb, response.id);
+	if (ret)
+		goto unlock;
 
+	domain = dlb->sched_domains[response.id];
+
+	if (dlb->f->f_mode & FMODE_WRITE)
+		flags = O_RDWR;
+
+	fd = anon_inode_getfd("[dlbdomain]", &dlb_domain_fops,
+			      domain, flags);
+
+	if (fd < 0) {
+		dev_err(dlb->dev, "Failed to get anon fd.\n");
+		kref_put(&domain->refcnt, dlb_free_domain);
+		ret = fd;
+		goto unlock;
+	}
+
+	arg->domain_fd = fd;
+
+unlock:
 	mutex_unlock(&dlb->resource_mutex);
 
 	memcpy(karg, &response, sizeof(response));
@@ -84,6 +113,7 @@ static ssize_t dlb_cfs_domain_##name##_store(			\
 	return count;						\
 }								\
 
+DLB_CONFIGFS_DOMAIN_SHOW(domain_fd)
 DLB_CONFIGFS_DOMAIN_SHOW(status)
 DLB_CONFIGFS_DOMAIN_SHOW(domain_id)
 DLB_CONFIGFS_DOMAIN_SHOW(num_ldb_queues)
@@ -137,6 +167,7 @@ static ssize_t dlb_cfs_domain_create_store(struct config_item *item,
 
 		dlb_cfs_domain->status = args.response.status;
 		dlb_cfs_domain->domain_id = args.response.id;
+		dlb_cfs_domain->domain_fd = args.domain_fd;
 
 		if (ret) {
 			dev_err(dlb->dev,
@@ -145,11 +176,23 @@ static ssize_t dlb_cfs_domain_create_store(struct config_item *item,
 		}
 
 		dlb_cfs_domain->create = 1;
+	} else if (create_in == 0 && dlb_cfs_domain->create == 1) {
+		dev_dbg(dlb->dev,
+			"Close domain: %s\n",
+			dlb_cfs_domain->group.cg_item.ci_namebuf);
+
+		ret = close_fd(dlb_cfs_domain->domain_fd);
+		if (ret)
+			dev_err(dlb->dev,
+				"close sched domain failed: ret=%d\n", ret);
+
+		dlb_cfs_domain->create = 0;
 	}
 
 	return count;
 }
 
+CONFIGFS_ATTR_RO(dlb_cfs_domain_, domain_fd);
 CONFIGFS_ATTR_RO(dlb_cfs_domain_, status);
 CONFIGFS_ATTR_RO(dlb_cfs_domain_, domain_id);
 CONFIGFS_ATTR(dlb_cfs_domain_, num_ldb_queues);
@@ -162,6 +205,7 @@ CONFIGFS_ATTR(dlb_cfs_domain_, num_dir_credits);
 CONFIGFS_ATTR(dlb_cfs_domain_, create);
 
 static struct configfs_attribute *dlb_cfs_domain_attrs[] = {
+	&dlb_cfs_domain_attr_domain_fd,
 	&dlb_cfs_domain_attr_status,
 	&dlb_cfs_domain_attr_domain_id,
 	&dlb_cfs_domain_attr_num_ldb_queues,
diff --git a/drivers/misc/dlb/dlb_main.c b/drivers/misc/dlb/dlb_main.c
index 1bd9ca7772a9..3c949d9b4cf0 100644
--- a/drivers/misc/dlb/dlb_main.c
+++ b/drivers/misc/dlb/dlb_main.c
@@ -61,8 +61,76 @@ static int dlb_device_create(struct dlb *dlb, struct pci_dev *pdev)
 /****** Char dev callbacks ******/
 /********************************/
 
+static int dlb_open(struct inode *i, struct file *f)
+{
+	struct dlb *dlb;
+
+	mutex_lock(&dlb_ids_lock);
+	dlb = idr_find(&dlb_ids, iminor(i));
+	mutex_unlock(&dlb_ids_lock);
+
+	f->private_data = dlb;
+	dlb->f = f;
+
+	return 0;
+}
+
 static const struct file_operations dlb_fops = {
 	.owner   = THIS_MODULE,
+	.open    = dlb_open,
+};
+
+int dlb_init_domain(struct dlb *dlb, u32 domain_id)
+{
+	struct dlb_domain *domain;
+
+	domain = kzalloc(sizeof(*domain), GFP_KERNEL);
+	if (!domain)
+		return -ENOMEM;
+
+	domain->id = domain_id;
+
+	kref_init(&domain->refcnt);
+	domain->dlb = dlb;
+
+	dlb->sched_domains[domain_id] = domain;
+
+	return 0;
+}
+
+static int __dlb_free_domain(struct dlb_domain *domain)
+{
+	struct dlb *dlb = domain->dlb;
+
+	dlb->sched_domains[domain->id] = NULL;
+
+	kfree(domain);
+
+	return 0;
+}
+
+void dlb_free_domain(struct kref *kref)
+{
+	__dlb_free_domain(container_of(kref, struct dlb_domain, refcnt));
+}
+
+static int dlb_domain_close(struct inode *i, struct file *f)
+{
+	struct dlb_domain *domain = f->private_data;
+	struct dlb *dlb = domain->dlb;
+
+	mutex_lock(&dlb->resource_mutex);
+
+	kref_put(&domain->refcnt, dlb_free_domain);
+
+	mutex_unlock(&dlb->resource_mutex);
+
+	return 0;
+}
+
+const struct file_operations dlb_domain_fops = {
+	.owner   = THIS_MODULE,
+	.release = dlb_domain_close,
 };
 
 /**********************************/
diff --git a/drivers/misc/dlb/dlb_main.h b/drivers/misc/dlb/dlb_main.h
index 4921333a6ec3..6c9b9cce148e 100644
--- a/drivers/misc/dlb/dlb_main.h
+++ b/drivers/misc/dlb/dlb_main.h
@@ -13,6 +13,7 @@
 #include <linux/types.h>
 #include <linux/bitfield.h>
 
+#include <uapi/linux/dlb.h>
 #include "dlb_args.h"
 
 /*
@@ -248,10 +249,20 @@ int dlb_pf_init_driver_state(struct dlb *dlb);
 void dlb_pf_enable_pm(struct dlb *dlb);
 int dlb_pf_wait_for_device_ready(struct dlb *dlb, struct pci_dev *pdev);
 
+extern const struct file_operations dlb_domain_fops;
+
+struct dlb_domain {
+	struct dlb *dlb;
+	struct kref refcnt;
+	u8 id;
+};
+
 struct dlb {
 	struct pci_dev *pdev;
 	struct dlb_hw hw;
 	struct device *dev;
+	struct dlb_domain *sched_domains[DLB_MAX_NUM_DOMAINS];
+	struct file *f;
 	/*
 	 * The resource mutex serializes access to driver data structures and
 	 * hardware registers.
@@ -326,6 +337,123 @@ static inline void dlb_bitmap_free(struct dlb_bitmap *bitmap)
 	kfree(bitmap);
 }
 
+/**
+ * dlb_bitmap_clear_range() - clear a range of bitmap entries
+ * @bitmap: pointer to dlb_bitmap structure.
+ * @bit: starting bit index.
+ * @len: length of the range.
+ *
+ * Return:
+ * Returns 0 upon success, < 0 otherwise.
+ *
+ * Errors:
+ * EINVAL - bitmap is NULL or is uninitialized, or the range exceeds the bitmap
+ *	    length.
+ */
+static inline int dlb_bitmap_clear_range(struct dlb_bitmap *bitmap,
+					 unsigned int bit,
+					 unsigned int len)
+{
+	if (!bitmap || !bitmap->map)
+		return -EINVAL;
+
+	if (bitmap->len <= bit)
+		return -EINVAL;
+
+	bitmap_clear(bitmap->map, bit, len);
+
+	return 0;
+}
+
+/**
+ * dlb_bitmap_find_set_bit_range() - find an range of set bits
+ * @bitmap: pointer to dlb_bitmap structure.
+ * @len: length of the range.
+ *
+ * This function looks for a range of set bits of length @len.
+ *
+ * Return:
+ * Returns the base bit index upon success, < 0 otherwise.
+ *
+ * Errors:
+ * ENOENT - unable to find a length *len* range of set bits.
+ * EINVAL - bitmap is NULL or is uninitialized, or len is invalid.
+ */
+static inline int dlb_bitmap_find_set_bit_range(struct dlb_bitmap *bitmap,
+						unsigned int len)
+{
+	struct dlb_bitmap *complement_mask = NULL;
+	int ret;
+
+	if (!bitmap || !bitmap->map || len == 0)
+		return -EINVAL;
+
+	if (bitmap->len < len)
+		return -ENOENT;
+
+	ret = dlb_bitmap_alloc(&complement_mask, bitmap->len);
+	if (ret)
+		return ret;
+
+	bitmap_zero(complement_mask->map, complement_mask->len);
+
+	bitmap_complement(complement_mask->map, bitmap->map, bitmap->len);
+
+	ret = bitmap_find_next_zero_area(complement_mask->map,
+					 complement_mask->len,
+					 0,
+					 len,
+					 0);
+
+	dlb_bitmap_free(complement_mask);
+
+	/* No set bit range of length len? */
+	return (ret >= (int)bitmap->len) ? -ENOENT : ret;
+}
+
+/**
+ * dlb_bitmap_longest_set_range() - returns longest contiguous range of set
+ *				     bits
+ * @bitmap: pointer to dlb_bitmap structure.
+ *
+ * Return:
+ * Returns the bitmap's longest contiguous range of set bits upon success,
+ * <0 otherwise.
+ *
+ * Errors:
+ * EINVAL - bitmap is NULL or is uninitialized.
+ */
+static inline int dlb_bitmap_longest_set_range(struct dlb_bitmap *bitmap)
+{
+	int max_len, len;
+	int start, end;
+
+	if (!bitmap || !bitmap->map)
+		return -EINVAL;
+
+	if (bitmap_weight(bitmap->map, bitmap->len) == 0)
+		return 0;
+
+	max_len = 0;
+	bitmap_for_each_set_region(bitmap->map, start, end, 0, bitmap->len) {
+		len = end - start;
+		if (max_len < len)
+			max_len = len;
+	}
+	return max_len;
+}
+
+int dlb_init_domain(struct dlb *dlb, u32 domain_id);
+void dlb_free_domain(struct kref *kref);
+
+static inline struct device *hw_to_dev(struct dlb_hw *hw)
+{
+	struct dlb *dlb;
+
+	dlb = container_of(hw, struct dlb, hw);
+	return dlb->dev;
+}
+
 /* Prototypes for dlb_resource.c */
 int dlb_resource_init(struct dlb_hw *hw);
 void dlb_resource_free(struct dlb_hw *hw);
diff --git a/drivers/misc/dlb/dlb_regs.h b/drivers/misc/dlb/dlb_regs.h
index 72f3cb22b933..0fd499f384de 100644
--- a/drivers/misc/dlb/dlb_regs.h
+++ b/drivers/misc/dlb/dlb_regs.h
@@ -6,6 +6,24 @@
 
 #include <linux/types.h>
 
+#define CHP_CFG_DIR_VAS_CRD(x) \
+	(0x40000000 + (x) * 0x1000)
+#define CHP_CFG_DIR_VAS_CRD_RST 0x0
+
+#define CHP_CFG_DIR_VAS_CRD_COUNT	0x00003FFF
+#define CHP_CFG_DIR_VAS_CRD_RSVD0	0xFFFFC000
+#define CHP_CFG_DIR_VAS_CRD_COUNT_LOC	0
+#define CHP_CFG_DIR_VAS_CRD_RSVD0_LOC	14
+
+#define CHP_CFG_LDB_VAS_CRD(x) \
+	(0x40080000 + (x) * 0x1000)
+#define CHP_CFG_LDB_VAS_CRD_RST 0x0
+
+#define CHP_CFG_LDB_VAS_CRD_COUNT	0x00007FFF
+#define CHP_CFG_LDB_VAS_CRD_RSVD0	0xFFFF8000
+#define CHP_CFG_LDB_VAS_CRD_COUNT_LOC	0
+#define CHP_CFG_LDB_VAS_CRD_RSVD0_LOC	15
+
 #define CM_CFG_DIAGNOSTIC_IDLE_STATUS 0xb4000004
 #define CM_CFG_DIAGNOSTIC_IDLE_STATUS_RST 0x9d0fffff
 
diff --git a/drivers/misc/dlb/dlb_resource.c b/drivers/misc/dlb/dlb_resource.c
index 7d7ebf3db292..2d74d158219c 100644
--- a/drivers/misc/dlb/dlb_resource.c
+++ b/drivers/misc/dlb/dlb_resource.c
@@ -190,11 +190,537 @@ int dlb_resource_init(struct dlb_hw *hw)
 	return ret;
 }
 
+static int dlb_attach_ldb_queues(struct dlb_hw *hw,
+				 struct dlb_function_resources *rsrcs,
+				 struct dlb_hw_domain *domain, u32 num_queues,
+				 struct dlb_cmd_response *resp)
+{
+	unsigned int i;
+
+	if (rsrcs->num_avail_ldb_queues < num_queues) {
+		resp->status = DLB_ST_LDB_QUEUES_UNAVAILABLE;
+		dev_dbg(hw_to_dev(hw), "[%s()] Internal error: %d\n", __func__,
+			resp->status);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < num_queues; i++) {
+		struct dlb_ldb_queue *queue;
+
+		queue = list_first_entry_or_null(&rsrcs->avail_ldb_queues,
+						 typeof(*queue), func_list);
+		if (!queue) {
+			dev_err(hw_to_dev(hw),
+				"[%s()] Internal error: domain validation failed\n",
+				__func__);
+			return -EFAULT;
+		}
+
+		list_del(&queue->func_list);
+
+		queue->domain_id = domain->id;
+		queue->owned = true;
+
+		list_add(&queue->domain_list, &domain->avail_ldb_queues);
+	}
+
+	rsrcs->num_avail_ldb_queues -= num_queues;
+
+	return 0;
+}
+
+static struct dlb_ldb_port *
+dlb_get_next_ldb_port(struct dlb_hw *hw, struct dlb_function_resources *rsrcs,
+		      u32 domain_id, u32 cos_id)
+{
+	struct dlb_ldb_port *port;
+
+	/*
+	 * To reduce the odds of consecutive load-balanced ports mapping to the
+	 * same queue(s), the driver attempts to allocate ports whose neighbors
+	 * are owned by a different domain.
+	 */
+	list_for_each_entry(port, &rsrcs->avail_ldb_ports[cos_id], func_list) {
+		u32 next, prev;
+		u32 phys_id;
+
+		phys_id = port->id;
+		next = phys_id + 1;
+		prev = phys_id - 1;
+
+		if (phys_id == DLB_MAX_NUM_LDB_PORTS - 1)
+			next = 0;
+		if (phys_id == 0)
+			prev = DLB_MAX_NUM_LDB_PORTS - 1;
+
+		if (!hw->rsrcs.ldb_ports[next].owned ||
+		    hw->rsrcs.ldb_ports[next].domain_id == domain_id)
+			continue;
+
+		if (!hw->rsrcs.ldb_ports[prev].owned ||
+		    hw->rsrcs.ldb_ports[prev].domain_id == domain_id)
+			continue;
+
+		return port;
+	}
+
+	/*
+	 * Failing that, the driver looks for a port with one neighbor owned by
+	 * a different domain and the other unallocated.
+	 */
+	list_for_each_entry(port, &rsrcs->avail_ldb_ports[cos_id], func_list) {
+		u32 next, prev;
+		u32 phys_id;
+
+		phys_id = port->id;
+		next = phys_id + 1;
+		prev = phys_id - 1;
+
+		if (phys_id == DLB_MAX_NUM_LDB_PORTS - 1)
+			next = 0;
+		if (phys_id == 0)
+			prev = DLB_MAX_NUM_LDB_PORTS - 1;
+
+		if (!hw->rsrcs.ldb_ports[prev].owned &&
+		    hw->rsrcs.ldb_ports[next].owned &&
+		    hw->rsrcs.ldb_ports[next].domain_id != domain_id)
+			return port;
+
+		if (!hw->rsrcs.ldb_ports[next].owned &&
+		    hw->rsrcs.ldb_ports[prev].owned &&
+		    hw->rsrcs.ldb_ports[prev].domain_id != domain_id)
+			return port;
+	}
+
+	/*
+	 * Failing that, the driver looks for a port with both neighbors
+	 * unallocated.
+	 */
+	list_for_each_entry(port, &rsrcs->avail_ldb_ports[cos_id], func_list) {
+		u32 next, prev;
+		u32 phys_id;
+
+		phys_id = port->id;
+		next = phys_id + 1;
+		prev = phys_id - 1;
+
+		if (phys_id == DLB_MAX_NUM_LDB_PORTS - 1)
+			next = 0;
+		if (phys_id == 0)
+			prev = DLB_MAX_NUM_LDB_PORTS - 1;
+
+		if (!hw->rsrcs.ldb_ports[prev].owned &&
+		    !hw->rsrcs.ldb_ports[next].owned)
+			return port;
+	}
+
+	/* If all else fails, the driver returns the next available port. */
+	return list_first_entry_or_null(&rsrcs->avail_ldb_ports[cos_id],
+					typeof(*port), func_list);
+}
+
+static int __dlb_attach_ldb_ports(struct dlb_hw *hw,
+				  struct dlb_function_resources *rsrcs,
+				  struct dlb_hw_domain *domain, u32 num_ports,
+				  u32 cos_id, struct dlb_cmd_response *resp)
+{
+	unsigned int i;
+
+	if (rsrcs->num_avail_ldb_ports[cos_id] < num_ports) {
+		resp->status = DLB_ST_LDB_PORTS_UNAVAILABLE;
+		dev_dbg(hw_to_dev(hw),
+			"[%s()] Internal error: %d\n",
+			__func__, resp->status);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < num_ports; i++) {
+		struct dlb_ldb_port *port;
+
+		port = dlb_get_next_ldb_port(hw, rsrcs,
+					     domain->id, cos_id);
+		if (!port) {
+			dev_err(hw_to_dev(hw),
+				"[%s()] Internal error: domain validation failed\n",
+				__func__);
+			return -EFAULT;
+		}
+
+		list_del(&port->func_list);
+
+		port->domain_id = domain->id;
+		port->owned = true;
+
+		list_add(&port->domain_list,
+			 &domain->avail_ldb_ports[cos_id]);
+	}
+
+	rsrcs->num_avail_ldb_ports[cos_id] -= num_ports;
+
+	return 0;
+}
+
+static int dlb_attach_ldb_ports(struct dlb_hw *hw,
+				struct dlb_function_resources *rsrcs,
+				struct dlb_hw_domain *domain,
+				struct dlb_create_sched_domain_args *args,
+				struct dlb_cmd_response *resp)
+{
+	unsigned int i, j;
+	int ret;
+
+	/* Allocate num_ldb_ports from any class-of-service */
+	for (i = 0; i < args->num_ldb_ports; i++) {
+		for (j = 0; j < DLB_NUM_COS_DOMAINS; j++) {
+			ret = __dlb_attach_ldb_ports(hw, rsrcs, domain, 1, j, resp);
+			if (ret == 0)
+				break;
+		}
+
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int dlb_attach_dir_ports(struct dlb_hw *hw,
+				struct dlb_function_resources *rsrcs,
+				struct dlb_hw_domain *domain, u32 num_ports,
+				struct dlb_cmd_response *resp)
+{
+	unsigned int i;
+
+	if (rsrcs->num_avail_dir_pq_pairs < num_ports) {
+		resp->status = DLB_ST_DIR_PORTS_UNAVAILABLE;
+		dev_dbg(hw_to_dev(hw),
+			"[%s()] Internal error: %d\n",
+			__func__, resp->status);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < num_ports; i++) {
+		struct dlb_dir_pq_pair *port;
+
+		port = list_first_entry_or_null(&rsrcs->avail_dir_pq_pairs,
+						typeof(*port), func_list);
+		if (!port) {
+			dev_err(hw_to_dev(hw),
+				"[%s()] Internal error: domain validation failed\n",
+				__func__);
+			return -EFAULT;
+		}
+
+		list_del(&port->func_list);
+
+		port->domain_id = domain->id;
+		port->owned = true;
+
+		list_add(&port->domain_list, &domain->avail_dir_pq_pairs);
+	}
+
+	rsrcs->num_avail_dir_pq_pairs -= num_ports;
+
+	return 0;
+}
+
+static int dlb_attach_ldb_credits(struct dlb_function_resources *rsrcs,
+				  struct dlb_hw_domain *domain, u32 num_credits,
+				  struct dlb_cmd_response *resp)
+{
+	if (rsrcs->num_avail_qed_entries < num_credits) {
+		resp->status = DLB_ST_LDB_CREDITS_UNAVAILABLE;
+		return -EINVAL;
+	}
+
+	rsrcs->num_avail_qed_entries -= num_credits;
+	domain->num_ldb_credits += num_credits;
+	return 0;
+}
+
+static int dlb_attach_dir_credits(struct dlb_function_resources *rsrcs,
+				  struct dlb_hw_domain *domain, u32 num_credits,
+				  struct dlb_cmd_response *resp)
+{
+	if (rsrcs->num_avail_dqed_entries < num_credits) {
+		resp->status = DLB_ST_DIR_CREDITS_UNAVAILABLE;
+		return -EINVAL;
+	}
+
+	rsrcs->num_avail_dqed_entries -= num_credits;
+	domain->num_dir_credits += num_credits;
+	return 0;
+}
+
+static int dlb_attach_atomic_inflights(struct dlb_function_resources *rsrcs,
+				       struct dlb_hw_domain *domain,
+				       u32 num_atomic_inflights,
+				       struct dlb_cmd_response *resp)
+{
+	if (rsrcs->num_avail_aqed_entries < num_atomic_inflights) {
+		resp->status = DLB_ST_ATOMIC_INFLIGHTS_UNAVAILABLE;
+		return -EINVAL;
+	}
+
+	rsrcs->num_avail_aqed_entries -= num_atomic_inflights;
+	domain->num_avail_aqed_entries += num_atomic_inflights;
+	return 0;
+}
+
+static int
+dlb_attach_domain_hist_list_entries(struct dlb_function_resources *rsrcs,
+				    struct dlb_hw_domain *domain,
+				    u32 num_hist_list_entries,
+				    struct dlb_cmd_response *resp)
+{
+	struct dlb_bitmap *bitmap;
+	int base;
+
+	if (num_hist_list_entries) {
+		bitmap = rsrcs->avail_hist_list_entries;
+
+		base = dlb_bitmap_find_set_bit_range(bitmap,
+						     num_hist_list_entries);
+		if (base < 0)
+			goto error;
+
+		domain->total_hist_list_entries = num_hist_list_entries;
+		domain->avail_hist_list_entries = num_hist_list_entries;
+		domain->hist_list_entry_base = base;
+		domain->hist_list_entry_offset = 0;
+
+		dlb_bitmap_clear_range(bitmap, base, num_hist_list_entries);
+	}
+	return 0;
+
+error:
+	resp->status = DLB_ST_HIST_LIST_ENTRIES_UNAVAILABLE;
+	return -EINVAL;
+}
+
+static int
+dlb_verify_create_sched_dom_args(struct dlb_function_resources *rsrcs,
+				 struct dlb_create_sched_domain_args *args,
+				 struct dlb_cmd_response *resp,
+				 struct dlb_hw_domain **out_domain)
+{
+	u32 num_avail_ldb_ports, req_ldb_ports;
+	struct dlb_bitmap *avail_hl_entries;
+	unsigned int max_contig_hl_range;
+	struct dlb_hw_domain *domain;
+	int i;
+
+	avail_hl_entries = rsrcs->avail_hist_list_entries;
+
+	max_contig_hl_range = dlb_bitmap_longest_set_range(avail_hl_entries);
+
+	num_avail_ldb_ports = 0;
+	req_ldb_ports = 0;
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++)
+		num_avail_ldb_ports += rsrcs->num_avail_ldb_ports[i];
+
+	req_ldb_ports += args->num_ldb_ports;
+
+	if (rsrcs->num_avail_domains < 1) {
+		resp->status = DLB_ST_DOMAIN_UNAVAILABLE;
+		return -EINVAL;
+	}
+
+	domain = list_first_entry_or_null(&rsrcs->avail_domains,
+					  typeof(*domain), func_list);
+	if (!domain) {
+		resp->status = DLB_ST_DOMAIN_UNAVAILABLE;
+		return -EFAULT;
+	}
+
+	if (rsrcs->num_avail_ldb_queues < args->num_ldb_queues) {
+		resp->status = DLB_ST_LDB_QUEUES_UNAVAILABLE;
+		return -EINVAL;
+	}
+
+	if (req_ldb_ports > num_avail_ldb_ports) {
+		resp->status = DLB_ST_LDB_PORTS_UNAVAILABLE;
+		return -EINVAL;
+	}
+
+	if (args->num_ldb_queues > 0 && req_ldb_ports == 0) {
+		resp->status = DLB_ST_LDB_PORT_REQUIRED_FOR_LDB_QUEUES;
+		return -EINVAL;
+	}
+
+	if (rsrcs->num_avail_dir_pq_pairs < args->num_dir_ports) {
+		resp->status = DLB_ST_DIR_PORTS_UNAVAILABLE;
+		return -EINVAL;
+	}
+
+	if (rsrcs->num_avail_qed_entries < args->num_ldb_credits) {
+		resp->status = DLB_ST_LDB_CREDITS_UNAVAILABLE;
+		return -EINVAL;
+	}
+
+	if (rsrcs->num_avail_dqed_entries < args->num_dir_credits) {
+		resp->status = DLB_ST_DIR_CREDITS_UNAVAILABLE;
+		return -EINVAL;
+	}
+
+	if (rsrcs->num_avail_aqed_entries < args->num_atomic_inflights) {
+		resp->status = DLB_ST_ATOMIC_INFLIGHTS_UNAVAILABLE;
+		return -EINVAL;
+	}
+
+	if (max_contig_hl_range < args->num_hist_list_entries) {
+		resp->status = DLB_ST_HIST_LIST_ENTRIES_UNAVAILABLE;
+		return -EINVAL;
+	}
+
+	*out_domain = domain;
+
+	return 0;
+}
+
+static void dlb_configure_domain_credits(struct dlb_hw *hw,
+					 struct dlb_hw_domain *domain)
+{
+	u32 reg;
+
+	reg = FIELD_PREP(CHP_CFG_LDB_VAS_CRD_COUNT, domain->num_ldb_credits);
+	DLB_CSR_WR(hw, CHP_CFG_LDB_VAS_CRD(domain->id), reg);
+
+	reg = FIELD_PREP(CHP_CFG_DIR_VAS_CRD_COUNT, domain->num_dir_credits);
+	DLB_CSR_WR(hw, CHP_CFG_DIR_VAS_CRD(domain->id), reg);
+}
+
+static int
+dlb_domain_attach_resources(struct dlb_hw *hw,
+			    struct dlb_function_resources *rsrcs,
+			    struct dlb_hw_domain *domain,
+			    struct dlb_create_sched_domain_args *args,
+			    struct dlb_cmd_response *resp)
+{
+	int ret;
+
+	ret = dlb_attach_ldb_queues(hw, rsrcs, domain, args->num_ldb_queues, resp);
+	if (ret)
+		return ret;
+
+	ret = dlb_attach_ldb_ports(hw, rsrcs, domain, args, resp);
+	if (ret)
+		return ret;
+
+	ret = dlb_attach_dir_ports(hw, rsrcs, domain, args->num_dir_ports, resp);
+	if (ret)
+		return ret;
+
+	ret = dlb_attach_ldb_credits(rsrcs, domain,
+				     args->num_ldb_credits, resp);
+	if (ret)
+		return ret;
+
+	ret = dlb_attach_dir_credits(rsrcs, domain, args->num_dir_credits, resp);
+	if (ret)
+		return ret;
+
+	ret = dlb_attach_domain_hist_list_entries(rsrcs, domain,
+						  args->num_hist_list_entries,
+						  resp);
+	if (ret)
+		return ret;
+
+	ret = dlb_attach_atomic_inflights(rsrcs, domain,
+					  args->num_atomic_inflights, resp);
+	if (ret)
+		return ret;
+
+	dlb_configure_domain_credits(hw, domain);
+
+	domain->configured = true;
+
+	domain->started = false;
+
+	rsrcs->num_avail_domains--;
+
+	return 0;
+}
+
+static void
+dlb_log_create_sched_domain_args(struct dlb_hw *hw,
+				 struct dlb_create_sched_domain_args *args)
+{
+	dev_dbg(hw_to_dev(hw), "DLB create sched domain arguments:\n");
+	dev_dbg(hw_to_dev(hw), "\tNumber of LDB queues:          %d\n",
+		args->num_ldb_queues);
+	dev_dbg(hw_to_dev(hw), "\tNumber of LDB ports (any CoS): %d\n",
+		args->num_ldb_ports);
+	dev_dbg(hw_to_dev(hw), "\tNumber of DIR ports:           %d\n",
+		args->num_dir_ports);
+	dev_dbg(hw_to_dev(hw), "\tNumber of ATM inflights:       %d\n",
+		args->num_atomic_inflights);
+	dev_dbg(hw_to_dev(hw), "\tNumber of hist list entries:   %d\n",
+		args->num_hist_list_entries);
+	dev_dbg(hw_to_dev(hw), "\tNumber of LDB credits:         %d\n",
+		args->num_ldb_credits);
+	dev_dbg(hw_to_dev(hw), "\tNumber of DIR credits:         %d\n",
+		args->num_dir_credits);
+}
+
+/**
+ * dlb_hw_create_sched_domain() - create a scheduling domain
+ * @hw: dlb_hw handle for a particular device.
+ * @args: scheduling domain creation arguments.
+ * @resp: response structure.
+ *
+ * This function creates a scheduling domain containing the resources specified
+ * in args. The individual resources (queues, ports, credits) can be configured
+ * after creating a scheduling domain.
+ *
+ * Return:
+ * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
+ * assigned a detailed error code from enum dlb_error. If successful, resp->id
+ * contains the domain ID.
+ *
+ * Errors:
+ * EINVAL - A requested resource is unavailable, or the requested domain name
+ *	    is already in use.
+ * EFAULT - Internal error (resp->status not set).
+ */
 int dlb_hw_create_sched_domain(struct dlb_hw *hw,
 			       struct dlb_create_sched_domain_args *args,
 			       struct dlb_cmd_response *resp)
 {
-	resp->id = 0;
+	struct dlb_function_resources *rsrcs;
+	struct dlb_hw_domain *domain;
+	int ret;
+
+	rsrcs = &hw->pf;
+
+	dlb_log_create_sched_domain_args(hw, args);
+
+	/*
+	 * Verify that hardware resources are available before attempting to
+	 * satisfy the request. This simplifies the error unwinding code.
+	 */
+	ret = dlb_verify_create_sched_dom_args(rsrcs, args, resp, &domain);
+	if (ret)
+		return ret;
+
+	dlb_init_domain_rsrc_lists(domain);
+
+	ret = dlb_domain_attach_resources(hw, rsrcs, domain, args, resp);
+	if (ret) {
+		dev_err(hw_to_dev(hw),
+			"[%s()] Internal error: failed to verify args.\n",
+			__func__);
+
+		return ret;
+	}
+
+	/*
+	 * Configuration succeeded, so move the resource from the 'avail' to
+	 * the 'used' list (if it's not already there).
+	 */
+	list_move(&domain->func_list, &rsrcs->used_domains);
+
+	resp->id = domain->id;
 	resp->status = 0;
 
 	return 0;
diff --git a/include/uapi/linux/dlb.h b/include/uapi/linux/dlb.h
new file mode 100644
index 000000000000..91551d8a0175
--- /dev/null
+++ b/include/uapi/linux/dlb.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright(C) 2016-2020 Intel Corporation. All rights reserved. */
+
+#ifndef __DLB_H
+#define __DLB_H
+
+#include <linux/types.h>
+
+enum dlb_error {
+	DLB_ST_SUCCESS = 0,
+	DLB_ST_DOMAIN_UNAVAILABLE,
+	DLB_ST_LDB_PORTS_UNAVAILABLE,
+	DLB_ST_DIR_PORTS_UNAVAILABLE,
+	DLB_ST_LDB_QUEUES_UNAVAILABLE,
+	DLB_ST_LDB_CREDITS_UNAVAILABLE,
+	DLB_ST_DIR_CREDITS_UNAVAILABLE,
+	DLB_ST_SEQUENCE_NUMBERS_UNAVAILABLE,
+	DLB_ST_ATOMIC_INFLIGHTS_UNAVAILABLE,
+	DLB_ST_HIST_LIST_ENTRIES_UNAVAILABLE,
+	DLB_ST_LDB_PORT_REQUIRED_FOR_LDB_QUEUES,
+};
+#endif /* __DLB_H */
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [RFC PATCH v12 06/17] dlb: add domain software reset
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
                   ` (4 preceding siblings ...)
  2021-12-21  6:50 ` [RFC PATCH v12 05/17] dlb: add scheduling domain configuration Mike Ximing Chen
@ 2021-12-21  6:50 ` Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 07/17] dlb: add low-level register reset operations Mike Ximing Chen
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

Add operation to reset a domain's resource's software state when its
reference count reaches zero, and re-inserts those resources in their
respective available-resources linked lists, for use by future scheduling
domains.

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
---
 drivers/misc/dlb/dlb_configfs.c |  10 +-
 drivers/misc/dlb/dlb_main.c     |  10 +-
 drivers/misc/dlb/dlb_main.h     |  36 ++++++
 drivers/misc/dlb/dlb_resource.c | 204 ++++++++++++++++++++++++++++++++
 include/uapi/linux/dlb.h        |   1 +
 5 files changed, 259 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/dlb/dlb_configfs.c b/drivers/misc/dlb/dlb_configfs.c
index 7e5db0390a6a..dc4d1a3bae0f 100644
--- a/drivers/misc/dlb/dlb_configfs.c
+++ b/drivers/misc/dlb/dlb_configfs.c
@@ -20,13 +20,21 @@ static int dlb_configfs_create_sched_domain(struct dlb *dlb,
 
 	mutex_lock(&dlb->resource_mutex);
 
+	if (dlb->domain_reset_failed) {
+		response.status = DLB_ST_DOMAIN_RESET_FAILED;
+		ret = -EINVAL;
+		goto unlock;
+	}
+
 	ret = dlb_hw_create_sched_domain(&dlb->hw, arg, &response);
 	if (ret)
 		goto unlock;
 
 	ret = dlb_init_domain(dlb, response.id);
-	if (ret)
+	if (ret) {
+		dlb_reset_domain(&dlb->hw, response.id);
 		goto unlock;
+	}
 
 	domain = dlb->sched_domains[response.id];
 
diff --git a/drivers/misc/dlb/dlb_main.c b/drivers/misc/dlb/dlb_main.c
index 3c949d9b4cf0..343bf72dc9c7 100644
--- a/drivers/misc/dlb/dlb_main.c
+++ b/drivers/misc/dlb/dlb_main.c
@@ -101,12 +101,20 @@ int dlb_init_domain(struct dlb *dlb, u32 domain_id)
 static int __dlb_free_domain(struct dlb_domain *domain)
 {
 	struct dlb *dlb = domain->dlb;
+	int ret;
+
+	ret = dlb_reset_domain(&dlb->hw, domain->id);
+	if (ret) {
+		dlb->domain_reset_failed = true;
+		dev_err(dlb->dev,
+			"Internal error: Domain reset failed. To recover, reset the device.\n");
+	}
 
 	dlb->sched_domains[domain->id] = NULL;
 
 	kfree(domain);
 
-	return 0;
+	return ret;
 }
 
 void dlb_free_domain(struct kref *kref)
diff --git a/drivers/misc/dlb/dlb_main.h b/drivers/misc/dlb/dlb_main.h
index 6c9b9cce148e..b6e79397f312 100644
--- a/drivers/misc/dlb/dlb_main.h
+++ b/drivers/misc/dlb/dlb_main.h
@@ -139,6 +139,12 @@ struct dlb_sn_group {
 	u32 id;
 };
 
+static inline void
+dlb_sn_group_free_slot(struct dlb_sn_group *group, int slot)
+{
+	group->slot_use_bitmap &= ~(BIT(slot));
+}
+
 /*
  * Scheduling domain level resource data structure.
  *
@@ -271,6 +277,7 @@ struct dlb {
 	enum dlb_device_type type;
 	int id;
 	dev_t dev_number;
+	u8 domain_reset_failed;
 };
 
 /*************************/
@@ -337,6 +344,34 @@ static inline void dlb_bitmap_free(struct dlb_bitmap *bitmap)
 	kfree(bitmap);
 }
 
+/**
+ * dlb_bitmap_set_range() - set a range of bitmap entries
+ * @bitmap: pointer to dlb_bitmap structure.
+ * @bit: starting bit index.
+ * @len: length of the range.
+ *
+ * Return:
+ * Returns 0 upon success, < 0 otherwise.
+ *
+ * Errors:
+ * EINVAL - bitmap is NULL or is uninitialized, or the range exceeds the bitmap
+ *	    length.
+ */
+static inline int dlb_bitmap_set_range(struct dlb_bitmap *bitmap,
+				       unsigned int bit,
+				       unsigned int len)
+{
+	if (!bitmap || !bitmap->map)
+		return -EINVAL;
+
+	if (bitmap->len <= bit)
+		return -EINVAL;
+
+	bitmap_set(bitmap->map, bit, len);
+
+	return 0;
+}
+
 /**
  * dlb_bitmap_clear_range() - clear a range of bitmap entries
  * @bitmap: pointer to dlb_bitmap structure.
@@ -460,6 +495,7 @@ void dlb_resource_free(struct dlb_hw *hw);
 int dlb_hw_create_sched_domain(struct dlb_hw *hw,
 			       struct dlb_create_sched_domain_args *args,
 			       struct dlb_cmd_response *resp);
+int dlb_reset_domain(struct dlb_hw *hw, u32 domain_id);
 void dlb_clr_pmcsr_disable(struct dlb_hw *hw);
 
 /* Prototypes for dlb_configfs.c */
diff --git a/drivers/misc/dlb/dlb_resource.c b/drivers/misc/dlb/dlb_resource.c
index 2d74d158219c..c5b3f1ff3d7e 100644
--- a/drivers/misc/dlb/dlb_resource.c
+++ b/drivers/misc/dlb/dlb_resource.c
@@ -190,6 +190,14 @@ int dlb_resource_init(struct dlb_hw *hw)
 	return ret;
 }
 
+static struct dlb_hw_domain *dlb_get_domain_from_id(struct dlb_hw *hw, u32 id)
+{
+	if (id >= DLB_MAX_NUM_DOMAINS)
+		return NULL;
+
+	return &hw->domains[id];
+}
+
 static int dlb_attach_ldb_queues(struct dlb_hw *hw,
 				 struct dlb_function_resources *rsrcs,
 				 struct dlb_hw_domain *domain, u32 num_queues,
@@ -726,6 +734,202 @@ int dlb_hw_create_sched_domain(struct dlb_hw *hw,
 	return 0;
 }
 
+/*
+ * dlb_domain_reset_software_state() - returns domain's resources
+ * @hw: dlb_hw handle for a particular device.
+ * @domain: pointer to scheduling domain.
+ *
+ * This function returns the resources allocated/assigned to a domain back to
+ * the device/function level resource pool. These resources include ldb/dir
+ * queues,  ports, history lists, etc. It is called by the dlb_reset_domain().
+ * When a domain is created/initialized, resources are moved to a domain from
+ * the resource pool.
+ *
+ */
+static int dlb_domain_reset_software_state(struct dlb_hw *hw,
+					   struct dlb_hw_domain *domain)
+{
+	struct dlb *dlb = container_of(hw, struct dlb, hw);
+	struct dlb_dir_pq_pair *tmp_dir_port;
+	struct dlb_function_resources *rsrcs;
+	struct dlb_ldb_queue *tmp_ldb_queue;
+	struct dlb_ldb_port *tmp_ldb_port;
+	struct dlb_dir_pq_pair *dir_port;
+	struct dlb_ldb_queue *ldb_queue;
+	struct dlb_ldb_port *ldb_port;
+	int ret, i;
+
+	lockdep_assert_held(&dlb->resource_mutex);
+
+	rsrcs = domain->parent_func;
+
+	/* Move the domain's ldb queues to the function's avail list */
+	list_for_each_entry_safe(ldb_queue, tmp_ldb_queue,
+				 &domain->used_ldb_queues, domain_list) {
+		if (ldb_queue->sn_cfg_valid) {
+			struct dlb_sn_group *grp;
+
+			grp = &hw->rsrcs.sn_groups[ldb_queue->sn_group];
+
+			dlb_sn_group_free_slot(grp, ldb_queue->sn_slot);
+			ldb_queue->sn_cfg_valid = false;
+		}
+
+		ldb_queue->owned = false;
+		ldb_queue->num_mappings = 0;
+		ldb_queue->num_pending_additions = 0;
+
+		list_del(&ldb_queue->domain_list);
+		list_add(&ldb_queue->func_list, &rsrcs->avail_ldb_queues);
+		rsrcs->num_avail_ldb_queues++;
+	}
+
+	list_for_each_entry_safe(ldb_queue, tmp_ldb_queue,
+				 &domain->avail_ldb_queues, domain_list) {
+		ldb_queue->owned = false;
+
+		list_del(&ldb_queue->domain_list);
+		list_add(&ldb_queue->func_list, &rsrcs->avail_ldb_queues);
+		rsrcs->num_avail_ldb_queues++;
+	}
+
+	/* Move the domain's ldb ports to the function's avail list */
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++) {
+		list_for_each_entry_safe(ldb_port, tmp_ldb_port,
+				 &domain->used_ldb_ports[i], domain_list) {
+			int j;
+
+			ldb_port->owned = false;
+			ldb_port->configured = false;
+			ldb_port->num_pending_removals = 0;
+			ldb_port->num_mappings = 0;
+			ldb_port->init_tkn_cnt = 0;
+			for (j = 0; j < DLB_MAX_NUM_QIDS_PER_LDB_CQ; j++)
+				ldb_port->qid_map[j].state =
+					DLB_QUEUE_UNMAPPED;
+
+			list_del(&ldb_port->domain_list);
+			list_add(&ldb_port->func_list,
+				 &rsrcs->avail_ldb_ports[i]);
+			rsrcs->num_avail_ldb_ports[i]++;
+		}
+
+		list_for_each_entry_safe(ldb_port, tmp_ldb_port,
+				 &domain->avail_ldb_ports[i], domain_list) {
+			ldb_port->owned = false;
+
+			list_del(&ldb_port->domain_list);
+			list_add(&ldb_port->func_list,
+				 &rsrcs->avail_ldb_ports[i]);
+			rsrcs->num_avail_ldb_ports[i]++;
+		}
+	}
+
+	/* Move the domain's dir ports to the function's avail list */
+	list_for_each_entry_safe(dir_port, tmp_dir_port,
+				 &domain->used_dir_pq_pairs, domain_list) {
+		dir_port->owned = false;
+		dir_port->port_configured = false;
+		dir_port->init_tkn_cnt = 0;
+
+		list_del(&dir_port->domain_list);
+
+		list_add(&dir_port->func_list, &rsrcs->avail_dir_pq_pairs);
+		rsrcs->num_avail_dir_pq_pairs++;
+	}
+
+	list_for_each_entry_safe(dir_port, tmp_dir_port,
+				 &domain->avail_dir_pq_pairs, domain_list) {
+		dir_port->owned = false;
+
+		list_del(&dir_port->domain_list);
+
+		list_add(&dir_port->func_list, &rsrcs->avail_dir_pq_pairs);
+		rsrcs->num_avail_dir_pq_pairs++;
+	}
+
+	/* Return hist list entries to the function */
+	ret = dlb_bitmap_set_range(rsrcs->avail_hist_list_entries,
+				   domain->hist_list_entry_base,
+				   domain->total_hist_list_entries);
+	if (ret) {
+		dev_err(hw_to_dev(hw),
+			"[%s()] Internal error: domain hist list base doesn't match the function's bitmap.\n",
+			__func__);
+		return ret;
+	}
+
+	domain->total_hist_list_entries = 0;
+	domain->avail_hist_list_entries = 0;
+	domain->hist_list_entry_base = 0;
+	domain->hist_list_entry_offset = 0;
+
+	rsrcs->num_avail_qed_entries += domain->num_ldb_credits;
+	domain->num_ldb_credits = 0;
+
+	rsrcs->num_avail_dqed_entries += domain->num_dir_credits;
+	domain->num_dir_credits = 0;
+
+	rsrcs->num_avail_aqed_entries += domain->num_avail_aqed_entries;
+	rsrcs->num_avail_aqed_entries += domain->num_used_aqed_entries;
+	domain->num_avail_aqed_entries = 0;
+	domain->num_used_aqed_entries = 0;
+
+	domain->num_pending_removals = 0;
+	domain->num_pending_additions = 0;
+	domain->configured = false;
+	domain->started = false;
+
+	/*
+	 * Move the domain out of the used_domains list and back to the
+	 * function's avail_domains list.
+	 */
+	list_move(&domain->func_list, &rsrcs->avail_domains);
+	rsrcs->num_avail_domains++;
+
+	return 0;
+}
+
+static void dlb_log_reset_domain(struct dlb_hw *hw, u32 domain_id)
+{
+	dev_dbg(hw_to_dev(hw), "DLB reset domain:\n");
+	dev_dbg(hw_to_dev(hw), "\tDomain ID: %d\n", domain_id);
+}
+
+/**
+ * dlb_reset_domain() - reset a scheduling domain
+ * @hw: dlb_hw handle for a particular device.
+ * @domain_id: domain ID.
+ *
+ * This function resets and frees a DLB 2.0 scheduling domain and its associated
+ * resources.
+ *
+ * Pre-condition: the driver must ensure software has stopped sending QEs
+ * through this domain's producer ports before invoking this function, or
+ * undefined behavior will result.
+ *
+ * Return:
+ * Returns 0 upon success, -1 otherwise.
+ *
+ * EINVAL - Invalid domain ID, or the domain is not configured.
+ * EFAULT - Internal error. (Possibly caused if software is the pre-condition
+ *	    is not met.)
+ * ETIMEDOUT - Hardware component didn't reset in the expected time.
+ */
+int dlb_reset_domain(struct dlb_hw *hw, u32 domain_id)
+{
+	struct dlb_hw_domain *domain;
+
+	dlb_log_reset_domain(hw, domain_id);
+
+	domain = dlb_get_domain_from_id(hw, domain_id);
+
+	if (!domain || !domain->configured)
+		return -EINVAL;
+
+	return dlb_domain_reset_software_state(hw, domain);
+}
+
 /**
  * dlb_clr_pmcsr_disable() - power on bulk of DLB 2.0 logic
  * @hw: dlb_hw handle for a particular device.
diff --git a/include/uapi/linux/dlb.h b/include/uapi/linux/dlb.h
index 91551d8a0175..580a5cafbe61 100644
--- a/include/uapi/linux/dlb.h
+++ b/include/uapi/linux/dlb.h
@@ -18,5 +18,6 @@ enum dlb_error {
 	DLB_ST_ATOMIC_INFLIGHTS_UNAVAILABLE,
 	DLB_ST_HIST_LIST_ENTRIES_UNAVAILABLE,
 	DLB_ST_LDB_PORT_REQUIRED_FOR_LDB_QUEUES,
+	DLB_ST_DOMAIN_RESET_FAILED,
 };
 #endif /* __DLB_H */
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [RFC PATCH v12 07/17] dlb: add low-level register reset operations
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
                   ` (5 preceding siblings ...)
  2021-12-21  6:50 ` [RFC PATCH v12 06/17] dlb: add domain software reset Mike Ximing Chen
@ 2021-12-21  6:50 ` Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 08/17] dlb: add runtime power-management support Mike Ximing Chen
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

Program all registers used to configure the domain's resources back to
their reset values during scheduling domain reset. This ensures the device
is in a known good state if/when it is configured again in the future.

Additional work is required if a resource is in-use (e.g. a queue is
non-empty) at that time. Support for these cases will be added in
subsequent commits.

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
---
 drivers/misc/dlb/dlb_regs.h     | 3527 ++++++++++++++++++++++++++++++-
 drivers/misc/dlb/dlb_resource.c |  387 ++++
 2 files changed, 3902 insertions(+), 12 deletions(-)

diff --git a/drivers/misc/dlb/dlb_regs.h b/drivers/misc/dlb/dlb_regs.h
index 0fd499f384de..5e4609504a01 100644
--- a/drivers/misc/dlb/dlb_regs.h
+++ b/drivers/misc/dlb/dlb_regs.h
@@ -4,25 +4,3475 @@
 #ifndef __DLB_REGS_H
 #define __DLB_REGS_H
 
-#include <linux/types.h>
+#define PF_VF2PF_MAILBOX_BYTES 256
+#define PF_VF2PF_MAILBOX(vf_id, x) \
+	(0x1000 + 0x4 * (x) + (vf_id) * 0x10000)
+#define PF_VF2PF_MAILBOX_RST 0x0
+
+#define PF_VF2PF_MAILBOX_MSG	0xFFFFFFFF
+#define PF_VF2PF_MAILBOX_MSG_LOC	0
+
+#define PF_VF2PF_MAILBOX_ISR(vf_id) \
+	(0x1f00 + (vf_id) * 0x10000)
+#define PF_VF2PF_MAILBOX_ISR_RST 0x0
+
+#define PF_VF2PF_MAILBOX_ISR_VF0_ISR	0x00000001
+#define PF_VF2PF_MAILBOX_ISR_VF1_ISR	0x00000002
+#define PF_VF2PF_MAILBOX_ISR_VF2_ISR	0x00000004
+#define PF_VF2PF_MAILBOX_ISR_VF3_ISR	0x00000008
+#define PF_VF2PF_MAILBOX_ISR_VF4_ISR	0x00000010
+#define PF_VF2PF_MAILBOX_ISR_VF5_ISR	0x00000020
+#define PF_VF2PF_MAILBOX_ISR_VF6_ISR	0x00000040
+#define PF_VF2PF_MAILBOX_ISR_VF7_ISR	0x00000080
+#define PF_VF2PF_MAILBOX_ISR_VF8_ISR	0x00000100
+#define PF_VF2PF_MAILBOX_ISR_VF9_ISR	0x00000200
+#define PF_VF2PF_MAILBOX_ISR_VF10_ISR	0x00000400
+#define PF_VF2PF_MAILBOX_ISR_VF11_ISR	0x00000800
+#define PF_VF2PF_MAILBOX_ISR_VF12_ISR	0x00001000
+#define PF_VF2PF_MAILBOX_ISR_VF13_ISR	0x00002000
+#define PF_VF2PF_MAILBOX_ISR_VF14_ISR	0x00004000
+#define PF_VF2PF_MAILBOX_ISR_VF15_ISR	0x00008000
+#define PF_VF2PF_MAILBOX_ISR_RSVD0	0xFFFF0000
+#define PF_VF2PF_MAILBOX_ISR_VF0_ISR_LOC	0
+#define PF_VF2PF_MAILBOX_ISR_VF1_ISR_LOC	1
+#define PF_VF2PF_MAILBOX_ISR_VF2_ISR_LOC	2
+#define PF_VF2PF_MAILBOX_ISR_VF3_ISR_LOC	3
+#define PF_VF2PF_MAILBOX_ISR_VF4_ISR_LOC	4
+#define PF_VF2PF_MAILBOX_ISR_VF5_ISR_LOC	5
+#define PF_VF2PF_MAILBOX_ISR_VF6_ISR_LOC	6
+#define PF_VF2PF_MAILBOX_ISR_VF7_ISR_LOC	7
+#define PF_VF2PF_MAILBOX_ISR_VF8_ISR_LOC	8
+#define PF_VF2PF_MAILBOX_ISR_VF9_ISR_LOC	9
+#define PF_VF2PF_MAILBOX_ISR_VF10_ISR_LOC	10
+#define PF_VF2PF_MAILBOX_ISR_VF11_ISR_LOC	11
+#define PF_VF2PF_MAILBOX_ISR_VF12_ISR_LOC	12
+#define PF_VF2PF_MAILBOX_ISR_VF13_ISR_LOC	13
+#define PF_VF2PF_MAILBOX_ISR_VF14_ISR_LOC	14
+#define PF_VF2PF_MAILBOX_ISR_VF15_ISR_LOC	15
+#define PF_VF2PF_MAILBOX_ISR_RSVD0_LOC		16
+
+#define PF_VF2PF_FLR_ISR(vf_id) \
+	(0x1f04 + (vf_id) * 0x10000)
+#define PF_VF2PF_FLR_ISR_RST 0x0
+
+#define PF_VF2PF_FLR_ISR_VF0_ISR	0x00000001
+#define PF_VF2PF_FLR_ISR_VF1_ISR	0x00000002
+#define PF_VF2PF_FLR_ISR_VF2_ISR	0x00000004
+#define PF_VF2PF_FLR_ISR_VF3_ISR	0x00000008
+#define PF_VF2PF_FLR_ISR_VF4_ISR	0x00000010
+#define PF_VF2PF_FLR_ISR_VF5_ISR	0x00000020
+#define PF_VF2PF_FLR_ISR_VF6_ISR	0x00000040
+#define PF_VF2PF_FLR_ISR_VF7_ISR	0x00000080
+#define PF_VF2PF_FLR_ISR_VF8_ISR	0x00000100
+#define PF_VF2PF_FLR_ISR_VF9_ISR	0x00000200
+#define PF_VF2PF_FLR_ISR_VF10_ISR	0x00000400
+#define PF_VF2PF_FLR_ISR_VF11_ISR	0x00000800
+#define PF_VF2PF_FLR_ISR_VF12_ISR	0x00001000
+#define PF_VF2PF_FLR_ISR_VF13_ISR	0x00002000
+#define PF_VF2PF_FLR_ISR_VF14_ISR	0x00004000
+#define PF_VF2PF_FLR_ISR_VF15_ISR	0x00008000
+#define PF_VF2PF_FLR_ISR_RSVD0		0xFFFF0000
+#define PF_VF2PF_FLR_ISR_VF0_ISR_LOC	0
+#define PF_VF2PF_FLR_ISR_VF1_ISR_LOC	1
+#define PF_VF2PF_FLR_ISR_VF2_ISR_LOC	2
+#define PF_VF2PF_FLR_ISR_VF3_ISR_LOC	3
+#define PF_VF2PF_FLR_ISR_VF4_ISR_LOC	4
+#define PF_VF2PF_FLR_ISR_VF5_ISR_LOC	5
+#define PF_VF2PF_FLR_ISR_VF6_ISR_LOC	6
+#define PF_VF2PF_FLR_ISR_VF7_ISR_LOC	7
+#define PF_VF2PF_FLR_ISR_VF8_ISR_LOC	8
+#define PF_VF2PF_FLR_ISR_VF9_ISR_LOC	9
+#define PF_VF2PF_FLR_ISR_VF10_ISR_LOC	10
+#define PF_VF2PF_FLR_ISR_VF11_ISR_LOC	11
+#define PF_VF2PF_FLR_ISR_VF12_ISR_LOC	12
+#define PF_VF2PF_FLR_ISR_VF13_ISR_LOC	13
+#define PF_VF2PF_FLR_ISR_VF14_ISR_LOC	14
+#define PF_VF2PF_FLR_ISR_VF15_ISR_LOC	15
+#define PF_VF2PF_FLR_ISR_RSVD0_LOC	16
+
+#define PF_VF2PF_ISR_PEND(vf_id) \
+	(0x1f10 + (vf_id) * 0x10000)
+#define PF_VF2PF_ISR_PEND_RST 0x0
+
+#define PF_VF2PF_ISR_PEND_ISR_PEND	0x00000001
+#define PF_VF2PF_ISR_PEND_RSVD0		0xFFFFFFFE
+#define PF_VF2PF_ISR_PEND_ISR_PEND_LOC	0
+#define PF_VF2PF_ISR_PEND_RSVD0_LOC	1
+
+#define PF_PF2VF_MAILBOX_BYTES 64
+#define PF_PF2VF_MAILBOX(vf_id, x) \
+	(0x2000 + 0x4 * (x) + (vf_id) * 0x10000)
+#define PF_PF2VF_MAILBOX_RST 0x0
+
+#define PF_PF2VF_MAILBOX_MSG	0xFFFFFFFF
+#define PF_PF2VF_MAILBOX_MSG_LOC	0
+
+#define PF_PF2VF_MAILBOX_ISR(vf_id) \
+	(0x2f00 + (vf_id) * 0x10000)
+#define PF_PF2VF_MAILBOX_ISR_RST 0x0
+
+#define PF_PF2VF_MAILBOX_ISR_VF0_ISR	0x00000001
+#define PF_PF2VF_MAILBOX_ISR_VF1_ISR	0x00000002
+#define PF_PF2VF_MAILBOX_ISR_VF2_ISR	0x00000004
+#define PF_PF2VF_MAILBOX_ISR_VF3_ISR	0x00000008
+#define PF_PF2VF_MAILBOX_ISR_VF4_ISR	0x00000010
+#define PF_PF2VF_MAILBOX_ISR_VF5_ISR	0x00000020
+#define PF_PF2VF_MAILBOX_ISR_VF6_ISR	0x00000040
+#define PF_PF2VF_MAILBOX_ISR_VF7_ISR	0x00000080
+#define PF_PF2VF_MAILBOX_ISR_VF8_ISR	0x00000100
+#define PF_PF2VF_MAILBOX_ISR_VF9_ISR	0x00000200
+#define PF_PF2VF_MAILBOX_ISR_VF10_ISR	0x00000400
+#define PF_PF2VF_MAILBOX_ISR_VF11_ISR	0x00000800
+#define PF_PF2VF_MAILBOX_ISR_VF12_ISR	0x00001000
+#define PF_PF2VF_MAILBOX_ISR_VF13_ISR	0x00002000
+#define PF_PF2VF_MAILBOX_ISR_VF14_ISR	0x00004000
+#define PF_PF2VF_MAILBOX_ISR_VF15_ISR	0x00008000
+#define PF_PF2VF_MAILBOX_ISR_RSVD0	0xFFFF0000
+#define PF_PF2VF_MAILBOX_ISR_VF0_ISR_LOC	0
+#define PF_PF2VF_MAILBOX_ISR_VF1_ISR_LOC	1
+#define PF_PF2VF_MAILBOX_ISR_VF2_ISR_LOC	2
+#define PF_PF2VF_MAILBOX_ISR_VF3_ISR_LOC	3
+#define PF_PF2VF_MAILBOX_ISR_VF4_ISR_LOC	4
+#define PF_PF2VF_MAILBOX_ISR_VF5_ISR_LOC	5
+#define PF_PF2VF_MAILBOX_ISR_VF6_ISR_LOC	6
+#define PF_PF2VF_MAILBOX_ISR_VF7_ISR_LOC	7
+#define PF_PF2VF_MAILBOX_ISR_VF8_ISR_LOC	8
+#define PF_PF2VF_MAILBOX_ISR_VF9_ISR_LOC	9
+#define PF_PF2VF_MAILBOX_ISR_VF10_ISR_LOC	10
+#define PF_PF2VF_MAILBOX_ISR_VF11_ISR_LOC	11
+#define PF_PF2VF_MAILBOX_ISR_VF12_ISR_LOC	12
+#define PF_PF2VF_MAILBOX_ISR_VF13_ISR_LOC	13
+#define PF_PF2VF_MAILBOX_ISR_VF14_ISR_LOC	14
+#define PF_PF2VF_MAILBOX_ISR_VF15_ISR_LOC	15
+#define PF_PF2VF_MAILBOX_ISR_RSVD0_LOC		16
+
+#define PF_VF_RESET_IN_PROGRESS(vf_id) \
+	(0x3000 + (vf_id) * 0x10000)
+#define PF_VF_RESET_IN_PROGRESS_RST 0xffff
+
+#define PF_VF_RESET_IN_PROGRESS_VF0_RESET_IN_PROGRESS	0x00000001
+#define PF_VF_RESET_IN_PROGRESS_VF1_RESET_IN_PROGRESS	0x00000002
+#define PF_VF_RESET_IN_PROGRESS_VF2_RESET_IN_PROGRESS	0x00000004
+#define PF_VF_RESET_IN_PROGRESS_VF3_RESET_IN_PROGRESS	0x00000008
+#define PF_VF_RESET_IN_PROGRESS_VF4_RESET_IN_PROGRESS	0x00000010
+#define PF_VF_RESET_IN_PROGRESS_VF5_RESET_IN_PROGRESS	0x00000020
+#define PF_VF_RESET_IN_PROGRESS_VF6_RESET_IN_PROGRESS	0x00000040
+#define PF_VF_RESET_IN_PROGRESS_VF7_RESET_IN_PROGRESS	0x00000080
+#define PF_VF_RESET_IN_PROGRESS_VF8_RESET_IN_PROGRESS	0x00000100
+#define PF_VF_RESET_IN_PROGRESS_VF9_RESET_IN_PROGRESS	0x00000200
+#define PF_VF_RESET_IN_PROGRESS_VF10_RESET_IN_PROGRESS	0x00000400
+#define PF_VF_RESET_IN_PROGRESS_VF11_RESET_IN_PROGRESS	0x00000800
+#define PF_VF_RESET_IN_PROGRESS_VF12_RESET_IN_PROGRESS	0x00001000
+#define PF_VF_RESET_IN_PROGRESS_VF13_RESET_IN_PROGRESS	0x00002000
+#define PF_VF_RESET_IN_PROGRESS_VF14_RESET_IN_PROGRESS	0x00004000
+#define PF_VF_RESET_IN_PROGRESS_VF15_RESET_IN_PROGRESS	0x00008000
+#define PF_VF_RESET_IN_PROGRESS_RSVD0			0xFFFF0000
+#define PF_VF_RESET_IN_PROGRESS_VF0_RESET_IN_PROGRESS_LOC	0
+#define PF_VF_RESET_IN_PROGRESS_VF1_RESET_IN_PROGRESS_LOC	1
+#define PF_VF_RESET_IN_PROGRESS_VF2_RESET_IN_PROGRESS_LOC	2
+#define PF_VF_RESET_IN_PROGRESS_VF3_RESET_IN_PROGRESS_LOC	3
+#define PF_VF_RESET_IN_PROGRESS_VF4_RESET_IN_PROGRESS_LOC	4
+#define PF_VF_RESET_IN_PROGRESS_VF5_RESET_IN_PROGRESS_LOC	5
+#define PF_VF_RESET_IN_PROGRESS_VF6_RESET_IN_PROGRESS_LOC	6
+#define PF_VF_RESET_IN_PROGRESS_VF7_RESET_IN_PROGRESS_LOC	7
+#define PF_VF_RESET_IN_PROGRESS_VF8_RESET_IN_PROGRESS_LOC	8
+#define PF_VF_RESET_IN_PROGRESS_VF9_RESET_IN_PROGRESS_LOC	9
+#define PF_VF_RESET_IN_PROGRESS_VF10_RESET_IN_PROGRESS_LOC	10
+#define PF_VF_RESET_IN_PROGRESS_VF11_RESET_IN_PROGRESS_LOC	11
+#define PF_VF_RESET_IN_PROGRESS_VF12_RESET_IN_PROGRESS_LOC	12
+#define PF_VF_RESET_IN_PROGRESS_VF13_RESET_IN_PROGRESS_LOC	13
+#define PF_VF_RESET_IN_PROGRESS_VF14_RESET_IN_PROGRESS_LOC	14
+#define PF_VF_RESET_IN_PROGRESS_VF15_RESET_IN_PROGRESS_LOC	15
+#define PF_VF_RESET_IN_PROGRESS_RSVD0_LOC			16
+
+#define MSIX_VECTOR_CTRL(x) \
+	(0x100000c + (x) * 0x10)
+#define MSIX_VECTOR_CTRL_RST 0x1
+
+#define MSIX_VECTOR_CTRL_VEC_MASK	0x00000001
+#define MSIX_VECTOR_CTRL_RSVD0		0xFFFFFFFE
+#define MSIX_VECTOR_CTRL_VEC_MASK_LOC	0
+#define MSIX_VECTOR_CTRL_RSVD0_LOC	1
+
+#define IOSF_SMON_COMP_MASK1(x) \
+	(0x8002024 + (x) * 0x40)
+#define IOSF_SMON_COMP_MASK1_RST 0xffffffff
+
+#define IOSF_SMON_COMP_MASK1_COMP_MASK1	0xFFFFFFFF
+#define IOSF_SMON_COMP_MASK1_COMP_MASK1_LOC	0
+
+#define IOSF_SMON_COMP_MASK0(x) \
+	(0x8002020 + (x) * 0x40)
+#define IOSF_SMON_COMP_MASK0_RST 0xffffffff
+
+#define IOSF_SMON_COMP_MASK0_COMP_MASK0	0xFFFFFFFF
+#define IOSF_SMON_COMP_MASK0_COMP_MASK0_LOC	0
+
+#define IOSF_SMON_MAX_TMR(x) \
+	(0x800201c + (x) * 0x40)
+#define IOSF_SMON_MAX_TMR_RST 0x0
+
+#define IOSF_SMON_MAX_TMR_MAXVALUE	0xFFFFFFFF
+#define IOSF_SMON_MAX_TMR_MAXVALUE_LOC	0
+
+#define IOSF_SMON_TMR(x) \
+	(0x8002018 + (x) * 0x40)
+#define IOSF_SMON_TMR_RST 0x0
+
+#define IOSF_SMON_TMR_TIMER_VAL	0xFFFFFFFF
+#define IOSF_SMON_TMR_TIMER_VAL_LOC	0
+
+#define IOSF_SMON_ACTIVITYCNTR1(x) \
+	(0x8002014 + (x) * 0x40)
+#define IOSF_SMON_ACTIVITYCNTR1_RST 0x0
+
+#define IOSF_SMON_ACTIVITYCNTR1_COUNTER1	0xFFFFFFFF
+#define IOSF_SMON_ACTIVITYCNTR1_COUNTER1_LOC	0
+
+#define IOSF_SMON_ACTIVITYCNTR0(x) \
+	(0x8002010 + (x) * 0x40)
+#define IOSF_SMON_ACTIVITYCNTR0_RST 0x0
+
+#define IOSF_SMON_ACTIVITYCNTR0_COUNTER0	0xFFFFFFFF
+#define IOSF_SMON_ACTIVITYCNTR0_COUNTER0_LOC	0
+
+#define IOSF_SMON_COMPARE1(x) \
+	(0x800200c + (x) * 0x40)
+#define IOSF_SMON_COMPARE1_RST 0x0
+
+#define IOSF_SMON_COMPARE1_COMPARE1	0xFFFFFFFF
+#define IOSF_SMON_COMPARE1_COMPARE1_LOC	0
+
+#define IOSF_SMON_COMPARE0(x) \
+	(0x8002008 + (x) * 0x40)
+#define IOSF_SMON_COMPARE0_RST 0x0
+
+#define IOSF_SMON_COMPARE0_COMPARE0	0xFFFFFFFF
+#define IOSF_SMON_COMPARE0_COMPARE0_LOC	0
+
+#define IOSF_SMON_CFG1(x) \
+	(0x8002004 + (x) * 0x40)
+#define IOSF_SMON_CFG1_RST 0x0
+
+#define IOSF_SMON_CFG1_MODE0	0x000000FF
+#define IOSF_SMON_CFG1_MODE1	0x0000FF00
+#define IOSF_SMON_CFG1_RSVD	0xFFFF0000
+#define IOSF_SMON_CFG1_MODE0_LOC	0
+#define IOSF_SMON_CFG1_MODE1_LOC	8
+#define IOSF_SMON_CFG1_RSVD_LOC		16
+
+#define IOSF_SMON_CFG0(x) \
+	(0x8002000 + (x) * 0x40)
+#define IOSF_SMON_CFG0_RST 0x40000000
+
+#define IOSF_SMON_CFG0_SMON_ENABLE		0x00000001
+#define IOSF_SMON_CFG0_RSVD2			0x0000000E
+#define IOSF_SMON_CFG0_SMON0_FUNCTION		0x00000070
+#define IOSF_SMON_CFG0_SMON0_FUNCTION_COMPARE	0x00000080
+#define IOSF_SMON_CFG0_SMON1_FUNCTION		0x00000700
+#define IOSF_SMON_CFG0_SMON1_FUNCTION_COMPARE	0x00000800
+#define IOSF_SMON_CFG0_SMON_MODE		0x0000F000
+#define IOSF_SMON_CFG0_STOPCOUNTEROVFL		0x00010000
+#define IOSF_SMON_CFG0_INTCOUNTEROVFL		0x00020000
+#define IOSF_SMON_CFG0_STATCOUNTER0OVFL		0x00040000
+#define IOSF_SMON_CFG0_STATCOUNTER1OVFL		0x00080000
+#define IOSF_SMON_CFG0_STOPTIMEROVFL		0x00100000
+#define IOSF_SMON_CFG0_INTTIMEROVFL		0x00200000
+#define IOSF_SMON_CFG0_STATTIMEROVFL		0x00400000
+#define IOSF_SMON_CFG0_RSVD1			0x00800000
+#define IOSF_SMON_CFG0_TIMER_PRESCALE		0x1F000000
+#define IOSF_SMON_CFG0_RSVD0			0x20000000
+#define IOSF_SMON_CFG0_VERSION			0xC0000000
+#define IOSF_SMON_CFG0_SMON_ENABLE_LOC			0
+#define IOSF_SMON_CFG0_RSVD2_LOC			1
+#define IOSF_SMON_CFG0_SMON0_FUNCTION_LOC		4
+#define IOSF_SMON_CFG0_SMON0_FUNCTION_COMPARE_LOC	7
+#define IOSF_SMON_CFG0_SMON1_FUNCTION_LOC		8
+#define IOSF_SMON_CFG0_SMON1_FUNCTION_COMPARE_LOC	11
+#define IOSF_SMON_CFG0_SMON_MODE_LOC			12
+#define IOSF_SMON_CFG0_STOPCOUNTEROVFL_LOC		16
+#define IOSF_SMON_CFG0_INTCOUNTEROVFL_LOC		17
+#define IOSF_SMON_CFG0_STATCOUNTER0OVFL_LOC		18
+#define IOSF_SMON_CFG0_STATCOUNTER1OVFL_LOC		19
+#define IOSF_SMON_CFG0_STOPTIMEROVFL_LOC		20
+#define IOSF_SMON_CFG0_INTTIMEROVFL_LOC			21
+#define IOSF_SMON_CFG0_STATTIMEROVFL_LOC		22
+#define IOSF_SMON_CFG0_RSVD1_LOC			23
+#define IOSF_SMON_CFG0_TIMER_PRESCALE_LOC		24
+#define IOSF_SMON_CFG0_RSVD0_LOC			29
+#define IOSF_SMON_CFG0_VERSION_LOC			30
+
+#define IOSF_FUNC_VF_BAR_DSBL(x) \
+	(0x20 + (x) * 0x4)
+#define IOSF_FUNC_VF_BAR_DSBL_RST 0x0
+
+#define IOSF_FUNC_VF_BAR_DSBL_FUNC_VF_BAR_DIS	0x00000001
+#define IOSF_FUNC_VF_BAR_DSBL_RSVD0		0xFFFFFFFE
+#define IOSF_FUNC_VF_BAR_DSBL_FUNC_VF_BAR_DIS_LOC	0
+#define IOSF_FUNC_VF_BAR_DSBL_RSVD0_LOC			1
+
+#define SYS_TOTAL_VAS 0x1000011c
+#define SYS_TOTAL_VAS_RST 0x20
+
+#define SYS_TOTAL_VAS_TOTAL_VAS	0xFFFFFFFF
+#define SYS_TOTAL_VAS_TOTAL_VAS_LOC	0
+
+#define SYS_TOTAL_DIR_PORTS 0x10000118
+#define SYS_TOTAL_DIR_PORTS_RST 0x40
+
+#define SYS_TOTAL_DIR_PORTS_TOTAL_DIR_PORTS	0xFFFFFFFF
+#define SYS_TOTAL_DIR_PORTS_TOTAL_DIR_PORTS_LOC	0
+
+#define SYS_TOTAL_LDB_PORTS 0x10000114
+#define SYS_TOTAL_LDB_PORTS_RST 0x40
+
+#define SYS_TOTAL_LDB_PORTS_TOTAL_LDB_PORTS	0xFFFFFFFF
+#define SYS_TOTAL_LDB_PORTS_TOTAL_LDB_PORTS_LOC	0
+
+#define SYS_TOTAL_DIR_QID 0x10000110
+#define SYS_TOTAL_DIR_QID_RST 0x40
+
+#define SYS_TOTAL_DIR_QID_TOTAL_DIR_QID	0xFFFFFFFF
+#define SYS_TOTAL_DIR_QID_TOTAL_DIR_QID_LOC	0
+
+#define SYS_TOTAL_LDB_QID 0x1000010c
+#define SYS_TOTAL_LDB_QID_RST 0x20
+
+#define SYS_TOTAL_LDB_QID_TOTAL_LDB_QID	0xFFFFFFFF
+#define SYS_TOTAL_LDB_QID_TOTAL_LDB_QID_LOC	0
+
+#define SYS_TOTAL_DIR_CRDS 0x10000108
+#define SYS_TOTAL_DIR_CRDS_RST 0x1000
+
+#define SYS_TOTAL_DIR_CRDS_TOTAL_DIR_CREDITS	0xFFFFFFFF
+#define SYS_TOTAL_DIR_CRDS_TOTAL_DIR_CREDITS_LOC	0
+
+#define SYS_TOTAL_LDB_CRDS 0x10000104
+#define SYS_TOTAL_LDB_CRDS_RST 0x2000
+
+#define SYS_TOTAL_LDB_CRDS_TOTAL_LDB_CREDITS	0xFFFFFFFF
+#define SYS_TOTAL_LDB_CRDS_TOTAL_LDB_CREDITS_LOC	0
+
+#define SYS_ALARM_PF_SYND2 0x10000508
+#define SYS_ALARM_PF_SYND2_RST 0x0
+
+#define SYS_ALARM_PF_SYND2_LOCK_ID	0x0000FFFF
+#define SYS_ALARM_PF_SYND2_MEAS		0x00010000
+#define SYS_ALARM_PF_SYND2_DEBUG	0x00FE0000
+#define SYS_ALARM_PF_SYND2_CQ_POP	0x01000000
+#define SYS_ALARM_PF_SYND2_QE_UHL	0x02000000
+#define SYS_ALARM_PF_SYND2_QE_ORSP	0x04000000
+#define SYS_ALARM_PF_SYND2_QE_VALID	0x08000000
+#define SYS_ALARM_PF_SYND2_CQ_INT_REARM	0x10000000
+#define SYS_ALARM_PF_SYND2_DSI_ERROR	0x20000000
+#define SYS_ALARM_PF_SYND2_RSVD0	0xC0000000
+#define SYS_ALARM_PF_SYND2_LOCK_ID_LOC		0
+#define SYS_ALARM_PF_SYND2_MEAS_LOC		16
+#define SYS_ALARM_PF_SYND2_DEBUG_LOC		17
+#define SYS_ALARM_PF_SYND2_CQ_POP_LOC		24
+#define SYS_ALARM_PF_SYND2_QE_UHL_LOC		25
+#define SYS_ALARM_PF_SYND2_QE_ORSP_LOC		26
+#define SYS_ALARM_PF_SYND2_QE_VALID_LOC		27
+#define SYS_ALARM_PF_SYND2_CQ_INT_REARM_LOC	28
+#define SYS_ALARM_PF_SYND2_DSI_ERROR_LOC	29
+#define SYS_ALARM_PF_SYND2_RSVD0_LOC		30
+
+#define SYS_ALARM_PF_SYND1 0x10000504
+#define SYS_ALARM_PF_SYND1_RST 0x0
+
+#define SYS_ALARM_PF_SYND1_DSI		0x0000FFFF
+#define SYS_ALARM_PF_SYND1_QID		0x00FF0000
+#define SYS_ALARM_PF_SYND1_QTYPE	0x03000000
+#define SYS_ALARM_PF_SYND1_QPRI		0x1C000000
+#define SYS_ALARM_PF_SYND1_MSG_TYPE	0xE0000000
+#define SYS_ALARM_PF_SYND1_DSI_LOC	0
+#define SYS_ALARM_PF_SYND1_QID_LOC	16
+#define SYS_ALARM_PF_SYND1_QTYPE_LOC	24
+#define SYS_ALARM_PF_SYND1_QPRI_LOC	26
+#define SYS_ALARM_PF_SYND1_MSG_TYPE_LOC	29
+
+#define SYS_ALARM_PF_SYND0 0x10000500
+#define SYS_ALARM_PF_SYND0_RST 0x0
+
+#define SYS_ALARM_PF_SYND0_SYNDROME	0x000000FF
+#define SYS_ALARM_PF_SYND0_RTYPE	0x00000300
+#define SYS_ALARM_PF_SYND0_RSVD0	0x00001C00
+#define SYS_ALARM_PF_SYND0_IS_LDB	0x00002000
+#define SYS_ALARM_PF_SYND0_CLS		0x0000C000
+#define SYS_ALARM_PF_SYND0_AID		0x003F0000
+#define SYS_ALARM_PF_SYND0_UNIT		0x03C00000
+#define SYS_ALARM_PF_SYND0_SOURCE	0x3C000000
+#define SYS_ALARM_PF_SYND0_MORE		0x40000000
+#define SYS_ALARM_PF_SYND0_VALID	0x80000000
+#define SYS_ALARM_PF_SYND0_SYNDROME_LOC	0
+#define SYS_ALARM_PF_SYND0_RTYPE_LOC	8
+#define SYS_ALARM_PF_SYND0_RSVD0_LOC	10
+#define SYS_ALARM_PF_SYND0_IS_LDB_LOC	13
+#define SYS_ALARM_PF_SYND0_CLS_LOC	14
+#define SYS_ALARM_PF_SYND0_AID_LOC	16
+#define SYS_ALARM_PF_SYND0_UNIT_LOC	22
+#define SYS_ALARM_PF_SYND0_SOURCE_LOC	26
+#define SYS_ALARM_PF_SYND0_MORE_LOC	30
+#define SYS_ALARM_PF_SYND0_VALID_LOC	31
+
+#define SYS_VF_LDB_VPP_V(x) \
+	(0x10000f00 + (x) * 0x1000)
+#define SYS_VF_LDB_VPP_V_RST 0x0
+
+#define SYS_VF_LDB_VPP_V_VPP_V	0x00000001
+#define SYS_VF_LDB_VPP_V_RSVD0	0xFFFFFFFE
+#define SYS_VF_LDB_VPP_V_VPP_V_LOC	0
+#define SYS_VF_LDB_VPP_V_RSVD0_LOC	1
+
+#define SYS_VF_LDB_VPP2PP(x) \
+	(0x10000f04 + (x) * 0x1000)
+#define SYS_VF_LDB_VPP2PP_RST 0x0
+
+#define SYS_VF_LDB_VPP2PP_PP	0x0000003F
+#define SYS_VF_LDB_VPP2PP_RSVD0	0xFFFFFFC0
+#define SYS_VF_LDB_VPP2PP_PP_LOC	0
+#define SYS_VF_LDB_VPP2PP_RSVD0_LOC	6
+
+#define SYS_VF_DIR_VPP_V(x) \
+	(0x10000f08 + (x) * 0x1000)
+#define SYS_VF_DIR_VPP_V_RST 0x0
+
+#define SYS_VF_DIR_VPP_V_VPP_V	0x00000001
+#define SYS_VF_DIR_VPP_V_RSVD0	0xFFFFFFFE
+#define SYS_VF_DIR_VPP_V_VPP_V_LOC	0
+#define SYS_VF_DIR_VPP_V_RSVD0_LOC	1
+
+#define SYS_VF_DIR_VPP2PP(x) \
+	(0x10000f0c + (x) * 0x1000)
+#define SYS_VF_DIR_VPP2PP_RST 0x0
+
+#define SYS_VF_DIR_VPP2PP_PP	0x0000003F
+#define SYS_VF_DIR_VPP2PP_RSVD0	0xFFFFFFC0
+#define SYS_VF_DIR_VPP2PP_PP_LOC	0
+#define SYS_VF_DIR_VPP2PP_RSVD0_LOC	6
+
+#define SYS_VF_LDB_VQID_V(x) \
+	(0x10000f10 + (x) * 0x1000)
+#define SYS_VF_LDB_VQID_V_RST 0x0
+
+#define SYS_VF_LDB_VQID_V_VQID_V	0x00000001
+#define SYS_VF_LDB_VQID_V_RSVD0		0xFFFFFFFE
+#define SYS_VF_LDB_VQID_V_VQID_V_LOC	0
+#define SYS_VF_LDB_VQID_V_RSVD0_LOC	1
+
+#define SYS_VF_LDB_VQID2QID(x) \
+	(0x10000f14 + (x) * 0x1000)
+#define SYS_VF_LDB_VQID2QID_RST 0x0
+
+#define SYS_VF_LDB_VQID2QID_QID		0x0000001F
+#define SYS_VF_LDB_VQID2QID_RSVD0	0xFFFFFFE0
+#define SYS_VF_LDB_VQID2QID_QID_LOC	0
+#define SYS_VF_LDB_VQID2QID_RSVD0_LOC	5
+
+#define SYS_LDB_QID2VQID(x) \
+	(0x10000f18 + (x) * 0x1000)
+#define SYS_LDB_QID2VQID_RST 0x0
+
+#define SYS_LDB_QID2VQID_VQID	0x0000001F
+#define SYS_LDB_QID2VQID_RSVD0	0xFFFFFFE0
+#define SYS_LDB_QID2VQID_VQID_LOC	0
+#define SYS_LDB_QID2VQID_RSVD0_LOC	5
+
+#define SYS_VF_DIR_VQID_V(x) \
+	(0x10000f1c + (x) * 0x1000)
+#define SYS_VF_DIR_VQID_V_RST 0x0
+
+#define SYS_VF_DIR_VQID_V_VQID_V	0x00000001
+#define SYS_VF_DIR_VQID_V_RSVD0		0xFFFFFFFE
+#define SYS_VF_DIR_VQID_V_VQID_V_LOC	0
+#define SYS_VF_DIR_VQID_V_RSVD0_LOC	1
+
+#define SYS_VF_DIR_VQID2QID(x) \
+	(0x10000f20 + (x) * 0x1000)
+#define SYS_VF_DIR_VQID2QID_RST 0x0
+
+#define SYS_VF_DIR_VQID2QID_QID		0x0000003F
+#define SYS_VF_DIR_VQID2QID_RSVD0	0xFFFFFFC0
+#define SYS_VF_DIR_VQID2QID_QID_LOC	0
+#define SYS_VF_DIR_VQID2QID_RSVD0_LOC	6
+
+#define SYS_LDB_VASQID_V(x) \
+	(0x10000f24 + (x) * 0x1000)
+#define SYS_LDB_VASQID_V_RST 0x0
+
+#define SYS_LDB_VASQID_V_VASQID_V	0x00000001
+#define SYS_LDB_VASQID_V_RSVD0		0xFFFFFFFE
+#define SYS_LDB_VASQID_V_VASQID_V_LOC	0
+#define SYS_LDB_VASQID_V_RSVD0_LOC	1
+
+#define SYS_DIR_VASQID_V(x) \
+	(0x10000f28 + (x) * 0x1000)
+#define SYS_DIR_VASQID_V_RST 0x0
+
+#define SYS_DIR_VASQID_V_VASQID_V	0x00000001
+#define SYS_DIR_VASQID_V_RSVD0		0xFFFFFFFE
+#define SYS_DIR_VASQID_V_VASQID_V_LOC	0
+#define SYS_DIR_VASQID_V_RSVD0_LOC	1
+
+#define SYS_ALARM_VF_SYND2(x) \
+	(0x10000f48 + (x) * 0x1000)
+#define SYS_ALARM_VF_SYND2_RST 0x0
+
+#define SYS_ALARM_VF_SYND2_LOCK_ID	0x0000FFFF
+#define SYS_ALARM_VF_SYND2_DEBUG	0x00FF0000
+#define SYS_ALARM_VF_SYND2_CQ_POP	0x01000000
+#define SYS_ALARM_VF_SYND2_QE_UHL	0x02000000
+#define SYS_ALARM_VF_SYND2_QE_ORSP	0x04000000
+#define SYS_ALARM_VF_SYND2_QE_VALID	0x08000000
+#define SYS_ALARM_VF_SYND2_ISZ		0x10000000
+#define SYS_ALARM_VF_SYND2_DSI_ERROR	0x20000000
+#define SYS_ALARM_VF_SYND2_DLBRSVD	0xC0000000
+#define SYS_ALARM_VF_SYND2_LOCK_ID_LOC		0
+#define SYS_ALARM_VF_SYND2_DEBUG_LOC		16
+#define SYS_ALARM_VF_SYND2_CQ_POP_LOC		24
+#define SYS_ALARM_VF_SYND2_QE_UHL_LOC		25
+#define SYS_ALARM_VF_SYND2_QE_ORSP_LOC		26
+#define SYS_ALARM_VF_SYND2_QE_VALID_LOC		27
+#define SYS_ALARM_VF_SYND2_ISZ_LOC		28
+#define SYS_ALARM_VF_SYND2_DSI_ERROR_LOC	29
+#define SYS_ALARM_VF_SYND2_DLBRSVD_LOC		30
+
+#define SYS_ALARM_VF_SYND1(x) \
+	(0x10000f44 + (x) * 0x1000)
+#define SYS_ALARM_VF_SYND1_RST 0x0
+
+#define SYS_ALARM_VF_SYND1_DSI		0x0000FFFF
+#define SYS_ALARM_VF_SYND1_QID		0x00FF0000
+#define SYS_ALARM_VF_SYND1_QTYPE	0x03000000
+#define SYS_ALARM_VF_SYND1_QPRI		0x1C000000
+#define SYS_ALARM_VF_SYND1_MSG_TYPE	0xE0000000
+#define SYS_ALARM_VF_SYND1_DSI_LOC	0
+#define SYS_ALARM_VF_SYND1_QID_LOC	16
+#define SYS_ALARM_VF_SYND1_QTYPE_LOC	24
+#define SYS_ALARM_VF_SYND1_QPRI_LOC	26
+#define SYS_ALARM_VF_SYND1_MSG_TYPE_LOC	29
+
+#define SYS_ALARM_VF_SYND0(x) \
+	(0x10000f40 + (x) * 0x1000)
+#define SYS_ALARM_VF_SYND0_RST 0x0
+
+#define SYS_ALARM_VF_SYND0_SYNDROME		0x000000FF
+#define SYS_ALARM_VF_SYND0_RTYPE		0x00000300
+#define SYS_ALARM_VF_SYND0_VF_SYND0_PARITY	0x00000400
+#define SYS_ALARM_VF_SYND0_VF_SYND1_PARITY	0x00000800
+#define SYS_ALARM_VF_SYND0_VF_SYND2_PARITY	0x00001000
+#define SYS_ALARM_VF_SYND0_IS_LDB		0x00002000
+#define SYS_ALARM_VF_SYND0_CLS			0x0000C000
+#define SYS_ALARM_VF_SYND0_AID			0x003F0000
+#define SYS_ALARM_VF_SYND0_UNIT			0x03C00000
+#define SYS_ALARM_VF_SYND0_SOURCE		0x3C000000
+#define SYS_ALARM_VF_SYND0_MORE			0x40000000
+#define SYS_ALARM_VF_SYND0_VALID		0x80000000
+#define SYS_ALARM_VF_SYND0_SYNDROME_LOC		0
+#define SYS_ALARM_VF_SYND0_RTYPE_LOC		8
+#define SYS_ALARM_VF_SYND0_VF_SYND0_PARITY_LOC	10
+#define SYS_ALARM_VF_SYND0_VF_SYND1_PARITY_LOC	11
+#define SYS_ALARM_VF_SYND0_VF_SYND2_PARITY_LOC	12
+#define SYS_ALARM_VF_SYND0_IS_LDB_LOC		13
+#define SYS_ALARM_VF_SYND0_CLS_LOC		14
+#define SYS_ALARM_VF_SYND0_AID_LOC		16
+#define SYS_ALARM_VF_SYND0_UNIT_LOC		22
+#define SYS_ALARM_VF_SYND0_SOURCE_LOC		26
+#define SYS_ALARM_VF_SYND0_MORE_LOC		30
+#define SYS_ALARM_VF_SYND0_VALID_LOC		31
+
+#define SYS_LDB_QID_CFG_V(x) \
+	(0x10000f58 + (x) * 0x1000)
+#define SYS_LDB_QID_CFG_V_RST 0x0
+
+#define SYS_LDB_QID_CFG_V_SN_CFG_V	0x00000001
+#define SYS_LDB_QID_CFG_V_FID_CFG_V	0x00000002
+#define SYS_LDB_QID_CFG_V_RSVD0		0xFFFFFFFC
+#define SYS_LDB_QID_CFG_V_SN_CFG_V_LOC	0
+#define SYS_LDB_QID_CFG_V_FID_CFG_V_LOC	1
+#define SYS_LDB_QID_CFG_V_RSVD0_LOC	2
+
+#define SYS_LDB_QID_ITS(x) \
+	(0x10000f54 + (x) * 0x1000)
+#define SYS_LDB_QID_ITS_RST 0x0
+
+#define SYS_LDB_QID_ITS_QID_ITS	0x00000001
+#define SYS_LDB_QID_ITS_RSVD0	0xFFFFFFFE
+#define SYS_LDB_QID_ITS_QID_ITS_LOC	0
+#define SYS_LDB_QID_ITS_RSVD0_LOC	1
+
+#define SYS_LDB_QID_V(x) \
+	(0x10000f50 + (x) * 0x1000)
+#define SYS_LDB_QID_V_RST 0x0
+
+#define SYS_LDB_QID_V_QID_V	0x00000001
+#define SYS_LDB_QID_V_RSVD0	0xFFFFFFFE
+#define SYS_LDB_QID_V_QID_V_LOC	0
+#define SYS_LDB_QID_V_RSVD0_LOC	1
+
+#define SYS_DIR_QID_ITS(x) \
+	(0x10000f64 + (x) * 0x1000)
+#define SYS_DIR_QID_ITS_RST 0x0
+
+#define SYS_DIR_QID_ITS_QID_ITS	0x00000001
+#define SYS_DIR_QID_ITS_RSVD0	0xFFFFFFFE
+#define SYS_DIR_QID_ITS_QID_ITS_LOC	0
+#define SYS_DIR_QID_ITS_RSVD0_LOC	1
+
+#define SYS_DIR_QID_V(x) \
+	(0x10000f60 + (x) * 0x1000)
+#define SYS_DIR_QID_V_RST 0x0
+
+#define SYS_DIR_QID_V_QID_V	0x00000001
+#define SYS_DIR_QID_V_RSVD0	0xFFFFFFFE
+#define SYS_DIR_QID_V_QID_V_LOC	0
+#define SYS_DIR_QID_V_RSVD0_LOC	1
+
+#define SYS_LDB_CQ_AI_DATA(x) \
+	(0x10000fa8 + (x) * 0x1000)
+#define SYS_LDB_CQ_AI_DATA_RST 0x0
+
+#define SYS_LDB_CQ_AI_DATA_CQ_AI_DATA	0xFFFFFFFF
+#define SYS_LDB_CQ_AI_DATA_CQ_AI_DATA_LOC	0
+
+#define SYS_LDB_CQ_AI_ADDR(x) \
+	(0x10000fa4 + (x) * 0x1000)
+#define SYS_LDB_CQ_AI_ADDR_RST 0x0
+
+#define SYS_LDB_CQ_AI_ADDR_RSVD1	0x00000003
+#define SYS_LDB_CQ_AI_ADDR_CQ_AI_ADDR	0x000FFFFC
+#define SYS_LDB_CQ_AI_ADDR_RSVD0	0xFFF00000
+#define SYS_LDB_CQ_AI_ADDR_RSVD1_LOC		0
+#define SYS_LDB_CQ_AI_ADDR_CQ_AI_ADDR_LOC	2
+#define SYS_LDB_CQ_AI_ADDR_RSVD0_LOC		20
+
+#define SYS_LDB_CQ_PASID(x) \
+	(0x10000fa0 + (x) * 0x1000)
+#define SYS_LDB_CQ_PASID_RST 0x0
+
+#define SYS_LDB_CQ_PASID_PASID		0x000FFFFF
+#define SYS_LDB_CQ_PASID_EXE_REQ	0x00100000
+#define SYS_LDB_CQ_PASID_PRIV_REQ	0x00200000
+#define SYS_LDB_CQ_PASID_FMT2		0x00400000
+#define SYS_LDB_CQ_PASID_RSVD0		0xFF800000
+#define SYS_LDB_CQ_PASID_PASID_LOC	0
+#define SYS_LDB_CQ_PASID_EXE_REQ_LOC	20
+#define SYS_LDB_CQ_PASID_PRIV_REQ_LOC	21
+#define SYS_LDB_CQ_PASID_FMT2_LOC	22
+#define SYS_LDB_CQ_PASID_RSVD0_LOC	23
+
+#define SYS_LDB_CQ_AT(x) \
+	(0x10000f9c + (x) * 0x1000)
+#define SYS_LDB_CQ_AT_RST 0x0
+
+#define SYS_LDB_CQ_AT_CQ_AT	0x00000003
+#define SYS_LDB_CQ_AT_RSVD0	0xFFFFFFFC
+#define SYS_LDB_CQ_AT_CQ_AT_LOC	0
+#define SYS_LDB_CQ_AT_RSVD0_LOC	2
+
+#define SYS_LDB_CQ_ISR(x) \
+	(0x10000f98 + (x) * 0x1000)
+#define SYS_LDB_CQ_ISR_RST 0x0
+/* CQ Interrupt Modes */
+#define DLB_CQ_ISR_MODE_DIS  0
+#define DLB_CQ_ISR_MODE_MSI  1
+#define DLB_CQ_ISR_MODE_MSIX 2
+#define DLB_CQ_ISR_MODE_ADI  3
+
+#define SYS_LDB_CQ_ISR_VECTOR	0x0000003F
+#define SYS_LDB_CQ_ISR_VF	0x000003C0
+#define SYS_LDB_CQ_ISR_EN_CODE	0x00000C00
+#define SYS_LDB_CQ_ISR_RSVD0	0xFFFFF000
+#define SYS_LDB_CQ_ISR_VECTOR_LOC	0
+#define SYS_LDB_CQ_ISR_VF_LOC		6
+#define SYS_LDB_CQ_ISR_EN_CODE_LOC	10
+#define SYS_LDB_CQ_ISR_RSVD0_LOC	12
+
+#define SYS_LDB_CQ2VF_PF_RO(x) \
+	(0x10000f94 + (x) * 0x1000)
+#define SYS_LDB_CQ2VF_PF_RO_RST 0x0
+
+#define SYS_LDB_CQ2VF_PF_RO_VF		0x0000000F
+#define SYS_LDB_CQ2VF_PF_RO_IS_PF	0x00000010
+#define SYS_LDB_CQ2VF_PF_RO_RO		0x00000020
+#define SYS_LDB_CQ2VF_PF_RO_RSVD0	0xFFFFFFC0
+#define SYS_LDB_CQ2VF_PF_RO_VF_LOC	0
+#define SYS_LDB_CQ2VF_PF_RO_IS_PF_LOC	4
+#define SYS_LDB_CQ2VF_PF_RO_RO_LOC	5
+#define SYS_LDB_CQ2VF_PF_RO_RSVD0_LOC	6
+
+#define SYS_LDB_PP_V(x) \
+	(0x10000f90 + (x) * 0x1000)
+#define SYS_LDB_PP_V_RST 0x0
+
+#define SYS_LDB_PP_V_PP_V	0x00000001
+#define SYS_LDB_PP_V_RSVD0	0xFFFFFFFE
+#define SYS_LDB_PP_V_PP_V_LOC	0
+#define SYS_LDB_PP_V_RSVD0_LOC	1
+
+#define SYS_LDB_PP2VDEV(x) \
+	(0x10000f8c + (x) * 0x1000)
+#define SYS_LDB_PP2VDEV_RST 0x0
+
+#define SYS_LDB_PP2VDEV_VDEV	0x0000000F
+#define SYS_LDB_PP2VDEV_RSVD0	0xFFFFFFF0
+#define SYS_LDB_PP2VDEV_VDEV_LOC	0
+#define SYS_LDB_PP2VDEV_RSVD0_LOC	4
+
+#define SYS_LDB_PP2VAS(x) \
+	(0x10000f88 + (x) * 0x1000)
+#define SYS_LDB_PP2VAS_RST 0x0
+
+#define SYS_LDB_PP2VAS_VAS	0x0000001F
+#define SYS_LDB_PP2VAS_RSVD0	0xFFFFFFE0
+#define SYS_LDB_PP2VAS_VAS_LOC		0
+#define SYS_LDB_PP2VAS_RSVD0_LOC	5
+
+#define SYS_LDB_CQ_ADDR_U(x) \
+	(0x10000f84 + (x) * 0x1000)
+#define SYS_LDB_CQ_ADDR_U_RST 0x0
+
+#define SYS_LDB_CQ_ADDR_U_ADDR_U	0xFFFFFFFF
+#define SYS_LDB_CQ_ADDR_U_ADDR_U_LOC	0
+
+#define SYS_LDB_CQ_ADDR_L(x) \
+	(0x10000f80 + (x) * 0x1000)
+#define SYS_LDB_CQ_ADDR_L_RST 0x0
+
+#define SYS_LDB_CQ_ADDR_L_RSVD0		0x0000003F
+#define SYS_LDB_CQ_ADDR_L_ADDR_L	0xFFFFFFC0
+#define SYS_LDB_CQ_ADDR_L_RSVD0_LOC	0
+#define SYS_LDB_CQ_ADDR_L_ADDR_L_LOC	6
+
+#define SYS_DIR_CQ_FMT(x) \
+	(0x10000fec + (x) * 0x1000)
+#define SYS_DIR_CQ_FMT_RST 0x0
+
+#define SYS_DIR_CQ_FMT_KEEP_PF_PPID	0x00000001
+#define SYS_DIR_CQ_FMT_RSVD0		0xFFFFFFFE
+#define SYS_DIR_CQ_FMT_KEEP_PF_PPID_LOC	0
+#define SYS_DIR_CQ_FMT_RSVD0_LOC	1
+
+#define SYS_DIR_CQ_AI_DATA(x) \
+	(0x10000fe8 + (x) * 0x1000)
+#define SYS_DIR_CQ_AI_DATA_RST 0x0
+
+#define SYS_DIR_CQ_AI_DATA_CQ_AI_DATA	0xFFFFFFFF
+#define SYS_DIR_CQ_AI_DATA_CQ_AI_DATA_LOC	0
+
+#define SYS_DIR_CQ_AI_ADDR(x) \
+	(0x10000fe4 + (x) * 0x1000)
+#define SYS_DIR_CQ_AI_ADDR_RST 0x0
+
+#define SYS_DIR_CQ_AI_ADDR_RSVD1	0x00000003
+#define SYS_DIR_CQ_AI_ADDR_CQ_AI_ADDR	0x000FFFFC
+#define SYS_DIR_CQ_AI_ADDR_RSVD0	0xFFF00000
+#define SYS_DIR_CQ_AI_ADDR_RSVD1_LOC		0
+#define SYS_DIR_CQ_AI_ADDR_CQ_AI_ADDR_LOC	2
+#define SYS_DIR_CQ_AI_ADDR_RSVD0_LOC		20
+
+#define SYS_DIR_CQ_PASID(x) \
+	(0x10000fe0 + (x) * 0x1000)
+#define SYS_DIR_CQ_PASID_RST 0x0
+
+#define SYS_DIR_CQ_PASID_PASID		0x000FFFFF
+#define SYS_DIR_CQ_PASID_EXE_REQ	0x00100000
+#define SYS_DIR_CQ_PASID_PRIV_REQ	0x00200000
+#define SYS_DIR_CQ_PASID_FMT2		0x00400000
+#define SYS_DIR_CQ_PASID_RSVD0		0xFF800000
+#define SYS_DIR_CQ_PASID_PASID_LOC	0
+#define SYS_DIR_CQ_PASID_EXE_REQ_LOC	20
+#define SYS_DIR_CQ_PASID_PRIV_REQ_LOC	21
+#define SYS_DIR_CQ_PASID_FMT2_LOC	22
+#define SYS_DIR_CQ_PASID_RSVD0_LOC	23
+
+#define SYS_DIR_CQ_AT(x) \
+	(0x10000fdc + (x) * 0x1000)
+#define SYS_DIR_CQ_AT_RST 0x0
+
+#define SYS_DIR_CQ_AT_CQ_AT	0x00000003
+#define SYS_DIR_CQ_AT_RSVD0	0xFFFFFFFC
+#define SYS_DIR_CQ_AT_CQ_AT_LOC	0
+#define SYS_DIR_CQ_AT_RSVD0_LOC	2
+
+#define SYS_DIR_CQ_ISR(x) \
+	(0x10000fd8 + (x) * 0x1000)
+#define SYS_DIR_CQ_ISR_RST 0x0
+
+#define SYS_DIR_CQ_ISR_VECTOR	0x0000003F
+#define SYS_DIR_CQ_ISR_VF	0x000003C0
+#define SYS_DIR_CQ_ISR_EN_CODE	0x00000C00
+#define SYS_DIR_CQ_ISR_RSVD0	0xFFFFF000
+#define SYS_DIR_CQ_ISR_VECTOR_LOC	0
+#define SYS_DIR_CQ_ISR_VF_LOC		6
+#define SYS_DIR_CQ_ISR_EN_CODE_LOC	10
+#define SYS_DIR_CQ_ISR_RSVD0_LOC	12
+
+#define SYS_DIR_CQ2VF_PF_RO(x) \
+	(0x10000fd4 + (x) * 0x1000)
+#define SYS_DIR_CQ2VF_PF_RO_RST 0x0
+
+#define SYS_DIR_CQ2VF_PF_RO_VF		0x0000000F
+#define SYS_DIR_CQ2VF_PF_RO_IS_PF	0x00000010
+#define SYS_DIR_CQ2VF_PF_RO_RO		0x00000020
+#define SYS_DIR_CQ2VF_PF_RO_RSVD0	0xFFFFFFC0
+#define SYS_DIR_CQ2VF_PF_RO_VF_LOC	0
+#define SYS_DIR_CQ2VF_PF_RO_IS_PF_LOC	4
+#define SYS_DIR_CQ2VF_PF_RO_RO_LOC	5
+#define SYS_DIR_CQ2VF_PF_RO_RSVD0_LOC	6
+
+#define SYS_DIR_PP_V(x) \
+	(0x10000fd0 + (x) * 0x1000)
+#define SYS_DIR_PP_V_RST 0x0
+
+#define SYS_DIR_PP_V_PP_V	0x00000001
+#define SYS_DIR_PP_V_RSVD0	0xFFFFFFFE
+#define SYS_DIR_PP_V_PP_V_LOC	0
+#define SYS_DIR_PP_V_RSVD0_LOC	1
+
+#define SYS_DIR_PP2VDEV(x) \
+	(0x10000fcc + (x) * 0x1000)
+#define SYS_DIR_PP2VDEV_RST 0x0
+
+#define SYS_DIR_PP2VDEV_VDEV	0x0000000F
+#define SYS_DIR_PP2VDEV_RSVD0	0xFFFFFFF0
+#define SYS_DIR_PP2VDEV_VDEV_LOC	0
+#define SYS_DIR_PP2VDEV_RSVD0_LOC	4
+
+#define SYS_DIR_PP2VAS(x) \
+	(0x10000fc8 + (x) * 0x1000)
+#define SYS_DIR_PP2VAS_RST 0x0
+
+#define SYS_DIR_PP2VAS_VAS	0x0000001F
+#define SYS_DIR_PP2VAS_RSVD0	0xFFFFFFE0
+#define SYS_DIR_PP2VAS_VAS_LOC		0
+#define SYS_DIR_PP2VAS_RSVD0_LOC	5
+
+#define SYS_DIR_CQ_ADDR_U(x) \
+	(0x10000fc4 + (x) * 0x1000)
+#define SYS_DIR_CQ_ADDR_U_RST 0x0
+
+#define SYS_DIR_CQ_ADDR_U_ADDR_U	0xFFFFFFFF
+#define SYS_DIR_CQ_ADDR_U_ADDR_U_LOC	0
+
+#define SYS_DIR_CQ_ADDR_L(x) \
+	(0x10000fc0 + (x) * 0x1000)
+#define SYS_DIR_CQ_ADDR_L_RST 0x0
+
+#define SYS_DIR_CQ_ADDR_L_RSVD0		0x0000003F
+#define SYS_DIR_CQ_ADDR_L_ADDR_L	0xFFFFFFC0
+#define SYS_DIR_CQ_ADDR_L_RSVD0_LOC	0
+#define SYS_DIR_CQ_ADDR_L_ADDR_L_LOC	6
+
+#define SYS_PM_SMON_COMP_MASK1 0x10003024
+#define SYS_PM_SMON_COMP_MASK1_RST 0xffffffff
+
+#define SYS_PM_SMON_COMP_MASK1_COMP_MASK1	0xFFFFFFFF
+#define SYS_PM_SMON_COMP_MASK1_COMP_MASK1_LOC	0
+
+#define SYS_PM_SMON_COMP_MASK0 0x10003020
+#define SYS_PM_SMON_COMP_MASK0_RST 0xffffffff
+
+#define SYS_PM_SMON_COMP_MASK0_COMP_MASK0	0xFFFFFFFF
+#define SYS_PM_SMON_COMP_MASK0_COMP_MASK0_LOC	0
+
+#define SYS_PM_SMON_MAX_TMR 0x1000301c
+#define SYS_PM_SMON_MAX_TMR_RST 0x0
+
+#define SYS_PM_SMON_MAX_TMR_MAXVALUE	0xFFFFFFFF
+#define SYS_PM_SMON_MAX_TMR_MAXVALUE_LOC	0
+
+#define SYS_PM_SMON_TMR 0x10003018
+#define SYS_PM_SMON_TMR_RST 0x0
+
+#define SYS_PM_SMON_TMR_TIMER_VAL	0xFFFFFFFF
+#define SYS_PM_SMON_TMR_TIMER_VAL_LOC	0
+
+#define SYS_PM_SMON_ACTIVITYCNTR1 0x10003014
+#define SYS_PM_SMON_ACTIVITYCNTR1_RST 0x0
+
+#define SYS_PM_SMON_ACTIVITYCNTR1_COUNTER1	0xFFFFFFFF
+#define SYS_PM_SMON_ACTIVITYCNTR1_COUNTER1_LOC	0
+
+#define SYS_PM_SMON_ACTIVITYCNTR0 0x10003010
+#define SYS_PM_SMON_ACTIVITYCNTR0_RST 0x0
+
+#define SYS_PM_SMON_ACTIVITYCNTR0_COUNTER0	0xFFFFFFFF
+#define SYS_PM_SMON_ACTIVITYCNTR0_COUNTER0_LOC	0
+
+#define SYS_PM_SMON_COMPARE1 0x1000300c
+#define SYS_PM_SMON_COMPARE1_RST 0x0
+
+#define SYS_PM_SMON_COMPARE1_COMPARE1	0xFFFFFFFF
+#define SYS_PM_SMON_COMPARE1_COMPARE1_LOC	0
+
+#define SYS_PM_SMON_COMPARE0 0x10003008
+#define SYS_PM_SMON_COMPARE0_RST 0x0
+
+#define SYS_PM_SMON_COMPARE0_COMPARE0	0xFFFFFFFF
+#define SYS_PM_SMON_COMPARE0_COMPARE0_LOC	0
+
+#define SYS_PM_SMON_CFG1 0x10003004
+#define SYS_PM_SMON_CFG1_RST 0x0
+
+#define SYS_PM_SMON_CFG1_MODE0	0x000000FF
+#define SYS_PM_SMON_CFG1_MODE1	0x0000FF00
+#define SYS_PM_SMON_CFG1_RSVD	0xFFFF0000
+#define SYS_PM_SMON_CFG1_MODE0_LOC	0
+#define SYS_PM_SMON_CFG1_MODE1_LOC	8
+#define SYS_PM_SMON_CFG1_RSVD_LOC	16
+
+#define SYS_PM_SMON_CFG0 0x10003000
+#define SYS_PM_SMON_CFG0_RST 0x40000000
+
+#define SYS_PM_SMON_CFG0_SMON_ENABLE		0x00000001
+#define SYS_PM_SMON_CFG0_RSVD2			0x0000000E
+#define SYS_PM_SMON_CFG0_SMON0_FUNCTION		0x00000070
+#define SYS_PM_SMON_CFG0_SMON0_FUNCTION_COMPARE	0x00000080
+#define SYS_PM_SMON_CFG0_SMON1_FUNCTION		0x00000700
+#define SYS_PM_SMON_CFG0_SMON1_FUNCTION_COMPARE	0x00000800
+#define SYS_PM_SMON_CFG0_SMON_MODE		0x0000F000
+#define SYS_PM_SMON_CFG0_STOPCOUNTEROVFL	0x00010000
+#define SYS_PM_SMON_CFG0_INTCOUNTEROVFL		0x00020000
+#define SYS_PM_SMON_CFG0_STATCOUNTER0OVFL	0x00040000
+#define SYS_PM_SMON_CFG0_STATCOUNTER1OVFL	0x00080000
+#define SYS_PM_SMON_CFG0_STOPTIMEROVFL		0x00100000
+#define SYS_PM_SMON_CFG0_INTTIMEROVFL		0x00200000
+#define SYS_PM_SMON_CFG0_STATTIMEROVFL		0x00400000
+#define SYS_PM_SMON_CFG0_RSVD1			0x00800000
+#define SYS_PM_SMON_CFG0_TIMER_PRESCALE		0x1F000000
+#define SYS_PM_SMON_CFG0_RSVD0			0x20000000
+#define SYS_PM_SMON_CFG0_VERSION		0xC0000000
+#define SYS_PM_SMON_CFG0_SMON_ENABLE_LOC		0
+#define SYS_PM_SMON_CFG0_RSVD2_LOC			1
+#define SYS_PM_SMON_CFG0_SMON0_FUNCTION_LOC		4
+#define SYS_PM_SMON_CFG0_SMON0_FUNCTION_COMPARE_LOC	7
+#define SYS_PM_SMON_CFG0_SMON1_FUNCTION_LOC		8
+#define SYS_PM_SMON_CFG0_SMON1_FUNCTION_COMPARE_LOC	11
+#define SYS_PM_SMON_CFG0_SMON_MODE_LOC			12
+#define SYS_PM_SMON_CFG0_STOPCOUNTEROVFL_LOC		16
+#define SYS_PM_SMON_CFG0_INTCOUNTEROVFL_LOC		17
+#define SYS_PM_SMON_CFG0_STATCOUNTER0OVFL_LOC		18
+#define SYS_PM_SMON_CFG0_STATCOUNTER1OVFL_LOC		19
+#define SYS_PM_SMON_CFG0_STOPTIMEROVFL_LOC		20
+#define SYS_PM_SMON_CFG0_INTTIMEROVFL_LOC		21
+#define SYS_PM_SMON_CFG0_STATTIMEROVFL_LOC		22
+#define SYS_PM_SMON_CFG0_RSVD1_LOC			23
+#define SYS_PM_SMON_CFG0_TIMER_PRESCALE_LOC		24
+#define SYS_PM_SMON_CFG0_RSVD0_LOC			29
+#define SYS_PM_SMON_CFG0_VERSION_LOC			30
+
+#define SYS_SMON_COMP_MASK1(x) \
+	(0x18002024 + (x) * 0x40)
+#define SYS_SMON_COMP_MASK1_RST 0xffffffff
+
+#define SYS_SMON_COMP_MASK1_COMP_MASK1	0xFFFFFFFF
+#define SYS_SMON_COMP_MASK1_COMP_MASK1_LOC	0
+
+#define SYS_SMON_COMP_MASK0(x) \
+	(0x18002020 + (x) * 0x40)
+#define SYS_SMON_COMP_MASK0_RST 0xffffffff
+
+#define SYS_SMON_COMP_MASK0_COMP_MASK0	0xFFFFFFFF
+#define SYS_SMON_COMP_MASK0_COMP_MASK0_LOC	0
+
+#define SYS_SMON_MAX_TMR(x) \
+	(0x1800201c + (x) * 0x40)
+#define SYS_SMON_MAX_TMR_RST 0x0
+
+#define SYS_SMON_MAX_TMR_MAXVALUE	0xFFFFFFFF
+#define SYS_SMON_MAX_TMR_MAXVALUE_LOC	0
+
+#define SYS_SMON_TMR(x) \
+	(0x18002018 + (x) * 0x40)
+#define SYS_SMON_TMR_RST 0x0
+
+#define SYS_SMON_TMR_TIMER_VAL	0xFFFFFFFF
+#define SYS_SMON_TMR_TIMER_VAL_LOC	0
+
+#define SYS_SMON_ACTIVITYCNTR1(x) \
+	(0x18002014 + (x) * 0x40)
+#define SYS_SMON_ACTIVITYCNTR1_RST 0x0
+
+#define SYS_SMON_ACTIVITYCNTR1_COUNTER1	0xFFFFFFFF
+#define SYS_SMON_ACTIVITYCNTR1_COUNTER1_LOC	0
+
+#define SYS_SMON_ACTIVITYCNTR0(x) \
+	(0x18002010 + (x) * 0x40)
+#define SYS_SMON_ACTIVITYCNTR0_RST 0x0
+
+#define SYS_SMON_ACTIVITYCNTR0_COUNTER0	0xFFFFFFFF
+#define SYS_SMON_ACTIVITYCNTR0_COUNTER0_LOC	0
+
+#define SYS_SMON_COMPARE1(x) \
+	(0x1800200c + (x) * 0x40)
+#define SYS_SMON_COMPARE1_RST 0x0
+
+#define SYS_SMON_COMPARE1_COMPARE1	0xFFFFFFFF
+#define SYS_SMON_COMPARE1_COMPARE1_LOC	0
+
+#define SYS_SMON_COMPARE0(x) \
+	(0x18002008 + (x) * 0x40)
+#define SYS_SMON_COMPARE0_RST 0x0
+
+#define SYS_SMON_COMPARE0_COMPARE0	0xFFFFFFFF
+#define SYS_SMON_COMPARE0_COMPARE0_LOC	0
+
+#define SYS_SMON_CFG1(x) \
+	(0x18002004 + (x) * 0x40)
+#define SYS_SMON_CFG1_RST 0x0
+
+#define SYS_SMON_CFG1_MODE0	0x000000FF
+#define SYS_SMON_CFG1_MODE1	0x0000FF00
+#define SYS_SMON_CFG1_RSVD	0xFFFF0000
+#define SYS_SMON_CFG1_MODE0_LOC	0
+#define SYS_SMON_CFG1_MODE1_LOC	8
+#define SYS_SMON_CFG1_RSVD_LOC	16
+
+#define SYS_SMON_CFG0(x) \
+	(0x18002000 + (x) * 0x40)
+#define SYS_SMON_CFG0_RST 0x40000000
+
+#define SYS_SMON_CFG0_SMON_ENABLE		0x00000001
+#define SYS_SMON_CFG0_RSVD2			0x0000000E
+#define SYS_SMON_CFG0_SMON0_FUNCTION		0x00000070
+#define SYS_SMON_CFG0_SMON0_FUNCTION_COMPARE	0x00000080
+#define SYS_SMON_CFG0_SMON1_FUNCTION		0x00000700
+#define SYS_SMON_CFG0_SMON1_FUNCTION_COMPARE	0x00000800
+#define SYS_SMON_CFG0_SMON_MODE			0x0000F000
+#define SYS_SMON_CFG0_STOPCOUNTEROVFL		0x00010000
+#define SYS_SMON_CFG0_INTCOUNTEROVFL		0x00020000
+#define SYS_SMON_CFG0_STATCOUNTER0OVFL		0x00040000
+#define SYS_SMON_CFG0_STATCOUNTER1OVFL		0x00080000
+#define SYS_SMON_CFG0_STOPTIMEROVFL		0x00100000
+#define SYS_SMON_CFG0_INTTIMEROVFL		0x00200000
+#define SYS_SMON_CFG0_STATTIMEROVFL		0x00400000
+#define SYS_SMON_CFG0_RSVD1			0x00800000
+#define SYS_SMON_CFG0_TIMER_PRESCALE		0x1F000000
+#define SYS_SMON_CFG0_RSVD0			0x20000000
+#define SYS_SMON_CFG0_VERSION			0xC0000000
+#define SYS_SMON_CFG0_SMON_ENABLE_LOC			0
+#define SYS_SMON_CFG0_RSVD2_LOC				1
+#define SYS_SMON_CFG0_SMON0_FUNCTION_LOC		4
+#define SYS_SMON_CFG0_SMON0_FUNCTION_COMPARE_LOC	7
+#define SYS_SMON_CFG0_SMON1_FUNCTION_LOC		8
+#define SYS_SMON_CFG0_SMON1_FUNCTION_COMPARE_LOC	11
+#define SYS_SMON_CFG0_SMON_MODE_LOC			12
+#define SYS_SMON_CFG0_STOPCOUNTEROVFL_LOC		16
+#define SYS_SMON_CFG0_INTCOUNTEROVFL_LOC		17
+#define SYS_SMON_CFG0_STATCOUNTER0OVFL_LOC		18
+#define SYS_SMON_CFG0_STATCOUNTER1OVFL_LOC		19
+#define SYS_SMON_CFG0_STOPTIMEROVFL_LOC			20
+#define SYS_SMON_CFG0_INTTIMEROVFL_LOC			21
+#define SYS_SMON_CFG0_STATTIMEROVFL_LOC			22
+#define SYS_SMON_CFG0_RSVD1_LOC				23
+#define SYS_SMON_CFG0_TIMER_PRESCALE_LOC		24
+#define SYS_SMON_CFG0_RSVD0_LOC				29
+#define SYS_SMON_CFG0_VERSION_LOC			30
+
+#define SYS_INGRESS_ALARM_ENBL 0x10000300
+#define SYS_INGRESS_ALARM_ENBL_RST 0x0
+
+#define SYS_INGRESS_ALARM_ENBL_ILLEGAL_HCW		0x00000001
+#define SYS_INGRESS_ALARM_ENBL_ILLEGAL_PP		0x00000002
+#define SYS_INGRESS_ALARM_ENBL_ILLEGAL_PASID		0x00000004
+#define SYS_INGRESS_ALARM_ENBL_ILLEGAL_QID		0x00000008
+#define SYS_INGRESS_ALARM_ENBL_DISABLED_QID		0x00000010
+#define SYS_INGRESS_ALARM_ENBL_ILLEGAL_LDB_QID_CFG	0x00000020
+#define SYS_INGRESS_ALARM_ENBL_RSVD0			0xFFFFFFC0
+#define SYS_INGRESS_ALARM_ENBL_ILLEGAL_HCW_LOC		0
+#define SYS_INGRESS_ALARM_ENBL_ILLEGAL_PP_LOC		1
+#define SYS_INGRESS_ALARM_ENBL_ILLEGAL_PASID_LOC	2
+#define SYS_INGRESS_ALARM_ENBL_ILLEGAL_QID_LOC		3
+#define SYS_INGRESS_ALARM_ENBL_DISABLED_QID_LOC		4
+#define SYS_INGRESS_ALARM_ENBL_ILLEGAL_LDB_QID_CFG_LOC	5
+#define SYS_INGRESS_ALARM_ENBL_RSVD0_LOC		6
+
+#define SYS_MSIX_ACK 0x10000400
+#define SYS_MSIX_ACK_RST 0x0
+
+#define SYS_MSIX_ACK_MSIX_0_ACK	0x00000001
+#define SYS_MSIX_ACK_MSIX_1_ACK	0x00000002
+#define SYS_MSIX_ACK_RSVD0	0xFFFFFFFC
+#define SYS_MSIX_ACK_MSIX_0_ACK_LOC	0
+#define SYS_MSIX_ACK_MSIX_1_ACK_LOC	1
+#define SYS_MSIX_ACK_RSVD0_LOC		2
+
+#define SYS_MSIX_PASSTHRU 0x10000404
+#define SYS_MSIX_PASSTHRU_RST 0x0
+
+#define SYS_MSIX_PASSTHRU_MSIX_0_PASSTHRU	0x00000001
+#define SYS_MSIX_PASSTHRU_MSIX_1_PASSTHRU	0x00000002
+#define SYS_MSIX_PASSTHRU_RSVD0			0xFFFFFFFC
+#define SYS_MSIX_PASSTHRU_MSIX_0_PASSTHRU_LOC	0
+#define SYS_MSIX_PASSTHRU_MSIX_1_PASSTHRU_LOC	1
+#define SYS_MSIX_PASSTHRU_RSVD0_LOC		2
+
+#define SYS_MSIX_MODE 0x10000408
+#define SYS_MSIX_MODE_RST 0x0
+/* MSI-X Modes */
+#define DLB_MSIX_MODE_PACKED     0
+#define DLB_MSIX_MODE_COMPRESSED 1
+
+#define SYS_MSIX_MODE_MODE	0x00000001
+#define SYS_MSIX_MODE_POLL_MODE	0x00000002
+#define SYS_MSIX_MODE_POLL_MASK	0x00000004
+#define SYS_MSIX_MODE_POLL_LOCK	0x00000008
+#define SYS_MSIX_MODE_RSVD0	0xFFFFFFF0
+#define SYS_MSIX_MODE_MODE_LOC		0
+#define SYS_MSIX_MODE_POLL_MODE_LOC	1
+#define SYS_MSIX_MODE_POLL_MASK_LOC	2
+#define SYS_MSIX_MODE_POLL_LOCK_LOC	3
+#define SYS_MSIX_MODE_RSVD0_LOC		4
+
+#define SYS_DIR_CQ_31_0_OCC_INT_STS 0x10000440
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_RST 0x0
+
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_0_OCC_INT	0x00000001
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_1_OCC_INT	0x00000002
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_2_OCC_INT	0x00000004
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_3_OCC_INT	0x00000008
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_4_OCC_INT	0x00000010
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_5_OCC_INT	0x00000020
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_6_OCC_INT	0x00000040
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_7_OCC_INT	0x00000080
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_8_OCC_INT	0x00000100
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_9_OCC_INT	0x00000200
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_10_OCC_INT	0x00000400
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_11_OCC_INT	0x00000800
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_12_OCC_INT	0x00001000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_13_OCC_INT	0x00002000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_14_OCC_INT	0x00004000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_15_OCC_INT	0x00008000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_16_OCC_INT	0x00010000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_17_OCC_INT	0x00020000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_18_OCC_INT	0x00040000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_19_OCC_INT	0x00080000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_20_OCC_INT	0x00100000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_21_OCC_INT	0x00200000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_22_OCC_INT	0x00400000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_23_OCC_INT	0x00800000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_24_OCC_INT	0x01000000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_25_OCC_INT	0x02000000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_26_OCC_INT	0x04000000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_27_OCC_INT	0x08000000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_28_OCC_INT	0x10000000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_29_OCC_INT	0x20000000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_30_OCC_INT	0x40000000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_31_OCC_INT	0x80000000
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_0_OCC_INT_LOC	0
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_1_OCC_INT_LOC	1
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_2_OCC_INT_LOC	2
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_3_OCC_INT_LOC	3
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_4_OCC_INT_LOC	4
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_5_OCC_INT_LOC	5
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_6_OCC_INT_LOC	6
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_7_OCC_INT_LOC	7
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_8_OCC_INT_LOC	8
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_9_OCC_INT_LOC	9
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_10_OCC_INT_LOC	10
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_11_OCC_INT_LOC	11
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_12_OCC_INT_LOC	12
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_13_OCC_INT_LOC	13
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_14_OCC_INT_LOC	14
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_15_OCC_INT_LOC	15
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_16_OCC_INT_LOC	16
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_17_OCC_INT_LOC	17
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_18_OCC_INT_LOC	18
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_19_OCC_INT_LOC	19
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_20_OCC_INT_LOC	20
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_21_OCC_INT_LOC	21
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_22_OCC_INT_LOC	22
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_23_OCC_INT_LOC	23
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_24_OCC_INT_LOC	24
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_25_OCC_INT_LOC	25
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_26_OCC_INT_LOC	26
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_27_OCC_INT_LOC	27
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_28_OCC_INT_LOC	28
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_29_OCC_INT_LOC	29
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_30_OCC_INT_LOC	30
+#define SYS_DIR_CQ_31_0_OCC_INT_STS_CQ_31_OCC_INT_LOC	31
+
+#define SYS_DIR_CQ_63_32_OCC_INT_STS 0x10000444
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_RST 0x0
+
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_32_OCC_INT	0x00000001
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_33_OCC_INT	0x00000002
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_34_OCC_INT	0x00000004
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_35_OCC_INT	0x00000008
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_36_OCC_INT	0x00000010
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_37_OCC_INT	0x00000020
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_38_OCC_INT	0x00000040
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_39_OCC_INT	0x00000080
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_40_OCC_INT	0x00000100
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_41_OCC_INT	0x00000200
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_42_OCC_INT	0x00000400
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_43_OCC_INT	0x00000800
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_44_OCC_INT	0x00001000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_45_OCC_INT	0x00002000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_46_OCC_INT	0x00004000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_47_OCC_INT	0x00008000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_48_OCC_INT	0x00010000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_49_OCC_INT	0x00020000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_50_OCC_INT	0x00040000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_51_OCC_INT	0x00080000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_52_OCC_INT	0x00100000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_53_OCC_INT	0x00200000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_54_OCC_INT	0x00400000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_55_OCC_INT	0x00800000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_56_OCC_INT	0x01000000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_57_OCC_INT	0x02000000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_58_OCC_INT	0x04000000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_59_OCC_INT	0x08000000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_60_OCC_INT	0x10000000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_61_OCC_INT	0x20000000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_62_OCC_INT	0x40000000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_63_OCC_INT	0x80000000
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_32_OCC_INT_LOC	0
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_33_OCC_INT_LOC	1
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_34_OCC_INT_LOC	2
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_35_OCC_INT_LOC	3
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_36_OCC_INT_LOC	4
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_37_OCC_INT_LOC	5
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_38_OCC_INT_LOC	6
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_39_OCC_INT_LOC	7
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_40_OCC_INT_LOC	8
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_41_OCC_INT_LOC	9
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_42_OCC_INT_LOC	10
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_43_OCC_INT_LOC	11
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_44_OCC_INT_LOC	12
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_45_OCC_INT_LOC	13
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_46_OCC_INT_LOC	14
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_47_OCC_INT_LOC	15
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_48_OCC_INT_LOC	16
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_49_OCC_INT_LOC	17
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_50_OCC_INT_LOC	18
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_51_OCC_INT_LOC	19
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_52_OCC_INT_LOC	20
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_53_OCC_INT_LOC	21
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_54_OCC_INT_LOC	22
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_55_OCC_INT_LOC	23
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_56_OCC_INT_LOC	24
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_57_OCC_INT_LOC	25
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_58_OCC_INT_LOC	26
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_59_OCC_INT_LOC	27
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_60_OCC_INT_LOC	28
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_61_OCC_INT_LOC	29
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_62_OCC_INT_LOC	30
+#define SYS_DIR_CQ_63_32_OCC_INT_STS_CQ_63_OCC_INT_LOC	31
+
+#define SYS_LDB_CQ_31_0_OCC_INT_STS 0x10000460
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_RST 0x0
+
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_0_OCC_INT	0x00000001
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_1_OCC_INT	0x00000002
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_2_OCC_INT	0x00000004
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_3_OCC_INT	0x00000008
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_4_OCC_INT	0x00000010
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_5_OCC_INT	0x00000020
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_6_OCC_INT	0x00000040
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_7_OCC_INT	0x00000080
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_8_OCC_INT	0x00000100
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_9_OCC_INT	0x00000200
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_10_OCC_INT	0x00000400
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_11_OCC_INT	0x00000800
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_12_OCC_INT	0x00001000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_13_OCC_INT	0x00002000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_14_OCC_INT	0x00004000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_15_OCC_INT	0x00008000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_16_OCC_INT	0x00010000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_17_OCC_INT	0x00020000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_18_OCC_INT	0x00040000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_19_OCC_INT	0x00080000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_20_OCC_INT	0x00100000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_21_OCC_INT	0x00200000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_22_OCC_INT	0x00400000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_23_OCC_INT	0x00800000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_24_OCC_INT	0x01000000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_25_OCC_INT	0x02000000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_26_OCC_INT	0x04000000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_27_OCC_INT	0x08000000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_28_OCC_INT	0x10000000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_29_OCC_INT	0x20000000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_30_OCC_INT	0x40000000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_31_OCC_INT	0x80000000
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_0_OCC_INT_LOC	0
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_1_OCC_INT_LOC	1
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_2_OCC_INT_LOC	2
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_3_OCC_INT_LOC	3
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_4_OCC_INT_LOC	4
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_5_OCC_INT_LOC	5
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_6_OCC_INT_LOC	6
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_7_OCC_INT_LOC	7
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_8_OCC_INT_LOC	8
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_9_OCC_INT_LOC	9
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_10_OCC_INT_LOC	10
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_11_OCC_INT_LOC	11
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_12_OCC_INT_LOC	12
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_13_OCC_INT_LOC	13
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_14_OCC_INT_LOC	14
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_15_OCC_INT_LOC	15
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_16_OCC_INT_LOC	16
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_17_OCC_INT_LOC	17
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_18_OCC_INT_LOC	18
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_19_OCC_INT_LOC	19
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_20_OCC_INT_LOC	20
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_21_OCC_INT_LOC	21
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_22_OCC_INT_LOC	22
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_23_OCC_INT_LOC	23
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_24_OCC_INT_LOC	24
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_25_OCC_INT_LOC	25
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_26_OCC_INT_LOC	26
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_27_OCC_INT_LOC	27
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_28_OCC_INT_LOC	28
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_29_OCC_INT_LOC	29
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_30_OCC_INT_LOC	30
+#define SYS_LDB_CQ_31_0_OCC_INT_STS_CQ_31_OCC_INT_LOC	31
+
+#define SYS_LDB_CQ_63_32_OCC_INT_STS 0x10000464
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_RST 0x0
+
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_32_OCC_INT	0x00000001
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_33_OCC_INT	0x00000002
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_34_OCC_INT	0x00000004
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_35_OCC_INT	0x00000008
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_36_OCC_INT	0x00000010
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_37_OCC_INT	0x00000020
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_38_OCC_INT	0x00000040
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_39_OCC_INT	0x00000080
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_40_OCC_INT	0x00000100
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_41_OCC_INT	0x00000200
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_42_OCC_INT	0x00000400
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_43_OCC_INT	0x00000800
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_44_OCC_INT	0x00001000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_45_OCC_INT	0x00002000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_46_OCC_INT	0x00004000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_47_OCC_INT	0x00008000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_48_OCC_INT	0x00010000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_49_OCC_INT	0x00020000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_50_OCC_INT	0x00040000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_51_OCC_INT	0x00080000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_52_OCC_INT	0x00100000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_53_OCC_INT	0x00200000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_54_OCC_INT	0x00400000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_55_OCC_INT	0x00800000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_56_OCC_INT	0x01000000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_57_OCC_INT	0x02000000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_58_OCC_INT	0x04000000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_59_OCC_INT	0x08000000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_60_OCC_INT	0x10000000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_61_OCC_INT	0x20000000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_62_OCC_INT	0x40000000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_63_OCC_INT	0x80000000
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_32_OCC_INT_LOC	0
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_33_OCC_INT_LOC	1
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_34_OCC_INT_LOC	2
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_35_OCC_INT_LOC	3
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_36_OCC_INT_LOC	4
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_37_OCC_INT_LOC	5
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_38_OCC_INT_LOC	6
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_39_OCC_INT_LOC	7
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_40_OCC_INT_LOC	8
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_41_OCC_INT_LOC	9
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_42_OCC_INT_LOC	10
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_43_OCC_INT_LOC	11
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_44_OCC_INT_LOC	12
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_45_OCC_INT_LOC	13
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_46_OCC_INT_LOC	14
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_47_OCC_INT_LOC	15
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_48_OCC_INT_LOC	16
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_49_OCC_INT_LOC	17
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_50_OCC_INT_LOC	18
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_51_OCC_INT_LOC	19
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_52_OCC_INT_LOC	20
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_53_OCC_INT_LOC	21
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_54_OCC_INT_LOC	22
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_55_OCC_INT_LOC	23
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_56_OCC_INT_LOC	24
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_57_OCC_INT_LOC	25
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_58_OCC_INT_LOC	26
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_59_OCC_INT_LOC	27
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_60_OCC_INT_LOC	28
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_61_OCC_INT_LOC	29
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_62_OCC_INT_LOC	30
+#define SYS_LDB_CQ_63_32_OCC_INT_STS_CQ_63_OCC_INT_LOC	31
+
+#define SYS_DIR_CQ_OPT_CLR 0x100004c0
+#define SYS_DIR_CQ_OPT_CLR_RST 0x0
+
+#define SYS_DIR_CQ_OPT_CLR_CQ		0x0000003F
+#define SYS_DIR_CQ_OPT_CLR_RSVD0	0xFFFFFFC0
+#define SYS_DIR_CQ_OPT_CLR_CQ_LOC	0
+#define SYS_DIR_CQ_OPT_CLR_RSVD0_LOC	6
+
+#define SYS_ALARM_HW_SYND 0x1000050c
+#define SYS_ALARM_HW_SYND_RST 0x0
+
+#define SYS_ALARM_HW_SYND_SYNDROME	0x000000FF
+#define SYS_ALARM_HW_SYND_RTYPE		0x00000300
+#define SYS_ALARM_HW_SYND_ALARM		0x00000400
+#define SYS_ALARM_HW_SYND_CWD		0x00000800
+#define SYS_ALARM_HW_SYND_VF_PF_MB	0x00001000
+#define SYS_ALARM_HW_SYND_RSVD0		0x00002000
+#define SYS_ALARM_HW_SYND_CLS		0x0000C000
+#define SYS_ALARM_HW_SYND_AID		0x003F0000
+#define SYS_ALARM_HW_SYND_UNIT		0x03C00000
+#define SYS_ALARM_HW_SYND_SOURCE	0x3C000000
+#define SYS_ALARM_HW_SYND_MORE		0x40000000
+#define SYS_ALARM_HW_SYND_VALID		0x80000000
+#define SYS_ALARM_HW_SYND_SYNDROME_LOC	0
+#define SYS_ALARM_HW_SYND_RTYPE_LOC	8
+#define SYS_ALARM_HW_SYND_ALARM_LOC	10
+#define SYS_ALARM_HW_SYND_CWD_LOC	11
+#define SYS_ALARM_HW_SYND_VF_PF_MB_LOC	12
+#define SYS_ALARM_HW_SYND_RSVD0_LOC	13
+#define SYS_ALARM_HW_SYND_CLS_LOC	14
+#define SYS_ALARM_HW_SYND_AID_LOC	16
+#define SYS_ALARM_HW_SYND_UNIT_LOC	22
+#define SYS_ALARM_HW_SYND_SOURCE_LOC	26
+#define SYS_ALARM_HW_SYND_MORE_LOC	30
+#define SYS_ALARM_HW_SYND_VALID_LOC	31
+
+#define AQED_QID_FID_LIM(x) \
+	(0x20000000 + (x) * 0x1000)
+#define AQED_QID_FID_LIM_RST 0x7ff
+
+#define AQED_QID_FID_LIM_QID_FID_LIMIT	0x00001FFF
+#define AQED_QID_FID_LIM_RSVD0		0xFFFFE000
+#define AQED_QID_FID_LIM_QID_FID_LIMIT_LOC	0
+#define AQED_QID_FID_LIM_RSVD0_LOC		13
+
+#define AQED_QID_HID_WIDTH(x) \
+	(0x20080000 + (x) * 0x1000)
+#define AQED_QID_HID_WIDTH_RST 0x0
+
+#define AQED_QID_HID_WIDTH_COMPRESS_CODE	0x00000007
+#define AQED_QID_HID_WIDTH_RSVD0		0xFFFFFFF8
+#define AQED_QID_HID_WIDTH_COMPRESS_CODE_LOC	0
+#define AQED_QID_HID_WIDTH_RSVD0_LOC		3
+
+#define AQED_CFG_ARB_WEIGHTS_TQPRI_ATM_0 0x24000004
+#define AQED_CFG_ARB_WEIGHTS_TQPRI_ATM_0_RST 0xfefcfaf8
+
+#define AQED_CFG_ARB_WEIGHTS_TQPRI_ATM_0_PRI0	0x000000FF
+#define AQED_CFG_ARB_WEIGHTS_TQPRI_ATM_0_PRI1	0x0000FF00
+#define AQED_CFG_ARB_WEIGHTS_TQPRI_ATM_0_PRI2	0x00FF0000
+#define AQED_CFG_ARB_WEIGHTS_TQPRI_ATM_0_PRI3	0xFF000000
+#define AQED_CFG_ARB_WEIGHTS_TQPRI_ATM_0_PRI0_LOC	0
+#define AQED_CFG_ARB_WEIGHTS_TQPRI_ATM_0_PRI1_LOC	8
+#define AQED_CFG_ARB_WEIGHTS_TQPRI_ATM_0_PRI2_LOC	16
+#define AQED_CFG_ARB_WEIGHTS_TQPRI_ATM_0_PRI3_LOC	24
+
+#define AQED_SMON_ACTIVITYCNTR0 0x2c00004c
+#define AQED_SMON_ACTIVITYCNTR0_RST 0x0
+
+#define AQED_SMON_ACTIVITYCNTR0_COUNTER0	0xFFFFFFFF
+#define AQED_SMON_ACTIVITYCNTR0_COUNTER0_LOC	0
+
+#define AQED_SMON_ACTIVITYCNTR1 0x2c000050
+#define AQED_SMON_ACTIVITYCNTR1_RST 0x0
+
+#define AQED_SMON_ACTIVITYCNTR1_COUNTER1	0xFFFFFFFF
+#define AQED_SMON_ACTIVITYCNTR1_COUNTER1_LOC	0
+
+#define AQED_SMON_COMPARE0 0x2c000054
+#define AQED_SMON_COMPARE0_RST 0x0
+
+#define AQED_SMON_COMPARE0_COMPARE0	0xFFFFFFFF
+#define AQED_SMON_COMPARE0_COMPARE0_LOC	0
+
+#define AQED_SMON_COMPARE1 0x2c000058
+#define AQED_SMON_COMPARE1_RST 0x0
+
+#define AQED_SMON_COMPARE1_COMPARE1	0xFFFFFFFF
+#define AQED_SMON_COMPARE1_COMPARE1_LOC	0
+
+#define AQED_SMON_CFG0 0x2c00005c
+#define AQED_SMON_CFG0_RST 0x40000000
+
+#define AQED_SMON_CFG0_SMON_ENABLE		0x00000001
+#define AQED_SMON_CFG0_SMON_0TRIGGER_ENABLE	0x00000002
+#define AQED_SMON_CFG0_RSVZ0			0x0000000C
+#define AQED_SMON_CFG0_SMON0_FUNCTION		0x00000070
+#define AQED_SMON_CFG0_SMON0_FUNCTION_COMPARE	0x00000080
+#define AQED_SMON_CFG0_SMON1_FUNCTION		0x00000700
+#define AQED_SMON_CFG0_SMON1_FUNCTION_COMPARE	0x00000800
+#define AQED_SMON_CFG0_SMON_MODE		0x0000F000
+#define AQED_SMON_CFG0_STOPCOUNTEROVFL		0x00010000
+#define AQED_SMON_CFG0_INTCOUNTEROVFL		0x00020000
+#define AQED_SMON_CFG0_STATCOUNTER0OVFL		0x00040000
+#define AQED_SMON_CFG0_STATCOUNTER1OVFL		0x00080000
+#define AQED_SMON_CFG0_STOPTIMEROVFL		0x00100000
+#define AQED_SMON_CFG0_INTTIMEROVFL		0x00200000
+#define AQED_SMON_CFG0_STATTIMEROVFL		0x00400000
+#define AQED_SMON_CFG0_RSVZ1			0x00800000
+#define AQED_SMON_CFG0_TIMER_PRESCALE		0x1F000000
+#define AQED_SMON_CFG0_RSVZ2			0x20000000
+#define AQED_SMON_CFG0_VERSION			0xC0000000
+#define AQED_SMON_CFG0_SMON_ENABLE_LOC			0
+#define AQED_SMON_CFG0_SMON_0TRIGGER_ENABLE_LOC		1
+#define AQED_SMON_CFG0_RSVZ0_LOC			2
+#define AQED_SMON_CFG0_SMON0_FUNCTION_LOC		4
+#define AQED_SMON_CFG0_SMON0_FUNCTION_COMPARE_LOC	7
+#define AQED_SMON_CFG0_SMON1_FUNCTION_LOC		8
+#define AQED_SMON_CFG0_SMON1_FUNCTION_COMPARE_LOC	11
+#define AQED_SMON_CFG0_SMON_MODE_LOC			12
+#define AQED_SMON_CFG0_STOPCOUNTEROVFL_LOC		16
+#define AQED_SMON_CFG0_INTCOUNTEROVFL_LOC		17
+#define AQED_SMON_CFG0_STATCOUNTER0OVFL_LOC		18
+#define AQED_SMON_CFG0_STATCOUNTER1OVFL_LOC		19
+#define AQED_SMON_CFG0_STOPTIMEROVFL_LOC		20
+#define AQED_SMON_CFG0_INTTIMEROVFL_LOC			21
+#define AQED_SMON_CFG0_STATTIMEROVFL_LOC		22
+#define AQED_SMON_CFG0_RSVZ1_LOC			23
+#define AQED_SMON_CFG0_TIMER_PRESCALE_LOC		24
+#define AQED_SMON_CFG0_RSVZ2_LOC			29
+#define AQED_SMON_CFG0_VERSION_LOC			30
+
+#define AQED_SMON_CFG1 0x2c000060
+#define AQED_SMON_CFG1_RST 0x0
+
+#define AQED_SMON_CFG1_MODE0	0x000000FF
+#define AQED_SMON_CFG1_MODE1	0x0000FF00
+#define AQED_SMON_CFG1_RSVZ0	0xFFFF0000
+#define AQED_SMON_CFG1_MODE0_LOC	0
+#define AQED_SMON_CFG1_MODE1_LOC	8
+#define AQED_SMON_CFG1_RSVZ0_LOC	16
+
+#define AQED_SMON_MAX_TMR 0x2c000064
+#define AQED_SMON_MAX_TMR_RST 0x0
+
+#define AQED_SMON_MAX_TMR_MAXVALUE	0xFFFFFFFF
+#define AQED_SMON_MAX_TMR_MAXVALUE_LOC	0
+
+#define AQED_SMON_TMR 0x2c000068
+#define AQED_SMON_TMR_RST 0x0
+
+#define AQED_SMON_TMR_TIMER	0xFFFFFFFF
+#define AQED_SMON_TMR_TIMER_LOC	0
+
+#define ATM_QID2CQIDIX_00(x) \
+	(0x30080000 + (x) * 0x1000)
+#define ATM_QID2CQIDIX_00_RST 0x0
+#define ATM_QID2CQIDIX(x, y) \
+	(ATM_QID2CQIDIX_00(x) + 0x80000 * (y))
+#define ATM_QID2CQIDIX_NUM 16
+
+#define ATM_QID2CQIDIX_00_CQ_P0	0x000000FF
+#define ATM_QID2CQIDIX_00_CQ_P1	0x0000FF00
+#define ATM_QID2CQIDIX_00_CQ_P2	0x00FF0000
+#define ATM_QID2CQIDIX_00_CQ_P3	0xFF000000
+#define ATM_QID2CQIDIX_00_CQ_P0_LOC	0
+#define ATM_QID2CQIDIX_00_CQ_P1_LOC	8
+#define ATM_QID2CQIDIX_00_CQ_P2_LOC	16
+#define ATM_QID2CQIDIX_00_CQ_P3_LOC	24
+
+#define ATM_CFG_ARB_WEIGHTS_RDY_BIN 0x34000004
+#define ATM_CFG_ARB_WEIGHTS_RDY_BIN_RST 0xfffefdfc
+
+#define ATM_CFG_ARB_WEIGHTS_RDY_BIN_BIN0	0x000000FF
+#define ATM_CFG_ARB_WEIGHTS_RDY_BIN_BIN1	0x0000FF00
+#define ATM_CFG_ARB_WEIGHTS_RDY_BIN_BIN2	0x00FF0000
+#define ATM_CFG_ARB_WEIGHTS_RDY_BIN_BIN3	0xFF000000
+#define ATM_CFG_ARB_WEIGHTS_RDY_BIN_BIN0_LOC	0
+#define ATM_CFG_ARB_WEIGHTS_RDY_BIN_BIN1_LOC	8
+#define ATM_CFG_ARB_WEIGHTS_RDY_BIN_BIN2_LOC	16
+#define ATM_CFG_ARB_WEIGHTS_RDY_BIN_BIN3_LOC	24
+
+#define ATM_CFG_ARB_WEIGHTS_SCHED_BIN 0x34000008
+#define ATM_CFG_ARB_WEIGHTS_SCHED_BIN_RST 0xfffefdfc
+
+#define ATM_CFG_ARB_WEIGHTS_SCHED_BIN_BIN0	0x000000FF
+#define ATM_CFG_ARB_WEIGHTS_SCHED_BIN_BIN1	0x0000FF00
+#define ATM_CFG_ARB_WEIGHTS_SCHED_BIN_BIN2	0x00FF0000
+#define ATM_CFG_ARB_WEIGHTS_SCHED_BIN_BIN3	0xFF000000
+#define ATM_CFG_ARB_WEIGHTS_SCHED_BIN_BIN0_LOC	0
+#define ATM_CFG_ARB_WEIGHTS_SCHED_BIN_BIN1_LOC	8
+#define ATM_CFG_ARB_WEIGHTS_SCHED_BIN_BIN2_LOC	16
+#define ATM_CFG_ARB_WEIGHTS_SCHED_BIN_BIN3_LOC	24
+
+#define ATM_SMON_ACTIVITYCNTR0 0x3c000050
+#define ATM_SMON_ACTIVITYCNTR0_RST 0x0
+
+#define ATM_SMON_ACTIVITYCNTR0_COUNTER0	0xFFFFFFFF
+#define ATM_SMON_ACTIVITYCNTR0_COUNTER0_LOC	0
+
+#define ATM_SMON_ACTIVITYCNTR1 0x3c000054
+#define ATM_SMON_ACTIVITYCNTR1_RST 0x0
+
+#define ATM_SMON_ACTIVITYCNTR1_COUNTER1	0xFFFFFFFF
+#define ATM_SMON_ACTIVITYCNTR1_COUNTER1_LOC	0
+
+#define ATM_SMON_COMPARE0 0x3c000058
+#define ATM_SMON_COMPARE0_RST 0x0
+
+#define ATM_SMON_COMPARE0_COMPARE0	0xFFFFFFFF
+#define ATM_SMON_COMPARE0_COMPARE0_LOC	0
+
+#define ATM_SMON_COMPARE1 0x3c00005c
+#define ATM_SMON_COMPARE1_RST 0x0
+
+#define ATM_SMON_COMPARE1_COMPARE1	0xFFFFFFFF
+#define ATM_SMON_COMPARE1_COMPARE1_LOC	0
+
+#define ATM_SMON_CFG0 0x3c000060
+#define ATM_SMON_CFG0_RST 0x40000000
+
+#define ATM_SMON_CFG0_SMON_ENABLE		0x00000001
+#define ATM_SMON_CFG0_SMON_0TRIGGER_ENABLE	0x00000002
+#define ATM_SMON_CFG0_RSVZ0			0x0000000C
+#define ATM_SMON_CFG0_SMON0_FUNCTION		0x00000070
+#define ATM_SMON_CFG0_SMON0_FUNCTION_COMPARE	0x00000080
+#define ATM_SMON_CFG0_SMON1_FUNCTION		0x00000700
+#define ATM_SMON_CFG0_SMON1_FUNCTION_COMPARE	0x00000800
+#define ATM_SMON_CFG0_SMON_MODE			0x0000F000
+#define ATM_SMON_CFG0_STOPCOUNTEROVFL		0x00010000
+#define ATM_SMON_CFG0_INTCOUNTEROVFL		0x00020000
+#define ATM_SMON_CFG0_STATCOUNTER0OVFL		0x00040000
+#define ATM_SMON_CFG0_STATCOUNTER1OVFL		0x00080000
+#define ATM_SMON_CFG0_STOPTIMEROVFL		0x00100000
+#define ATM_SMON_CFG0_INTTIMEROVFL		0x00200000
+#define ATM_SMON_CFG0_STATTIMEROVFL		0x00400000
+#define ATM_SMON_CFG0_RSVZ1			0x00800000
+#define ATM_SMON_CFG0_TIMER_PRESCALE		0x1F000000
+#define ATM_SMON_CFG0_RSVZ2			0x20000000
+#define ATM_SMON_CFG0_VERSION			0xC0000000
+#define ATM_SMON_CFG0_SMON_ENABLE_LOC			0
+#define ATM_SMON_CFG0_SMON_0TRIGGER_ENABLE_LOC		1
+#define ATM_SMON_CFG0_RSVZ0_LOC				2
+#define ATM_SMON_CFG0_SMON0_FUNCTION_LOC		4
+#define ATM_SMON_CFG0_SMON0_FUNCTION_COMPARE_LOC	7
+#define ATM_SMON_CFG0_SMON1_FUNCTION_LOC		8
+#define ATM_SMON_CFG0_SMON1_FUNCTION_COMPARE_LOC	11
+#define ATM_SMON_CFG0_SMON_MODE_LOC			12
+#define ATM_SMON_CFG0_STOPCOUNTEROVFL_LOC		16
+#define ATM_SMON_CFG0_INTCOUNTEROVFL_LOC		17
+#define ATM_SMON_CFG0_STATCOUNTER0OVFL_LOC		18
+#define ATM_SMON_CFG0_STATCOUNTER1OVFL_LOC		19
+#define ATM_SMON_CFG0_STOPTIMEROVFL_LOC			20
+#define ATM_SMON_CFG0_INTTIMEROVFL_LOC			21
+#define ATM_SMON_CFG0_STATTIMEROVFL_LOC			22
+#define ATM_SMON_CFG0_RSVZ1_LOC				23
+#define ATM_SMON_CFG0_TIMER_PRESCALE_LOC		24
+#define ATM_SMON_CFG0_RSVZ2_LOC				29
+#define ATM_SMON_CFG0_VERSION_LOC			30
+
+#define ATM_SMON_CFG1 0x3c000064
+#define ATM_SMON_CFG1_RST 0x0
+
+#define ATM_SMON_CFG1_MODE0	0x000000FF
+#define ATM_SMON_CFG1_MODE1	0x0000FF00
+#define ATM_SMON_CFG1_RSVZ0	0xFFFF0000
+#define ATM_SMON_CFG1_MODE0_LOC	0
+#define ATM_SMON_CFG1_MODE1_LOC	8
+#define ATM_SMON_CFG1_RSVZ0_LOC	16
+
+#define ATM_SMON_MAX_TMR 0x3c000068
+#define ATM_SMON_MAX_TMR_RST 0x0
+
+#define ATM_SMON_MAX_TMR_MAXVALUE	0xFFFFFFFF
+#define ATM_SMON_MAX_TMR_MAXVALUE_LOC	0
+
+#define ATM_SMON_TMR 0x3c00006c
+#define ATM_SMON_TMR_RST 0x0
+
+#define ATM_SMON_TMR_TIMER	0xFFFFFFFF
+#define ATM_SMON_TMR_TIMER_LOC	0
 
 #define CHP_CFG_DIR_VAS_CRD(x) \
 	(0x40000000 + (x) * 0x1000)
 #define CHP_CFG_DIR_VAS_CRD_RST 0x0
 
-#define CHP_CFG_DIR_VAS_CRD_COUNT	0x00003FFF
-#define CHP_CFG_DIR_VAS_CRD_RSVD0	0xFFFFC000
-#define CHP_CFG_DIR_VAS_CRD_COUNT_LOC	0
-#define CHP_CFG_DIR_VAS_CRD_RSVD0_LOC	14
+#define CHP_CFG_DIR_VAS_CRD_COUNT	0x00003FFF
+#define CHP_CFG_DIR_VAS_CRD_RSVD0	0xFFFFC000
+#define CHP_CFG_DIR_VAS_CRD_COUNT_LOC	0
+#define CHP_CFG_DIR_VAS_CRD_RSVD0_LOC	14
+
+#define CHP_CFG_LDB_VAS_CRD(x) \
+	(0x40080000 + (x) * 0x1000)
+#define CHP_CFG_LDB_VAS_CRD_RST 0x0
+
+#define CHP_CFG_LDB_VAS_CRD_COUNT	0x00007FFF
+#define CHP_CFG_LDB_VAS_CRD_RSVD0	0xFFFF8000
+#define CHP_CFG_LDB_VAS_CRD_COUNT_LOC	0
+#define CHP_CFG_LDB_VAS_CRD_RSVD0_LOC	15
+
+#define CHP_ORD_QID_SN(x) \
+	(0x40100000 + (x) * 0x1000)
+#define CHP_ORD_QID_SN_RST 0x0
+
+#define CHP_ORD_QID_SN_SN	0x000003FF
+#define CHP_ORD_QID_SN_RSVD0	0xFFFFFC00
+#define CHP_ORD_QID_SN_SN_LOC		0
+#define CHP_ORD_QID_SN_RSVD0_LOC	10
+
+#define CHP_ORD_QID_SN_MAP(x) \
+	(0x40180000 + (x) * 0x1000)
+#define CHP_ORD_QID_SN_MAP_RST 0x0
+
+#define CHP_ORD_QID_SN_MAP_MODE		0x00000007
+#define CHP_ORD_QID_SN_MAP_SLOT		0x00000078
+#define CHP_ORD_QID_SN_MAP_RSVZ0	0x00000080
+#define CHP_ORD_QID_SN_MAP_GRP		0x00000100
+#define CHP_ORD_QID_SN_MAP_RSVZ1	0x00000200
+#define CHP_ORD_QID_SN_MAP_RSVD0	0xFFFFFC00
+#define CHP_ORD_QID_SN_MAP_MODE_LOC	0
+#define CHP_ORD_QID_SN_MAP_SLOT_LOC	3
+#define CHP_ORD_QID_SN_MAP_RSVZ0_LOC	7
+#define CHP_ORD_QID_SN_MAP_GRP_LOC	8
+#define CHP_ORD_QID_SN_MAP_RSVZ1_LOC	9
+#define CHP_ORD_QID_SN_MAP_RSVD0_LOC	10
+
+#define CHP_SN_CHK_ENBL(x) \
+	(0x40200000 + (x) * 0x1000)
+#define CHP_SN_CHK_ENBL_RST 0x0
+
+#define CHP_SN_CHK_ENBL_EN	0x00000001
+#define CHP_SN_CHK_ENBL_RSVD0	0xFFFFFFFE
+#define CHP_SN_CHK_ENBL_EN_LOC		0
+#define CHP_SN_CHK_ENBL_RSVD0_LOC	1
+
+#define CHP_DIR_CQ_DEPTH(x) \
+	(0x40280000 + (x) * 0x1000)
+#define CHP_DIR_CQ_DEPTH_RST 0x0
+
+#define CHP_DIR_CQ_DEPTH_DEPTH	0x00001FFF
+#define CHP_DIR_CQ_DEPTH_RSVD0	0xFFFFE000
+#define CHP_DIR_CQ_DEPTH_DEPTH_LOC	0
+#define CHP_DIR_CQ_DEPTH_RSVD0_LOC	13
+
+#define CHP_DIR_CQ_INT_DEPTH_THRSH(x) \
+	(0x40300000 + (x) * 0x1000)
+#define CHP_DIR_CQ_INT_DEPTH_THRSH_RST 0x0
+
+#define CHP_DIR_CQ_INT_DEPTH_THRSH_DEPTH_THRESHOLD	0x00001FFF
+#define CHP_DIR_CQ_INT_DEPTH_THRSH_RSVD0		0xFFFFE000
+#define CHP_DIR_CQ_INT_DEPTH_THRSH_DEPTH_THRESHOLD_LOC	0
+#define CHP_DIR_CQ_INT_DEPTH_THRSH_RSVD0_LOC		13
+
+#define CHP_DIR_CQ_INT_ENB(x) \
+	(0x40380000 + (x) * 0x1000)
+#define CHP_DIR_CQ_INT_ENB_RST 0x0
+
+#define CHP_DIR_CQ_INT_ENB_EN_TIM	0x00000001
+#define CHP_DIR_CQ_INT_ENB_EN_DEPTH	0x00000002
+#define CHP_DIR_CQ_INT_ENB_RSVD0	0xFFFFFFFC
+#define CHP_DIR_CQ_INT_ENB_EN_TIM_LOC	0
+#define CHP_DIR_CQ_INT_ENB_EN_DEPTH_LOC	1
+#define CHP_DIR_CQ_INT_ENB_RSVD0_LOC	2
+
+#define CHP_DIR_CQ_TMR_THRSH(x) \
+	(0x40480000 + (x) * 0x1000)
+#define CHP_DIR_CQ_TMR_THRSH_RST 0x1
+
+#define CHP_DIR_CQ_TMR_THRSH_THRSH_0	0x00000001
+#define CHP_DIR_CQ_TMR_THRSH_THRSH_13_1	0x00003FFE
+#define CHP_DIR_CQ_TMR_THRSH_RSVD0	0xFFFFC000
+#define CHP_DIR_CQ_TMR_THRSH_THRSH_0_LOC	0
+#define CHP_DIR_CQ_TMR_THRSH_THRSH_13_1_LOC	1
+#define CHP_DIR_CQ_TMR_THRSH_RSVD0_LOC		14
+
+#define CHP_DIR_CQ_TKN_DEPTH_SEL(x) \
+	(0x40500000 + (x) * 0x1000)
+#define CHP_DIR_CQ_TKN_DEPTH_SEL_RST 0x0
+
+#define CHP_DIR_CQ_TKN_DEPTH_SEL_TOKEN_DEPTH_SELECT	0x0000000F
+#define CHP_DIR_CQ_TKN_DEPTH_SEL_RSVD0			0xFFFFFFF0
+#define CHP_DIR_CQ_TKN_DEPTH_SEL_TOKEN_DEPTH_SELECT_LOC	0
+#define CHP_DIR_CQ_TKN_DEPTH_SEL_RSVD0_LOC		4
+
+#define CHP_DIR_CQ_WD_ENB(x) \
+	(0x40580000 + (x) * 0x1000)
+#define CHP_DIR_CQ_WD_ENB_RST 0x0
+
+#define CHP_DIR_CQ_WD_ENB_WD_ENABLE	0x00000001
+#define CHP_DIR_CQ_WD_ENB_RSVD0		0xFFFFFFFE
+#define CHP_DIR_CQ_WD_ENB_WD_ENABLE_LOC	0
+#define CHP_DIR_CQ_WD_ENB_RSVD0_LOC	1
+
+#define CHP_DIR_CQ_WPTR(x) \
+	(0x40600000 + (x) * 0x1000)
+#define CHP_DIR_CQ_WPTR_RST 0x0
+
+#define CHP_DIR_CQ_WPTR_WRITE_POINTER	0x00001FFF
+#define CHP_DIR_CQ_WPTR_RSVD0		0xFFFFE000
+#define CHP_DIR_CQ_WPTR_WRITE_POINTER_LOC	0
+#define CHP_DIR_CQ_WPTR_RSVD0_LOC		13
+
+#define CHP_DIR_CQ2VAS(x) \
+	(0x40680000 + (x) * 0x1000)
+#define CHP_DIR_CQ2VAS_RST 0x0
+
+#define CHP_DIR_CQ2VAS_CQ2VAS	0x0000001F
+#define CHP_DIR_CQ2VAS_RSVD0	0xFFFFFFE0
+#define CHP_DIR_CQ2VAS_CQ2VAS_LOC	0
+#define CHP_DIR_CQ2VAS_RSVD0_LOC	5
+
+#define CHP_HIST_LIST_BASE(x) \
+	(0x40700000 + (x) * 0x1000)
+#define CHP_HIST_LIST_BASE_RST 0x0
+
+#define CHP_HIST_LIST_BASE_BASE		0x00001FFF
+#define CHP_HIST_LIST_BASE_RSVD0	0xFFFFE000
+#define CHP_HIST_LIST_BASE_BASE_LOC	0
+#define CHP_HIST_LIST_BASE_RSVD0_LOC	13
+
+#define CHP_HIST_LIST_LIM(x) \
+	(0x40780000 + (x) * 0x1000)
+#define CHP_HIST_LIST_LIM_RST 0x0
+
+#define CHP_HIST_LIST_LIM_LIMIT	0x00001FFF
+#define CHP_HIST_LIST_LIM_RSVD0	0xFFFFE000
+#define CHP_HIST_LIST_LIM_LIMIT_LOC	0
+#define CHP_HIST_LIST_LIM_RSVD0_LOC	13
+
+#define CHP_HIST_LIST_POP_PTR(x) \
+	(0x40800000 + (x) * 0x1000)
+#define CHP_HIST_LIST_POP_PTR_RST 0x0
+
+#define CHP_HIST_LIST_POP_PTR_POP_PTR		0x00001FFF
+#define CHP_HIST_LIST_POP_PTR_GENERATION	0x00002000
+#define CHP_HIST_LIST_POP_PTR_RSVD0		0xFFFFC000
+#define CHP_HIST_LIST_POP_PTR_POP_PTR_LOC	0
+#define CHP_HIST_LIST_POP_PTR_GENERATION_LOC	13
+#define CHP_HIST_LIST_POP_PTR_RSVD0_LOC		14
+
+#define CHP_HIST_LIST_PUSH_PTR(x) \
+	(0x40880000 + (x) * 0x1000)
+#define CHP_HIST_LIST_PUSH_PTR_RST 0x0
+
+#define CHP_HIST_LIST_PUSH_PTR_PUSH_PTR		0x00001FFF
+#define CHP_HIST_LIST_PUSH_PTR_GENERATION	0x00002000
+#define CHP_HIST_LIST_PUSH_PTR_RSVD0		0xFFFFC000
+#define CHP_HIST_LIST_PUSH_PTR_PUSH_PTR_LOC	0
+#define CHP_HIST_LIST_PUSH_PTR_GENERATION_LOC	13
+#define CHP_HIST_LIST_PUSH_PTR_RSVD0_LOC	14
+
+#define CHP_LDB_CQ_DEPTH(x) \
+	(0x40900000 + (x) * 0x1000)
+#define CHP_LDB_CQ_DEPTH_RST 0x0
+
+#define CHP_LDB_CQ_DEPTH_DEPTH	0x000007FF
+#define CHP_LDB_CQ_DEPTH_RSVD0	0xFFFFF800
+#define CHP_LDB_CQ_DEPTH_DEPTH_LOC	0
+#define CHP_LDB_CQ_DEPTH_RSVD0_LOC	11
+
+#define CHP_LDB_CQ_INT_DEPTH_THRSH(x) \
+	(0x40980000 + (x) * 0x1000)
+#define CHP_LDB_CQ_INT_DEPTH_THRSH_RST 0x0
+
+#define CHP_LDB_CQ_INT_DEPTH_THRSH_DEPTH_THRESHOLD	0x000007FF
+#define CHP_LDB_CQ_INT_DEPTH_THRSH_RSVD0		0xFFFFF800
+#define CHP_LDB_CQ_INT_DEPTH_THRSH_DEPTH_THRESHOLD_LOC	0
+#define CHP_LDB_CQ_INT_DEPTH_THRSH_RSVD0_LOC		11
+
+#define CHP_LDB_CQ_INT_ENB(x) \
+	(0x40a00000 + (x) * 0x1000)
+#define CHP_LDB_CQ_INT_ENB_RST 0x0
+
+#define CHP_LDB_CQ_INT_ENB_EN_TIM	0x00000001
+#define CHP_LDB_CQ_INT_ENB_EN_DEPTH	0x00000002
+#define CHP_LDB_CQ_INT_ENB_RSVD0	0xFFFFFFFC
+#define CHP_LDB_CQ_INT_ENB_EN_TIM_LOC	0
+#define CHP_LDB_CQ_INT_ENB_EN_DEPTH_LOC	1
+#define CHP_LDB_CQ_INT_ENB_RSVD0_LOC	2
+
+#define CHP_LDB_CQ_TMR_THRSH(x) \
+	(0x40b00000 + (x) * 0x1000)
+#define CHP_LDB_CQ_TMR_THRSH_RST 0x1
+
+#define CHP_LDB_CQ_TMR_THRSH_THRSH_0	0x00000001
+#define CHP_LDB_CQ_TMR_THRSH_THRSH_13_1	0x00003FFE
+#define CHP_LDB_CQ_TMR_THRSH_RSVD0	0xFFFFC000
+#define CHP_LDB_CQ_TMR_THRSH_THRSH_0_LOC	0
+#define CHP_LDB_CQ_TMR_THRSH_THRSH_13_1_LOC	1
+#define CHP_LDB_CQ_TMR_THRSH_RSVD0_LOC		14
+
+#define CHP_LDB_CQ_TKN_DEPTH_SEL(x) \
+	(0x40b80000 + (x) * 0x1000)
+#define CHP_LDB_CQ_TKN_DEPTH_SEL_RST 0x0
+
+#define CHP_LDB_CQ_TKN_DEPTH_SEL_TOKEN_DEPTH_SELECT	0x0000000F
+#define CHP_LDB_CQ_TKN_DEPTH_SEL_RSVD0			0xFFFFFFF0
+#define CHP_LDB_CQ_TKN_DEPTH_SEL_TOKEN_DEPTH_SELECT_LOC	0
+#define CHP_LDB_CQ_TKN_DEPTH_SEL_RSVD0_LOC		4
+
+#define CHP_LDB_CQ_WD_ENB(x) \
+	(0x40c00000 + (x) * 0x1000)
+#define CHP_LDB_CQ_WD_ENB_RST 0x0
+
+#define CHP_LDB_CQ_WD_ENB_WD_ENABLE	0x00000001
+#define CHP_LDB_CQ_WD_ENB_RSVD0		0xFFFFFFFE
+#define CHP_LDB_CQ_WD_ENB_WD_ENABLE_LOC	0
+#define CHP_LDB_CQ_WD_ENB_RSVD0_LOC	1
+
+#define CHP_LDB_CQ_WPTR(x) \
+	(0x40c80000 + (x) * 0x1000)
+#define CHP_LDB_CQ_WPTR_RST 0x0
+
+#define CHP_LDB_CQ_WPTR_WRITE_POINTER	0x000007FF
+#define CHP_LDB_CQ_WPTR_RSVD0		0xFFFFF800
+#define CHP_LDB_CQ_WPTR_WRITE_POINTER_LOC	0
+#define CHP_LDB_CQ_WPTR_RSVD0_LOC		11
+
+#define CHP_LDB_CQ2VAS(x) \
+	(0x40d00000 + (x) * 0x1000)
+#define CHP_LDB_CQ2VAS_RST 0x0
+
+#define CHP_LDB_CQ2VAS_CQ2VAS	0x0000001F
+#define CHP_LDB_CQ2VAS_RSVD0	0xFFFFFFE0
+#define CHP_LDB_CQ2VAS_CQ2VAS_LOC	0
+#define CHP_LDB_CQ2VAS_RSVD0_LOC	5
+
+#define CHP_CFG_CHP_CSR_CTRL 0x44000008
+#define CHP_CFG_CHP_CSR_CTRL_RST 0x180002
+
+#define CHP_CFG_CHP_CSR_CTRL_INT_COR_ALARM_DIS		0x00000001
+#define CHP_CFG_CHP_CSR_CTRL_INT_COR_SYND_DIS		0x00000002
+#define CHP_CFG_CHP_CSR_CTRL_INT_UNCR_ALARM_DIS		0x00000004
+#define CHP_CFG_CHP_CSR_CTRL_INT_UNC_SYND_DIS		0x00000008
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF0_ALARM_DIS		0x00000010
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF0_SYND_DIS		0x00000020
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF1_ALARM_DIS		0x00000040
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF1_SYND_DIS		0x00000080
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF2_ALARM_DIS		0x00000100
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF2_SYND_DIS		0x00000200
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF3_ALARM_DIS		0x00000400
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF3_SYND_DIS		0x00000800
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF4_ALARM_DIS		0x00001000
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF4_SYND_DIS		0x00002000
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF5_ALARM_DIS		0x00004000
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF5_SYND_DIS		0x00008000
+#define CHP_CFG_CHP_CSR_CTRL_DLB_COR_ALARM_ENABLE	0x00010000
+#define CHP_CFG_CHP_CSR_CTRL_CFG_64BYTES_QE_LDB_CQ_MODE	0x00020000
+#define CHP_CFG_CHP_CSR_CTRL_CFG_64BYTES_QE_DIR_CQ_MODE	0x00040000
+#define CHP_CFG_CHP_CSR_CTRL_PAD_WRITE_LDB		0x00080000
+#define CHP_CFG_CHP_CSR_CTRL_PAD_WRITE_DIR		0x00100000
+#define CHP_CFG_CHP_CSR_CTRL_PAD_FIRST_WRITE_LDB	0x00200000
+#define CHP_CFG_CHP_CSR_CTRL_PAD_FIRST_WRITE_DIR	0x00400000
+#define CHP_CFG_CHP_CSR_CTRL_RSVZ0			0xFF800000
+#define CHP_CFG_CHP_CSR_CTRL_INT_COR_ALARM_DIS_LOC		0
+#define CHP_CFG_CHP_CSR_CTRL_INT_COR_SYND_DIS_LOC		1
+#define CHP_CFG_CHP_CSR_CTRL_INT_UNCR_ALARM_DIS_LOC		2
+#define CHP_CFG_CHP_CSR_CTRL_INT_UNC_SYND_DIS_LOC		3
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF0_ALARM_DIS_LOC		4
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF0_SYND_DIS_LOC		5
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF1_ALARM_DIS_LOC		6
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF1_SYND_DIS_LOC		7
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF2_ALARM_DIS_LOC		8
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF2_SYND_DIS_LOC		9
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF3_ALARM_DIS_LOC		10
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF3_SYND_DIS_LOC		11
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF4_ALARM_DIS_LOC		12
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF4_SYND_DIS_LOC		13
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF5_ALARM_DIS_LOC		14
+#define CHP_CFG_CHP_CSR_CTRL_INT_INF5_SYND_DIS_LOC		15
+#define CHP_CFG_CHP_CSR_CTRL_DLB_COR_ALARM_ENABLE_LOC		16
+#define CHP_CFG_CHP_CSR_CTRL_CFG_64BYTES_QE_LDB_CQ_MODE_LOC	17
+#define CHP_CFG_CHP_CSR_CTRL_CFG_64BYTES_QE_DIR_CQ_MODE_LOC	18
+#define CHP_CFG_CHP_CSR_CTRL_PAD_WRITE_LDB_LOC			19
+#define CHP_CFG_CHP_CSR_CTRL_PAD_WRITE_DIR_LOC			20
+#define CHP_CFG_CHP_CSR_CTRL_PAD_FIRST_WRITE_LDB_LOC		21
+#define CHP_CFG_CHP_CSR_CTRL_PAD_FIRST_WRITE_DIR_LOC		22
+#define CHP_CFG_CHP_CSR_CTRL_RSVZ0_LOC				23
+
+#define CHP_DIR_CQ_INTR_ARMED0 0x4400005c
+#define CHP_DIR_CQ_INTR_ARMED0_RST 0x0
+
+#define CHP_DIR_CQ_INTR_ARMED0_ARMED	0xFFFFFFFF
+#define CHP_DIR_CQ_INTR_ARMED0_ARMED_LOC	0
+
+#define CHP_DIR_CQ_INTR_ARMED1 0x44000060
+#define CHP_DIR_CQ_INTR_ARMED1_RST 0x0
+
+#define CHP_DIR_CQ_INTR_ARMED1_ARMED	0xFFFFFFFF
+#define CHP_DIR_CQ_INTR_ARMED1_ARMED_LOC	0
+
+#define CHP_CFG_DIR_CQ_TIMER_CTL 0x44000084
+#define CHP_CFG_DIR_CQ_TIMER_CTL_RST 0x0
+
+#define CHP_CFG_DIR_CQ_TIMER_CTL_SAMPLE_INTERVAL	0x000000FF
+#define CHP_CFG_DIR_CQ_TIMER_CTL_ENB			0x00000100
+#define CHP_CFG_DIR_CQ_TIMER_CTL_RSVZ0			0xFFFFFE00
+#define CHP_CFG_DIR_CQ_TIMER_CTL_SAMPLE_INTERVAL_LOC	0
+#define CHP_CFG_DIR_CQ_TIMER_CTL_ENB_LOC		8
+#define CHP_CFG_DIR_CQ_TIMER_CTL_RSVZ0_LOC		9
+
+#define CHP_CFG_DIR_WDTO_0 0x44000088
+#define CHP_CFG_DIR_WDTO_0_RST 0x0
+
+#define CHP_CFG_DIR_WDTO_0_WDTO	0xFFFFFFFF
+#define CHP_CFG_DIR_WDTO_0_WDTO_LOC	0
+
+#define CHP_CFG_DIR_WDTO_1 0x4400008c
+#define CHP_CFG_DIR_WDTO_1_RST 0x0
+
+#define CHP_CFG_DIR_WDTO_1_WDTO	0xFFFFFFFF
+#define CHP_CFG_DIR_WDTO_1_WDTO_LOC	0
+
+#define CHP_CFG_DIR_WD_DISABLE0 0x44000098
+#define CHP_CFG_DIR_WD_DISABLE0_RST 0xffffffff
+
+#define CHP_CFG_DIR_WD_DISABLE0_WD_DISABLE	0xFFFFFFFF
+#define CHP_CFG_DIR_WD_DISABLE0_WD_DISABLE_LOC	0
+
+#define CHP_CFG_DIR_WD_DISABLE1 0x4400009c
+#define CHP_CFG_DIR_WD_DISABLE1_RST 0xffffffff
+
+#define CHP_CFG_DIR_WD_DISABLE1_WD_DISABLE	0xFFFFFFFF
+#define CHP_CFG_DIR_WD_DISABLE1_WD_DISABLE_LOC	0
+
+#define CHP_CFG_DIR_WD_ENB_INTERVAL 0x440000a0
+#define CHP_CFG_DIR_WD_ENB_INTERVAL_RST 0x0
+
+#define CHP_CFG_DIR_WD_ENB_INTERVAL_SAMPLE_INTERVAL	0x0FFFFFFF
+#define CHP_CFG_DIR_WD_ENB_INTERVAL_ENB			0x10000000
+#define CHP_CFG_DIR_WD_ENB_INTERVAL_RSVZ0		0xE0000000
+#define CHP_CFG_DIR_WD_ENB_INTERVAL_SAMPLE_INTERVAL_LOC	0
+#define CHP_CFG_DIR_WD_ENB_INTERVAL_ENB_LOC		28
+#define CHP_CFG_DIR_WD_ENB_INTERVAL_RSVZ0_LOC		29
+
+#define CHP_CFG_DIR_WD_THRESHOLD 0x440000ac
+#define CHP_CFG_DIR_WD_THRESHOLD_RST 0x0
+
+#define CHP_CFG_DIR_WD_THRESHOLD_WD_THRESHOLD	0x000000FF
+#define CHP_CFG_DIR_WD_THRESHOLD_RSVZ0		0xFFFFFF00
+#define CHP_CFG_DIR_WD_THRESHOLD_WD_THRESHOLD_LOC	0
+#define CHP_CFG_DIR_WD_THRESHOLD_RSVZ0_LOC		8
+
+#define CHP_LDB_CQ_INTR_ARMED0 0x440000b0
+#define CHP_LDB_CQ_INTR_ARMED0_RST 0x0
+
+#define CHP_LDB_CQ_INTR_ARMED0_ARMED	0xFFFFFFFF
+#define CHP_LDB_CQ_INTR_ARMED0_ARMED_LOC	0
+
+#define CHP_LDB_CQ_INTR_ARMED1 0x440000b4
+#define CHP_LDB_CQ_INTR_ARMED1_RST 0x0
+
+#define CHP_LDB_CQ_INTR_ARMED1_ARMED	0xFFFFFFFF
+#define CHP_LDB_CQ_INTR_ARMED1_ARMED_LOC	0
+
+#define CHP_CFG_LDB_CQ_TIMER_CTL 0x440000d8
+#define CHP_CFG_LDB_CQ_TIMER_CTL_RST 0x0
+
+#define CHP_CFG_LDB_CQ_TIMER_CTL_SAMPLE_INTERVAL	0x000000FF
+#define CHP_CFG_LDB_CQ_TIMER_CTL_ENB			0x00000100
+#define CHP_CFG_LDB_CQ_TIMER_CTL_RSVZ0			0xFFFFFE00
+#define CHP_CFG_LDB_CQ_TIMER_CTL_SAMPLE_INTERVAL_LOC	0
+#define CHP_CFG_LDB_CQ_TIMER_CTL_ENB_LOC		8
+#define CHP_CFG_LDB_CQ_TIMER_CTL_RSVZ0_LOC		9
+
+#define CHP_CFG_LDB_WDTO_0 0x440000dc
+#define CHP_CFG_LDB_WDTO_0_RST 0x0
+
+#define CHP_CFG_LDB_WDTO_0_WDTO	0xFFFFFFFF
+#define CHP_CFG_LDB_WDTO_0_WDTO_LOC	0
+
+#define CHP_CFG_LDB_WDTO_1 0x440000e0
+#define CHP_CFG_LDB_WDTO_1_RST 0x0
+
+#define CHP_CFG_LDB_WDTO_1_WDTO	0xFFFFFFFF
+#define CHP_CFG_LDB_WDTO_1_WDTO_LOC	0
+
+#define CHP_CFG_LDB_WD_DISABLE0 0x440000ec
+#define CHP_CFG_LDB_WD_DISABLE0_RST 0xffffffff
+
+#define CHP_CFG_LDB_WD_DISABLE0_WD_DISABLE	0xFFFFFFFF
+#define CHP_CFG_LDB_WD_DISABLE0_WD_DISABLE_LOC	0
+
+#define CHP_CFG_LDB_WD_DISABLE1 0x440000f0
+#define CHP_CFG_LDB_WD_DISABLE1_RST 0xffffffff
+
+#define CHP_CFG_LDB_WD_DISABLE1_WD_DISABLE	0xFFFFFFFF
+#define CHP_CFG_LDB_WD_DISABLE1_WD_DISABLE_LOC	0
+
+#define CHP_CFG_LDB_WD_ENB_INTERVAL 0x440000f4
+#define CHP_CFG_LDB_WD_ENB_INTERVAL_RST 0x0
+
+#define CHP_CFG_LDB_WD_ENB_INTERVAL_SAMPLE_INTERVAL	0x0FFFFFFF
+#define CHP_CFG_LDB_WD_ENB_INTERVAL_ENB			0x10000000
+#define CHP_CFG_LDB_WD_ENB_INTERVAL_RSVZ0		0xE0000000
+#define CHP_CFG_LDB_WD_ENB_INTERVAL_SAMPLE_INTERVAL_LOC	0
+#define CHP_CFG_LDB_WD_ENB_INTERVAL_ENB_LOC		28
+#define CHP_CFG_LDB_WD_ENB_INTERVAL_RSVZ0_LOC		29
+
+#define CHP_CFG_LDB_WD_THRESHOLD 0x44000100
+#define CHP_CFG_LDB_WD_THRESHOLD_RST 0x0
+
+#define CHP_CFG_LDB_WD_THRESHOLD_WD_THRESHOLD	0x000000FF
+#define CHP_CFG_LDB_WD_THRESHOLD_RSVZ0		0xFFFFFF00
+#define CHP_CFG_LDB_WD_THRESHOLD_WD_THRESHOLD_LOC	0
+#define CHP_CFG_LDB_WD_THRESHOLD_RSVZ0_LOC		8
+
+#define CHP_SMON_COMPARE0 0x4c000000
+#define CHP_SMON_COMPARE0_RST 0x0
+
+#define CHP_SMON_COMPARE0_COMPARE0	0xFFFFFFFF
+#define CHP_SMON_COMPARE0_COMPARE0_LOC	0
+
+#define CHP_SMON_COMPARE1 0x4c000004
+#define CHP_SMON_COMPARE1_RST 0x0
+
+#define CHP_SMON_COMPARE1_COMPARE1	0xFFFFFFFF
+#define CHP_SMON_COMPARE1_COMPARE1_LOC	0
+
+#define CHP_SMON_CFG0 0x4c000008
+#define CHP_SMON_CFG0_RST 0x40000000
+
+#define CHP_SMON_CFG0_SMON_ENABLE		0x00000001
+#define CHP_SMON_CFG0_SMON_0TRIGGER_ENABLE	0x00000002
+#define CHP_SMON_CFG0_RSVZ0			0x0000000C
+#define CHP_SMON_CFG0_SMON0_FUNCTION		0x00000070
+#define CHP_SMON_CFG0_SMON0_FUNCTION_COMPARE	0x00000080
+#define CHP_SMON_CFG0_SMON1_FUNCTION		0x00000700
+#define CHP_SMON_CFG0_SMON1_FUNCTION_COMPARE	0x00000800
+#define CHP_SMON_CFG0_SMON_MODE			0x0000F000
+#define CHP_SMON_CFG0_STOPCOUNTEROVFL		0x00010000
+#define CHP_SMON_CFG0_INTCOUNTEROVFL		0x00020000
+#define CHP_SMON_CFG0_STATCOUNTER0OVFL		0x00040000
+#define CHP_SMON_CFG0_STATCOUNTER1OVFL		0x00080000
+#define CHP_SMON_CFG0_STOPTIMEROVFL		0x00100000
+#define CHP_SMON_CFG0_INTTIMEROVFL		0x00200000
+#define CHP_SMON_CFG0_STATTIMEROVFL		0x00400000
+#define CHP_SMON_CFG0_RSVZ1			0x00800000
+#define CHP_SMON_CFG0_TIMER_PRESCALE		0x1F000000
+#define CHP_SMON_CFG0_RSVZ2			0x20000000
+#define CHP_SMON_CFG0_VERSION			0xC0000000
+#define CHP_SMON_CFG0_SMON_ENABLE_LOC			0
+#define CHP_SMON_CFG0_SMON_0TRIGGER_ENABLE_LOC		1
+#define CHP_SMON_CFG0_RSVZ0_LOC				2
+#define CHP_SMON_CFG0_SMON0_FUNCTION_LOC		4
+#define CHP_SMON_CFG0_SMON0_FUNCTION_COMPARE_LOC	7
+#define CHP_SMON_CFG0_SMON1_FUNCTION_LOC		8
+#define CHP_SMON_CFG0_SMON1_FUNCTION_COMPARE_LOC	11
+#define CHP_SMON_CFG0_SMON_MODE_LOC			12
+#define CHP_SMON_CFG0_STOPCOUNTEROVFL_LOC		16
+#define CHP_SMON_CFG0_INTCOUNTEROVFL_LOC		17
+#define CHP_SMON_CFG0_STATCOUNTER0OVFL_LOC		18
+#define CHP_SMON_CFG0_STATCOUNTER1OVFL_LOC		19
+#define CHP_SMON_CFG0_STOPTIMEROVFL_LOC			20
+#define CHP_SMON_CFG0_INTTIMEROVFL_LOC			21
+#define CHP_SMON_CFG0_STATTIMEROVFL_LOC			22
+#define CHP_SMON_CFG0_RSVZ1_LOC				23
+#define CHP_SMON_CFG0_TIMER_PRESCALE_LOC		24
+#define CHP_SMON_CFG0_RSVZ2_LOC				29
+#define CHP_SMON_CFG0_VERSION_LOC			30
+
+#define CHP_SMON_CFG1 0x4c00000c
+#define CHP_SMON_CFG1_RST 0x0
+
+#define CHP_SMON_CFG1_MODE0	0x000000FF
+#define CHP_SMON_CFG1_MODE1	0x0000FF00
+#define CHP_SMON_CFG1_RSVZ0	0xFFFF0000
+#define CHP_SMON_CFG1_MODE0_LOC	0
+#define CHP_SMON_CFG1_MODE1_LOC	8
+#define CHP_SMON_CFG1_RSVZ0_LOC	16
+
+#define CHP_SMON_ACTIVITYCNTR0 0x4c000010
+#define CHP_SMON_ACTIVITYCNTR0_RST 0x0
+
+#define CHP_SMON_ACTIVITYCNTR0_COUNTER0	0xFFFFFFFF
+#define CHP_SMON_ACTIVITYCNTR0_COUNTER0_LOC	0
+
+#define CHP_SMON_ACTIVITYCNTR1 0x4c000014
+#define CHP_SMON_ACTIVITYCNTR1_RST 0x0
 
-#define CHP_CFG_LDB_VAS_CRD(x) \
-	(0x40080000 + (x) * 0x1000)
-#define CHP_CFG_LDB_VAS_CRD_RST 0x0
+#define CHP_SMON_ACTIVITYCNTR1_COUNTER1	0xFFFFFFFF
+#define CHP_SMON_ACTIVITYCNTR1_COUNTER1_LOC	0
 
-#define CHP_CFG_LDB_VAS_CRD_COUNT	0x00007FFF
-#define CHP_CFG_LDB_VAS_CRD_RSVD0	0xFFFF8000
-#define CHP_CFG_LDB_VAS_CRD_COUNT_LOC	0
-#define CHP_CFG_LDB_VAS_CRD_RSVD0_LOC	15
+#define CHP_SMON_MAX_TMR 0x4c000018
+#define CHP_SMON_MAX_TMR_RST 0x0
+
+#define CHP_SMON_MAX_TMR_MAXVALUE	0xFFFFFFFF
+#define CHP_SMON_MAX_TMR_MAXVALUE_LOC	0
+
+#define CHP_SMON_TMR 0x4c00001c
+#define CHP_SMON_TMR_RST 0x0
+
+#define CHP_SMON_TMR_TIMER	0xFFFFFFFF
+#define CHP_SMON_TMR_TIMER_LOC	0
+
+#define CHP_CTRL_DIAG_02 0x4c000028
+#define CHP_CTRL_DIAG_02_RST 0x1555
+
+#define CHP_CTRL_DIAG_02_EGRESS_CREDIT_STATUS_EMPTY			0x00000001
+#define CHP_CTRL_DIAG_02_EGRESS_CREDIT_STATUS_AFULL			0x00000002
+#define CHP_CTRL_DIAG_02_CHP_OUTBOUND_HCW_PIPE_CREDIT_STATUS_EMPTY	0x00000004
+#define CHP_CTRL_DIAG_02_CHP_OUTBOUND_HCW_PIPE_CREDIT_STATUS_AFULL	0x00000008
+#define CHP_CTRL_DIAG_02_CHP_LSP_AP_CMP_PIPE_CREDIT_STATUS_EMPTY	0x00000010
+#define CHP_CTRL_DIAG_02_CHP_LSP_AP_CMP_PIPE_CREDIT_STATUS_AFULL	0x00000020
+#define CHP_CTRL_DIAG_02_CHP_LSP_TOK_PIPE_CREDIT_STATUS_EMPTY		0x00000040
+#define CHP_CTRL_DIAG_02_CHP_LSP_TOK_PIPE_CREDIT_STATUS_AFULL		0x00000080
+#define CHP_CTRL_DIAG_02_CHP_ROP_PIPE_CREDIT_STATUS_EMPTY		0x00000100
+#define CHP_CTRL_DIAG_02_CHP_ROP_PIPE_CREDIT_STATUS_AFULL		0x00000200
+#define CHP_CTRL_DIAG_02_QED_TO_CQ_PIPE_CREDIT_STATUS_EMPTY		0x00000400
+#define CHP_CTRL_DIAG_02_QED_TO_CQ_PIPE_CREDIT_STATUS_AFULL		0x00000800
+#define CHP_CTRL_DIAG_02_EGRESS_LSP_TOKEN_CREDIT_STATUS_EMPTY		0x00001000
+#define CHP_CTRL_DIAG_02_EGRESS_LSP_TOKEN_CREDIT_STATUS_AFULL		0x00002000
+#define CHP_CTRL_DIAG_02_RSVD0						0xFFFFC000
+#define CHP_CTRL_DIAG_02_EGRESS_CREDIT_STATUS_EMPTY_LOC			0
+#define CHP_CTRL_DIAG_02_EGRESS_CREDIT_STATUS_AFULL_LOC			1
+#define CHP_CTRL_DIAG_02_CHP_OUTBOUND_HCW_PIPE_CREDIT_STATUS_EMPTY_LOC	2
+#define CHP_CTRL_DIAG_02_CHP_OUTBOUND_HCW_PIPE_CREDIT_STATUS_AFULL_LOC	3
+#define CHP_CTRL_DIAG_02_CHP_LSP_AP_CMP_PIPE_CREDIT_STATUS_EMPTY_LOC	4
+#define CHP_CTRL_DIAG_02_CHP_LSP_AP_CMP_PIPE_CREDIT_STATUS_AFULL_LOC	5
+#define CHP_CTRL_DIAG_02_CHP_LSP_TOK_PIPE_CREDIT_STATUS_EMPTY_LOC	6
+#define CHP_CTRL_DIAG_02_CHP_LSP_TOK_PIPE_CREDIT_STATUS_AFULL_LOC	7
+#define CHP_CTRL_DIAG_02_CHP_ROP_PIPE_CREDIT_STATUS_EMPTY_LOC		8
+#define CHP_CTRL_DIAG_02_CHP_ROP_PIPE_CREDIT_STATUS_AFULL_LOC		9
+#define CHP_CTRL_DIAG_02_QED_TO_CQ_PIPE_CREDIT_STATUS_EMPTY_LOC		10
+#define CHP_CTRL_DIAG_02_QED_TO_CQ_PIPE_CREDIT_STATUS_AFULL_LOC		11
+#define CHP_CTRL_DIAG_02_EGRESS_LSP_TOKEN_CREDIT_STATUS_EMPTY_LOC	12
+#define CHP_CTRL_DIAG_02_EGRESS_LSP_TOKEN_CREDIT_STATUS_AFULL_LOC	13
+#define CHP_CTRL_DIAG_02_RSVD0_LOC					14
+
+#define DP_CFG_ARB_WEIGHTS_TQPRI_DIR_0 0x54000000
+#define DP_CFG_ARB_WEIGHTS_TQPRI_DIR_0_RST 0xfefcfaf8
+
+#define DP_CFG_ARB_WEIGHTS_TQPRI_DIR_0_PRI0	0x000000FF
+#define DP_CFG_ARB_WEIGHTS_TQPRI_DIR_0_PRI1	0x0000FF00
+#define DP_CFG_ARB_WEIGHTS_TQPRI_DIR_0_PRI2	0x00FF0000
+#define DP_CFG_ARB_WEIGHTS_TQPRI_DIR_0_PRI3	0xFF000000
+#define DP_CFG_ARB_WEIGHTS_TQPRI_DIR_0_PRI0_LOC	0
+#define DP_CFG_ARB_WEIGHTS_TQPRI_DIR_0_PRI1_LOC	8
+#define DP_CFG_ARB_WEIGHTS_TQPRI_DIR_0_PRI2_LOC	16
+#define DP_CFG_ARB_WEIGHTS_TQPRI_DIR_0_PRI3_LOC	24
+
+#define DP_CFG_ARB_WEIGHTS_TQPRI_DIR_1 0x54000004
+#define DP_CFG_ARB_WEIGHTS_TQPRI_DIR_1_RST 0x0
+
+#define DP_CFG_ARB_WEIGHTS_TQPRI_DIR_1_RSVZ0	0xFFFFFFFF
+#define DP_CFG_ARB_WEIGHTS_TQPRI_DIR_1_RSVZ0_LOC	0
+
+#define DP_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0 0x54000008
+#define DP_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_RST 0xfefcfaf8
+
+#define DP_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_PRI0	0x000000FF
+#define DP_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_PRI1	0x0000FF00
+#define DP_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_PRI2	0x00FF0000
+#define DP_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_PRI3	0xFF000000
+#define DP_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_PRI0_LOC	0
+#define DP_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_PRI1_LOC	8
+#define DP_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_PRI2_LOC	16
+#define DP_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_PRI3_LOC	24
+
+#define DP_CFG_ARB_WEIGHTS_TQPRI_REPLAY_1 0x5400000c
+#define DP_CFG_ARB_WEIGHTS_TQPRI_REPLAY_1_RST 0x0
+
+#define DP_CFG_ARB_WEIGHTS_TQPRI_REPLAY_1_RSVZ0	0xFFFFFFFF
+#define DP_CFG_ARB_WEIGHTS_TQPRI_REPLAY_1_RSVZ0_LOC	0
+
+#define DP_DIR_CSR_CTRL 0x54000010
+#define DP_DIR_CSR_CTRL_RST 0x0
+
+#define DP_DIR_CSR_CTRL_INT_COR_ALARM_DIS	0x00000001
+#define DP_DIR_CSR_CTRL_INT_COR_SYND_DIS	0x00000002
+#define DP_DIR_CSR_CTRL_INT_UNCR_ALARM_DIS	0x00000004
+#define DP_DIR_CSR_CTRL_INT_UNC_SYND_DIS	0x00000008
+#define DP_DIR_CSR_CTRL_INT_INF0_ALARM_DIS	0x00000010
+#define DP_DIR_CSR_CTRL_INT_INF0_SYND_DIS	0x00000020
+#define DP_DIR_CSR_CTRL_INT_INF1_ALARM_DIS	0x00000040
+#define DP_DIR_CSR_CTRL_INT_INF1_SYND_DIS	0x00000080
+#define DP_DIR_CSR_CTRL_INT_INF2_ALARM_DIS	0x00000100
+#define DP_DIR_CSR_CTRL_INT_INF2_SYND_DIS	0x00000200
+#define DP_DIR_CSR_CTRL_INT_INF3_ALARM_DIS	0x00000400
+#define DP_DIR_CSR_CTRL_INT_INF3_SYND_DIS	0x00000800
+#define DP_DIR_CSR_CTRL_INT_INF4_ALARM_DIS	0x00001000
+#define DP_DIR_CSR_CTRL_INT_INF4_SYND_DIS	0x00002000
+#define DP_DIR_CSR_CTRL_INT_INF5_ALARM_DIS	0x00004000
+#define DP_DIR_CSR_CTRL_INT_INF5_SYND_DIS	0x00008000
+#define DP_DIR_CSR_CTRL_RSVZ0			0xFFFF0000
+#define DP_DIR_CSR_CTRL_INT_COR_ALARM_DIS_LOC	0
+#define DP_DIR_CSR_CTRL_INT_COR_SYND_DIS_LOC	1
+#define DP_DIR_CSR_CTRL_INT_UNCR_ALARM_DIS_LOC	2
+#define DP_DIR_CSR_CTRL_INT_UNC_SYND_DIS_LOC	3
+#define DP_DIR_CSR_CTRL_INT_INF0_ALARM_DIS_LOC	4
+#define DP_DIR_CSR_CTRL_INT_INF0_SYND_DIS_LOC	5
+#define DP_DIR_CSR_CTRL_INT_INF1_ALARM_DIS_LOC	6
+#define DP_DIR_CSR_CTRL_INT_INF1_SYND_DIS_LOC	7
+#define DP_DIR_CSR_CTRL_INT_INF2_ALARM_DIS_LOC	8
+#define DP_DIR_CSR_CTRL_INT_INF2_SYND_DIS_LOC	9
+#define DP_DIR_CSR_CTRL_INT_INF3_ALARM_DIS_LOC	10
+#define DP_DIR_CSR_CTRL_INT_INF3_SYND_DIS_LOC	11
+#define DP_DIR_CSR_CTRL_INT_INF4_ALARM_DIS_LOC	12
+#define DP_DIR_CSR_CTRL_INT_INF4_SYND_DIS_LOC	13
+#define DP_DIR_CSR_CTRL_INT_INF5_ALARM_DIS_LOC	14
+#define DP_DIR_CSR_CTRL_INT_INF5_SYND_DIS_LOC	15
+#define DP_DIR_CSR_CTRL_RSVZ0_LOC		16
+
+#define DP_SMON_ACTIVITYCNTR0 0x5c000058
+#define DP_SMON_ACTIVITYCNTR0_RST 0x0
+
+#define DP_SMON_ACTIVITYCNTR0_COUNTER0	0xFFFFFFFF
+#define DP_SMON_ACTIVITYCNTR0_COUNTER0_LOC	0
+
+#define DP_SMON_ACTIVITYCNTR1 0x5c00005c
+#define DP_SMON_ACTIVITYCNTR1_RST 0x0
+
+#define DP_SMON_ACTIVITYCNTR1_COUNTER1	0xFFFFFFFF
+#define DP_SMON_ACTIVITYCNTR1_COUNTER1_LOC	0
+
+#define DP_SMON_COMPARE0 0x5c000060
+#define DP_SMON_COMPARE0_RST 0x0
+
+#define DP_SMON_COMPARE0_COMPARE0	0xFFFFFFFF
+#define DP_SMON_COMPARE0_COMPARE0_LOC	0
+
+#define DP_SMON_COMPARE1 0x5c000064
+#define DP_SMON_COMPARE1_RST 0x0
+
+#define DP_SMON_COMPARE1_COMPARE1	0xFFFFFFFF
+#define DP_SMON_COMPARE1_COMPARE1_LOC	0
+
+#define DP_SMON_CFG0 0x5c000068
+#define DP_SMON_CFG0_RST 0x40000000
+
+#define DP_SMON_CFG0_SMON_ENABLE		0x00000001
+#define DP_SMON_CFG0_SMON_0TRIGGER_ENABLE	0x00000002
+#define DP_SMON_CFG0_RSVZ0			0x0000000C
+#define DP_SMON_CFG0_SMON0_FUNCTION		0x00000070
+#define DP_SMON_CFG0_SMON0_FUNCTION_COMPARE	0x00000080
+#define DP_SMON_CFG0_SMON1_FUNCTION		0x00000700
+#define DP_SMON_CFG0_SMON1_FUNCTION_COMPARE	0x00000800
+#define DP_SMON_CFG0_SMON_MODE			0x0000F000
+#define DP_SMON_CFG0_STOPCOUNTEROVFL		0x00010000
+#define DP_SMON_CFG0_INTCOUNTEROVFL		0x00020000
+#define DP_SMON_CFG0_STATCOUNTER0OVFL		0x00040000
+#define DP_SMON_CFG0_STATCOUNTER1OVFL		0x00080000
+#define DP_SMON_CFG0_STOPTIMEROVFL		0x00100000
+#define DP_SMON_CFG0_INTTIMEROVFL		0x00200000
+#define DP_SMON_CFG0_STATTIMEROVFL		0x00400000
+#define DP_SMON_CFG0_RSVZ1			0x00800000
+#define DP_SMON_CFG0_TIMER_PRESCALE		0x1F000000
+#define DP_SMON_CFG0_RSVZ2			0x20000000
+#define DP_SMON_CFG0_VERSION			0xC0000000
+#define DP_SMON_CFG0_SMON_ENABLE_LOC		0
+#define DP_SMON_CFG0_SMON_0TRIGGER_ENABLE_LOC	1
+#define DP_SMON_CFG0_RSVZ0_LOC			2
+#define DP_SMON_CFG0_SMON0_FUNCTION_LOC		4
+#define DP_SMON_CFG0_SMON0_FUNCTION_COMPARE_LOC	7
+#define DP_SMON_CFG0_SMON1_FUNCTION_LOC		8
+#define DP_SMON_CFG0_SMON1_FUNCTION_COMPARE_LOC	11
+#define DP_SMON_CFG0_SMON_MODE_LOC		12
+#define DP_SMON_CFG0_STOPCOUNTEROVFL_LOC	16
+#define DP_SMON_CFG0_INTCOUNTEROVFL_LOC		17
+#define DP_SMON_CFG0_STATCOUNTER0OVFL_LOC	18
+#define DP_SMON_CFG0_STATCOUNTER1OVFL_LOC	19
+#define DP_SMON_CFG0_STOPTIMEROVFL_LOC		20
+#define DP_SMON_CFG0_INTTIMEROVFL_LOC		21
+#define DP_SMON_CFG0_STATTIMEROVFL_LOC		22
+#define DP_SMON_CFG0_RSVZ1_LOC			23
+#define DP_SMON_CFG0_TIMER_PRESCALE_LOC		24
+#define DP_SMON_CFG0_RSVZ2_LOC			29
+#define DP_SMON_CFG0_VERSION_LOC		30
+
+#define DP_SMON_CFG1 0x5c00006c
+#define DP_SMON_CFG1_RST 0x0
+
+#define DP_SMON_CFG1_MODE0	0x000000FF
+#define DP_SMON_CFG1_MODE1	0x0000FF00
+#define DP_SMON_CFG1_RSVZ0	0xFFFF0000
+#define DP_SMON_CFG1_MODE0_LOC	0
+#define DP_SMON_CFG1_MODE1_LOC	8
+#define DP_SMON_CFG1_RSVZ0_LOC	16
+
+#define DP_SMON_MAX_TMR 0x5c000070
+#define DP_SMON_MAX_TMR_RST 0x0
+
+#define DP_SMON_MAX_TMR_MAXVALUE	0xFFFFFFFF
+#define DP_SMON_MAX_TMR_MAXVALUE_LOC	0
+
+#define DP_SMON_TMR 0x5c000074
+#define DP_SMON_TMR_RST 0x0
+
+#define DP_SMON_TMR_TIMER	0xFFFFFFFF
+#define DP_SMON_TMR_TIMER_LOC	0
+
+#define DQED_SMON_ACTIVITYCNTR0 0x6c000024
+#define DQED_SMON_ACTIVITYCNTR0_RST 0x0
+
+#define DQED_SMON_ACTIVITYCNTR0_COUNTER0	0xFFFFFFFF
+#define DQED_SMON_ACTIVITYCNTR0_COUNTER0_LOC	0
+
+#define DQED_SMON_ACTIVITYCNTR1 0x6c000028
+#define DQED_SMON_ACTIVITYCNTR1_RST 0x0
+
+#define DQED_SMON_ACTIVITYCNTR1_COUNTER1	0xFFFFFFFF
+#define DQED_SMON_ACTIVITYCNTR1_COUNTER1_LOC	0
+
+#define DQED_SMON_COMPARE0 0x6c00002c
+#define DQED_SMON_COMPARE0_RST 0x0
+
+#define DQED_SMON_COMPARE0_COMPARE0	0xFFFFFFFF
+#define DQED_SMON_COMPARE0_COMPARE0_LOC	0
+
+#define DQED_SMON_COMPARE1 0x6c000030
+#define DQED_SMON_COMPARE1_RST 0x0
+
+#define DQED_SMON_COMPARE1_COMPARE1	0xFFFFFFFF
+#define DQED_SMON_COMPARE1_COMPARE1_LOC	0
+
+#define DQED_SMON_CFG0 0x6c000034
+#define DQED_SMON_CFG0_RST 0x40000000
+
+#define DQED_SMON_CFG0_SMON_ENABLE		0x00000001
+#define DQED_SMON_CFG0_SMON_0TRIGGER_ENABLE	0x00000002
+#define DQED_SMON_CFG0_RSVZ0			0x0000000C
+#define DQED_SMON_CFG0_SMON0_FUNCTION		0x00000070
+#define DQED_SMON_CFG0_SMON0_FUNCTION_COMPARE	0x00000080
+#define DQED_SMON_CFG0_SMON1_FUNCTION		0x00000700
+#define DQED_SMON_CFG0_SMON1_FUNCTION_COMPARE	0x00000800
+#define DQED_SMON_CFG0_SMON_MODE		0x0000F000
+#define DQED_SMON_CFG0_STOPCOUNTEROVFL		0x00010000
+#define DQED_SMON_CFG0_INTCOUNTEROVFL		0x00020000
+#define DQED_SMON_CFG0_STATCOUNTER0OVFL		0x00040000
+#define DQED_SMON_CFG0_STATCOUNTER1OVFL		0x00080000
+#define DQED_SMON_CFG0_STOPTIMEROVFL		0x00100000
+#define DQED_SMON_CFG0_INTTIMEROVFL		0x00200000
+#define DQED_SMON_CFG0_STATTIMEROVFL		0x00400000
+#define DQED_SMON_CFG0_RSVZ1			0x00800000
+#define DQED_SMON_CFG0_TIMER_PRESCALE		0x1F000000
+#define DQED_SMON_CFG0_RSVZ2			0x20000000
+#define DQED_SMON_CFG0_VERSION			0xC0000000
+#define DQED_SMON_CFG0_SMON_ENABLE_LOC			0
+#define DQED_SMON_CFG0_SMON_0TRIGGER_ENABLE_LOC		1
+#define DQED_SMON_CFG0_RSVZ0_LOC			2
+#define DQED_SMON_CFG0_SMON0_FUNCTION_LOC		4
+#define DQED_SMON_CFG0_SMON0_FUNCTION_COMPARE_LOC	7
+#define DQED_SMON_CFG0_SMON1_FUNCTION_LOC		8
+#define DQED_SMON_CFG0_SMON1_FUNCTION_COMPARE_LOC	11
+#define DQED_SMON_CFG0_SMON_MODE_LOC			12
+#define DQED_SMON_CFG0_STOPCOUNTEROVFL_LOC		16
+#define DQED_SMON_CFG0_INTCOUNTEROVFL_LOC		17
+#define DQED_SMON_CFG0_STATCOUNTER0OVFL_LOC		18
+#define DQED_SMON_CFG0_STATCOUNTER1OVFL_LOC		19
+#define DQED_SMON_CFG0_STOPTIMEROVFL_LOC		20
+#define DQED_SMON_CFG0_INTTIMEROVFL_LOC			21
+#define DQED_SMON_CFG0_STATTIMEROVFL_LOC		22
+#define DQED_SMON_CFG0_RSVZ1_LOC			23
+#define DQED_SMON_CFG0_TIMER_PRESCALE_LOC		24
+#define DQED_SMON_CFG0_RSVZ2_LOC			29
+#define DQED_SMON_CFG0_VERSION_LOC			30
+
+#define DQED_SMON_CFG1 0x6c000038
+#define DQED_SMON_CFG1_RST 0x0
+
+#define DQED_SMON_CFG1_MODE0	0x000000FF
+#define DQED_SMON_CFG1_MODE1	0x0000FF00
+#define DQED_SMON_CFG1_RSVZ0	0xFFFF0000
+#define DQED_SMON_CFG1_MODE0_LOC	0
+#define DQED_SMON_CFG1_MODE1_LOC	8
+#define DQED_SMON_CFG1_RSVZ0_LOC	16
+
+#define DQED_SMON_MAX_TMR 0x6c00003c
+#define DQED_SMON_MAX_TMR_RST 0x0
+
+#define DQED_SMON_MAX_TMR_MAXVALUE	0xFFFFFFFF
+#define DQED_SMON_MAX_TMR_MAXVALUE_LOC	0
+
+#define DQED_SMON_TMR 0x6c000040
+#define DQED_SMON_TMR_RST 0x0
+
+#define DQED_SMON_TMR_TIMER	0xFFFFFFFF
+#define DQED_SMON_TMR_TIMER_LOC	0
+
+#define QED_SMON_ACTIVITYCNTR0 0x7c000024
+#define QED_SMON_ACTIVITYCNTR0_RST 0x0
+
+#define QED_SMON_ACTIVITYCNTR0_COUNTER0	0xFFFFFFFF
+#define QED_SMON_ACTIVITYCNTR0_COUNTER0_LOC	0
+
+#define QED_SMON_ACTIVITYCNTR1 0x7c000028
+#define QED_SMON_ACTIVITYCNTR1_RST 0x0
+
+#define QED_SMON_ACTIVITYCNTR1_COUNTER1	0xFFFFFFFF
+#define QED_SMON_ACTIVITYCNTR1_COUNTER1_LOC	0
+
+#define QED_SMON_COMPARE0 0x7c00002c
+#define QED_SMON_COMPARE0_RST 0x0
+
+#define QED_SMON_COMPARE0_COMPARE0	0xFFFFFFFF
+#define QED_SMON_COMPARE0_COMPARE0_LOC	0
+
+#define QED_SMON_COMPARE1 0x7c000030
+#define QED_SMON_COMPARE1_RST 0x0
+
+#define QED_SMON_COMPARE1_COMPARE1	0xFFFFFFFF
+#define QED_SMON_COMPARE1_COMPARE1_LOC	0
+
+#define QED_SMON_CFG0 0x7c000034
+#define QED_SMON_CFG0_RST 0x40000000
+
+#define QED_SMON_CFG0_SMON_ENABLE		0x00000001
+#define QED_SMON_CFG0_SMON_0TRIGGER_ENABLE	0x00000002
+#define QED_SMON_CFG0_RSVZ0			0x0000000C
+#define QED_SMON_CFG0_SMON0_FUNCTION		0x00000070
+#define QED_SMON_CFG0_SMON0_FUNCTION_COMPARE	0x00000080
+#define QED_SMON_CFG0_SMON1_FUNCTION		0x00000700
+#define QED_SMON_CFG0_SMON1_FUNCTION_COMPARE	0x00000800
+#define QED_SMON_CFG0_SMON_MODE			0x0000F000
+#define QED_SMON_CFG0_STOPCOUNTEROVFL		0x00010000
+#define QED_SMON_CFG0_INTCOUNTEROVFL		0x00020000
+#define QED_SMON_CFG0_STATCOUNTER0OVFL		0x00040000
+#define QED_SMON_CFG0_STATCOUNTER1OVFL		0x00080000
+#define QED_SMON_CFG0_STOPTIMEROVFL		0x00100000
+#define QED_SMON_CFG0_INTTIMEROVFL		0x00200000
+#define QED_SMON_CFG0_STATTIMEROVFL		0x00400000
+#define QED_SMON_CFG0_RSVZ1			0x00800000
+#define QED_SMON_CFG0_TIMER_PRESCALE		0x1F000000
+#define QED_SMON_CFG0_RSVZ2			0x20000000
+#define QED_SMON_CFG0_VERSION			0xC0000000
+#define QED_SMON_CFG0_SMON_ENABLE_LOC			0
+#define QED_SMON_CFG0_SMON_0TRIGGER_ENABLE_LOC		1
+#define QED_SMON_CFG0_RSVZ0_LOC				2
+#define QED_SMON_CFG0_SMON0_FUNCTION_LOC		4
+#define QED_SMON_CFG0_SMON0_FUNCTION_COMPARE_LOC	7
+#define QED_SMON_CFG0_SMON1_FUNCTION_LOC		8
+#define QED_SMON_CFG0_SMON1_FUNCTION_COMPARE_LOC	11
+#define QED_SMON_CFG0_SMON_MODE_LOC			12
+#define QED_SMON_CFG0_STOPCOUNTEROVFL_LOC		16
+#define QED_SMON_CFG0_INTCOUNTEROVFL_LOC		17
+#define QED_SMON_CFG0_STATCOUNTER0OVFL_LOC		18
+#define QED_SMON_CFG0_STATCOUNTER1OVFL_LOC		19
+#define QED_SMON_CFG0_STOPTIMEROVFL_LOC			20
+#define QED_SMON_CFG0_INTTIMEROVFL_LOC			21
+#define QED_SMON_CFG0_STATTIMEROVFL_LOC			22
+#define QED_SMON_CFG0_RSVZ1_LOC				23
+#define QED_SMON_CFG0_TIMER_PRESCALE_LOC		24
+#define QED_SMON_CFG0_RSVZ2_LOC				29
+#define QED_SMON_CFG0_VERSION_LOC			30
+
+#define QED_SMON_CFG1 0x7c000038
+#define QED_SMON_CFG1_RST 0x0
+
+#define QED_SMON_CFG1_MODE0	0x000000FF
+#define QED_SMON_CFG1_MODE1	0x0000FF00
+#define QED_SMON_CFG1_RSVZ0	0xFFFF0000
+#define QED_SMON_CFG1_MODE0_LOC	0
+#define QED_SMON_CFG1_MODE1_LOC	8
+#define QED_SMON_CFG1_RSVZ0_LOC	16
+
+#define QED_SMON_MAX_TMR 0x7c00003c
+#define QED_SMON_MAX_TMR_RST 0x0
+
+#define QED_SMON_MAX_TMR_MAXVALUE	0xFFFFFFFF
+#define QED_SMON_MAX_TMR_MAXVALUE_LOC	0
+
+#define QED_SMON_TMR 0x7c000040
+#define QED_SMON_TMR_RST 0x0
+
+#define QED_SMON_TMR_TIMER	0xFFFFFFFF
+#define QED_SMON_TMR_TIMER_LOC	0
+
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_ATQ_0 0x84000000
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_ATQ_0_RST 0xfefcfaf8
+
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_ATQ_0_PRI0	0x000000FF
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_ATQ_0_PRI1	0x0000FF00
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_ATQ_0_PRI2	0x00FF0000
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_ATQ_0_PRI3	0xFF000000
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_ATQ_0_PRI0_LOC	0
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_ATQ_0_PRI1_LOC	8
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_ATQ_0_PRI2_LOC	16
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_ATQ_0_PRI3_LOC	24
+
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_ATQ_1 0x84000004
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_ATQ_1_RST 0x0
+
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_ATQ_1_RSVZ0	0xFFFFFFFF
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_ATQ_1_RSVZ0_LOC	0
+
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_NALB_0 0x84000008
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_NALB_0_RST 0xfefcfaf8
+
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_NALB_0_PRI0	0x000000FF
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_NALB_0_PRI1	0x0000FF00
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_NALB_0_PRI2	0x00FF0000
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_NALB_0_PRI3	0xFF000000
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_NALB_0_PRI0_LOC	0
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_NALB_0_PRI1_LOC	8
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_NALB_0_PRI2_LOC	16
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_NALB_0_PRI3_LOC	24
+
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_NALB_1 0x8400000c
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_NALB_1_RST 0x0
+
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_NALB_1_RSVZ0	0xFFFFFFFF
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_NALB_1_RSVZ0_LOC	0
+
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0 0x84000010
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_RST 0xfefcfaf8
+
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_PRI0	0x000000FF
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_PRI1	0x0000FF00
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_PRI2	0x00FF0000
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_PRI3	0xFF000000
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_PRI0_LOC	0
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_PRI1_LOC	8
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_PRI2_LOC	16
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_REPLAY_0_PRI3_LOC	24
+
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_REPLAY_1 0x84000014
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_REPLAY_1_RST 0x0
+
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_REPLAY_1_RSVZ0	0xFFFFFFFF
+#define NALB_CFG_ARB_WEIGHTS_TQPRI_REPLAY_1_RSVZ0_LOC	0
+
+#define NALB_SMON_ACTIVITYCNTR0 0x8c000064
+#define NALB_SMON_ACTIVITYCNTR0_RST 0x0
+
+#define NALB_SMON_ACTIVITYCNTR0_COUNTER0	0xFFFFFFFF
+#define NALB_SMON_ACTIVITYCNTR0_COUNTER0_LOC	0
+
+#define NALB_SMON_ACTIVITYCNTR1 0x8c000068
+#define NALB_SMON_ACTIVITYCNTR1_RST 0x0
+
+#define NALB_SMON_ACTIVITYCNTR1_COUNTER1	0xFFFFFFFF
+#define NALB_SMON_ACTIVITYCNTR1_COUNTER1_LOC	0
+
+#define NALB_SMON_COMPARE0 0x8c00006c
+#define NALB_SMON_COMPARE0_RST 0x0
+
+#define NALB_SMON_COMPARE0_COMPARE0	0xFFFFFFFF
+#define NALB_SMON_COMPARE0_COMPARE0_LOC	0
+
+#define NALB_SMON_COMPARE1 0x8c000070
+#define NALB_SMON_COMPARE1_RST 0x0
+
+#define NALB_SMON_COMPARE1_COMPARE1	0xFFFFFFFF
+#define NALB_SMON_COMPARE1_COMPARE1_LOC	0
+
+#define NALB_SMON_CFG0 0x8c000074
+#define NALB_SMON_CFG0_RST 0x40000000
+
+#define NALB_SMON_CFG0_SMON_ENABLE		0x00000001
+#define NALB_SMON_CFG0_SMON_0TRIGGER_ENABLE	0x00000002
+#define NALB_SMON_CFG0_RSVZ0			0x0000000C
+#define NALB_SMON_CFG0_SMON0_FUNCTION		0x00000070
+#define NALB_SMON_CFG0_SMON0_FUNCTION_COMPARE	0x00000080
+#define NALB_SMON_CFG0_SMON1_FUNCTION		0x00000700
+#define NALB_SMON_CFG0_SMON1_FUNCTION_COMPARE	0x00000800
+#define NALB_SMON_CFG0_SMON_MODE		0x0000F000
+#define NALB_SMON_CFG0_STOPCOUNTEROVFL		0x00010000
+#define NALB_SMON_CFG0_INTCOUNTEROVFL		0x00020000
+#define NALB_SMON_CFG0_STATCOUNTER0OVFL		0x00040000
+#define NALB_SMON_CFG0_STATCOUNTER1OVFL		0x00080000
+#define NALB_SMON_CFG0_STOPTIMEROVFL		0x00100000
+#define NALB_SMON_CFG0_INTTIMEROVFL		0x00200000
+#define NALB_SMON_CFG0_STATTIMEROVFL		0x00400000
+#define NALB_SMON_CFG0_RSVZ1			0x00800000
+#define NALB_SMON_CFG0_TIMER_PRESCALE		0x1F000000
+#define NALB_SMON_CFG0_RSVZ2			0x20000000
+#define NALB_SMON_CFG0_VERSION			0xC0000000
+#define NALB_SMON_CFG0_SMON_ENABLE_LOC			0
+#define NALB_SMON_CFG0_SMON_0TRIGGER_ENABLE_LOC		1
+#define NALB_SMON_CFG0_RSVZ0_LOC			2
+#define NALB_SMON_CFG0_SMON0_FUNCTION_LOC		4
+#define NALB_SMON_CFG0_SMON0_FUNCTION_COMPARE_LOC	7
+#define NALB_SMON_CFG0_SMON1_FUNCTION_LOC		8
+#define NALB_SMON_CFG0_SMON1_FUNCTION_COMPARE_LOC	11
+#define NALB_SMON_CFG0_SMON_MODE_LOC			12
+#define NALB_SMON_CFG0_STOPCOUNTEROVFL_LOC		16
+#define NALB_SMON_CFG0_INTCOUNTEROVFL_LOC		17
+#define NALB_SMON_CFG0_STATCOUNTER0OVFL_LOC		18
+#define NALB_SMON_CFG0_STATCOUNTER1OVFL_LOC		19
+#define NALB_SMON_CFG0_STOPTIMEROVFL_LOC		20
+#define NALB_SMON_CFG0_INTTIMEROVFL_LOC			21
+#define NALB_SMON_CFG0_STATTIMEROVFL_LOC		22
+#define NALB_SMON_CFG0_RSVZ1_LOC			23
+#define NALB_SMON_CFG0_TIMER_PRESCALE_LOC		24
+#define NALB_SMON_CFG0_RSVZ2_LOC			29
+#define NALB_SMON_CFG0_VERSION_LOC			30
+
+#define NALB_SMON_CFG1 0x8c000078
+#define NALB_SMON_CFG1_RST 0x0
+
+#define NALB_SMON_CFG1_MODE0	0x000000FF
+#define NALB_SMON_CFG1_MODE1	0x0000FF00
+#define NALB_SMON_CFG1_RSVZ0	0xFFFF0000
+#define NALB_SMON_CFG1_MODE0_LOC	0
+#define NALB_SMON_CFG1_MODE1_LOC	8
+#define NALB_SMON_CFG1_RSVZ0_LOC	16
+
+#define NALB_SMON_MAX_TMR 0x8c00007c
+#define NALB_SMON_MAX_TMR_RST 0x0
+
+#define NALB_SMON_MAX_TMR_MAXVALUE	0xFFFFFFFF
+#define NALB_SMON_MAX_TMR_MAXVALUE_LOC	0
+
+#define NALB_SMON_TMR 0x8c000080
+#define NALB_SMON_TMR_RST 0x0
+
+#define NALB_SMON_TMR_TIMER	0xFFFFFFFF
+#define NALB_SMON_TMR_TIMER_LOC	0
+
+#define RO_GRP_0_SLT_SHFT(x) \
+	(0x96000000 + (x) * 0x4)
+#define RO_GRP_0_SLT_SHFT_RST 0x0
+
+#define RO_GRP_0_SLT_SHFT_CHANGE	0x000003FF
+#define RO_GRP_0_SLT_SHFT_RSVD0		0xFFFFFC00
+#define RO_GRP_0_SLT_SHFT_CHANGE_LOC	0
+#define RO_GRP_0_SLT_SHFT_RSVD0_LOC	10
+
+#define RO_GRP_1_SLT_SHFT(x) \
+	(0x96010000 + (x) * 0x4)
+#define RO_GRP_1_SLT_SHFT_RST 0x0
+
+#define RO_GRP_1_SLT_SHFT_CHANGE	0x000003FF
+#define RO_GRP_1_SLT_SHFT_RSVD0		0xFFFFFC00
+#define RO_GRP_1_SLT_SHFT_CHANGE_LOC	0
+#define RO_GRP_1_SLT_SHFT_RSVD0_LOC	10
+
+#define RO_GRP_SN_MODE 0x94000000
+#define RO_GRP_SN_MODE_RST 0x0
+
+#define RO_GRP_SN_MODE_SN_MODE_0	0x00000007
+#define RO_GRP_SN_MODE_RSZV0		0x000000F8
+#define RO_GRP_SN_MODE_SN_MODE_1	0x00000700
+#define RO_GRP_SN_MODE_RSZV1		0xFFFFF800
+#define RO_GRP_SN_MODE_SN_MODE_0_LOC	0
+#define RO_GRP_SN_MODE_RSZV0_LOC	3
+#define RO_GRP_SN_MODE_SN_MODE_1_LOC	8
+#define RO_GRP_SN_MODE_RSZV1_LOC	11
+
+#define RO_CFG_CTRL_GENERAL_0 0x9c000000
+#define RO_CFG_CTRL_GENERAL_0_RST 0x0
+
+#define RO_CFG_CTRL_GENERAL_0_UNIT_SINGLE_STEP_MODE	0x00000001
+#define RO_CFG_CTRL_GENERAL_0_RR_EN			0x00000002
+#define RO_CFG_CTRL_GENERAL_0_RSZV0			0xFFFFFFFC
+#define RO_CFG_CTRL_GENERAL_0_UNIT_SINGLE_STEP_MODE_LOC	0
+#define RO_CFG_CTRL_GENERAL_0_RR_EN_LOC			1
+#define RO_CFG_CTRL_GENERAL_0_RSZV0_LOC			2
+
+#define RO_SMON_ACTIVITYCNTR0 0x9c000030
+#define RO_SMON_ACTIVITYCNTR0_RST 0x0
+
+#define RO_SMON_ACTIVITYCNTR0_COUNTER0	0xFFFFFFFF
+#define RO_SMON_ACTIVITYCNTR0_COUNTER0_LOC	0
+
+#define RO_SMON_ACTIVITYCNTR1 0x9c000034
+#define RO_SMON_ACTIVITYCNTR1_RST 0x0
+
+#define RO_SMON_ACTIVITYCNTR1_COUNTER1	0xFFFFFFFF
+#define RO_SMON_ACTIVITYCNTR1_COUNTER1_LOC	0
+
+#define RO_SMON_COMPARE0 0x9c000038
+#define RO_SMON_COMPARE0_RST 0x0
+
+#define RO_SMON_COMPARE0_COMPARE0	0xFFFFFFFF
+#define RO_SMON_COMPARE0_COMPARE0_LOC	0
+
+#define RO_SMON_COMPARE1 0x9c00003c
+#define RO_SMON_COMPARE1_RST 0x0
+
+#define RO_SMON_COMPARE1_COMPARE1	0xFFFFFFFF
+#define RO_SMON_COMPARE1_COMPARE1_LOC	0
+
+#define RO_SMON_CFG0 0x9c000040
+#define RO_SMON_CFG0_RST 0x40000000
+
+#define RO_SMON_CFG0_SMON_ENABLE		0x00000001
+#define RO_SMON_CFG0_SMON_0TRIGGER_ENABLE	0x00000002
+#define RO_SMON_CFG0_RSVZ0			0x0000000C
+#define RO_SMON_CFG0_SMON0_FUNCTION		0x00000070
+#define RO_SMON_CFG0_SMON0_FUNCTION_COMPARE	0x00000080
+#define RO_SMON_CFG0_SMON1_FUNCTION		0x00000700
+#define RO_SMON_CFG0_SMON1_FUNCTION_COMPARE	0x00000800
+#define RO_SMON_CFG0_SMON_MODE			0x0000F000
+#define RO_SMON_CFG0_STOPCOUNTEROVFL		0x00010000
+#define RO_SMON_CFG0_INTCOUNTEROVFL		0x00020000
+#define RO_SMON_CFG0_STATCOUNTER0OVFL		0x00040000
+#define RO_SMON_CFG0_STATCOUNTER1OVFL		0x00080000
+#define RO_SMON_CFG0_STOPTIMEROVFL		0x00100000
+#define RO_SMON_CFG0_INTTIMEROVFL		0x00200000
+#define RO_SMON_CFG0_STATTIMEROVFL		0x00400000
+#define RO_SMON_CFG0_RSVZ1			0x00800000
+#define RO_SMON_CFG0_TIMER_PRESCALE		0x1F000000
+#define RO_SMON_CFG0_RSVZ2			0x20000000
+#define RO_SMON_CFG0_VERSION			0xC0000000
+#define RO_SMON_CFG0_SMON_ENABLE_LOC		0
+#define RO_SMON_CFG0_SMON_0TRIGGER_ENABLE_LOC	1
+#define RO_SMON_CFG0_RSVZ0_LOC			2
+#define RO_SMON_CFG0_SMON0_FUNCTION_LOC		4
+#define RO_SMON_CFG0_SMON0_FUNCTION_COMPARE_LOC	7
+#define RO_SMON_CFG0_SMON1_FUNCTION_LOC		8
+#define RO_SMON_CFG0_SMON1_FUNCTION_COMPARE_LOC	11
+#define RO_SMON_CFG0_SMON_MODE_LOC		12
+#define RO_SMON_CFG0_STOPCOUNTEROVFL_LOC	16
+#define RO_SMON_CFG0_INTCOUNTEROVFL_LOC		17
+#define RO_SMON_CFG0_STATCOUNTER0OVFL_LOC	18
+#define RO_SMON_CFG0_STATCOUNTER1OVFL_LOC	19
+#define RO_SMON_CFG0_STOPTIMEROVFL_LOC		20
+#define RO_SMON_CFG0_INTTIMEROVFL_LOC		21
+#define RO_SMON_CFG0_STATTIMEROVFL_LOC		22
+#define RO_SMON_CFG0_RSVZ1_LOC			23
+#define RO_SMON_CFG0_TIMER_PRESCALE_LOC		24
+#define RO_SMON_CFG0_RSVZ2_LOC			29
+#define RO_SMON_CFG0_VERSION_LOC		30
+
+#define RO_SMON_CFG1 0x9c000044
+#define RO_SMON_CFG1_RST 0x0
+
+#define RO_SMON_CFG1_MODE0	0x000000FF
+#define RO_SMON_CFG1_MODE1	0x0000FF00
+#define RO_SMON_CFG1_RSVZ0	0xFFFF0000
+#define RO_SMON_CFG1_MODE0_LOC	0
+#define RO_SMON_CFG1_MODE1_LOC	8
+#define RO_SMON_CFG1_RSVZ0_LOC	16
+
+#define RO_SMON_MAX_TMR 0x9c000048
+#define RO_SMON_MAX_TMR_RST 0x0
+
+#define RO_SMON_MAX_TMR_MAXVALUE	0xFFFFFFFF
+#define RO_SMON_MAX_TMR_MAXVALUE_LOC	0
+
+#define RO_SMON_TMR 0x9c00004c
+#define RO_SMON_TMR_RST 0x0
+
+#define RO_SMON_TMR_TIMER	0xFFFFFFFF
+#define RO_SMON_TMR_TIMER_LOC	0
+
+#define LSP_CQ2PRIOV(x) \
+	(0xa0000000 + (x) * 0x1000)
+#define LSP_CQ2PRIOV_RST 0x0
+
+#define LSP_CQ2PRIOV_PRIO	0x00FFFFFF
+#define LSP_CQ2PRIOV_V		0xFF000000
+#define LSP_CQ2PRIOV_PRIO_LOC	0
+#define LSP_CQ2PRIOV_V_LOC	24
+
+#define LSP_CQ2QID0(x) \
+	(0xa0080000 + (x) * 0x1000)
+#define LSP_CQ2QID0_RST 0x0
+
+#define LSP_CQ2QID0_QID_P0	0x0000007F
+#define LSP_CQ2QID0_RSVD3	0x00000080
+#define LSP_CQ2QID0_QID_P1	0x00007F00
+#define LSP_CQ2QID0_RSVD2	0x00008000
+#define LSP_CQ2QID0_QID_P2	0x007F0000
+#define LSP_CQ2QID0_RSVD1	0x00800000
+#define LSP_CQ2QID0_QID_P3	0x7F000000
+#define LSP_CQ2QID0_RSVD0	0x80000000
+#define LSP_CQ2QID0_QID_P0_LOC	0
+#define LSP_CQ2QID0_RSVD3_LOC	7
+#define LSP_CQ2QID0_QID_P1_LOC	8
+#define LSP_CQ2QID0_RSVD2_LOC	15
+#define LSP_CQ2QID0_QID_P2_LOC	16
+#define LSP_CQ2QID0_RSVD1_LOC	23
+#define LSP_CQ2QID0_QID_P3_LOC	24
+#define LSP_CQ2QID0_RSVD0_LOC	31
+
+#define LSP_CQ2QID1(x) \
+	(0xa0100000 + (x) * 0x1000)
+#define LSP_CQ2QID1_RST 0x0
+
+#define LSP_CQ2QID1_QID_P4	0x0000007F
+#define LSP_CQ2QID1_RSVD3	0x00000080
+#define LSP_CQ2QID1_QID_P5	0x00007F00
+#define LSP_CQ2QID1_RSVD2	0x00008000
+#define LSP_CQ2QID1_QID_P6	0x007F0000
+#define LSP_CQ2QID1_RSVD1	0x00800000
+#define LSP_CQ2QID1_QID_P7	0x7F000000
+#define LSP_CQ2QID1_RSVD0	0x80000000
+#define LSP_CQ2QID1_QID_P4_LOC	0
+#define LSP_CQ2QID1_RSVD3_LOC	7
+#define LSP_CQ2QID1_QID_P5_LOC	8
+#define LSP_CQ2QID1_RSVD2_LOC	15
+#define LSP_CQ2QID1_QID_P6_LOC	16
+#define LSP_CQ2QID1_RSVD1_LOC	23
+#define LSP_CQ2QID1_QID_P7_LOC	24
+#define LSP_CQ2QID1_RSVD0_LOC	31
+
+#define LSP_CQ_DIR_DSBL(x) \
+	(0xa0180000 + (x) * 0x1000)
+#define LSP_CQ_DIR_DSBL_RST 0x1
+
+#define LSP_CQ_DIR_DSBL_DISABLED	0x00000001
+#define LSP_CQ_DIR_DSBL_RSVD0		0xFFFFFFFE
+#define LSP_CQ_DIR_DSBL_DISABLED_LOC	0
+#define LSP_CQ_DIR_DSBL_RSVD0_LOC	1
+
+#define LSP_CQ_DIR_TKN_CNT(x) \
+	(0xa0200000 + (x) * 0x1000)
+#define LSP_CQ_DIR_TKN_CNT_RST 0x0
+
+#define LSP_CQ_DIR_TKN_CNT_COUNT	0x00001FFF
+#define LSP_CQ_DIR_TKN_CNT_RSVD0	0xFFFFE000
+#define LSP_CQ_DIR_TKN_CNT_COUNT_LOC	0
+#define LSP_CQ_DIR_TKN_CNT_RSVD0_LOC	13
+
+#define LSP_CQ_DIR_TKN_DEPTH_SEL_DSI(x) \
+	(0xa0280000 + (x) * 0x1000)
+#define LSP_CQ_DIR_TKN_DEPTH_SEL_DSI_RST 0x0
+
+#define LSP_CQ_DIR_TKN_DEPTH_SEL_DSI_TOKEN_DEPTH_SELECT	0x0000000F
+#define LSP_CQ_DIR_TKN_DEPTH_SEL_DSI_DISABLE_WB_OPT	0x00000010
+#define LSP_CQ_DIR_TKN_DEPTH_SEL_DSI_IGNORE_DEPTH	0x00000020
+#define LSP_CQ_DIR_TKN_DEPTH_SEL_DSI_RSVD0		0xFFFFFFC0
+#define LSP_CQ_DIR_TKN_DEPTH_SEL_DSI_TOKEN_DEPTH_SELECT_LOC	0
+#define LSP_CQ_DIR_TKN_DEPTH_SEL_DSI_DISABLE_WB_OPT_LOC		4
+#define LSP_CQ_DIR_TKN_DEPTH_SEL_DSI_IGNORE_DEPTH_LOC		5
+#define LSP_CQ_DIR_TKN_DEPTH_SEL_DSI_RSVD0_LOC			6
+
+#define LSP_CQ_DIR_TOT_SCH_CNTL(x) \
+	(0xa0300000 + (x) * 0x1000)
+#define LSP_CQ_DIR_TOT_SCH_CNTL_RST 0x0
+
+#define LSP_CQ_DIR_TOT_SCH_CNTL_COUNT	0xFFFFFFFF
+#define LSP_CQ_DIR_TOT_SCH_CNTL_COUNT_LOC	0
+
+#define LSP_CQ_DIR_TOT_SCH_CNTH(x) \
+	(0xa0380000 + (x) * 0x1000)
+#define LSP_CQ_DIR_TOT_SCH_CNTH_RST 0x0
+
+#define LSP_CQ_DIR_TOT_SCH_CNTH_COUNT	0xFFFFFFFF
+#define LSP_CQ_DIR_TOT_SCH_CNTH_COUNT_LOC	0
+
+#define LSP_CQ_LDB_DSBL(x) \
+	(0xa0400000 + (x) * 0x1000)
+#define LSP_CQ_LDB_DSBL_RST 0x1
+
+#define LSP_CQ_LDB_DSBL_DISABLED	0x00000001
+#define LSP_CQ_LDB_DSBL_RSVD0		0xFFFFFFFE
+#define LSP_CQ_LDB_DSBL_DISABLED_LOC	0
+#define LSP_CQ_LDB_DSBL_RSVD0_LOC	1
+
+#define LSP_CQ_LDB_INFL_CNT(x) \
+	(0xa0480000 + (x) * 0x1000)
+#define LSP_CQ_LDB_INFL_CNT_RST 0x0
+
+#define LSP_CQ_LDB_INFL_CNT_COUNT	0x00000FFF
+#define LSP_CQ_LDB_INFL_CNT_RSVD0	0xFFFFF000
+#define LSP_CQ_LDB_INFL_CNT_COUNT_LOC	0
+#define LSP_CQ_LDB_INFL_CNT_RSVD0_LOC	12
+
+#define LSP_CQ_LDB_INFL_LIM(x) \
+	(0xa0500000 + (x) * 0x1000)
+#define LSP_CQ_LDB_INFL_LIM_RST 0x0
+
+#define LSP_CQ_LDB_INFL_LIM_LIMIT	0x00000FFF
+#define LSP_CQ_LDB_INFL_LIM_RSVD0	0xFFFFF000
+#define LSP_CQ_LDB_INFL_LIM_LIMIT_LOC	0
+#define LSP_CQ_LDB_INFL_LIM_RSVD0_LOC	12
+
+#define LSP_CQ_LDB_TKN_CNT(x) \
+	(0xa0580000 + (x) * 0x1000)
+#define LSP_CQ_LDB_TKN_CNT_RST 0x0
+
+#define LSP_CQ_LDB_TKN_CNT_TOKEN_COUNT	0x000007FF
+#define LSP_CQ_LDB_TKN_CNT_RSVD0	0xFFFFF800
+#define LSP_CQ_LDB_TKN_CNT_TOKEN_COUNT_LOC	0
+#define LSP_CQ_LDB_TKN_CNT_RSVD0_LOC		11
+
+#define LSP_CQ_LDB_TKN_DEPTH_SEL(x) \
+	(0xa0600000 + (x) * 0x1000)
+#define LSP_CQ_LDB_TKN_DEPTH_SEL_RST 0x0
+
+#define LSP_CQ_LDB_TKN_DEPTH_SEL_TOKEN_DEPTH_SELECT	0x0000000F
+#define LSP_CQ_LDB_TKN_DEPTH_SEL_IGNORE_DEPTH		0x00000010
+#define LSP_CQ_LDB_TKN_DEPTH_SEL_RSVD0			0xFFFFFFE0
+#define LSP_CQ_LDB_TKN_DEPTH_SEL_TOKEN_DEPTH_SELECT_LOC	0
+#define LSP_CQ_LDB_TKN_DEPTH_SEL_IGNORE_DEPTH_LOC	4
+#define LSP_CQ_LDB_TKN_DEPTH_SEL_RSVD0_LOC		5
+
+#define LSP_CQ_LDB_TOT_SCH_CNTL(x) \
+	(0xa0680000 + (x) * 0x1000)
+#define LSP_CQ_LDB_TOT_SCH_CNTL_RST 0x0
+
+#define LSP_CQ_LDB_TOT_SCH_CNTL_COUNT	0xFFFFFFFF
+#define LSP_CQ_LDB_TOT_SCH_CNTL_COUNT_LOC	0
+
+#define LSP_CQ_LDB_TOT_SCH_CNTH(x) \
+	(0xa0700000 + (x) * 0x1000)
+#define LSP_CQ_LDB_TOT_SCH_CNTH_RST 0x0
+
+#define LSP_CQ_LDB_TOT_SCH_CNTH_COUNT	0xFFFFFFFF
+#define LSP_CQ_LDB_TOT_SCH_CNTH_COUNT_LOC	0
+
+#define LSP_QID_DIR_MAX_DEPTH(x) \
+	(0xa0780000 + (x) * 0x1000)
+#define LSP_QID_DIR_MAX_DEPTH_RST 0x0
+
+#define LSP_QID_DIR_MAX_DEPTH_DEPTH	0x00001FFF
+#define LSP_QID_DIR_MAX_DEPTH_RSVD0	0xFFFFE000
+#define LSP_QID_DIR_MAX_DEPTH_DEPTH_LOC	0
+#define LSP_QID_DIR_MAX_DEPTH_RSVD0_LOC	13
+
+#define LSP_QID_DIR_TOT_ENQ_CNTL(x) \
+	(0xa0800000 + (x) * 0x1000)
+#define LSP_QID_DIR_TOT_ENQ_CNTL_RST 0x0
+
+#define LSP_QID_DIR_TOT_ENQ_CNTL_COUNT	0xFFFFFFFF
+#define LSP_QID_DIR_TOT_ENQ_CNTL_COUNT_LOC	0
+
+#define LSP_QID_DIR_TOT_ENQ_CNTH(x) \
+	(0xa0880000 + (x) * 0x1000)
+#define LSP_QID_DIR_TOT_ENQ_CNTH_RST 0x0
+
+#define LSP_QID_DIR_TOT_ENQ_CNTH_COUNT	0xFFFFFFFF
+#define LSP_QID_DIR_TOT_ENQ_CNTH_COUNT_LOC	0
+
+#define LSP_QID_DIR_ENQUEUE_CNT(x) \
+	(0xa0900000 + (x) * 0x1000)
+#define LSP_QID_DIR_ENQUEUE_CNT_RST 0x0
+
+#define LSP_QID_DIR_ENQUEUE_CNT_COUNT	0x00001FFF
+#define LSP_QID_DIR_ENQUEUE_CNT_RSVD0	0xFFFFE000
+#define LSP_QID_DIR_ENQUEUE_CNT_COUNT_LOC	0
+#define LSP_QID_DIR_ENQUEUE_CNT_RSVD0_LOC	13
+
+#define LSP_QID_DIR_DEPTH_THRSH(x) \
+	(0xa0980000 + (x) * 0x1000)
+#define LSP_QID_DIR_DEPTH_THRSH_RST 0x0
+
+#define LSP_QID_DIR_DEPTH_THRSH_THRESH	0x00001FFF
+#define LSP_QID_DIR_DEPTH_THRSH_RSVD0	0xFFFFE000
+#define LSP_QID_DIR_DEPTH_THRSH_THRESH_LOC	0
+#define LSP_QID_DIR_DEPTH_THRSH_RSVD0_LOC	13
+
+#define LSP_QID_AQED_ACTIVE_CNT(x) \
+	(0xa0a00000 + (x) * 0x1000)
+#define LSP_QID_AQED_ACTIVE_CNT_RST 0x0
+
+#define LSP_QID_AQED_ACTIVE_CNT_COUNT	0x00000FFF
+#define LSP_QID_AQED_ACTIVE_CNT_RSVD0	0xFFFFF000
+#define LSP_QID_AQED_ACTIVE_CNT_COUNT_LOC	0
+#define LSP_QID_AQED_ACTIVE_CNT_RSVD0_LOC	12
+
+#define LSP_QID_AQED_ACTIVE_LIM(x) \
+	(0xa0a80000 + (x) * 0x1000)
+#define LSP_QID_AQED_ACTIVE_LIM_RST 0x0
+
+#define LSP_QID_AQED_ACTIVE_LIM_LIMIT	0x00000FFF
+#define LSP_QID_AQED_ACTIVE_LIM_RSVD0	0xFFFFF000
+#define LSP_QID_AQED_ACTIVE_LIM_LIMIT_LOC	0
+#define LSP_QID_AQED_ACTIVE_LIM_RSVD0_LOC	12
+
+#define LSP_QID_ATM_TOT_ENQ_CNTL(x) \
+	(0xa0b00000 + (x) * 0x1000)
+#define LSP_QID_ATM_TOT_ENQ_CNTL_RST 0x0
+
+#define LSP_QID_ATM_TOT_ENQ_CNTL_COUNT	0xFFFFFFFF
+#define LSP_QID_ATM_TOT_ENQ_CNTL_COUNT_LOC	0
+
+#define LSP_QID_ATM_TOT_ENQ_CNTH(x) \
+	(0xa0b80000 + (x) * 0x1000)
+#define LSP_QID_ATM_TOT_ENQ_CNTH_RST 0x0
+
+#define LSP_QID_ATM_TOT_ENQ_CNTH_COUNT	0xFFFFFFFF
+#define LSP_QID_ATM_TOT_ENQ_CNTH_COUNT_LOC	0
+
+#define LSP_QID_ATQ_ENQUEUE_CNT(x) \
+	(0xa0c00000 + (x) * 0x1000)
+#define LSP_QID_ATQ_ENQUEUE_CNT_RST 0x0
+
+#define LSP_QID_ATQ_ENQUEUE_CNT_COUNT	0x00003FFF
+#define LSP_QID_ATQ_ENQUEUE_CNT_RSVD0	0xFFFFC000
+#define LSP_QID_ATQ_ENQUEUE_CNT_COUNT_LOC	0
+#define LSP_QID_ATQ_ENQUEUE_CNT_RSVD0_LOC	14
+
+#define LSP_QID_LDB_ENQUEUE_CNT(x) \
+	(0xa0c80000 + (x) * 0x1000)
+#define LSP_QID_LDB_ENQUEUE_CNT_RST 0x0
+
+#define LSP_QID_LDB_ENQUEUE_CNT_COUNT	0x00003FFF
+#define LSP_QID_LDB_ENQUEUE_CNT_RSVD0	0xFFFFC000
+#define LSP_QID_LDB_ENQUEUE_CNT_COUNT_LOC	0
+#define LSP_QID_LDB_ENQUEUE_CNT_RSVD0_LOC	14
+
+#define LSP_QID_LDB_INFL_CNT(x) \
+	(0xa0d00000 + (x) * 0x1000)
+#define LSP_QID_LDB_INFL_CNT_RST 0x0
+
+#define LSP_QID_LDB_INFL_CNT_COUNT	0x00000FFF
+#define LSP_QID_LDB_INFL_CNT_RSVD0	0xFFFFF000
+#define LSP_QID_LDB_INFL_CNT_COUNT_LOC	0
+#define LSP_QID_LDB_INFL_CNT_RSVD0_LOC	12
+
+#define LSP_QID_LDB_INFL_LIM(x) \
+	(0xa0d80000 + (x) * 0x1000)
+#define LSP_QID_LDB_INFL_LIM_RST 0x0
+
+#define LSP_QID_LDB_INFL_LIM_LIMIT	0x00000FFF
+#define LSP_QID_LDB_INFL_LIM_RSVD0	0xFFFFF000
+#define LSP_QID_LDB_INFL_LIM_LIMIT_LOC	0
+#define LSP_QID_LDB_INFL_LIM_RSVD0_LOC	12
+
+#define LSP_QID2CQIDIX_00(x) \
+	(0xa0e00000 + (x) * 0x1000)
+#define LSP_QID2CQIDIX_00_RST 0x0
+#define LSP_QID2CQIDIX(x, y) \
+	(LSP_QID2CQIDIX_00(x) + 0x80000 * (y))
+#define LSP_QID2CQIDIX_NUM 16
+
+#define LSP_QID2CQIDIX_00_CQ_P0	0x000000FF
+#define LSP_QID2CQIDIX_00_CQ_P1	0x0000FF00
+#define LSP_QID2CQIDIX_00_CQ_P2	0x00FF0000
+#define LSP_QID2CQIDIX_00_CQ_P3	0xFF000000
+#define LSP_QID2CQIDIX_00_CQ_P0_LOC	0
+#define LSP_QID2CQIDIX_00_CQ_P1_LOC	8
+#define LSP_QID2CQIDIX_00_CQ_P2_LOC	16
+#define LSP_QID2CQIDIX_00_CQ_P3_LOC	24
+
+#define LSP_QID2CQIDIX2_00(x) \
+	(0xa1600000 + (x) * 0x1000)
+#define LSP_QID2CQIDIX2_00_RST 0x0
+#define LSP_QID2CQIDIX2(x, y) \
+	(LSP_QID2CQIDIX2_00(x) + 0x80000 * (y))
+#define LSP_QID2CQIDIX2_NUM 16
+
+#define LSP_QID2CQIDIX2_00_CQ_P0	0x000000FF
+#define LSP_QID2CQIDIX2_00_CQ_P1	0x0000FF00
+#define LSP_QID2CQIDIX2_00_CQ_P2	0x00FF0000
+#define LSP_QID2CQIDIX2_00_CQ_P3	0xFF000000
+#define LSP_QID2CQIDIX2_00_CQ_P0_LOC	0
+#define LSP_QID2CQIDIX2_00_CQ_P1_LOC	8
+#define LSP_QID2CQIDIX2_00_CQ_P2_LOC	16
+#define LSP_QID2CQIDIX2_00_CQ_P3_LOC	24
+
+#define LSP_QID_LDB_REPLAY_CNT(x) \
+	(0xa1e00000 + (x) * 0x1000)
+#define LSP_QID_LDB_REPLAY_CNT_RST 0x0
+
+#define LSP_QID_LDB_REPLAY_CNT_COUNT	0x00003FFF
+#define LSP_QID_LDB_REPLAY_CNT_RSVD0	0xFFFFC000
+#define LSP_QID_LDB_REPLAY_CNT_COUNT_LOC	0
+#define LSP_QID_LDB_REPLAY_CNT_RSVD0_LOC	14
+
+#define LSP_QID_NALDB_MAX_DEPTH(x) \
+	(0xa1f00000 + (x) * 0x1000)
+#define LSP_QID_NALDB_MAX_DEPTH_RST 0x0
+
+#define LSP_QID_NALDB_MAX_DEPTH_DEPTH	0x00003FFF
+#define LSP_QID_NALDB_MAX_DEPTH_RSVD0	0xFFFFC000
+#define LSP_QID_NALDB_MAX_DEPTH_DEPTH_LOC	0
+#define LSP_QID_NALDB_MAX_DEPTH_RSVD0_LOC	14
+
+#define LSP_QID_NALDB_TOT_ENQ_CNTL(x) \
+	(0xa1f80000 + (x) * 0x1000)
+#define LSP_QID_NALDB_TOT_ENQ_CNTL_RST 0x0
+
+#define LSP_QID_NALDB_TOT_ENQ_CNTL_COUNT	0xFFFFFFFF
+#define LSP_QID_NALDB_TOT_ENQ_CNTL_COUNT_LOC	0
+
+#define LSP_QID_NALDB_TOT_ENQ_CNTH(x) \
+	(0xa2000000 + (x) * 0x1000)
+#define LSP_QID_NALDB_TOT_ENQ_CNTH_RST 0x0
+
+#define LSP_QID_NALDB_TOT_ENQ_CNTH_COUNT	0xFFFFFFFF
+#define LSP_QID_NALDB_TOT_ENQ_CNTH_COUNT_LOC	0
+
+#define LSP_QID_ATM_DEPTH_THRSH(x) \
+	(0xa2080000 + (x) * 0x1000)
+#define LSP_QID_ATM_DEPTH_THRSH_RST 0x0
+
+#define LSP_QID_ATM_DEPTH_THRSH_THRESH	0x00003FFF
+#define LSP_QID_ATM_DEPTH_THRSH_RSVD0	0xFFFFC000
+#define LSP_QID_ATM_DEPTH_THRSH_THRESH_LOC	0
+#define LSP_QID_ATM_DEPTH_THRSH_RSVD0_LOC	14
+
+#define LSP_QID_NALDB_DEPTH_THRSH(x) \
+	(0xa2100000 + (x) * 0x1000)
+#define LSP_QID_NALDB_DEPTH_THRSH_RST 0x0
+
+#define LSP_QID_NALDB_DEPTH_THRSH_THRESH	0x00003FFF
+#define LSP_QID_NALDB_DEPTH_THRSH_RSVD0		0xFFFFC000
+#define LSP_QID_NALDB_DEPTH_THRSH_THRESH_LOC	0
+#define LSP_QID_NALDB_DEPTH_THRSH_RSVD0_LOC	14
+
+#define LSP_QID_ATM_ACTIVE(x) \
+	(0xa2180000 + (x) * 0x1000)
+#define LSP_QID_ATM_ACTIVE_RST 0x0
+
+#define LSP_QID_ATM_ACTIVE_COUNT	0x00003FFF
+#define LSP_QID_ATM_ACTIVE_RSVD0	0xFFFFC000
+#define LSP_QID_ATM_ACTIVE_COUNT_LOC	0
+#define LSP_QID_ATM_ACTIVE_RSVD0_LOC	14
+
+#define LSP_CFG_ARB_WEIGHT_ATM_NALB_QID_0 0xa4000008
+#define LSP_CFG_ARB_WEIGHT_ATM_NALB_QID_0_RST 0x0
+
+#define LSP_CFG_ARB_WEIGHT_ATM_NALB_QID_0_PRI0_WEIGHT	0x000000FF
+#define LSP_CFG_ARB_WEIGHT_ATM_NALB_QID_0_PRI1_WEIGHT	0x0000FF00
+#define LSP_CFG_ARB_WEIGHT_ATM_NALB_QID_0_PRI2_WEIGHT	0x00FF0000
+#define LSP_CFG_ARB_WEIGHT_ATM_NALB_QID_0_PRI3_WEIGHT	0xFF000000
+#define LSP_CFG_ARB_WEIGHT_ATM_NALB_QID_0_PRI0_WEIGHT_LOC	0
+#define LSP_CFG_ARB_WEIGHT_ATM_NALB_QID_0_PRI1_WEIGHT_LOC	8
+#define LSP_CFG_ARB_WEIGHT_ATM_NALB_QID_0_PRI2_WEIGHT_LOC	16
+#define LSP_CFG_ARB_WEIGHT_ATM_NALB_QID_0_PRI3_WEIGHT_LOC	24
+
+#define LSP_CFG_ARB_WEIGHT_ATM_NALB_QID_1 0xa400000c
+#define LSP_CFG_ARB_WEIGHT_ATM_NALB_QID_1_RST 0x0
+
+#define LSP_CFG_ARB_WEIGHT_ATM_NALB_QID_1_RSVZ0	0xFFFFFFFF
+#define LSP_CFG_ARB_WEIGHT_ATM_NALB_QID_1_RSVZ0_LOC	0
+
+#define LSP_CFG_ARB_WEIGHT_LDB_QID_0 0xa4000014
+#define LSP_CFG_ARB_WEIGHT_LDB_QID_0_RST 0x0
+
+#define LSP_CFG_ARB_WEIGHT_LDB_QID_0_PRI0_WEIGHT	0x000000FF
+#define LSP_CFG_ARB_WEIGHT_LDB_QID_0_PRI1_WEIGHT	0x0000FF00
+#define LSP_CFG_ARB_WEIGHT_LDB_QID_0_PRI2_WEIGHT	0x00FF0000
+#define LSP_CFG_ARB_WEIGHT_LDB_QID_0_PRI3_WEIGHT	0xFF000000
+#define LSP_CFG_ARB_WEIGHT_LDB_QID_0_PRI0_WEIGHT_LOC	0
+#define LSP_CFG_ARB_WEIGHT_LDB_QID_0_PRI1_WEIGHT_LOC	8
+#define LSP_CFG_ARB_WEIGHT_LDB_QID_0_PRI2_WEIGHT_LOC	16
+#define LSP_CFG_ARB_WEIGHT_LDB_QID_0_PRI3_WEIGHT_LOC	24
+
+#define LSP_CFG_ARB_WEIGHT_LDB_QID_1 0xa4000018
+#define LSP_CFG_ARB_WEIGHT_LDB_QID_1_RST 0x0
+
+#define LSP_CFG_ARB_WEIGHT_LDB_QID_1_RSVZ0	0xFFFFFFFF
+#define LSP_CFG_ARB_WEIGHT_LDB_QID_1_RSVZ0_LOC	0
+
+#define LSP_LDB_SCHED_CTRL 0xa400002c
+#define LSP_LDB_SCHED_CTRL_RST 0x0
+
+#define LSP_LDB_SCHED_CTRL_CQ			0x000000FF
+#define LSP_LDB_SCHED_CTRL_QIDIX		0x00000700
+#define LSP_LDB_SCHED_CTRL_VALUE		0x00000800
+#define LSP_LDB_SCHED_CTRL_NALB_HASWORK_V	0x00001000
+#define LSP_LDB_SCHED_CTRL_RLIST_HASWORK_V	0x00002000
+#define LSP_LDB_SCHED_CTRL_SLIST_HASWORK_V	0x00004000
+#define LSP_LDB_SCHED_CTRL_INFLIGHT_OK_V	0x00008000
+#define LSP_LDB_SCHED_CTRL_AQED_NFULL_V		0x00010000
+#define LSP_LDB_SCHED_CTRL_RSVZ0		0xFFFE0000
+#define LSP_LDB_SCHED_CTRL_CQ_LOC		0
+#define LSP_LDB_SCHED_CTRL_QIDIX_LOC		8
+#define LSP_LDB_SCHED_CTRL_VALUE_LOC		11
+#define LSP_LDB_SCHED_CTRL_NALB_HASWORK_V_LOC	12
+#define LSP_LDB_SCHED_CTRL_RLIST_HASWORK_V_LOC	13
+#define LSP_LDB_SCHED_CTRL_SLIST_HASWORK_V_LOC	14
+#define LSP_LDB_SCHED_CTRL_INFLIGHT_OK_V_LOC	15
+#define LSP_LDB_SCHED_CTRL_AQED_NFULL_V_LOC	16
+#define LSP_LDB_SCHED_CTRL_RSVZ0_LOC		17
+
+#define LSP_DIR_SCH_CNT_L 0xa4000034
+#define LSP_DIR_SCH_CNT_L_RST 0x0
+
+#define LSP_DIR_SCH_CNT_L_COUNT	0xFFFFFFFF
+#define LSP_DIR_SCH_CNT_L_COUNT_LOC	0
+
+#define LSP_DIR_SCH_CNT_H 0xa4000038
+#define LSP_DIR_SCH_CNT_H_RST 0x0
+
+#define LSP_DIR_SCH_CNT_H_COUNT	0xFFFFFFFF
+#define LSP_DIR_SCH_CNT_H_COUNT_LOC	0
+
+#define LSP_LDB_SCH_CNT_L 0xa400003c
+#define LSP_LDB_SCH_CNT_L_RST 0x0
+
+#define LSP_LDB_SCH_CNT_L_COUNT	0xFFFFFFFF
+#define LSP_LDB_SCH_CNT_L_COUNT_LOC	0
+
+#define LSP_LDB_SCH_CNT_H 0xa4000040
+#define LSP_LDB_SCH_CNT_H_RST 0x0
+
+#define LSP_LDB_SCH_CNT_H_COUNT	0xFFFFFFFF
+#define LSP_LDB_SCH_CNT_H_COUNT_LOC	0
+
+#define LSP_CFG_SHDW_CTRL 0xa4000070
+#define LSP_CFG_SHDW_CTRL_RST 0x0
+
+#define LSP_CFG_SHDW_CTRL_TRANSFER	0x00000001
+#define LSP_CFG_SHDW_CTRL_RSVD0		0xFFFFFFFE
+#define LSP_CFG_SHDW_CTRL_TRANSFER_LOC	0
+#define LSP_CFG_SHDW_CTRL_RSVD0_LOC	1
+
+#define LSP_CFG_SHDW_RANGE_COS(x) \
+	(0xa4000074 + (x) * 4)
+#define LSP_CFG_SHDW_RANGE_COS_RST 0x40
+
+#define LSP_CFG_SHDW_RANGE_COS_BW_RANGE		0x000001FF
+#define LSP_CFG_SHDW_RANGE_COS_RSVZ0		0x7FFFFE00
+#define LSP_CFG_SHDW_RANGE_COS_NO_EXTRA_CREDIT	0x80000000
+#define LSP_CFG_SHDW_RANGE_COS_BW_RANGE_LOC		0
+#define LSP_CFG_SHDW_RANGE_COS_RSVZ0_LOC		9
+#define LSP_CFG_SHDW_RANGE_COS_NO_EXTRA_CREDIT_LOC	31
+
+#define LSP_CFG_CTRL_GENERAL_0 0xac000000
+#define LSP_CFG_CTRL_GENERAL_0_RST 0x0
+
+#define LSP_CFG_CTRL_GENERAL_0_DISAB_ATQ_EMPTY_ARB	0x00000001
+#define LSP_CFG_CTRL_GENERAL_0_INC_TOK_UNIT_IDLE	0x00000002
+#define LSP_CFG_CTRL_GENERAL_0_DISAB_RLIST_PRI		0x00000004
+#define LSP_CFG_CTRL_GENERAL_0_INC_CMP_UNIT_IDLE	0x00000008
+#define LSP_CFG_CTRL_GENERAL_0_RSVZ0			0x00000030
+#define LSP_CFG_CTRL_GENERAL_0_DIR_SINGLE_OP		0x00000040
+#define LSP_CFG_CTRL_GENERAL_0_DIR_HALF_BW		0x00000080
+#define LSP_CFG_CTRL_GENERAL_0_DIR_SINGLE_OUT		0x00000100
+#define LSP_CFG_CTRL_GENERAL_0_DIR_DISAB_MULTI		0x00000200
+#define LSP_CFG_CTRL_GENERAL_0_ATQ_SINGLE_OP		0x00000400
+#define LSP_CFG_CTRL_GENERAL_0_ATQ_HALF_BW		0x00000800
+#define LSP_CFG_CTRL_GENERAL_0_ATQ_SINGLE_OUT		0x00001000
+#define LSP_CFG_CTRL_GENERAL_0_ATQ_DISAB_MULTI		0x00002000
+#define LSP_CFG_CTRL_GENERAL_0_DIRRPL_SINGLE_OP		0x00004000
+#define LSP_CFG_CTRL_GENERAL_0_DIRRPL_HALF_BW		0x00008000
+#define LSP_CFG_CTRL_GENERAL_0_DIRRPL_SINGLE_OUT	0x00010000
+#define LSP_CFG_CTRL_GENERAL_0_LBRPL_SINGLE_OP		0x00020000
+#define LSP_CFG_CTRL_GENERAL_0_LBRPL_HALF_BW		0x00040000
+#define LSP_CFG_CTRL_GENERAL_0_LBRPL_SINGLE_OUT		0x00080000
+#define LSP_CFG_CTRL_GENERAL_0_LDB_SINGLE_OP		0x00100000
+#define LSP_CFG_CTRL_GENERAL_0_LDB_HALF_BW		0x00200000
+#define LSP_CFG_CTRL_GENERAL_0_LDB_DISAB_MULTI		0x00400000
+#define LSP_CFG_CTRL_GENERAL_0_ATM_SINGLE_SCH		0x00800000
+#define LSP_CFG_CTRL_GENERAL_0_ATM_SINGLE_CMP		0x01000000
+#define LSP_CFG_CTRL_GENERAL_0_LDB_CE_TOG_ARB		0x02000000
+#define LSP_CFG_CTRL_GENERAL_0_RSVZ1			0x04000000
+#define LSP_CFG_CTRL_GENERAL_0_SMON0_VALID_SEL		0x18000000
+#define LSP_CFG_CTRL_GENERAL_0_SMON0_VALUE_SEL		0x20000000
+#define LSP_CFG_CTRL_GENERAL_0_SMON0_COMPARE_SEL	0xC0000000
+#define LSP_CFG_CTRL_GENERAL_0_DISAB_ATQ_EMPTY_ARB_LOC	0
+#define LSP_CFG_CTRL_GENERAL_0_INC_TOK_UNIT_IDLE_LOC	1
+#define LSP_CFG_CTRL_GENERAL_0_DISAB_RLIST_PRI_LOC	2
+#define LSP_CFG_CTRL_GENERAL_0_INC_CMP_UNIT_IDLE_LOC	3
+#define LSP_CFG_CTRL_GENERAL_0_RSVZ0_LOC		4
+#define LSP_CFG_CTRL_GENERAL_0_DIR_SINGLE_OP_LOC	6
+#define LSP_CFG_CTRL_GENERAL_0_DIR_HALF_BW_LOC		7
+#define LSP_CFG_CTRL_GENERAL_0_DIR_SINGLE_OUT_LOC	8
+#define LSP_CFG_CTRL_GENERAL_0_DIR_DISAB_MULTI_LOC	9
+#define LSP_CFG_CTRL_GENERAL_0_ATQ_SINGLE_OP_LOC	10
+#define LSP_CFG_CTRL_GENERAL_0_ATQ_HALF_BW_LOC		11
+#define LSP_CFG_CTRL_GENERAL_0_ATQ_SINGLE_OUT_LOC	12
+#define LSP_CFG_CTRL_GENERAL_0_ATQ_DISAB_MULTI_LOC	13
+#define LSP_CFG_CTRL_GENERAL_0_DIRRPL_SINGLE_OP_LOC	14
+#define LSP_CFG_CTRL_GENERAL_0_DIRRPL_HALF_BW_LOC	15
+#define LSP_CFG_CTRL_GENERAL_0_DIRRPL_SINGLE_OUT_LOC	16
+#define LSP_CFG_CTRL_GENERAL_0_LBRPL_SINGLE_OP_LOC	17
+#define LSP_CFG_CTRL_GENERAL_0_LBRPL_HALF_BW_LOC	18
+#define LSP_CFG_CTRL_GENERAL_0_LBRPL_SINGLE_OUT_LOC	19
+#define LSP_CFG_CTRL_GENERAL_0_LDB_SINGLE_OP_LOC	20
+#define LSP_CFG_CTRL_GENERAL_0_LDB_HALF_BW_LOC		21
+#define LSP_CFG_CTRL_GENERAL_0_LDB_DISAB_MULTI_LOC	22
+#define LSP_CFG_CTRL_GENERAL_0_ATM_SINGLE_SCH_LOC	23
+#define LSP_CFG_CTRL_GENERAL_0_ATM_SINGLE_CMP_LOC	24
+#define LSP_CFG_CTRL_GENERAL_0_LDB_CE_TOG_ARB_LOC	25
+#define LSP_CFG_CTRL_GENERAL_0_RSVZ1_LOC		26
+#define LSP_CFG_CTRL_GENERAL_0_SMON0_VALID_SEL_LOC	27
+#define LSP_CFG_CTRL_GENERAL_0_SMON0_VALUE_SEL_LOC	29
+#define LSP_CFG_CTRL_GENERAL_0_SMON0_COMPARE_SEL_LOC	30
+
+#define LSP_SMON_COMPARE0 0xac000048
+#define LSP_SMON_COMPARE0_RST 0x0
+
+#define LSP_SMON_COMPARE0_COMPARE0	0xFFFFFFFF
+#define LSP_SMON_COMPARE0_COMPARE0_LOC	0
+
+#define LSP_SMON_COMPARE1 0xac00004c
+#define LSP_SMON_COMPARE1_RST 0x0
+
+#define LSP_SMON_COMPARE1_COMPARE1	0xFFFFFFFF
+#define LSP_SMON_COMPARE1_COMPARE1_LOC	0
+
+#define LSP_SMON_CFG0 0xac000050
+#define LSP_SMON_CFG0_RST 0x40000000
+
+#define LSP_SMON_CFG0_SMON_ENABLE		0x00000001
+#define LSP_SMON_CFG0_SMON_0TRIGGER_ENABLE	0x00000002
+#define LSP_SMON_CFG0_RSVZ0			0x0000000C
+#define LSP_SMON_CFG0_SMON0_FUNCTION		0x00000070
+#define LSP_SMON_CFG0_SMON0_FUNCTION_COMPARE	0x00000080
+#define LSP_SMON_CFG0_SMON1_FUNCTION		0x00000700
+#define LSP_SMON_CFG0_SMON1_FUNCTION_COMPARE	0x00000800
+#define LSP_SMON_CFG0_SMON_MODE			0x0000F000
+#define LSP_SMON_CFG0_STOPCOUNTEROVFL		0x00010000
+#define LSP_SMON_CFG0_INTCOUNTEROVFL		0x00020000
+#define LSP_SMON_CFG0_STATCOUNTER0OVFL		0x00040000
+#define LSP_SMON_CFG0_STATCOUNTER1OVFL		0x00080000
+#define LSP_SMON_CFG0_STOPTIMEROVFL		0x00100000
+#define LSP_SMON_CFG0_INTTIMEROVFL		0x00200000
+#define LSP_SMON_CFG0_STATTIMEROVFL		0x00400000
+#define LSP_SMON_CFG0_RSVZ1			0x00800000
+#define LSP_SMON_CFG0_TIMER_PRESCALE		0x1F000000
+#define LSP_SMON_CFG0_RSVZ2			0x20000000
+#define LSP_SMON_CFG0_VERSION			0xC0000000
+#define LSP_SMON_CFG0_SMON_ENABLE_LOC			0
+#define LSP_SMON_CFG0_SMON_0TRIGGER_ENABLE_LOC		1
+#define LSP_SMON_CFG0_RSVZ0_LOC				2
+#define LSP_SMON_CFG0_SMON0_FUNCTION_LOC		4
+#define LSP_SMON_CFG0_SMON0_FUNCTION_COMPARE_LOC	7
+#define LSP_SMON_CFG0_SMON1_FUNCTION_LOC		8
+#define LSP_SMON_CFG0_SMON1_FUNCTION_COMPARE_LOC	11
+#define LSP_SMON_CFG0_SMON_MODE_LOC			12
+#define LSP_SMON_CFG0_STOPCOUNTEROVFL_LOC		16
+#define LSP_SMON_CFG0_INTCOUNTEROVFL_LOC		17
+#define LSP_SMON_CFG0_STATCOUNTER0OVFL_LOC		18
+#define LSP_SMON_CFG0_STATCOUNTER1OVFL_LOC		19
+#define LSP_SMON_CFG0_STOPTIMEROVFL_LOC			20
+#define LSP_SMON_CFG0_INTTIMEROVFL_LOC			21
+#define LSP_SMON_CFG0_STATTIMEROVFL_LOC			22
+#define LSP_SMON_CFG0_RSVZ1_LOC				23
+#define LSP_SMON_CFG0_TIMER_PRESCALE_LOC		24
+#define LSP_SMON_CFG0_RSVZ2_LOC				29
+#define LSP_SMON_CFG0_VERSION_LOC			30
+
+#define LSP_SMON_CFG1 0xac000054
+#define LSP_SMON_CFG1_RST 0x0
+
+#define LSP_SMON_CFG1_MODE0	0x000000FF
+#define LSP_SMON_CFG1_MODE1	0x0000FF00
+#define LSP_SMON_CFG1_RSVZ0	0xFFFF0000
+#define LSP_SMON_CFG1_MODE0_LOC	0
+#define LSP_SMON_CFG1_MODE1_LOC	8
+#define LSP_SMON_CFG1_RSVZ0_LOC	16
+
+#define LSP_SMON_ACTIVITYCNTR0 0xac000058
+#define LSP_SMON_ACTIVITYCNTR0_RST 0x0
+
+#define LSP_SMON_ACTIVITYCNTR0_COUNTER0	0xFFFFFFFF
+#define LSP_SMON_ACTIVITYCNTR0_COUNTER0_LOC	0
+
+#define LSP_SMON_ACTIVITYCNTR1 0xac00005c
+#define LSP_SMON_ACTIVITYCNTR1_RST 0x0
+
+#define LSP_SMON_ACTIVITYCNTR1_COUNTER1	0xFFFFFFFF
+#define LSP_SMON_ACTIVITYCNTR1_COUNTER1_LOC	0
+
+#define LSP_SMON_MAX_TMR 0xac000060
+#define LSP_SMON_MAX_TMR_RST 0x0
+
+#define LSP_SMON_MAX_TMR_MAXVALUE	0xFFFFFFFF
+#define LSP_SMON_MAX_TMR_MAXVALUE_LOC	0
+
+#define LSP_SMON_TMR 0xac000064
+#define LSP_SMON_TMR_RST 0x0
+
+#define LSP_SMON_TMR_TIMER	0xFFFFFFFF
+#define LSP_SMON_TMR_TIMER_LOC	0
+
+#define CM_DIAG_RESET_STS 0xb4000000
+#define CM_DIAG_RESET_STS_RST 0x80000bff
+
+#define CM_DIAG_RESET_STS_CHP_PF_RESET_DONE	0x00000001
+#define CM_DIAG_RESET_STS_ROP_PF_RESET_DONE	0x00000002
+#define CM_DIAG_RESET_STS_LSP_PF_RESET_DONE	0x00000004
+#define CM_DIAG_RESET_STS_NALB_PF_RESET_DONE	0x00000008
+#define CM_DIAG_RESET_STS_AP_PF_RESET_DONE	0x00000010
+#define CM_DIAG_RESET_STS_DP_PF_RESET_DONE	0x00000020
+#define CM_DIAG_RESET_STS_QED_PF_RESET_DONE	0x00000040
+#define CM_DIAG_RESET_STS_DQED_PF_RESET_DONE	0x00000080
+#define CM_DIAG_RESET_STS_AQED_PF_RESET_DONE	0x00000100
+#define CM_DIAG_RESET_STS_SYS_PF_RESET_DONE	0x00000200
+#define CM_DIAG_RESET_STS_PF_RESET_ACTIVE	0x00000400
+#define CM_DIAG_RESET_STS_FLRSM_STATE		0x0003F800
+#define CM_DIAG_RESET_STS_RSVD0			0x7FFC0000
+#define CM_DIAG_RESET_STS_DLB_PROC_RESET_DONE	0x80000000
+#define CM_DIAG_RESET_STS_CHP_PF_RESET_DONE_LOC		0
+#define CM_DIAG_RESET_STS_ROP_PF_RESET_DONE_LOC		1
+#define CM_DIAG_RESET_STS_LSP_PF_RESET_DONE_LOC		2
+#define CM_DIAG_RESET_STS_NALB_PF_RESET_DONE_LOC	3
+#define CM_DIAG_RESET_STS_AP_PF_RESET_DONE_LOC		4
+#define CM_DIAG_RESET_STS_DP_PF_RESET_DONE_LOC		5
+#define CM_DIAG_RESET_STS_QED_PF_RESET_DONE_LOC		6
+#define CM_DIAG_RESET_STS_DQED_PF_RESET_DONE_LOC	7
+#define CM_DIAG_RESET_STS_AQED_PF_RESET_DONE_LOC	8
+#define CM_DIAG_RESET_STS_SYS_PF_RESET_DONE_LOC		9
+#define CM_DIAG_RESET_STS_PF_RESET_ACTIVE_LOC		10
+#define CM_DIAG_RESET_STS_FLRSM_STATE_LOC		11
+#define CM_DIAG_RESET_STS_RSVD0_LOC			18
+#define CM_DIAG_RESET_STS_DLB_PROC_RESET_DONE_LOC	31
 
 #define CM_CFG_DIAGNOSTIC_IDLE_STATUS 0xb4000004
 #define CM_CFG_DIAGNOSTIC_IDLE_STATUS_RST 0x9d0fffff
@@ -134,4 +3584,57 @@
 #define CM_CFG_PM_PMCSR_DISABLE_DISABLE_LOC	0
 #define CM_CFG_PM_PMCSR_DISABLE_RSVZ0_LOC	1
 
+#define VF_VF2PF_MAILBOX_BYTES 256
+#define VF_VF2PF_MAILBOX(x) \
+	(0x1000 + (x) * 0x4)
+#define VF_VF2PF_MAILBOX_RST 0x0
+
+#define VF_VF2PF_MAILBOX_MSG	0xFFFFFFFF
+#define VF_VF2PF_MAILBOX_MSG_LOC	0
+
+#define VF_VF2PF_MAILBOX_ISR 0x1f00
+#define VF_VF2PF_MAILBOX_ISR_RST 0x0
+#define VF_SIOV_MBOX_ISR_TRIGGER 0x8000
+
+#define VF_VF2PF_MAILBOX_ISR_ISR	0x00000001
+#define VF_VF2PF_MAILBOX_ISR_RSVD0	0xFFFFFFFE
+#define VF_VF2PF_MAILBOX_ISR_ISR_LOC	0
+#define VF_VF2PF_MAILBOX_ISR_RSVD0_LOC	1
+
+#define VF_PF2VF_MAILBOX_BYTES 64
+#define VF_PF2VF_MAILBOX(x) \
+	(0x2000 + (x) * 0x4)
+#define VF_PF2VF_MAILBOX_RST 0x0
+
+#define VF_PF2VF_MAILBOX_MSG	0xFFFFFFFF
+#define VF_PF2VF_MAILBOX_MSG_LOC	0
+
+#define VF_PF2VF_MAILBOX_ISR 0x2f00
+#define VF_PF2VF_MAILBOX_ISR_RST 0x0
+
+#define VF_PF2VF_MAILBOX_ISR_PF_ISR	0x00000001
+#define VF_PF2VF_MAILBOX_ISR_RSVD0	0xFFFFFFFE
+#define VF_PF2VF_MAILBOX_ISR_PF_ISR_LOC	0
+#define VF_PF2VF_MAILBOX_ISR_RSVD0_LOC	1
+
+#define VF_VF_MSI_ISR_PEND 0x2f10
+#define VF_VF_MSI_ISR_PEND_RST 0x0
+
+#define VF_VF_MSI_ISR_PEND_ISR_PEND	0xFFFFFFFF
+#define VF_VF_MSI_ISR_PEND_ISR_PEND_LOC	0
+
+#define VF_VF_RESET_IN_PROGRESS 0x3000
+#define VF_VF_RESET_IN_PROGRESS_RST 0x1
+
+#define VF_VF_RESET_IN_PROGRESS_RESET_IN_PROGRESS	0x00000001
+#define VF_VF_RESET_IN_PROGRESS_RSVD0			0xFFFFFFFE
+#define VF_VF_RESET_IN_PROGRESS_RESET_IN_PROGRESS_LOC	0
+#define VF_VF_RESET_IN_PROGRESS_RSVD0_LOC		1
+
+#define VF_VF_MSI_ISR 0x4000
+#define VF_VF_MSI_ISR_RST 0x0
+
+#define VF_VF_MSI_ISR_VF_MSI_ISR	0xFFFFFFFF
+#define VF_VF_MSI_ISR_VF_MSI_ISR_LOC	0
+
 #endif /* __DLB_REGS_H */
diff --git a/drivers/misc/dlb/dlb_resource.c b/drivers/misc/dlb/dlb_resource.c
index c5b3f1ff3d7e..84f6cba6b681 100644
--- a/drivers/misc/dlb/dlb_resource.c
+++ b/drivers/misc/dlb/dlb_resource.c
@@ -890,6 +890,390 @@ static int dlb_domain_reset_software_state(struct dlb_hw *hw,
 	return 0;
 }
 
+static void __dlb_domain_reset_ldb_port_registers(struct dlb_hw *hw,
+						  struct dlb_ldb_port *port)
+{
+	DLB_CSR_WR(hw,
+		   SYS_LDB_PP2VAS(port->id),
+		   SYS_LDB_PP2VAS_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_LDB_CQ2VAS(port->id),
+		   CHP_LDB_CQ2VAS_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_LDB_PP2VDEV(port->id),
+		   SYS_LDB_PP2VDEV_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_LDB_PP_V(port->id),
+		   SYS_LDB_PP_V_RST);
+
+	DLB_CSR_WR(hw,
+		   LSP_CQ_LDB_DSBL(port->id),
+		   LSP_CQ_LDB_DSBL_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_LDB_CQ_DEPTH(port->id),
+		   CHP_LDB_CQ_DEPTH_RST);
+
+	DLB_CSR_WR(hw,
+		   LSP_CQ_LDB_INFL_LIM(port->id),
+		   LSP_CQ_LDB_INFL_LIM_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_HIST_LIST_LIM(port->id),
+		   CHP_HIST_LIST_LIM_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_HIST_LIST_BASE(port->id),
+		   CHP_HIST_LIST_BASE_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_HIST_LIST_POP_PTR(port->id),
+		   CHP_HIST_LIST_POP_PTR_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_HIST_LIST_PUSH_PTR(port->id),
+		   CHP_HIST_LIST_PUSH_PTR_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_LDB_CQ_INT_DEPTH_THRSH(port->id),
+		   CHP_LDB_CQ_INT_DEPTH_THRSH_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_LDB_CQ_TMR_THRSH(port->id),
+		   CHP_LDB_CQ_TMR_THRSH_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_LDB_CQ_INT_ENB(port->id),
+		   CHP_LDB_CQ_INT_ENB_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_LDB_CQ_ISR(port->id),
+		   SYS_LDB_CQ_ISR_RST);
+
+	DLB_CSR_WR(hw,
+		   LSP_CQ_LDB_TKN_DEPTH_SEL(port->id),
+		   LSP_CQ_LDB_TKN_DEPTH_SEL_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_LDB_CQ_TKN_DEPTH_SEL(port->id),
+		   CHP_LDB_CQ_TKN_DEPTH_SEL_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_LDB_CQ_WPTR(port->id),
+		   CHP_LDB_CQ_WPTR_RST);
+
+	DLB_CSR_WR(hw,
+		   LSP_CQ_LDB_TKN_CNT(port->id),
+		   LSP_CQ_LDB_TKN_CNT_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_LDB_CQ_ADDR_L(port->id),
+		   SYS_LDB_CQ_ADDR_L_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_LDB_CQ_ADDR_U(port->id),
+		   SYS_LDB_CQ_ADDR_U_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_LDB_CQ_AT(port->id),
+		   SYS_LDB_CQ_AT_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_LDB_CQ_PASID(port->id),
+		   SYS_LDB_CQ_PASID_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_LDB_CQ2VF_PF_RO(port->id),
+		   SYS_LDB_CQ2VF_PF_RO_RST);
+
+	DLB_CSR_WR(hw,
+		   LSP_CQ_LDB_TOT_SCH_CNTL(port->id),
+		   LSP_CQ_LDB_TOT_SCH_CNTL_RST);
+
+	DLB_CSR_WR(hw,
+		   LSP_CQ_LDB_TOT_SCH_CNTH(port->id),
+		   LSP_CQ_LDB_TOT_SCH_CNTH_RST);
+
+	DLB_CSR_WR(hw,
+		   LSP_CQ2QID0(port->id),
+		   LSP_CQ2QID0_RST);
+
+	DLB_CSR_WR(hw,
+		   LSP_CQ2QID1(port->id),
+		   LSP_CQ2QID1_RST);
+
+	DLB_CSR_WR(hw,
+		   LSP_CQ2PRIOV(port->id),
+		   LSP_CQ2PRIOV_RST);
+}
+
+static void dlb_domain_reset_ldb_port_registers(struct dlb_hw *hw,
+						struct dlb_hw_domain *domain)
+{
+	struct dlb_ldb_port *port;
+	int i;
+
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++) {
+		list_for_each_entry(port, &domain->used_ldb_ports[i], domain_list)
+			__dlb_domain_reset_ldb_port_registers(hw, port);
+	}
+}
+
+static void
+__dlb_domain_reset_dir_port_registers(struct dlb_hw *hw,
+				      struct dlb_dir_pq_pair *port)
+{
+	DLB_CSR_WR(hw,
+		   CHP_DIR_CQ2VAS(port->id),
+		   CHP_DIR_CQ2VAS_RST);
+
+	DLB_CSR_WR(hw,
+		   LSP_CQ_DIR_DSBL(port->id),
+		   LSP_CQ_DIR_DSBL_RST);
+
+	DLB_CSR_WR(hw, SYS_DIR_CQ_OPT_CLR, port->id);
+
+	DLB_CSR_WR(hw,
+		   CHP_DIR_CQ_DEPTH(port->id),
+		   CHP_DIR_CQ_DEPTH_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_DIR_CQ_INT_DEPTH_THRSH(port->id),
+		   CHP_DIR_CQ_INT_DEPTH_THRSH_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_DIR_CQ_TMR_THRSH(port->id),
+		   CHP_DIR_CQ_TMR_THRSH_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_DIR_CQ_INT_ENB(port->id),
+		   CHP_DIR_CQ_INT_ENB_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_DIR_CQ_ISR(port->id),
+		   SYS_DIR_CQ_ISR_RST);
+
+	DLB_CSR_WR(hw,
+		   LSP_CQ_DIR_TKN_DEPTH_SEL_DSI(port->id),
+		   LSP_CQ_DIR_TKN_DEPTH_SEL_DSI_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_DIR_CQ_TKN_DEPTH_SEL(port->id),
+		   CHP_DIR_CQ_TKN_DEPTH_SEL_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_DIR_CQ_WPTR(port->id),
+		   CHP_DIR_CQ_WPTR_RST);
+
+	DLB_CSR_WR(hw,
+		   LSP_CQ_DIR_TKN_CNT(port->id),
+		   LSP_CQ_DIR_TKN_CNT_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_DIR_CQ_ADDR_L(port->id),
+		   SYS_DIR_CQ_ADDR_L_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_DIR_CQ_ADDR_U(port->id),
+		   SYS_DIR_CQ_ADDR_U_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_DIR_CQ_AT(port->id),
+		   SYS_DIR_CQ_AT_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_DIR_CQ_PASID(port->id),
+		   SYS_DIR_CQ_PASID_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_DIR_CQ_FMT(port->id),
+		   SYS_DIR_CQ_FMT_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_DIR_CQ2VF_PF_RO(port->id),
+		   SYS_DIR_CQ2VF_PF_RO_RST);
+
+	DLB_CSR_WR(hw,
+		   LSP_CQ_DIR_TOT_SCH_CNTL(port->id),
+		   LSP_CQ_DIR_TOT_SCH_CNTL_RST);
+
+	DLB_CSR_WR(hw,
+		   LSP_CQ_DIR_TOT_SCH_CNTH(port->id),
+		   LSP_CQ_DIR_TOT_SCH_CNTH_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_DIR_PP2VAS(port->id),
+		   SYS_DIR_PP2VAS_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_DIR_CQ2VAS(port->id),
+		   CHP_DIR_CQ2VAS_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_DIR_PP2VDEV(port->id),
+		   SYS_DIR_PP2VDEV_RST);
+
+	DLB_CSR_WR(hw,
+		   SYS_DIR_PP_V(port->id),
+		   SYS_DIR_PP_V_RST);
+}
+
+static void dlb_domain_reset_dir_port_registers(struct dlb_hw *hw,
+						struct dlb_hw_domain *domain)
+{
+	struct dlb_dir_pq_pair *port;
+
+	list_for_each_entry(port, &domain->used_dir_pq_pairs, domain_list)
+		__dlb_domain_reset_dir_port_registers(hw, port);
+}
+
+static void dlb_domain_reset_ldb_queue_registers(struct dlb_hw *hw,
+						 struct dlb_hw_domain *domain)
+{
+	struct dlb_ldb_queue *queue;
+
+	list_for_each_entry(queue, &domain->used_ldb_queues, domain_list) {
+		unsigned int queue_id = queue->id;
+		int i;
+
+		DLB_CSR_WR(hw,
+			   LSP_QID_NALDB_TOT_ENQ_CNTL(queue_id),
+			   LSP_QID_NALDB_TOT_ENQ_CNTL_RST);
+
+		DLB_CSR_WR(hw,
+			   LSP_QID_NALDB_TOT_ENQ_CNTH(queue_id),
+			   LSP_QID_NALDB_TOT_ENQ_CNTH_RST);
+
+		DLB_CSR_WR(hw,
+			   LSP_QID_ATM_TOT_ENQ_CNTL(queue_id),
+			   LSP_QID_ATM_TOT_ENQ_CNTL_RST);
+
+		DLB_CSR_WR(hw,
+			   LSP_QID_ATM_TOT_ENQ_CNTH(queue_id),
+			   LSP_QID_ATM_TOT_ENQ_CNTH_RST);
+
+		DLB_CSR_WR(hw,
+			   LSP_QID_NALDB_MAX_DEPTH(queue_id),
+			   LSP_QID_NALDB_MAX_DEPTH_RST);
+
+		DLB_CSR_WR(hw,
+			   LSP_QID_LDB_INFL_LIM(queue_id),
+			   LSP_QID_LDB_INFL_LIM_RST);
+
+		DLB_CSR_WR(hw,
+			   LSP_QID_AQED_ACTIVE_LIM(queue_id),
+			   LSP_QID_AQED_ACTIVE_LIM_RST);
+
+		DLB_CSR_WR(hw,
+			   LSP_QID_ATM_DEPTH_THRSH(queue_id),
+			   LSP_QID_ATM_DEPTH_THRSH_RST);
+
+		DLB_CSR_WR(hw,
+			   LSP_QID_NALDB_DEPTH_THRSH(queue_id),
+			   LSP_QID_NALDB_DEPTH_THRSH_RST);
+
+		DLB_CSR_WR(hw,
+			   SYS_LDB_QID_ITS(queue_id),
+			   SYS_LDB_QID_ITS_RST);
+
+		DLB_CSR_WR(hw,
+			   CHP_ORD_QID_SN(queue_id),
+			   CHP_ORD_QID_SN_RST);
+
+		DLB_CSR_WR(hw,
+			   CHP_ORD_QID_SN_MAP(queue_id),
+			   CHP_ORD_QID_SN_MAP_RST);
+
+		DLB_CSR_WR(hw,
+			   SYS_LDB_QID_V(queue_id),
+			   SYS_LDB_QID_V_RST);
+
+		DLB_CSR_WR(hw,
+			   SYS_LDB_QID_CFG_V(queue_id),
+			   SYS_LDB_QID_CFG_V_RST);
+
+		if (queue->sn_cfg_valid) {
+			u32 offs[2];
+
+			offs[0] = RO_GRP_0_SLT_SHFT(queue->sn_slot);
+			offs[1] = RO_GRP_1_SLT_SHFT(queue->sn_slot);
+
+			DLB_CSR_WR(hw,
+				   offs[queue->sn_group],
+				   RO_GRP_0_SLT_SHFT_RST);
+		}
+
+		for (i = 0; i < LSP_QID2CQIDIX_NUM; i++) {
+			DLB_CSR_WR(hw,
+				   LSP_QID2CQIDIX(queue_id, i),
+				   LSP_QID2CQIDIX_00_RST);
+
+			DLB_CSR_WR(hw,
+				   LSP_QID2CQIDIX2(queue_id, i),
+				   LSP_QID2CQIDIX2_00_RST);
+
+			DLB_CSR_WR(hw,
+				   ATM_QID2CQIDIX(queue_id, i),
+				   ATM_QID2CQIDIX_00_RST);
+		}
+	}
+}
+
+static void dlb_domain_reset_dir_queue_registers(struct dlb_hw *hw,
+						 struct dlb_hw_domain *domain)
+{
+	struct dlb_dir_pq_pair *queue;
+
+	list_for_each_entry(queue, &domain->used_dir_pq_pairs, domain_list) {
+		DLB_CSR_WR(hw,
+			   LSP_QID_DIR_MAX_DEPTH(queue->id),
+			   LSP_QID_DIR_MAX_DEPTH_RST);
+
+		DLB_CSR_WR(hw,
+			   LSP_QID_DIR_TOT_ENQ_CNTL(queue->id),
+			   LSP_QID_DIR_TOT_ENQ_CNTL_RST);
+
+		DLB_CSR_WR(hw,
+			   LSP_QID_DIR_TOT_ENQ_CNTH(queue->id),
+			   LSP_QID_DIR_TOT_ENQ_CNTH_RST);
+
+		DLB_CSR_WR(hw,
+			   LSP_QID_DIR_DEPTH_THRSH(queue->id),
+			   LSP_QID_DIR_DEPTH_THRSH_RST);
+
+		DLB_CSR_WR(hw,
+			   SYS_DIR_QID_ITS(queue->id),
+			   SYS_DIR_QID_ITS_RST);
+
+		DLB_CSR_WR(hw,
+			   SYS_DIR_QID_V(queue->id),
+			   SYS_DIR_QID_V_RST);
+	}
+}
+
+static void dlb_domain_reset_registers(struct dlb_hw *hw,
+				       struct dlb_hw_domain *domain)
+{
+	dlb_domain_reset_ldb_port_registers(hw, domain);
+
+	dlb_domain_reset_dir_port_registers(hw, domain);
+
+	dlb_domain_reset_ldb_queue_registers(hw, domain);
+
+	dlb_domain_reset_dir_queue_registers(hw, domain);
+
+	DLB_CSR_WR(hw,
+		   CHP_CFG_LDB_VAS_CRD(domain->id),
+		   CHP_CFG_LDB_VAS_CRD_RST);
+
+	DLB_CSR_WR(hw,
+		   CHP_CFG_DIR_VAS_CRD(domain->id),
+		   CHP_CFG_DIR_VAS_CRD_RST);
+}
+
 static void dlb_log_reset_domain(struct dlb_hw *hw, u32 domain_id)
 {
 	dev_dbg(hw_to_dev(hw), "DLB reset domain:\n");
@@ -927,6 +1311,9 @@ int dlb_reset_domain(struct dlb_hw *hw, u32 domain_id)
 	if (!domain || !domain->configured)
 		return -EINVAL;
 
+	/* Reset the QID and port state. */
+	dlb_domain_reset_registers(hw, domain);
+
 	return dlb_domain_reset_software_state(hw, domain);
 }
 
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [RFC PATCH v12 08/17] dlb: add runtime power-management support
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
                   ` (6 preceding siblings ...)
  2021-12-21  6:50 ` [RFC PATCH v12 07/17] dlb: add low-level register reset operations Mike Ximing Chen
@ 2021-12-21  6:50 ` Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 09/17] dlb: add queue create, reset, get-depth configfs interface Mike Ximing Chen
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

Implemented a power-management policy of putting the device in D0 when in
use (when there are any open device files or memory mappings, or there are
any virtual devices), and D3Hot otherwise.

Add resume/suspend callbacks; when the device resumes, reset the hardware
to a known good state.

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
---
 drivers/misc/dlb/dlb_main.c   | 98 ++++++++++++++++++++++++++++++++++-
 drivers/misc/dlb/dlb_pf_ops.c |  8 +++
 2 files changed, 105 insertions(+), 1 deletion(-)

diff --git a/drivers/misc/dlb/dlb_main.c b/drivers/misc/dlb/dlb_main.c
index 343bf72dc9c7..4b263e849061 100644
--- a/drivers/misc/dlb/dlb_main.c
+++ b/drivers/misc/dlb/dlb_main.c
@@ -8,6 +8,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/pm_runtime.h>
 #include <linux/uaccess.h>
 
 #include "dlb_main.h"
@@ -72,12 +73,32 @@ static int dlb_open(struct inode *i, struct file *f)
 	f->private_data = dlb;
 	dlb->f = f;
 
+	/*
+	 * Increment the device's usage count and immediately wake it
+	 * if it was suspended.
+	 */
+	pm_runtime_get_sync(&dlb->pdev->dev);
+
+	return 0;
+}
+
+static int dlb_close(struct inode *i, struct file *f)
+{
+	struct dlb *dlb = f->private_data;
+
+	/*
+	 * Decrement the device's usage count and suspend it when
+	 * the application stops using it.
+	 */
+	pm_runtime_put_sync_suspend(&dlb->pdev->dev);
+
 	return 0;
 }
 
 static const struct file_operations dlb_fops = {
 	.owner   = THIS_MODULE,
 	.open    = dlb_open,
+	.release = dlb_close,
 };
 
 int dlb_init_domain(struct dlb *dlb, u32 domain_id)
@@ -95,6 +116,12 @@ int dlb_init_domain(struct dlb *dlb, u32 domain_id)
 
 	dlb->sched_domains[domain_id] = domain;
 
+	/*
+	 * The matching put is in dlb_free_domain, executed when the domain's
+	 * refcnt reaches zero.
+	 */
+	pm_runtime_get_sync(&dlb->pdev->dev);
+
 	return 0;
 }
 
@@ -119,7 +146,21 @@ static int __dlb_free_domain(struct dlb_domain *domain)
 
 void dlb_free_domain(struct kref *kref)
 {
-	__dlb_free_domain(container_of(kref, struct dlb_domain, refcnt));
+	struct dlb_domain *domain;
+	struct dlb *dlb;
+
+	domain = container_of(kref, struct dlb_domain, refcnt);
+
+	dlb = domain->dlb;
+
+	__dlb_free_domain(domain);
+
+	/*
+	 * Decrement the device's usage count and suspend it when
+	 * the last application stops using it. The matching get is in
+	 * dlb_init_domain.
+	 */
+	pm_runtime_put_sync_suspend(&dlb->pdev->dev);
 }
 
 static int dlb_domain_close(struct inode *i, struct file *f)
@@ -230,6 +271,14 @@ static int dlb_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
 	if (ret)
 		goto init_driver_state_fail;
 
+	/*
+	 * Undo the 'get' operation by the PCI layer during probe and
+	 * (if PF) immediately suspend the device. Since the device is only
+	 * enabled when an application requests it, an autosuspend delay is
+	 * likely not beneficial.
+	 */
+	pm_runtime_put_sync_suspend(&pdev->dev);
+
 	return 0;
 
 init_driver_state_fail:
@@ -254,6 +303,9 @@ static void dlb_remove(struct pci_dev *pdev)
 {
 	struct dlb *dlb = pci_get_drvdata(pdev);
 
+	/* Undo the PM operation in dlb_probe(). */
+	pm_runtime_get_noresume(&pdev->dev);
+
 	dlb_resource_free(&dlb->hw);
 
 	device_destroy(dlb_class, dlb->dev_number);
@@ -265,17 +317,61 @@ static void dlb_remove(struct pci_dev *pdev)
 	mutex_unlock(&dlb_ids_lock);
 }
 
+#ifdef CONFIG_PM
+static void dlb_reset_hardware_state(struct dlb *dlb)
+{
+	dlb_reset_device(dlb->pdev);
+}
+
+static int dlb_runtime_suspend(struct device *dev)
+{
+	/* Return and let the PCI subsystem put the device in D3hot. */
+
+	return 0;
+}
+
+static int dlb_runtime_resume(struct device *dev)
+{
+	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+	struct dlb *dlb = pci_get_drvdata(pdev);
+	int ret;
+
+	/*
+	 * The PCI subsystem put the device in D0, but the device may not have
+	 * completed powering up. Wait until the device is ready before
+	 * proceeding.
+	 */
+	ret = dlb_pf_wait_for_device_ready(dlb, pdev);
+	if (ret)
+		return ret;
+
+	/* Now reinitialize the device state. */
+	dlb_reset_hardware_state(dlb);
+
+	return 0;
+}
+#endif
+
 static struct pci_device_id dlb_id_table[] = {
 	{ PCI_DEVICE_DATA(INTEL, DLB_PF, DLB_PF) },
 	{ 0 }
 };
 MODULE_DEVICE_TABLE(pci, dlb_id_table);
 
+#ifdef CONFIG_PM
+static const struct dev_pm_ops dlb_pm_ops = {
+	SET_RUNTIME_PM_OPS(dlb_runtime_suspend, dlb_runtime_resume, NULL)
+};
+#endif
+
 static struct pci_driver dlb_pci_driver = {
 	.name		 = "dlb",
 	.id_table	 = dlb_id_table,
 	.probe		 = dlb_probe,
 	.remove		 = dlb_remove,
+#ifdef CONFIG_PM
+	.driver.pm	 = &dlb_pm_ops,
+#endif
 };
 
 static int __init dlb_init_module(void)
diff --git a/drivers/misc/dlb/dlb_pf_ops.c b/drivers/misc/dlb/dlb_pf_ops.c
index 8d179beb9d5b..65213c0475e5 100644
--- a/drivers/misc/dlb/dlb_pf_ops.c
+++ b/drivers/misc/dlb/dlb_pf_ops.c
@@ -2,6 +2,7 @@
 /* Copyright(C) 2016-2020 Intel Corporation. All rights reserved. */
 
 #include <linux/delay.h>
+#include <linux/pm_runtime.h>
 
 #include "dlb_main.h"
 #include "dlb_regs.h"
@@ -43,6 +44,13 @@ int dlb_pf_init_driver_state(struct dlb *dlb)
 {
 	mutex_init(&dlb->resource_mutex);
 
+	/*
+	 * Allow PF runtime power-management (forbidden by default by the PCI
+	 * layer during scan). The driver puts the device into D3hot while
+	 * there are no scheduling domains to service.
+	 */
+	pm_runtime_allow(&dlb->pdev->dev);
+
 	return 0;
 }
 
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [RFC PATCH v12 09/17] dlb: add queue create, reset, get-depth configfs interface
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
                   ` (7 preceding siblings ...)
  2021-12-21  6:50 ` [RFC PATCH v12 08/17] dlb: add runtime power-management support Mike Ximing Chen
@ 2021-12-21  6:50 ` Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 10/17] dlb: add register operations for queue management Mike Ximing Chen
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

Add configfs interface to create DLB queues and query their depth, and the
corresponding scheduling domain reset code to drain the queues when they
are no longer in use.

When a CPU enqueues a queue entry (QE) to DLB, the QE entry is sent to
a DLB queue. These queues hold queue entries (QEs) that have not yet
been scheduled to a destination port. The queue's depth is the number of
QEs residing in a queue.

Each queue supports multiple priority levels, and while a directed queue
has a 1:1 mapping with a directed port, load-balanced queues can be
configured with a set of load-balanced ports that software desires the
queue's QEs to be scheduled to.

For ease of review, this commit is limited to higher-level code including
the configfs interface, request verification, and debug log messages. All
low level register access/configuration code will be included in a
subsequent commit.

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
---
 drivers/misc/dlb/dlb_args.h     | 110 +++++++
 drivers/misc/dlb/dlb_configfs.c | 276 ++++++++++++++++
 drivers/misc/dlb/dlb_configfs.h |  58 ++++
 drivers/misc/dlb/dlb_main.h     |  41 +++
 drivers/misc/dlb/dlb_resource.c | 538 ++++++++++++++++++++++++++++++++
 include/uapi/linux/dlb.h        |   9 +
 6 files changed, 1032 insertions(+)

diff --git a/drivers/misc/dlb/dlb_args.h b/drivers/misc/dlb/dlb_args.h
index a7541a6b0ebe..2a1584756e43 100644
--- a/drivers/misc/dlb/dlb_args.h
+++ b/drivers/misc/dlb/dlb_args.h
@@ -57,4 +57,114 @@ struct dlb_create_sched_domain_args {
 	__u32 num_ldb_credits;
 	__u32 num_dir_credits;
 };
+
+/*************************************************/
+/* 'domain' level control/access data structures */
+/*************************************************/
+
+/*
+ * dlb_create_ldb_queue_args: Used to configure a load-balanced queue.
+ *
+ * Output parameters:
+ * @response.status: Detailed error code. In certain cases, such as if the
+ *	request arg is invalid, the driver won't set status.
+ * @response.id: Queue ID.
+ *
+ * Input parameters:
+ * @num_atomic_inflights: This specifies the amount of temporary atomic QE
+ *	storage for this queue. If zero, the queue will not support atomic
+ *	scheduling.
+ * @num_sequence_numbers: This specifies the number of sequence numbers used
+ *	by this queue. If zero, the queue will not support ordered scheduling.
+ *	If non-zero, the queue will not support unordered scheduling.
+ * @num_qid_inflights: The maximum number of QEs that can be inflight
+ *	(scheduled to a CQ but not completed) at any time. If
+ *	num_sequence_numbers is non-zero, num_qid_inflights must be set equal
+ *	to num_sequence_numbers.
+ * @lock_id_comp_level: Lock ID compression level. Specifies the number of
+ *	unique lock IDs the queue should compress down to. Valid compression
+ *	levels: 0, 64, 128, 256, 512, 1k, 2k, 4k, 64k. If lock_id_comp_level is
+ *	0, the queue won't compress its lock IDs.
+ * @depth_threshold: DLB sets two bits in the received QE to indicate the
+ *	depth of the queue relative to the threshold before scheduling the
+ *	QE to a CQ:
+ *	- 2’b11: depth > threshold
+ *	- 2’b10: threshold >= depth > 0.75 * threshold
+ *	- 2’b01: 0.75 * threshold >= depth > 0.5 * threshold
+ *	- 2’b00: depth <= 0.5 * threshold
+ */
+struct dlb_create_ldb_queue_args {
+	/* Output parameters */
+	struct dlb_cmd_response response;
+	/* Input parameters */
+	__u32 num_sequence_numbers;
+	__u32 num_qid_inflights;
+	__u32 num_atomic_inflights;
+	__u32 lock_id_comp_level;
+	__u32 depth_threshold;
+};
+
+/*
+ * dlb_create_dir_queue_args: Used to configure a directed queue.
+ *
+ * Output parameters:
+ * @response.status: Detailed error code. In certain cases, such as if the
+ *	request arg is invalid, the driver won't set status.
+ * @response.id: Queue ID.
+ *
+ * Input parameters:
+ * @port_id: Port ID. If the corresponding directed port is already created,
+ *	specify its ID here. Else this argument must be 0xFFFFFFFF to indicate
+ *	that the queue is being created before the port.
+ * @depth_threshold: DLB sets two bits in the received QE to indicate the
+ *	depth of the queue relative to the threshold before scheduling the
+ *	QE to a CQ:
+ *	- 2’b11: depth > threshold
+ *	- 2’b10: threshold >= depth > 0.75 * threshold
+ *	- 2’b01: 0.75 * threshold >= depth > 0.5 * threshold
+ *	- 2’b00: depth <= 0.5 * threshold
+ */
+struct dlb_create_dir_queue_args {
+	/* Output parameters */
+	struct dlb_cmd_response response;
+	/* Input parameters */
+	__s32 port_id;
+	__u32 depth_threshold;
+};
+
+/*
+ * dlb_get_ldb_queue_depth_args: Used to get a load-balanced queue's depth.
+ *
+ * Output parameters:
+ * @response.status: Detailed error code. In certain cases, such as if the
+ *	request arg is invalid, the driver won't set status.
+ * @response.id: queue depth.
+ *
+ * Input parameters:
+ * @queue_id: The load-balanced queue ID.
+ */
+struct dlb_get_ldb_queue_depth_args {
+	/* Output parameters */
+	struct dlb_cmd_response response;
+	/* Input parameters */
+	__u32 queue_id;
+};
+
+/*
+ * dlb_get_dir_queue_depth_args: Used to get a directed queue's depth.
+ *
+ * Output parameters:
+ * @response.status: Detailed error code. In certain cases, such as if the
+ *	request arg is invalid, the driver won't set status.
+ * @response.id: queue depth.
+ *
+ * Input parameters:
+ * @queue_id: The directed queue ID.
+ */
+struct dlb_get_dir_queue_depth_args {
+	/* Output parameters */
+	struct dlb_cmd_response response;
+	/* Input parameters */
+	__u32 queue_id;
+};
 #endif /* DLB_ARGS_H */
diff --git a/drivers/misc/dlb/dlb_configfs.c b/drivers/misc/dlb/dlb_configfs.c
index dc4d1a3bae0f..f47d3d9b96ba 100644
--- a/drivers/misc/dlb/dlb_configfs.c
+++ b/drivers/misc/dlb/dlb_configfs.c
@@ -9,6 +9,42 @@
 
 struct dlb_device_configfs dlb_dev_configfs[16];
 
+/*
+ * DLB domain configfs callback template minimizes replication of boilerplate
+ * code to copy arguments, acquire and release the resource lock, and execute
+ * the command.  The arguments and response structure name should have the
+ * format dlb_<lower_name>_args.
+ */
+#define DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(lower_name)		   \
+static int dlb_domain_configfs_##lower_name(struct dlb *dlb,		   \
+				   struct dlb_domain *domain,		   \
+				   void *karg)				   \
+{									   \
+	struct dlb_cmd_response response = {0};				   \
+	struct dlb_##lower_name##_args *arg = karg;			   \
+	int ret;							   \
+									   \
+	mutex_lock(&dlb->resource_mutex);				   \
+									   \
+	ret = dlb_hw_##lower_name(&dlb->hw,				   \
+				  domain->id,				   \
+				  arg,					   \
+				  &response);				   \
+									   \
+	mutex_unlock(&dlb->resource_mutex);				   \
+									   \
+	BUILD_BUG_ON(offsetof(typeof(*arg), response) != 0);		   \
+									   \
+	memcpy(karg, &response, sizeof(response));			   \
+									   \
+	return ret;							   \
+}
+
+DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(create_ldb_queue)
+DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(create_dir_queue)
+DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(get_ldb_queue_depth)
+DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(get_dir_queue_depth)
+
 static int dlb_configfs_create_sched_domain(struct dlb *dlb,
 					    void *karg)
 {
@@ -87,6 +123,213 @@ static int dlb_configfs_create_sched_domain(struct dlb *dlb,
  *                    ...
  */
 
+/*
+ * ------ Configfs for dlb queues ---------
+ *
+ * These are the templates for show and store functions in queue
+ * groups/directories, which minimizes replication of boilerplate
+ * code to copy arguments. All attributes, except for "create" store,
+ * use the template. "name" is the attribute name in the group.
+ */
+#define DLB_CONFIGFS_QUEUE_SHOW(name)				\
+static ssize_t dlb_cfs_queue_##name##_show(			\
+	struct config_item *item,				\
+	char *page)						\
+{								\
+	return sprintf(page, "%u\n",				\
+	       to_dlb_cfs_queue(item)->name);			\
+}								\
+
+#define DLB_CONFIGFS_QUEUE_STORE(name)				\
+static ssize_t dlb_cfs_queue_##name##_store(			\
+	struct config_item *item,				\
+	const char *page,					\
+	size_t count)						\
+{								\
+	struct dlb_cfs_queue *dlb_cfs_queue =			\
+				to_dlb_cfs_queue(item);		\
+	int ret;						\
+								\
+	ret = kstrtoint(page, 10,				\
+			 &dlb_cfs_queue->name);			\
+	if (ret)						\
+		return ret;					\
+								\
+	return count;						\
+}								\
+
+static ssize_t dlb_cfs_queue_queue_depth_show(struct config_item *item,
+					      char *page)
+{
+	struct dlb_cfs_queue *dlb_cfs_queue = to_dlb_cfs_queue(item);
+	struct dlb_domain *dlb_domain;
+	struct dlb *dlb = NULL;
+	int ret;
+
+	ret = dlb_configfs_get_dlb_domain(dlb_cfs_queue->domain_grp,
+					  &dlb, &dlb_domain);
+	if (ret)
+		return ret;
+
+	if (dlb_cfs_queue->is_ldb) {
+		struct dlb_get_ldb_queue_depth_args args = {0};
+
+		args.queue_id = dlb_cfs_queue->queue_id;
+		ret = dlb_domain_configfs_get_ldb_queue_depth(dlb,
+						dlb_domain, &args);
+
+		dlb_cfs_queue->status = args.response.status;
+		dlb_cfs_queue->queue_depth = args.response.id;
+	} else {
+		struct dlb_get_dir_queue_depth_args args = {0};
+
+		args.queue_id = dlb_cfs_queue->queue_id;
+		ret = dlb_domain_configfs_get_dir_queue_depth(dlb,
+						dlb_domain, &args);
+
+		dlb_cfs_queue->status = args.response.status;
+		dlb_cfs_queue->queue_depth = args.response.id;
+	}
+
+	if (ret) {
+		dev_err(dlb->dev,
+			"Getting queue depth failed: ret=%d\n", ret);
+		return ret;
+	}
+
+	return sprintf(page, "%u\n", dlb_cfs_queue->queue_depth);
+}
+
+DLB_CONFIGFS_QUEUE_SHOW(status)
+DLB_CONFIGFS_QUEUE_SHOW(queue_id)
+DLB_CONFIGFS_QUEUE_SHOW(is_ldb)
+DLB_CONFIGFS_QUEUE_SHOW(depth_threshold)
+DLB_CONFIGFS_QUEUE_SHOW(num_sequence_numbers)
+DLB_CONFIGFS_QUEUE_SHOW(num_qid_inflights)
+DLB_CONFIGFS_QUEUE_SHOW(num_atomic_inflights)
+DLB_CONFIGFS_QUEUE_SHOW(lock_id_comp_level)
+DLB_CONFIGFS_QUEUE_SHOW(port_id)
+DLB_CONFIGFS_QUEUE_SHOW(create)
+
+DLB_CONFIGFS_QUEUE_STORE(is_ldb)
+DLB_CONFIGFS_QUEUE_STORE(depth_threshold)
+DLB_CONFIGFS_QUEUE_STORE(num_sequence_numbers)
+DLB_CONFIGFS_QUEUE_STORE(num_qid_inflights)
+DLB_CONFIGFS_QUEUE_STORE(num_atomic_inflights)
+DLB_CONFIGFS_QUEUE_STORE(lock_id_comp_level)
+DLB_CONFIGFS_QUEUE_STORE(port_id)
+
+static ssize_t dlb_cfs_queue_create_store(struct config_item *item,
+					  const char *page, size_t count)
+{
+	struct dlb_cfs_queue *dlb_cfs_queue = to_dlb_cfs_queue(item);
+	struct dlb_domain *dlb_domain;
+	struct dlb *dlb = NULL;
+	int ret;
+
+	ret = dlb_configfs_get_dlb_domain(dlb_cfs_queue->domain_grp,
+					  &dlb, &dlb_domain);
+	if (ret)
+		return ret;
+
+	ret = kstrtoint(page, 10, &dlb_cfs_queue->create);
+	if (ret)
+		return ret;
+
+	if (dlb_cfs_queue->create == 0)  /* ToDo ? */
+		return count;
+
+	if (dlb_cfs_queue->is_ldb) {
+		struct dlb_create_ldb_queue_args args = {0};
+
+		args.num_sequence_numbers = dlb_cfs_queue->num_sequence_numbers;
+		args.num_qid_inflights = dlb_cfs_queue->num_qid_inflights;
+		args.num_atomic_inflights = dlb_cfs_queue->num_atomic_inflights;
+		args.lock_id_comp_level = dlb_cfs_queue->lock_id_comp_level;
+		args.depth_threshold = dlb_cfs_queue->depth_threshold;
+
+		dev_dbg(dlb->dev,
+			"Creating ldb queue: %s\n",
+			dlb_cfs_queue->group.cg_item.ci_namebuf);
+
+		ret = dlb_domain_configfs_create_ldb_queue(dlb, dlb_domain, &args);
+
+		dlb_cfs_queue->status = args.response.status;
+		dlb_cfs_queue->queue_id = args.response.id;
+	} else {
+		struct dlb_create_dir_queue_args args = {0};
+
+		args.port_id = dlb_cfs_queue->port_id;
+		args.depth_threshold = dlb_cfs_queue->depth_threshold;
+
+		dev_dbg(dlb->dev,
+			"Creating ldb queue: %s\n",
+			dlb_cfs_queue->group.cg_item.ci_namebuf);
+
+		ret = dlb_domain_configfs_create_dir_queue(dlb, dlb_domain, &args);
+
+		dlb_cfs_queue->status = args.response.status;
+		dlb_cfs_queue->queue_id = args.response.id;
+	}
+
+	if (ret) {
+		dev_err(dlb->dev,
+			"create queue() failed: ret=%d is_ldb=%u\n", ret,
+			dlb_cfs_queue->is_ldb);
+		return ret;
+	}
+
+	return count;
+}
+
+CONFIGFS_ATTR_RO(dlb_cfs_queue_, status);
+CONFIGFS_ATTR_RO(dlb_cfs_queue_, queue_id);
+CONFIGFS_ATTR_RO(dlb_cfs_queue_, queue_depth);
+CONFIGFS_ATTR(dlb_cfs_queue_, is_ldb);
+CONFIGFS_ATTR(dlb_cfs_queue_, depth_threshold);
+CONFIGFS_ATTR(dlb_cfs_queue_, num_sequence_numbers);
+CONFIGFS_ATTR(dlb_cfs_queue_, num_qid_inflights);
+CONFIGFS_ATTR(dlb_cfs_queue_, num_atomic_inflights);
+CONFIGFS_ATTR(dlb_cfs_queue_, lock_id_comp_level);
+CONFIGFS_ATTR(dlb_cfs_queue_, port_id);
+CONFIGFS_ATTR(dlb_cfs_queue_, create);
+
+static struct configfs_attribute *dlb_cfs_queue_attrs[] = {
+	&dlb_cfs_queue_attr_status,
+	&dlb_cfs_queue_attr_queue_id,
+	&dlb_cfs_queue_attr_queue_depth,
+	&dlb_cfs_queue_attr_is_ldb,
+	&dlb_cfs_queue_attr_depth_threshold,
+	&dlb_cfs_queue_attr_num_sequence_numbers,
+	&dlb_cfs_queue_attr_num_qid_inflights,
+	&dlb_cfs_queue_attr_num_atomic_inflights,
+	&dlb_cfs_queue_attr_lock_id_comp_level,
+	&dlb_cfs_queue_attr_port_id,
+	&dlb_cfs_queue_attr_create,
+
+	NULL,
+};
+
+static void dlb_cfs_queue_release(struct config_item *item)
+{
+	kfree(to_dlb_cfs_queue(item));
+}
+
+static struct configfs_item_operations dlb_cfs_queue_item_ops = {
+	.release	= dlb_cfs_queue_release,
+};
+
+/*
+ * Note that, since no extra work is required on ->drop_item(),
+ * no ->drop_item() is provided. no _group_ops either because we
+ * don't need to create any groups or items in queue configfs.
+ */
+static const struct config_item_type dlb_cfs_queue_type = {
+	.ct_item_ops	= &dlb_cfs_queue_item_ops,
+	.ct_attrs	= dlb_cfs_queue_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
 /*
  * ------ Configfs for dlb domains---------
  *
@@ -228,6 +471,30 @@ static struct configfs_attribute *dlb_cfs_domain_attrs[] = {
 	NULL,
 };
 
+static struct config_group *dlb_cfs_domain_make_queue_port(struct config_group *group,
+							   const char *name)
+{
+	if (strstr(name, "queue")) {
+		struct dlb_cfs_queue *dlb_cfs_queue;
+
+		dlb_cfs_queue = kzalloc(sizeof(*dlb_cfs_queue), GFP_KERNEL);
+		if (!dlb_cfs_queue)
+			return ERR_PTR(-ENOMEM);
+
+		dlb_cfs_queue->domain_grp = group;
+
+		config_group_init_type_name(&dlb_cfs_queue->group, name,
+					    &dlb_cfs_queue_type);
+
+		dlb_cfs_queue->queue_id = 0xffffffff;
+		dlb_cfs_queue->port_id = 0xffffffff;
+
+		return &dlb_cfs_queue->group;
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
 static void dlb_cfs_domain_release(struct config_item *item)
 {
 	kfree(to_dlb_cfs_domain(item));
@@ -237,8 +504,17 @@ static struct configfs_item_operations dlb_cfs_domain_item_ops = {
 	.release	= dlb_cfs_domain_release,
 };
 
+/*
+ * Note that, since no extra work is required on ->drop_item(),
+ * no ->drop_item() is provided.
+ */
+static struct configfs_group_operations dlb_cfs_domain_group_ops = {
+	.make_group     = dlb_cfs_domain_make_queue_port,
+};
+
 static const struct config_item_type dlb_cfs_domain_type = {
 	.ct_item_ops	= &dlb_cfs_domain_item_ops,
+	.ct_group_ops	= &dlb_cfs_domain_group_ops,
 	.ct_attrs	= dlb_cfs_domain_attrs,
 	.ct_owner	= THIS_MODULE,
 };
diff --git a/drivers/misc/dlb/dlb_configfs.h b/drivers/misc/dlb/dlb_configfs.h
index 03019e046429..e70b40560742 100644
--- a/drivers/misc/dlb/dlb_configfs.h
+++ b/drivers/misc/dlb/dlb_configfs.h
@@ -29,6 +29,35 @@ struct dlb_cfs_domain {
 
 };
 
+struct dlb_cfs_queue {
+	struct config_group group;
+	struct config_group *domain_grp;
+	unsigned int status;
+	unsigned int queue_id;
+	/* Input parameters */
+	unsigned int is_ldb;
+	unsigned int queue_depth;
+	unsigned int depth_threshold;
+	unsigned int create;
+
+	/* For LDB queue only */
+	unsigned int num_sequence_numbers;
+	unsigned int num_qid_inflights;
+	unsigned int num_atomic_inflights;
+	unsigned int lock_id_comp_level;
+
+	/* For DIR queue only, default = 0xffffffff */
+	unsigned int port_id;
+
+};
+
+static inline
+struct dlb_cfs_queue *to_dlb_cfs_queue(struct config_item *item)
+{
+	return container_of(to_config_group(item),
+			    struct dlb_cfs_queue, group);
+}
+
 static inline
 struct dlb_cfs_domain *to_dlb_cfs_domain(struct config_item *item)
 {
@@ -36,4 +65,33 @@ struct dlb_cfs_domain *to_dlb_cfs_domain(struct config_item *item)
 			    struct dlb_cfs_domain, group);
 }
 
+/*
+ * Get the dlb and dlb_domain pointers from the domain configfs group
+ * in the dlb_cfs_domain structure.
+ */
+static
+int dlb_configfs_get_dlb_domain(struct config_group *domain_grp,
+				struct dlb **dlb,
+				struct dlb_domain **dlb_domain)
+{
+	struct dlb_device_configfs *dlb_dev_configfs;
+	struct dlb_cfs_domain *dlb_cfs_domain;
+
+	dlb_cfs_domain = container_of(domain_grp, struct dlb_cfs_domain, group);
+
+	dlb_dev_configfs = container_of(dlb_cfs_domain->dev_grp,
+					struct dlb_device_configfs,
+					dev_group);
+	*dlb = dlb_dev_configfs->dlb;
+
+	if (!*dlb)
+		return -EINVAL;
+
+	*dlb_domain = (*dlb)->sched_domains[dlb_cfs_domain->domain_id];
+
+	if (!*dlb_domain)
+		return -EINVAL;
+
+	return 0;
+}
 #endif /* DLB_CONFIGFS_H */
diff --git a/drivers/misc/dlb/dlb_main.h b/drivers/misc/dlb/dlb_main.h
index b6e79397f312..7c63ab63991b 100644
--- a/drivers/misc/dlb/dlb_main.h
+++ b/drivers/misc/dlb/dlb_main.h
@@ -139,6 +139,35 @@ struct dlb_sn_group {
 	u32 id;
 };
 
+static inline bool dlb_sn_group_full(struct dlb_sn_group *group)
+{
+	/* SN mask
+	 *	0x0000ffff,  64 SNs per queue,   mode 0
+	 *	0x000000ff,  128 SNs per queue,  mode 1
+	 *	0x0000000f,  256 SNs per queue,  mode 2
+	 *	0x00000003,  512 SNs per queue,  mode 3
+	 *	0x00000001,  1024 SNs per queue, mode 4
+	 */
+	u32 mask = GENMASK(15 >> group->mode, 0);
+
+	return group->slot_use_bitmap == mask;
+}
+
+static inline int dlb_sn_group_alloc_slot(struct dlb_sn_group *group)
+{
+	u32 bound = 16 >> group->mode; /* {16, 8, 4, 2, 1} */
+	u32 i;
+
+	for (i = 0; i < bound; i++) {
+		if (!(group->slot_use_bitmap & BIT(i))) {
+			group->slot_use_bitmap |= BIT(i);
+			return i;
+		}
+	}
+
+	return -1;
+}
+
 static inline void
 dlb_sn_group_free_slot(struct dlb_sn_group *group, int slot)
 {
@@ -495,8 +524,20 @@ void dlb_resource_free(struct dlb_hw *hw);
 int dlb_hw_create_sched_domain(struct dlb_hw *hw,
 			       struct dlb_create_sched_domain_args *args,
 			       struct dlb_cmd_response *resp);
+int dlb_hw_create_ldb_queue(struct dlb_hw *hw, u32 domain_id,
+			    struct dlb_create_ldb_queue_args *args,
+			    struct dlb_cmd_response *resp);
+int dlb_hw_create_dir_queue(struct dlb_hw *hw, u32 domain_id,
+			    struct dlb_create_dir_queue_args *args,
+			    struct dlb_cmd_response *resp);
 int dlb_reset_domain(struct dlb_hw *hw, u32 domain_id);
 void dlb_clr_pmcsr_disable(struct dlb_hw *hw);
+int dlb_hw_get_ldb_queue_depth(struct dlb_hw *hw, u32 domain_id,
+			       struct dlb_get_ldb_queue_depth_args *args,
+			       struct dlb_cmd_response *resp);
+int dlb_hw_get_dir_queue_depth(struct dlb_hw *hw, u32 domain_id,
+			       struct dlb_get_dir_queue_depth_args *args,
+			       struct dlb_cmd_response *resp);
 
 /* Prototypes for dlb_configfs.c */
 int dlb_configfs_create_device(struct dlb *dlb);
diff --git a/drivers/misc/dlb/dlb_resource.c b/drivers/misc/dlb/dlb_resource.c
index 84f6cba6b681..971fc60ce93e 100644
--- a/drivers/misc/dlb/dlb_resource.c
+++ b/drivers/misc/dlb/dlb_resource.c
@@ -198,6 +198,38 @@ static struct dlb_hw_domain *dlb_get_domain_from_id(struct dlb_hw *hw, u32 id)
 	return &hw->domains[id];
 }
 
+static struct dlb_dir_pq_pair *
+dlb_get_domain_used_dir_pq(u32 id, bool vdev_req, struct dlb_hw_domain *domain)
+{
+	struct dlb_dir_pq_pair *port;
+
+	if (id >= DLB_MAX_NUM_DIR_PORTS)
+		return NULL;
+
+	list_for_each_entry(port, &domain->used_dir_pq_pairs, domain_list) {
+		if (!vdev_req && port->id == id)
+			return port;
+	}
+
+	return NULL;
+}
+
+static struct dlb_ldb_queue *
+dlb_get_domain_ldb_queue(u32 id, bool vdev_req, struct dlb_hw_domain *domain)
+{
+	struct dlb_ldb_queue *queue;
+
+	if (id >= DLB_MAX_NUM_LDB_QUEUES)
+		return NULL;
+
+	list_for_each_entry(queue, &domain->used_ldb_queues, domain_list) {
+		if (!vdev_req && queue->id == id)
+			return queue;
+	}
+
+	return NULL;
+}
+
 static int dlb_attach_ldb_queues(struct dlb_hw *hw,
 				 struct dlb_function_resources *rsrcs,
 				 struct dlb_hw_domain *domain, u32 num_queues,
@@ -586,6 +618,154 @@ dlb_verify_create_sched_dom_args(struct dlb_function_resources *rsrcs,
 	return 0;
 }
 
+static int
+dlb_verify_create_ldb_queue_args(struct dlb_hw *hw, u32 domain_id,
+				 struct dlb_create_ldb_queue_args *args,
+				 struct dlb_cmd_response *resp,
+				 struct dlb_hw_domain **out_domain,
+				 struct dlb_ldb_queue **out_queue)
+{
+	struct dlb_hw_domain *domain;
+	struct dlb_ldb_queue *queue;
+	int i;
+
+	domain = dlb_get_domain_from_id(hw, domain_id);
+
+	if (!domain) {
+		resp->status = DLB_ST_INVALID_DOMAIN_ID;
+		return -EINVAL;
+	}
+
+	if (!domain->configured) {
+		resp->status = DLB_ST_DOMAIN_NOT_CONFIGURED;
+		return -EINVAL;
+	}
+
+	if (domain->started) {
+		resp->status = DLB_ST_DOMAIN_STARTED;
+		return -EINVAL;
+	}
+
+	queue = list_first_entry_or_null(&domain->avail_ldb_queues,
+					 typeof(*queue), domain_list);
+	if (!queue) {
+		resp->status = DLB_ST_LDB_QUEUES_UNAVAILABLE;
+		return -EINVAL;
+	}
+
+	if (args->num_sequence_numbers) {
+		for (i = 0; i < DLB_MAX_NUM_SEQUENCE_NUMBER_GROUPS; i++) {
+			struct dlb_sn_group *group = &hw->rsrcs.sn_groups[i];
+
+			if (group->sequence_numbers_per_queue ==
+			    args->num_sequence_numbers &&
+			    !dlb_sn_group_full(group))
+				break;
+		}
+
+		if (i == DLB_MAX_NUM_SEQUENCE_NUMBER_GROUPS) {
+			resp->status = DLB_ST_SEQUENCE_NUMBERS_UNAVAILABLE;
+			return -EINVAL;
+		}
+	}
+
+	if (args->num_qid_inflights > 4096) {
+		resp->status = DLB_ST_INVALID_QID_INFLIGHT_ALLOCATION;
+		return -EINVAL;
+	}
+
+	/* Inflights must be <= number of sequence numbers if ordered */
+	if (args->num_sequence_numbers != 0 &&
+	    args->num_qid_inflights > args->num_sequence_numbers) {
+		resp->status = DLB_ST_INVALID_QID_INFLIGHT_ALLOCATION;
+		return -EINVAL;
+	}
+
+	if (domain->num_avail_aqed_entries < args->num_atomic_inflights) {
+		resp->status = DLB_ST_ATOMIC_INFLIGHTS_UNAVAILABLE;
+		return -EINVAL;
+	}
+
+	if (args->num_atomic_inflights &&
+	    args->lock_id_comp_level != 0 &&
+	    args->lock_id_comp_level != 64 &&
+	    args->lock_id_comp_level != 128 &&
+	    args->lock_id_comp_level != 256 &&
+	    args->lock_id_comp_level != 512 &&
+	    args->lock_id_comp_level != 1024 &&
+	    args->lock_id_comp_level != 2048 &&
+	    args->lock_id_comp_level != 4096 &&
+	    args->lock_id_comp_level != 65536) {
+		resp->status = DLB_ST_INVALID_LOCK_ID_COMP_LEVEL;
+		return -EINVAL;
+	}
+
+	*out_domain = domain;
+	*out_queue = queue;
+
+	return 0;
+}
+
+static int
+dlb_verify_create_dir_queue_args(struct dlb_hw *hw, u32 domain_id,
+				 struct dlb_create_dir_queue_args *args,
+				 struct dlb_cmd_response *resp,
+				 struct dlb_hw_domain **out_domain,
+				 struct dlb_dir_pq_pair **out_queue)
+{
+	struct dlb_hw_domain *domain;
+	struct dlb_dir_pq_pair *pq;
+
+	domain = dlb_get_domain_from_id(hw, domain_id);
+
+	if (!domain) {
+		resp->status = DLB_ST_INVALID_DOMAIN_ID;
+		return -EINVAL;
+	}
+
+	if (!domain->configured) {
+		resp->status = DLB_ST_DOMAIN_NOT_CONFIGURED;
+		return -EINVAL;
+	}
+
+	if (domain->started) {
+		resp->status = DLB_ST_DOMAIN_STARTED;
+		return -EINVAL;
+	}
+
+	/*
+	 * If the user claims the port is already configured, validate the port
+	 * ID, its domain, and whether the port is configured.
+	 */
+	if (args->port_id != -1) {
+		pq = dlb_get_domain_used_dir_pq(args->port_id,
+						false,
+						domain);
+
+		if (!pq || pq->domain_id != domain->id ||
+		    !pq->port_configured) {
+			resp->status = DLB_ST_INVALID_PORT_ID;
+			return -EINVAL;
+		}
+	} else {
+		/*
+		 * If the queue's port is not configured, validate that a free
+		 * port-queue pair is available.
+		 */
+		pq = list_first_entry_or_null(&domain->avail_dir_pq_pairs,
+					      typeof(*pq), domain_list);
+		if (!pq) {
+			resp->status = DLB_ST_DIR_QUEUES_UNAVAILABLE;
+			return -EINVAL;
+		}
+	}
+
+	*out_domain = domain;
+	*out_queue = pq;
+
+	return 0;
+}
+
 static void dlb_configure_domain_credits(struct dlb_hw *hw,
 					 struct dlb_hw_domain *domain)
 {
@@ -650,6 +830,68 @@ dlb_domain_attach_resources(struct dlb_hw *hw,
 	return 0;
 }
 
+static int
+dlb_ldb_queue_attach_to_sn_group(struct dlb_hw *hw,
+				 struct dlb_ldb_queue *queue,
+				 struct dlb_create_ldb_queue_args *args)
+{
+	int slot = -1;
+	int i;
+
+	queue->sn_cfg_valid = false;
+
+	if (args->num_sequence_numbers == 0)
+		return 0;
+
+	for (i = 0; i < DLB_MAX_NUM_SEQUENCE_NUMBER_GROUPS; i++) {
+		struct dlb_sn_group *group = &hw->rsrcs.sn_groups[i];
+
+		if (group->sequence_numbers_per_queue ==
+		    args->num_sequence_numbers &&
+		    !dlb_sn_group_full(group)) {
+			slot = dlb_sn_group_alloc_slot(group);
+			if (slot >= 0)
+				break;
+		}
+	}
+
+	if (slot == -1) {
+		dev_err(hw_to_dev(hw),
+			"[%s():%d] Internal error: no sequence number slots available\n",
+			__func__, __LINE__);
+		return -EFAULT;
+	}
+
+	queue->sn_cfg_valid = true;
+	queue->sn_group = i;
+	queue->sn_slot = slot;
+	return 0;
+}
+
+static int
+dlb_ldb_queue_attach_resources(struct dlb_hw *hw,
+			       struct dlb_hw_domain *domain,
+			       struct dlb_ldb_queue *queue,
+			       struct dlb_create_ldb_queue_args *args)
+{
+	int ret;
+
+	ret = dlb_ldb_queue_attach_to_sn_group(hw, queue, args);
+	if (ret)
+		return ret;
+
+	/* Attach QID inflights */
+	queue->num_qid_inflights = args->num_qid_inflights;
+
+	/* Attach atomic inflights */
+	queue->aqed_limit = args->num_atomic_inflights;
+
+	domain->num_avail_aqed_entries -= args->num_atomic_inflights;
+	domain->num_used_aqed_entries += args->num_atomic_inflights;
+
+	return 0;
+}
+
 static void
 dlb_log_create_sched_domain_args(struct dlb_hw *hw,
 				 struct dlb_create_sched_domain_args *args)
@@ -734,6 +976,145 @@ int dlb_hw_create_sched_domain(struct dlb_hw *hw,
 	return 0;
 }
 
+static void
+dlb_log_create_ldb_queue_args(struct dlb_hw *hw, u32 domain_id,
+			      struct dlb_create_ldb_queue_args *args)
+{
+	dev_dbg(hw_to_dev(hw), "DLB create load-balanced queue arguments:\n");
+	dev_dbg(hw_to_dev(hw), "\tDomain ID:                  %d\n",
+		domain_id);
+	dev_dbg(hw_to_dev(hw), "\tNumber of sequence numbers: %d\n",
+		args->num_sequence_numbers);
+	dev_dbg(hw_to_dev(hw), "\tNumber of QID inflights:    %d\n",
+		args->num_qid_inflights);
+	dev_dbg(hw_to_dev(hw), "\tNumber of ATM inflights:    %d\n",
+		args->num_atomic_inflights);
+}
+
+/**
+ * dlb_hw_create_ldb_queue() - create a load-balanced queue
+ * @hw: dlb_hw handle for a particular device.
+ * @domain_id: domain ID.
+ * @args: queue creation arguments.
+ * @resp: response structure.
+ *
+ * This function creates a load-balanced queue.
+ *
+ * Return:
+ * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
+ * assigned a detailed error code from enum dlb_error. If successful, resp->id
+ * contains the queue ID.
+ *
+ * Errors:
+ * EINVAL - A requested resource is unavailable, the domain is not configured,
+ *	    the domain has already been started, or the requested queue name is
+ *	    already in use.
+ * EFAULT - Internal error (resp->status not set).
+ */
+int dlb_hw_create_ldb_queue(struct dlb_hw *hw, u32 domain_id,
+			    struct dlb_create_ldb_queue_args *args,
+			    struct dlb_cmd_response *resp)
+{
+	struct dlb_hw_domain *domain;
+	struct dlb_ldb_queue *queue;
+	int ret;
+
+	dlb_log_create_ldb_queue_args(hw, domain_id, args);
+
+	/*
+	 * Verify that hardware resources are available before attempting to
+	 * satisfy the request. This simplifies the error unwinding code.
+	 */
+	ret = dlb_verify_create_ldb_queue_args(hw, domain_id, args, resp,
+					       &domain, &queue);
+	if (ret)
+		return ret;
+
+	ret = dlb_ldb_queue_attach_resources(hw, domain, queue, args);
+	if (ret) {
+		dev_err(hw_to_dev(hw),
+			"[%s():%d] Internal error: failed to attach the ldb queue resources\n",
+			__func__, __LINE__);
+		return ret;
+	}
+
+	queue->num_mappings = 0;
+
+	queue->configured = true;
+
+	/*
+	 * Configuration succeeded, so move the resource from the 'avail' to
+	 * the 'used' list.
+	 */
+	list_move(&queue->domain_list, &domain->used_ldb_queues);
+
+	resp->status = 0;
+	resp->id = queue->id;
+
+	return 0;
+}
+
+static void
+dlb_log_create_dir_queue_args(struct dlb_hw *hw, u32 domain_id,
+			      struct dlb_create_dir_queue_args *args)
+{
+	dev_dbg(hw_to_dev(hw), "DLB create directed queue arguments:\n");
+	dev_dbg(hw_to_dev(hw), "\tDomain ID: %d\n", domain_id);
+	dev_dbg(hw_to_dev(hw), "\tPort ID:   %d\n", args->port_id);
+}
+
+/**
+ * dlb_hw_create_dir_queue() - create a directed queue
+ * @hw: dlb_hw handle for a particular device.
+ * @domain_id: domain ID.
+ * @args: queue creation arguments.
+ * @resp: response structure.
+ *
+ * This function creates a directed queue.
+ *
+ * Return:
+ * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
+ * assigned a detailed error code from enum dlb_error. If successful, resp->id
+ * contains the queue ID.
+ *
+ * Errors:
+ * EINVAL - A requested resource is unavailable, the domain is not configured,
+ *	    or the domain has already been started.
+ * EFAULT - Internal error (resp->status not set).
+ */
+int dlb_hw_create_dir_queue(struct dlb_hw *hw, u32 domain_id,
+			    struct dlb_create_dir_queue_args *args,
+			    struct dlb_cmd_response *resp)
+{
+	struct dlb_dir_pq_pair *queue;
+	struct dlb_hw_domain *domain;
+	int ret;
+
+	dlb_log_create_dir_queue_args(hw, domain_id, args);
+
+	/*
+	 * Verify that hardware resources are available before attempting to
+	 * satisfy the request. This simplifies the error unwinding code.
+	 */
+	ret = dlb_verify_create_dir_queue_args(hw, domain_id, args, resp,
+					       &domain, &queue);
+	if (ret)
+		return ret;
+
+	/*
+	 * Configuration succeeded, so move the resource from the 'avail' to
+	 * the 'used' list (if it's not already there).
+	 */
+	if (args->port_id == -1)
+		list_move(&queue->domain_list, &domain->used_dir_pq_pairs);
+
+	resp->status = 0;
+
+	resp->id = queue->id;
+
+	return 0;
+}
+
 /*
  * dlb_domain_reset_software_state() - returns domain's resources
  * @hw: dlb_hw handle for a particular device.
@@ -890,6 +1271,131 @@ static int dlb_domain_reset_software_state(struct dlb_hw *hw,
 	return 0;
 }
 
+static void dlb_log_get_dir_queue_depth(struct dlb_hw *hw, u32 domain_id,
+					u32 queue_id)
+{
+	dev_dbg(hw_to_dev(hw), "DLB get directed queue depth:\n");
+	dev_dbg(hw_to_dev(hw), "\tDomain ID: %d\n", domain_id);
+	dev_dbg(hw_to_dev(hw), "\tQueue ID: %d\n", queue_id);
+}
+
+/**
+ * dlb_hw_get_dir_queue_depth() - returns the depth of a directed queue
+ * @hw: dlb_hw handle for a particular device.
+ * @domain_id: domain ID.
+ * @args: queue depth args
+ * @resp: response structure.
+ *
+ * This function returns the depth of a directed queue.
+ *
+ * Return:
+ * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
+ * assigned a detailed error code from enum dlb_error. If successful, resp->id
+ * contains the depth.
+ *
+ * Errors:
+ * EINVAL - Invalid domain ID or queue ID.
+ */
+int dlb_hw_get_dir_queue_depth(struct dlb_hw *hw, u32 domain_id,
+			       struct dlb_get_dir_queue_depth_args *args,
+			       struct dlb_cmd_response *resp)
+{
+	struct dlb_dir_pq_pair *queue;
+	struct dlb_hw_domain *domain;
+	int id;
+
+	id = domain_id;
+
+	dlb_log_get_dir_queue_depth(hw, domain_id, args->queue_id);
+
+	domain = dlb_get_domain_from_id(hw, id);
+	if (!domain) {
+		resp->status = DLB_ST_INVALID_DOMAIN_ID;
+		return -EINVAL;
+	}
+
+	id = args->queue_id;
+
+	queue = dlb_get_domain_used_dir_pq(id, false, domain);
+	if (!queue) {
+		resp->status = DLB_ST_INVALID_QID;
+		return -EINVAL;
+	}
+
+	resp->id = 0;
+
+	return 0;
+}
+
+static u32 dlb_ldb_queue_depth(struct dlb_hw *hw, struct dlb_ldb_queue *queue)
+{
+	u32 aqed, ldb, atm;
+
+	aqed = DLB_CSR_RD(hw, LSP_QID_AQED_ACTIVE_CNT(queue->id));
+	ldb = DLB_CSR_RD(hw, LSP_QID_LDB_ENQUEUE_CNT(queue->id));
+	atm = DLB_CSR_RD(hw, LSP_QID_ATM_ACTIVE(queue->id));
+
+	return FIELD_GET(LSP_QID_AQED_ACTIVE_CNT_COUNT, aqed)
+	       + FIELD_GET(LSP_QID_LDB_ENQUEUE_CNT_COUNT, ldb)
+	       + FIELD_GET(LSP_QID_ATM_ACTIVE_COUNT, atm);
+}
+
+static bool dlb_ldb_queue_is_empty(struct dlb_hw *hw, struct dlb_ldb_queue *queue)
+{
+	return dlb_ldb_queue_depth(hw, queue) == 0;
+}
+
+static void dlb_log_get_ldb_queue_depth(struct dlb_hw *hw, u32 domain_id,
+					u32 queue_id)
+{
+	dev_dbg(hw_to_dev(hw), "DLB get load-balanced queue depth:\n");
+	dev_dbg(hw_to_dev(hw), "\tDomain ID: %d\n", domain_id);
+	dev_dbg(hw_to_dev(hw), "\tQueue ID: %d\n", queue_id);
+}
+
+/**
+ * dlb_hw_get_ldb_queue_depth() - returns the depth of a load-balanced queue
+ * @hw: dlb_hw handle for a particular device.
+ * @domain_id: domain ID.
+ * @args: queue depth args
+ * @resp: response structure.
+ *
+ * This function returns the depth of a load-balanced queue.
+ *
+ * Return:
+ * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
+ * assigned a detailed error code from enum dlb_error. If successful, resp->id
+ * contains the depth.
+ *
+ * Errors:
+ * EINVAL - Invalid domain ID or queue ID.
+ */
+int dlb_hw_get_ldb_queue_depth(struct dlb_hw *hw, u32 domain_id,
+			       struct dlb_get_ldb_queue_depth_args *args,
+			       struct dlb_cmd_response *resp)
+{
+	struct dlb_hw_domain *domain;
+	struct dlb_ldb_queue *queue;
+
+	dlb_log_get_ldb_queue_depth(hw, domain_id, args->queue_id);
+
+	domain = dlb_get_domain_from_id(hw, domain_id);
+	if (!domain) {
+		resp->status = DLB_ST_INVALID_DOMAIN_ID;
+		return -EINVAL;
+	}
+
+	queue = dlb_get_domain_ldb_queue(args->queue_id, false, domain);
+	if (!queue) {
+		resp->status = DLB_ST_INVALID_QID;
+		return -EINVAL;
+	}
+
+	resp->id = 0;
+
+	return 0;
+}
+
 static void __dlb_domain_reset_ldb_port_registers(struct dlb_hw *hw,
 						  struct dlb_ldb_port *port)
 {
@@ -1254,6 +1760,27 @@ static void dlb_domain_reset_dir_queue_registers(struct dlb_hw *hw,
 	}
 }
 
+static int dlb_domain_verify_reset_success(struct dlb_hw *hw,
+					   struct dlb_hw_domain *domain)
+{
+	struct dlb_ldb_queue *queue;
+
+	/*
+	 * Confirm that all the domain's queue's inflight counts and AQED
+	 * active counts are 0.
+	 */
+	list_for_each_entry(queue, &domain->used_ldb_queues, domain_list) {
+		if (!dlb_ldb_queue_is_empty(hw, queue)) {
+			dev_err(hw_to_dev(hw),
+				"[%s()] Internal error: failed to empty ldb queue %d\n",
+				__func__, queue->id);
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
 static void dlb_domain_reset_registers(struct dlb_hw *hw,
 				       struct dlb_hw_domain *domain)
 {
@@ -1303,6 +1830,7 @@ static void dlb_log_reset_domain(struct dlb_hw *hw, u32 domain_id)
 int dlb_reset_domain(struct dlb_hw *hw, u32 domain_id)
 {
 	struct dlb_hw_domain *domain;
+	int ret;
 
 	dlb_log_reset_domain(hw, domain_id);
 
@@ -1311,6 +1839,16 @@ int dlb_reset_domain(struct dlb_hw *hw, u32 domain_id)
 	if (!domain || !domain->configured)
 		return -EINVAL;
 
+	/*
+	 * For each queue owned by this domain, disable its write permissions to
+	 * cause any traffic sent to it to be dropped. Well-behaved software
+	 * should not be sending QEs at this point.
+	 */
+
+	ret = dlb_domain_verify_reset_success(hw, domain);
+	if (ret)
+		return ret;
+
 	/* Reset the QID and port state. */
 	dlb_domain_reset_registers(hw, domain);
 
diff --git a/include/uapi/linux/dlb.h b/include/uapi/linux/dlb.h
index 580a5cafbe61..3586afbccdbf 100644
--- a/include/uapi/linux/dlb.h
+++ b/include/uapi/linux/dlb.h
@@ -19,5 +19,14 @@ enum dlb_error {
 	DLB_ST_HIST_LIST_ENTRIES_UNAVAILABLE,
 	DLB_ST_LDB_PORT_REQUIRED_FOR_LDB_QUEUES,
 	DLB_ST_DOMAIN_RESET_FAILED,
+	DLB_ST_INVALID_DOMAIN_ID,
+	DLB_ST_INVALID_QID_INFLIGHT_ALLOCATION,
+	DLB_ST_INVALID_LDB_QUEUE_ID,
+	DLB_ST_DOMAIN_NOT_CONFIGURED,
+	DLB_ST_INVALID_QID,
+	DLB_ST_DOMAIN_STARTED,
+	DLB_ST_DIR_QUEUES_UNAVAILABLE,
+	DLB_ST_INVALID_PORT_ID,
+	DLB_ST_INVALID_LOCK_ID_COMP_LEVEL,
 };
 #endif /* __DLB_H */
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [RFC PATCH v12 10/17] dlb: add register operations for queue management
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
                   ` (8 preceding siblings ...)
  2021-12-21  6:50 ` [RFC PATCH v12 09/17] dlb: add queue create, reset, get-depth configfs interface Mike Ximing Chen
@ 2021-12-21  6:50 ` Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 11/17] dlb: add configfs interface to configure ports Mike Ximing Chen
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

Add the low-level code for configuring a new queue and querying its depth.
When configuring a queue, program the device based on the user-supplied
queue configuration (from the corresponding configfs attributes).

Also add low-level code for resetting (draining) a non-empty queue during
scheduling domain reset. Draining a queue is an iterative process of
checking if the queue is empty, and if not then selecting a linked 'victim'
port and dequeueing the queue's events through this port. A port can only
receive a small number of events at a time, usually much fewer than the
queue depth, so draining a queue typically takes multiple iterations. This
process is finite since software cannot enqueue new events to the DLB's
(finite) on-device storage.

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
---
 drivers/misc/dlb/dlb_main.h     |  46 +++
 drivers/misc/dlb/dlb_resource.c | 574 +++++++++++++++++++++++++++++++-
 2 files changed, 618 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/dlb/dlb_main.h b/drivers/misc/dlb/dlb_main.h
index 7c63ab63991b..3bd2d9ee0a44 100644
--- a/drivers/misc/dlb/dlb_main.h
+++ b/drivers/misc/dlb/dlb_main.h
@@ -57,6 +57,52 @@
 
 #define PCI_DEVICE_ID_INTEL_DLB_PF		0x2710
 
+/*
+ * Hardware-defined base addresses. Those prefixed 'DLB_DRV' are only used by
+ * the PF driver.
+ */
+#define DLB_DRV_LDB_PP_BASE   0x2300000
+#define DLB_DRV_LDB_PP_STRIDE 0x1000
+#define DLB_DRV_LDB_PP_BOUND  (DLB_DRV_LDB_PP_BASE + \
+				DLB_DRV_LDB_PP_STRIDE * DLB_MAX_NUM_LDB_PORTS)
+#define DLB_DRV_DIR_PP_BASE   0x2200000
+#define DLB_DRV_DIR_PP_STRIDE 0x1000
+#define DLB_DRV_DIR_PP_BOUND  (DLB_DRV_DIR_PP_BASE + \
+				DLB_DRV_DIR_PP_STRIDE * DLB_MAX_NUM_DIR_PORTS)
+#define DLB_LDB_PP_BASE       0x2100000
+#define DLB_LDB_PP_STRIDE     0x1000
+#define DLB_LDB_PP_BOUND      (DLB_LDB_PP_BASE + \
+				DLB_LDB_PP_STRIDE * DLB_MAX_NUM_LDB_PORTS)
+#define DLB_LDB_PP_OFFSET(id) (DLB_LDB_PP_BASE + (id) * DLB_PP_SIZE)
+#define DLB_DIR_PP_BASE       0x2000000
+#define DLB_DIR_PP_STRIDE     0x1000
+#define DLB_DIR_PP_BOUND      (DLB_DIR_PP_BASE + \
+				DLB_DIR_PP_STRIDE * DLB_MAX_NUM_DIR_PORTS)
+#define DLB_DIR_PP_OFFSET(id) (DLB_DIR_PP_BASE + (id) * DLB_PP_SIZE)
+
+struct dlb_hcw {
+	u64 data;
+	/* Word 3 */
+	u16 opaque;
+	u8 qid;
+	u8 sched_type:2;
+	u8 priority:3;
+	u8 msg_type:3;
+	/* Word 4 */
+	u16 lock_id;
+	u8 ts_flag:1;
+	u8 rsvd1:2;
+	u8 no_dec:1;
+	u8 cmp_id:4;
+	u8 cq_token:1;
+	u8 qe_comp:1;
+	u8 qe_frag:1;
+	u8 qe_valid:1;
+	u8 int_arm:1;
+	u8 error:1;
+	u8 rsvd:2;
+};
+
 struct dlb_ldb_queue {
 	struct list_head domain_list;
 	struct list_head func_list;
diff --git a/drivers/misc/dlb/dlb_resource.c b/drivers/misc/dlb/dlb_resource.c
index 971fc60ce93e..83c000839f15 100644
--- a/drivers/misc/dlb/dlb_resource.c
+++ b/drivers/misc/dlb/dlb_resource.c
@@ -1,9 +1,21 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright(C) 2016-2020 Intel Corporation. All rights reserved. */
 
+#include <linux/log2.h>
 #include "dlb_regs.h"
 #include "dlb_main.h"
 
+/*
+ * The PF driver cannot assume that a register write will affect subsequent HCW
+ * writes. To ensure a write completes, the driver must read back a CSR. This
+ * function only need be called for configuration that can occur after the
+ * domain has started; prior to starting, applications can't send HCWs.
+ */
+static inline void dlb_flush_csr(struct dlb_hw *hw)
+{
+	DLB_CSR_RD(hw, SYS_TOTAL_VAS);
+}
+
 static void dlb_init_fn_rsrc_lists(struct dlb_function_resources *rsrc)
 {
 	int i;
@@ -766,6 +778,112 @@ dlb_verify_create_dir_queue_args(struct dlb_hw *hw, u32 domain_id,
 	return 0;
 }
 
+static void dlb_configure_ldb_queue(struct dlb_hw *hw,
+				    struct dlb_hw_domain *domain,
+				    struct dlb_ldb_queue *queue,
+				    struct dlb_create_ldb_queue_args *args)
+{
+	struct dlb_sn_group *sn_group;
+	unsigned int offs;
+	u32 reg = 0;
+	u32 alimit;
+	u32 level;
+
+	/* QID write permissions are turned on when the domain is started */
+	offs = domain->id * DLB_MAX_NUM_LDB_QUEUES + queue->id;
+
+	DLB_CSR_WR(hw, SYS_LDB_VASQID_V(offs), reg);
+
+	/*
+	 * Unordered QIDs get 4K inflights, ordered get as many as the number
+	 * of sequence numbers.
+	 */
+	reg = FIELD_PREP(LSP_QID_LDB_INFL_LIM_LIMIT, args->num_qid_inflights);
+	DLB_CSR_WR(hw, LSP_QID_LDB_INFL_LIM(queue->id), reg);
+
+	alimit = queue->aqed_limit;
+
+	if (alimit > DLB_MAX_NUM_AQED_ENTRIES)
+		alimit = DLB_MAX_NUM_AQED_ENTRIES;
+
+	reg = FIELD_PREP(LSP_QID_AQED_ACTIVE_LIM_LIMIT, alimit);
+	DLB_CSR_WR(hw, LSP_QID_AQED_ACTIVE_LIM(queue->id), reg);
+
+	level = args->lock_id_comp_level;
+	if (level >= 64 && level <= 4096 && is_power_of_2(level)) {
+		reg &= ~AQED_QID_HID_WIDTH_COMPRESS_CODE;
+		reg |= FIELD_PREP(AQED_QID_HID_WIDTH_COMPRESS_CODE, ilog2(level) - 5);
+	} else {
+		reg = 0;
+	}
+
+	DLB_CSR_WR(hw, AQED_QID_HID_WIDTH(queue->id), reg);
+
+	reg = 0;
+	/* Don't timestamp QEs that pass through this queue */
+	DLB_CSR_WR(hw, SYS_LDB_QID_ITS(queue->id), reg);
+
+	reg = FIELD_PREP(LSP_QID_ATM_DEPTH_THRSH_THRESH, args->depth_threshold);
+	DLB_CSR_WR(hw, LSP_QID_ATM_DEPTH_THRSH(queue->id), reg);
+
+	reg = FIELD_PREP(LSP_QID_NALDB_DEPTH_THRSH_THRESH, args->depth_threshold);
+	DLB_CSR_WR(hw, LSP_QID_NALDB_DEPTH_THRSH(queue->id), reg);
+
+	/*
+	 * This register limits the number of inflight flows a queue can have
+	 * at one time.  It has an upper bound of 2048, but can be
+	 * over-subscribed. 512 is chosen so that a single queue doesn't use
+	 * the entire atomic storage, but can use a substantial portion if
+	 * needed.
+	 */
+	reg = FIELD_PREP(AQED_QID_FID_LIM_QID_FID_LIMIT, 512);
+	DLB_CSR_WR(hw, AQED_QID_FID_LIM(queue->id), reg);
+
+	/* Configure SNs */
+	sn_group = &hw->rsrcs.sn_groups[queue->sn_group];
+	reg = FIELD_PREP(CHP_ORD_QID_SN_MAP_MODE, sn_group->mode);
+	reg |= FIELD_PREP(CHP_ORD_QID_SN_MAP_SLOT, queue->sn_slot);
+	reg |= FIELD_PREP(CHP_ORD_QID_SN_MAP_GRP, sn_group->id);
+
+	DLB_CSR_WR(hw, CHP_ORD_QID_SN_MAP(queue->id), reg);
+
+	reg = FIELD_PREP(SYS_LDB_QID_CFG_V_SN_CFG_V,
+		  (u32)(args->num_sequence_numbers != 0));
+	reg |= FIELD_PREP(SYS_LDB_QID_CFG_V_FID_CFG_V,
+		  (u32)(args->num_atomic_inflights != 0));
+
+	DLB_CSR_WR(hw, SYS_LDB_QID_CFG_V(queue->id), reg);
+
+	reg = SYS_LDB_QID_V_QID_V;
+	DLB_CSR_WR(hw, SYS_LDB_QID_V(queue->id), reg);
+}
+
+static void dlb_configure_dir_queue(struct dlb_hw *hw,
+				    struct dlb_hw_domain *domain,
+				    struct dlb_dir_pq_pair *queue,
+				    struct dlb_create_dir_queue_args *args)
+{
+	unsigned int offs;
+	u32 reg = 0;
+
+	/* QID write permissions are turned on when the domain is started */
+	offs = domain->id * DLB_MAX_NUM_DIR_QUEUES +
+		queue->id;
+
+	DLB_CSR_WR(hw, SYS_DIR_VASQID_V(offs), reg);
+
+	/* Don't timestamp QEs that pass through this queue */
+	DLB_CSR_WR(hw, SYS_DIR_QID_ITS(queue->id), reg);
+
+	reg = FIELD_PREP(LSP_QID_DIR_DEPTH_THRSH_THRESH, args->depth_threshold);
+	DLB_CSR_WR(hw, LSP_QID_DIR_DEPTH_THRSH(queue->id), reg);
+
+	reg = SYS_DIR_QID_V_QID_V;
+	DLB_CSR_WR(hw, SYS_DIR_QID_V(queue->id), reg);
+
+	queue->queue_configured = true;
+}
+
 static void dlb_configure_domain_credits(struct dlb_hw *hw,
 					 struct dlb_hw_domain *domain)
 {
@@ -892,6 +1010,56 @@ dlb_ldb_queue_attach_resources(struct dlb_hw *hw,
 	return 0;
 }
 
+static void dlb_ldb_port_cq_enable(struct dlb_hw *hw,
+				   struct dlb_ldb_port *port)
+{
+	u32 reg = 0;
+
+	/*
+	 * Don't re-enable the port if a removal is pending. The caller should
+	 * mark this port as enabled (if it isn't already), and when the
+	 * removal completes the port will be enabled.
+	 */
+	if (port->num_pending_removals)
+		return;
+
+	DLB_CSR_WR(hw, LSP_CQ_LDB_DSBL(port->id), reg);
+
+	dlb_flush_csr(hw);
+}
+
+static void dlb_ldb_port_cq_disable(struct dlb_hw *hw,
+				    struct dlb_ldb_port *port)
+{
+	u32 reg = 0;
+
+	reg |= LSP_CQ_LDB_DSBL_DISABLED;
+	DLB_CSR_WR(hw, LSP_CQ_LDB_DSBL(port->id), reg);
+
+	dlb_flush_csr(hw);
+}
+
+static void dlb_dir_port_cq_enable(struct dlb_hw *hw,
+				   struct dlb_dir_pq_pair *port)
+{
+	u32 reg = 0;
+
+	DLB_CSR_WR(hw, LSP_CQ_DIR_DSBL(port->id), reg);
+
+	dlb_flush_csr(hw);
+}
+
+static void dlb_dir_port_cq_disable(struct dlb_hw *hw,
+				    struct dlb_dir_pq_pair *port)
+{
+	u32 reg = 0;
+
+	reg |= LSP_CQ_DIR_DSBL_DISABLED;
+	DLB_CSR_WR(hw, LSP_CQ_DIR_DSBL(port->id), reg);
+
+	dlb_flush_csr(hw);
+}
+
 static void
 dlb_log_create_sched_domain_args(struct dlb_hw *hw,
 				 struct dlb_create_sched_domain_args *args)
@@ -1038,6 +1206,8 @@ int dlb_hw_create_ldb_queue(struct dlb_hw *hw, u32 domain_id,
 		return ret;
 	}
 
+	dlb_configure_ldb_queue(hw, domain, queue, args);
+
 	queue->num_mappings = 0;
 
 	queue->configured = true;
@@ -1101,6 +1271,8 @@ int dlb_hw_create_dir_queue(struct dlb_hw *hw, u32 domain_id,
 	if (ret)
 		return ret;
 
+	dlb_configure_dir_queue(hw, domain, queue, args);
+
 	/*
 	 * Configuration succeeded, so move the resource from the 'avail' to
 	 * the 'used' list (if it's not already there).
@@ -1115,6 +1287,92 @@ int dlb_hw_create_dir_queue(struct dlb_hw *hw, u32 domain_id,
 	return 0;
 }
 
+static u32 dlb_ldb_cq_inflight_count(struct dlb_hw *hw,
+				     struct dlb_ldb_port *port)
+{
+	u32 cnt;
+
+	cnt = DLB_CSR_RD(hw, LSP_CQ_LDB_INFL_CNT(port->id));
+
+	return FIELD_GET(LSP_CQ_LDB_INFL_CNT_COUNT, cnt);
+}
+
+static u32 dlb_ldb_cq_token_count(struct dlb_hw *hw, struct dlb_ldb_port *port)
+{
+	u32 cnt;
+
+	cnt = DLB_CSR_RD(hw, LSP_CQ_LDB_TKN_CNT(port->id));
+
+	/*
+	 * Account for the initial token count, which is used in order to
+	 * provide a CQ with depth less than 8.
+	 */
+
+	return FIELD_GET(LSP_CQ_LDB_TKN_CNT_TOKEN_COUNT, cnt) - port->init_tkn_cnt;
+}
+
+static void __iomem *dlb_producer_port_addr(struct dlb_hw *hw, u8 port_id,
+					    bool is_ldb)
+{
+	struct dlb *dlb = container_of(hw, struct dlb, hw);
+	uintptr_t address = (uintptr_t)dlb->hw.func_kva;
+	unsigned long size;
+
+	if (is_ldb) {
+		size = DLB_LDB_PP_STRIDE;
+		address += DLB_DRV_LDB_PP_BASE + size * port_id;
+	} else {
+		size = DLB_DIR_PP_STRIDE;
+		address += DLB_DRV_DIR_PP_BASE + size * port_id;
+	}
+
+	return (void __iomem *)address;
+}
+
+static void dlb_drain_ldb_cq(struct dlb_hw *hw, struct dlb_ldb_port *port)
+{
+	u32 infl_cnt, tkn_cnt;
+	unsigned int i;
+
+	infl_cnt = dlb_ldb_cq_inflight_count(hw, port);
+	tkn_cnt = dlb_ldb_cq_token_count(hw, port);
+
+	if (infl_cnt || tkn_cnt) {
+		struct dlb_hcw hcw_mem[8], *hcw;
+		void __iomem *pp_addr;
+
+		pp_addr = dlb_producer_port_addr(hw, port->id, true);
+
+		/* Point hcw to a 64B-aligned location */
+		hcw = (struct dlb_hcw *)((uintptr_t)&hcw_mem[4] & ~0x3F);
+
+		/*
+		 * Program the first HCW for a completion and token return and
+		 * the other HCWs as NOOPS
+		 */
+
+		memset(hcw, 0, 4 * sizeof(*hcw));
+		hcw->qe_comp = (infl_cnt > 0);
+		hcw->cq_token = (tkn_cnt > 0);
+		hcw->lock_id = tkn_cnt - 1;
+
+		/*
+		 * To ensure outstanding HCWs reach the device before subsequent
+		 * device accesses, fence them.
+		 */
+		wmb();
+
+		/* Return tokens in the first HCW */
+		iosubmit_cmds512(pp_addr, hcw, 1);
+
+		hcw->cq_token = 0;
+
+		/* Issue remaining completions (if any) */
+		for (i = 1; i < infl_cnt; i++)
+			iosubmit_cmds512(pp_addr, hcw, 1);
+	}
+}
+
 /*
  * dlb_domain_reset_software_state() - returns domain's resources
  * @hw: dlb_hw handle for a particular device.
@@ -1271,6 +1529,21 @@ static int dlb_domain_reset_software_state(struct dlb_hw *hw,
 	return 0;
 }
 
+static u32 dlb_dir_queue_depth(struct dlb_hw *hw, struct dlb_dir_pq_pair *queue)
+{
+	u32 cnt;
+
+	cnt = DLB_CSR_RD(hw, LSP_QID_DIR_ENQUEUE_CNT(queue->id));
+
+	return FIELD_GET(LSP_QID_DIR_ENQUEUE_CNT_COUNT, cnt);
+}
+
+static bool dlb_dir_queue_is_empty(struct dlb_hw *hw,
+				   struct dlb_dir_pq_pair *queue)
+{
+	return dlb_dir_queue_depth(hw, queue) == 0;
+}
+
 static void dlb_log_get_dir_queue_depth(struct dlb_hw *hw, u32 domain_id,
 					u32 queue_id)
 {
@@ -1322,7 +1595,7 @@ int dlb_hw_get_dir_queue_depth(struct dlb_hw *hw, u32 domain_id,
 		return -EINVAL;
 	}
 
-	resp->id = 0;
+	resp->id = dlb_dir_queue_depth(hw, queue);
 
 	return 0;
 }
@@ -1391,7 +1664,7 @@ int dlb_hw_get_ldb_queue_depth(struct dlb_hw *hw, u32 domain_id,
 		return -EINVAL;
 	}
 
-	resp->id = 0;
+	resp->id = dlb_ldb_queue_depth(hw, queue);
 
 	return 0;
 }
@@ -1760,6 +2033,21 @@ static void dlb_domain_reset_dir_queue_registers(struct dlb_hw *hw,
 	}
 }
 
+static u32 dlb_dir_cq_token_count(struct dlb_hw *hw,
+				  struct dlb_dir_pq_pair *port)
+{
+	u32 cnt;
+
+	cnt = DLB_CSR_RD(hw, LSP_CQ_DIR_TKN_CNT(port->id));
+
+	/*
+	 * Account for the initial token count, which is used in order to
+	 * provide a CQ with depth less than 8.
+	 */
+
+	return FIELD_GET(LSP_CQ_DIR_TKN_CNT_COUNT, cnt) - port->init_tkn_cnt;
+}
+
 static int dlb_domain_verify_reset_success(struct dlb_hw *hw,
 					   struct dlb_hw_domain *domain)
 {
@@ -1801,6 +2089,270 @@ static void dlb_domain_reset_registers(struct dlb_hw *hw,
 		   CHP_CFG_DIR_VAS_CRD_RST);
 }
 
+static void dlb_domain_drain_ldb_cqs(struct dlb_hw *hw,
+				     struct dlb_hw_domain *domain,
+				     bool toggle_port)
+{
+	struct dlb_ldb_port *port;
+	int i;
+
+	/* If the domain hasn't been started, there's no traffic to drain */
+	if (!domain->started)
+		return;
+
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++) {
+		list_for_each_entry(port, &domain->used_ldb_ports[i], domain_list) {
+			if (toggle_port)
+				dlb_ldb_port_cq_disable(hw, port);
+
+			dlb_drain_ldb_cq(hw, port);
+
+			if (toggle_port)
+				dlb_ldb_port_cq_enable(hw, port);
+		}
+	}
+}
+
+static bool dlb_domain_mapped_queues_empty(struct dlb_hw *hw,
+					   struct dlb_hw_domain *domain)
+{
+	struct dlb_ldb_queue *queue;
+
+	list_for_each_entry(queue, &domain->used_ldb_queues, domain_list) {
+		if (queue->num_mappings == 0)
+			continue;
+
+		if (!dlb_ldb_queue_is_empty(hw, queue))
+			return false;
+	}
+
+	return true;
+}
+
+static int dlb_domain_drain_mapped_queues(struct dlb_hw *hw,
+					  struct dlb_hw_domain *domain)
+{
+	int i;
+
+	/* If the domain hasn't been started, there's no traffic to drain */
+	if (!domain->started)
+		return 0;
+
+	if (domain->num_pending_removals > 0) {
+		dev_err(hw_to_dev(hw),
+			"[%s()] Internal error: failed to unmap domain queues\n",
+			__func__);
+		return -EFAULT;
+	}
+
+	for (i = 0; i < DLB_MAX_QID_EMPTY_CHECK_LOOPS; i++) {
+		dlb_domain_drain_ldb_cqs(hw, domain, true);
+
+		if (dlb_domain_mapped_queues_empty(hw, domain))
+			break;
+	}
+
+	if (i == DLB_MAX_QID_EMPTY_CHECK_LOOPS) {
+		dev_err(hw_to_dev(hw),
+			"[%s()] Internal error: failed to empty queues\n",
+			__func__);
+		return -EFAULT;
+	}
+
+	/*
+	 * Drain the CQs one more time. For the queues to go empty, they would
+	 * have scheduled one or more QEs.
+	 */
+	dlb_domain_drain_ldb_cqs(hw, domain, true);
+
+	return 0;
+}
+
+static int dlb_drain_dir_cq(struct dlb_hw *hw, struct dlb_dir_pq_pair *port)
+{
+	unsigned int port_id = port->id;
+	u32 cnt;
+
+	/* Return any outstanding tokens */
+	cnt = dlb_dir_cq_token_count(hw, port);
+
+	if (cnt != 0) {
+		struct dlb_hcw hcw_mem[8], *hcw;
+		void __iomem *pp_addr;
+
+		pp_addr = dlb_producer_port_addr(hw, port_id, false);
+
+		/* Point hcw to a 64B-aligned location */
+		hcw = (struct dlb_hcw *)((uintptr_t)&hcw_mem[4] & ~0x3F);
+
+		/*
+		 * Program the first HCW for a batch token return and
+		 * the rest as NOOPS
+		 */
+		memset(hcw, 0, 4 * sizeof(*hcw));
+		hcw->cq_token = 1;
+		hcw->lock_id = cnt - 1;
+
+		/*
+		 * To ensure outstanding HCWs reach the device before subsequent
+		 * device accesses, fence them.
+		 */
+		wmb();
+
+		iosubmit_cmds512(pp_addr, hcw, 1);
+	}
+
+	return 0;
+}
+
+static int dlb_domain_drain_dir_cqs(struct dlb_hw *hw,
+				    struct dlb_hw_domain *domain,
+				    bool toggle_port)
+{
+	struct dlb_dir_pq_pair *port;
+	int ret;
+
+	list_for_each_entry(port, &domain->used_dir_pq_pairs, domain_list) {
+		/*
+		 * Can't drain a port if it's not configured, and there's
+		 * nothing to drain if its queue is unconfigured.
+		 */
+		if (!port->port_configured || !port->queue_configured)
+			continue;
+
+		if (toggle_port)
+			dlb_dir_port_cq_disable(hw, port);
+
+		ret = dlb_drain_dir_cq(hw, port);
+		if (ret)
+			return ret;
+
+		if (toggle_port)
+			dlb_dir_port_cq_enable(hw, port);
+	}
+
+	return 0;
+}
+
+static bool dlb_domain_dir_queues_empty(struct dlb_hw *hw,
+					struct dlb_hw_domain *domain)
+{
+	struct dlb_dir_pq_pair *queue;
+
+	list_for_each_entry(queue, &domain->used_dir_pq_pairs, domain_list) {
+		if (!dlb_dir_queue_is_empty(hw, queue))
+			return false;
+	}
+
+	return true;
+}
+
+static int dlb_domain_drain_dir_queues(struct dlb_hw *hw,
+				       struct dlb_hw_domain *domain)
+{
+	int i, ret;
+
+	/* If the domain hasn't been started, there's no traffic to drain */
+	if (!domain->started)
+		return 0;
+
+	for (i = 0; i < DLB_MAX_QID_EMPTY_CHECK_LOOPS; i++) {
+		ret = dlb_domain_drain_dir_cqs(hw, domain, true);
+		if (ret)
+			return ret;
+
+		if (dlb_domain_dir_queues_empty(hw, domain))
+			break;
+	}
+
+	if (i == DLB_MAX_QID_EMPTY_CHECK_LOOPS) {
+		dev_err(hw_to_dev(hw),
+			"[%s()] Internal error: failed to empty queues\n",
+			__func__);
+		return -EFAULT;
+	}
+
+	/*
+	 * Drain the CQs one more time. For the queues to go empty, they would
+	 * have scheduled one or more QEs.
+	 */
+	ret = dlb_domain_drain_dir_cqs(hw, domain, true);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void
+dlb_domain_disable_ldb_queue_write_perms(struct dlb_hw *hw,
+					 struct dlb_hw_domain *domain)
+{
+	int domain_offset = domain->id * DLB_MAX_NUM_LDB_QUEUES;
+	struct dlb_ldb_queue *queue;
+
+	list_for_each_entry(queue, &domain->used_ldb_queues, domain_list) {
+		int idx = domain_offset + queue->id;
+
+		DLB_CSR_WR(hw, SYS_LDB_VASQID_V(idx), 0);
+	}
+}
+
+static void
+dlb_domain_disable_dir_queue_write_perms(struct dlb_hw *hw,
+					 struct dlb_hw_domain *domain)
+{
+	int domain_offset = domain->id * DLB_MAX_NUM_DIR_PORTS;
+	struct dlb_dir_pq_pair *queue;
+
+	list_for_each_entry(queue, &domain->used_dir_pq_pairs, domain_list) {
+		int idx = domain_offset + queue->id;
+
+		DLB_CSR_WR(hw, SYS_DIR_VASQID_V(idx), 0);
+	}
+}
+
+static void dlb_domain_disable_dir_cqs(struct dlb_hw *hw,
+				       struct dlb_hw_domain *domain)
+{
+	struct dlb_dir_pq_pair *port;
+
+	list_for_each_entry(port, &domain->used_dir_pq_pairs, domain_list) {
+		port->enabled = false;
+
+		dlb_dir_port_cq_disable(hw, port);
+	}
+}
+
+static void dlb_domain_disable_ldb_cqs(struct dlb_hw *hw,
+				       struct dlb_hw_domain *domain)
+{
+	struct dlb_ldb_port *port;
+	int i;
+
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++) {
+		list_for_each_entry(port, &domain->used_ldb_ports[i], domain_list) {
+			port->enabled = false;
+
+			dlb_ldb_port_cq_disable(hw, port);
+		}
+	}
+}
+
+static void dlb_domain_enable_ldb_cqs(struct dlb_hw *hw,
+				      struct dlb_hw_domain *domain)
+{
+	struct dlb_ldb_port *port;
+	int i;
+
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++) {
+		list_for_each_entry(port, &domain->used_ldb_ports[i], domain_list) {
+			port->enabled = true;
+
+			dlb_ldb_port_cq_enable(hw, port);
+		}
+	}
+}
+
 static void dlb_log_reset_domain(struct dlb_hw *hw, u32 domain_id)
 {
 	dev_dbg(hw_to_dev(hw), "DLB reset domain:\n");
@@ -1844,6 +2396,24 @@ int dlb_reset_domain(struct dlb_hw *hw, u32 domain_id)
 	 * cause any traffic sent to it to be dropped. Well-behaved software
 	 * should not be sending QEs at this point.
 	 */
+	dlb_domain_disable_dir_queue_write_perms(hw, domain);
+
+	dlb_domain_disable_ldb_queue_write_perms(hw, domain);
+
+	/* Re-enable the CQs in order to drain the mapped queues. */
+	dlb_domain_enable_ldb_cqs(hw, domain);
+
+	ret = dlb_domain_drain_mapped_queues(hw, domain);
+	if (ret)
+		return ret;
+
+	/* Done draining LDB QEs, so disable the CQs. */
+	dlb_domain_disable_ldb_cqs(hw, domain);
+
+	dlb_domain_drain_dir_queues(hw, domain);
+
+	/* Done draining DIR QEs, so disable the CQs. */
+	dlb_domain_disable_dir_cqs(hw, domain);
 
 	ret = dlb_domain_verify_reset_success(hw, domain);
 	if (ret)
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [RFC PATCH v12 11/17] dlb: add configfs interface to configure ports
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
                   ` (9 preceding siblings ...)
  2021-12-21  6:50 ` [RFC PATCH v12 10/17] dlb: add register operations for queue management Mike Ximing Chen
@ 2021-12-21  6:50 ` Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 12/17] dlb: add register operations for port management Mike Ximing Chen
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

Add high-level code for port configuration and poll-mode query configfs
interface, argument verification, and placeholder functions for the
low-level register accesses. A subsequent commit will add the low-level
logic.

The port is a core's interface to the DLB, and it consists of an MMIO page
(the "producer port" (PP)) through which the core enqueues queue entries
and an in-memory queue (the "consumer queue" (CQ)) to which the device
schedules QEs. A subsequent commit will add the mmap interface for an
application to directly access the PP and CQ regions.

The driver allocates DMA memory for each port's CQ, and frees this memory
during domain reset or driver removal. Domain reset will also drains each
port's CQ and disables them from further scheduling.

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
---
 drivers/misc/dlb/dlb_args.h     |  59 +++++-
 drivers/misc/dlb/dlb_configfs.c | 295 ++++++++++++++++++++++++++-
 drivers/misc/dlb/dlb_configfs.h |  24 +++
 drivers/misc/dlb/dlb_main.c     |  51 +++++
 drivers/misc/dlb/dlb_main.h     |  22 +++
 drivers/misc/dlb/dlb_pf_ops.c   |   7 +
 drivers/misc/dlb/dlb_resource.c | 341 ++++++++++++++++++++++++++++++++
 include/uapi/linux/dlb.h        |   6 +
 8 files changed, 803 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/dlb/dlb_args.h b/drivers/misc/dlb/dlb_args.h
index 2a1584756e43..b54483bfa767 100644
--- a/drivers/misc/dlb/dlb_args.h
+++ b/drivers/misc/dlb/dlb_args.h
@@ -167,4 +167,61 @@ struct dlb_get_dir_queue_depth_args {
 	/* Input parameters */
 	__u32 queue_id;
 };
-#endif /* DLB_ARGS_H */
+
+/*
+ * dlb_create_ldb_port_args: Used to configure a load-balanced port.
+ *
+ * Output parameters:
+ * @response.status: Detailed error code. In certain cases, such as if the
+ *	request arg is invalid, the driver won't set status.
+ * @response.id: port ID.
+ *
+ * Input parameters:
+ * @cq_depth: Depth of the port's CQ. Must be a power-of-two between 8 and
+ *	1024, inclusive.
+ * @cq_depth_threshold: CQ depth interrupt threshold. A value of N means that
+ *	the CQ interrupt won't fire until there are N or more outstanding CQ
+ *	tokens.
+ * @num_hist_list_entries: Number of history list entries. This must be
+ *	greater than or equal cq_depth.
+ */
+
+struct dlb_create_ldb_port_args {
+	/* Output parameters */
+	struct dlb_cmd_response response;
+	/* Input parameters */
+	__u16 cq_depth;
+	__u16 cq_depth_threshold;
+	__u16 cq_history_list_size;
+};
+
+/*
+ * dlb_create_dir_port_args: Used to configure a directed port.
+ *
+ * Output parameters:
+ * @response.status: Detailed error code. In certain cases, such as if the
+ *	request arg is invalid, the driver won't set status.
+ * @response.id: Port ID.
+ *
+ * Input parameters:
+ * @cq_depth: Depth of the port's CQ. Must be a power-of-two between 8 and
+ *	1024, inclusive.
+ * @cq_depth_threshold: CQ depth interrupt threshold. A value of N means that
+ *	the CQ interrupt won't fire until there are N or more outstanding CQ
+ *	tokens.
+ * @qid: Queue ID. If the corresponding directed queue is already created,
+ *	specify its ID here. Else this argument must be 0xFFFFFFFF to indicate
+ *	that the port is being created before the queue.
+ */
+struct dlb_create_dir_port_args {
+	/* Output parameters */
+	struct dlb_cmd_response response;
+	/* Input parameters */
+	__u16 cq_depth;
+	__u16 cq_depth_threshold;
+	__s32 queue_id;
+};
+
+#define DLB_CQ_SIZE 65536
+
+#endif /* __DLB_ARGS_H */
diff --git a/drivers/misc/dlb/dlb_configfs.c b/drivers/misc/dlb/dlb_configfs.c
index f47d3d9b96ba..045d1dae2b7f 100644
--- a/drivers/misc/dlb/dlb_configfs.c
+++ b/drivers/misc/dlb/dlb_configfs.c
@@ -45,6 +45,109 @@ DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(create_dir_queue)
 DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(get_ldb_queue_depth)
 DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(get_dir_queue_depth)
 
+static int dlb_domain_configfs_create_ldb_port(struct dlb *dlb,
+					       struct dlb_domain *domain,
+					       void *karg)
+{
+	struct dlb_cmd_response response = {0};
+	struct dlb_create_ldb_port_args *arg = karg;
+	dma_addr_t cq_dma_base = 0;
+	void *cq_base;
+	int ret;
+
+	mutex_lock(&dlb->resource_mutex);
+
+	cq_base = dma_alloc_coherent(&dlb->pdev->dev,
+				     DLB_CQ_SIZE,
+				     &cq_dma_base,
+				     GFP_KERNEL);
+	if (!cq_base) {
+		response.status = DLB_ST_NO_MEMORY;
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	ret = dlb_hw_create_ldb_port(&dlb->hw, domain->id,
+				     arg, (uintptr_t)cq_dma_base,
+				     &response);
+	if (ret)
+		goto unlock;
+
+	/* Fill out the per-port data structure */
+	dlb->ldb_port[response.id].id = response.id;
+	dlb->ldb_port[response.id].is_ldb = true;
+	dlb->ldb_port[response.id].domain = domain;
+	dlb->ldb_port[response.id].cq_base = cq_base;
+	dlb->ldb_port[response.id].cq_dma_base = cq_dma_base;
+	dlb->ldb_port[response.id].valid = true;
+
+unlock:
+	if (ret && cq_dma_base)
+		dma_free_coherent(&dlb->pdev->dev,
+				  DLB_CQ_SIZE,
+				  cq_base,
+				  cq_dma_base);
+
+	mutex_unlock(&dlb->resource_mutex);
+
+	BUILD_BUG_ON(offsetof(typeof(*arg), response) != 0);
+
+	memcpy(karg, &response, sizeof(response));
+
+	return ret;
+}
+
+static int dlb_domain_configfs_create_dir_port(struct dlb *dlb,
+					       struct dlb_domain *domain,
+					       void *karg)
+{
+	struct dlb_cmd_response response = {0};
+	struct dlb_create_dir_port_args *arg = karg;
+	dma_addr_t cq_dma_base = 0;
+	void *cq_base;
+	int ret;
+
+	mutex_lock(&dlb->resource_mutex);
+
+	cq_base = dma_alloc_coherent(&dlb->pdev->dev,
+				     DLB_CQ_SIZE,
+				     &cq_dma_base,
+				     GFP_KERNEL);
+	if (!cq_base) {
+		response.status = DLB_ST_NO_MEMORY;
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	ret = dlb_hw_create_dir_port(&dlb->hw, domain->id,
+				     arg, (uintptr_t)cq_dma_base,
+				     &response);
+	if (ret)
+		goto unlock;
+
+	/* Fill out the per-port data structure */
+	dlb->dir_port[response.id].id = response.id;
+	dlb->dir_port[response.id].is_ldb = false;
+	dlb->dir_port[response.id].domain = domain;
+	dlb->dir_port[response.id].cq_base = cq_base;
+	dlb->dir_port[response.id].cq_dma_base = cq_dma_base;
+	dlb->dir_port[response.id].valid = true;
+unlock:
+	if (ret && cq_dma_base)
+		dma_free_coherent(&dlb->pdev->dev,
+				  DLB_CQ_SIZE,
+				  cq_base,
+				  cq_dma_base);
+
+	mutex_unlock(&dlb->resource_mutex);
+
+	BUILD_BUG_ON(offsetof(typeof(*arg), response) != 0);
+
+	memcpy(karg, &response, sizeof(response));
+
+	return ret;
+}
+
 static int dlb_configfs_create_sched_domain(struct dlb *dlb,
 					    void *karg)
 {
@@ -330,6 +433,180 @@ static const struct config_item_type dlb_cfs_queue_type = {
 	.ct_owner	= THIS_MODULE,
 };
 
+/*
+ * ------ Configfs for dlb ports ---------
+ *
+ * These are the templates for show and store functions in port
+ * groups/directories, which minimizes replication of boilerplate
+ * code to copy arguments. Most attributes, use the simple template.
+ * "name" is the attribute name in the group.
+ */
+#define DLB_CONFIGFS_PORT_SHOW(name)					\
+static ssize_t dlb_cfs_port_##name##_show(				\
+	struct config_item *item,					\
+	char *page)							\
+{									\
+	return sprintf(page, "%u\n", to_dlb_cfs_port(item)->name);	\
+}									\
+
+#define DLB_CONFIGFS_PORT_SHOW64(name)					\
+static ssize_t dlb_cfs_port_##name##_show(				\
+	struct config_item *item,					\
+	char *page)							\
+{									\
+	return sprintf(page, "%llx\n", to_dlb_cfs_port(item)->name);	\
+}									\
+
+#define DLB_CONFIGFS_PORT_STORE(name)					\
+static ssize_t dlb_cfs_port_##name##_store(				\
+	struct config_item *item,					\
+	const char *page,						\
+	size_t count)							\
+{									\
+	struct dlb_cfs_port *dlb_cfs_port = to_dlb_cfs_port(item);	\
+	int ret;							\
+									\
+	ret = kstrtoint(page, 10, &dlb_cfs_port->name);			\
+	if (ret)							\
+		return ret;						\
+									\
+	return count;							\
+}									\
+
+#define DLB_CONFIGFS_PORT_STORE64(name)					\
+static ssize_t dlb_cfs_port_##name##_store(				\
+	struct config_item *item,					\
+	const char *page,						\
+	size_t count)							\
+{									\
+	int ret;							\
+	struct dlb_cfs_port *dlb_cfs_port = to_dlb_cfs_port(item);	\
+									\
+	ret = kstrtoll(page, 16, &dlb_cfs_port->name);			\
+	if (ret)							\
+		return ret;						\
+									\
+	return count;							\
+}									\
+
+DLB_CONFIGFS_PORT_SHOW(status)
+DLB_CONFIGFS_PORT_SHOW(port_id)
+DLB_CONFIGFS_PORT_SHOW(is_ldb)
+DLB_CONFIGFS_PORT_SHOW(cq_depth)
+DLB_CONFIGFS_PORT_SHOW(cq_depth_threshold)
+DLB_CONFIGFS_PORT_SHOW(cq_history_list_size)
+DLB_CONFIGFS_PORT_SHOW(create)
+DLB_CONFIGFS_PORT_SHOW(queue_id)
+
+DLB_CONFIGFS_PORT_STORE(is_ldb)
+DLB_CONFIGFS_PORT_STORE(cq_depth)
+DLB_CONFIGFS_PORT_STORE(cq_depth_threshold)
+DLB_CONFIGFS_PORT_STORE(cq_history_list_size)
+DLB_CONFIGFS_PORT_STORE(queue_id)
+
+static ssize_t dlb_cfs_port_create_store(struct config_item *item,
+					 const char *page, size_t count)
+{
+	struct dlb_cfs_port *dlb_cfs_port = to_dlb_cfs_port(item);
+	struct dlb_domain *dlb_domain;
+	struct dlb *dlb = NULL;
+	int ret;
+
+	ret = dlb_configfs_get_dlb_domain(dlb_cfs_port->domain_grp,
+					  &dlb, &dlb_domain);
+	if (ret)
+		return ret;
+
+	ret = kstrtoint(page, 10, &dlb_cfs_port->create);
+	if (ret)
+		return ret;
+
+	if (dlb_cfs_port->create == 0)
+		return count;
+
+	if (dlb_cfs_port->is_ldb) {
+		struct dlb_create_ldb_port_args args = {0};
+
+		args.cq_depth = dlb_cfs_port->cq_depth;
+		args.cq_depth_threshold = dlb_cfs_port->cq_depth_threshold;
+		args.cq_history_list_size = dlb_cfs_port->cq_history_list_size;
+
+		dev_dbg(dlb->dev,
+			"Creating ldb port: %s\n",
+			dlb_cfs_port->group.cg_item.ci_namebuf);
+
+		ret = dlb_domain_configfs_create_ldb_port(dlb, dlb_domain, &args);
+
+		dlb_cfs_port->status = args.response.status;
+		dlb_cfs_port->port_id = args.response.id;
+	} else {
+		struct dlb_create_dir_port_args args = {0};
+
+		args.queue_id = dlb_cfs_port->queue_id;
+		args.cq_depth = dlb_cfs_port->cq_depth;
+		args.cq_depth_threshold = dlb_cfs_port->cq_depth_threshold;
+
+		dev_dbg(dlb->dev,
+			"Creating dir port: %s\n",
+			dlb_cfs_port->group.cg_item.ci_namebuf);
+
+		ret = dlb_domain_configfs_create_dir_port(dlb, dlb_domain, &args);
+
+		dlb_cfs_port->status = args.response.status;
+		dlb_cfs_port->port_id = args.response.id;
+	}
+
+	if (ret) {
+		dev_err(dlb->dev,
+			"creat port %s failed: ret=%d\n",
+			dlb_cfs_port->group.cg_item.ci_namebuf, ret);
+		return ret;
+	}
+
+	return count;
+}
+
+CONFIGFS_ATTR_RO(dlb_cfs_port_, status);
+CONFIGFS_ATTR_RO(dlb_cfs_port_, port_id);
+CONFIGFS_ATTR(dlb_cfs_port_, is_ldb);
+CONFIGFS_ATTR(dlb_cfs_port_, cq_depth);
+CONFIGFS_ATTR(dlb_cfs_port_, cq_depth_threshold);
+CONFIGFS_ATTR(dlb_cfs_port_, cq_history_list_size);
+CONFIGFS_ATTR(dlb_cfs_port_, create);
+CONFIGFS_ATTR(dlb_cfs_port_, queue_id);
+
+static struct configfs_attribute *dlb_cfs_port_attrs[] = {
+	&dlb_cfs_port_attr_status,
+	&dlb_cfs_port_attr_port_id,
+	&dlb_cfs_port_attr_is_ldb,
+	&dlb_cfs_port_attr_cq_depth,
+	&dlb_cfs_port_attr_cq_depth_threshold,
+	&dlb_cfs_port_attr_cq_history_list_size,
+	&dlb_cfs_port_attr_create,
+	&dlb_cfs_port_attr_queue_id,
+
+	NULL,
+};
+
+static void dlb_cfs_port_release(struct config_item *item)
+{
+	kfree(to_dlb_cfs_port(item));
+}
+
+static struct configfs_item_operations dlb_cfs_port_item_ops = {
+	.release	= dlb_cfs_port_release,
+};
+
+/*
+ * Note that, since no extra work is required on ->drop_item(),
+ * no ->drop_item() is provided.
+ */
+static const struct config_item_type dlb_cfs_port_type = {
+	.ct_item_ops	= &dlb_cfs_port_item_ops,
+	.ct_attrs	= dlb_cfs_port_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
 /*
  * ------ Configfs for dlb domains---------
  *
@@ -474,7 +751,23 @@ static struct configfs_attribute *dlb_cfs_domain_attrs[] = {
 static struct config_group *dlb_cfs_domain_make_queue_port(struct config_group *group,
 							   const char *name)
 {
-	if (strstr(name, "queue")) {
+	if (strstr(name, "port")) {
+		struct dlb_cfs_port *dlb_cfs_port;
+
+		dlb_cfs_port = kzalloc(sizeof(*dlb_cfs_port), GFP_KERNEL);
+		if (!dlb_cfs_port)
+			return ERR_PTR(-ENOMEM);
+
+		dlb_cfs_port->domain_grp = group;
+
+		config_group_init_type_name(&dlb_cfs_port->group, name,
+					    &dlb_cfs_port_type);
+
+		dlb_cfs_port->queue_id = 0xffffffff;
+		dlb_cfs_port->port_id = 0xffffffff;
+
+		return &dlb_cfs_port->group;
+	} else if (strstr(name, "queue")) {
 		struct dlb_cfs_queue *dlb_cfs_queue;
 
 		dlb_cfs_queue = kzalloc(sizeof(*dlb_cfs_queue), GFP_KERNEL);
diff --git a/drivers/misc/dlb/dlb_configfs.h b/drivers/misc/dlb/dlb_configfs.h
index e70b40560742..06f4f93d4139 100644
--- a/drivers/misc/dlb/dlb_configfs.h
+++ b/drivers/misc/dlb/dlb_configfs.h
@@ -51,6 +51,23 @@ struct dlb_cfs_queue {
 
 };
 
+struct dlb_cfs_port {
+	struct config_group group;
+	struct config_group *domain_grp;
+	unsigned int status;
+	unsigned int port_id;
+	/* Input parameters */
+	unsigned int is_ldb;
+	unsigned int cq_depth;
+	unsigned int cq_depth_threshold;
+	unsigned int cq_history_list_size;
+	unsigned int create;
+
+	/* For DIR port only, default = 0xffffffff */
+	unsigned int queue_id;
+
+};
+
 static inline
 struct dlb_cfs_queue *to_dlb_cfs_queue(struct config_item *item)
 {
@@ -58,6 +75,13 @@ struct dlb_cfs_queue *to_dlb_cfs_queue(struct config_item *item)
 			    struct dlb_cfs_queue, group);
 }
 
+static inline
+struct dlb_cfs_port *to_dlb_cfs_port(struct config_item *item)
+{
+	return container_of(to_config_group(item),
+			    struct dlb_cfs_port, group);
+}
+
 static inline
 struct dlb_cfs_domain *to_dlb_cfs_domain(struct config_item *item)
 {
diff --git a/drivers/misc/dlb/dlb_main.c b/drivers/misc/dlb/dlb_main.c
index 4b263e849061..9e6168b27859 100644
--- a/drivers/misc/dlb/dlb_main.c
+++ b/drivers/misc/dlb/dlb_main.c
@@ -125,12 +125,56 @@ int dlb_init_domain(struct dlb *dlb, u32 domain_id)
 	return 0;
 }
 
+static void dlb_release_port_memory(struct dlb *dlb,
+				    struct dlb_port *port,
+				    bool check_domain,
+				    u32 domain_id)
+{
+	if (port->valid &&
+	    (!check_domain || port->domain->id == domain_id))
+		dma_free_coherent(&dlb->pdev->dev,
+				  DLB_CQ_SIZE,
+				  port->cq_base,
+				  port->cq_dma_base);
+
+	port->valid = false;
+}
+
+static void dlb_release_domain_memory(struct dlb *dlb,
+				      bool check_domain,
+				      u32 domain_id)
+{
+	struct dlb_port *port;
+	int i;
+
+	for (i = 0; i < DLB_MAX_NUM_LDB_PORTS; i++) {
+		port = &dlb->ldb_port[i];
+
+		dlb_release_port_memory(dlb, port, check_domain, domain_id);
+	}
+
+	for (i = 0; i < DLB_MAX_NUM_DIR_PORTS; i++) {
+		port = &dlb->dir_port[i];
+
+		dlb_release_port_memory(dlb, port, check_domain, domain_id);
+	}
+}
+
+static void dlb_release_device_memory(struct dlb *dlb)
+{
+	dlb_release_domain_memory(dlb, false, 0);
+}
+
 static int __dlb_free_domain(struct dlb_domain *domain)
 {
 	struct dlb *dlb = domain->dlb;
 	int ret;
 
 	ret = dlb_reset_domain(&dlb->hw, domain->id);
+
+	/* Unpin and free all memory pages associated with the domain */
+	dlb_release_domain_memory(dlb, true, domain->id);
+
 	if (ret) {
 		dlb->domain_reset_failed = true;
 		dev_err(dlb->dev,
@@ -271,6 +315,8 @@ static int dlb_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
 	if (ret)
 		goto init_driver_state_fail;
 
+	dlb_pf_init_hardware(dlb);
+
 	/*
 	 * Undo the 'get' operation by the PCI layer during probe and
 	 * (if PF) immediately suspend the device. Since the device is only
@@ -308,6 +354,8 @@ static void dlb_remove(struct pci_dev *pdev)
 
 	dlb_resource_free(&dlb->hw);
 
+	dlb_release_device_memory(dlb);
+
 	device_destroy(dlb_class, dlb->dev_number);
 
 	pci_disable_pcie_error_reporting(pdev);
@@ -321,6 +369,9 @@ static void dlb_remove(struct pci_dev *pdev)
 static void dlb_reset_hardware_state(struct dlb *dlb)
 {
 	dlb_reset_device(dlb->pdev);
+
+	/* Reinitialize any other hardware state */
+	dlb_pf_init_hardware(dlb);
 }
 
 static int dlb_runtime_suspend(struct device *dev)
diff --git a/drivers/misc/dlb/dlb_main.h b/drivers/misc/dlb/dlb_main.h
index 3bd2d9ee0a44..fbfbc6e3fc87 100644
--- a/drivers/misc/dlb/dlb_main.h
+++ b/drivers/misc/dlb/dlb_main.h
@@ -329,9 +329,19 @@ void dlb_pf_unmap_pci_bar_space(struct dlb *dlb, struct pci_dev *pdev);
 int dlb_pf_init_driver_state(struct dlb *dlb);
 void dlb_pf_enable_pm(struct dlb *dlb);
 int dlb_pf_wait_for_device_ready(struct dlb *dlb, struct pci_dev *pdev);
+void dlb_pf_init_hardware(struct dlb *dlb);
 
 extern const struct file_operations dlb_domain_fops;
 
+struct dlb_port {
+	void *cq_base;
+	dma_addr_t cq_dma_base;
+	struct dlb_domain *domain;
+	int id;
+	u8 is_ldb;
+	u8 valid;
+};
+
 struct dlb_domain {
 	struct dlb *dlb;
 	struct kref refcnt;
@@ -344,6 +354,8 @@ struct dlb {
 	struct device *dev;
 	struct dlb_domain *sched_domains[DLB_MAX_NUM_DOMAINS];
 	struct file *f;
+	struct dlb_port ldb_port[DLB_MAX_NUM_LDB_PORTS];
+	struct dlb_port dir_port[DLB_MAX_NUM_DIR_PORTS];
 	/*
 	 * The resource mutex serializes access to driver data structures and
 	 * hardware registers.
@@ -576,6 +588,14 @@ int dlb_hw_create_ldb_queue(struct dlb_hw *hw, u32 domain_id,
 int dlb_hw_create_dir_queue(struct dlb_hw *hw, u32 domain_id,
 			    struct dlb_create_dir_queue_args *args,
 			    struct dlb_cmd_response *resp);
+int dlb_hw_create_dir_port(struct dlb_hw *hw, u32 domain_id,
+			   struct dlb_create_dir_port_args *args,
+			   uintptr_t cq_dma_base,
+			   struct dlb_cmd_response *resp);
+int dlb_hw_create_ldb_port(struct dlb_hw *hw, u32 domain_id,
+			   struct dlb_create_ldb_port_args *args,
+			   uintptr_t cq_dma_base,
+			   struct dlb_cmd_response *resp);
 int dlb_reset_domain(struct dlb_hw *hw, u32 domain_id);
 void dlb_clr_pmcsr_disable(struct dlb_hw *hw);
 int dlb_hw_get_ldb_queue_depth(struct dlb_hw *hw, u32 domain_id,
@@ -584,6 +604,8 @@ int dlb_hw_get_ldb_queue_depth(struct dlb_hw *hw, u32 domain_id,
 int dlb_hw_get_dir_queue_depth(struct dlb_hw *hw, u32 domain_id,
 			       struct dlb_get_dir_queue_depth_args *args,
 			       struct dlb_cmd_response *resp);
+void dlb_hw_enable_sparse_ldb_cq_mode(struct dlb_hw *hw);
+void dlb_hw_enable_sparse_dir_cq_mode(struct dlb_hw *hw);
 
 /* Prototypes for dlb_configfs.c */
 int dlb_configfs_create_device(struct dlb *dlb);
diff --git a/drivers/misc/dlb/dlb_pf_ops.c b/drivers/misc/dlb/dlb_pf_ops.c
index 65213c0475e5..66fb4ffae939 100644
--- a/drivers/misc/dlb/dlb_pf_ops.c
+++ b/drivers/misc/dlb/dlb_pf_ops.c
@@ -95,3 +95,10 @@ int dlb_pf_wait_for_device_ready(struct dlb *dlb, struct pci_dev *pdev)
 
 	return 0;
 }
+
+void dlb_pf_init_hardware(struct dlb *dlb)
+{
+	/* Use sparse mode as default */
+	dlb_hw_enable_sparse_ldb_cq_mode(&dlb->hw);
+	dlb_hw_enable_sparse_dir_cq_mode(&dlb->hw);
+}
diff --git a/drivers/misc/dlb/dlb_resource.c b/drivers/misc/dlb/dlb_resource.c
index 83c000839f15..3521ae2ca76b 100644
--- a/drivers/misc/dlb/dlb_resource.c
+++ b/drivers/misc/dlb/dlb_resource.c
@@ -884,6 +884,163 @@ static void dlb_configure_dir_queue(struct dlb_hw *hw,
 	queue->queue_configured = true;
 }
 
+static bool
+dlb_cq_depth_is_valid(u32 depth)
+{
+	/* Valid values for depth are
+	 * 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, and 1024.
+	 */
+	if (!is_power_of_2(depth) || depth > 1024)
+		return false;
+
+	return true;
+}
+
+static int
+dlb_verify_create_ldb_port_args(struct dlb_hw *hw, u32 domain_id,
+				uintptr_t cq_dma_base,
+				struct dlb_create_ldb_port_args *args,
+				struct dlb_cmd_response *resp,
+				struct dlb_hw_domain **out_domain,
+				struct dlb_ldb_port **out_port, int *out_cos_id)
+{
+	struct dlb_ldb_port *port = NULL;
+	struct dlb_hw_domain *domain;
+	int i, id;
+
+	domain = dlb_get_domain_from_id(hw, domain_id);
+
+	if (!domain) {
+		resp->status = DLB_ST_INVALID_DOMAIN_ID;
+		return -EINVAL;
+	}
+
+	if (!domain->configured) {
+		resp->status = DLB_ST_DOMAIN_NOT_CONFIGURED;
+		return -EINVAL;
+	}
+
+	if (domain->started) {
+		resp->status = DLB_ST_DOMAIN_STARTED;
+		return -EINVAL;
+	}
+
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++) {
+		id = i % DLB_NUM_COS_DOMAINS;
+
+		port = list_first_entry_or_null(&domain->avail_ldb_ports[id],
+						typeof(*port), domain_list);
+		if (port)
+			break;
+	}
+
+	if (!port) {
+		resp->status = DLB_ST_LDB_PORTS_UNAVAILABLE;
+		return -EINVAL;
+	}
+
+	/* DLB requires 64B alignment */
+	if (!IS_ALIGNED(cq_dma_base, 64)) {
+		resp->status = DLB_ST_INVALID_CQ_VIRT_ADDR;
+		return -EINVAL;
+	}
+
+	if (!dlb_cq_depth_is_valid(args->cq_depth)) {
+		resp->status = DLB_ST_INVALID_CQ_DEPTH;
+		return -EINVAL;
+	}
+
+	/* The history list size must be >= 1 */
+	if (!args->cq_history_list_size) {
+		resp->status = DLB_ST_INVALID_HIST_LIST_DEPTH;
+		return -EINVAL;
+	}
+
+	if (args->cq_history_list_size > domain->avail_hist_list_entries) {
+		resp->status = DLB_ST_HIST_LIST_ENTRIES_UNAVAILABLE;
+		return -EINVAL;
+	}
+
+	*out_domain = domain;
+	*out_port = port;
+	*out_cos_id = id;
+
+	return 0;
+}
+
+static int
+dlb_verify_create_dir_port_args(struct dlb_hw *hw, u32 domain_id,
+				uintptr_t cq_dma_base,
+				struct dlb_create_dir_port_args *args,
+				struct dlb_cmd_response *resp,
+				struct dlb_hw_domain **out_domain,
+				struct dlb_dir_pq_pair **out_port)
+{
+	struct dlb_hw_domain *domain;
+	struct dlb_dir_pq_pair *pq;
+
+	domain = dlb_get_domain_from_id(hw, domain_id);
+
+	if (!domain) {
+		resp->status = DLB_ST_INVALID_DOMAIN_ID;
+		return -EINVAL;
+	}
+
+	if (!domain->configured) {
+		resp->status = DLB_ST_DOMAIN_NOT_CONFIGURED;
+		return -EINVAL;
+	}
+
+	if (domain->started) {
+		resp->status = DLB_ST_DOMAIN_STARTED;
+		return -EINVAL;
+	}
+
+	if (args->queue_id != -1) {
+		/*
+		 * If the user claims the queue is already configured, validate
+		 * the queue ID, its domain, and whether the queue is
+		 * configured.
+		 */
+		pq = dlb_get_domain_used_dir_pq(args->queue_id,
+						false,
+						domain);
+
+		if (!pq || pq->domain_id != domain->id ||
+		    !pq->queue_configured) {
+			resp->status = DLB_ST_INVALID_DIR_QUEUE_ID;
+			return -EINVAL;
+		}
+	} else {
+		/*
+		 * If the port's queue is not configured, validate that a free
+		 * port-queue pair is available.
+		 */
+		pq = list_first_entry_or_null(&domain->avail_dir_pq_pairs,
+					      typeof(*pq), domain_list);
+		if (!pq) {
+			resp->status = DLB_ST_DIR_PORTS_UNAVAILABLE;
+			return -EINVAL;
+		}
+	}
+
+	/* DLB requires 64B alignment */
+	if (!IS_ALIGNED(cq_dma_base, 64)) {
+		resp->status = DLB_ST_INVALID_CQ_VIRT_ADDR;
+		return -EINVAL;
+	}
+
+	if (!dlb_cq_depth_is_valid(args->cq_depth)) {
+		resp->status = DLB_ST_INVALID_CQ_DEPTH;
+		return -EINVAL;
+	}
+
+	*out_domain = domain;
+	*out_port = pq;
+
+	return 0;
+}
+
 static void dlb_configure_domain_credits(struct dlb_hw *hw,
 					 struct dlb_hw_domain *domain)
 {
@@ -1287,6 +1444,146 @@ int dlb_hw_create_dir_queue(struct dlb_hw *hw, u32 domain_id,
 	return 0;
 }
 
+static void
+dlb_log_create_ldb_port_args(struct dlb_hw *hw, u32 domain_id,
+			     uintptr_t cq_dma_base,
+			     struct dlb_create_ldb_port_args *args)
+{
+	dev_dbg(hw_to_dev(hw), "DLB create load-balanced port arguments:\n");
+	dev_dbg(hw_to_dev(hw), "\tDomain ID:                 %d\n",
+		domain_id);
+	dev_dbg(hw_to_dev(hw), "\tCQ depth:                  %d\n",
+		args->cq_depth);
+	dev_dbg(hw_to_dev(hw), "\tCQ hist list size:         %d\n",
+		args->cq_history_list_size);
+	dev_dbg(hw_to_dev(hw), "\tCQ base address:           0x%lx\n",
+		cq_dma_base);
+}
+
+/**
+ * dlb_hw_create_ldb_port() - create a load-balanced port
+ * @hw: dlb_hw handle for a particular device.
+ * @domain_id: domain ID.
+ * @args: port creation arguments.
+ * @cq_dma_base: base address of the CQ memory. This can be a PA or an IOVA.
+ * @resp: response structure.
+ *
+ * This function creates a load-balanced port.
+ *
+ * Return:
+ * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
+ * assigned a detailed error code from enum dlb_error. If successful, resp->id
+ * contains the port ID.
+ *
+ * Errors:
+ * EINVAL - A requested resource is unavailable, a credit setting is invalid, a
+ *	    pointer address is not properly aligned, the domain is not
+ *	    configured, or the domain has already been started.
+ * EFAULT - Internal error (resp->status not set).
+ */
+int dlb_hw_create_ldb_port(struct dlb_hw *hw, u32 domain_id,
+			   struct dlb_create_ldb_port_args *args,
+			   uintptr_t cq_dma_base,
+			   struct dlb_cmd_response *resp)
+{
+	struct dlb_hw_domain *domain;
+	struct dlb_ldb_port *port;
+	int ret, cos_id;
+
+	dlb_log_create_ldb_port_args(hw, domain_id, cq_dma_base,
+				     args);
+
+	/*
+	 * Verify that hardware resources are available before attempting to
+	 * satisfy the request. This simplifies the error unwinding code.
+	 */
+	ret = dlb_verify_create_ldb_port_args(hw, domain_id, cq_dma_base, args,
+					      resp, &domain,
+					      &port, &cos_id);
+	if (ret)
+		return ret;
+
+	/*
+	 * Configuration succeeded, so move the resource from the 'avail' to
+	 * the 'used' list.
+	 */
+	list_move(&port->domain_list, &domain->used_ldb_ports[cos_id]);
+
+	resp->status = 0;
+	resp->id = port->id;
+
+	return 0;
+}
+
+static void
+dlb_log_create_dir_port_args(struct dlb_hw *hw,
+			     u32 domain_id, uintptr_t cq_dma_base,
+			     struct dlb_create_dir_port_args *args)
+{
+	dev_dbg(hw_to_dev(hw), "DLB create directed port arguments:\n");
+	dev_dbg(hw_to_dev(hw), "\tDomain ID:                 %d\n",
+		domain_id);
+	dev_dbg(hw_to_dev(hw), "\tCQ depth:                  %d\n",
+		args->cq_depth);
+	dev_dbg(hw_to_dev(hw), "\tCQ base address:           0x%lx\n",
+		cq_dma_base);
+}
+
+/**
+ * dlb_hw_create_dir_port() - create a directed port
+ * @hw: dlb_hw handle for a particular device.
+ * @domain_id: domain ID.
+ * @args: port creation arguments.
+ * @cq_dma_base: base address of the CQ memory. This can be a PA or an IOVA.
+ * @resp: response structure.
+ *
+ * This function creates a directed port.
+ *
+ * Return:
+ * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
+ * assigned a detailed error code from enum dlb_error. If successful, resp->id
+ * contains the port ID.
+ *
+ * Errors:
+ * EINVAL - A requested resource is unavailable, a credit setting is invalid, a
+ *	    pointer address is not properly aligned, the domain is not
+ *	    configured, or the domain has already been started.
+ * EFAULT - Internal error (resp->status not set).
+ */
+int dlb_hw_create_dir_port(struct dlb_hw *hw, u32 domain_id,
+			   struct dlb_create_dir_port_args *args,
+			   uintptr_t cq_dma_base,
+			   struct dlb_cmd_response *resp)
+{
+	struct dlb_dir_pq_pair *port;
+	struct dlb_hw_domain *domain;
+	int ret;
+
+	dlb_log_create_dir_port_args(hw, domain_id, cq_dma_base, args);
+
+	/*
+	 * Verify that hardware resources are available before attempting to
+	 * satisfy the request. This simplifies the error unwinding code.
+	 */
+	ret = dlb_verify_create_dir_port_args(hw, domain_id, cq_dma_base,
+					      args, resp,
+					      &domain, &port);
+	if (ret)
+		return ret;
+
+	/*
+	 * Configuration succeeded, so move the resource from the 'avail' to
+	 * the 'used' list (if it's not already there).
+	 */
+	if (args->queue_id == -1)
+		list_move(&port->domain_list, &domain->used_dir_pq_pairs);
+
+	resp->status = 0;
+	resp->id = port->id;
+
+	return 0;
+}
+
 static u32 dlb_ldb_cq_inflight_count(struct dlb_hw *hw,
 				     struct dlb_ldb_port *port)
 {
@@ -2400,6 +2697,15 @@ int dlb_reset_domain(struct dlb_hw *hw, u32 domain_id)
 
 	dlb_domain_disable_ldb_queue_write_perms(hw, domain);
 
+	/*
+	 * Disable the LDB CQs and drain them in order to complete the map and
+	 * unmap procedures, which require zero CQ inflights and zero QID
+	 * inflights respectively.
+	 */
+	dlb_domain_disable_ldb_cqs(hw, domain);
+
+	dlb_domain_drain_ldb_cqs(hw, domain, false);
+
 	/* Re-enable the CQs in order to drain the mapped queues. */
 	dlb_domain_enable_ldb_cqs(hw, domain);
 
@@ -2443,3 +2749,38 @@ void dlb_clr_pmcsr_disable(struct dlb_hw *hw)
 
 	DLB_CSR_WR(hw, CM_CFG_PM_PMCSR_DISABLE, pmcsr_dis);
 }
+
+/**
+ * dlb_hw_enable_sparse_ldb_cq_mode() - enable sparse mode for load-balanced
+ *      ports.
+ * @hw: dlb_hw handle for a particular device.
+ *
+ * This function must be called prior to configuring scheduling domains.
+ */
+void dlb_hw_enable_sparse_ldb_cq_mode(struct dlb_hw *hw)
+{
+	u32 ctrl;
+
+	ctrl = DLB_CSR_RD(hw, CHP_CFG_CHP_CSR_CTRL);
+
+	ctrl |= CHP_CFG_CHP_CSR_CTRL_CFG_64BYTES_QE_LDB_CQ_MODE;
+
+	DLB_CSR_WR(hw, CHP_CFG_CHP_CSR_CTRL, ctrl);
+}
+
+/**
+ * dlb_hw_enable_sparse_dir_cq_mode() - enable sparse mode for directed ports.
+ * @hw: dlb_hw handle for a particular device.
+ *
+ * This function must be called prior to configuring scheduling domains.
+ */
+void dlb_hw_enable_sparse_dir_cq_mode(struct dlb_hw *hw)
+{
+	u32 ctrl;
+
+	ctrl = DLB_CSR_RD(hw, CHP_CFG_CHP_CSR_CTRL);
+
+	ctrl |= CHP_CFG_CHP_CSR_CTRL_CFG_64BYTES_QE_DIR_CQ_MODE;
+
+	DLB_CSR_WR(hw, CHP_CFG_CHP_CSR_CTRL, ctrl);
+}
diff --git a/include/uapi/linux/dlb.h b/include/uapi/linux/dlb.h
index 3586afbccdbf..e8a629f2d10b 100644
--- a/include/uapi/linux/dlb.h
+++ b/include/uapi/linux/dlb.h
@@ -28,5 +28,11 @@ enum dlb_error {
 	DLB_ST_DIR_QUEUES_UNAVAILABLE,
 	DLB_ST_INVALID_PORT_ID,
 	DLB_ST_INVALID_LOCK_ID_COMP_LEVEL,
+	DLB_ST_NO_MEMORY,
+	DLB_ST_INVALID_COS_ID,
+	DLB_ST_INVALID_CQ_VIRT_ADDR,
+	DLB_ST_INVALID_CQ_DEPTH,
+	DLB_ST_INVALID_HIST_LIST_DEPTH,
+	DLB_ST_INVALID_DIR_QUEUE_ID,
 };
 #endif /* __DLB_H */
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [RFC PATCH v12 12/17] dlb: add register operations for port management
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
                   ` (10 preceding siblings ...)
  2021-12-21  6:50 ` [RFC PATCH v12 11/17] dlb: add configfs interface to configure ports Mike Ximing Chen
@ 2021-12-21  6:50 ` Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 13/17] dlb: add port mmap support Mike Ximing Chen
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

Add the low-level code for configuring a new port, programming the
device-wide poll mode setting, and resetting a port.

The low-level port configuration functions program the device based on the
user-supplied parameters (from configfs attributes). These parameter are
first verified, e.g.  to ensure that the port's CQ base address is properly
cache-line aligned.

During domain reset, each port is drained until its inflight count and
owed-token count reaches 0, reflecting an empty CQ. Once the ports are
drained, the domain reset operation disables them from being candidates
for future scheduling decisions -- until they are re-assigned to a new
scheduling domain in the future and re-enabled.

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
---
 drivers/misc/dlb/dlb_resource.c | 418 +++++++++++++++++++++++++++++++-
 1 file changed, 417 insertions(+), 1 deletion(-)

diff --git a/drivers/misc/dlb/dlb_resource.c b/drivers/misc/dlb/dlb_resource.c
index 3521ae2ca76b..d1e1d1efe8c7 100644
--- a/drivers/misc/dlb/dlb_resource.c
+++ b/drivers/misc/dlb/dlb_resource.c
@@ -1217,6 +1217,296 @@ static void dlb_dir_port_cq_disable(struct dlb_hw *hw,
 	dlb_flush_csr(hw);
 }
 
+static void dlb_ldb_port_configure_pp(struct dlb_hw *hw,
+				      struct dlb_hw_domain *domain,
+				      struct dlb_ldb_port *port)
+{
+	u32 reg;
+
+	reg = FIELD_PREP(SYS_LDB_PP2VAS_VAS, domain->id);
+	DLB_CSR_WR(hw, SYS_LDB_PP2VAS(port->id), reg);
+
+	reg = 0;
+	reg |= SYS_LDB_PP_V_PP_V;
+	DLB_CSR_WR(hw, SYS_LDB_PP_V(port->id), reg);
+}
+
+static int dlb_ldb_port_configure_cq(struct dlb_hw *hw,
+				     struct dlb_hw_domain *domain,
+				     struct dlb_ldb_port *port,
+				     uintptr_t cq_dma_base,
+				     struct dlb_create_ldb_port_args *args)
+{
+	u32 hl_base = 0;
+	u32 reg = 0;
+	u32 ds, n;
+
+	/* The CQ address is 64B-aligned, and the DLB only wants bits [63:6] */
+	reg = FIELD_PREP(SYS_LDB_CQ_ADDR_L_ADDR_L, cq_dma_base >> 6);
+	DLB_CSR_WR(hw, SYS_LDB_CQ_ADDR_L(port->id), reg);
+
+	reg = cq_dma_base >> 32;
+	DLB_CSR_WR(hw, SYS_LDB_CQ_ADDR_U(port->id), reg);
+
+	/*
+	 * 'ro' == relaxed ordering. This setting allows DLB to write
+	 * cache lines out-of-order (but QEs within a cache line are always
+	 * updated in-order).
+	 */
+	reg = FIELD_PREP(SYS_LDB_CQ2VF_PF_RO_IS_PF, 1);
+	reg |= SYS_LDB_CQ2VF_PF_RO_RO;
+
+	DLB_CSR_WR(hw, SYS_LDB_CQ2VF_PF_RO(port->id), reg);
+
+	if (!dlb_cq_depth_is_valid(args->cq_depth)) {
+		dev_err(hw_to_dev(hw),
+			"[%s():%d] Internal error: invalid CQ depth\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (args->cq_depth <= 8) {
+		ds = 1;
+	} else {
+		n = ilog2(args->cq_depth);
+		ds = (n - 2) & 0x0f;
+	}
+
+	reg = FIELD_PREP(CHP_LDB_CQ_TKN_DEPTH_SEL_TOKEN_DEPTH_SELECT, ds);
+	DLB_CSR_WR(hw, CHP_LDB_CQ_TKN_DEPTH_SEL(port->id), reg);
+
+	/*
+	 * To support CQs with depth less than 8, program the token count
+	 * register with a non-zero initial value. Operations such as domain
+	 * reset must take this initial value into account when quiescing the
+	 * CQ.
+	 */
+	port->init_tkn_cnt = 0;
+
+	if (args->cq_depth < 8) {
+		port->init_tkn_cnt = 8 - args->cq_depth;
+
+		reg = FIELD_PREP(LSP_CQ_LDB_TKN_CNT_TOKEN_COUNT, port->init_tkn_cnt);
+		DLB_CSR_WR(hw, LSP_CQ_LDB_TKN_CNT(port->id), reg);
+	} else {
+		DLB_CSR_WR(hw,
+			   LSP_CQ_LDB_TKN_CNT(port->id),
+			   LSP_CQ_LDB_TKN_CNT_RST);
+	}
+
+	reg = FIELD_PREP(LSP_CQ_LDB_TKN_DEPTH_SEL_TOKEN_DEPTH_SELECT, ds);
+	DLB_CSR_WR(hw, LSP_CQ_LDB_TKN_DEPTH_SEL(port->id), reg);
+
+	/* Reset the CQ write pointer */
+	DLB_CSR_WR(hw,
+		   CHP_LDB_CQ_WPTR(port->id),
+		   CHP_LDB_CQ_WPTR_RST);
+
+	reg = FIELD_PREP(CHP_HIST_LIST_LIM_LIMIT, port->hist_list_entry_limit - 1);
+	DLB_CSR_WR(hw, CHP_HIST_LIST_LIM(port->id), reg);
+
+	hl_base = FIELD_PREP(CHP_HIST_LIST_BASE_BASE, port->hist_list_entry_base);
+	DLB_CSR_WR(hw, CHP_HIST_LIST_BASE(port->id), hl_base);
+
+	/*
+	 * The inflight limit sets a cap on the number of QEs for which this CQ
+	 * can owe completions at one time.
+	 */
+	reg = FIELD_PREP(LSP_CQ_LDB_INFL_LIM_LIMIT, args->cq_history_list_size);
+	DLB_CSR_WR(hw, LSP_CQ_LDB_INFL_LIM(port->id), reg);
+
+	reg = FIELD_PREP(CHP_HIST_LIST_PUSH_PTR_PUSH_PTR,
+		  FIELD_GET(CHP_HIST_LIST_BASE_BASE, hl_base));
+	DLB_CSR_WR(hw, CHP_HIST_LIST_PUSH_PTR(port->id), reg);
+
+	reg = FIELD_PREP(CHP_HIST_LIST_POP_PTR_POP_PTR,
+		  FIELD_GET(CHP_HIST_LIST_BASE_BASE, hl_base));
+	DLB_CSR_WR(hw, CHP_HIST_LIST_POP_PTR(port->id), reg);
+
+	/*
+	 * Address translation (AT) settings: 0: untranslated, 2: translated
+	 * (see ATS spec regarding Address Type field for more details)
+	 */
+
+	reg = 0;
+	DLB_CSR_WR(hw, SYS_LDB_CQ_AT(port->id), reg);
+	DLB_CSR_WR(hw, SYS_LDB_CQ_PASID(port->id), reg);
+
+	reg = FIELD_PREP(CHP_LDB_CQ2VAS_CQ2VAS, domain->id);
+	DLB_CSR_WR(hw, CHP_LDB_CQ2VAS(port->id), reg);
+
+	/* Disable the port's QID mappings */
+	reg = 0;
+	DLB_CSR_WR(hw, LSP_CQ2PRIOV(port->id), reg);
+
+	return 0;
+}
+
+static int dlb_configure_ldb_port(struct dlb_hw *hw, struct dlb_hw_domain *domain,
+				  struct dlb_ldb_port *port,
+				  uintptr_t cq_dma_base,
+				  struct dlb_create_ldb_port_args *args)
+{
+	int ret, i;
+
+	port->hist_list_entry_base = domain->hist_list_entry_base +
+				     domain->hist_list_entry_offset;
+	port->hist_list_entry_limit = port->hist_list_entry_base +
+				      args->cq_history_list_size;
+
+	domain->hist_list_entry_offset += args->cq_history_list_size;
+	domain->avail_hist_list_entries -= args->cq_history_list_size;
+
+	ret = dlb_ldb_port_configure_cq(hw,
+					domain,
+					port,
+					cq_dma_base,
+					args);
+	if (ret)
+		return ret;
+
+	dlb_ldb_port_configure_pp(hw, domain, port);
+
+	dlb_ldb_port_cq_enable(hw, port);
+
+	for (i = 0; i < DLB_MAX_NUM_QIDS_PER_LDB_CQ; i++)
+		port->qid_map[i].state = DLB_QUEUE_UNMAPPED;
+	port->num_mappings = 0;
+
+	port->enabled = true;
+
+	port->configured = true;
+
+	return 0;
+}
+
+static void dlb_dir_port_configure_pp(struct dlb_hw *hw,
+				      struct dlb_hw_domain *domain,
+				      struct dlb_dir_pq_pair *port)
+{
+	u32 reg;
+
+	reg = FIELD_PREP(SYS_DIR_PP2VAS_VAS, domain->id);
+	DLB_CSR_WR(hw, SYS_DIR_PP2VAS(port->id), reg);
+
+	reg = 0;
+	reg |= SYS_DIR_PP_V_PP_V;
+	DLB_CSR_WR(hw, SYS_DIR_PP_V(port->id), reg);
+}
+
+static int dlb_dir_port_configure_cq(struct dlb_hw *hw,
+				     struct dlb_hw_domain *domain,
+				     struct dlb_dir_pq_pair *port,
+				     uintptr_t cq_dma_base,
+				     struct dlb_create_dir_port_args *args)
+{
+	u32 reg;
+	u32 ds, n;
+
+	/* The CQ address is 64B-aligned, and the DLB only wants bits [63:6] */
+	reg = FIELD_PREP(SYS_DIR_CQ_ADDR_L_ADDR_L, cq_dma_base >> 6);
+	DLB_CSR_WR(hw, SYS_DIR_CQ_ADDR_L(port->id), reg);
+
+	reg = cq_dma_base >> 32;
+	DLB_CSR_WR(hw, SYS_DIR_CQ_ADDR_U(port->id), reg);
+
+	/*
+	 * 'ro' == relaxed ordering. This setting allows DLB to write
+	 * cache lines out-of-order (but QEs within a cache line are always
+	 * updated in-order).
+	 */
+	reg = FIELD_PREP(SYS_DIR_CQ2VF_PF_RO_IS_PF, 1);
+	reg |= SYS_DIR_CQ2VF_PF_RO_RO;
+
+	DLB_CSR_WR(hw, SYS_DIR_CQ2VF_PF_RO(port->id), reg);
+
+	if (!dlb_cq_depth_is_valid(args->cq_depth)) {
+		dev_err(hw_to_dev(hw),
+			"[%s():%d] Internal error: invalid CQ depth\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (args->cq_depth <= 8) {
+		ds = 1;
+	} else {
+		n = ilog2(args->cq_depth);
+		ds = (n - 2) & 0x0f;
+	}
+
+	reg = FIELD_PREP(CHP_DIR_CQ_TKN_DEPTH_SEL_TOKEN_DEPTH_SELECT, ds);
+	DLB_CSR_WR(hw, CHP_DIR_CQ_TKN_DEPTH_SEL(port->id), reg);
+
+	/*
+	 * To support CQs with depth less than 8, program the token count
+	 * register with a non-zero initial value. Operations such as domain
+	 * reset must take this initial value into account when quiescing the
+	 * CQ.
+	 */
+	port->init_tkn_cnt = 0;
+
+	if (args->cq_depth < 8) {
+		port->init_tkn_cnt = 8 - args->cq_depth;
+
+		reg = FIELD_PREP(LSP_CQ_DIR_TKN_CNT_COUNT, port->init_tkn_cnt);
+		DLB_CSR_WR(hw, LSP_CQ_DIR_TKN_CNT(port->id), reg);
+	} else {
+		DLB_CSR_WR(hw,
+			   LSP_CQ_DIR_TKN_CNT(port->id),
+			   LSP_CQ_DIR_TKN_CNT_RST);
+	}
+
+	reg = FIELD_PREP(LSP_CQ_DIR_TKN_DEPTH_SEL_DSI_TOKEN_DEPTH_SELECT, ds);
+	DLB_CSR_WR(hw, LSP_CQ_DIR_TKN_DEPTH_SEL_DSI(port->id), reg);
+
+	/* Reset the CQ write pointer */
+	DLB_CSR_WR(hw,
+		   CHP_DIR_CQ_WPTR(port->id),
+		   CHP_DIR_CQ_WPTR_RST);
+
+	/* Virtualize the PPID */
+	reg = 0;
+	DLB_CSR_WR(hw, SYS_DIR_CQ_FMT(port->id), reg);
+
+	/*
+	 * Address translation (AT) settings: 0: untranslated, 2: translated
+	 * (see ATS spec regarding Address Type field for more details)
+	 */
+	reg = 0;
+	DLB_CSR_WR(hw, SYS_DIR_CQ_AT(port->id), reg);
+
+	DLB_CSR_WR(hw, SYS_DIR_CQ_PASID(port->id), reg);
+
+	reg = FIELD_PREP(CHP_DIR_CQ2VAS_CQ2VAS, domain->id);
+	DLB_CSR_WR(hw, CHP_DIR_CQ2VAS(port->id), reg);
+
+	return 0;
+}
+
+static int dlb_configure_dir_port(struct dlb_hw *hw, struct dlb_hw_domain *domain,
+				  struct dlb_dir_pq_pair *port,
+				  uintptr_t cq_dma_base,
+				  struct dlb_create_dir_port_args *args)
+{
+	int ret;
+
+	ret = dlb_dir_port_configure_cq(hw, domain, port, cq_dma_base,
+					args);
+
+	if (ret)
+		return ret;
+
+	dlb_dir_port_configure_pp(hw, domain, port);
+
+	dlb_dir_port_cq_enable(hw, port);
+
+	port->enabled = true;
+
+	port->port_configured = true;
+
+	return 0;
+}
+
 static void
 dlb_log_create_sched_domain_args(struct dlb_hw *hw,
 				 struct dlb_create_sched_domain_args *args)
@@ -1503,6 +1793,11 @@ int dlb_hw_create_ldb_port(struct dlb_hw *hw, u32 domain_id,
 	if (ret)
 		return ret;
 
+	ret = dlb_configure_ldb_port(hw, domain, port, cq_dma_base,
+				     args);
+	if (ret)
+		return ret;
+
 	/*
 	 * Configuration succeeded, so move the resource from the 'avail' to
 	 * the 'used' list.
@@ -1571,6 +1866,11 @@ int dlb_hw_create_dir_port(struct dlb_hw *hw, u32 domain_id,
 	if (ret)
 		return ret;
 
+	ret = dlb_configure_dir_port(hw, domain, port, cq_dma_base,
+				     args);
+	if (ret)
+		return ret;
+
 	/*
 	 * Configuration succeeded, so move the resource from the 'avail' to
 	 * the 'used' list (if it's not already there).
@@ -1670,6 +1970,33 @@ static void dlb_drain_ldb_cq(struct dlb_hw *hw, struct dlb_ldb_port *port)
 	}
 }
 
+static int dlb_domain_wait_for_ldb_cqs_to_empty(struct dlb_hw *hw,
+						struct dlb_hw_domain *domain)
+{
+	struct dlb_ldb_port *port;
+	int i;
+
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++) {
+		list_for_each_entry(port, &domain->used_ldb_ports[i], domain_list) {
+			int j;
+
+			for (j = 0; j < DLB_MAX_CQ_COMP_CHECK_LOOPS; j++) {
+				if (dlb_ldb_cq_inflight_count(hw, port) == 0)
+					break;
+			}
+
+			if (j == DLB_MAX_CQ_COMP_CHECK_LOOPS) {
+				dev_err(hw_to_dev(hw),
+					"[%s()] Internal error: failed to flush load-balanced port %d's completions.\n",
+					__func__, port->id);
+				return -EFAULT;
+			}
+		}
+	}
+
+	return 0;
+}
+
 /*
  * dlb_domain_reset_software_state() - returns domain's resources
  * @hw: dlb_hw handle for a particular device.
@@ -2348,7 +2675,10 @@ static u32 dlb_dir_cq_token_count(struct dlb_hw *hw,
 static int dlb_domain_verify_reset_success(struct dlb_hw *hw,
 					   struct dlb_hw_domain *domain)
 {
+	struct dlb_dir_pq_pair *dir_port;
+	struct dlb_ldb_port *ldb_port;
 	struct dlb_ldb_queue *queue;
+	int i;
 
 	/*
 	 * Confirm that all the domain's queue's inflight counts and AQED
@@ -2363,6 +2693,35 @@ static int dlb_domain_verify_reset_success(struct dlb_hw *hw,
 		}
 	}
 
+	/* Confirm that all the domain's CQs inflight and token counts are 0. */
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++) {
+		list_for_each_entry(ldb_port, &domain->used_ldb_ports[i], domain_list) {
+			if (dlb_ldb_cq_inflight_count(hw, ldb_port) ||
+			    dlb_ldb_cq_token_count(hw, ldb_port)) {
+				dev_err(hw_to_dev(hw),
+					"[%s()] Internal error: failed to empty ldb port %d\n",
+					__func__, ldb_port->id);
+				return -EFAULT;
+			}
+		}
+	}
+
+	list_for_each_entry(dir_port, &domain->used_dir_pq_pairs, domain_list) {
+		if (!dlb_dir_queue_is_empty(hw, dir_port)) {
+			dev_err(hw_to_dev(hw),
+				"[%s()] Internal error: failed to empty dir queue %d\n",
+				__func__, dir_port->id);
+			return -EFAULT;
+		}
+
+		if (dlb_dir_cq_token_count(hw, dir_port)) {
+			dev_err(hw_to_dev(hw),
+				"[%s()] Internal error: failed to empty dir port %d\n",
+				__func__, dir_port->id);
+			return -EFAULT;
+		}
+	}
+
 	return 0;
 }
 
@@ -2580,6 +2939,51 @@ static int dlb_domain_drain_dir_queues(struct dlb_hw *hw,
 	return 0;
 }
 
+static void
+dlb_domain_disable_dir_producer_ports(struct dlb_hw *hw,
+				      struct dlb_hw_domain *domain)
+{
+	struct dlb_dir_pq_pair *port;
+	u32 pp_v = 0;
+
+	list_for_each_entry(port, &domain->used_dir_pq_pairs, domain_list) {
+		DLB_CSR_WR(hw, SYS_DIR_PP_V(port->id), pp_v);
+	}
+}
+
+static void
+dlb_domain_disable_ldb_producer_ports(struct dlb_hw *hw,
+				      struct dlb_hw_domain *domain)
+{
+	struct dlb_ldb_port *port;
+	u32 pp_v = 0;
+	int i;
+
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++) {
+		list_for_each_entry(port, &domain->used_ldb_ports[i], domain_list) {
+			DLB_CSR_WR(hw,
+				   SYS_LDB_PP_V(port->id),
+				   pp_v);
+		}
+	}
+}
+
+static void dlb_domain_disable_ldb_seq_checks(struct dlb_hw *hw,
+					      struct dlb_hw_domain *domain)
+{
+	struct dlb_ldb_port *port;
+	u32 chk_en = 0;
+	int i;
+
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++) {
+		list_for_each_entry(port, &domain->used_ldb_ports[i], domain_list) {
+			DLB_CSR_WR(hw,
+				   CHP_SN_CHK_ENBL(port->id),
+				   chk_en);
+		}
+	}
+}
+
 static void
 dlb_domain_disable_ldb_queue_write_perms(struct dlb_hw *hw,
 					 struct dlb_hw_domain *domain)
@@ -2697,6 +3101,9 @@ int dlb_reset_domain(struct dlb_hw *hw, u32 domain_id)
 
 	dlb_domain_disable_ldb_queue_write_perms(hw, domain);
 
+	/* Turn off completion tracking on all the domain's PPs. */
+	dlb_domain_disable_ldb_seq_checks(hw, domain);
+
 	/*
 	 * Disable the LDB CQs and drain them in order to complete the map and
 	 * unmap procedures, which require zero CQ inflights and zero QID
@@ -2706,6 +3113,10 @@ int dlb_reset_domain(struct dlb_hw *hw, u32 domain_id)
 
 	dlb_domain_drain_ldb_cqs(hw, domain, false);
 
+	ret = dlb_domain_wait_for_ldb_cqs_to_empty(hw, domain);
+	if (ret)
+		return ret;
+
 	/* Re-enable the CQs in order to drain the mapped queues. */
 	dlb_domain_enable_ldb_cqs(hw, domain);
 
@@ -2721,6 +3132,11 @@ int dlb_reset_domain(struct dlb_hw *hw, u32 domain_id)
 	/* Done draining DIR QEs, so disable the CQs. */
 	dlb_domain_disable_dir_cqs(hw, domain);
 
+	/* Disable PPs */
+	dlb_domain_disable_dir_producer_ports(hw, domain);
+
+	dlb_domain_disable_ldb_producer_ports(hw, domain);
+
 	ret = dlb_domain_verify_reset_success(hw, domain);
 	if (ret)
 		return ret;
@@ -2752,7 +3168,7 @@ void dlb_clr_pmcsr_disable(struct dlb_hw *hw)
 
 /**
  * dlb_hw_enable_sparse_ldb_cq_mode() - enable sparse mode for load-balanced
- *      ports.
+ *	ports.
  * @hw: dlb_hw handle for a particular device.
  *
  * This function must be called prior to configuring scheduling domains.
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [RFC PATCH v12 13/17] dlb: add port mmap support
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
                   ` (11 preceding siblings ...)
  2021-12-21  6:50 ` [RFC PATCH v12 12/17] dlb: add register operations for port management Mike Ximing Chen
@ 2021-12-21  6:50 ` Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 14/17] dlb: add start domain configfs attribute Mike Ximing Chen
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

Once a port is created, the application can mmap the corresponding DMA
memory and MMIO into user-space. This allows user-space applications to
do (performance-sensitive) enqueue and dequeue independent of the kernel
driver.

The mmap callback is only available through special port files: a producer
port (PP) file and a consumer queue (CQ) file. User-space gets an fd for
these files by calling a new ioctl, DLB_DOMAIN_CMD_GET_{LDB,
DIR}_PORT_{PP, CQ}_FD, and passing in a port ID. If the ioctl succeeds, the
returned fd can be used to mmap that port's PP/CQ.

Device reset requires first unmapping all user-space mappings, to prevent
applications from interfering with the reset operation. To this end, the
driver uses a single inode -- allocated when the first PP/CQ file is
created, and freed when the last such file is closed -- and attaches all
port files to this common inode, as done elsewhere in Linux (e.g. cxl,
dax).

Allocating this inode requires creating a pseudo-filesystem. The driver
initializes this FS when the inode is allocated, and frees the FS after the
inode is freed.

The driver doesn't use anon_inode_getfd() for these port mmap files because
the anon inode layer uses a single inode that is shared with other kernel
components -- calling unmap_mapping_range() on that shared inode would
likely break the kernel.

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
---
 drivers/misc/dlb/Makefile       |   1 +
 drivers/misc/dlb/dlb_args.h     |  31 ++++++
 drivers/misc/dlb/dlb_configfs.c | 162 ++++++++++++++++++++++++++++++++
 drivers/misc/dlb/dlb_configfs.h |  70 ++++++++++++++
 drivers/misc/dlb/dlb_file.c     | 149 +++++++++++++++++++++++++++++
 drivers/misc/dlb/dlb_main.c     | 120 +++++++++++++++++++++++
 drivers/misc/dlb/dlb_main.h     |  24 +++++
 drivers/misc/dlb/dlb_resource.c | 109 +++++++++++++++++++++
 8 files changed, 666 insertions(+)
 create mode 100644 drivers/misc/dlb/dlb_file.c

diff --git a/drivers/misc/dlb/Makefile b/drivers/misc/dlb/Makefile
index 1567bfdfc7a7..c7a8a3235a4a 100644
--- a/drivers/misc/dlb/Makefile
+++ b/drivers/misc/dlb/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_INTEL_DLB) := dlb.o
 
 dlb-objs := dlb_main.o
 dlb-objs += dlb_pf_ops.o dlb_resource.o dlb_configfs.o
+dlb-objs += dlb_file.o
diff --git a/drivers/misc/dlb/dlb_args.h b/drivers/misc/dlb/dlb_args.h
index b54483bfa767..b16670e62370 100644
--- a/drivers/misc/dlb/dlb_args.h
+++ b/drivers/misc/dlb/dlb_args.h
@@ -189,6 +189,8 @@ struct dlb_get_dir_queue_depth_args {
 struct dlb_create_ldb_port_args {
 	/* Output parameters */
 	struct dlb_cmd_response response;
+	__u32 pp_fd;
+	__u32 cq_fd;
 	/* Input parameters */
 	__u16 cq_depth;
 	__u16 cq_depth_threshold;
@@ -216,12 +218,41 @@ struct dlb_create_ldb_port_args {
 struct dlb_create_dir_port_args {
 	/* Output parameters */
 	struct dlb_cmd_response response;
+	__u32 pp_fd;
+	__u32 cq_fd;
 	/* Input parameters */
 	__u16 cq_depth;
 	__u16 cq_depth_threshold;
 	__s32 queue_id;
 };
 
+/*
+ * dlb_get_port_fd_args: Used to get file descriptor to mmap a producer port
+ *	(PP) or a consumer queue (CQ)
+ *
+ *	The port must have been previously created in the device's configfs.
+ *	The fd is used to mmap the PP/CQ region.
+ *
+ * Output parameters:
+ * @response.status: Detailed error code. In certain cases, such as if the
+ *	request arg is invalid, the driver won't set status.
+ * @response.id: fd.
+ *
+ * Input parameters:
+ * @port_id: port ID.
+ */
+struct dlb_get_port_fd_args {
+	/* Output parameters */
+	struct dlb_cmd_response response;
+	/* Input parameters */
+	__u32 port_id;
+};
+
+/*
+ * Mapping sizes for memory mapping the consumer queue (CQ) memory space, and
+ * producer port (PP) MMIO space.
+ */
 #define DLB_CQ_SIZE 65536
+#define DLB_PP_SIZE 4096
 
 #endif /* __DLB_ARGS_H */
diff --git a/drivers/misc/dlb/dlb_configfs.c b/drivers/misc/dlb/dlb_configfs.c
index 045d1dae2b7f..1401ad1a04de 100644
--- a/drivers/misc/dlb/dlb_configfs.c
+++ b/drivers/misc/dlb/dlb_configfs.c
@@ -45,6 +45,90 @@ DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(create_dir_queue)
 DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(get_ldb_queue_depth)
 DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(get_dir_queue_depth)
 
+static int dlb_create_port_fd(struct dlb *dlb,
+			      const char *prefix,
+			      u32 id,
+			      const struct file_operations *fops,
+			      int *fd,
+			      struct file **f)
+{
+	char *name;
+	int ret;
+
+	ret = get_unused_fd_flags(O_RDWR);
+	if (ret < 0)
+		return ret;
+
+	*fd = ret;
+
+	name = kasprintf(GFP_KERNEL, "%s:%d", prefix, id);
+	if (!name) {
+		put_unused_fd(*fd);
+		return -ENOMEM;
+	}
+
+	*f = dlb_getfile(dlb, O_RDWR | O_CLOEXEC, fops, name);
+
+	kfree(name);
+
+	if (IS_ERR(*f)) {
+		put_unused_fd(*fd);
+		return PTR_ERR(*f);
+	}
+
+	return 0;
+}
+
+static int dlb_domain_get_port_fd(struct dlb *dlb,
+				  struct dlb_domain *domain,
+				  u32 port_id,
+				  int *fd,
+				  const char *name,
+				  const struct file_operations *fops,
+				  bool is_ldb)
+{
+	struct dlb_port *port;
+	struct file *file;
+	int ret;
+
+	if (is_ldb && dlb_ldb_port_owned_by_domain(&dlb->hw, domain->id,
+						   port_id) != 1) {
+		ret = -EINVAL;
+		goto end;
+	}
+
+	if (!is_ldb && dlb_dir_port_owned_by_domain(&dlb->hw, domain->id,
+						    port_id) != 1) {
+		ret = -EINVAL;
+		goto end;
+	}
+
+	port = (is_ldb) ? &dlb->ldb_port[port_id] : &dlb->dir_port[port_id];
+
+	if (!port->valid) {
+		ret = -EINVAL;
+		goto end;
+	}
+
+	ret = dlb_create_port_fd(dlb, name, port_id, fops, fd, &file);
+	if (ret < 0)
+		goto end;
+
+	file->private_data = port;
+end:
+	/*
+	 * Save fd_install() until after the last point of failure. The domain
+	 * refcnt is decremented in the close callback.
+	 */
+	if (ret == 0) {
+		kref_get(&domain->refcnt);
+
+		fd_install(*fd, file);
+	}
+
+	return ret;
+}
+
 static int dlb_domain_configfs_create_ldb_port(struct dlb *dlb,
 					       struct dlb_domain *domain,
 					       void *karg)
@@ -132,6 +216,7 @@ static int dlb_domain_configfs_create_dir_port(struct dlb *dlb,
 	dlb->dir_port[response.id].cq_base = cq_base;
 	dlb->dir_port[response.id].cq_dma_base = cq_dma_base;
 	dlb->dir_port[response.id].valid = true;
+
 unlock:
 	if (ret && cq_dma_base)
 		dma_free_coherent(&dlb->pdev->dev,
@@ -200,6 +285,28 @@ static int dlb_configfs_create_sched_domain(struct dlb *dlb,
 	return ret;
 }
 
+/*
+ * Reset the file descriptors for the producer port and consumer queue. Used
+ * a port is closed.
+ *
+ */
+int dlb_configfs_reset_port_fd(struct dlb *dlb,
+			       struct dlb_domain *dlb_domain,
+			       int port_id)
+{
+	struct dlb_cfs_port *dlb_cfs_port;
+
+	dlb_cfs_port = dlb_configfs_get_port_from_id(dlb, dlb_domain, port_id);
+
+	if (!dlb_cfs_port)
+		return -EINVAL;
+
+	dlb_cfs_port->pp_fd = 0xffffffff;
+	dlb_cfs_port->cq_fd = 0xffffffff;
+
+	return 0;
+}
+
 /*
  * Configfs directory structure for dlb driver implementation:
  *
@@ -457,6 +564,52 @@ static ssize_t dlb_cfs_port_##name##_show(				\
 	return sprintf(page, "%llx\n", to_dlb_cfs_port(item)->name);	\
 }									\
 
+#define DLB_CONFIGFS_PORT_SHOW_FD(name)					\
+static ssize_t dlb_cfs_port_##name##_show(				\
+	struct config_item *item,					\
+	char *page)							\
+{									\
+	struct dlb_cfs_port *dlb_cfs_port = to_dlb_cfs_port(item);	\
+	char filename[16], prefix[16];					\
+	struct dlb_domain *domain;					\
+	struct dlb *dlb = NULL;						\
+	int port_id, is_ldb;						\
+	int fd, ret;							\
+									\
+	if (to_dlb_cfs_port(item)->name != 0xffffffff)			\
+		goto end;						\
+									\
+	ret = dlb_configfs_get_dlb_domain(dlb_cfs_port->domain_grp,	\
+					    &dlb, &domain);		\
+	if (ret)							\
+		return ret;						\
+									\
+	port_id = dlb_cfs_port->port_id;				\
+	is_ldb = dlb_cfs_port->is_ldb;					\
+									\
+	if (is_ldb)							\
+		sprintf(filename, "dlb_ldb");				\
+	else								\
+		sprintf(filename, "dlb_dir");				\
+									\
+	if (!strcmp(#name, "pp_fd")) {					\
+		sprintf(prefix, "%s_pp:", filename);			\
+		ret = dlb_domain_get_port_fd(dlb, domain, port_id,	\
+				&fd, prefix, &dlb_pp_fops, is_ldb);	\
+		dlb_cfs_port->pp_fd = fd;				\
+	} else {							\
+		sprintf(prefix, "%s_cq:", filename);			\
+		ret = dlb_domain_get_port_fd(dlb, domain, port_id,	\
+				&fd, prefix, &dlb_cq_fops, is_ldb);	\
+		dlb_cfs_port->cq_fd = fd;				\
+	}								\
+									\
+	if (ret)							\
+		return ret;						\
+end:									\
+	return sprintf(page, "%u\n", to_dlb_cfs_port(item)->name);	\
+}									\
+
 #define DLB_CONFIGFS_PORT_STORE(name)					\
 static ssize_t dlb_cfs_port_##name##_store(				\
 	struct config_item *item,					\
@@ -489,6 +642,8 @@ static ssize_t dlb_cfs_port_##name##_store(				\
 	return count;							\
 }									\
 
+DLB_CONFIGFS_PORT_SHOW_FD(pp_fd)
+DLB_CONFIGFS_PORT_SHOW_FD(cq_fd)
 DLB_CONFIGFS_PORT_SHOW(status)
 DLB_CONFIGFS_PORT_SHOW(port_id)
 DLB_CONFIGFS_PORT_SHOW(is_ldb)
@@ -556,6 +711,9 @@ static ssize_t dlb_cfs_port_create_store(struct config_item *item,
 		dlb_cfs_port->port_id = args.response.id;
 	}
 
+	dlb_cfs_port->pp_fd = 0xffffffff;
+	dlb_cfs_port->cq_fd = 0xffffffff;
+
 	if (ret) {
 		dev_err(dlb->dev,
 			"creat port %s failed: ret=%d\n",
@@ -566,6 +724,8 @@ static ssize_t dlb_cfs_port_create_store(struct config_item *item,
 	return count;
 }
 
+CONFIGFS_ATTR_RO(dlb_cfs_port_, pp_fd);
+CONFIGFS_ATTR_RO(dlb_cfs_port_, cq_fd);
 CONFIGFS_ATTR_RO(dlb_cfs_port_, status);
 CONFIGFS_ATTR_RO(dlb_cfs_port_, port_id);
 CONFIGFS_ATTR(dlb_cfs_port_, is_ldb);
@@ -576,6 +736,8 @@ CONFIGFS_ATTR(dlb_cfs_port_, create);
 CONFIGFS_ATTR(dlb_cfs_port_, queue_id);
 
 static struct configfs_attribute *dlb_cfs_port_attrs[] = {
+	&dlb_cfs_port_attr_pp_fd,
+	&dlb_cfs_port_attr_cq_fd,
 	&dlb_cfs_port_attr_status,
 	&dlb_cfs_port_attr_port_id,
 	&dlb_cfs_port_attr_is_ldb,
diff --git a/drivers/misc/dlb/dlb_configfs.h b/drivers/misc/dlb/dlb_configfs.h
index 06f4f93d4139..23874abfa42e 100644
--- a/drivers/misc/dlb/dlb_configfs.h
+++ b/drivers/misc/dlb/dlb_configfs.h
@@ -11,6 +11,8 @@ struct dlb_device_configfs {
 	struct dlb *dlb;
 };
 
+extern struct dlb_device_configfs dlb_dev_configfs[16];
+
 struct dlb_cfs_domain {
 	struct config_group group;
 	struct config_group *dev_grp;
@@ -56,6 +58,8 @@ struct dlb_cfs_port {
 	struct config_group *domain_grp;
 	unsigned int status;
 	unsigned int port_id;
+	unsigned int pp_fd;
+	unsigned int cq_fd;
 	/* Input parameters */
 	unsigned int is_ldb;
 	unsigned int cq_depth;
@@ -118,4 +122,70 @@ int dlb_configfs_get_dlb_domain(struct config_group *domain_grp,
 
 	return 0;
 }
+
+static inline struct config_item *to_item(struct list_head *entry)
+{
+	return container_of(entry, struct config_item, ci_entry);
+}
+
+/*
+ * Find configfs group for a port from a port_id.
+ *
+ */
+static inline
+struct dlb_cfs_port *dlb_configfs_get_port_from_id(struct dlb *dlb,
+					struct dlb_domain *dlb_domain,
+					int port_id)
+{
+	struct dlb_cfs_domain *dlb_cfs_domain = NULL;
+	struct dlb_cfs_port *dlb_cfs_port = NULL;
+	struct config_group *dev_grp;
+	struct list_head *entry;
+	int grp_found = 0;
+
+	dev_grp = &dlb_dev_configfs[dlb->id].dev_group;
+
+	list_for_each(entry, &dev_grp->cg_children) {
+		struct config_item *item = to_item(entry);
+
+		if (config_item_name(item))
+			dev_dbg(dlb->dev,
+				"%s: item = %s\n", __func__,
+				config_item_name(item));
+
+		dlb_cfs_domain = to_dlb_cfs_domain(item);
+
+		if (dlb_cfs_domain->domain_id == dlb_domain->id) {
+			grp_found = 1;
+			break;
+		}
+	}
+
+	if (!grp_found)
+		return NULL;
+
+	grp_found = 0;
+
+	list_for_each(entry, &dlb_cfs_domain->group.cg_children) {
+		struct config_item *item = to_item(entry);
+
+		if (strnstr(config_item_name(item), "port", 5)) {
+			dev_dbg(dlb->dev,
+				"%s: item = %s\n", __func__,
+				config_item_name(item));
+
+			dlb_cfs_port = to_dlb_cfs_port(item);
+
+			if (dlb_cfs_port->port_id == port_id) {
+				grp_found = 1;
+				break;
+			}
+		}
+	}
+
+	if (!grp_found)
+		return NULL;
+
+	return dlb_cfs_port;
+}
 #endif /* DLB_CONFIGFS_H */
diff --git a/drivers/misc/dlb/dlb_file.c b/drivers/misc/dlb/dlb_file.c
new file mode 100644
index 000000000000..310b86735353
--- /dev/null
+++ b/drivers/misc/dlb/dlb_file.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(C) 2016-2020 Intel Corporation. All rights reserved. */
+
+#include <linux/anon_inodes.h>
+#include <linux/file.h>
+#include <linux/module.h>
+#include <linux/mount.h>
+#include <linux/pseudo_fs.h>
+
+#include "dlb_main.h"
+
+/*
+ * dlb tracks its memory mappings so it can revoke them when an FLR is
+ * requested and user-space cannot be allowed to access the device. To achieve
+ * that, the driver creates a single inode through which all driver-created
+ * files can share a struct address_space, and unmaps the inode's address space
+ * during the reset preparation phase. Since the anon inode layer shares its
+ * inode with multiple kernel components, we cannot use that here.
+ *
+ * Doing so requires a custom pseudo-filesystem to allocate the inode. The FS
+ * and the inode are allocated on demand when a file is created, and both are
+ * freed when the last such file is closed.
+ *
+ * This is inspired by other drivers (cxl, dax, mem) and the anon inode layer.
+ */
+static int dlb_fs_cnt;
+static struct vfsmount *dlb_vfs_mount;
+
+#define DLBFS_MAGIC 0x444C4232 /* ASCII for DLB */
+static int dlb_init_fs_context(struct fs_context *fc)
+{
+	return init_pseudo(fc, DLBFS_MAGIC) ? 0 : -ENOMEM;
+}
+
+static struct file_system_type dlb_fs_type = {
+	.name	 = "dlb",
+	.owner	 = THIS_MODULE,
+	.init_fs_context = dlb_init_fs_context,
+	.kill_sb = kill_anon_super,
+};
+
+/* Allocate an anonymous inode. Must hold the resource mutex while calling. */
+static struct inode *dlb_alloc_inode(struct dlb *dlb)
+{
+	struct inode *inode;
+	int ret;
+
+	/* Increment the pseudo-FS's refcnt and (if not already) mount it. */
+	ret = simple_pin_fs(&dlb_fs_type, &dlb_vfs_mount, &dlb_fs_cnt);
+	if (ret < 0) {
+		dev_err(dlb->dev,
+			"[%s()] Cannot mount pseudo filesystem: %d\n",
+			__func__, ret);
+		return ERR_PTR(ret);
+	}
+
+	dlb->inode_cnt++;
+
+	if (dlb->inode_cnt > 1) {
+		/*
+		 * Return the previously allocated inode. In this case, there
+		 * is guaranteed >= 1 reference and so ihold() is safe to call.
+		 */
+		ihold(dlb->inode);
+		return dlb->inode;
+	}
+
+	inode = alloc_anon_inode(dlb_vfs_mount->mnt_sb);
+	if (IS_ERR(inode)) {
+		dev_err(dlb->dev,
+			"[%s()] Cannot allocate inode: %ld\n",
+			__func__, PTR_ERR(inode));
+		dlb->inode_cnt = 0;
+		simple_release_fs(&dlb_vfs_mount, &dlb_fs_cnt);
+	}
+
+	dlb->inode = inode;
+
+	return inode;
+}
+
+/*
+ * Decrement the inode reference count and release the FS. Intended for
+ * unwinding dlb_alloc_inode(). Must hold the resource mutex while calling.
+ */
+static void dlb_free_inode(struct inode *inode)
+{
+	iput(inode);
+	simple_release_fs(&dlb_vfs_mount, &dlb_fs_cnt);
+}
+
+/*
+ * Release the FS. Intended for use in a file_operations release callback,
+ * which decrements the inode reference count separately. Must hold the
+ * resource mutex while calling.
+ */
+void dlb_release_fs(struct dlb *dlb)
+{
+	mutex_lock(&dlb_driver_mutex);
+
+	simple_release_fs(&dlb_vfs_mount, &dlb_fs_cnt);
+
+	dlb->inode_cnt--;
+
+	/* When the fs refcnt reaches zero, the inode has been freed */
+	if (dlb->inode_cnt == 0)
+		dlb->inode = NULL;
+
+	mutex_unlock(&dlb_driver_mutex);
+}
+
+/*
+ * Allocate a file with the requested flags, file operations, and name that
+ * uses the device's shared inode. Must hold the resource mutex while calling.
+ *
+ * Caller must separately allocate an fd and install the file in that fd.
+ */
+struct file *dlb_getfile(struct dlb *dlb,
+			 int flags,
+			 const struct file_operations *fops,
+			 const char *name)
+{
+	struct inode *inode;
+	struct file *f;
+
+	if (!try_module_get(THIS_MODULE))
+		return ERR_PTR(-ENOENT);
+
+	mutex_lock(&dlb_driver_mutex);
+
+	inode = dlb_alloc_inode(dlb);
+	if (IS_ERR(inode)) {
+		mutex_unlock(&dlb_driver_mutex);
+		module_put(THIS_MODULE);
+		return ERR_CAST(inode);
+	}
+
+	f = alloc_file_pseudo(inode, dlb_vfs_mount, name, flags, fops);
+	if (IS_ERR(f)) {
+		dlb_free_inode(inode);
+		mutex_unlock(&dlb_driver_mutex);
+		module_put(THIS_MODULE);
+		return f;
+	}
+
+	mutex_unlock(&dlb_driver_mutex);
+
+	return f;
+}
diff --git a/drivers/misc/dlb/dlb_main.c b/drivers/misc/dlb/dlb_main.c
index 9e6168b27859..ce3cbe15e198 100644
--- a/drivers/misc/dlb/dlb_main.c
+++ b/drivers/misc/dlb/dlb_main.c
@@ -16,6 +16,9 @@
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Intel(R) Dynamic Load Balancer (DLB) Driver");
 
+/* The driver mutex protects data structures that used by multiple devices. */
+DEFINE_MUTEX(dlb_driver_mutex);
+
 static struct class *dlb_class;
 static struct cdev dlb_cdev;
 static dev_t dlb_devt;
@@ -226,6 +229,123 @@ const struct file_operations dlb_domain_fops = {
 	.release = dlb_domain_close,
 };
 
+static unsigned long dlb_get_pp_addr(struct dlb *dlb, struct dlb_port *port)
+{
+	unsigned long pgoff = dlb->hw.func_phys_addr;
+
+	if (port->is_ldb)
+		pgoff += DLB_LDB_PP_OFFSET(port->id);
+	else
+		pgoff += DLB_DIR_PP_OFFSET(port->id);
+
+	return pgoff;
+}
+
+static int dlb_pp_mmap(struct file *f, struct vm_area_struct *vma)
+{
+	struct dlb_port *port = f->private_data;
+	struct dlb_domain *domain = port->domain;
+	struct dlb *dlb = domain->dlb;
+	unsigned long pgoff;
+	pgprot_t pgprot;
+	int ret;
+
+	mutex_lock(&dlb->resource_mutex);
+
+	if ((vma->vm_end - vma->vm_start) != DLB_PP_SIZE) {
+		ret = -EINVAL;
+		goto end;
+	}
+
+	pgprot = pgprot_noncached(vma->vm_page_prot);
+
+	pgoff = dlb_get_pp_addr(dlb, port);
+	ret = io_remap_pfn_range(vma,
+				 vma->vm_start,
+				 pgoff >> PAGE_SHIFT,
+				 vma->vm_end - vma->vm_start,
+				 pgprot);
+
+end:
+	mutex_unlock(&dlb->resource_mutex);
+
+	return ret;
+}
+
+static int dlb_cq_mmap(struct file *f, struct vm_area_struct *vma)
+{
+	struct dlb_port *port = f->private_data;
+	struct dlb_domain *domain = port->domain;
+	struct dlb *dlb = domain->dlb;
+	struct page *page;
+	int ret;
+
+	mutex_lock(&dlb->resource_mutex);
+
+	if ((vma->vm_end - vma->vm_start) != DLB_CQ_SIZE) {
+		ret = -EINVAL;
+		goto end;
+	}
+
+	page = virt_to_page(port->cq_base);
+
+	ret = remap_pfn_range(vma,
+			      vma->vm_start,
+			      page_to_pfn(page),
+			      vma->vm_end - vma->vm_start,
+			      vma->vm_page_prot);
+end:
+	mutex_unlock(&dlb->resource_mutex);
+
+	return ret;
+}
+
+static void dlb_port_unmap(struct dlb *dlb, struct dlb_port *port)
+{
+	if (!port->cq_base) {
+		unmap_mapping_range(dlb->inode->i_mapping,
+				    (unsigned long)port->cq_base,
+				    DLB_CQ_SIZE, 1);
+	} else {
+		unmap_mapping_range(dlb->inode->i_mapping,
+				    dlb_get_pp_addr(dlb, port),
+				    DLB_PP_SIZE, 1);
+	}
+}
+
+static int dlb_port_close(struct inode *i, struct file *f)
+{
+	struct dlb_port *port = f->private_data;
+	struct dlb_domain *domain = port->domain;
+	struct dlb *dlb = domain->dlb;
+
+	mutex_lock(&dlb->resource_mutex);
+
+	kref_put(&domain->refcnt, dlb_free_domain);
+
+	dlb_port_unmap(dlb, port);
+	dlb_configfs_reset_port_fd(dlb, domain, port->id);
+
+	/* Decrement the refcnt of the pseudo-FS used to allocate the inode */
+	dlb_release_fs(dlb);
+
+	mutex_unlock(&dlb->resource_mutex);
+
+	return 0;
+}
+
+const struct file_operations dlb_pp_fops = {
+	.owner   = THIS_MODULE,
+	.release = dlb_port_close,
+	.mmap    = dlb_pp_mmap,
+};
+
+const struct file_operations dlb_cq_fops = {
+	.owner   = THIS_MODULE,
+	.release = dlb_port_close,
+	.mmap    = dlb_cq_mmap,
+};
+
 /**********************************/
 /****** PCI driver callbacks ******/
 /**********************************/
diff --git a/drivers/misc/dlb/dlb_main.h b/drivers/misc/dlb/dlb_main.h
index fbfbc6e3fc87..b361cf55cd8a 100644
--- a/drivers/misc/dlb/dlb_main.h
+++ b/drivers/misc/dlb/dlb_main.h
@@ -12,6 +12,7 @@
 #include <linux/pci.h>
 #include <linux/types.h>
 #include <linux/bitfield.h>
+#include <linux/file.h>
 
 #include <uapi/linux/dlb.h>
 #include "dlb_args.h"
@@ -318,6 +319,8 @@ struct dlb_hw {
 #define DLB_NUM_FUNCS_PER_DEVICE (1 + DLB_MAX_NUM_VDEVS)
 #define DLB_MAX_NUM_DEVICES	 (DLB_MAX_NUM_PFS * DLB_NUM_FUNCS_PER_DEVICE)
 
+extern struct mutex dlb_driver_mutex;
+
 enum dlb_device_type {
 	DLB_PF,
 };
@@ -332,6 +335,8 @@ int dlb_pf_wait_for_device_ready(struct dlb *dlb, struct pci_dev *pdev);
 void dlb_pf_init_hardware(struct dlb *dlb);
 
 extern const struct file_operations dlb_domain_fops;
+extern const struct file_operations dlb_pp_fops;
+extern const struct file_operations dlb_cq_fops;
 
 struct dlb_port {
 	void *cq_base;
@@ -356,6 +361,11 @@ struct dlb {
 	struct file *f;
 	struct dlb_port ldb_port[DLB_MAX_NUM_LDB_PORTS];
 	struct dlb_port dir_port[DLB_MAX_NUM_DIR_PORTS];
+	/*
+	 * Anonymous inode used to share an address_space for all domain
+	 * device file mappings.
+	 */
+	struct inode *inode;
 	/*
 	 * The resource mutex serializes access to driver data structures and
 	 * hardware registers.
@@ -363,6 +373,7 @@ struct dlb {
 	struct mutex resource_mutex;
 	enum dlb_device_type type;
 	int id;
+	u32 inode_cnt;
 	dev_t dev_number;
 	u8 domain_reset_failed;
 };
@@ -576,6 +587,13 @@ static inline struct device *hw_to_dev(struct dlb_hw *hw)
 	return dlb->dev;
 }
 
+/* Prototypes for dlb_file.c */
+void dlb_release_fs(struct dlb *dlb);
+struct file *dlb_getfile(struct dlb *dlb,
+			 int flags,
+			 const struct file_operations *fops,
+			 const char *name);
+
 /* Prototypes for dlb_resource.c */
 int dlb_resource_init(struct dlb_hw *hw);
 void dlb_resource_free(struct dlb_hw *hw);
@@ -597,6 +615,8 @@ int dlb_hw_create_ldb_port(struct dlb_hw *hw, u32 domain_id,
 			   uintptr_t cq_dma_base,
 			   struct dlb_cmd_response *resp);
 int dlb_reset_domain(struct dlb_hw *hw, u32 domain_id);
+int dlb_ldb_port_owned_by_domain(struct dlb_hw *hw, u32 domain_id, u32 port_id);
+int dlb_dir_port_owned_by_domain(struct dlb_hw *hw, u32 domain_id, u32 port_id);
 void dlb_clr_pmcsr_disable(struct dlb_hw *hw);
 int dlb_hw_get_ldb_queue_depth(struct dlb_hw *hw, u32 domain_id,
 			       struct dlb_get_ldb_queue_depth_args *args,
@@ -611,5 +631,9 @@ void dlb_hw_enable_sparse_dir_cq_mode(struct dlb_hw *hw);
 int dlb_configfs_create_device(struct dlb *dlb);
 int configfs_dlb_init(void);
 void configfs_dlb_exit(void);
+int dlb_configfs_reset_port_fd(struct dlb *dlb,
+			       struct dlb_domain *dlb_domain,
+			       int port_id);
+
 
 #endif /* __DLB_MAIN_H */
diff --git a/drivers/misc/dlb/dlb_resource.c b/drivers/misc/dlb/dlb_resource.c
index d1e1d1efe8c7..b5d75cb9be7a 100644
--- a/drivers/misc/dlb/dlb_resource.c
+++ b/drivers/misc/dlb/dlb_resource.c
@@ -210,6 +210,30 @@ static struct dlb_hw_domain *dlb_get_domain_from_id(struct dlb_hw *hw, u32 id)
 	return &hw->domains[id];
 }
 
+static struct dlb_ldb_port *
+dlb_get_domain_ldb_port(u32 id, bool vdev_req, struct dlb_hw_domain *domain)
+{
+	struct dlb_ldb_port *port;
+	int i;
+
+	if (id >= DLB_MAX_NUM_LDB_PORTS)
+		return NULL;
+
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++) {
+		list_for_each_entry(port, &domain->used_ldb_ports[i], domain_list) {
+			if (!vdev_req && port->id == id)
+				return port;
+		}
+
+		list_for_each_entry(port, &domain->avail_ldb_ports[i], domain_list) {
+			if (!vdev_req && port->id == id)
+				return port;
+		}
+	}
+
+	return NULL;
+}
+
 static struct dlb_dir_pq_pair *
 dlb_get_domain_used_dir_pq(u32 id, bool vdev_req, struct dlb_hw_domain *domain)
 {
@@ -226,6 +250,27 @@ dlb_get_domain_used_dir_pq(u32 id, bool vdev_req, struct dlb_hw_domain *domain)
 	return NULL;
 }
 
+static struct dlb_dir_pq_pair *
+dlb_get_domain_dir_pq(u32 id, bool vdev_req, struct dlb_hw_domain *domain)
+{
+	struct dlb_dir_pq_pair *port;
+
+	if (id >= DLB_MAX_NUM_DIR_PORTS)
+		return NULL;
+
+	list_for_each_entry(port, &domain->used_dir_pq_pairs, domain_list) {
+		if (!vdev_req && port->id == id)
+			return port;
+	}
+
+	list_for_each_entry(port, &domain->avail_dir_pq_pairs, domain_list) {
+		if (!vdev_req && port->id == id)
+			return port;
+	}
+
+	return NULL;
+}
+
 static struct dlb_ldb_queue *
 dlb_get_domain_ldb_queue(u32 id, bool vdev_req, struct dlb_hw_domain *domain)
 {
@@ -3147,6 +3192,70 @@ int dlb_reset_domain(struct dlb_hw *hw, u32 domain_id)
 	return dlb_domain_reset_software_state(hw, domain);
 }
 
+/**
+ * dlb_ldb_port_owned_by_domain() - query whether a port is owned by a domain
+ * @hw: dlb_hw handle for a particular device.
+ * @domain_id: domain ID.
+ * @port_id: port ID.
+ *
+ * This function returns whether a load-balanced port is owned by a specified
+ * domain.
+ *
+ * Return:
+ * Returns 0 if false, 1 if true, <0 otherwise.
+ *
+ * EINVAL - Invalid domain or port ID, or the domain is not configured.
+ */
+int dlb_ldb_port_owned_by_domain(struct dlb_hw *hw, u32 domain_id, u32 port_id)
+{
+	struct dlb_hw_domain *domain;
+	struct dlb_ldb_port *port;
+
+	domain = dlb_get_domain_from_id(hw, domain_id);
+
+	if (!domain || !domain->configured)
+		return -EINVAL;
+
+	port = dlb_get_domain_ldb_port(port_id, false, domain);
+
+	if (!port)
+		return -EINVAL;
+
+	return port->domain_id == domain->id;
+}
+
+/**
+ * dlb_dir_port_owned_by_domain() - query whether a port is owned by a domain
+ * @hw: dlb_hw handle for a particular device.
+ * @domain_id: domain ID.
+ * @port_id: port ID.
+ *
+ * This function returns whether a directed port is owned by a specified
+ * domain.
+ *
+ * Return:
+ * Returns 0 if false, 1 if true, <0 otherwise.
+ *
+ * EINVAL - Invalid domain or port ID, or the domain is not configured.
+ */
+int dlb_dir_port_owned_by_domain(struct dlb_hw *hw, u32 domain_id, u32 port_id)
+{
+	struct dlb_dir_pq_pair *port;
+	struct dlb_hw_domain *domain;
+
+	domain = dlb_get_domain_from_id(hw, domain_id);
+
+	if (!domain || !domain->configured)
+		return -EINVAL;
+
+	port = dlb_get_domain_dir_pq(port_id, false, domain);
+
+	if (!port)
+		return -EINVAL;
+
+	return port->domain_id == domain->id;
+}
+
 /**
  * dlb_clr_pmcsr_disable() - power on bulk of DLB 2.0 logic
  * @hw: dlb_hw handle for a particular device.
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [RFC PATCH v12 14/17] dlb: add start domain configfs attribute
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
                   ` (12 preceding siblings ...)
  2021-12-21  6:50 ` [RFC PATCH v12 13/17] dlb: add port mmap support Mike Ximing Chen
@ 2021-12-21  6:50 ` Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 15/17] dlb: add queue map, unmap, and pending unmap Mike Ximing Chen
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

Add configfs interface to start a domain. Once a scheduling domain and its
resources have been configured, this ioctl is called to allow the domain's
ports to begin enqueueing to the device. Once started, the domain's
resources cannot be configured again until after the domain is reset.

A write to "start" configfs file in a domain directory instructs the DLB
device to start load-balancing operations.

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
---
 drivers/misc/dlb/dlb_args.h     |  17 +++++
 drivers/misc/dlb/dlb_configfs.c |  42 +++++++++++++
 drivers/misc/dlb/dlb_configfs.h |   1 +
 drivers/misc/dlb/dlb_main.h     |   2 +
 drivers/misc/dlb/dlb_resource.c | 106 ++++++++++++++++++++++++++++++++
 5 files changed, 168 insertions(+)

diff --git a/drivers/misc/dlb/dlb_args.h b/drivers/misc/dlb/dlb_args.h
index b16670e62370..7c3e7794efee 100644
--- a/drivers/misc/dlb/dlb_args.h
+++ b/drivers/misc/dlb/dlb_args.h
@@ -248,6 +248,23 @@ struct dlb_get_port_fd_args {
 	__u32 port_id;
 };
 
+/*
+ * dlb_start_domain_args: Used to mark the end of the domain configuration. This
+ *	must be called before passing QEs into the device, and no configuration
+ *	via configfs can be done once the domain has started. Sending QEs into the
+ *	device before starting the domain will result in undefined behavior.
+ * Input parameters:
+ * - (None)
+ *
+ * Output parameters:
+ * @response.status: Detailed error code. In certain cases, such as if the
+ *	configfs request arg is invalid, the driver won't set status.
+ */
+struct dlb_start_domain_args {
+	/* Output parameters */
+	struct dlb_cmd_response response;
+};
+
 /*
  * Mapping sizes for memory mapping the consumer queue (CQ) memory space, and
  * producer port (PP) MMIO space.
diff --git a/drivers/misc/dlb/dlb_configfs.c b/drivers/misc/dlb/dlb_configfs.c
index 1401ad1a04de..1f7e8a293594 100644
--- a/drivers/misc/dlb/dlb_configfs.c
+++ b/drivers/misc/dlb/dlb_configfs.c
@@ -44,6 +44,7 @@ DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(create_ldb_queue)
 DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(create_dir_queue)
 DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(get_ldb_queue_depth)
 DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(get_dir_queue_depth)
+DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(start_domain)
 
 static int dlb_create_port_fd(struct dlb *dlb,
 			      const char *prefix,
@@ -814,6 +815,7 @@ DLB_CONFIGFS_DOMAIN_SHOW(num_hist_list_entries)
 DLB_CONFIGFS_DOMAIN_SHOW(num_ldb_credits)
 DLB_CONFIGFS_DOMAIN_SHOW(num_dir_credits)
 DLB_CONFIGFS_DOMAIN_SHOW(create)
+DLB_CONFIGFS_DOMAIN_SHOW(start)
 
 DLB_CONFIGFS_DOMAIN_STORE(num_ldb_queues)
 DLB_CONFIGFS_DOMAIN_STORE(num_ldb_ports)
@@ -882,6 +884,44 @@ static ssize_t dlb_cfs_domain_create_store(struct config_item *item,
 	return count;
 }
 
+static ssize_t dlb_cfs_domain_start_store(struct config_item *item,
+					  const char *page, size_t count)
+{
+	struct dlb_cfs_domain *dlb_cfs_domain = to_dlb_cfs_domain(item);
+	struct dlb_device_configfs *dlb_dev_configfs;
+	struct dlb_domain *dlb_domain;
+	struct dlb *dlb;
+	int ret;
+
+	dlb_dev_configfs = container_of(dlb_cfs_domain->dev_grp,
+					struct dlb_device_configfs,
+					dev_group);
+	dlb = dlb_dev_configfs->dlb;
+
+	ret = kstrtoint(page, 10, &dlb_cfs_domain->start);
+	if (ret)
+		return ret;
+
+	if (dlb_cfs_domain->start == 1) {
+		struct dlb_start_domain_args args;
+
+		memcpy(&args.response, &dlb_cfs_domain->status,
+		       sizeof(struct dlb_start_domain_args));
+
+		dlb_domain = dlb->sched_domains[dlb_cfs_domain->domain_id];
+		ret = dlb_domain_configfs_start_domain(dlb, dlb_domain, &args);
+
+		dlb_cfs_domain->status = args.response.status;
+
+		if (ret) {
+			dev_err(dlb->dev,
+				"start sched domain failed: ret=%d\n", ret);
+			return ret;
+		}
+	}
+	return count;
+}
+
 CONFIGFS_ATTR_RO(dlb_cfs_domain_, domain_fd);
 CONFIGFS_ATTR_RO(dlb_cfs_domain_, status);
 CONFIGFS_ATTR_RO(dlb_cfs_domain_, domain_id);
@@ -893,6 +933,7 @@ CONFIGFS_ATTR(dlb_cfs_domain_, num_hist_list_entries);
 CONFIGFS_ATTR(dlb_cfs_domain_, num_ldb_credits);
 CONFIGFS_ATTR(dlb_cfs_domain_, num_dir_credits);
 CONFIGFS_ATTR(dlb_cfs_domain_, create);
+CONFIGFS_ATTR(dlb_cfs_domain_, start);
 
 static struct configfs_attribute *dlb_cfs_domain_attrs[] = {
 	&dlb_cfs_domain_attr_domain_fd,
@@ -906,6 +947,7 @@ static struct configfs_attribute *dlb_cfs_domain_attrs[] = {
 	&dlb_cfs_domain_attr_num_ldb_credits,
 	&dlb_cfs_domain_attr_num_dir_credits,
 	&dlb_cfs_domain_attr_create,
+	&dlb_cfs_domain_attr_start,
 
 	NULL,
 };
diff --git a/drivers/misc/dlb/dlb_configfs.h b/drivers/misc/dlb/dlb_configfs.h
index 23874abfa42e..2503d0242399 100644
--- a/drivers/misc/dlb/dlb_configfs.h
+++ b/drivers/misc/dlb/dlb_configfs.h
@@ -28,6 +28,7 @@ struct dlb_cfs_domain {
 	unsigned int num_ldb_credits;
 	unsigned int num_dir_credits;
 	unsigned int create;
+	unsigned int start;
 
 };
 
diff --git a/drivers/misc/dlb/dlb_main.h b/drivers/misc/dlb/dlb_main.h
index b361cf55cd8a..bff006e2dc8d 100644
--- a/drivers/misc/dlb/dlb_main.h
+++ b/drivers/misc/dlb/dlb_main.h
@@ -614,6 +614,8 @@ int dlb_hw_create_ldb_port(struct dlb_hw *hw, u32 domain_id,
 			   struct dlb_create_ldb_port_args *args,
 			   uintptr_t cq_dma_base,
 			   struct dlb_cmd_response *resp);
+int dlb_hw_start_domain(struct dlb_hw *hw, u32 domain_id, void *unused,
+			struct dlb_cmd_response *resp);
 int dlb_reset_domain(struct dlb_hw *hw, u32 domain_id);
 int dlb_ldb_port_owned_by_domain(struct dlb_hw *hw, u32 domain_id, u32 port_id);
 int dlb_dir_port_owned_by_domain(struct dlb_hw *hw, u32 domain_id, u32 port_id);
diff --git a/drivers/misc/dlb/dlb_resource.c b/drivers/misc/dlb/dlb_resource.c
index b5d75cb9be7a..9e38fa850e5c 100644
--- a/drivers/misc/dlb/dlb_resource.c
+++ b/drivers/misc/dlb/dlb_resource.c
@@ -1086,6 +1086,34 @@ dlb_verify_create_dir_port_args(struct dlb_hw *hw, u32 domain_id,
 	return 0;
 }
 
+static int dlb_verify_start_domain_args(struct dlb_hw *hw, u32 domain_id,
+					struct dlb_cmd_response *resp,
+					struct dlb_hw_domain **out_domain)
+{
+	struct dlb_hw_domain *domain;
+
+	domain = dlb_get_domain_from_id(hw, domain_id);
+
+	if (!domain) {
+		resp->status = DLB_ST_INVALID_DOMAIN_ID;
+		return -EINVAL;
+	}
+
+	if (!domain->configured) {
+		resp->status = DLB_ST_DOMAIN_NOT_CONFIGURED;
+		return -EINVAL;
+	}
+
+	if (domain->started) {
+		resp->status = DLB_ST_DOMAIN_STARTED;
+		return -EINVAL;
+	}
+
+	*out_domain = domain;
+
+	return 0;
+}
+
 static void dlb_configure_domain_credits(struct dlb_hw *hw,
 					 struct dlb_hw_domain *domain)
 {
@@ -2470,6 +2498,84 @@ static void dlb_domain_reset_ldb_port_registers(struct dlb_hw *hw,
 	}
 }
 
+static void dlb_log_start_domain(struct dlb_hw *hw, u32 domain_id)
+{
+	dev_dbg(hw_to_dev(hw), "DLB start domain arguments:\n");
+	dev_dbg(hw_to_dev(hw), "\tDomain ID: %d\n", domain_id);
+}
+
+/**
+ * dlb_hw_start_domain() - start a scheduling domain
+ * @hw: dlb_hw handle for a particular device.
+ * @domain_id: domain ID.
+ * @unused: unused.
+ * @resp: response structure.
+ *
+ * This function starts a scheduling domain, which allows applications to send
+ * traffic through it. Once a domain is started, its resources can no longer be
+ * configured (besides QID remapping and port enable/disable).
+ *
+ * Return:
+ * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
+ * assigned a detailed error code from enum dlb_error.
+ *
+ * Errors:
+ * EINVAL - the domain is not configured, or the domain is already started.
+ */
+int
+dlb_hw_start_domain(struct dlb_hw *hw, u32 domain_id, void *unused,
+		    struct dlb_cmd_response *resp)
+{
+	struct dlb_dir_pq_pair *dir_queue;
+	struct dlb_ldb_queue *ldb_queue;
+	struct dlb_hw_domain *domain;
+	int ret;
+
+	dlb_log_start_domain(hw, domain_id);
+
+	ret = dlb_verify_start_domain_args(hw, domain_id, resp,
+					   &domain);
+	if (ret)
+		return ret;
+
+	/*
+	 * Enable load-balanced and directed queue write permissions for the
+	 * queues this domain owns. Without this, the DLB will drop all
+	 * incoming traffic to those queues.
+	 */
+	list_for_each_entry(ldb_queue, &domain->used_ldb_queues, domain_list) {
+		u32 vasqid_v = 0;
+		unsigned int offs;
+
+		vasqid_v |= SYS_LDB_VASQID_V_VASQID_V;
+
+		offs = domain->id * DLB_MAX_NUM_LDB_QUEUES +
+			ldb_queue->id;
+
+		DLB_CSR_WR(hw, SYS_LDB_VASQID_V(offs), vasqid_v);
+	}
+
+	list_for_each_entry(dir_queue, &domain->used_dir_pq_pairs, domain_list) {
+		u32 vasqid_v = 0;
+		unsigned int offs;
+
+		vasqid_v |= SYS_DIR_VASQID_V_VASQID_V;
+
+		offs = domain->id * DLB_MAX_NUM_DIR_PORTS +
+			dir_queue->id;
+
+		DLB_CSR_WR(hw, SYS_DIR_VASQID_V(offs), vasqid_v);
+	}
+
+	dlb_flush_csr(hw);
+
+	domain->started = true;
+
+	resp->status = 0;
+
+	return 0;
+}
+
 static void
 __dlb_domain_reset_dir_port_registers(struct dlb_hw *hw,
 				      struct dlb_dir_pq_pair *port)
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [RFC PATCH v12 15/17] dlb: add queue map, unmap, and pending unmap
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
                   ` (13 preceding siblings ...)
  2021-12-21  6:50 ` [RFC PATCH v12 14/17] dlb: add start domain configfs attribute Mike Ximing Chen
@ 2021-12-21  6:50 ` Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 16/17] dlb: add static queue map register operations Mike Ximing Chen
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

Add the high-level code for queue map, unmap, and pending unmap query
configfs interface and argument verification -- with stubs for the
low-level register accesses and the queue map/unmap state machine, to be
filled in a later commit.

The queue map/unmap in this commit refers to link/unlink between DLB's
load-balanced queues (internal) and consumer ports.See Documentation/
misc-devices/dlb.rst for details.

Load-balanced queues can be "mapped" to any number of load-balanced ports.
Once mapped, the port becomes a candidate to which the device can schedule
queue entries from the queue. If a port is unmapped from a queue, it is no
longer a candidate for scheduling from that queue.

The pending unmaps function queries how many unmap operations are
in-progress for a given port. These operations are asynchronous, so
multiple may be in-flight at any given time.

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
---
 drivers/misc/dlb/dlb_args.h     |  63 ++++++
 drivers/misc/dlb/dlb_configfs.c | 101 ++++++++++
 drivers/misc/dlb/dlb_configfs.h |   3 +
 drivers/misc/dlb/dlb_main.h     |   9 +
 drivers/misc/dlb/dlb_resource.c | 330 ++++++++++++++++++++++++++++++++
 include/uapi/linux/dlb.h        |   2 +
 6 files changed, 508 insertions(+)

diff --git a/drivers/misc/dlb/dlb_args.h b/drivers/misc/dlb/dlb_args.h
index 7c3e7794efee..eac8890c3a70 100644
--- a/drivers/misc/dlb/dlb_args.h
+++ b/drivers/misc/dlb/dlb_args.h
@@ -265,6 +265,69 @@ struct dlb_start_domain_args {
 	struct dlb_cmd_response response;
 };
 
+/*
+ * dlb_map_qid_args: Used to map a load-balanced queue to a load-balanced port.
+ *
+ * Output parameters:
+ * @response.status: Detailed error code. In certain cases, such as if the
+ *	request arg is invalid, the driver won't set status.
+ *
+ * Input parameters:
+ * @port_id: Load-balanced port ID.
+ * @qid: Load-balanced queue ID.
+ * @priority: Queue->port service priority.
+ */
+struct dlb_map_qid_args {
+	/* Output parameters */
+	struct dlb_cmd_response response;
+	/* Input parameters */
+	__u32 port_id;
+	__u32 qid;
+	__u32 priority;
+};
+
+/*
+ * dlb_unmap_qid_args: Used to nnmap a load-balanced queue to a load-balanced
+ *	port.
+ *
+ * Output parameters:
+ * @response.status: Detailed error code. In certain cases, such as if the
+ *	request arg is invalid, the driver won't set status.
+ *
+ * Input parameters:
+ * @port_id: Load-balanced port ID.
+ * @qid: Load-balanced queue ID.
+ */
+struct dlb_unmap_qid_args {
+	/* Output parameters */
+	struct dlb_cmd_response response;
+	/* Input parameters */
+	__u32 port_id;
+	__u32 qid;
+};
+
+/*
+ * dlb_pending_port_unmaps_args: Used to get number of queue unmap operations in
+ *	progress for a load-balanced port.
+ *
+ *	Note: This is a snapshot; the number of unmap operations in progress
+ *	is subject to change at any time.
+ *
+ * Output parameters:
+ * @response.status: Detailed error code. In certain cases, such as if the
+ *	request arg is invalid, the driver won't set status.
+ * @response.id: number of unmaps in progress.
+ *
+ * Input parameters:
+ * @port_id: Load-balanced port ID.
+ */
+struct dlb_pending_port_unmaps_args {
+	/* Output parameters */
+	struct dlb_cmd_response response;
+	/* Input parameters */
+	__u32 port_id;
+};
+
 /*
  * Mapping sizes for memory mapping the consumer queue (CQ) memory space, and
  * producer port (PP) MMIO space.
diff --git a/drivers/misc/dlb/dlb_configfs.c b/drivers/misc/dlb/dlb_configfs.c
index 1f7e8a293594..3f279c81fbbb 100644
--- a/drivers/misc/dlb/dlb_configfs.c
+++ b/drivers/misc/dlb/dlb_configfs.c
@@ -45,6 +45,8 @@ DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(create_dir_queue)
 DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(get_ldb_queue_depth)
 DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(get_dir_queue_depth)
 DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(start_domain)
+DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(map_qid)
+DLB_DOMAIN_CONFIGFS_CALLBACK_TEMPLATE(unmap_qid)
 
 static int dlb_create_port_fd(struct dlb *dlb,
 			      const char *prefix,
@@ -611,6 +613,15 @@ end:									\
 	return sprintf(page, "%u\n", to_dlb_cfs_port(item)->name);	\
 }									\
 
+#define DLB_CONFIGFS_PORT_LINK_SHOW(name, port)				\
+static ssize_t dlb_cfs_port_##name##_##port##_show(			\
+	struct config_item *item,					\
+	char *page)							\
+{									\
+	return sprintf(page, "Ox%08x\n",				\
+	       to_dlb_cfs_port(item)->name[port]);			\
+}
+
 #define DLB_CONFIGFS_PORT_STORE(name)					\
 static ssize_t dlb_cfs_port_##name##_store(				\
 	struct config_item *item,					\
@@ -643,6 +654,55 @@ static ssize_t dlb_cfs_port_##name##_store(				\
 	return count;							\
 }									\
 
+#define DLB_CONFIGFS_PORT_LINK_STORE(name, port)			\
+static ssize_t dlb_cfs_port_##name##_##port##_store(			\
+	struct config_item *item,					\
+	const char *page,						\
+	size_t count)							\
+{									\
+	struct dlb_cfs_port *dlb_cfs_port = to_dlb_cfs_port(item);	\
+	struct dlb_domain *dlb_domain;					\
+	struct dlb *dlb = NULL;						\
+	int ret;							\
+									\
+	ret = dlb_configfs_get_dlb_domain(dlb_cfs_port->domain_grp,	\
+					  &dlb, &dlb_domain);		\
+	if (ret)							\
+		return ret;						\
+									\
+	ret = kstrtoint(page, 16, &dlb_cfs_port->name[port]);		\
+	if (ret)							\
+		return ret;						\
+									\
+	if (dlb_cfs_port->name[port] & 0x10000) {			\
+		struct dlb_map_qid_args args;				\
+									\
+		args.port_id = dlb_cfs_port->port_id;			\
+		args.qid = dlb_cfs_port->name[port] & 0xff;		\
+		args.priority = (dlb_cfs_port->name[port] >> 8) & 0xff;	\
+									\
+		ret = dlb_domain_configfs_map_qid(dlb, dlb_domain,	\
+						  &args);		\
+									\
+		dlb_cfs_port->status = args.response.status;		\
+	} else {							\
+		struct dlb_unmap_qid_args args;				\
+									\
+		args.port_id = dlb_cfs_port->port_id;			\
+		args.qid = dlb_cfs_port->name[port] & 0xff;		\
+									\
+		ret = dlb_domain_configfs_unmap_qid(dlb, dlb_domain,	\
+						    &args);		\
+									\
+		dlb_cfs_port->status = args.response.status;		\
+	}								\
+									\
+	if (ret)							\
+		return ret;						\
+									\
+	return count;							\
+}
+
 DLB_CONFIGFS_PORT_SHOW_FD(pp_fd)
 DLB_CONFIGFS_PORT_SHOW_FD(cq_fd)
 DLB_CONFIGFS_PORT_SHOW(status)
@@ -652,12 +712,28 @@ DLB_CONFIGFS_PORT_SHOW(cq_depth)
 DLB_CONFIGFS_PORT_SHOW(cq_depth_threshold)
 DLB_CONFIGFS_PORT_SHOW(cq_history_list_size)
 DLB_CONFIGFS_PORT_SHOW(create)
+DLB_CONFIGFS_PORT_LINK_SHOW(queue_link, 0)
+DLB_CONFIGFS_PORT_LINK_SHOW(queue_link, 1)
+DLB_CONFIGFS_PORT_LINK_SHOW(queue_link, 2)
+DLB_CONFIGFS_PORT_LINK_SHOW(queue_link, 3)
+DLB_CONFIGFS_PORT_LINK_SHOW(queue_link, 4)
+DLB_CONFIGFS_PORT_LINK_SHOW(queue_link, 5)
+DLB_CONFIGFS_PORT_LINK_SHOW(queue_link, 6)
+DLB_CONFIGFS_PORT_LINK_SHOW(queue_link, 7)
 DLB_CONFIGFS_PORT_SHOW(queue_id)
 
 DLB_CONFIGFS_PORT_STORE(is_ldb)
 DLB_CONFIGFS_PORT_STORE(cq_depth)
 DLB_CONFIGFS_PORT_STORE(cq_depth_threshold)
 DLB_CONFIGFS_PORT_STORE(cq_history_list_size)
+DLB_CONFIGFS_PORT_LINK_STORE(queue_link, 0)
+DLB_CONFIGFS_PORT_LINK_STORE(queue_link, 1)
+DLB_CONFIGFS_PORT_LINK_STORE(queue_link, 2)
+DLB_CONFIGFS_PORT_LINK_STORE(queue_link, 3)
+DLB_CONFIGFS_PORT_LINK_STORE(queue_link, 4)
+DLB_CONFIGFS_PORT_LINK_STORE(queue_link, 5)
+DLB_CONFIGFS_PORT_LINK_STORE(queue_link, 6)
+DLB_CONFIGFS_PORT_LINK_STORE(queue_link, 7)
 DLB_CONFIGFS_PORT_STORE(queue_id)
 
 static ssize_t dlb_cfs_port_create_store(struct config_item *item,
@@ -682,6 +758,7 @@ static ssize_t dlb_cfs_port_create_store(struct config_item *item,
 
 	if (dlb_cfs_port->is_ldb) {
 		struct dlb_create_ldb_port_args args = {0};
+		int i;
 
 		args.cq_depth = dlb_cfs_port->cq_depth;
 		args.cq_depth_threshold = dlb_cfs_port->cq_depth_threshold;
@@ -695,6 +772,10 @@ static ssize_t dlb_cfs_port_create_store(struct config_item *item,
 
 		dlb_cfs_port->status = args.response.status;
 		dlb_cfs_port->port_id = args.response.id;
+
+		/* reset the links */
+		for (i = 0; i < DLB_MAX_NUM_QIDS_PER_LDB_CQ; i++)
+			dlb_cfs_port->queue_link[i] = 0x1ffff;
 	} else {
 		struct dlb_create_dir_port_args args = {0};
 
@@ -734,6 +815,14 @@ CONFIGFS_ATTR(dlb_cfs_port_, cq_depth);
 CONFIGFS_ATTR(dlb_cfs_port_, cq_depth_threshold);
 CONFIGFS_ATTR(dlb_cfs_port_, cq_history_list_size);
 CONFIGFS_ATTR(dlb_cfs_port_, create);
+CONFIGFS_ATTR(dlb_cfs_port_, queue_link_0);
+CONFIGFS_ATTR(dlb_cfs_port_, queue_link_1);
+CONFIGFS_ATTR(dlb_cfs_port_, queue_link_2);
+CONFIGFS_ATTR(dlb_cfs_port_, queue_link_3);
+CONFIGFS_ATTR(dlb_cfs_port_, queue_link_4);
+CONFIGFS_ATTR(dlb_cfs_port_, queue_link_5);
+CONFIGFS_ATTR(dlb_cfs_port_, queue_link_6);
+CONFIGFS_ATTR(dlb_cfs_port_, queue_link_7);
 CONFIGFS_ATTR(dlb_cfs_port_, queue_id);
 
 static struct configfs_attribute *dlb_cfs_port_attrs[] = {
@@ -746,6 +835,14 @@ static struct configfs_attribute *dlb_cfs_port_attrs[] = {
 	&dlb_cfs_port_attr_cq_depth_threshold,
 	&dlb_cfs_port_attr_cq_history_list_size,
 	&dlb_cfs_port_attr_create,
+	&dlb_cfs_port_attr_queue_link_0,
+	&dlb_cfs_port_attr_queue_link_1,
+	&dlb_cfs_port_attr_queue_link_2,
+	&dlb_cfs_port_attr_queue_link_3,
+	&dlb_cfs_port_attr_queue_link_4,
+	&dlb_cfs_port_attr_queue_link_5,
+	&dlb_cfs_port_attr_queue_link_6,
+	&dlb_cfs_port_attr_queue_link_7,
 	&dlb_cfs_port_attr_queue_id,
 
 	NULL,
@@ -957,6 +1054,7 @@ static struct config_group *dlb_cfs_domain_make_queue_port(struct config_group *
 {
 	if (strstr(name, "port")) {
 		struct dlb_cfs_port *dlb_cfs_port;
+		int i;
 
 		dlb_cfs_port = kzalloc(sizeof(*dlb_cfs_port), GFP_KERNEL);
 		if (!dlb_cfs_port)
@@ -967,6 +1065,9 @@ static struct config_group *dlb_cfs_domain_make_queue_port(struct config_group *
 		config_group_init_type_name(&dlb_cfs_port->group, name,
 					    &dlb_cfs_port_type);
 
+		for (i = 0; i < 8; i++)
+			dlb_cfs_port->queue_link[i] = 0xffffffff;
+
 		dlb_cfs_port->queue_id = 0xffffffff;
 		dlb_cfs_port->port_id = 0xffffffff;
 
diff --git a/drivers/misc/dlb/dlb_configfs.h b/drivers/misc/dlb/dlb_configfs.h
index 2503d0242399..91cc7d829f9a 100644
--- a/drivers/misc/dlb/dlb_configfs.h
+++ b/drivers/misc/dlb/dlb_configfs.h
@@ -68,6 +68,9 @@ struct dlb_cfs_port {
 	unsigned int cq_history_list_size;
 	unsigned int create;
 
+	/* For LDB port only */
+	unsigned int queue_link[DLB_MAX_NUM_QIDS_PER_LDB_CQ];
+
 	/* For DIR port only, default = 0xffffffff */
 	unsigned int queue_id;
 
diff --git a/drivers/misc/dlb/dlb_main.h b/drivers/misc/dlb/dlb_main.h
index bff006e2dc8d..f410e7307c12 100644
--- a/drivers/misc/dlb/dlb_main.h
+++ b/drivers/misc/dlb/dlb_main.h
@@ -616,6 +616,12 @@ int dlb_hw_create_ldb_port(struct dlb_hw *hw, u32 domain_id,
 			   struct dlb_cmd_response *resp);
 int dlb_hw_start_domain(struct dlb_hw *hw, u32 domain_id, void *unused,
 			struct dlb_cmd_response *resp);
+int dlb_hw_map_qid(struct dlb_hw *hw, u32 domain_id,
+		   struct dlb_map_qid_args *args,
+		   struct dlb_cmd_response *resp);
+int dlb_hw_unmap_qid(struct dlb_hw *hw, u32 domain_id,
+		     struct dlb_unmap_qid_args *args,
+		     struct dlb_cmd_response *resp);
 int dlb_reset_domain(struct dlb_hw *hw, u32 domain_id);
 int dlb_ldb_port_owned_by_domain(struct dlb_hw *hw, u32 domain_id, u32 port_id);
 int dlb_dir_port_owned_by_domain(struct dlb_hw *hw, u32 domain_id, u32 port_id);
@@ -626,6 +632,9 @@ int dlb_hw_get_ldb_queue_depth(struct dlb_hw *hw, u32 domain_id,
 int dlb_hw_get_dir_queue_depth(struct dlb_hw *hw, u32 domain_id,
 			       struct dlb_get_dir_queue_depth_args *args,
 			       struct dlb_cmd_response *resp);
+int dlb_hw_pending_port_unmaps(struct dlb_hw *hw, u32 domain_id,
+			       struct dlb_pending_port_unmaps_args *args,
+			       struct dlb_cmd_response *resp);
 void dlb_hw_enable_sparse_ldb_cq_mode(struct dlb_hw *hw);
 void dlb_hw_enable_sparse_dir_cq_mode(struct dlb_hw *hw);
 
diff --git a/drivers/misc/dlb/dlb_resource.c b/drivers/misc/dlb/dlb_resource.c
index 9e38fa850e5c..5d4ffdab69b5 100644
--- a/drivers/misc/dlb/dlb_resource.c
+++ b/drivers/misc/dlb/dlb_resource.c
@@ -210,6 +210,30 @@ static struct dlb_hw_domain *dlb_get_domain_from_id(struct dlb_hw *hw, u32 id)
 	return &hw->domains[id];
 }
 
+static struct dlb_ldb_port *
+dlb_get_domain_used_ldb_port(u32 id, bool vdev_req, struct dlb_hw_domain *domain)
+{
+	struct dlb_ldb_port *port;
+	int i;
+
+	if (id >= DLB_MAX_NUM_LDB_PORTS)
+		return NULL;
+
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++) {
+		list_for_each_entry(port, &domain->used_ldb_ports[i], domain_list) {
+			if (!vdev_req && port->id == id)
+				return port;
+		}
+
+		list_for_each_entry(port, &domain->avail_ldb_ports[i], domain_list) {
+			if (!vdev_req && port->id == id)
+				return port;
+		}
+	}
+
+	return NULL;
+}
+
 static struct dlb_ldb_port *
 dlb_get_domain_ldb_port(u32 id, bool vdev_req, struct dlb_hw_domain *domain)
 {
@@ -1114,6 +1138,122 @@ static int dlb_verify_start_domain_args(struct dlb_hw *hw, u32 domain_id,
 	return 0;
 }
 
+static int dlb_verify_map_qid_args(struct dlb_hw *hw, u32 domain_id,
+				   struct dlb_map_qid_args *args,
+				   struct dlb_cmd_response *resp,
+				   struct dlb_hw_domain **out_domain,
+				   struct dlb_ldb_port **out_port,
+				   struct dlb_ldb_queue **out_queue)
+{
+	struct dlb_hw_domain *domain;
+	struct dlb_ldb_queue *queue;
+	struct dlb_ldb_port *port;
+	int id;
+
+	domain = dlb_get_domain_from_id(hw, domain_id);
+
+	if (!domain) {
+		resp->status = DLB_ST_INVALID_DOMAIN_ID;
+		return -EINVAL;
+	}
+
+	if (!domain->configured) {
+		resp->status = DLB_ST_DOMAIN_NOT_CONFIGURED;
+		return -EINVAL;
+	}
+
+	id = args->port_id;
+
+	port = dlb_get_domain_used_ldb_port(id, false, domain);
+
+	if (!port || !port->configured) {
+		resp->status = DLB_ST_INVALID_PORT_ID;
+		return -EINVAL;
+	}
+
+	if (args->priority >= DLB_QID_PRIORITIES) {
+		resp->status = DLB_ST_INVALID_PRIORITY;
+		return -EINVAL;
+	}
+
+	queue = dlb_get_domain_ldb_queue(args->qid, false, domain);
+
+	if (!queue || !queue->configured) {
+		resp->status = DLB_ST_INVALID_QID;
+		return -EINVAL;
+	}
+
+	if (queue->domain_id != domain->id) {
+		resp->status = DLB_ST_INVALID_QID;
+		return -EINVAL;
+	}
+
+	if (port->domain_id != domain->id) {
+		resp->status = DLB_ST_INVALID_PORT_ID;
+		return -EINVAL;
+	}
+
+	*out_domain = domain;
+	*out_queue = queue;
+	*out_port = port;
+
+	return 0;
+}
+
+static int dlb_verify_unmap_qid_args(struct dlb_hw *hw, u32 domain_id,
+				     struct dlb_unmap_qid_args *args,
+				     struct dlb_cmd_response *resp,
+				     struct dlb_hw_domain **out_domain,
+				     struct dlb_ldb_port **out_port,
+				     struct dlb_ldb_queue **out_queue)
+{
+	struct dlb_hw_domain *domain;
+	struct dlb_ldb_queue *queue;
+	struct dlb_ldb_port *port;
+	int id;
+
+	domain = dlb_get_domain_from_id(hw, domain_id);
+
+	if (!domain) {
+		resp->status = DLB_ST_INVALID_DOMAIN_ID;
+		return -EINVAL;
+	}
+
+	if (!domain->configured) {
+		resp->status = DLB_ST_DOMAIN_NOT_CONFIGURED;
+		return -EINVAL;
+	}
+
+	id = args->port_id;
+
+	port = dlb_get_domain_used_ldb_port(id, false, domain);
+
+	if (!port || !port->configured) {
+		resp->status = DLB_ST_INVALID_PORT_ID;
+		return -EINVAL;
+	}
+
+	if (port->domain_id != domain->id) {
+		resp->status = DLB_ST_INVALID_PORT_ID;
+		return -EINVAL;
+	}
+
+	queue = dlb_get_domain_ldb_queue(args->qid, false, domain);
+
+	if (!queue || !queue->configured) {
+		dev_err(hw_to_dev(hw), "[%s()] Can't unmap unconfigured queue %d\n",
+			__func__, args->qid);
+		resp->status = DLB_ST_INVALID_QID;
+		return -EINVAL;
+	}
+
+	*out_domain = domain;
+	*out_port = port;
+	*out_queue = queue;
+
+	return 0;
+}
+
 static void dlb_configure_domain_credits(struct dlb_hw *hw,
 					 struct dlb_hw_domain *domain)
 {
@@ -1957,6 +2097,145 @@ int dlb_hw_create_dir_port(struct dlb_hw *hw, u32 domain_id,
 	return 0;
 }
 
+static void dlb_log_map_qid(struct dlb_hw *hw, u32 domain_id,
+			    struct dlb_map_qid_args *args)
+{
+	dev_dbg(hw_to_dev(hw), "DLB map QID arguments:\n");
+	dev_dbg(hw_to_dev(hw), "\tDomain ID: %d\n",
+		domain_id);
+	dev_dbg(hw_to_dev(hw), "\tPort ID:   %d\n",
+		args->port_id);
+	dev_dbg(hw_to_dev(hw), "\tQueue ID:  %d\n",
+		args->qid);
+	dev_dbg(hw_to_dev(hw), "\tPriority:  %d\n",
+		args->priority);
+}
+
+/**
+ * dlb_hw_map_qid() - map a load-balanced queue to a load-balanced port
+ * @hw: dlb_hw handle for a particular device.
+ * @domain_id: domain ID.
+ * @args: map QID arguments.
+ * @resp: response structure.
+ *
+ * This function configures the DLB to schedule QEs from the specified queue
+ * to the specified port. Each load-balanced port can be mapped to up to 8
+ * queues; each load-balanced queue can potentially map to all the
+ * load-balanced ports.
+ *
+ * A successful return does not necessarily mean the mapping was configured. If
+ * this function is unable to immediately map the queue to the port, it will
+ * add the requested operation to a per-port list of pending map/unmap
+ * operations, and (if it's not already running) launch a kernel thread that
+ * periodically attempts to process all pending operations. In a sense, this is
+ * an asynchronous function.
+ *
+ * This asynchronicity creates two views of the state of hardware: the actual
+ * hardware state and the requested state (as if every request completed
+ * immediately). If there are any pending map/unmap operations, the requested
+ * state will differ from the actual state. All validation is performed with
+ * respect to the pending state; for instance, if there are 8 pending map
+ * operations for port X, a request for a 9th will fail because a load-balanced
+ * port can only map up to 8 queues.
+ *
+ * Return:
+ * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
+ * assigned a detailed error code from enum dlb_error.
+ *
+ * Errors:
+ * EINVAL - A requested resource is unavailable, invalid port or queue ID, or
+ *	    the domain is not configured.
+ * EFAULT - Internal error (resp->status not set).
+ */
+int dlb_hw_map_qid(struct dlb_hw *hw, u32 domain_id,
+		   struct dlb_map_qid_args *args,
+		   struct dlb_cmd_response *resp)
+{
+	struct dlb_hw_domain *domain;
+	struct dlb_ldb_queue *queue;
+	struct dlb_ldb_port *port;
+	int ret;
+
+	dlb_log_map_qid(hw, domain_id, args);
+
+	/*
+	 * Verify that hardware resources are available before attempting to
+	 * satisfy the request. This simplifies the error unwinding code.
+	 */
+	ret = dlb_verify_map_qid_args(hw, domain_id, args, resp,
+				      &domain, &port, &queue);
+	if (ret)
+		return ret;
+
+	resp->status = 0;
+
+	return 0;
+}
+
+static void dlb_log_unmap_qid(struct dlb_hw *hw, u32 domain_id,
+			      struct dlb_unmap_qid_args *args)
+{
+	dev_dbg(hw_to_dev(hw), "DLB unmap QID arguments:\n");
+	dev_dbg(hw_to_dev(hw), "\tDomain ID: %d\n",
+		domain_id);
+	dev_dbg(hw_to_dev(hw), "\tPort ID:   %d\n",
+		args->port_id);
+	dev_dbg(hw_to_dev(hw), "\tQueue ID:  %d\n",
+		args->qid);
+	if (args->qid < DLB_MAX_NUM_LDB_QUEUES)
+		dev_dbg(hw_to_dev(hw), "\tQueue's num mappings:  %d\n",
+			hw->rsrcs.ldb_queues[args->qid].num_mappings);
+}
+
+/**
+ * dlb_hw_unmap_qid() - Unmap a load-balanced queue from a load-balanced port
+ * @hw: dlb_hw handle for a particular device.
+ * @domain_id: domain ID.
+ * @args: unmap QID arguments.
+ * @resp: response structure.
+ *
+ * This function configures the DLB to stop scheduling QEs from the specified
+ * queue to the specified port.
+ *
+ * A successful return does not necessarily mean the mapping was removed. If
+ * this function is unable to immediately unmap the queue from the port, it
+ * will add the requested operation to a per-port list of pending map/unmap
+ * operations, and (if it's not already running) launch a kernel thread that
+ * periodically attempts to process all pending operations. See
+ * dlb_hw_map_qid() for more details.
+ *
+ * Return:
+ * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
+ * assigned a detailed error code from enum dlb_error.
+ *
+ * Errors:
+ * EINVAL - A requested resource is unavailable, invalid port or queue ID, or
+ *	    the domain is not configured.
+ * EFAULT - Internal error (resp->status not set).
+ */
+int dlb_hw_unmap_qid(struct dlb_hw *hw, u32 domain_id,
+		     struct dlb_unmap_qid_args *args,
+		     struct dlb_cmd_response *resp)
+{
+	struct dlb_hw_domain *domain;
+	struct dlb_ldb_queue *queue;
+	struct dlb_ldb_port *port;
+	int ret;
+
+	dlb_log_unmap_qid(hw, domain_id, args);
+
+	/*
+	 * Verify that hardware resources are available before attempting to
+	 * satisfy the request. This simplifies the error unwinding code.
+	 */
+	ret = dlb_verify_unmap_qid_args(hw, domain_id, args, resp,
+					&domain, &port, &queue);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 static u32 dlb_ldb_cq_inflight_count(struct dlb_hw *hw,
 				     struct dlb_ldb_port *port)
 {
@@ -2297,6 +2576,57 @@ int dlb_hw_get_dir_queue_depth(struct dlb_hw *hw, u32 domain_id,
 	return 0;
 }
 
+static void
+dlb_log_pending_port_unmaps_args(struct dlb_hw *hw,
+				 struct dlb_pending_port_unmaps_args *args)
+{
+	dev_dbg(hw_to_dev(hw), "DLB unmaps in progress arguments:\n");
+	dev_dbg(hw_to_dev(hw), "\tPort ID: %d\n", args->port_id);
+}
+
+/**
+ * dlb_hw_pending_port_unmaps() - returns the number of unmap operations in
+ *	progress.
+ * @hw: dlb_hw handle for a particular device.
+ * @domain_id: domain ID.
+ * @args: number of unmaps in progress args
+ * @resp: response structure.
+ *
+ * Return:
+ * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
+ * assigned a detailed error code from enum dlb_error. If successful, resp->id
+ * contains the number of unmaps in progress.
+ *
+ * Errors:
+ * EINVAL - Invalid port ID.
+ */
+int dlb_hw_pending_port_unmaps(struct dlb_hw *hw, u32 domain_id,
+			       struct dlb_pending_port_unmaps_args *args,
+			       struct dlb_cmd_response *resp)
+{
+	struct dlb_hw_domain *domain;
+	struct dlb_ldb_port *port;
+
+	dlb_log_pending_port_unmaps_args(hw, args);
+
+	domain = dlb_get_domain_from_id(hw, domain_id);
+
+	if (!domain) {
+		resp->status = DLB_ST_INVALID_DOMAIN_ID;
+		return -EINVAL;
+	}
+
+	port = dlb_get_domain_used_ldb_port(args->port_id, false, domain);
+	if (!port || !port->configured) {
+		resp->status = DLB_ST_INVALID_PORT_ID;
+		return -EINVAL;
+	}
+
+	resp->id = port->num_pending_removals;
+
+	return 0;
+}
+
 static u32 dlb_ldb_queue_depth(struct dlb_hw *hw, struct dlb_ldb_queue *queue)
 {
 	u32 aqed, ldb, atm;
diff --git a/include/uapi/linux/dlb.h b/include/uapi/linux/dlb.h
index e8a629f2d10b..a946f9c5e387 100644
--- a/include/uapi/linux/dlb.h
+++ b/include/uapi/linux/dlb.h
@@ -34,5 +34,7 @@ enum dlb_error {
 	DLB_ST_INVALID_CQ_DEPTH,
 	DLB_ST_INVALID_HIST_LIST_DEPTH,
 	DLB_ST_INVALID_DIR_QUEUE_ID,
+	DLB_ST_INVALID_PRIORITY,
+	DLB_ST_NO_QID_SLOTS_AVAILABLE,
 };
 #endif /* __DLB_H */
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [RFC PATCH v12 16/17] dlb: add static queue map register operations
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
                   ` (14 preceding siblings ...)
  2021-12-21  6:50 ` [RFC PATCH v12 15/17] dlb: add queue map, unmap, and pending unmap Mike Ximing Chen
@ 2021-12-21  6:50 ` Mike Ximing Chen
  2021-12-21  6:50 ` [RFC PATCH v12 17/17] dlb: add basic sysfs interfaces Mike Ximing Chen
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

Add the register accesses that implement the static queue map operation and
handle an unmap request when a queue map operation is in progress.

If a queue map operation is requested before the domain is started, it is a
synchronous procedure on "static"/unchanging hardware. (The "dynamic"
operation, when traffic is flowing in the device, will be added in a later
commit.)

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
---
 drivers/misc/dlb/dlb_resource.c | 163 ++++++++++++++++++++++++++++++++
 1 file changed, 163 insertions(+)

diff --git a/drivers/misc/dlb/dlb_resource.c b/drivers/misc/dlb/dlb_resource.c
index 5d4ffdab69b5..e19c0f6cc321 100644
--- a/drivers/misc/dlb/dlb_resource.c
+++ b/drivers/misc/dlb/dlb_resource.c
@@ -1200,6 +1200,38 @@ static int dlb_verify_map_qid_args(struct dlb_hw *hw, u32 domain_id,
 	return 0;
 }
 
+static bool dlb_port_find_slot(struct dlb_ldb_port *port,
+			       enum dlb_qid_map_state state, int *slot)
+{
+	int i;
+
+	for (i = 0; i < DLB_MAX_NUM_QIDS_PER_LDB_CQ; i++) {
+		if (port->qid_map[i].state == state)
+			break;
+	}
+
+	*slot = i;
+
+	return (i < DLB_MAX_NUM_QIDS_PER_LDB_CQ);
+}
+
+static bool dlb_port_find_slot_queue(struct dlb_ldb_port *port,
+				     enum dlb_qid_map_state state,
+				     struct dlb_ldb_queue *queue, int *slot)
+{
+	int i;
+
+	for (i = 0; i < DLB_MAX_NUM_QIDS_PER_LDB_CQ; i++) {
+		if (port->qid_map[i].state == state &&
+		    port->qid_map[i].qid == queue->id)
+			break;
+	}
+
+	*slot = i;
+
+	return (i < DLB_MAX_NUM_QIDS_PER_LDB_CQ);
+}
+
 static int dlb_verify_unmap_qid_args(struct dlb_hw *hw, u32 domain_id,
 				     struct dlb_unmap_qid_args *args,
 				     struct dlb_cmd_response *resp,
@@ -1720,6 +1752,125 @@ static int dlb_configure_dir_port(struct dlb_hw *hw, struct dlb_hw_domain *domai
 	return 0;
 }
 
+static int dlb_ldb_port_map_qid_static(struct dlb_hw *hw, struct dlb_ldb_port *p,
+				       struct dlb_ldb_queue *q, u8 priority)
+{
+	u32 lsp_qid2cq2;
+	u32 lsp_qid2cq;
+	u32 atm_qid2cq;
+	u32 cq2priov;
+	u32 cq2qid;
+	int i;
+
+	/* Look for a pending or already mapped slot, else an unused slot */
+	if (!dlb_port_find_slot_queue(p, DLB_QUEUE_MAP_IN_PROG, q, &i) &&
+	    !dlb_port_find_slot_queue(p, DLB_QUEUE_MAPPED, q, &i) &&
+	    !dlb_port_find_slot(p, DLB_QUEUE_UNMAPPED, &i)) {
+		dev_err(hw_to_dev(hw),
+			"[%s():%d] Internal error: CQ has no available QID mapping slots\n",
+			__func__, __LINE__);
+		return -EFAULT;
+	}
+
+	/* Read-modify-write the priority and valid bit register */
+	cq2priov = DLB_CSR_RD(hw, LSP_CQ2PRIOV(p->id));
+
+	cq2priov |= (1U << (i + LSP_CQ2PRIOV_V_LOC)) & LSP_CQ2PRIOV_V;
+	cq2priov |= ((priority & 0x7) << (i + LSP_CQ2PRIOV_PRIO_LOC) * 3)
+		    & LSP_CQ2PRIOV_PRIO;
+
+	DLB_CSR_WR(hw, LSP_CQ2PRIOV(p->id), cq2priov);
+
+	/* Read-modify-write the QID map register */
+	if (i < 4)
+		cq2qid = DLB_CSR_RD(hw, LSP_CQ2QID0(p->id));
+	else
+		cq2qid = DLB_CSR_RD(hw, LSP_CQ2QID1(p->id));
+
+	if (i == 0 || i == 4) {
+		cq2qid &= ~LSP_CQ2QID0_QID_P0;
+		cq2qid |= FIELD_PREP(LSP_CQ2QID0_QID_P0, q->id);
+	} else if (i == 1 || i == 5) {
+		cq2qid &= ~LSP_CQ2QID0_QID_P1;
+		cq2qid |= FIELD_PREP(LSP_CQ2QID0_QID_P1, q->id);
+	} else if (i == 2 || i == 6) {
+		cq2qid &= ~LSP_CQ2QID0_QID_P2;
+		cq2qid |= FIELD_PREP(LSP_CQ2QID0_QID_P2, q->id);
+	} else if (i == 3 || i == 7) {
+		cq2qid &= ~LSP_CQ2QID0_QID_P3;
+		cq2qid |= FIELD_PREP(LSP_CQ2QID0_QID_P3, q->id);
+	}
+
+	if (i < 4)
+		DLB_CSR_WR(hw, LSP_CQ2QID0(p->id), cq2qid);
+	else
+		DLB_CSR_WR(hw, LSP_CQ2QID1(p->id), cq2qid);
+
+	atm_qid2cq = DLB_CSR_RD(hw,
+				ATM_QID2CQIDIX(q->id,
+					       p->id / 4));
+
+	lsp_qid2cq = DLB_CSR_RD(hw,
+				LSP_QID2CQIDIX(q->id,
+					       p->id / 4));
+
+	lsp_qid2cq2 = DLB_CSR_RD(hw,
+				 LSP_QID2CQIDIX2(q->id,
+						 p->id / 4));
+
+	switch (p->id % 4) {
+	case 0:
+		atm_qid2cq |= (1 << (i + ATM_QID2CQIDIX_00_CQ_P0_LOC));
+		lsp_qid2cq |= (1 << (i + LSP_QID2CQIDIX_00_CQ_P0_LOC));
+		lsp_qid2cq2 |= (1 << (i + LSP_QID2CQIDIX2_00_CQ_P0_LOC));
+		break;
+
+	case 1:
+		atm_qid2cq |= (1 << (i + ATM_QID2CQIDIX_00_CQ_P1_LOC));
+		lsp_qid2cq |= (1 << (i + LSP_QID2CQIDIX_00_CQ_P1_LOC));
+		lsp_qid2cq2 |= (1 << (i + LSP_QID2CQIDIX2_00_CQ_P1_LOC));
+		break;
+
+	case 2:
+		atm_qid2cq |= (1 << (i + ATM_QID2CQIDIX_00_CQ_P2_LOC));
+		lsp_qid2cq |= (1 << (i + LSP_QID2CQIDIX_00_CQ_P2_LOC));
+		lsp_qid2cq2 |= (1 << (i + LSP_QID2CQIDIX2_00_CQ_P2_LOC));
+		break;
+
+	case 3:
+		atm_qid2cq |= (1 << (i + ATM_QID2CQIDIX_00_CQ_P3_LOC));
+		lsp_qid2cq |= (1 << (i + LSP_QID2CQIDIX_00_CQ_P3_LOC));
+		lsp_qid2cq2 |= (1 << (i + LSP_QID2CQIDIX2_00_CQ_P3_LOC));
+		break;
+	}
+
+	DLB_CSR_WR(hw,
+		   ATM_QID2CQIDIX(q->id, p->id / 4),
+		   atm_qid2cq);
+
+	DLB_CSR_WR(hw,
+		   LSP_QID2CQIDIX(q->id, p->id / 4),
+		   lsp_qid2cq);
+
+	DLB_CSR_WR(hw,
+		   LSP_QID2CQIDIX2(q->id, p->id / 4),
+		   lsp_qid2cq2);
+
+	dlb_flush_csr(hw);
+
+	p->qid_map[i].qid = q->id;
+	p->qid_map[i].priority = priority;
+
+	return 0;
+}
+
+static int dlb_ldb_port_map_qid(struct dlb_hw *hw, struct dlb_hw_domain *domain,
+				struct dlb_ldb_port *port,
+				struct dlb_ldb_queue *queue, u8 prio)
+{
+	return dlb_ldb_port_map_qid_static(hw, port, queue, prio);
+}
+
 static void
 dlb_log_create_sched_domain_args(struct dlb_hw *hw,
 				 struct dlb_create_sched_domain_args *args)
@@ -2155,6 +2306,7 @@ int dlb_hw_map_qid(struct dlb_hw *hw, u32 domain_id,
 	struct dlb_ldb_queue *queue;
 	struct dlb_ldb_port *port;
 	int ret;
+	u8 prio;
 
 	dlb_log_map_qid(hw, domain_id, args);
 
@@ -2167,6 +2319,17 @@ int dlb_hw_map_qid(struct dlb_hw *hw, u32 domain_id,
 	if (ret)
 		return ret;
 
+	prio = args->priority;
+
+	ret = dlb_ldb_port_map_qid(hw, domain, port, queue, prio);
+
+	/* If ret is less than zero, it's due to an internal error */
+	if (ret < 0)
+		return ret;
+
+	if (port->enabled)
+		dlb_ldb_port_cq_enable(hw, port);
+
 	resp->status = 0;
 
 	return 0;
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [RFC PATCH v12 17/17] dlb: add basic sysfs interfaces
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
                   ` (15 preceding siblings ...)
  2021-12-21  6:50 ` [RFC PATCH v12 16/17] dlb: add static queue map register operations Mike Ximing Chen
@ 2021-12-21  6:50 ` Mike Ximing Chen
  2021-12-21  7:20   ` Joe Perches
                     ` (2 more replies)
  2021-12-21  7:09 ` [RFC PATCH v12 00/17] dlb: introduce DLB device driver Greg KH
  2021-12-21  9:40 ` Andrew Lunn
  18 siblings, 3 replies; 51+ messages in thread
From: Mike Ximing Chen @ 2021-12-21  6:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

The dlb sysfs interfaces include files for reading the total and
available device resources, and reading the device ID and version. The
interfaces are used for device level configurations and resource
inquiries.

Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
---
 Documentation/ABI/testing/sysfs-driver-dlb | 116 ++++++++++++
 drivers/misc/dlb/dlb_args.h                |  34 ++++
 drivers/misc/dlb/dlb_main.c                |   5 +
 drivers/misc/dlb/dlb_main.h                |   3 +
 drivers/misc/dlb/dlb_pf_ops.c              | 195 +++++++++++++++++++++
 drivers/misc/dlb/dlb_resource.c            |  50 ++++++
 6 files changed, 403 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-driver-dlb

diff --git a/Documentation/ABI/testing/sysfs-driver-dlb b/Documentation/ABI/testing/sysfs-driver-dlb
new file mode 100644
index 000000000000..bf09ef6f8a3a
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-dlb
@@ -0,0 +1,116 @@
+What:		/sys/bus/pci/devices/.../total_resources/num_atomic_inflights
+What:		/sys/bus/pci/devices/.../total_resources/num_dir_credits
+What:		/sys/bus/pci/devices/.../total_resources/num_dir_ports
+What:		/sys/bus/pci/devices/.../total_resources/num_hist_list_entries
+What:		/sys/bus/pci/devices/.../total_resources/num_ldb_credits
+What:		/sys/bus/pci/devices/.../total_resources/num_ldb_ports
+What:		/sys/bus/pci/devices/.../total_resources/num_cos0_ldb_ports
+What:		/sys/bus/pci/devices/.../total_resources/num_cos1_ldb_ports
+What:		/sys/bus/pci/devices/.../total_resources/num_cos2_ldb_ports
+What:		/sys/bus/pci/devices/.../total_resources/num_cos3_ldb_ports
+What:		/sys/bus/pci/devices/.../total_resources/num_ldb_queues
+What:		/sys/bus/pci/devices/.../total_resources/num_sched_domains
+Date:		Oct 15, 2021
+KernelVersion:	5.15
+Contact:	mike.ximing.chen@intel.com
+Description:
+		The total_resources subdirectory contains read-only files that
+		indicate the total number of resources in the device.
+
+		num_atomic_inflights:  Total number of atomic inflights in the
+				       device. Atomic inflights refers to the
+				       on-device storage used by the atomic
+				       scheduler.
+
+		num_dir_credits:       Total number of directed credits in the
+				       device.
+
+		num_dir_ports:	       Total number of directed ports (and
+				       queues) in the device.
+
+		num_hist_list_entries: Total number of history list entries in
+				       the device.
+
+		num_ldb_credits:       Total number of load-balanced credits in
+				       the device.
+
+		num_ldb_ports:	       Total number of load-balanced ports in
+				       the device.
+
+		num_cos<M>_ldb_ports:  Total number of load-balanced ports
+				       belonging to class-of-service M in the
+				       device.
+
+		num_ldb_queues:	       Total number of load-balanced queues in
+				       the device.
+
+		num_sched_domains:     Total number of scheduling domains in the
+				       device.
+
+What:		/sys/bus/pci/devices/.../avail_resources/num_atomic_inflights
+What:		/sys/bus/pci/devices/.../avail_resources/num_dir_credits
+What:		/sys/bus/pci/devices/.../avail_resources/num_dir_ports
+What:		/sys/bus/pci/devices/.../avail_resources/num_hist_list_entries
+What:		/sys/bus/pci/devices/.../avail_resources/num_ldb_credits
+What:		/sys/bus/pci/devices/.../avail_resources/num_ldb_ports
+What:		/sys/bus/pci/devices/.../avail_resources/num_cos0_ldb_ports
+What:		/sys/bus/pci/devices/.../avail_resources/num_cos1_ldb_ports
+What:		/sys/bus/pci/devices/.../avail_resources/num_cos2_ldb_ports
+What:		/sys/bus/pci/devices/.../avail_resources/num_cos3_ldb_ports
+What:		/sys/bus/pci/devices/.../avail_resources/num_ldb_queues
+What:		/sys/bus/pci/devices/.../avail_resources/num_sched_domains
+What:		/sys/bus/pci/devices/.../avail_resources/max_ctg_hl_entries
+Date:		Oct 15, 2021
+KernelVersion:	5.15
+Contact:	mike.ximing.chen@intel.com
+Description:
+		The avail_resources subdirectory contains read-only files that
+		indicate the available number of resources in the device.
+		"Available" here means resources that are not currently in use
+		by an application or, in the case of a physical function
+		device, assigned to a virtual function.
+
+		num_atomic_inflights:  Available number of atomic inflights in
+				       the device.
+
+		num_dir_ports:	       Available number of directed ports (and
+				       queues) in the device.
+
+		num_hist_list_entries: Available number of history list entries
+				       in the device.
+
+		num_ldb_credits:       Available number of load-balanced credits
+				       in the device.
+
+		num_ldb_ports:	       Available number of load-balanced ports
+				       in the device.
+
+		num_cos<M>_ldb_ports:  Available number of load-balanced ports
+				       belonging to class-of-service M in the
+				       device.
+
+		num_ldb_queues:	       Available number of load-balanced queues
+				       in the device.
+
+		num_sched_domains:     Available number of scheduling domains in
+				       the device.
+
+		max_ctg_hl_entries:    Maximum contiguous history list entries
+				       available in the device.
+
+				       Each scheduling domain is created with
+				       an allocation of history list entries,
+				       and each domain's allocation of entries
+				       must be contiguous.
+
+What:		/sys/bus/pci/devices/.../dev_id
+Date:		Oct 15, 2021
+KernelVersion:	5.15
+Contact:	mike.ximing.chen@intel.com
+Description:	Device ID used in /dev, i.e. /dev/dlb<device ID>
+
+		Each DLB 2.0 PF and VF device is granted a unique ID by the
+		kernel driver, and this ID is used to construct the device's
+		/dev directory: /dev/dlb<device ID>. This sysfs file can be read
+		to determine a device's ID, which allows the user to map a
+		device file to a PCI BDF.
diff --git a/drivers/misc/dlb/dlb_args.h b/drivers/misc/dlb/dlb_args.h
index eac8890c3a70..7a48751f4b56 100644
--- a/drivers/misc/dlb/dlb_args.h
+++ b/drivers/misc/dlb/dlb_args.h
@@ -58,6 +58,40 @@ struct dlb_create_sched_domain_args {
 	__u32 num_dir_credits;
 };
 
+/*
+ * dlb_get_num_resources_args: Used to get the number of available resources
+ *      (queues, ports, etc.) that this device owns.
+ *
+ * Output parameters:
+ * @response.status: Detailed error code. In certain cases, such as if the
+ *	request arg is invalid, the driver won't set status.
+ * @num_domains: Number of available scheduling domains.
+ * @num_ldb_queues: Number of available load-balanced queues.
+ * @num_ldb_ports: Total number of available load-balanced ports.
+ * @num_dir_ports: Number of available directed ports. There is one directed
+ *	queue for every directed port.
+ * @num_atomic_inflights: Amount of available temporary atomic QE storage.
+ * @num_hist_list_entries: Amount of history list storage.
+ * @max_contiguous_hist_list_entries: History list storage is allocated in
+ *	a contiguous chunk, and this return value is the longest available
+ *	contiguous range of history list entries.
+ * @num_ldb_credits: Amount of available load-balanced QE storage.
+ * @num_dir_credits: Amount of available directed QE storage.
+ */
+struct dlb_get_num_resources_args {
+	/* Output parameters */
+	struct dlb_cmd_response response;
+	__u32 num_sched_domains;
+	__u32 num_ldb_queues;
+	__u32 num_ldb_ports;
+	__u32 num_dir_ports;
+	__u32 num_atomic_inflights;
+	__u32 num_hist_list_entries;
+	__u32 max_contiguous_hist_list_entries;
+	__u32 num_ldb_credits;
+	__u32 num_dir_credits;
+};
+
 /*************************************************/
 /* 'domain' level control/access data structures */
 /*************************************************/
diff --git a/drivers/misc/dlb/dlb_main.c b/drivers/misc/dlb/dlb_main.c
index ce3cbe15e198..ea2139462602 100644
--- a/drivers/misc/dlb/dlb_main.c
+++ b/drivers/misc/dlb/dlb_main.c
@@ -409,6 +409,10 @@ static int dlb_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
 	if (ret)
 		goto dma_set_mask_fail;
 
+	ret = dlb_pf_sysfs_create(dlb);
+	if (ret)
+		goto sysfs_create_fail;
+
 	ret = dlb_configfs_create_device(dlb);
 	if (ret)
 		goto configfs_create_fail;
@@ -453,6 +457,7 @@ static int dlb_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
 dlb_reset_fail:
 wait_for_device_ready_fail:
 configfs_create_fail:
+sysfs_create_fail:
 dma_set_mask_fail:
 	device_destroy(dlb_class, dlb->dev_number);
 map_pci_bar_fail:
diff --git a/drivers/misc/dlb/dlb_main.h b/drivers/misc/dlb/dlb_main.h
index f410e7307c12..2c1401532496 100644
--- a/drivers/misc/dlb/dlb_main.h
+++ b/drivers/misc/dlb/dlb_main.h
@@ -330,6 +330,7 @@ struct dlb;
 int dlb_pf_map_pci_bar_space(struct dlb *dlb, struct pci_dev *pdev);
 void dlb_pf_unmap_pci_bar_space(struct dlb *dlb, struct pci_dev *pdev);
 int dlb_pf_init_driver_state(struct dlb *dlb);
+int dlb_pf_sysfs_create(struct dlb *dlb);
 void dlb_pf_enable_pm(struct dlb *dlb);
 int dlb_pf_wait_for_device_ready(struct dlb *dlb, struct pci_dev *pdev);
 void dlb_pf_init_hardware(struct dlb *dlb);
@@ -625,6 +626,8 @@ int dlb_hw_unmap_qid(struct dlb_hw *hw, u32 domain_id,
 int dlb_reset_domain(struct dlb_hw *hw, u32 domain_id);
 int dlb_ldb_port_owned_by_domain(struct dlb_hw *hw, u32 domain_id, u32 port_id);
 int dlb_dir_port_owned_by_domain(struct dlb_hw *hw, u32 domain_id, u32 port_id);
+int dlb_hw_get_num_resources(struct dlb_hw *hw,
+			     struct dlb_get_num_resources_args *arg);
 void dlb_clr_pmcsr_disable(struct dlb_hw *hw);
 int dlb_hw_get_ldb_queue_depth(struct dlb_hw *hw, u32 domain_id,
 			       struct dlb_get_ldb_queue_depth_args *args,
diff --git a/drivers/misc/dlb/dlb_pf_ops.c b/drivers/misc/dlb/dlb_pf_ops.c
index 66fb4ffae939..4dde46642d6e 100644
--- a/drivers/misc/dlb/dlb_pf_ops.c
+++ b/drivers/misc/dlb/dlb_pf_ops.c
@@ -102,3 +102,198 @@ void dlb_pf_init_hardware(struct dlb *dlb)
 	dlb_hw_enable_sparse_ldb_cq_mode(&dlb->hw);
 	dlb_hw_enable_sparse_dir_cq_mode(&dlb->hw);
 }
+
+/*****************************/
+/****** Sysfs callbacks ******/
+/*****************************/
+
+#define DLB_TOTAL_SYSFS_SHOW(name, macro)		\
+static ssize_t total_##name##_show(			\
+	struct device *dev,				\
+	struct device_attribute *attr,			\
+	char *buf)					\
+{							\
+	int val = DLB_MAX_NUM_##macro;			\
+							\
+	return scnprintf(buf, PAGE_SIZE, "%d\n", val);	\
+}
+
+DLB_TOTAL_SYSFS_SHOW(num_sched_domains, DOMAINS)
+DLB_TOTAL_SYSFS_SHOW(num_ldb_queues, LDB_QUEUES)
+DLB_TOTAL_SYSFS_SHOW(num_ldb_ports, LDB_PORTS)
+DLB_TOTAL_SYSFS_SHOW(num_dir_ports, DIR_PORTS)
+DLB_TOTAL_SYSFS_SHOW(num_ldb_credits, LDB_CREDITS)
+DLB_TOTAL_SYSFS_SHOW(num_dir_credits, DIR_CREDITS)
+DLB_TOTAL_SYSFS_SHOW(num_atomic_inflights, AQED_ENTRIES)
+DLB_TOTAL_SYSFS_SHOW(num_hist_list_entries, HIST_LIST_ENTRIES)
+
+#define DLB_AVAIL_SYSFS_SHOW(name)			     \
+static ssize_t avail_##name##_show(			     \
+	struct device *dev,				     \
+	struct device_attribute *attr,			     \
+	char *buf)					     \
+{							     \
+	struct dlb *dlb = dev_get_drvdata(dev);		     \
+	struct dlb_get_num_resources_args arg;		     \
+	struct dlb_hw *hw = &dlb->hw;			     \
+	int val;					     \
+							     \
+	mutex_lock(&dlb->resource_mutex);		     \
+							     \
+	val = dlb_hw_get_num_resources(hw, &arg);	     \
+							     \
+	mutex_unlock(&dlb->resource_mutex);		     \
+							     \
+	if (val)					     \
+		return -1;				     \
+							     \
+	val = arg.name;					     \
+							     \
+	return scnprintf(buf, PAGE_SIZE, "%d\n", val);	     \
+}
+
+DLB_AVAIL_SYSFS_SHOW(num_sched_domains)
+DLB_AVAIL_SYSFS_SHOW(num_ldb_queues)
+DLB_AVAIL_SYSFS_SHOW(num_ldb_ports)
+DLB_AVAIL_SYSFS_SHOW(num_dir_ports)
+DLB_AVAIL_SYSFS_SHOW(num_ldb_credits)
+DLB_AVAIL_SYSFS_SHOW(num_dir_credits)
+DLB_AVAIL_SYSFS_SHOW(num_atomic_inflights)
+DLB_AVAIL_SYSFS_SHOW(num_hist_list_entries)
+
+static ssize_t max_ctg_hl_entries_show(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	struct dlb *dlb = dev_get_drvdata(dev);
+	struct dlb_get_num_resources_args arg;
+	struct dlb_hw *hw = &dlb->hw;
+	int val;
+
+	mutex_lock(&dlb->resource_mutex);
+
+	val = dlb_hw_get_num_resources(hw, &arg);
+
+	mutex_unlock(&dlb->resource_mutex);
+
+	if (val)
+		return -1;
+
+	val = arg.max_contiguous_hist_list_entries;
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+/*
+ * Device attribute name doesn't match the show function name, so we define our
+ * own DEVICE_ATTR macro.
+ */
+#define DLB_DEVICE_ATTR_RO(_prefix, _name) \
+struct device_attribute dev_attr_##_prefix##_##_name = {\
+	.attr = { .name = __stringify(_name), .mode = 0444 },\
+	.show = _prefix##_##_name##_show,\
+}
+
+static DLB_DEVICE_ATTR_RO(total, num_sched_domains);
+static DLB_DEVICE_ATTR_RO(total, num_ldb_queues);
+static DLB_DEVICE_ATTR_RO(total, num_ldb_ports);
+static DLB_DEVICE_ATTR_RO(total, num_dir_ports);
+static DLB_DEVICE_ATTR_RO(total, num_ldb_credits);
+static DLB_DEVICE_ATTR_RO(total, num_dir_credits);
+static DLB_DEVICE_ATTR_RO(total, num_atomic_inflights);
+static DLB_DEVICE_ATTR_RO(total, num_hist_list_entries);
+
+static struct attribute *dlb_total_attrs[] = {
+	&dev_attr_total_num_sched_domains.attr,
+	&dev_attr_total_num_ldb_queues.attr,
+	&dev_attr_total_num_ldb_ports.attr,
+	&dev_attr_total_num_dir_ports.attr,
+	&dev_attr_total_num_ldb_credits.attr,
+	&dev_attr_total_num_dir_credits.attr,
+	&dev_attr_total_num_atomic_inflights.attr,
+	&dev_attr_total_num_hist_list_entries.attr,
+	NULL
+};
+
+static const struct attribute_group dlb_total_attr_group = {
+	.attrs = dlb_total_attrs,
+	.name = "total_resources",
+};
+
+static DLB_DEVICE_ATTR_RO(avail, num_sched_domains);
+static DLB_DEVICE_ATTR_RO(avail, num_ldb_queues);
+static DLB_DEVICE_ATTR_RO(avail, num_ldb_ports);
+static DLB_DEVICE_ATTR_RO(avail, num_dir_ports);
+static DLB_DEVICE_ATTR_RO(avail, num_ldb_credits);
+static DLB_DEVICE_ATTR_RO(avail, num_dir_credits);
+static DLB_DEVICE_ATTR_RO(avail, num_atomic_inflights);
+static DLB_DEVICE_ATTR_RO(avail, num_hist_list_entries);
+static DEVICE_ATTR_RO(max_ctg_hl_entries);
+
+static struct attribute *dlb_avail_attrs[] = {
+	&dev_attr_avail_num_sched_domains.attr,
+	&dev_attr_avail_num_ldb_queues.attr,
+	&dev_attr_avail_num_ldb_ports.attr,
+	&dev_attr_avail_num_dir_ports.attr,
+	&dev_attr_avail_num_ldb_credits.attr,
+	&dev_attr_avail_num_dir_credits.attr,
+	&dev_attr_avail_num_atomic_inflights.attr,
+	&dev_attr_avail_num_hist_list_entries.attr,
+	&dev_attr_max_ctg_hl_entries.attr,
+	NULL
+};
+
+static const struct attribute_group dlb_avail_attr_group = {
+	.attrs = dlb_avail_attrs,
+	.name = "avail_resources",
+};
+
+static ssize_t dev_id_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	struct dlb *dlb = dev_get_drvdata(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", dlb->id);
+}
+
+/* [7:0]: device revision, [15:8]: device version */
+#define DLB_SET_DEVICE_VERSION(ver, rev) (((ver) << 8) | (rev))
+
+static ssize_t dev_ver_show(struct device *dev,
+			    struct device_attribute *attr,
+			    char *buf)
+{
+	int ver;
+
+	ver = DLB_SET_DEVICE_VERSION(2, 0);
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", ver);
+}
+
+static DEVICE_ATTR_RO(dev_id);
+static DEVICE_ATTR_RO(dev_ver);
+
+static struct attribute *dlb_dev_id_attr[] = {
+	&dev_attr_dev_id.attr,
+	&dev_attr_dev_ver.attr,
+	NULL
+};
+
+static const struct attribute_group dlb_dev_id_attr_group = {
+	.attrs = dlb_dev_id_attr,
+};
+
+static const struct attribute_group *dlb_pf_attr_groups[] = {
+	&dlb_dev_id_attr_group,
+	&dlb_total_attr_group,
+	&dlb_avail_attr_group,
+	NULL,
+};
+
+int dlb_pf_sysfs_create(struct dlb *dlb)
+{
+	struct device *dev = &dlb->pdev->dev;
+
+	return devm_device_add_groups(dev, dlb_pf_attr_groups);
+}
diff --git a/drivers/misc/dlb/dlb_resource.c b/drivers/misc/dlb/dlb_resource.c
index e19c0f6cc321..6926ad95d9e2 100644
--- a/drivers/misc/dlb/dlb_resource.c
+++ b/drivers/misc/dlb/dlb_resource.c
@@ -3855,6 +3855,56 @@ int dlb_dir_port_owned_by_domain(struct dlb_hw *hw, u32 domain_id, u32 port_id)
 	return port->domain_id == domain->id;
 }
 
+/**
+ * dlb_hw_get_num_resources() - query the PCI function's available resources
+ * @hw: dlb_hw handle for a particular device.
+ * @arg: pointer to resource counts.
+ *
+ * This function returns the number of available resources for the PF or for a
+ * VF.
+ *
+ * Return:
+ * Returns 0 upon success, -EINVAL if input argument is
+ * invalid.
+ */
+int dlb_hw_get_num_resources(struct dlb_hw *hw,
+			     struct dlb_get_num_resources_args *arg)
+{
+	struct dlb_function_resources *rsrcs;
+	struct dlb_bitmap *map;
+	int i;
+
+	if (!hw || !arg)
+		return -EINVAL;
+
+	rsrcs = &hw->pf;
+
+	arg->num_sched_domains = rsrcs->num_avail_domains;
+
+	arg->num_ldb_queues = rsrcs->num_avail_ldb_queues;
+
+	arg->num_ldb_ports = 0;
+	for (i = 0; i < DLB_NUM_COS_DOMAINS; i++)
+		arg->num_ldb_ports += rsrcs->num_avail_ldb_ports[i];
+
+	arg->num_dir_ports = rsrcs->num_avail_dir_pq_pairs;
+
+	arg->num_atomic_inflights = rsrcs->num_avail_aqed_entries;
+
+	map = rsrcs->avail_hist_list_entries;
+
+	arg->num_hist_list_entries = bitmap_weight(map->map, map->len);
+
+	arg->max_contiguous_hist_list_entries =
+		dlb_bitmap_longest_set_range(map);
+
+	arg->num_ldb_credits = rsrcs->num_avail_qed_entries;
+
+	arg->num_dir_credits = rsrcs->num_avail_dqed_entries;
+
+	return 0;
+}
+
 /**
  * dlb_clr_pmcsr_disable() - power on bulk of DLB 2.0 logic
  * @hw: dlb_hw handle for a particular device.
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-21  6:50 ` [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver Mike Ximing Chen
@ 2021-12-21  7:00   ` Joe Perches
  2021-12-21 23:22     ` Chen, Mike Ximing
  2021-12-21  7:12   ` Greg KH
  2021-12-21  9:53   ` Andrew Lunn
  2 siblings, 1 reply; 51+ messages in thread
From: Joe Perches @ 2021-12-21  7:00 UTC (permalink / raw)
  To: Mike Ximing Chen, linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

On Tue, 2021-12-21 at 00:50 -0600, Mike Ximing Chen wrote:
> Add a DLB entry to the MAINTAINERS file.

btw: Nice documentation

> diff --git a/MAINTAINERS b/MAINTAINERS
[]
> @@ -9335,6 +9335,13 @@ L:	linux-kernel@vger.kernel.org
>  S:	Supported
>  F:	arch/x86/include/asm/intel-family.h
>  
> +INTEL DYNAMIC LOAD BALANCER DRIVER
> +M:	Mike Ximing Chen <mike.ximing.chen@intel.com>
> +S:	Maintained
> +F:	Documentation/ABI/testing/sysfs-driver-dlb
> +F:	drivers/misc/dlb/
> +F:	include/uapi/linux/dlb.h
> +
>  INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
>  M:	Jani Nikula <jani.nikula@linux.intel.com>
>  M:	Joonas Lahtinen <joonas.lahtinen@linux.intel.com>

Section is not in the appropriate alphabetic order.

dynamic should be after drm

> diff --git a/drivers/misc/dlb/dlb_main.c b/drivers/misc/dlb/dlb_main.c
[]
> +// SPDX-License-Identifier: GPL-2.0-only
[]
> +MODULE_LICENSE("GPL v2");

Should use "GPL" not "GPL v2".

https://lore.kernel.org/lkml/alpine.DEB.2.21.1901282105450.1669@nanos.tec.linutronix.de/



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 00/17] dlb: introduce DLB device driver
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
                   ` (16 preceding siblings ...)
  2021-12-21  6:50 ` [RFC PATCH v12 17/17] dlb: add basic sysfs interfaces Mike Ximing Chen
@ 2021-12-21  7:09 ` Greg KH
  2021-12-21 14:03   ` Chen, Mike Ximing
  2021-12-21  9:40 ` Andrew Lunn
  18 siblings, 1 reply; 51+ messages in thread
From: Greg KH @ 2021-12-21  7:09 UTC (permalink / raw)
  To: Mike Ximing Chen
  Cc: linux-kernel, arnd, dan.j.williams, pierre-louis.bossart, netdev,
	davem, kuba

On Tue, Dec 21, 2021 at 12:50:30AM -0600, Mike Ximing Chen wrote:
> v12:

<snip>

How is a "RFC" series on version 12?  "RFC" means "I do not think this
should be merged, please give me some comments on how this is all
structured" which I think is not the case here.

> - The following coding style changes suggested by Dan will be implemented
>   in the next revision
> -- Replace DLB_CSR_RD() and DLB_CSR_WR() with direct ioread32() and
>    iowrite32() call.
> -- Remove bitmap wrappers and use linux bitmap functions directly.
> -- Use trace_event in configfs attribute file update.

Why submit a patch series that you know will be changed?  Just do the
work, don't ask anyone to review stuff you know is incorrect, that just
wastes our time and ensures that we never want to review it again.

greg k-h

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-21  6:50 ` [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver Mike Ximing Chen
  2021-12-21  7:00   ` Joe Perches
@ 2021-12-21  7:12   ` Greg KH
  2021-12-21  8:57     ` Greg KH
  2021-12-21 14:05     ` Chen, Mike Ximing
  2021-12-21  9:53   ` Andrew Lunn
  2 siblings, 2 replies; 51+ messages in thread
From: Greg KH @ 2021-12-21  7:12 UTC (permalink / raw)
  To: Mike Ximing Chen
  Cc: linux-kernel, arnd, dan.j.williams, pierre-louis.bossart, netdev,
	davem, kuba

On Tue, Dec 21, 2021 at 12:50:31AM -0600, Mike Ximing Chen wrote:
> +/* Copyright(C) 2016-2020 Intel Corporation. All rights reserved. */

So you did not touch this at all in 2021?  And it had a copyrightable
changed added to it for every year, inclusive, from 2016-2020?

Please run this past your lawyers on how to do this properly.

greg k-h

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 17/17] dlb: add basic sysfs interfaces
  2021-12-21  6:50 ` [RFC PATCH v12 17/17] dlb: add basic sysfs interfaces Mike Ximing Chen
@ 2021-12-21  7:20   ` Joe Perches
  2021-12-21 23:18     ` Chen, Mike Ximing
  2021-12-21  8:56   ` Greg KH
  2021-12-21 23:34   ` Stephen Hemminger
  2 siblings, 1 reply; 51+ messages in thread
From: Joe Perches @ 2021-12-21  7:20 UTC (permalink / raw)
  To: Mike Ximing Chen, linux-kernel
  Cc: arnd, gregkh, dan.j.williams, pierre-louis.bossart, netdev, davem, kuba

On Tue, 2021-12-21 at 00:50 -0600, Mike Ximing Chen wrote:
> The dlb sysfs interfaces include files for reading the total and
> available device resources, and reading the device ID and version. The
> interfaces are used for device level configurations and resource
> inquiries.
[]
> diff --git a/drivers/misc/dlb/dlb_args.h b/drivers/misc/dlb/dlb_args.h
[]
> @@ -58,6 +58,40 @@ struct dlb_create_sched_domain_args {
>  	__u32 num_dir_credits;
>  };
>  
> +/*
> + * dlb_get_num_resources_args: Used to get the number of available resources
> + *      (queues, ports, etc.) that this device owns.
> + *
> + * Output parameters:
> + * @response.status: Detailed error code. In certain cases, such as if the
> + *	request arg is invalid, the driver won't set status.
> + * @num_domains: Number of available scheduling domains.
> + * @num_ldb_queues: Number of available load-balanced queues.
> + * @num_ldb_ports: Total number of available load-balanced ports.
> + * @num_dir_ports: Number of available directed ports. There is one directed
> + *	queue for every directed port.
> + * @num_atomic_inflights: Amount of available temporary atomic QE storage.
> + * @num_hist_list_entries: Amount of history list storage.
> + * @max_contiguous_hist_list_entries: History list storage is allocated in
> + *	a contiguous chunk, and this return value is the longest available
> + *	contiguous range of history list entries.
> + * @num_ldb_credits: Amount of available load-balanced QE storage.
> + * @num_dir_credits: Amount of available directed QE storage.
> + */

Is this supposed to be kernel-doc format with /** as the comment initiator ?

> +struct dlb_get_num_resources_args {
> +	/* Output parameters */
> +	struct dlb_cmd_response response;
> +	__u32 num_sched_domains;
> +	__u32 num_ldb_queues;
> +	__u32 num_ldb_ports;
> +	__u32 num_dir_ports;
> +	__u32 num_atomic_inflights;
> +	__u32 num_hist_list_entries;
> +	__u32 max_contiguous_hist_list_entries;
> +	__u32 num_ldb_credits;
> +	__u32 num_dir_credits;

__u32 is used when visible to user-space.
Do these really need to use __u32 and not u32 ?

> diff --git a/drivers/misc/dlb/dlb_pf_ops.c b/drivers/misc/dlb/dlb_pf_ops.c
[]
> @@ -102,3 +102,198 @@ void dlb_pf_init_hardware(struct dlb *dlb)
[]
> +#define DLB_TOTAL_SYSFS_SHOW(name, macro)		\
> +static ssize_t total_##name##_show(			\
> +	struct device *dev,				\
> +	struct device_attribute *attr,			\
> +	char *buf)					\
> +{							\
> +	int val = DLB_MAX_NUM_##macro;			\
> +							\
> +	return scnprintf(buf, PAGE_SIZE, "%d\n", val);	\

Use sysfs_emit rather than scnprintf

maybe:
	return sysfs_emit(buf, "%u\n", DLB_MAX_NUM_##macro);

> +#define DLB_AVAIL_SYSFS_SHOW(name)			     \
> +static ssize_t avail_##name##_show(			     \
> +	struct device *dev,				     \
> +	struct device_attribute *attr,			     \
> +	char *buf)					     \
> +{							     \
> +	struct dlb *dlb = dev_get_drvdata(dev);		     \
> +	struct dlb_get_num_resources_args arg;		     \
> +	struct dlb_hw *hw = &dlb->hw;			     \
> +	int val;					     \

u32 val?

> +							     \
> +	mutex_lock(&dlb->resource_mutex);		     \
> +							     \
> +	val = dlb_hw_get_num_resources(hw, &arg);	     \
> +							     \
> +	mutex_unlock(&dlb->resource_mutex);		     \
> +							     \
> +	if (val)					     \
> +		return -1;				     \
> +							     \
> +	val = arg.name;					     \
> +							     \
> +	return scnprintf(buf, PAGE_SIZE, "%d\n", val);	     \

sysfs_emit, etc...



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 17/17] dlb: add basic sysfs interfaces
  2021-12-21  6:50 ` [RFC PATCH v12 17/17] dlb: add basic sysfs interfaces Mike Ximing Chen
  2021-12-21  7:20   ` Joe Perches
@ 2021-12-21  8:56   ` Greg KH
  2021-12-21 14:07     ` Chen, Mike Ximing
  2021-12-21 23:34   ` Stephen Hemminger
  2 siblings, 1 reply; 51+ messages in thread
From: Greg KH @ 2021-12-21  8:56 UTC (permalink / raw)
  To: Mike Ximing Chen
  Cc: linux-kernel, arnd, dan.j.williams, pierre-louis.bossart, netdev,
	davem, kuba

On Tue, Dec 21, 2021 at 12:50:47AM -0600, Mike Ximing Chen wrote:
> +Date:		Oct 15, 2021
> +KernelVersion:	5.15

5.15 and that date was  long time ago :(

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-21  7:12   ` Greg KH
@ 2021-12-21  8:57     ` Greg KH
  2021-12-21 14:25       ` Chen, Mike Ximing
  2021-12-21 14:05     ` Chen, Mike Ximing
  1 sibling, 1 reply; 51+ messages in thread
From: Greg KH @ 2021-12-21  8:57 UTC (permalink / raw)
  To: Mike Ximing Chen
  Cc: linux-kernel, arnd, dan.j.williams, pierre-louis.bossart, netdev,
	davem, kuba

On Tue, Dec 21, 2021 at 08:12:00AM +0100, Greg KH wrote:
> On Tue, Dec 21, 2021 at 12:50:31AM -0600, Mike Ximing Chen wrote:
> > +/* Copyright(C) 2016-2020 Intel Corporation. All rights reserved. */
> 
> So you did not touch this at all in 2021?  And it had a copyrightable
> changed added to it for every year, inclusive, from 2016-2020?
> 
> Please run this past your lawyers on how to do this properly.

Ah, this was a "throw it over the fence at the community to handle for
me before I go on vacation" type of posting, based on your autoresponse
email that happened when I sent this.

That too isn't the most kind thing, would you want to be the reviewer of
this if it were sent to you?  Please take some time and start doing
patch reviews for the char/misc drivers on the mailing list before
submitting any more new code.

Also, this patch series goes agains the internal rules that I know your
company has, why is that?  Those rules are there for a good reason, and
by ignoring them, it's going to make it much harder to get patches to be
reviewed.

best of luck!

greg k-h

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 00/17] dlb: introduce DLB device driver
  2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
                   ` (17 preceding siblings ...)
  2021-12-21  7:09 ` [RFC PATCH v12 00/17] dlb: introduce DLB device driver Greg KH
@ 2021-12-21  9:40 ` Andrew Lunn
  2021-12-22  4:37   ` Chen, Mike Ximing
  18 siblings, 1 reply; 51+ messages in thread
From: Andrew Lunn @ 2021-12-21  9:40 UTC (permalink / raw)
  To: Mike Ximing Chen
  Cc: linux-kernel, arnd, gregkh, dan.j.williams, pierre-louis.bossart,
	netdev, davem, kuba

> 1. Before a scheduling domain is created/enabled, a set of parameters are
> passed to the kernel driver via configfs attribute files in an configfs domain
> directory (say $domain) created by user. Each attribute file corresponds to
> a configuration parameter of the domain. After writing to all the attribute
> files, user writes 1 to "create" attribute, which triggers an action (i.e.,
> domain creation) in the kernel driver. Since multiple processes/users can
> access the $domain directory, multiple users can write to the attribute files
> at the same time.  How do we guarantee an atomic update/configuration of a
> domain? In other words, if user A wants to set attributes 1 and 2, how can we
> prevent user B from changing attribute 1 and 2 before user A writes 1 to
> "create"? A configfs directory with individual attribute files seems to not
> be able to provide atomic configuration in this case. One option to solve this
> issue could be write a structured data (with a set of parameters) to a single
> attribute file. This would guarantee the atomic configuration, but may not be
> a conventional configfs operation.

How about throw away configfs and use netlink? Messages are atomic,
and you can add an arbitrary number of attributes to a single netlink
message. It will also make your code more network like, since nothing
else in the network stack uses configfs, as far as i know.

    Andrew

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-21  6:50 ` [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver Mike Ximing Chen
  2021-12-21  7:00   ` Joe Perches
  2021-12-21  7:12   ` Greg KH
@ 2021-12-21  9:53   ` Andrew Lunn
  2021-12-21 20:56     ` Chen, Mike Ximing
  2 siblings, 1 reply; 51+ messages in thread
From: Andrew Lunn @ 2021-12-21  9:53 UTC (permalink / raw)
  To: Mike Ximing Chen
  Cc: linux-kernel, arnd, gregkh, dan.j.williams, pierre-louis.bossart,
	netdev, davem, kuba

> +The following diagram shows a typical packet processing pipeline with the Intel DLB.
> +
> +                              WC1              WC4
> + +-----+   +----+   +---+  /      \  +---+  /      \  +---+   +----+   +-----+
> + |NIC  |   |Rx  |   |DLB| /        \ |DLB| /        \ |DLB|   |Tx  |   |NIC  |
> + |Ports|---|Core|---|   |-----WC2----|   |-----WC5----|   |---|Core|---|Ports|
> + +-----+   -----+   +---+ \        / +---+ \        / +---+   +----+   ------+
> +                           \      /         \      /
> +                              WC3              WC6

This is the only mention of NIC here. Does the application interface
to the network stack in the usual way to receive packets from the
TCP/IP stack up into user space and then copy it back down into the
MMIO block for it to enter the DLB for the first time? And at the end
of the path, does the application copy it from the MMIO into a
standard socket for TCP/IP processing to be send out the NIC?

Do you even needs NICs here? Could the data be coming of a video
camera and you are distributing image processing over a number of
cores?

	 Andrew

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 05/17] dlb: add scheduling domain configuration
  2021-12-21  6:50 ` [RFC PATCH v12 05/17] dlb: add scheduling domain configuration Mike Ximing Chen
@ 2021-12-21 12:18   ` kernel test robot
  0 siblings, 0 replies; 51+ messages in thread
From: kernel test robot @ 2021-12-21 12:18 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 2130 bytes --]

Hi Mike,

[FYI, it's a private test report for your RFC patch.]
[auto build test ERROR on 519d81956ee277b4419c723adfb154603c2565ba]

url:    https://github.com/0day-ci/linux/commits/Mike-Ximing-Chen/dlb-introduce-DLB-device-driver/20211221-145401
base:   519d81956ee277b4419c723adfb154603c2565ba
config: ia64-randconfig-r013-20211220 (https://download.01.org/0day-ci/archive/20211221/202112212044.gqdS9GD0-lkp(a)intel.com/config)
compiler: ia64-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/0eda6e751d0d56438a61a982ac6195888244b4fa
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Mike-Ximing-Chen/dlb-introduce-DLB-device-driver/20211221-145401
        git checkout 0eda6e751d0d56438a61a982ac6195888244b4fa
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=ia64 prepare

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> error: include/uapi/linux/dlb.h: missing "WITH Linux-syscall-note" for SPDX-License-Identifier
   make[2]: *** [scripts/Makefile.headersinst:63: usr/include/linux/dlb.h] Error 1
   make[2]: Target '__headers' not remade because of errors.
   make[1]: *** [Makefile:1305: headers] Error 2
   arch/ia64/kernel/asm-offsets.c:23:6: warning: no previous prototype for 'foo' [-Wmissing-prototypes]
      23 | void foo(void)
         |      ^~~
   <stdin>:1517:2: warning: #warning syscall clone3 not implemented [-Wcpp]
   make[1]: Target 'prepare' not remade because of errors.
   make: *** [Makefile:219: __sub-make] Error 2
   make: Target 'prepare' not remade because of errors.

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

^ permalink raw reply	[flat|nested] 51+ messages in thread

* RE: [RFC PATCH v12 00/17] dlb: introduce DLB device driver
  2021-12-21  7:09 ` [RFC PATCH v12 00/17] dlb: introduce DLB device driver Greg KH
@ 2021-12-21 14:03   ` Chen, Mike Ximing
  2021-12-21 14:31     ` Greg KH
  0 siblings, 1 reply; 51+ messages in thread
From: Chen, Mike Ximing @ 2021-12-21 14:03 UTC (permalink / raw)
  To: Greg KH
  Cc: linux-kernel, arnd, Williams, Dan J, pierre-louis.bossart,
	netdev, davem, kuba


> -----Original Message-----
> From: Greg KH <gregkh@linuxfoundation.org>
> Sent: Tuesday, December 21, 2021 2:10 AM
> To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; Williams, Dan J <dan.j.williams@intel.com>; pierre-
> louis.bossart@linux.intel.com; netdev@vger.kernel.org; davem@davemloft.net; kuba@kernel.org
> Subject: Re: [RFC PATCH v12 00/17] dlb: introduce DLB device driver
> 
> On Tue, Dec 21, 2021 at 12:50:30AM -0600, Mike Ximing Chen wrote:
> > v12:
> 
> <snip>
> 
> How is a "RFC" series on version 12?  "RFC" means "I do not think this should be merged, please give me
> some comments on how this is all structured" which I think is not the case here.

Hi Greg,

"RFC" here means exactly what you referred to. As you know we have made many changes since your
last review of the patch set (which was v10).  At this point we are not sure if we are on the right track in
terms of some configfs implementation, and would like some comments from the community. I stated
this in the cover letter before the change log: " This submission is still a work in progress.... , a couple of
issues that we would like to get help and suggestions from reviewers and community". I presented two
issues/questions we are facing, and would like to get comments. 

The code on the other hand are tested and validated on our hardware platforms. I kept the version number
in series (using v12, instead v1) so that reviewers can track the old submissions and have a better
understanding of the patch set's history.

> 
> > - The following coding style changes suggested by Dan will be implemented
> >   in the next revision
> > -- Replace DLB_CSR_RD() and DLB_CSR_WR() with direct ioread32() and
> >    iowrite32() call.
> > -- Remove bitmap wrappers and use linux bitmap functions directly.
> > -- Use trace_event in configfs attribute file update.
> 
> Why submit a patch series that you know will be changed?  Just do the work, don't ask anyone to review
> stuff you know is incorrect, that just wastes our time and ensures that we never want to review it again.
>
Since this is a RFC, and is not for merging or a full review, we though it was OK to log the pending coding
style changes. The patch set was submitted and reviewed by the community before, and there was no
complains on using macros like DLB_CSR_RD(), etc, but we think we can replace them for better
readability of the code.

Thanks
Mike 
 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* RE: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-21  7:12   ` Greg KH
  2021-12-21  8:57     ` Greg KH
@ 2021-12-21 14:05     ` Chen, Mike Ximing
  1 sibling, 0 replies; 51+ messages in thread
From: Chen, Mike Ximing @ 2021-12-21 14:05 UTC (permalink / raw)
  To: Greg KH
  Cc: linux-kernel, arnd, Williams, Dan J, pierre-louis.bossart,
	netdev, davem, kuba


> -----Original Message-----
> From: Greg KH <gregkh@linuxfoundation.org>
> Sent: Tuesday, December 21, 2021 2:12 AM
> To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; Williams, Dan J <dan.j.williams@intel.com>; pierre-
> louis.bossart@linux.intel.com; netdev@vger.kernel.org; davem@davemloft.net; kuba@kernel.org
> Subject: Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
> 
> On Tue, Dec 21, 2021 at 12:50:31AM -0600, Mike Ximing Chen wrote:
> > +/* Copyright(C) 2016-2020 Intel Corporation. All rights reserved. */
> 
> So you did not touch this at all in 2021?  And it had a copyrightable changed added to it for every year,
> inclusive, from 2016-2020?
> 
> Please run this past your lawyers on how to do this properly.
> 
> greg k-h

Thanks for pointing it out. I will fix this.

Mike

^ permalink raw reply	[flat|nested] 51+ messages in thread

* RE: [RFC PATCH v12 17/17] dlb: add basic sysfs interfaces
  2021-12-21  8:56   ` Greg KH
@ 2021-12-21 14:07     ` Chen, Mike Ximing
  0 siblings, 0 replies; 51+ messages in thread
From: Chen, Mike Ximing @ 2021-12-21 14:07 UTC (permalink / raw)
  To: Greg KH
  Cc: linux-kernel, arnd, Williams, Dan J, pierre-louis.bossart,
	netdev, davem, kuba



> -----Original Message-----
> From: Greg KH <gregkh@linuxfoundation.org>
> Sent: Tuesday, December 21, 2021 3:57 AM
> To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; Williams, Dan J <dan.j.williams@intel.com>; pierre-
> louis.bossart@linux.intel.com; netdev@vger.kernel.org; davem@davemloft.net; kuba@kernel.org
> Subject: Re: [RFC PATCH v12 17/17] dlb: add basic sysfs interfaces
> 
> On Tue, Dec 21, 2021 at 12:50:47AM -0600, Mike Ximing Chen wrote:
> > +Date:		Oct 15, 2021
> > +KernelVersion:	5.15
> 
> 5.15 and that date was  long time ago :(

Will use latest one in the future submissions.
Thanks
Mike

^ permalink raw reply	[flat|nested] 51+ messages in thread

* RE: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-21  8:57     ` Greg KH
@ 2021-12-21 14:25       ` Chen, Mike Ximing
  2021-12-21 14:42         ` Chen, Mike Ximing
  0 siblings, 1 reply; 51+ messages in thread
From: Chen, Mike Ximing @ 2021-12-21 14:25 UTC (permalink / raw)
  To: Greg KH
  Cc: linux-kernel, arnd, Williams, Dan J, pierre-louis.bossart,
	netdev, davem, kuba


> -----Original Message-----
> From: Greg KH <gregkh@linuxfoundation.org>
> Sent: Tuesday, December 21, 2021 3:57 AM
> To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; Williams, Dan J <dan.j.williams@intel.com>; pierre-
> louis.bossart@linux.intel.com; netdev@vger.kernel.org; davem@davemloft.net; kuba@kernel.org
> Subject: Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
> 
> On Tue, Dec 21, 2021 at 08:12:00AM +0100, Greg KH wrote:
> > On Tue, Dec 21, 2021 at 12:50:31AM -0600, Mike Ximing Chen wrote:
> > > +/* Copyright(C) 2016-2020 Intel Corporation. All rights reserved.
> > > +*/
> >
> > So you did not touch this at all in 2021?  And it had a copyrightable
> > changed added to it for every year, inclusive, from 2016-2020?
> >
> > Please run this past your lawyers on how to do this properly.
> 
> Ah, this was a "throw it over the fence at the community to handle for me before I go on vacation" type of
> posting, based on your autoresponse email that happened when I sent this.
> 
> That too isn't the most kind thing, would you want to be the reviewer of this if it were sent to you?  Please
> take some time and start doing patch reviews for the char/misc drivers on the mailing list before
> submitting any more new code.
> 
> Also, this patch series goes agains the internal rules that I know your company has, why is that?  Those
> rules are there for a good reason, and by ignoring them, it's going to make it much harder to get patches
> to be reviewed.
> 

I assume that you referred to the "Reviewed-by" rule from Intel. Since this is a RFC and we are seeking for
comments and guidance on our code structure, we thought it was appropriate to sent out patch set out
with a full endorsement from our internal reviewers. The questions I posted in the cover letter
(patch 00/17) are from the discussions with our internal reviewers.

I will take some days off as many people would do during this time of the year 😊, but will check mails daily
and response to questions/comments on the submission.

Thanks for your help.
Mike 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 00/17] dlb: introduce DLB device driver
  2021-12-21 14:03   ` Chen, Mike Ximing
@ 2021-12-21 14:31     ` Greg KH
  2021-12-21 18:44       ` Dan Williams
  0 siblings, 1 reply; 51+ messages in thread
From: Greg KH @ 2021-12-21 14:31 UTC (permalink / raw)
  To: Chen, Mike Ximing
  Cc: linux-kernel, arnd, Williams, Dan J, pierre-louis.bossart,
	netdev, davem, kuba

On Tue, Dec 21, 2021 at 02:03:38PM +0000, Chen, Mike Ximing wrote:
> 
> > -----Original Message-----
> > From: Greg KH <gregkh@linuxfoundation.org>
> > Sent: Tuesday, December 21, 2021 2:10 AM
> > To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> > Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; Williams, Dan J <dan.j.williams@intel.com>; pierre-
> > louis.bossart@linux.intel.com; netdev@vger.kernel.org; davem@davemloft.net; kuba@kernel.org
> > Subject: Re: [RFC PATCH v12 00/17] dlb: introduce DLB device driver
> > 
> > On Tue, Dec 21, 2021 at 12:50:30AM -0600, Mike Ximing Chen wrote:
> > > v12:
> > 
> > <snip>
> > 
> > How is a "RFC" series on version 12?  "RFC" means "I do not think this should be merged, please give me
> > some comments on how this is all structured" which I think is not the case here.
> 
> Hi Greg,
> 
> "RFC" here means exactly what you referred to. As you know we have made many changes since your
> last review of the patch set (which was v10).  At this point we are not sure if we are on the right track in
> terms of some configfs implementation, and would like some comments from the community. I stated
> this in the cover letter before the change log: " This submission is still a work in progress.... , a couple of
> issues that we would like to get help and suggestions from reviewers and community". I presented two
> issues/questions we are facing, and would like to get comments. 
> 
> The code on the other hand are tested and validated on our hardware platforms. I kept the version number
> in series (using v12, instead v1) so that reviewers can track the old submissions and have a better
> understanding of the patch set's history.

"RFC" means "I have no idea if this is correct, I am throwing it out
there and anyone who also cares about this type of thing, please
comment".

A patch that is on "RFC 12" means, "We all have no clue how to do this,
we give up and hope you all will do it for us."

I almost never comment on RFC patch series, except for portions of the
kernel that I really care about.  For a brand-new subsystem like this,
that I still do not understand who needs it, that is not the case.

I'm going to stop reviewing this patch series until you at least follow
the Intel required rules for sending kernel patches like this out.  To
not do so would be unfair to your coworkers who _DO_ follow the rules.

> > > - The following coding style changes suggested by Dan will be implemented
> > >   in the next revision
> > > -- Replace DLB_CSR_RD() and DLB_CSR_WR() with direct ioread32() and
> > >    iowrite32() call.
> > > -- Remove bitmap wrappers and use linux bitmap functions directly.
> > > -- Use trace_event in configfs attribute file update.
> > 
> > Why submit a patch series that you know will be changed?  Just do the work, don't ask anyone to review
> > stuff you know is incorrect, that just wastes our time and ensures that we never want to review it again.
> >
> Since this is a RFC, and is not for merging or a full review, we though it was OK to log the pending coding
> style changes. The patch set was submitted and reviewed by the community before, and there was no
> complains on using macros like DLB_CSR_RD(), etc, but we think we can replace them for better
> readability of the code.

Coding style changes should NEVER be ignored and put off for later.
To do so means you do not care about the brains of anyone who you are
wanting to read this code.  We have a coding style because of brains and
pattern matching, not because we are being mean.

good luck,

greg k-h

^ permalink raw reply	[flat|nested] 51+ messages in thread

* RE: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-21 14:25       ` Chen, Mike Ximing
@ 2021-12-21 14:42         ` Chen, Mike Ximing
  2021-12-21 15:02           ` Greg KH
  0 siblings, 1 reply; 51+ messages in thread
From: Chen, Mike Ximing @ 2021-12-21 14:42 UTC (permalink / raw)
  To: Chen, Mike Ximing, Greg KH
  Cc: linux-kernel, arnd, Williams, Dan J, pierre-louis.bossart,
	netdev, davem, kuba



> -----Original Message-----
> From: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> Sent: Tuesday, December 21, 2021 9:26 AM
> To: Greg KH <gregkh@linuxfoundation.org>
> Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; Williams, Dan J <dan.j.williams@intel.com>; pierre-
> louis.bossart@linux.intel.com; netdev@vger.kernel.org; davem@davemloft.net; kuba@kernel.org
> Subject: RE: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
> 
> 
> > -----Original Message-----
> > From: Greg KH <gregkh@linuxfoundation.org>
> > Sent: Tuesday, December 21, 2021 3:57 AM
> > To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> > Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; Williams, Dan J
> > <dan.j.williams@intel.com>; pierre- louis.bossart@linux.intel.com;
> > netdev@vger.kernel.org; davem@davemloft.net; kuba@kernel.org
> > Subject: Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
> >
> > On Tue, Dec 21, 2021 at 08:12:00AM +0100, Greg KH wrote:
> > > On Tue, Dec 21, 2021 at 12:50:31AM -0600, Mike Ximing Chen wrote:
> > > > +/* Copyright(C) 2016-2020 Intel Corporation. All rights reserved.
> > > > +*/
> > >
> > > So you did not touch this at all in 2021?  And it had a
> > > copyrightable changed added to it for every year, inclusive, from 2016-2020?
> > >
> > > Please run this past your lawyers on how to do this properly.
> >
> > Ah, this was a "throw it over the fence at the community to handle for
> > me before I go on vacation" type of posting, based on your autoresponse email that happened when I
> sent this.
> >
> > That too isn't the most kind thing, would you want to be the reviewer
> > of this if it were sent to you?  Please take some time and start doing
> > patch reviews for the char/misc drivers on the mailing list before submitting any more new code.
> >
> > Also, this patch series goes agains the internal rules that I know
> > your company has, why is that?  Those rules are there for a good
> > reason, and by ignoring them, it's going to make it much harder to get patches to be reviewed.
> >
> 
> I assume that you referred to the "Reviewed-by" rule from Intel. Since this is a RFC and we are seeking for
> comments and guidance on our code structure, we thought it was appropriate to send out patch set out
> with a full endorsement from our internal reviewers. The questions I posted in the cover letter (patch
> 00/17) are from the discussions with our internal reviewers.
.
"we thought it was appropriate to send out the patch set out without* a full endorsement from our
Internal reviewers"  --- sorry for misspelling.
> 
> I will take some days off as many people would do during this time of the year 😊, but will check mails
> daily and response to questions/comments on the submission.
> 
> Thanks for your help.
> Mike

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-21 14:42         ` Chen, Mike Ximing
@ 2021-12-21 15:02           ` Greg KH
  0 siblings, 0 replies; 51+ messages in thread
From: Greg KH @ 2021-12-21 15:02 UTC (permalink / raw)
  To: Chen, Mike Ximing
  Cc: linux-kernel, arnd, Williams, Dan J, pierre-louis.bossart,
	netdev, davem, kuba

On Tue, Dec 21, 2021 at 02:42:10PM +0000, Chen, Mike Ximing wrote:
> 
> 
> > -----Original Message-----
> > From: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> > Sent: Tuesday, December 21, 2021 9:26 AM
> > To: Greg KH <gregkh@linuxfoundation.org>
> > Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; Williams, Dan J <dan.j.williams@intel.com>; pierre-
> > louis.bossart@linux.intel.com; netdev@vger.kernel.org; davem@davemloft.net; kuba@kernel.org
> > Subject: RE: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
> > 
> > 
> > > -----Original Message-----
> > > From: Greg KH <gregkh@linuxfoundation.org>
> > > Sent: Tuesday, December 21, 2021 3:57 AM
> > > To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> > > Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; Williams, Dan J
> > > <dan.j.williams@intel.com>; pierre- louis.bossart@linux.intel.com;
> > > netdev@vger.kernel.org; davem@davemloft.net; kuba@kernel.org
> > > Subject: Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
> > >
> > > On Tue, Dec 21, 2021 at 08:12:00AM +0100, Greg KH wrote:
> > > > On Tue, Dec 21, 2021 at 12:50:31AM -0600, Mike Ximing Chen wrote:
> > > > > +/* Copyright(C) 2016-2020 Intel Corporation. All rights reserved.
> > > > > +*/
> > > >
> > > > So you did not touch this at all in 2021?  And it had a
> > > > copyrightable changed added to it for every year, inclusive, from 2016-2020?
> > > >
> > > > Please run this past your lawyers on how to do this properly.
> > >
> > > Ah, this was a "throw it over the fence at the community to handle for
> > > me before I go on vacation" type of posting, based on your autoresponse email that happened when I
> > sent this.
> > >
> > > That too isn't the most kind thing, would you want to be the reviewer
> > > of this if it were sent to you?  Please take some time and start doing
> > > patch reviews for the char/misc drivers on the mailing list before submitting any more new code.
> > >
> > > Also, this patch series goes agains the internal rules that I know
> > > your company has, why is that?  Those rules are there for a good
> > > reason, and by ignoring them, it's going to make it much harder to get patches to be reviewed.
> > >
> > 
> > I assume that you referred to the "Reviewed-by" rule from Intel. Since this is a RFC and we are seeking for
> > comments and guidance on our code structure, we thought it was appropriate to send out patch set out
> > with a full endorsement from our internal reviewers. The questions I posted in the cover letter (patch
> > 00/17) are from the discussions with our internal reviewers.
> .
> "we thought it was appropriate to send out the patch set out without* a full endorsement from our
> Internal reviewers"  --- sorry for misspelling.

I think you mean something like "we had an internal deadline to meet so
we are willing to ignore our rules and throw it over the wall and let
the community worry about it."

Congratulations, I now feel like the hours I spent last week talking to
hundreds of Intel developers about this very topic were totally wasted.

{sigh}

Intel now owes me another bottle of liquor...

greg k-h

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 00/17] dlb: introduce DLB device driver
  2021-12-21 14:31     ` Greg KH
@ 2021-12-21 18:44       ` Dan Williams
  2021-12-21 19:57         ` Andrew Lunn
  2021-12-22  8:01         ` Christoph Hellwig
  0 siblings, 2 replies; 51+ messages in thread
From: Dan Williams @ 2021-12-21 18:44 UTC (permalink / raw)
  To: Greg KH
  Cc: Chen, Mike Ximing, linux-kernel, arnd, pierre-louis.bossart,
	netdev, davem, kuba, Christoph Hellwig

[ add Christoph for configfs feedback ]

On Tue, Dec 21, 2021 at 7:03 AM Greg KH <gregkh@linuxfoundation.org> wrote:
>
> On Tue, Dec 21, 2021 at 02:03:38PM +0000, Chen, Mike Ximing wrote:
> >
> > > -----Original Message-----
> > > From: Greg KH <gregkh@linuxfoundation.org>
> > > Sent: Tuesday, December 21, 2021 2:10 AM
> > > To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> > > Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; Williams, Dan J <dan.j.williams@intel.com>; pierre-
> > > louis.bossart@linux.intel.com; netdev@vger.kernel.org; davem@davemloft.net; kuba@kernel.org
> > > Subject: Re: [RFC PATCH v12 00/17] dlb: introduce DLB device driver
> > >
> > > On Tue, Dec 21, 2021 at 12:50:30AM -0600, Mike Ximing Chen wrote:
> > > > v12:
> > >
> > > <snip>
> > >
> > > How is a "RFC" series on version 12?  "RFC" means "I do not think this should be merged, please give me
> > > some comments on how this is all structured" which I think is not the case here.
> >
> > Hi Greg,
> >
> > "RFC" here means exactly what you referred to. As you know we have made many changes since your
> > last review of the patch set (which was v10).  At this point we are not sure if we are on the right track in
> > terms of some configfs implementation, and would like some comments from the community. I stated
> > this in the cover letter before the change log: " This submission is still a work in progress.... , a couple of
> > issues that we would like to get help and suggestions from reviewers and community". I presented two
> > issues/questions we are facing, and would like to get comments.
> >
> > The code on the other hand are tested and validated on our hardware platforms. I kept the version number
> > in series (using v12, instead v1) so that reviewers can track the old submissions and have a better
> > understanding of the patch set's history.
>
> "RFC" means "I have no idea if this is correct, I am throwing it out
> there and anyone who also cares about this type of thing, please
> comment".
>
> A patch that is on "RFC 12" means, "We all have no clue how to do this,
> we give up and hope you all will do it for us."
>
> I almost never comment on RFC patch series, except for portions of the
> kernel that I really care about.  For a brand-new subsystem like this,
> that I still do not understand who needs it, that is not the case.
>
> I'm going to stop reviewing this patch series until you at least follow
> the Intel required rules for sending kernel patches like this out.  To
> not do so would be unfair to your coworkers who _DO_ follow the rules.
>
> > > > - The following coding style changes suggested by Dan will be implemented
> > > >   in the next revision
> > > > -- Replace DLB_CSR_RD() and DLB_CSR_WR() with direct ioread32() and
> > > >    iowrite32() call.
> > > > -- Remove bitmap wrappers and use linux bitmap functions directly.
> > > > -- Use trace_event in configfs attribute file update.
> > >
> > > Why submit a patch series that you know will be changed?  Just do the work, don't ask anyone to review
> > > stuff you know is incorrect, that just wastes our time and ensures that we never want to review it again.
> > >
> > Since this is a RFC, and is not for merging or a full review, we though it was OK to log the pending coding
> > style changes. The patch set was submitted and reviewed by the community before, and there was no
> > complains on using macros like DLB_CSR_RD(), etc, but we think we can replace them for better
> > readability of the code.
>
> Coding style changes should NEVER be ignored and put off for later.
> To do so means you do not care about the brains of anyone who you are
> wanting to read this code.  We have a coding style because of brains and
> pattern matching, not because we are being mean.

Hey Greg,

This is my fault.

To date Mike has been patiently and diligently following my review
feedback to continue to make the driver smaller and more Linux
idiomatic. Primarily this has been ripping and replacing a pile of
object configuration ioctls with configfs. While my confidence in that
review feedback was high, my confidence in the current round of deeper
architecture reworks is lower and they seemed to raise questions that
are likely FAQs with using configfs. Specifically the observation that
configfs, like sysfs, lacks an "atomically update multiple attributes"
capability. To my knowledge that's just the expected tradeoff with
pseudo-fs based configuration and it is up to userspace to coordinate
multiple configuration writers.

The other question is the use of anon_inode_getfd(). To me that
mechanism is reserved for syscall and ioctl based architectures, and
in this case it was only being used as a mechanism to get an automatic
teardown action at process exit. Again, my inclination is that configs
requires userspace to clean up anything it created. If "tear down on
last close" behavior is needed that would either need to come from a
userspace daemon to watch clients, or another character device that
clients could open to represent the active users of the configuration.
My preference is for the former.

I green-lighted the work-in-progress / RFC posting  (with the known
style warts) to get momentum on just those questions. I thought it
better to not polish this driver to a shine and get some mid-rework
feedback. Mike continues to be a pleasure to work with, please take
any frustrations on how this was presented out on me, I'll do better
next time for these types of questions. DLB is unlike anything I have
reviewed previously.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 00/17] dlb: introduce DLB device driver
  2021-12-21 18:44       ` Dan Williams
@ 2021-12-21 19:57         ` Andrew Lunn
  2021-12-22  8:01         ` Christoph Hellwig
  1 sibling, 0 replies; 51+ messages in thread
From: Andrew Lunn @ 2021-12-21 19:57 UTC (permalink / raw)
  To: Dan Williams
  Cc: Greg KH, Chen, Mike Ximing, linux-kernel, arnd,
	pierre-louis.bossart, netdev, davem, kuba, Christoph Hellwig

> Hey Greg,
> 
> This is my fault.
> 
> To date Mike has been patiently and diligently following my review
> feedback to continue to make the driver smaller and more Linux
> idiomatic. Primarily this has been ripping and replacing a pile of
> object configuration ioctls with configfs. While my confidence in that
> review feedback was high, my confidence in the current round of deeper
> architecture reworks is lower and they seemed to raise questions that
> are likely FAQs with using configfs. Specifically the observation that
> configfs, like sysfs, lacks an "atomically update multiple attributes"
> capability. To my knowledge that's just the expected tradeoff with
> pseudo-fs based configuration and it is up to userspace to coordinate
> multiple configuration writers.

Hi Dan

If this is considered a network accelerator, it probably should use
the same configuration mechanisms all of networking uses, netlink. I'm
not aware of anything network related using configfs, but it could
exist. netlink messages should also solve your atomisity problem.

But it does not really help with cleanup when the userspace user goes
away. Is there anything from GPU drivers which can be reused? They
must have some sort of cleanup when the user space DRM driver exits.

     Andrew

^ permalink raw reply	[flat|nested] 51+ messages in thread

* RE: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-21  9:53   ` Andrew Lunn
@ 2021-12-21 20:56     ` Chen, Mike Ximing
  2021-12-21 21:39       ` Andrew Lunn
  0 siblings, 1 reply; 51+ messages in thread
From: Chen, Mike Ximing @ 2021-12-21 20:56 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: linux-kernel, arnd, gregkh, Williams, Dan J,
	pierre-louis.bossart, netdev, davem, kuba



> -----Original Message-----
> From: Andrew Lunn <andrew@lunn.ch>
> Sent: Tuesday, December 21, 2021 4:54 AM
> To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; gregkh@linuxfoundation.org; Williams, Dan J
> <dan.j.williams@intel.com>; pierre-louis.bossart@linux.intel.com; netdev@vger.kernel.org;
> davem@davemloft.net; kuba@kernel.org
> Subject: Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
> 
> > +The following diagram shows a typical packet processing pipeline with the Intel DLB.
> > +
> > +                              WC1              WC4
> > + +-----+   +----+   +---+  /      \  +---+  /      \  +---+   +----+   +-----+
> > + |NIC  |   |Rx  |   |DLB| /        \ |DLB| /        \ |DLB|   |Tx  |   |NIC  |
> > + |Ports|---|Core|---|   |-----WC2----|   |-----WC5----|   |---|Core|---|Ports|
> > + +-----+   -----+   +---+ \        / +---+ \        / +---+   +----+   ------+
> > +                           \      /         \      /
> > +                              WC3              WC6
> 
> This is the only mention of NIC here. Does the application interface to the network stack in the usual way
> to receive packets from the TCP/IP stack up into user space and then copy it back down into the MMIO
> block for it to enter the DLB for the first time? And at the end of the path, does the application copy it
> from the MMIO into a standard socket for TCP/IP processing to be send out the NIC?
> 
For load balancing and distribution purposes, we do not handle packets directly in DLB. Instead, we only
send QEs (queue events) to MMIO for DLB to process. In an network application, QEs (64 bytes each) can
contain pointers to the actual packets. The worker cores can use these pointers to process packets and
forward them to the next stage. At the end of the path, the last work core can send the packets out to NIC.
 
> Do you even needs NICs here? Could the data be coming of a video camera and you are distributing image
> processing over a number of cores?
No, the diagram is just an example for packet processing applications. The data can come from other sources
such video cameras. The DLB can schedule up to 100 million packets/events per seconds. The frame rate from
a single camera is normally much, much lower than that.

> 
> 	 Andrew

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-21 20:56     ` Chen, Mike Ximing
@ 2021-12-21 21:39       ` Andrew Lunn
  2021-12-21 23:05         ` Chen, Mike Ximing
  0 siblings, 1 reply; 51+ messages in thread
From: Andrew Lunn @ 2021-12-21 21:39 UTC (permalink / raw)
  To: Chen, Mike Ximing
  Cc: linux-kernel, arnd, gregkh, Williams, Dan J,
	pierre-louis.bossart, netdev, davem, kuba

On Tue, Dec 21, 2021 at 08:56:42PM +0000, Chen, Mike Ximing wrote:
> 
> 
> > -----Original Message-----
> > From: Andrew Lunn <andrew@lunn.ch>
> > Sent: Tuesday, December 21, 2021 4:54 AM
> > To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> > Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; gregkh@linuxfoundation.org; Williams, Dan J
> > <dan.j.williams@intel.com>; pierre-louis.bossart@linux.intel.com; netdev@vger.kernel.org;
> > davem@davemloft.net; kuba@kernel.org
> > Subject: Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
> > 
> > > +The following diagram shows a typical packet processing pipeline with the Intel DLB.
> > > +
> > > +                              WC1              WC4
> > > + +-----+   +----+   +---+  /      \  +---+  /      \  +---+   +----+   +-----+
> > > + |NIC  |   |Rx  |   |DLB| /        \ |DLB| /        \ |DLB|   |Tx  |   |NIC  |
> > > + |Ports|---|Core|---|   |-----WC2----|   |-----WC5----|   |---|Core|---|Ports|
> > > + +-----+   -----+   +---+ \        / +---+ \        / +---+   +----+   ------+
> > > +                           \      /         \      /
> > > +                              WC3              WC6
> > 
> > This is the only mention of NIC here. Does the application interface to the network stack in the usual way
> > to receive packets from the TCP/IP stack up into user space and then copy it back down into the MMIO
> > block for it to enter the DLB for the first time? And at the end of the path, does the application copy it
> > from the MMIO into a standard socket for TCP/IP processing to be send out the NIC?
> > 
> For load balancing and distribution purposes, we do not handle packets directly in DLB. Instead, we only
> send QEs (queue events) to MMIO for DLB to process. In an network application, QEs (64 bytes each) can
> contain pointers to the actual packets. The worker cores can use these pointers to process packets and
> forward them to the next stage. At the end of the path, the last work core can send the packets out to NIC.

Sorry for asking so many questions, but i'm trying to understand the
architecture. As a network maintainer, and somebody who reviews
network drivers, i was trying to be sure there is not an actual
network MAC and PHY driver hiding in this code.

So you talk about packets. Do you actually mean frames? As in Ethernet
frames? TCP/IP processing has not occurred? Or does this plug into the
network stack at some level? After TCP reassembly has occurred? Are
these pointers to skbufs?

> > Do you even needs NICs here? Could the data be coming of a video camera and you are distributing image
> > processing over a number of cores?
> No, the diagram is just an example for packet processing applications. The data can come from other sources
> such video cameras. The DLB can schedule up to 100 million packets/events per seconds. The frame rate from
> a single camera is normally much, much lower than that.

So i'm trying to understand the scope of this accelerator. Is it just
a network accelerator? If so, are you pointing to skbufs? How are the
lifetimes of skbufs managed? How do you get skbufs out of the NIC? Are
you using XDP?

    Andrew

^ permalink raw reply	[flat|nested] 51+ messages in thread

* RE: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-21 21:39       ` Andrew Lunn
@ 2021-12-21 23:05         ` Chen, Mike Ximing
  2021-12-22 21:26           ` Andrew Lunn
  0 siblings, 1 reply; 51+ messages in thread
From: Chen, Mike Ximing @ 2021-12-21 23:05 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: linux-kernel, arnd, gregkh, Williams, Dan J,
	pierre-louis.bossart, netdev, davem, kuba



> -----Original Message-----
> From: Andrew Lunn <andrew@lunn.ch>
> Sent: Tuesday, December 21, 2021 4:39 PM
> To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; gregkh@linuxfoundation.org; Williams, Dan J
> <dan.j.williams@intel.com>; pierre-louis.bossart@linux.intel.com; netdev@vger.kernel.org;
> davem@davemloft.net; kuba@kernel.org
> Subject: Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
> 
> On Tue, Dec 21, 2021 at 08:56:42PM +0000, Chen, Mike Ximing wrote:
> >
> >
> > > -----Original Message-----
> > > From: Andrew Lunn <andrew@lunn.ch>
> > > Sent: Tuesday, December 21, 2021 4:54 AM
> > > To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> > > Cc: linux-kernel@vger.kernel.org; arnd@arndb.de;
> > > gregkh@linuxfoundation.org; Williams, Dan J
> > > <dan.j.williams@intel.com>; pierre-louis.bossart@linux.intel.com;
> > > netdev@vger.kernel.org; davem@davemloft.net; kuba@kernel.org
> > > Subject: Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
> > >
> > > > +The following diagram shows a typical packet processing pipeline with the Intel DLB.
> > > > +
> > > > +                              WC1              WC4
> > > > + +-----+   +----+   +---+  /      \  +---+  /      \  +---+   +----+   +-----+
> > > > + |NIC  |   |Rx  |   |DLB| /        \ |DLB| /        \ |DLB|   |Tx  |   |NIC  |
> > > > + |Ports|---|Core|---|   |-----WC2----|   |-----WC5----|   |---|Core|---|Ports|
> > > > + +-----+   -----+   +---+ \        / +---+ \        / +---+   +----+   ------+
> > > > +                           \      /         \      /
> > > > +                              WC3              WC6
> > >
> > > This is the only mention of NIC here. Does the application interface
> > > to the network stack in the usual way to receive packets from the
> > > TCP/IP stack up into user space and then copy it back down into the
> > > MMIO block for it to enter the DLB for the first time? And at the end of the path, does the application
> copy it from the MMIO into a standard socket for TCP/IP processing to be send out the NIC?
> > >
> > For load balancing and distribution purposes, we do not handle packets
> > directly in DLB. Instead, we only send QEs (queue events) to MMIO for
> > DLB to process. In an network application, QEs (64 bytes each) can
> > contain pointers to the actual packets. The worker cores can use these pointers to process packets and
> forward them to the next stage. At the end of the path, the last work core can send the packets out to NIC.
> 
> Sorry for asking so many questions, but i'm trying to understand the architecture. As a network maintainer,
> and somebody who reviews network drivers, i was trying to be sure there is not an actual network MAC
> and PHY driver hiding in this code.
> 
> So you talk about packets. Do you actually mean frames? As in Ethernet frames? TCP/IP processing has not
> occurred? Or does this plug into the network stack at some level? After TCP reassembly has occurred? Are
> these pointers to skbufs?
> 
There is no network MAC or PHY driver in the code. Actually DLB and the driver does not have any direct access to
the network ports/sockets. In the above diagram, the Rx/Tx CPU core receives/transmits packet (or frames)
from/to the NIC. These can be either L2 or L3 packets/frames. The Rx CPU core sends corresponding QEs with
proper meta data (such as pointers to packets/frames) to DLB, which distributes QEs to a set of worker cores.
the worker cores receive QEs, process the corresponding packets/frames, and send QEs back to DLB for
the next stage processing. After several stages of processing, the worker cores in the last stage send the QEs
to Tx core, which then transmits the packets/frames to NIC ports. So between the Rx core and Tx core is where
DLB and the driver operates. The DLB operation itself does not involve any network access.

I am not very familiar with skbufs, but they sound like queue buffers in the kernel. Most of the DLB applications
are in user space. So these pointers can be for any buffers that an application uses. DLB does not process any
packets/frames, it distributes QEs to worker cores which process the corresponding packets/frames.

> > > Do you even needs NICs here? Could the data be coming of a video
> > > camera and you are distributing image processing over a number of cores?
> > No, the diagram is just an example for packet processing applications.
> > The data can come from other sources such video cameras. The DLB can
> > schedule up to 100 million packets/events per seconds. The frame rate from a single camera is normally
> much, much lower than that.
> 
> So i'm trying to understand the scope of this accelerator. Is it just a network accelerator? If so, are you
> pointing to skbufs? How are the lifetimes of skbufs managed? How do you get skbufs out of the NIC? Are
> you using XDP?

This is not a network accelerator in the sense that it does not have direct access to the network sockets/ports. We do not use XDP.
What it does is to effectively distribute workloads (such as packet processing) among CPU cores and therefore
increases the total packet/frame processing throughput of the CPU processors (such as Intel's Xeon processors).
Imagine, for example, that the Rx core receives 1000 packets/frames in a burst with random payloads, how to
distribute the packet processing to (say) 16 CPU cores is the job of the DLB hardware. The driver is responsible
for the resource management, system configuration and reset, multiple user/application support, and virtualization
enablement.

Thanks
Mike


^ permalink raw reply	[flat|nested] 51+ messages in thread

* RE: [RFC PATCH v12 17/17] dlb: add basic sysfs interfaces
  2021-12-21  7:20   ` Joe Perches
@ 2021-12-21 23:18     ` Chen, Mike Ximing
  0 siblings, 0 replies; 51+ messages in thread
From: Chen, Mike Ximing @ 2021-12-21 23:18 UTC (permalink / raw)
  To: Joe Perches, linux-kernel
  Cc: arnd, gregkh, Williams, Dan J, pierre-louis.bossart, netdev, davem, kuba


> -----Original Message-----
> From: Joe Perches <joe@perches.com>
> Sent: Tuesday, December 21, 2021 2:20 AM
> To: Chen, Mike Ximing <mike.ximing.chen@intel.com>; linux-kernel@vger.kernel.org
> Cc: arnd@arndb.de; gregkh@linuxfoundation.org; Williams, Dan J <dan.j.williams@intel.com>; pierre-
> louis.bossart@linux.intel.com; netdev@vger.kernel.org; davem@davemloft.net; kuba@kernel.org
> Subject: Re: [RFC PATCH v12 17/17] dlb: add basic sysfs interfaces
> 
> On Tue, 2021-12-21 at 00:50 -0600, Mike Ximing Chen wrote:
> > The dlb sysfs interfaces include files for reading the total and
> > available device resources, and reading the device ID and version. The
> > interfaces are used for device level configurations and resource
> > inquiries.
> []
> > diff --git a/drivers/misc/dlb/dlb_args.h b/drivers/misc/dlb/dlb_args.h
> []
> > @@ -58,6 +58,40 @@ struct dlb_create_sched_domain_args {
> >  	__u32 num_dir_credits;
> >  };
> >
> > +/*
> > + * dlb_get_num_resources_args: Used to get the number of available resources
> > + *      (queues, ports, etc.) that this device owns.
> > + *
> > + * Output parameters:
> > + * @response.status: Detailed error code. In certain cases, such as if the
> > + *	request arg is invalid, the driver won't set status.
> > + * @num_domains: Number of available scheduling domains.
> > + * @num_ldb_queues: Number of available load-balanced queues.
> > + * @num_ldb_ports: Total number of available load-balanced ports.
> > + * @num_dir_ports: Number of available directed ports. There is one directed
> > + *	queue for every directed port.
> > + * @num_atomic_inflights: Amount of available temporary atomic QE storage.
> > + * @num_hist_list_entries: Amount of history list storage.
> > + * @max_contiguous_hist_list_entries: History list storage is allocated in
> > + *	a contiguous chunk, and this return value is the longest available
> > + *	contiguous range of history list entries.
> > + * @num_ldb_credits: Amount of available load-balanced QE storage.
> > + * @num_dir_credits: Amount of available directed QE storage.
> > + */
> 
> Is this supposed to be kernel-doc format with /** as the comment initiator ?
> 
Yes. Thanks

> > +struct dlb_get_num_resources_args {
> > +	/* Output parameters */
> > +	struct dlb_cmd_response response;
> > +	__u32 num_sched_domains;
> > +	__u32 num_ldb_queues;
> > +	__u32 num_ldb_ports;
> > +	__u32 num_dir_ports;
> > +	__u32 num_atomic_inflights;
> > +	__u32 num_hist_list_entries;
> > +	__u32 max_contiguous_hist_list_entries;
> > +	__u32 num_ldb_credits;
> > +	__u32 num_dir_credits;
> 
> __u32 is used when visible to user-space.
> Do these really need to use __u32 and not u32 ?
> 
Will change to u32.

> > diff --git a/drivers/misc/dlb/dlb_pf_ops.c
> > b/drivers/misc/dlb/dlb_pf_ops.c
> []
> > @@ -102,3 +102,198 @@ void dlb_pf_init_hardware(struct dlb *dlb)
> []
> > +#define DLB_TOTAL_SYSFS_SHOW(name, macro)		\
> > +static ssize_t total_##name##_show(			\
> > +	struct device *dev,				\
> > +	struct device_attribute *attr,			\
> > +	char *buf)					\
> > +{							\
> > +	int val = DLB_MAX_NUM_##macro;			\
> > +							\
> > +	return scnprintf(buf, PAGE_SIZE, "%d\n", val);	\
> 
> Use sysfs_emit rather than scnprintf
> 
> maybe:
> 	return sysfs_emit(buf, "%u\n", DLB_MAX_NUM_##macro);
> 
Yes. Thanks for the suggestion.

> > +#define DLB_AVAIL_SYSFS_SHOW(name)			     \
> > +static ssize_t avail_##name##_show(			     \
> > +	struct device *dev,				     \
> > +	struct device_attribute *attr,			     \
> > +	char *buf)					     \
> > +{							     \
> > +	struct dlb *dlb = dev_get_drvdata(dev);		     \
> > +	struct dlb_get_num_resources_args arg;		     \
> > +	struct dlb_hw *hw = &dlb->hw;			     \
> > +	int val;					     \
> 
> u32 val?
> 
It should be int. dlb_hw_get_num_resources(() returns int.

> > +							     \
> > +	mutex_lock(&dlb->resource_mutex);		     \
> > +							     \
> > +	val = dlb_hw_get_num_resources(hw, &arg);	     \
> > +							     \
> > +	mutex_unlock(&dlb->resource_mutex);		     \
> > +							     \
> > +	if (val)					     \
> > +		return -1;				     \
> > +							     \
> > +	val = arg.name;					     \
> > +							     \
> > +	return scnprintf(buf, PAGE_SIZE, "%d\n", val);	     \
> 
> sysfs_emit, etc...
> 


^ permalink raw reply	[flat|nested] 51+ messages in thread

* RE: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-21  7:00   ` Joe Perches
@ 2021-12-21 23:22     ` Chen, Mike Ximing
  2021-12-22  2:02       ` Joe Perches
  0 siblings, 1 reply; 51+ messages in thread
From: Chen, Mike Ximing @ 2021-12-21 23:22 UTC (permalink / raw)
  To: Joe Perches, linux-kernel
  Cc: arnd, gregkh, Williams, Dan J, pierre-louis.bossart, netdev, davem, kuba



> -----Original Message-----
> From: Joe Perches <joe@perches.com>
> Sent: Tuesday, December 21, 2021 2:00 AM
> To: Chen, Mike Ximing <mike.ximing.chen@intel.com>; linux-kernel@vger.kernel.org
> Cc: arnd@arndb.de; gregkh@linuxfoundation.org; Williams, Dan J <dan.j.williams@intel.com>; pierre-
> louis.bossart@linux.intel.com; netdev@vger.kernel.org; davem@davemloft.net; kuba@kernel.org
> Subject: Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
> 
> On Tue, 2021-12-21 at 00:50 -0600, Mike Ximing Chen wrote:
> > Add a DLB entry to the MAINTAINERS file.
> 
> btw: Nice documentation
> 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> []
> > @@ -9335,6 +9335,13 @@ L:	linux-kernel@vger.kernel.org
> >  S:	Supported
> >  F:	arch/x86/include/asm/intel-family.h
> >
> > +INTEL DYNAMIC LOAD BALANCER DRIVER
> > +M:	Mike Ximing Chen <mike.ximing.chen@intel.com>
> > +S:	Maintained
> > +F:	Documentation/ABI/testing/sysfs-driver-dlb
> > +F:	drivers/misc/dlb/
> > +F:	include/uapi/linux/dlb.h
> > +
> >  INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
> >  M:	Jani Nikula <jani.nikula@linux.intel.com>
> >  M:	Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> 
> Section is not in the appropriate alphabetic order.
> 
> dynamic should be after drm
> 
Thanks. Will fix.

> > diff --git a/drivers/misc/dlb/dlb_main.c b/drivers/misc/dlb/dlb_main.c
> []
> > +// SPDX-License-Identifier: GPL-2.0-only
> []
> > +MODULE_LICENSE("GPL v2");
> 
> Should use "GPL" not "GPL v2".
> 
> https://lore.kernel.org/lkml/alpine.DEB.2.21.1901282105450.1669@nanos.tec.linutronix.de/
> 
We support v2 only.

*      "GPL"                           [GNU Public License v2 or later]
 *      "GPL v2"                        [GNU Public License v2]

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 17/17] dlb: add basic sysfs interfaces
  2021-12-21  6:50 ` [RFC PATCH v12 17/17] dlb: add basic sysfs interfaces Mike Ximing Chen
  2021-12-21  7:20   ` Joe Perches
  2021-12-21  8:56   ` Greg KH
@ 2021-12-21 23:34   ` Stephen Hemminger
  2021-12-22  4:21     ` Chen, Mike Ximing
  2 siblings, 1 reply; 51+ messages in thread
From: Stephen Hemminger @ 2021-12-21 23:34 UTC (permalink / raw)
  To: Mike Ximing Chen
  Cc: linux-kernel, arnd, gregkh, dan.j.williams, pierre-louis.bossart,
	netdev, davem, kuba

On Tue, 21 Dec 2021 00:50:47 -0600
Mike Ximing Chen <mike.ximing.chen@intel.com> wrote:

> The dlb sysfs interfaces include files for reading the total and
> available device resources, and reading the device ID and version. The
> interfaces are used for device level configurations and resource
> inquiries.
> 
> Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
> ---
>  Documentation/ABI/testing/sysfs-driver-dlb | 116 ++++++++++++
>  drivers/misc/dlb/dlb_args.h                |  34 ++++
>  drivers/misc/dlb/dlb_main.c                |   5 +
>  drivers/misc/dlb/dlb_main.h                |   3 +
>  drivers/misc/dlb/dlb_pf_ops.c              | 195 +++++++++++++++++++++
>  drivers/misc/dlb/dlb_resource.c            |  50 ++++++
>  6 files changed, 403 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-driver-dlb
> 
> diff --git a/Documentation/ABI/testing/sysfs-driver-dlb b/Documentation/ABI/testing/sysfs-driver-dlb
> new file mode 100644
> index 000000000000..bf09ef6f8a3a
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-driver-dlb
> @@ -0,0 +1,116 @@
> +What:		/sys/bus/pci/devices/.../total_resources/num_atomic_inflights
> +What:		/sys/bus/pci/devices/.../total_resources/num_dir_credits
> +What:		/sys/bus/pci/devices/.../total_resources/num_dir_ports
> +What:		/sys/bus/pci/devices/.../total_resources/num_hist_list_entries
> +What:		/sys/bus/pci/devices/.../total_resources/num_ldb_credits
> +What:		/sys/bus/pci/devices/.../total_resources/num_ldb_ports
> +What:		/sys/bus/pci/devices/.../total_resources/num_cos0_ldb_ports
> +What:		/sys/bus/pci/devices/.../total_resources/num_cos1_ldb_ports
> +What:		/sys/bus/pci/devices/.../total_resources/num_cos2_ldb_ports
> +What:		/sys/bus/pci/devices/.../total_resources/num_cos3_ldb_ports
> +What:		/sys/bus/pci/devices/.../total_resources/num_ldb_queues
> +What:		/sys/bus/pci/devices/.../total_resources/num_sched_domains
> +Date:		Oct 15, 2021
> +KernelVersion:	5.15
> +Contact:	mike.ximing.chen@intel.com
> +Description:
> +		The total_resources subdirectory contains read-only files that
> +		indicate the total number of resources in the device.
> +
> +		num_atomic_inflights:  Total number of atomic inflights in the
> +				       device. Atomic inflights refers to the
> +				       on-device storage used by the atomic
> +				       scheduler.
> +
> +		num_dir_credits:       Total number of directed credits in the
> +				       device.
> +
> +		num_dir_ports:	       Total number of directed ports (and
> +				       queues) in the device.
> +
> +		num_hist_list_entries: Total number of history list entries in
> +				       the device.
> +
> +		num_ldb_credits:       Total number of load-balanced credits in
> +				       the device.
> +
> +		num_ldb_ports:	       Total number of load-balanced ports in
> +				       the device.
> +
> +		num_cos<M>_ldb_ports:  Total number of load-balanced ports
> +				       belonging to class-of-service M in the
> +				       device.
> +
> +		num_ldb_queues:	       Total number of load-balanced queues in
> +				       the device.
> +
> +		num_sched_domains:     Total number of scheduling domains in the
> +				       device.
> +

Sysfs is only slightly better than /proc as an API.
If it is just for testing than debugfs might be better.

Could this be done with a real netlink interface?
Maybe as part of devlink?


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-21 23:22     ` Chen, Mike Ximing
@ 2021-12-22  2:02       ` Joe Perches
  0 siblings, 0 replies; 51+ messages in thread
From: Joe Perches @ 2021-12-22  2:02 UTC (permalink / raw)
  To: Chen, Mike Ximing, linux-kernel
  Cc: arnd, gregkh, Williams, Dan J, pierre-louis.bossart, netdev, davem, kuba

On Tue, 2021-12-21 at 23:22 +0000, Chen, Mike Ximing wrote:
> > From: Joe Perches <joe@perches.com>
[]
> > > diff --git a/drivers/misc/dlb/dlb_main.c b/drivers/misc/dlb/dlb_main.c
> > []
> > > +// SPDX-License-Identifier: GPL-2.0-only
> > []
> > > +MODULE_LICENSE("GPL v2");
> > 
> > Should use "GPL" not "GPL v2".
> > 
> > https://lore.kernel.org/lkml/alpine.DEB.2.21.1901282105450.1669@nanos.tec.linutronix.de/
> > 
> We support v2 only.

This is specific to the MODULE_LICENSE use.

I think you should read the link above.



^ permalink raw reply	[flat|nested] 51+ messages in thread

* RE: [RFC PATCH v12 17/17] dlb: add basic sysfs interfaces
  2021-12-21 23:34   ` Stephen Hemminger
@ 2021-12-22  4:21     ` Chen, Mike Ximing
  0 siblings, 0 replies; 51+ messages in thread
From: Chen, Mike Ximing @ 2021-12-22  4:21 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: linux-kernel, arnd, gregkh, Williams, Dan J,
	pierre-louis.bossart, netdev, davem, kuba



> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org>
> Sent: Tuesday, December 21, 2021 6:35 PM
> To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; gregkh@linuxfoundation.org; Williams, Dan J
> <dan.j.williams@intel.com>; pierre-louis.bossart@linux.intel.com; netdev@vger.kernel.org;
> davem@davemloft.net; kuba@kernel.org
> Subject: Re: [RFC PATCH v12 17/17] dlb: add basic sysfs interfaces
> 
> On Tue, 21 Dec 2021 00:50:47 -0600
> Mike Ximing Chen <mike.ximing.chen@intel.com> wrote:
> 
> > The dlb sysfs interfaces include files for reading the total and
> > available device resources, and reading the device ID and version. The
> > interfaces are used for device level configurations and resource
> > inquiries.
> >
> > Signed-off-by: Mike Ximing Chen <mike.ximing.chen@intel.com>
> > ---
> >  Documentation/ABI/testing/sysfs-driver-dlb | 116 ++++++++++++
> >  drivers/misc/dlb/dlb_args.h                |  34 ++++
> >  drivers/misc/dlb/dlb_main.c                |   5 +
> >  drivers/misc/dlb/dlb_main.h                |   3 +
> >  drivers/misc/dlb/dlb_pf_ops.c              | 195 +++++++++++++++++++++
> >  drivers/misc/dlb/dlb_resource.c            |  50 ++++++
> >  6 files changed, 403 insertions(+)
> >  create mode 100644 Documentation/ABI/testing/sysfs-driver-dlb
> >
> > diff --git a/Documentation/ABI/testing/sysfs-driver-dlb
> > b/Documentation/ABI/testing/sysfs-driver-dlb
> > new file mode 100644
> > index 000000000000..bf09ef6f8a3a
> > --- /dev/null
> > +++ b/Documentation/ABI/testing/sysfs-driver-dlb
> > @@ -0,0 +1,116 @@
> > +What:		/sys/bus/pci/devices/.../total_resources/num_atomic_inflights
> > +What:		/sys/bus/pci/devices/.../total_resources/num_dir_credits
> > +What:		/sys/bus/pci/devices/.../total_resources/num_dir_ports
> > +What:		/sys/bus/pci/devices/.../total_resources/num_hist_list_entries
> > +What:		/sys/bus/pci/devices/.../total_resources/num_ldb_credits
> > +What:		/sys/bus/pci/devices/.../total_resources/num_ldb_ports
> > +What:		/sys/bus/pci/devices/.../total_resources/num_cos0_ldb_ports
> > +What:		/sys/bus/pci/devices/.../total_resources/num_cos1_ldb_ports
> > +What:		/sys/bus/pci/devices/.../total_resources/num_cos2_ldb_ports
> > +What:		/sys/bus/pci/devices/.../total_resources/num_cos3_ldb_ports
> > +What:		/sys/bus/pci/devices/.../total_resources/num_ldb_queues
> > +What:		/sys/bus/pci/devices/.../total_resources/num_sched_domains
> > +Date:		Oct 15, 2021
> > +KernelVersion:	5.15
> > +Contact:	mike.ximing.chen@intel.com
> > +Description:
> > +		The total_resources subdirectory contains read-only files that
> > +		indicate the total number of resources in the device.
> > +
> > +		num_atomic_inflights:  Total number of atomic inflights in the
> > +				       device. Atomic inflights refers to the
> > +				       on-device storage used by the atomic
> > +				       scheduler.
> > +
> > +		num_dir_credits:       Total number of directed credits in the
> > +				       device.
> > +
> > +		num_dir_ports:	       Total number of directed ports (and
> > +				       queues) in the device.
> > +
> > +		num_hist_list_entries: Total number of history list entries in
> > +				       the device.
> > +
> > +		num_ldb_credits:       Total number of load-balanced credits in
> > +				       the device.
> > +
> > +		num_ldb_ports:	       Total number of load-balanced ports in
> > +				       the device.
> > +
> > +		num_cos<M>_ldb_ports:  Total number of load-balanced ports
> > +				       belonging to class-of-service M in the
> > +				       device.
> > +
> > +		num_ldb_queues:	       Total number of load-balanced queues in
> > +				       the device.
> > +
> > +		num_sched_domains:     Total number of scheduling domains in the
> > +				       device.
> > +
> 
> Sysfs is only slightly better than /proc as an API.
> If it is just for testing than debugfs might be better.
> 
Sysfs in our driver is not only for testing. It is used for the system configuration
at run time.

> Could this be done with a real netlink interface?
> Maybe as part of devlink?
Thanks for the suggestion. I will look into some sample implementations of
devlink/netlink. Our current plan is to stay with the configfs interface, and
find ways to resolve issues related to atomic update and resource reset at
tear-down time.

Mike 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* RE: [RFC PATCH v12 00/17] dlb: introduce DLB device driver
  2021-12-21  9:40 ` Andrew Lunn
@ 2021-12-22  4:37   ` Chen, Mike Ximing
  0 siblings, 0 replies; 51+ messages in thread
From: Chen, Mike Ximing @ 2021-12-22  4:37 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: linux-kernel, arnd, gregkh, Williams, Dan J,
	pierre-louis.bossart, netdev, davem, kuba



> -----Original Message-----
> From: Andrew Lunn <andrew@lunn.ch>
> Sent: Tuesday, December 21, 2021 4:41 AM
> To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; gregkh@linuxfoundation.org; Williams, Dan J
> <dan.j.williams@intel.com>; pierre-louis.bossart@linux.intel.com; netdev@vger.kernel.org;
> davem@davemloft.net; kuba@kernel.org
> Subject: Re: [RFC PATCH v12 00/17] dlb: introduce DLB device driver
> 
> > 1. Before a scheduling domain is created/enabled, a set of parameters
> > are passed to the kernel driver via configfs attribute files in an
> > configfs domain directory (say $domain) created by user. Each
> > attribute file corresponds to a configuration parameter of the domain.
> > After writing to all the attribute files, user writes 1 to "create"
> > attribute, which triggers an action (i.e., domain creation) in the
> > kernel driver. Since multiple processes/users can access the $domain
> > directory, multiple users can write to the attribute files at the same
> > time.  How do we guarantee an atomic update/configuration of a domain?
> > In other words, if user A wants to set attributes 1 and 2, how can we
> > prevent user B from changing attribute 1 and 2 before user A writes 1
> > to "create"? A configfs directory with individual attribute files
> > seems to not be able to provide atomic configuration in this case. One
> > option to solve this issue could be write a structured data (with a
> > set of parameters) to a single attribute file. This would guarantee the atomic configuration, but may not
> be a conventional configfs operation.
> 
> How about throw away configfs and use netlink? Messages are atomic, and you can add an arbitrary
> number of attributes to a single netlink message. It will also make your code more network like, since
> nothing else in the network stack uses configfs, as far as i know.
> 
Hi Andrew,
As I explained in my other response, DLB is not a network accelerator and DLB
driver is not a part of network stack. We would obviously prefer to resolve the
atomic update and resource reset at tear-down Issues within the configfs
framework if possible. But I will take a look at the netlink implementations.

Thanks for the suggestion
Mike

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 00/17] dlb: introduce DLB device driver
  2021-12-21 18:44       ` Dan Williams
  2021-12-21 19:57         ` Andrew Lunn
@ 2021-12-22  8:01         ` Christoph Hellwig
  1 sibling, 0 replies; 51+ messages in thread
From: Christoph Hellwig @ 2021-12-22  8:01 UTC (permalink / raw)
  To: Dan Williams
  Cc: Greg KH, Chen, Mike Ximing, linux-kernel, arnd,
	pierre-louis.bossart, netdev, davem, kuba, Christoph Hellwig

On Tue, Dec 21, 2021 at 10:44:11AM -0800, Dan Williams wrote:
> are likely FAQs with using configfs. Specifically the observation that
> configfs, like sysfs, lacks an "atomically update multiple attributes"
> capability. To my knowledge that's just the expected tradeoff with
> pseudo-fs based configuration and it is up to userspace to coordinate
> multiple configuration writers.

Yes.  For the SCSI and nvme targets we do a required attributes must
be set before something can be enabled, but that might not work
everywhere.

> The other question is the use of anon_inode_getfd(). To me that
> mechanism is reserved for syscall and ioctl based architectures, and

It is.

> in this case it was only being used as a mechanism to get an automatic
> teardown action at process exit. Again, my inclination is that configs
> requires userspace to clean up anything it created. If "tear down on
> last close" behavior is needed that would either need to come from a
> userspace daemon to watch clients, or another character device that
> clients could open to represent the active users of the configuration.
> My preference is for the former.

This really sounds like configfs is the wrong interface.  But I'd have
to find time to see what dlb actually is before commenting on what might
be a better interface.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-21 23:05         ` Chen, Mike Ximing
@ 2021-12-22 21:26           ` Andrew Lunn
  2021-12-23  5:15             ` Chen, Mike Ximing
       [not found]             ` <20211222194746.3480dea8@hermes.local>
  0 siblings, 2 replies; 51+ messages in thread
From: Andrew Lunn @ 2021-12-22 21:26 UTC (permalink / raw)
  To: Chen, Mike Ximing
  Cc: linux-kernel, arnd, gregkh, Williams, Dan J,
	pierre-louis.bossart, netdev, davem, kuba

> > pointing to skbufs? How are the lifetimes of skbufs managed? How do you get skbufs out of the NIC? Are
> > you using XDP?
> 
> This is not a network accelerator in the sense that it does not have
> direct access to the network sockets/ports. We do not use XDP.

So not using XDP is a problem. I looked at previous versions of this
patch, and it is all DPDK. But DPDK is not in mainline, XDP is. In
order for this to be merged into mainline you need a mainline user of
it.

Maybe you should abandon mainline, and just get this driver merged
into the DPDK fork of Linux?

     Andrew

^ permalink raw reply	[flat|nested] 51+ messages in thread

* RE: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-22 21:26           ` Andrew Lunn
@ 2021-12-23  5:15             ` Chen, Mike Ximing
  2021-12-23 10:22               ` Andrew Lunn
       [not found]             ` <20211222194746.3480dea8@hermes.local>
  1 sibling, 1 reply; 51+ messages in thread
From: Chen, Mike Ximing @ 2021-12-23  5:15 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: linux-kernel, arnd, gregkh, Williams, Dan J,
	pierre-louis.bossart, netdev, davem, kuba



> -----Original Message-----
> From: Andrew Lunn <andrew@lunn.ch>
> Sent: Wednesday, December 22, 2021 4:27 PM
> To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; gregkh@linuxfoundation.org; Williams, Dan J
> <dan.j.williams@intel.com>; pierre-louis.bossart@linux.intel.com; netdev@vger.kernel.org;
> davem@davemloft.net; kuba@kernel.org
> Subject: Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
> 
> > > pointing to skbufs? How are the lifetimes of skbufs managed? How do
> > > you get skbufs out of the NIC? Are you using XDP?
> >
> > This is not a network accelerator in the sense that it does not have
> > direct access to the network sockets/ports. We do not use XDP.
> 
> So not using XDP is a problem. I looked at previous versions of this patch, and it is all DPDK. But DPDK is
> not in mainline, XDP is. In order for this to be merged into mainline you need a mainline user of it.
> 
> Maybe you should abandon mainline, and just get this driver merged into the DPDK fork of Linux?
> 
Hi Andrew,

I am not sure why not using XDP is a problem. As mentioned earlier, the
DLB driver is not a part of network stack.  

DPDK is one of applications that can make a good use of DLB, but is not the
only one. We have applications that access DLB directly via the kernel driver API
without using DPDK. Even in a DPDK application, the only part that involves
DLB is the eventdev poll mod driver module, in which we can replace a
traditional software base queue manager with DLB. The network access and
receiving/transmitting data from/to NIC is, on the other hand, handled by
the ethdev in DPDK. The eventdev (and DLB) distributes packet processing
over multiple worker cores.

Thanks
Mike

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
       [not found]             ` <20211222194746.3480dea8@hermes.local>
@ 2021-12-23  5:39               ` Dan Williams
  0 siblings, 0 replies; 51+ messages in thread
From: Dan Williams @ 2021-12-23  5:39 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Andrew Lunn, Chen, Mike Ximing, linux-kernel, arnd,
	pierre-louis.bossart@linux.intel.com
	<pierre-louis.bossart@linux.intel.com>,
	netdev@vger.kernel.org <netdev@vger.kernel.org>,
	davem@davemloft.net <davem@davemloft.net>,
	kuba@kernel.org

On Wed, Dec 22, 2021 at 7:48 PM Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
> On Wed, 22 Dec 2021 22:26:38 +0100
> Andrew Lunn <andrew@lunn.ch> wrote:
>
> > > > pointing to skbufs? How are the lifetimes of skbufs managed? How do you get skbufs out of the NIC? Are
> > > > you using XDP?
> > >
> > > This is not a network accelerator in the sense that it does not have
> > > direct access to the network sockets/ports. We do not use XDP.
> >
> > So not using XDP is a problem. I looked at previous versions of this
> > patch, and it is all DPDK. But DPDK is not in mainline, XDP is. In
> > order for this to be merged into mainline you need a mainline user of
> > it.
> >
> > Maybe you should abandon mainline, and just get this driver merged
> > into the DPDK fork of Linux?
>
> DPDK is all userspace and runs on stock kernels from Debian, Redhat, SUSE, ...
> There is no special fork for DPDK.

Appreciate the help Stephen. Netlink and taking this through
drivers/net/, where there are other folks that care about DPDK, seems
a better fit than drivers/misc/. I'll huddle with Mike after the
holidays.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-23  5:15             ` Chen, Mike Ximing
@ 2021-12-23 10:22               ` Andrew Lunn
  2021-12-27  0:40                 ` Chen, Mike Ximing
  0 siblings, 1 reply; 51+ messages in thread
From: Andrew Lunn @ 2021-12-23 10:22 UTC (permalink / raw)
  To: Chen, Mike Ximing
  Cc: linux-kernel, arnd, gregkh, Williams, Dan J,
	pierre-louis.bossart, netdev, davem, kuba

On Thu, Dec 23, 2021 at 05:15:34AM +0000, Chen, Mike Ximing wrote:
> 
> 
> > -----Original Message-----
> > From: Andrew Lunn <andrew@lunn.ch>
> > Sent: Wednesday, December 22, 2021 4:27 PM
> > To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> > Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; gregkh@linuxfoundation.org; Williams, Dan J
> > <dan.j.williams@intel.com>; pierre-louis.bossart@linux.intel.com; netdev@vger.kernel.org;
> > davem@davemloft.net; kuba@kernel.org
> > Subject: Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
> > 
> > > > pointing to skbufs? How are the lifetimes of skbufs managed? How do
> > > > you get skbufs out of the NIC? Are you using XDP?
> > >
> > > This is not a network accelerator in the sense that it does not have
> > > direct access to the network sockets/ports. We do not use XDP.
> > 
> > So not using XDP is a problem. I looked at previous versions of this patch, and it is all DPDK. But DPDK is
> > not in mainline, XDP is. In order for this to be merged into mainline you need a mainline user of it.
> > 
> > Maybe you should abandon mainline, and just get this driver merged into the DPDK fork of Linux?
> > 
> Hi Andrew,
> 
> I am not sure why not using XDP is a problem. As mentioned earlier, the
> DLB driver is not a part of network stack.  
> 
> DPDK is one of applications that can make a good use of DLB, but is not the
> only one. We have applications that access DLB directly via the kernel driver API
> without using DPDK.

Cool. Please can you point at a repo for the code? As i said, we just
need a userspace user, which gives us a good idea how the hardware is
supposed to be used, how the kAPI is to be used, and act as a good
test case for when kernel modifications are made. But it needs to be
pure mainline.

There have been a few good discussion on LWN about accelerators
recently. Worth reading.

	  Andrew

^ permalink raw reply	[flat|nested] 51+ messages in thread

* RE: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
  2021-12-23 10:22               ` Andrew Lunn
@ 2021-12-27  0:40                 ` Chen, Mike Ximing
  0 siblings, 0 replies; 51+ messages in thread
From: Chen, Mike Ximing @ 2021-12-27  0:40 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: linux-kernel, arnd, gregkh, Williams, Dan J,
	pierre-louis.bossart, netdev, davem, kuba


> -----Original Message-----
> From: Andrew Lunn <andrew@lunn.ch>
> Sent: Thursday, December 23, 2021 5:23 AM
> To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> Cc: linux-kernel@vger.kernel.org; arnd@arndb.de; gregkh@linuxfoundation.org; Williams, Dan J
> <dan.j.williams@intel.com>; pierre-louis.bossart@linux.intel.com; netdev@vger.kernel.org;
> davem@davemloft.net; kuba@kernel.org
> Subject: Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
> 
> On Thu, Dec 23, 2021 at 05:15:34AM +0000, Chen, Mike Ximing wrote:
> >
> >
> > > -----Original Message-----
> > > From: Andrew Lunn <andrew@lunn.ch>
> > > Sent: Wednesday, December 22, 2021 4:27 PM
> > > To: Chen, Mike Ximing <mike.ximing.chen@intel.com>
> > > Cc: linux-kernel@vger.kernel.org; arnd@arndb.de;
> > > gregkh@linuxfoundation.org; Williams, Dan J
> > > <dan.j.williams@intel.com>; pierre-louis.bossart@linux.intel.com;
> > > netdev@vger.kernel.org; davem@davemloft.net; kuba@kernel.org
> > > Subject: Re: [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver
> > >
> > > > > pointing to skbufs? How are the lifetimes of skbufs managed? How
> > > > > do you get skbufs out of the NIC? Are you using XDP?
> > > >
> > > > This is not a network accelerator in the sense that it does not
> > > > have direct access to the network sockets/ports. We do not use XDP.
> > >
> > > So not using XDP is a problem. I looked at previous versions of this
> > > patch, and it is all DPDK. But DPDK is not in mainline, XDP is. In order for this to be merged into
> mainline you need a mainline user of it.
> > >
> > > Maybe you should abandon mainline, and just get this driver merged into the DPDK fork of Linux?
> > >
> > Hi Andrew,
> >
> > I am not sure why not using XDP is a problem. As mentioned earlier,
> > the DLB driver is not a part of network stack.
> >
> > DPDK is one of applications that can make a good use of DLB, but is
> > not the only one. We have applications that access DLB directly via
> > the kernel driver API without using DPDK.
> 
> Cool. Please can you point at a repo for the code? As i said, we just need a userspace user, which gives us
> a good idea how the hardware is supposed to be used, how the kAPI is to be used, and act as a good test
> case for when kernel modifications are made. But it needs to be pure mainline.
> 
> There have been a few good discussion on LWN about accelerators recently. Worth reading.
> 
We don't have a public repo for dlb yet, but you can download the dlb 
software package at https://www.intel.com/content/www/us/en/download/686372/intel-dynamic-load-balancer.html.
It includes dlb kernel driver and sample user applications (for both
DPDK and non-DPDK users).

I will check out the discussion on LWN.
Thanks for the suggestion.

Mike

^ permalink raw reply	[flat|nested] 51+ messages in thread

end of thread, other threads:[~2021-12-27  0:45 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-21  6:50 [RFC PATCH v12 00/17] dlb: introduce DLB device driver Mike Ximing Chen
2021-12-21  6:50 ` [RFC PATCH v12 01/17] dlb: add skeleton for DLB driver Mike Ximing Chen
2021-12-21  7:00   ` Joe Perches
2021-12-21 23:22     ` Chen, Mike Ximing
2021-12-22  2:02       ` Joe Perches
2021-12-21  7:12   ` Greg KH
2021-12-21  8:57     ` Greg KH
2021-12-21 14:25       ` Chen, Mike Ximing
2021-12-21 14:42         ` Chen, Mike Ximing
2021-12-21 15:02           ` Greg KH
2021-12-21 14:05     ` Chen, Mike Ximing
2021-12-21  9:53   ` Andrew Lunn
2021-12-21 20:56     ` Chen, Mike Ximing
2021-12-21 21:39       ` Andrew Lunn
2021-12-21 23:05         ` Chen, Mike Ximing
2021-12-22 21:26           ` Andrew Lunn
2021-12-23  5:15             ` Chen, Mike Ximing
2021-12-23 10:22               ` Andrew Lunn
2021-12-27  0:40                 ` Chen, Mike Ximing
     [not found]             ` <20211222194746.3480dea8@hermes.local>
2021-12-23  5:39               ` Dan Williams
2021-12-21  6:50 ` [RFC PATCH v12 02/17] dlb: initialize DLB device Mike Ximing Chen
2021-12-21  6:50 ` [RFC PATCH v12 03/17] dlb: add resource and device initialization Mike Ximing Chen
2021-12-21  6:50 ` [RFC PATCH v12 04/17] dlb: add configfs interface and scheduling domain directory Mike Ximing Chen
2021-12-21  6:50 ` [RFC PATCH v12 05/17] dlb: add scheduling domain configuration Mike Ximing Chen
2021-12-21 12:18   ` kernel test robot
2021-12-21  6:50 ` [RFC PATCH v12 06/17] dlb: add domain software reset Mike Ximing Chen
2021-12-21  6:50 ` [RFC PATCH v12 07/17] dlb: add low-level register reset operations Mike Ximing Chen
2021-12-21  6:50 ` [RFC PATCH v12 08/17] dlb: add runtime power-management support Mike Ximing Chen
2021-12-21  6:50 ` [RFC PATCH v12 09/17] dlb: add queue create, reset, get-depth configfs interface Mike Ximing Chen
2021-12-21  6:50 ` [RFC PATCH v12 10/17] dlb: add register operations for queue management Mike Ximing Chen
2021-12-21  6:50 ` [RFC PATCH v12 11/17] dlb: add configfs interface to configure ports Mike Ximing Chen
2021-12-21  6:50 ` [RFC PATCH v12 12/17] dlb: add register operations for port management Mike Ximing Chen
2021-12-21  6:50 ` [RFC PATCH v12 13/17] dlb: add port mmap support Mike Ximing Chen
2021-12-21  6:50 ` [RFC PATCH v12 14/17] dlb: add start domain configfs attribute Mike Ximing Chen
2021-12-21  6:50 ` [RFC PATCH v12 15/17] dlb: add queue map, unmap, and pending unmap Mike Ximing Chen
2021-12-21  6:50 ` [RFC PATCH v12 16/17] dlb: add static queue map register operations Mike Ximing Chen
2021-12-21  6:50 ` [RFC PATCH v12 17/17] dlb: add basic sysfs interfaces Mike Ximing Chen
2021-12-21  7:20   ` Joe Perches
2021-12-21 23:18     ` Chen, Mike Ximing
2021-12-21  8:56   ` Greg KH
2021-12-21 14:07     ` Chen, Mike Ximing
2021-12-21 23:34   ` Stephen Hemminger
2021-12-22  4:21     ` Chen, Mike Ximing
2021-12-21  7:09 ` [RFC PATCH v12 00/17] dlb: introduce DLB device driver Greg KH
2021-12-21 14:03   ` Chen, Mike Ximing
2021-12-21 14:31     ` Greg KH
2021-12-21 18:44       ` Dan Williams
2021-12-21 19:57         ` Andrew Lunn
2021-12-22  8:01         ` Christoph Hellwig
2021-12-21  9:40 ` Andrew Lunn
2021-12-22  4:37   ` Chen, Mike Ximing

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.