Skip to content

Commit

Permalink
hwtracing: hisi_ptt: Add tune function support for HiSilicon PCIe Tun…
Browse files Browse the repository at this point in the history
…e and Trace device

Add tune function for the HiSilicon Tune and Trace device. The interface
of tune is exposed through sysfs attributes of PTT PMU device.

Acked-by: Mathieu Poirier <[email protected]>
Reviewed-by: Jonathan Cameron <[email protected]>
Reviewed-by: John Garry <[email protected]>
Signed-off-by: Yicong Yang <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Mathieu Poirier <[email protected]>
  • Loading branch information
Yicong Yang authored and mathieupoirier committed Sep 8, 2022
1 parent ff0de06 commit 5ca57b0
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 0 deletions.
131 changes: 131 additions & 0 deletions drivers/hwtracing/ptt/hisi_ptt.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,135 @@
/* Dynamic CPU hotplug state used by PTT */
static enum cpuhp_state hisi_ptt_pmu_online;

static bool hisi_ptt_wait_tuning_finish(struct hisi_ptt *hisi_ptt)
{
u32 val;

return !readl_poll_timeout(hisi_ptt->iobase + HISI_PTT_TUNING_INT_STAT,
val, !(val & HISI_PTT_TUNING_INT_STAT_MASK),
HISI_PTT_WAIT_POLL_INTERVAL_US,
HISI_PTT_WAIT_TUNE_TIMEOUT_US);
}

static ssize_t hisi_ptt_tune_attr_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct hisi_ptt *hisi_ptt = to_hisi_ptt(dev_get_drvdata(dev));
struct dev_ext_attribute *ext_attr;
struct hisi_ptt_tune_desc *desc;
u32 reg;
u16 val;

ext_attr = container_of(attr, struct dev_ext_attribute, attr);
desc = ext_attr->var;

mutex_lock(&hisi_ptt->tune_lock);

reg = readl(hisi_ptt->iobase + HISI_PTT_TUNING_CTRL);
reg &= ~(HISI_PTT_TUNING_CTRL_CODE | HISI_PTT_TUNING_CTRL_SUB);
reg |= FIELD_PREP(HISI_PTT_TUNING_CTRL_CODE | HISI_PTT_TUNING_CTRL_SUB,
desc->event_code);
writel(reg, hisi_ptt->iobase + HISI_PTT_TUNING_CTRL);

/* Write all 1 to indicates it's the read process */
writel(~0U, hisi_ptt->iobase + HISI_PTT_TUNING_DATA);

if (!hisi_ptt_wait_tuning_finish(hisi_ptt)) {
mutex_unlock(&hisi_ptt->tune_lock);
return -ETIMEDOUT;
}

reg = readl(hisi_ptt->iobase + HISI_PTT_TUNING_DATA);
reg &= HISI_PTT_TUNING_DATA_VAL_MASK;
val = FIELD_GET(HISI_PTT_TUNING_DATA_VAL_MASK, reg);

mutex_unlock(&hisi_ptt->tune_lock);
return sysfs_emit(buf, "%u\n", val);
}

static ssize_t hisi_ptt_tune_attr_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct hisi_ptt *hisi_ptt = to_hisi_ptt(dev_get_drvdata(dev));
struct dev_ext_attribute *ext_attr;
struct hisi_ptt_tune_desc *desc;
u32 reg;
u16 val;

ext_attr = container_of(attr, struct dev_ext_attribute, attr);
desc = ext_attr->var;

if (kstrtou16(buf, 10, &val))
return -EINVAL;

mutex_lock(&hisi_ptt->tune_lock);

reg = readl(hisi_ptt->iobase + HISI_PTT_TUNING_CTRL);
reg &= ~(HISI_PTT_TUNING_CTRL_CODE | HISI_PTT_TUNING_CTRL_SUB);
reg |= FIELD_PREP(HISI_PTT_TUNING_CTRL_CODE | HISI_PTT_TUNING_CTRL_SUB,
desc->event_code);
writel(reg, hisi_ptt->iobase + HISI_PTT_TUNING_CTRL);
writel(FIELD_PREP(HISI_PTT_TUNING_DATA_VAL_MASK, val),
hisi_ptt->iobase + HISI_PTT_TUNING_DATA);

if (!hisi_ptt_wait_tuning_finish(hisi_ptt)) {
mutex_unlock(&hisi_ptt->tune_lock);
return -ETIMEDOUT;
}

mutex_unlock(&hisi_ptt->tune_lock);
return count;
}

#define HISI_PTT_TUNE_ATTR(_name, _val, _show, _store) \
static struct hisi_ptt_tune_desc _name##_desc = { \
.name = #_name, \
.event_code = (_val), \
}; \
static struct dev_ext_attribute hisi_ptt_##_name##_attr = { \
.attr = __ATTR(_name, 0600, _show, _store), \
.var = &_name##_desc, \
}

#define HISI_PTT_TUNE_ATTR_COMMON(_name, _val) \
HISI_PTT_TUNE_ATTR(_name, _val, \
hisi_ptt_tune_attr_show, \
hisi_ptt_tune_attr_store)

/*
* The value of the tuning event are composed of two parts: main event code
* in BIT[0,15] and subevent code in BIT[16,23]. For example, qox_tx_cpl is
* a subevent of 'Tx path QoS control' which for tuning the weight of Tx
* completion TLPs. See hisi_ptt.rst documentation for more information.
*/
#define HISI_PTT_TUNE_QOS_TX_CPL (0x4 | (3 << 16))
#define HISI_PTT_TUNE_QOS_TX_NP (0x4 | (4 << 16))
#define HISI_PTT_TUNE_QOS_TX_P (0x4 | (5 << 16))
#define HISI_PTT_TUNE_RX_ALLOC_BUF_LEVEL (0x5 | (6 << 16))
#define HISI_PTT_TUNE_TX_ALLOC_BUF_LEVEL (0x5 | (7 << 16))

HISI_PTT_TUNE_ATTR_COMMON(qos_tx_cpl, HISI_PTT_TUNE_QOS_TX_CPL);
HISI_PTT_TUNE_ATTR_COMMON(qos_tx_np, HISI_PTT_TUNE_QOS_TX_NP);
HISI_PTT_TUNE_ATTR_COMMON(qos_tx_p, HISI_PTT_TUNE_QOS_TX_P);
HISI_PTT_TUNE_ATTR_COMMON(rx_alloc_buf_level, HISI_PTT_TUNE_RX_ALLOC_BUF_LEVEL);
HISI_PTT_TUNE_ATTR_COMMON(tx_alloc_buf_level, HISI_PTT_TUNE_TX_ALLOC_BUF_LEVEL);

static struct attribute *hisi_ptt_tune_attrs[] = {
&hisi_ptt_qos_tx_cpl_attr.attr.attr,
&hisi_ptt_qos_tx_np_attr.attr.attr,
&hisi_ptt_qos_tx_p_attr.attr.attr,
&hisi_ptt_rx_alloc_buf_level_attr.attr.attr,
&hisi_ptt_tx_alloc_buf_level_attr.attr.attr,
NULL,
};

static struct attribute_group hisi_ptt_tune_group = {
.name = "tune",
.attrs = hisi_ptt_tune_attrs,
};

static u16 hisi_ptt_get_filter_val(u16 devid, bool is_port)
{
if (is_port)
Expand Down Expand Up @@ -393,6 +522,7 @@ static struct attribute_group hisi_ptt_pmu_format_group = {
static const struct attribute_group *hisi_ptt_pmu_groups[] = {
&hisi_ptt_cpumask_attr_group,
&hisi_ptt_pmu_format_group,
&hisi_ptt_tune_group,
NULL
};

Expand Down Expand Up @@ -727,6 +857,7 @@ static int hisi_ptt_register_pmu(struct hisi_ptt *hisi_ptt)
if (ret)
return ret;

mutex_init(&hisi_ptt->tune_lock);
spin_lock_init(&hisi_ptt->pmu_lock);

hisi_ptt->hisi_ptt_pmu = (struct pmu) {
Expand Down
23 changes: 23 additions & 0 deletions drivers/hwtracing/ptt/hisi_ptt.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <linux/bits.h>
#include <linux/cpumask.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/perf_event.h>
#include <linux/spinlock.h>
Expand All @@ -22,6 +23,11 @@
/*
* The definition of the device registers and register fields.
*/
#define HISI_PTT_TUNING_CTRL 0x0000
#define HISI_PTT_TUNING_CTRL_CODE GENMASK(15, 0)
#define HISI_PTT_TUNING_CTRL_SUB GENMASK(23, 16)
#define HISI_PTT_TUNING_DATA 0x0004
#define HISI_PTT_TUNING_DATA_VAL_MASK GENMASK(15, 0)
#define HISI_PTT_TRACE_ADDR_SIZE 0x0800
#define HISI_PTT_TRACE_ADDR_BASE_LO_0 0x0810
#define HISI_PTT_TRACE_ADDR_BASE_HI_0 0x0814
Expand All @@ -37,6 +43,8 @@
#define HISI_PTT_TRACE_INT_STAT 0x0890
#define HISI_PTT_TRACE_INT_STAT_MASK GENMASK(3, 0)
#define HISI_PTT_TRACE_INT_MASK 0x0894
#define HISI_PTT_TUNING_INT_STAT 0x0898
#define HISI_PTT_TUNING_INT_STAT_MASK BIT(0)
#define HISI_PTT_TRACE_WR_STS 0x08a0
#define HISI_PTT_TRACE_WR_STS_WRITE GENMASK(27, 0)
#define HISI_PTT_TRACE_WR_STS_BUFFER GENMASK(29, 28)
Expand All @@ -59,6 +67,7 @@
#define HISI_PTT_RESET_TIMEOUT_US 10UL
#define HISI_PTT_RESET_POLL_INTERVAL_US 1UL
/* Poll timeout and interval for waiting hardware work to finish */
#define HISI_PTT_WAIT_TUNE_TIMEOUT_US 1000000UL
#define HISI_PTT_WAIT_TRACE_TIMEOUT_US 100UL
#define HISI_PTT_WAIT_POLL_INTERVAL_US 10UL

Expand All @@ -71,6 +80,18 @@
#define HISI_PTT_PMU_TYPE_MASK GENMASK(31, 24)
#define HISI_PTT_PMU_FORMAT_MASK GENMASK(35, 32)

/**
* struct hisi_ptt_tune_desc - Describe tune event for PTT tune
* @hisi_ptt: PTT device this tune event belongs to
* @name: name of this event
* @event_code: code of the event
*/
struct hisi_ptt_tune_desc {
struct hisi_ptt *hisi_ptt;
const char *name;
u32 event_code;
};

/**
* struct hisi_ptt_dma_buffer - Describe a single trace buffer of PTT trace.
* The detail of the data format is described
Expand Down Expand Up @@ -143,6 +164,7 @@ struct hisi_ptt_pmu_buf {
* @hisi_ptt_pmu: the pum device of trace
* @iobase: base IO address of the device
* @pdev: pci_dev of this PTT device
* @tune_lock: lock to serialize the tune process
* @pmu_lock: lock to serialize the perf process
* @upper_bdf: the upper BDF range of the PCI devices managed by this PTT device
* @lower_bdf: the lower BDF range of the PCI devices managed by this PTT device
Expand All @@ -156,6 +178,7 @@ struct hisi_ptt {
struct pmu hisi_ptt_pmu;
void __iomem *iobase;
struct pci_dev *pdev;
struct mutex tune_lock;
spinlock_t pmu_lock;
u32 upper_bdf;
u32 lower_bdf;
Expand Down

0 comments on commit 5ca57b0

Please sign in to comment.