RE: [PATCH] drm/amdgpu: Add sysfs file for PCIe usage v3

2019-01-09 Thread Russell, Kent


> -Original Message-
> From: Alex Deucher 
> Sent: Tuesday, January 08, 2019 11:26 AM
> To: Kuehling, Felix 
> Cc: Russell, Kent ; amd-gfx@lists.freedesktop.org;
> Deucher, Alexander 
> Subject: Re: [PATCH] drm/amdgpu: Add sysfs file for PCIe usage v3
> 
> On Tue, Jan 8, 2019 at 11:02 AM Kuehling, Felix 
> wrote:
> >
> >
> > On 2019-01-08 6:28 a.m., Russell, Kent wrote:
> > > Add a sysfs file that reports the number of bytes transmitted and
> > > received in the last second. This can be used to approximate the
> > > PCIe bandwidth usage over the last second.
> > >
> > > v2: Clarify use of mps as estimation of bandwidth
> >
> > I think you only updated the code comment, but not the output in sysfs.
> >
> > More generally, most amdgpu sysfs files report a single value, or a
> > set of values separated by spaces. That makes it easier to parse by
> > external tools. It's also supposed to be a stable API. They don't
> > usually include human readable text such as "bytes received:". It
> > would be up to a tool such as rocm-smi to turn this into human-readable
> text.
> >
> > In keeping with that convention I'd suggest reporting the PCIe
> > bandwidth as three numbers:
> >
> >   
> >
> > Then let the tool calculate the bytes estimate with the appropriate
> > warnings about how accurate that is.
> >
> > Alex does this match your understanding regarding sysfs conventions?
> 
> Yes, agreed.
> 
> Alex
That works for me. I always let the sclk/mclk sysfs file with their multi-line 
outputs get into my head. I'll make the appropriate change, which will also 
make it easier for the SMI to communicate how the values are established.

 Kent

> 
> >
> > Regards,
> >   Felix
> >
> > > v3: Don't make the file on APUs
> > >
> > > Signed-off-by: Kent Russell 
> > > ---
> > >  drivers/gpu/drm/amd/amdgpu/amdgpu.h|  4 
> > >  drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 38
> +
> > >  drivers/gpu/drm/amd/amdgpu/cik.c   | 41
> +++
> > >  drivers/gpu/drm/amd/amdgpu/si.c| 41
> +++
> > >  drivers/gpu/drm/amd/amdgpu/soc15.c | 44
> ++
> > >  drivers/gpu/drm/amd/amdgpu/vi.c| 41
> +++
> > >  6 files changed, 209 insertions(+)
> > >
> > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > > b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > > index e1b2c64..512b124 100644
> > > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > > @@ -542,6 +542,9 @@ struct amdgpu_asic_funcs {
> > >   bool (*need_full_reset)(struct amdgpu_device *adev);
> > >   /* initialize doorbell layout for specific asic*/
> > >   void (*init_doorbell_index)(struct amdgpu_device *adev);
> > > + /* PCIe bandwidth usage */
> > > + void (*get_pcie_usage)(struct amdgpu_device *adev, uint64_t
> *count0,
> > > +uint64_t *count1);
> > >  };
> > >
> > >  /*
> > > @@ -1045,6 +1048,7 @@ int emu_soc_asic_init(struct amdgpu_device
> > > *adev);  #define amdgpu_asic_invalidate_hdp(adev, r)
> > > (adev)->asic_funcs->invalidate_hdp((adev), (r))  #define
> > > amdgpu_asic_need_full_reset(adev)
> > > (adev)->asic_funcs->need_full_reset((adev))
> > >  #define amdgpu_asic_init_doorbell_index(adev)
> > > (adev)->asic_funcs->init_doorbell_index((adev))
> > > +#define amdgpu_asic_get_pcie_usage(adev, cnt0, cnt1)
> > > +((adev)->asic_funcs->get_pcie_usage((adev), (cnt0), (cnt1)))
> > >
> > >  /* Common functions */
> > >  bool amdgpu_device_should_recover_gpu(struct amdgpu_device
> *adev);
> > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
> > > b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
> > > index 6896dec..d2b29fd 100644
> > > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
> > > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
> > > @@ -990,6 +990,33 @@ static ssize_t amdgpu_get_busy_percent(struct
> device *dev,
> > >   return snprintf(buf, PAGE_SIZE, "%d\n", value);  }
> > >
> > > +/**
> > > + * DOC: pcie_bw
> > > + *
> > > + * The amdgpu driver provides a sysfs API for reading how much data
> > > + * has been sent and received by the GPU in the last seco

Re: [PATCH] drm/amdgpu: Add sysfs file for PCIe usage v3

2019-01-08 Thread Alex Deucher
On Tue, Jan 8, 2019 at 6:28 AM Russell, Kent  wrote:
>
> Add a sysfs file that reports the number of bytes transmitted and
> received in the last second. This can be used to approximate the PCIe
> bandwidth usage over the last second.
>
> v2: Clarify use of mps as estimation of bandwidth
> v3: Don't make the file on APUs
>
> Signed-off-by: Kent Russell 
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu.h|  4 
>  drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 38 +
>  drivers/gpu/drm/amd/amdgpu/cik.c   | 41 +++
>  drivers/gpu/drm/amd/amdgpu/si.c| 41 +++
>  drivers/gpu/drm/amd/amdgpu/soc15.c | 44 
> ++
>  drivers/gpu/drm/amd/amdgpu/vi.c| 41 +++
>  6 files changed, 209 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index e1b2c64..512b124 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -542,6 +542,9 @@ struct amdgpu_asic_funcs {
> bool (*need_full_reset)(struct amdgpu_device *adev);
> /* initialize doorbell layout for specific asic*/
> void (*init_doorbell_index)(struct amdgpu_device *adev);
> +   /* PCIe bandwidth usage */
> +   void (*get_pcie_usage)(struct amdgpu_device *adev, uint64_t *count0,
> +  uint64_t *count1);
>  };
>
>  /*
> @@ -1045,6 +1048,7 @@ int emu_soc_asic_init(struct amdgpu_device *adev);
>  #define amdgpu_asic_invalidate_hdp(adev, r) 
> (adev)->asic_funcs->invalidate_hdp((adev), (r))
>  #define amdgpu_asic_need_full_reset(adev) 
> (adev)->asic_funcs->need_full_reset((adev))
>  #define amdgpu_asic_init_doorbell_index(adev) 
> (adev)->asic_funcs->init_doorbell_index((adev))
> +#define amdgpu_asic_get_pcie_usage(adev, cnt0, cnt1) 
> ((adev)->asic_funcs->get_pcie_usage((adev), (cnt0), (cnt1)))
>
>  /* Common functions */
>  bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev);
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
> index 6896dec..d2b29fd 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
> @@ -990,6 +990,33 @@ static ssize_t amdgpu_get_busy_percent(struct device 
> *dev,
> return snprintf(buf, PAGE_SIZE, "%d\n", value);
>  }
>
> +/**
> + * DOC: pcie_bw
> + *
> + * The amdgpu driver provides a sysfs API for reading how much data
> + * has been sent and received by the GPU in the last second through PCIe.
> + * The file pcie_bw is used for this.
> + * The Perf counters calculate this and return the number of sent and 
> received
> + * messages, which we multiply by the maxsize of our PCIe packets (mps).
> + * Note that it is not possible to easily and quickly obtain the size of each
> + * packet transmitted, so we use the max payload size (mps) to estimate the
> + * PCIe bandwidth usage
> + */
> +static ssize_t amdgpu_get_pcie_bw(struct device *dev,
> +   struct device_attribute *attr,
> +   char *buf)
> +{
> +   struct drm_device *ddev = dev_get_drvdata(dev);
> +   struct amdgpu_device *adev = ddev->dev_private;
> +   uint64_t mps = pcie_get_mps(adev->pdev);
> +   uint64_t count0, count1;
> +
> +   amdgpu_asic_get_pcie_usage(adev, , );
> +   return snprintf(buf, PAGE_SIZE,
> +   "Bytes received: %llu\nBytes sent: %llu\n",
> +   count0 * mps, count1 * mps);
> +}
> +
>  static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, amdgpu_get_dpm_state, 
> amdgpu_set_dpm_state);
>  static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR,
>amdgpu_get_dpm_forced_performance_level,
> @@ -1025,6 +1052,7 @@ static DEVICE_ATTR(pp_od_clk_voltage, S_IRUGO | S_IWUSR,
> amdgpu_set_pp_od_clk_voltage);
>  static DEVICE_ATTR(gpu_busy_percent, S_IRUGO,
> amdgpu_get_busy_percent, NULL);
> +static DEVICE_ATTR(pcie_bw, S_IRUGO, amdgpu_get_pcie_bw, NULL);
>
>  static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
>   struct device_attribute *attr,
> @@ -2108,6 +2136,14 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
> "gpu_busy_level\n");
> return ret;
> }
> +   /* PCIe Perf counters won't work on APU nodes */
> +   if (adev->flags & !AMD_IS_APU) {
> +   ret = device_create_file(adev->dev, _attr_pcie_bw);
> +   if (ret) {
> +   DRM_ERROR("failed to create device file pcie_bw\n");
> +   return ret;
> +   }
> +   }
> ret = amdgpu_debugfs_pm_init(adev);
> if (ret) {
> DRM_ERROR("Failed to register debugfs file for dpm!\n");
> @@ -2147,6 +2183,8 @@ void amdgpu_pm_sysfs_fini(struct 

Re: [PATCH] drm/amdgpu: Add sysfs file for PCIe usage v3

2019-01-08 Thread Alex Deucher
On Tue, Jan 8, 2019 at 11:02 AM Kuehling, Felix  wrote:
>
>
> On 2019-01-08 6:28 a.m., Russell, Kent wrote:
> > Add a sysfs file that reports the number of bytes transmitted and
> > received in the last second. This can be used to approximate the PCIe
> > bandwidth usage over the last second.
> >
> > v2: Clarify use of mps as estimation of bandwidth
>
> I think you only updated the code comment, but not the output in sysfs.
>
> More generally, most amdgpu sysfs files report a single value, or a set
> of values separated by spaces. That makes it easier to parse by external
> tools. It's also supposed to be a stable API. They don't usually include
> human readable text such as "bytes received:". It would be up to a tool
> such as rocm-smi to turn this into human-readable text.
>
> In keeping with that convention I'd suggest reporting the PCIe bandwidth
> as three numbers:
>
>   
>
> Then let the tool calculate the bytes estimate with the appropriate
> warnings about how accurate that is.
>
> Alex does this match your understanding regarding sysfs conventions?

Yes, agreed.

Alex

>
> Regards,
>   Felix
>
> > v3: Don't make the file on APUs
> >
> > Signed-off-by: Kent Russell 
> > ---
> >  drivers/gpu/drm/amd/amdgpu/amdgpu.h|  4 
> >  drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 38 +
> >  drivers/gpu/drm/amd/amdgpu/cik.c   | 41 +++
> >  drivers/gpu/drm/amd/amdgpu/si.c| 41 +++
> >  drivers/gpu/drm/amd/amdgpu/soc15.c | 44 
> > ++
> >  drivers/gpu/drm/amd/amdgpu/vi.c| 41 +++
> >  6 files changed, 209 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
> > b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > index e1b2c64..512b124 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > @@ -542,6 +542,9 @@ struct amdgpu_asic_funcs {
> >   bool (*need_full_reset)(struct amdgpu_device *adev);
> >   /* initialize doorbell layout for specific asic*/
> >   void (*init_doorbell_index)(struct amdgpu_device *adev);
> > + /* PCIe bandwidth usage */
> > + void (*get_pcie_usage)(struct amdgpu_device *adev, uint64_t *count0,
> > +uint64_t *count1);
> >  };
> >
> >  /*
> > @@ -1045,6 +1048,7 @@ int emu_soc_asic_init(struct amdgpu_device *adev);
> >  #define amdgpu_asic_invalidate_hdp(adev, r) 
> > (adev)->asic_funcs->invalidate_hdp((adev), (r))
> >  #define amdgpu_asic_need_full_reset(adev) 
> > (adev)->asic_funcs->need_full_reset((adev))
> >  #define amdgpu_asic_init_doorbell_index(adev) 
> > (adev)->asic_funcs->init_doorbell_index((adev))
> > +#define amdgpu_asic_get_pcie_usage(adev, cnt0, cnt1) 
> > ((adev)->asic_funcs->get_pcie_usage((adev), (cnt0), (cnt1)))
> >
> >  /* Common functions */
> >  bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev);
> > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c 
> > b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
> > index 6896dec..d2b29fd 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
> > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
> > @@ -990,6 +990,33 @@ static ssize_t amdgpu_get_busy_percent(struct device 
> > *dev,
> >   return snprintf(buf, PAGE_SIZE, "%d\n", value);
> >  }
> >
> > +/**
> > + * DOC: pcie_bw
> > + *
> > + * The amdgpu driver provides a sysfs API for reading how much data
> > + * has been sent and received by the GPU in the last second through PCIe.
> > + * The file pcie_bw is used for this.
> > + * The Perf counters calculate this and return the number of sent and 
> > received
> > + * messages, which we multiply by the maxsize of our PCIe packets (mps).
> > + * Note that it is not possible to easily and quickly obtain the size of 
> > each
> > + * packet transmitted, so we use the max payload size (mps) to estimate the
> > + * PCIe bandwidth usage
> > + */
> > +static ssize_t amdgpu_get_pcie_bw(struct device *dev,
> > + struct device_attribute *attr,
> > + char *buf)
> > +{
> > + struct drm_device *ddev = dev_get_drvdata(dev);
> > + struct amdgpu_device *adev = ddev->dev_private;
> > + uint64_t mps = pcie_get_mps(adev->pdev);
> > + uint64_t count0, count1;
> > +
> > + amdgpu_asic_get_pcie_usage(adev, , );
> > + return snprintf(buf, PAGE_SIZE,
> > + "Bytes received: %llu\nBytes sent: %llu\n",
> > + count0 * mps, count1 * mps);
> > +}
> > +
> >  static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, 
> > amdgpu_get_dpm_state, amdgpu_set_dpm_state);
> >  static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR,
> >  amdgpu_get_dpm_forced_performance_level,
> > @@ -1025,6 +1052,7 @@ static DEVICE_ATTR(pp_od_clk_voltage, S_IRUGO | 
> > S_IWUSR,
> >   amdgpu_set_pp_od_clk_voltage);
> >  static DEVICE_ATTR(gpu_busy_percent, S_IRUGO,
> >   

Re: [PATCH] drm/amdgpu: Add sysfs file for PCIe usage v3

2019-01-08 Thread Kuehling, Felix

On 2019-01-08 6:28 a.m., Russell, Kent wrote:
> Add a sysfs file that reports the number of bytes transmitted and
> received in the last second. This can be used to approximate the PCIe
> bandwidth usage over the last second.
>
> v2: Clarify use of mps as estimation of bandwidth

I think you only updated the code comment, but not the output in sysfs.

More generally, most amdgpu sysfs files report a single value, or a set
of values separated by spaces. That makes it easier to parse by external
tools. It's also supposed to be a stable API. They don't usually include
human readable text such as "bytes received:". It would be up to a tool
such as rocm-smi to turn this into human-readable text.

In keeping with that convention I'd suggest reporting the PCIe bandwidth
as three numbers:

      

Then let the tool calculate the bytes estimate with the appropriate
warnings about how accurate that is.

Alex does this match your understanding regarding sysfs conventions?

Regards,
  Felix

> v3: Don't make the file on APUs
>
> Signed-off-by: Kent Russell 
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu.h|  4 
>  drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 38 +
>  drivers/gpu/drm/amd/amdgpu/cik.c   | 41 +++
>  drivers/gpu/drm/amd/amdgpu/si.c| 41 +++
>  drivers/gpu/drm/amd/amdgpu/soc15.c | 44 
> ++
>  drivers/gpu/drm/amd/amdgpu/vi.c| 41 +++
>  6 files changed, 209 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index e1b2c64..512b124 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -542,6 +542,9 @@ struct amdgpu_asic_funcs {
>   bool (*need_full_reset)(struct amdgpu_device *adev);
>   /* initialize doorbell layout for specific asic*/
>   void (*init_doorbell_index)(struct amdgpu_device *adev);
> + /* PCIe bandwidth usage */
> + void (*get_pcie_usage)(struct amdgpu_device *adev, uint64_t *count0,
> +uint64_t *count1);
>  };
>  
>  /*
> @@ -1045,6 +1048,7 @@ int emu_soc_asic_init(struct amdgpu_device *adev);
>  #define amdgpu_asic_invalidate_hdp(adev, r) 
> (adev)->asic_funcs->invalidate_hdp((adev), (r))
>  #define amdgpu_asic_need_full_reset(adev) 
> (adev)->asic_funcs->need_full_reset((adev))
>  #define amdgpu_asic_init_doorbell_index(adev) 
> (adev)->asic_funcs->init_doorbell_index((adev))
> +#define amdgpu_asic_get_pcie_usage(adev, cnt0, cnt1) 
> ((adev)->asic_funcs->get_pcie_usage((adev), (cnt0), (cnt1)))
>  
>  /* Common functions */
>  bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev);
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
> index 6896dec..d2b29fd 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
> @@ -990,6 +990,33 @@ static ssize_t amdgpu_get_busy_percent(struct device 
> *dev,
>   return snprintf(buf, PAGE_SIZE, "%d\n", value);
>  }
>  
> +/**
> + * DOC: pcie_bw
> + *
> + * The amdgpu driver provides a sysfs API for reading how much data
> + * has been sent and received by the GPU in the last second through PCIe.
> + * The file pcie_bw is used for this.
> + * The Perf counters calculate this and return the number of sent and 
> received
> + * messages, which we multiply by the maxsize of our PCIe packets (mps).
> + * Note that it is not possible to easily and quickly obtain the size of each
> + * packet transmitted, so we use the max payload size (mps) to estimate the
> + * PCIe bandwidth usage
> + */
> +static ssize_t amdgpu_get_pcie_bw(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + struct drm_device *ddev = dev_get_drvdata(dev);
> + struct amdgpu_device *adev = ddev->dev_private;
> + uint64_t mps = pcie_get_mps(adev->pdev);
> + uint64_t count0, count1;
> +
> + amdgpu_asic_get_pcie_usage(adev, , );
> + return snprintf(buf, PAGE_SIZE,
> + "Bytes received: %llu\nBytes sent: %llu\n",
> + count0 * mps, count1 * mps);
> +}
> +
>  static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, amdgpu_get_dpm_state, 
> amdgpu_set_dpm_state);
>  static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR,
>  amdgpu_get_dpm_forced_performance_level,
> @@ -1025,6 +1052,7 @@ static DEVICE_ATTR(pp_od_clk_voltage, S_IRUGO | S_IWUSR,
>   amdgpu_set_pp_od_clk_voltage);
>  static DEVICE_ATTR(gpu_busy_percent, S_IRUGO,
>   amdgpu_get_busy_percent, NULL);
> +static DEVICE_ATTR(pcie_bw, S_IRUGO, amdgpu_get_pcie_bw, NULL);
>  
>  static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
> struct device_attribute *attr,
> @@ -2108,6 +2136,14 @@ int amdgpu_pm_sysfs_init(struct 

[PATCH] drm/amdgpu: Add sysfs file for PCIe usage v3

2019-01-08 Thread Russell, Kent
Add a sysfs file that reports the number of bytes transmitted and
received in the last second. This can be used to approximate the PCIe
bandwidth usage over the last second.

v2: Clarify use of mps as estimation of bandwidth
v3: Don't make the file on APUs

Signed-off-by: Kent Russell 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h|  4 
 drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 38 +
 drivers/gpu/drm/amd/amdgpu/cik.c   | 41 +++
 drivers/gpu/drm/amd/amdgpu/si.c| 41 +++
 drivers/gpu/drm/amd/amdgpu/soc15.c | 44 ++
 drivers/gpu/drm/amd/amdgpu/vi.c| 41 +++
 6 files changed, 209 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index e1b2c64..512b124 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -542,6 +542,9 @@ struct amdgpu_asic_funcs {
bool (*need_full_reset)(struct amdgpu_device *adev);
/* initialize doorbell layout for specific asic*/
void (*init_doorbell_index)(struct amdgpu_device *adev);
+   /* PCIe bandwidth usage */
+   void (*get_pcie_usage)(struct amdgpu_device *adev, uint64_t *count0,
+  uint64_t *count1);
 };
 
 /*
@@ -1045,6 +1048,7 @@ int emu_soc_asic_init(struct amdgpu_device *adev);
 #define amdgpu_asic_invalidate_hdp(adev, r) 
(adev)->asic_funcs->invalidate_hdp((adev), (r))
 #define amdgpu_asic_need_full_reset(adev) 
(adev)->asic_funcs->need_full_reset((adev))
 #define amdgpu_asic_init_doorbell_index(adev) 
(adev)->asic_funcs->init_doorbell_index((adev))
+#define amdgpu_asic_get_pcie_usage(adev, cnt0, cnt1) 
((adev)->asic_funcs->get_pcie_usage((adev), (cnt0), (cnt1)))
 
 /* Common functions */
 bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
index 6896dec..d2b29fd 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
@@ -990,6 +990,33 @@ static ssize_t amdgpu_get_busy_percent(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", value);
 }
 
+/**
+ * DOC: pcie_bw
+ *
+ * The amdgpu driver provides a sysfs API for reading how much data
+ * has been sent and received by the GPU in the last second through PCIe.
+ * The file pcie_bw is used for this.
+ * The Perf counters calculate this and return the number of sent and received
+ * messages, which we multiply by the maxsize of our PCIe packets (mps).
+ * Note that it is not possible to easily and quickly obtain the size of each
+ * packet transmitted, so we use the max payload size (mps) to estimate the
+ * PCIe bandwidth usage
+ */
+static ssize_t amdgpu_get_pcie_bw(struct device *dev,
+   struct device_attribute *attr,
+   char *buf)
+{
+   struct drm_device *ddev = dev_get_drvdata(dev);
+   struct amdgpu_device *adev = ddev->dev_private;
+   uint64_t mps = pcie_get_mps(adev->pdev);
+   uint64_t count0, count1;
+
+   amdgpu_asic_get_pcie_usage(adev, , );
+   return snprintf(buf, PAGE_SIZE,
+   "Bytes received: %llu\nBytes sent: %llu\n",
+   count0 * mps, count1 * mps);
+}
+
 static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, amdgpu_get_dpm_state, 
amdgpu_set_dpm_state);
 static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR,
   amdgpu_get_dpm_forced_performance_level,
@@ -1025,6 +1052,7 @@ static DEVICE_ATTR(pp_od_clk_voltage, S_IRUGO | S_IWUSR,
amdgpu_set_pp_od_clk_voltage);
 static DEVICE_ATTR(gpu_busy_percent, S_IRUGO,
amdgpu_get_busy_percent, NULL);
+static DEVICE_ATTR(pcie_bw, S_IRUGO, amdgpu_get_pcie_bw, NULL);
 
 static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
  struct device_attribute *attr,
@@ -2108,6 +2136,14 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
"gpu_busy_level\n");
return ret;
}
+   /* PCIe Perf counters won't work on APU nodes */
+   if (adev->flags & !AMD_IS_APU) {
+   ret = device_create_file(adev->dev, _attr_pcie_bw);
+   if (ret) {
+   DRM_ERROR("failed to create device file pcie_bw\n");
+   return ret;
+   }
+   }
ret = amdgpu_debugfs_pm_init(adev);
if (ret) {
DRM_ERROR("Failed to register debugfs file for dpm!\n");
@@ -2147,6 +2183,8 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev)
device_remove_file(adev->dev,
_attr_pp_od_clk_voltage);
device_remove_file(adev->dev, _attr_gpu_busy_percent);
+   if (adev->flags & !AMD_IS_APU)
+   device_remove_file(adev->dev,