From: Gage Eads <gage.eads@intel.com>
To: linux-kernel@vger.kernel.org, arnd@arndb.de, gregkh@linuxfoundation.org
Cc: magnus.karlsson@intel.com, bjorn.topel@intel.com
Subject: [PATCH 03/20] dlb2: add resource and device initialization
Date: Sun, 12 Jul 2020 08:43:14 -0500 [thread overview]
Message-ID: <20200712134331.8169-4-gage.eads@intel.com> (raw)
In-Reply-To: <20200712134331.8169-1-gage.eads@intel.com>
This commit adds the hardware resource data structures and functions for
their initialization/teardown and for device power-on. In subsequent
commits, dlb2_resource.c will be expanded to hold the dlb2
resource-management and configuration logic (using the data structures
defined in dlb2_hw_types.h).
This commit also introduces dlb2_bitmap_* functions, a thin convenience
layer wrapping the Linux bitmap interfaces, used by the bitmaps in the dlb2
hardware types.
Signed-off-by: Gage Eads <gage.eads@intel.com>
Reviewed-by: Magnus Karlsson <magnus.karlsson@intel.com>
---
drivers/misc/dlb2/Makefile | 7 +-
drivers/misc/dlb2/dlb2_bitmap.h | 121 +++++++++++++++++++++++
drivers/misc/dlb2/dlb2_hw_types.h | 173 +++++++++++++++++++++++++++++++++
drivers/misc/dlb2/dlb2_main.c | 51 ++++++++++
drivers/misc/dlb2/dlb2_main.h | 11 +++
drivers/misc/dlb2/dlb2_pf_ops.c | 73 ++++++++++++++
drivers/misc/dlb2/dlb2_regs.h | 83 ++++++++++++++++
drivers/misc/dlb2/dlb2_resource.c | 197 ++++++++++++++++++++++++++++++++++++++
drivers/misc/dlb2/dlb2_resource.h | 46 +++++++++
9 files changed, 759 insertions(+), 3 deletions(-)
create mode 100644 drivers/misc/dlb2/dlb2_bitmap.h
create mode 100644 drivers/misc/dlb2/dlb2_regs.h
create mode 100644 drivers/misc/dlb2/dlb2_resource.c
create mode 100644 drivers/misc/dlb2/dlb2_resource.h
diff --git a/drivers/misc/dlb2/Makefile b/drivers/misc/dlb2/Makefile
index 95e67e5bd8ff..4fdf7ffc555b 100644
--- a/drivers/misc/dlb2/Makefile
+++ b/drivers/misc/dlb2/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_INTEL_DLB2) := dlb2.o
-dlb2-objs := \
- dlb2_main.o \
- dlb2_pf_ops.o \
+dlb2-objs := \
+ dlb2_main.o \
+ dlb2_pf_ops.o \
+ dlb2_resource.o \
diff --git a/drivers/misc/dlb2/dlb2_bitmap.h b/drivers/misc/dlb2/dlb2_bitmap.h
new file mode 100644
index 000000000000..c5bb4ba84d5c
--- /dev/null
+++ b/drivers/misc/dlb2/dlb2_bitmap.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ * Copyright(c) 2017-2020 Intel Corporation
+ */
+
+#ifndef __DLB2_OSDEP_BITMAP_H
+#define __DLB2_OSDEP_BITMAP_H
+
+#include <linux/bitmap.h>
+#include <linux/slab.h>
+
+#include "dlb2_main.h"
+
+/*************************/
+/*** Bitmap operations ***/
+/*************************/
+struct dlb2_bitmap {
+ unsigned long *map;
+ unsigned int len;
+};
+
+/**
+ * dlb2_bitmap_alloc() - alloc a bitmap data structure
+ * @bitmap: pointer to dlb2_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 dlb2_bitmap_alloc(struct dlb2_bitmap **bitmap,
+ unsigned int len)
+{
+ struct dlb2_bitmap *bm;
+
+ if (!bitmap || len == 0)
+ return -EINVAL;
+
+ bm = kzalloc(sizeof(*bm), GFP_KERNEL);
+ if (!bm)
+ return -ENOMEM;
+
+ bm->map = kcalloc(BITS_TO_LONGS(len), sizeof(*bm->map), GFP_KERNEL);
+ if (!bm->map) {
+ kfree(bm);
+ return -ENOMEM;
+ }
+
+ bm->len = len;
+
+ *bitmap = bm;
+
+ return 0;
+}
+
+/**
+ * dlb2_bitmap_free() - free a previously allocated bitmap data structure
+ * @bitmap: pointer to dlb2_bitmap structure.
+ *
+ * This function frees a bitmap that was allocated with dlb2_bitmap_alloc().
+ */
+static inline void dlb2_bitmap_free(struct dlb2_bitmap *bitmap)
+{
+ if (!bitmap)
+ return;
+
+ kfree(bitmap->map);
+
+ kfree(bitmap);
+}
+
+/**
+ * dlb2_bitmap_fill() - fill a bitmap with all 1s
+ * @bitmap: pointer to dlb2_bitmap structure.
+ *
+ * This function sets all bitmap values to 1.
+ *
+ * Return:
+ * Returns 0 upon success, < 0 otherwise.
+ *
+ * Errors:
+ * EINVAL - bitmap is NULL or is uninitialized.
+ */
+static inline int dlb2_bitmap_fill(struct dlb2_bitmap *bitmap)
+{
+ if (!bitmap || !bitmap->map)
+ return -EINVAL;
+
+ bitmap_fill(bitmap->map, bitmap->len);
+
+ return 0;
+}
+
+/**
+ * dlb2_bitmap_zero() - fill a bitmap with all 0s
+ * @bitmap: pointer to dlb2_bitmap structure.
+ *
+ * This function sets all bitmap values to 0.
+ *
+ * Return:
+ * Returns 0 upon success, < 0 otherwise.
+ *
+ * Errors:
+ * EINVAL - bitmap is NULL or is uninitialized.
+ */
+static inline int dlb2_bitmap_zero(struct dlb2_bitmap *bitmap)
+{
+ if (!bitmap || !bitmap->map)
+ return -EINVAL;
+
+ bitmap_zero(bitmap->map, bitmap->len);
+
+ return 0;
+}
+
+#endif /* __DLB2_OSDEP_BITMAP_H */
diff --git a/drivers/misc/dlb2/dlb2_hw_types.h b/drivers/misc/dlb2/dlb2_hw_types.h
index 860d81bf3103..c5c4e45d4ee5 100644
--- a/drivers/misc/dlb2/dlb2_hw_types.h
+++ b/drivers/misc/dlb2/dlb2_hw_types.h
@@ -6,6 +6,9 @@
#define __DLB2_HW_TYPES_H
#include <linux/io.h>
+#include <linux/types.h>
+
+#include "dlb2_bitmap.h"
#define DLB2_PCI_REG_READ(addr) ioread32(addr)
#define DLB2_PCI_REG_WRITE(reg, value) iowrite32(value, reg)
@@ -45,6 +48,169 @@
#define DLB2_MAX_QID_EMPTY_CHECK_LOOPS (32 * 64 * 1024 * (800 / 30))
#define DLB2_HZ 800000000
+struct dlb2_resource_id {
+ u32 phys_id;
+ u32 virt_id;
+ u8 vdev_owned;
+ u8 vdev_id;
+};
+
+struct dlb2_freelist {
+ u32 base;
+ u32 bound;
+ u32 offset;
+};
+
+static inline u32 dlb2_freelist_count(struct dlb2_freelist *list)
+{
+ return list->bound - list->base - list->offset;
+}
+
+struct dlb2_ldb_queue {
+ struct list_head domain_list;
+ struct list_head func_list;
+ struct dlb2_resource_id id;
+ struct dlb2_resource_id 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 dlb2_dir_pq_pair {
+ struct list_head domain_list;
+ struct list_head func_list;
+ struct dlb2_resource_id id;
+ struct dlb2_resource_id domain_id;
+ u32 ref_cnt;
+ u8 init_tkn_cnt;
+ u8 queue_configured;
+ u8 port_configured;
+ u8 owned;
+ u8 enabled;
+};
+
+enum dlb2_qid_map_state {
+ /* The slot doesn't contain a valid queue mapping */
+ DLB2_QUEUE_UNMAPPED,
+ /* The slot contains a valid queue mapping */
+ DLB2_QUEUE_MAPPED,
+ /* The driver is mapping a queue into this slot */
+ DLB2_QUEUE_MAP_IN_PROG,
+ /* The driver is unmapping a queue from this slot */
+ DLB2_QUEUE_UNMAP_IN_PROG,
+ /*
+ * The driver is unmapping a queue from this slot, and once complete
+ * will replace it with another mapping.
+ */
+ DLB2_QUEUE_UNMAP_IN_PROG_PENDING_MAP,
+};
+
+struct dlb2_ldb_port_qid_map {
+ enum dlb2_qid_map_state state;
+ u16 qid;
+ u16 pending_qid;
+ u8 priority;
+ u8 pending_priority;
+};
+
+struct dlb2_ldb_port {
+ struct list_head domain_list;
+ struct list_head func_list;
+ struct dlb2_resource_id id;
+ struct dlb2_resource_id domain_id;
+ /* The qid_map represents the hardware QID mapping state. */
+ struct dlb2_ldb_port_qid_map qid_map[DLB2_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 dlb2_sn_group {
+ u32 mode;
+ u32 sequence_numbers_per_queue;
+ u32 slot_use_bitmap;
+ u32 id;
+};
+
+struct dlb2_hw_domain {
+ struct dlb2_function_resources *parent_func;
+ struct list_head func_list;
+ struct list_head used_ldb_queues;
+ struct list_head used_ldb_ports[DLB2_NUM_COS_DOMAINS];
+ struct list_head used_dir_pq_pairs;
+ struct list_head avail_ldb_queues;
+ struct list_head avail_ldb_ports[DLB2_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;
+ struct dlb2_resource_id id;
+ int num_pending_removals;
+ int num_pending_additions;
+ u8 configured;
+ u8 started;
+};
+
+struct dlb2_function_resources {
+ struct list_head avail_domains;
+ struct list_head used_domains;
+ struct list_head avail_ldb_queues;
+ struct list_head avail_ldb_ports[DLB2_NUM_COS_DOMAINS];
+ struct list_head avail_dir_pq_pairs;
+ struct dlb2_bitmap *avail_hist_list_entries;
+ u32 num_avail_domains;
+ u32 num_avail_ldb_queues;
+ u32 num_avail_ldb_ports[DLB2_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 dlb2_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 dlb2 scheduling domain.
+ * -- A VDEV's available resources list. These are VDEV-owned unconfigured
+ * resources not allocated to a dlb2 scheduling domain.
+ * -- A domain's available resources list. These are domain-owned unconfigured
+ * resources.
+ * -- A domain's used resources list. These are 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 dlb2_hw_resources {
+ struct dlb2_ldb_queue ldb_queues[DLB2_MAX_NUM_LDB_QUEUES];
+ struct dlb2_ldb_port ldb_ports[DLB2_MAX_NUM_LDB_PORTS];
+ struct dlb2_dir_pq_pair dir_pq_pairs[DLB2_MAX_NUM_DIR_PORTS];
+ struct dlb2_sn_group sn_groups[DLB2_MAX_NUM_SEQUENCE_NUMBER_GROUPS];
+};
+
struct dlb2_hw {
/* BAR 0 address */
void __iomem *csr_kva;
@@ -52,6 +218,13 @@ struct dlb2_hw {
/* BAR 2 address */
void __iomem *func_kva;
unsigned long func_phys_addr;
+
+ /* Resource tracking */
+ struct dlb2_hw_resources rsrcs;
+ struct dlb2_function_resources pf;
+ struct dlb2_function_resources vdev[DLB2_MAX_NUM_VDEVS];
+ struct dlb2_hw_domain domains[DLB2_MAX_NUM_DOMAINS];
+ u8 cos_reservation[DLB2_NUM_COS_DOMAINS];
};
#endif /* __DLB2_HW_TYPES_H */
diff --git a/drivers/misc/dlb2/dlb2_main.c b/drivers/misc/dlb2/dlb2_main.c
index d6fb46c05985..ae39dfea51e3 100644
--- a/drivers/misc/dlb2/dlb2_main.c
+++ b/drivers/misc/dlb2/dlb2_main.c
@@ -12,6 +12,7 @@
#include <linux/uaccess.h>
#include "dlb2_main.h"
+#include "dlb2_resource.h"
static const char
dlb2_driver_copyright[] = "Copyright(c) 2018-2020 Intel Corporation";
@@ -27,6 +28,23 @@ static struct list_head dlb2_dev_list = LIST_HEAD_INIT(dlb2_dev_list);
static struct class *dlb2_class;
static dev_t dlb2_dev_number_base;
+static int dlb2_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;
+}
+
/*****************************/
/****** Devfs callbacks ******/
/*****************************/
@@ -139,12 +157,41 @@ static int dlb2_probe(struct pci_dev *pdev,
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.
+ */
+ dlb2_dev->ops->enable_pm(dlb2_dev);
+
+ ret = dlb2_dev->ops->wait_for_device_ready(dlb2_dev, pdev);
+ if (ret)
+ goto wait_for_device_ready_fail;
+
+ ret = dlb2_reset_device(pdev);
+ if (ret)
+ goto dlb2_reset_fail;
+
+ ret = dlb2_resource_init(&dlb2_dev->hw);
+ if (ret)
+ goto resource_init_fail;
+
+ ret = dlb2_dev->ops->init_driver_state(dlb2_dev);
+ if (ret)
+ goto init_driver_state_fail;
+
+ dlb2_dev->ops->init_hardware(dlb2_dev);
+
mutex_lock(&dlb2_driver_lock);
list_add(&dlb2_dev->list, &dlb2_dev_list);
mutex_unlock(&dlb2_driver_lock);
return 0;
+init_driver_state_fail:
+ dlb2_resource_free(&dlb2_dev->hw);
+resource_init_fail:
+dlb2_reset_fail:
+wait_for_device_ready_fail:
dma_set_mask_fail:
dlb2_dev->ops->device_destroy(dlb2_dev, dlb2_class);
device_add_fail:
@@ -175,6 +222,10 @@ static void dlb2_remove(struct pci_dev *pdev)
list_del(&dlb2_dev->list);
mutex_unlock(&dlb2_driver_lock);
+ dlb2_dev->ops->free_driver_state(dlb2_dev);
+
+ dlb2_resource_free(&dlb2_dev->hw);
+
dlb2_dev->ops->device_destroy(dlb2_dev, dlb2_class);
dlb2_dev->ops->cdev_del(dlb2_dev);
diff --git a/drivers/misc/dlb2/dlb2_main.h b/drivers/misc/dlb2/dlb2_main.h
index 5e35d1e7c251..0bb646b82e5c 100644
--- a/drivers/misc/dlb2/dlb2_main.h
+++ b/drivers/misc/dlb2/dlb2_main.h
@@ -39,6 +39,8 @@ struct dlb2_device_ops {
int (*map_pci_bar_space)(struct dlb2_dev *dev, struct pci_dev *pdev);
void (*unmap_pci_bar_space)(struct dlb2_dev *dev,
struct pci_dev *pdev);
+ int (*init_driver_state)(struct dlb2_dev *dev);
+ void (*free_driver_state)(struct dlb2_dev *dev);
int (*device_create)(struct dlb2_dev *dlb2_dev,
struct pci_dev *pdev,
struct class *dlb2_class);
@@ -48,6 +50,10 @@ struct dlb2_device_ops {
dev_t base,
const struct file_operations *fops);
void (*cdev_del)(struct dlb2_dev *dlb2_dev);
+ void (*enable_pm)(struct dlb2_dev *dev);
+ int (*wait_for_device_ready)(struct dlb2_dev *dev,
+ struct pci_dev *pdev);
+ void (*init_hardware)(struct dlb2_dev *dev);
};
extern struct dlb2_device_ops dlb2_pf_ops;
@@ -59,6 +65,11 @@ struct dlb2_dev {
struct dlb2_device_ops *ops;
struct list_head list;
struct device *dlb2_device;
+ /*
+ * The resource mutex serializes access to driver data structures and
+ * hardware registers.
+ */
+ struct mutex resource_mutex;
enum dlb2_device_type type;
int id;
dev_t dev_number;
diff --git a/drivers/misc/dlb2/dlb2_pf_ops.c b/drivers/misc/dlb2/dlb2_pf_ops.c
index 14a50a778675..01664211d60a 100644
--- a/drivers/misc/dlb2/dlb2_pf_ops.c
+++ b/drivers/misc/dlb2/dlb2_pf_ops.c
@@ -1,7 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright(c) 2017-2020 Intel Corporation */
+#include <linux/delay.h>
+
#include "dlb2_main.h"
+#include "dlb2_regs.h"
+#include "dlb2_resource.h"
/********************************/
/****** PCI BAR management ******/
@@ -64,6 +68,19 @@ dlb2_pf_map_pci_bar_space(struct dlb2_dev *dlb2_dev,
/*******************************/
static int
+dlb2_pf_init_driver_state(struct dlb2_dev *dlb2_dev)
+{
+ mutex_init(&dlb2_dev->resource_mutex);
+
+ return 0;
+}
+
+static void
+dlb2_pf_free_driver_state(struct dlb2_dev *dlb2_dev)
+{
+}
+
+static int
dlb2_pf_cdev_add(struct dlb2_dev *dlb2_dev,
dev_t base,
const struct file_operations *fops)
@@ -126,6 +143,57 @@ dlb2_pf_device_destroy(struct dlb2_dev *dlb2_dev,
device_destroy(dlb2_class, dlb2_dev->dev_number);
}
+static void
+dlb2_pf_enable_pm(struct dlb2_dev *dlb2_dev)
+{
+ dlb2_clr_pmcsr_disable(&dlb2_dev->hw);
+}
+
+#define DLB2_READY_RETRY_LIMIT 1000
+static int
+dlb2_pf_wait_for_device_ready(struct dlb2_dev *dlb2_dev,
+ struct pci_dev *pdev)
+{
+ u32 retries = DLB2_READY_RETRY_LIMIT;
+
+ /* Allow at least 1s for the device to become active after power-on */
+ do {
+ union dlb2_cfg_mstr_cfg_diagnostic_idle_status idle;
+ union dlb2_cfg_mstr_cfg_pm_status pm_st;
+ u32 addr;
+
+ addr = DLB2_CFG_MSTR_CFG_PM_STATUS;
+
+ pm_st.val = DLB2_CSR_RD(&dlb2_dev->hw, addr);
+
+ addr = DLB2_CFG_MSTR_CFG_DIAGNOSTIC_IDLE_STATUS;
+
+ idle.val = DLB2_CSR_RD(&dlb2_dev->hw, addr);
+
+ if (pm_st.field.pmsm == 1 && idle.field.dlb_func_idle == 1)
+ break;
+
+ dev_dbg(&pdev->dev, "[%s()] pm_st: 0x%x\n",
+ __func__, pm_st.val);
+ dev_dbg(&pdev->dev, "[%s()] idle: 0x%x\n",
+ __func__, idle.val);
+
+ usleep_range(1000, 2000);
+ } while (--retries);
+
+ if (!retries) {
+ dev_err(&pdev->dev, "Device idle test failed\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void
+dlb2_pf_init_hardware(struct dlb2_dev *dlb2_dev)
+{
+}
+
/********************************/
/****** DLB2 PF Device Ops ******/
/********************************/
@@ -133,8 +201,13 @@ dlb2_pf_device_destroy(struct dlb2_dev *dlb2_dev,
struct dlb2_device_ops dlb2_pf_ops = {
.map_pci_bar_space = dlb2_pf_map_pci_bar_space,
.unmap_pci_bar_space = dlb2_pf_unmap_pci_bar_space,
+ .init_driver_state = dlb2_pf_init_driver_state,
+ .free_driver_state = dlb2_pf_free_driver_state,
.device_create = dlb2_pf_device_create,
.device_destroy = dlb2_pf_device_destroy,
.cdev_add = dlb2_pf_cdev_add,
.cdev_del = dlb2_pf_cdev_del,
+ .enable_pm = dlb2_pf_enable_pm,
+ .wait_for_device_ready = dlb2_pf_wait_for_device_ready,
+ .init_hardware = dlb2_pf_init_hardware,
};
diff --git a/drivers/misc/dlb2/dlb2_regs.h b/drivers/misc/dlb2/dlb2_regs.h
new file mode 100644
index 000000000000..77612c40ce0b
--- /dev/null
+++ b/drivers/misc/dlb2/dlb2_regs.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+ * Copyright(c) 2016-2020 Intel Corporation
+ */
+
+#ifndef __DLB2_REGS_H
+#define __DLB2_REGS_H
+
+#include "linux/types.h"
+
+#define DLB2_CFG_MSTR_CFG_DIAGNOSTIC_IDLE_STATUS 0xb4000004
+#define DLB2_CFG_MSTR_CFG_DIAGNOSTIC_IDLE_STATUS_RST 0x9d0fffff
+union dlb2_cfg_mstr_cfg_diagnostic_idle_status {
+ struct {
+ u32 chp_pipeidle : 1;
+ u32 rop_pipeidle : 1;
+ u32 lsp_pipeidle : 1;
+ u32 nalb_pipeidle : 1;
+ u32 ap_pipeidle : 1;
+ u32 dp_pipeidle : 1;
+ u32 qed_pipeidle : 1;
+ u32 dqed_pipeidle : 1;
+ u32 aqed_pipeidle : 1;
+ u32 sys_pipeidle : 1;
+ u32 chp_unit_idle : 1;
+ u32 rop_unit_idle : 1;
+ u32 lsp_unit_idle : 1;
+ u32 nalb_unit_idle : 1;
+ u32 ap_unit_idle : 1;
+ u32 dp_unit_idle : 1;
+ u32 qed_unit_idle : 1;
+ u32 dqed_unit_idle : 1;
+ u32 aqed_unit_idle : 1;
+ u32 sys_unit_idle : 1;
+ u32 rsvd1 : 4;
+ u32 mstr_cfg_ring_idle : 1;
+ u32 mstr_cfg_mstr_idle : 1;
+ u32 mstr_flr_clkreq_b : 1;
+ u32 mstr_proc_idle : 1;
+ u32 mstr_proc_idle_masked : 1;
+ u32 rsvd0 : 2;
+ u32 dlb_func_idle : 1;
+ } field;
+ u32 val;
+};
+
+#define DLB2_CFG_MSTR_CFG_PM_STATUS 0xb4000014
+#define DLB2_CFG_MSTR_CFG_PM_STATUS_RST 0x100403e
+union dlb2_cfg_mstr_cfg_pm_status {
+ struct {
+ u32 prochot : 1;
+ u32 pgcb_dlb_idle : 1;
+ u32 pgcb_dlb_pg_rdy_ack_b : 1;
+ u32 pmsm_pgcb_req_b : 1;
+ u32 pgbc_pmc_pg_req_b : 1;
+ u32 pmc_pgcb_pg_ack_b : 1;
+ u32 pmc_pgcb_fet_en_b : 1;
+ u32 pgcb_fet_en_b : 1;
+ u32 rsvz0 : 1;
+ u32 rsvz1 : 1;
+ u32 fuse_force_on : 1;
+ u32 fuse_proc_disable : 1;
+ u32 rsvz2 : 1;
+ u32 rsvz3 : 1;
+ u32 pm_fsm_d0tod3_ok : 1;
+ u32 pm_fsm_d3tod0_ok : 1;
+ u32 dlb_in_d3 : 1;
+ u32 rsvz4 : 7;
+ u32 pmsm : 8;
+ } field;
+ u32 val;
+};
+
+#define DLB2_CFG_MSTR_CFG_PM_PMCSR_DISABLE 0xb4000018
+#define DLB2_CFG_MSTR_CFG_PM_PMCSR_DISABLE_RST 0x1
+union dlb2_cfg_mstr_cfg_pm_pmcsr_disable {
+ struct {
+ u32 disable : 1;
+ u32 rsvz0 : 31;
+ } field;
+ u32 val;
+};
+
+#endif /* __DLB2_REGS_H */
diff --git a/drivers/misc/dlb2/dlb2_resource.c b/drivers/misc/dlb2/dlb2_resource.c
new file mode 100644
index 000000000000..036ab10d7a98
--- /dev/null
+++ b/drivers/misc/dlb2/dlb2_resource.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+/* Copyright(c) 2016-2020 Intel Corporation */
+
+#include "dlb2_bitmap.h"
+#include "dlb2_hw_types.h"
+#include "dlb2_regs.h"
+#include "dlb2_resource.h"
+
+static void dlb2_init_fn_rsrc_lists(struct dlb2_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 < DLB2_NUM_COS_DOMAINS; i++)
+ INIT_LIST_HEAD(&rsrc->avail_ldb_ports[i]);
+}
+
+static void dlb2_init_domain_rsrc_lists(struct dlb2_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 < DLB2_NUM_COS_DOMAINS; i++)
+ INIT_LIST_HEAD(&domain->used_ldb_ports[i]);
+ for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++)
+ INIT_LIST_HEAD(&domain->avail_ldb_ports[i]);
+}
+
+void dlb2_resource_free(struct dlb2_hw *hw)
+{
+ int i;
+
+ if (hw->pf.avail_hist_list_entries)
+ dlb2_bitmap_free(hw->pf.avail_hist_list_entries);
+
+ for (i = 0; i < DLB2_MAX_NUM_VDEVS; i++) {
+ if (hw->vdev[i].avail_hist_list_entries)
+ dlb2_bitmap_free(hw->vdev[i].avail_hist_list_entries);
+ }
+}
+
+int dlb2_resource_init(struct dlb2_hw *hw)
+{
+ 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. This is application
+ * dependent, but the driver interleaves port IDs as much as possible
+ * to reduce the likelihood of this. This initial allocation 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.).
+ */
+ u8 init_ldb_port_allocation[DLB2_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,
+ };
+
+ /* Zero-out resource tracking data structures */
+ memset(&hw->rsrcs, 0, sizeof(hw->rsrcs));
+ memset(&hw->pf, 0, sizeof(hw->pf));
+
+ dlb2_init_fn_rsrc_lists(&hw->pf);
+
+ for (i = 0; i < DLB2_MAX_NUM_VDEVS; i++) {
+ memset(&hw->vdev[i], 0, sizeof(hw->vdev[i]));
+ dlb2_init_fn_rsrc_lists(&hw->vdev[i]);
+ }
+
+ for (i = 0; i < DLB2_MAX_NUM_DOMAINS; i++) {
+ memset(&hw->domains[i], 0, sizeof(hw->domains[i]));
+ dlb2_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 = DLB2_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 = DLB2_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 < DLB2_NUM_COS_DOMAINS; i++)
+ hw->pf.num_avail_ldb_ports[i] =
+ DLB2_MAX_NUM_LDB_PORTS / DLB2_NUM_COS_DOMAINS;
+
+ for (i = 0; i < DLB2_MAX_NUM_LDB_PORTS; i++) {
+ int cos_id = i >> DLB2_NUM_COS_DOMAINS;
+ struct dlb2_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 = DLB2_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 = DLB2_MAX_NUM_LDB_CREDITS;
+ hw->pf.num_avail_dqed_entries = DLB2_MAX_NUM_DIR_CREDITS;
+ hw->pf.num_avail_aqed_entries = DLB2_MAX_NUM_AQED_ENTRIES;
+
+ ret = dlb2_bitmap_alloc(&hw->pf.avail_hist_list_entries,
+ DLB2_MAX_NUM_HIST_LIST_ENTRIES);
+ if (ret)
+ goto unwind;
+
+ ret = dlb2_bitmap_fill(hw->pf.avail_hist_list_entries);
+ if (ret)
+ goto unwind;
+
+ for (i = 0; i < DLB2_MAX_NUM_VDEVS; i++) {
+ ret = dlb2_bitmap_alloc(&hw->vdev[i].avail_hist_list_entries,
+ DLB2_MAX_NUM_HIST_LIST_ENTRIES);
+ if (ret)
+ goto unwind;
+
+ ret = dlb2_bitmap_zero(hw->vdev[i].avail_hist_list_entries);
+ if (ret)
+ goto unwind;
+ }
+
+ /* Initialize the hardware resource IDs */
+ for (i = 0; i < DLB2_MAX_NUM_DOMAINS; i++) {
+ hw->domains[i].id.phys_id = i;
+ hw->domains[i].id.vdev_owned = false;
+ }
+
+ for (i = 0; i < DLB2_MAX_NUM_LDB_QUEUES; i++) {
+ hw->rsrcs.ldb_queues[i].id.phys_id = i;
+ hw->rsrcs.ldb_queues[i].id.vdev_owned = false;
+ }
+
+ for (i = 0; i < DLB2_MAX_NUM_LDB_PORTS; i++) {
+ hw->rsrcs.ldb_ports[i].id.phys_id = i;
+ hw->rsrcs.ldb_ports[i].id.vdev_owned = false;
+ }
+
+ for (i = 0; i < DLB2_MAX_NUM_DIR_PORTS; i++) {
+ hw->rsrcs.dir_pq_pairs[i].id.phys_id = i;
+ hw->rsrcs.dir_pq_pairs[i].id.vdev_owned = false;
+ }
+
+ for (i = 0; i < DLB2_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 < DLB2_NUM_COS_DOMAINS; i++)
+ hw->cos_reservation[i] = 100 / DLB2_NUM_COS_DOMAINS;
+
+ return 0;
+
+unwind:
+ dlb2_resource_free(hw);
+
+ return ret;
+}
+
+void dlb2_clr_pmcsr_disable(struct dlb2_hw *hw)
+{
+ union dlb2_cfg_mstr_cfg_pm_pmcsr_disable r0;
+
+ r0.val = DLB2_CSR_RD(hw, DLB2_CFG_MSTR_CFG_PM_PMCSR_DISABLE);
+
+ r0.field.disable = 0;
+
+ DLB2_CSR_WR(hw, DLB2_CFG_MSTR_CFG_PM_PMCSR_DISABLE, r0.val);
+}
diff --git a/drivers/misc/dlb2/dlb2_resource.h b/drivers/misc/dlb2/dlb2_resource.h
new file mode 100644
index 000000000000..73528943d36e
--- /dev/null
+++ b/drivers/misc/dlb2/dlb2_resource.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+ * Copyright(c) 2016-2020 Intel Corporation
+ */
+
+#ifndef __DLB2_RESOURCE_H
+#define __DLB2_RESOURCE_H
+
+#include <linux/types.h>
+
+#include "dlb2_hw_types.h"
+
+/**
+ * dlb2_resource_init() - initialize the device
+ * @hw: pointer to struct dlb2_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.
+ *
+ * The dlb2_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 dlb2_resource_init(struct dlb2_hw *hw);
+
+/**
+ * dlb2_resource_free() - free device state memory
+ * @hw: dlb2_hw handle for a particular device.
+ *
+ * This function frees software state pointed to by dlb2_hw. This function
+ * should be called when resetting the device or unloading the driver.
+ */
+void dlb2_resource_free(struct dlb2_hw *hw);
+
+/**
+ * dlb2_clr_pmcsr_disable() - power on bulk of DLB 2.0 logic
+ * @hw: dlb2_hw handle for a particular device.
+ *
+ * Clearing the PMCSR must be done at initialization to make the device fully
+ * operational.
+ */
+void dlb2_clr_pmcsr_disable(struct dlb2_hw *hw);
+
+#endif /* __DLB2_RESOURCE_H */
--
2.13.6
next prev parent reply other threads:[~2020-07-12 13:47 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-07-12 13:43 [PATCH 00/20] dlb2: introduce DLB 2.0 device driver Gage Eads
2020-07-12 13:43 ` [PATCH 01/20] dlb2: add skeleton for DLB 2.0 driver Gage Eads
2020-07-12 15:56 ` Greg KH
2020-07-17 18:19 ` Eads, Gage
2020-07-18 6:46 ` Greg KH
2020-07-12 15:58 ` Greg KH
2020-07-17 18:18 ` Eads, Gage
2020-07-18 6:46 ` Greg KH
2020-07-20 19:02 ` Eads, Gage
2020-07-20 19:19 ` Greg KH
2020-07-24 21:00 ` Eads, Gage
2020-07-12 13:43 ` [PATCH 02/20] dlb2: initialize PF device Gage Eads
2020-07-12 13:43 ` Gage Eads [this message]
2020-07-12 13:43 ` [PATCH 04/20] dlb2: add device ioctl layer and first 4 ioctls Gage Eads
2020-07-12 14:42 ` Randy Dunlap
2020-07-17 18:20 ` Eads, Gage
2020-07-12 14:53 ` Randy Dunlap
2020-07-17 18:20 ` Eads, Gage
2020-07-12 15:28 ` Arnd Bergmann
2020-07-17 18:19 ` Eads, Gage
2020-07-17 18:56 ` Arnd Bergmann
2020-07-17 20:05 ` Eads, Gage
2020-07-18 6:48 ` gregkh
2020-08-04 22:20 ` Eads, Gage
2020-08-05 6:46 ` gregkh
2020-08-05 15:07 ` Eads, Gage
2020-08-05 15:17 ` gregkh
2020-08-05 15:39 ` Eads, Gage
2020-07-12 13:43 ` [PATCH 05/20] dlb2: add sched domain config and reset support Gage Eads
2020-07-12 13:43 ` [PATCH 06/20] dlb2: add ioctl to get sched domain fd Gage Eads
2020-07-12 13:43 ` [PATCH 07/20] dlb2: add runtime power-management support Gage Eads
2020-07-12 13:43 ` [PATCH 08/20] dlb2: add queue create and queue-depth-get ioctls Gage Eads
2020-07-12 13:43 ` [PATCH 09/20] dlb2: add ioctl to configure ports, query poll mode Gage Eads
2020-07-12 15:34 ` Arnd Bergmann
2020-07-17 18:19 ` Eads, Gage
2020-07-12 13:43 ` [PATCH 10/20] dlb2: add port mmap support Gage Eads
2020-07-12 13:43 ` [PATCH 11/20] dlb2: add start domain ioctl Gage Eads
2020-07-12 13:43 ` [PATCH 12/20] dlb2: add queue map and unmap ioctls Gage Eads
2020-07-12 13:43 ` [PATCH 13/20] dlb2: add port enable/disable ioctls Gage Eads
2020-07-12 13:43 ` [PATCH 14/20] dlb2: add CQ interrupt support Gage Eads
2020-07-12 13:43 ` [PATCH 15/20] dlb2: add domain alert support Gage Eads
2020-07-12 13:43 ` [PATCH 16/20] dlb2: add sequence-number management ioctls Gage Eads
2020-07-12 13:43 ` [PATCH 17/20] dlb2: add cos bandwidth get/set ioctls Gage Eads
2020-07-12 13:43 ` [PATCH 18/20] dlb2: add device FLR support Gage Eads
2020-07-12 13:43 ` [PATCH 19/20] dlb2: add basic PF sysfs interfaces Gage Eads
2020-07-12 13:43 ` [PATCH 20/20] dlb2: add ingress error handling Gage Eads
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200712134331.8169-4-gage.eads@intel.com \
--to=gage.eads@intel.com \
--cc=arnd@arndb.de \
--cc=bjorn.topel@intel.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=magnus.karlsson@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.