988001c735
The pointer outp is being initialized with a value that is never read. All the reads of outp occur after outp has neen set to an appropriate value rather than using the first value is initialized with. The assignment is redundant and can be removed. Cleans up clang scan warning: drivers/hwtracing/intel_th/sth.c:73:15: warning: Value stored to 'outp' during its initialization is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King <colin.i.king@gmail.com> Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Link: https://lore.kernel.org/r/20240429130119.1518073-9-alexander.shishkin@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
262 lines
5.7 KiB
C
262 lines
5.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Intel(R) Trace Hub Software Trace Hub support
|
|
*
|
|
* Copyright (C) 2014-2015 Intel Corporation.
|
|
*/
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/module.h>
|
|
#include <linux/device.h>
|
|
#include <linux/io.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/stm.h>
|
|
|
|
#include "intel_th.h"
|
|
#include "sth.h"
|
|
|
|
struct sth_device {
|
|
void __iomem *base;
|
|
void __iomem *channels;
|
|
phys_addr_t channels_phys;
|
|
struct device *dev;
|
|
struct stm_data stm;
|
|
unsigned int sw_nmasters;
|
|
};
|
|
|
|
static struct intel_th_channel __iomem *
|
|
sth_channel(struct sth_device *sth, unsigned int master, unsigned int channel)
|
|
{
|
|
struct intel_th_channel __iomem *sw_map = sth->channels;
|
|
|
|
return &sw_map[(master - sth->stm.sw_start) * sth->stm.sw_nchannels +
|
|
channel];
|
|
}
|
|
|
|
static void sth_iowrite(void __iomem *dest, const unsigned char *payload,
|
|
unsigned int size)
|
|
{
|
|
switch (size) {
|
|
#ifdef CONFIG_64BIT
|
|
case 8:
|
|
writeq_relaxed(*(u64 *)payload, dest);
|
|
break;
|
|
#endif
|
|
case 4:
|
|
writel_relaxed(*(u32 *)payload, dest);
|
|
break;
|
|
case 2:
|
|
writew_relaxed(*(u16 *)payload, dest);
|
|
break;
|
|
case 1:
|
|
writeb_relaxed(*(u8 *)payload, dest);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static ssize_t notrace sth_stm_packet(struct stm_data *stm_data,
|
|
unsigned int master,
|
|
unsigned int channel,
|
|
unsigned int packet,
|
|
unsigned int flags,
|
|
unsigned int size,
|
|
const unsigned char *payload)
|
|
{
|
|
struct sth_device *sth = container_of(stm_data, struct sth_device, stm);
|
|
struct intel_th_channel __iomem *out =
|
|
sth_channel(sth, master, channel);
|
|
unsigned long reg = REG_STH_TRIG;
|
|
u64 __iomem *outp;
|
|
|
|
#ifndef CONFIG_64BIT
|
|
if (size > 4)
|
|
size = 4;
|
|
#endif
|
|
|
|
size = rounddown_pow_of_two(size);
|
|
|
|
switch (packet) {
|
|
/* Global packets (GERR, XSYNC, TRIG) are sent with register writes */
|
|
case STP_PACKET_GERR:
|
|
reg += 4;
|
|
fallthrough;
|
|
|
|
case STP_PACKET_XSYNC:
|
|
reg += 8;
|
|
fallthrough;
|
|
|
|
case STP_PACKET_TRIG:
|
|
if (flags & STP_PACKET_TIMESTAMPED)
|
|
reg += 4;
|
|
writeb_relaxed(*payload, sth->base + reg);
|
|
break;
|
|
|
|
case STP_PACKET_MERR:
|
|
if (size > 4)
|
|
size = 4;
|
|
|
|
sth_iowrite(&out->MERR, payload, size);
|
|
break;
|
|
|
|
case STP_PACKET_FLAG:
|
|
if (flags & STP_PACKET_TIMESTAMPED)
|
|
outp = (u64 __iomem *)&out->FLAG_TS;
|
|
else
|
|
outp = (u64 __iomem *)&out->FLAG;
|
|
|
|
size = 0;
|
|
writeb_relaxed(0, outp);
|
|
break;
|
|
|
|
case STP_PACKET_USER:
|
|
if (flags & STP_PACKET_TIMESTAMPED)
|
|
outp = &out->USER_TS;
|
|
else
|
|
outp = &out->USER;
|
|
sth_iowrite(outp, payload, size);
|
|
break;
|
|
|
|
case STP_PACKET_DATA:
|
|
outp = &out->Dn;
|
|
|
|
if (flags & STP_PACKET_TIMESTAMPED)
|
|
outp += 2;
|
|
if (flags & STP_PACKET_MARKED)
|
|
outp++;
|
|
|
|
sth_iowrite(outp, payload, size);
|
|
break;
|
|
default:
|
|
return -ENOTSUPP;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
static phys_addr_t
|
|
sth_stm_mmio_addr(struct stm_data *stm_data, unsigned int master,
|
|
unsigned int channel, unsigned int nr_chans)
|
|
{
|
|
struct sth_device *sth = container_of(stm_data, struct sth_device, stm);
|
|
phys_addr_t addr;
|
|
|
|
master -= sth->stm.sw_start;
|
|
addr = sth->channels_phys + (master * sth->stm.sw_nchannels + channel) *
|
|
sizeof(struct intel_th_channel);
|
|
|
|
if (offset_in_page(addr) ||
|
|
offset_in_page(nr_chans * sizeof(struct intel_th_channel)))
|
|
return 0;
|
|
|
|
return addr;
|
|
}
|
|
|
|
static int sth_stm_link(struct stm_data *stm_data, unsigned int master,
|
|
unsigned int channel)
|
|
{
|
|
struct sth_device *sth = container_of(stm_data, struct sth_device, stm);
|
|
|
|
return intel_th_set_output(to_intel_th_device(sth->dev), master);
|
|
}
|
|
|
|
static int intel_th_sw_init(struct sth_device *sth)
|
|
{
|
|
u32 reg;
|
|
|
|
reg = ioread32(sth->base + REG_STH_STHCAP1);
|
|
sth->stm.sw_nchannels = reg & 0xff;
|
|
|
|
reg = ioread32(sth->base + REG_STH_STHCAP0);
|
|
sth->stm.sw_start = reg & 0xffff;
|
|
sth->stm.sw_end = reg >> 16;
|
|
|
|
sth->sw_nmasters = sth->stm.sw_end - sth->stm.sw_start;
|
|
dev_dbg(sth->dev, "sw_start: %x sw_end: %x masters: %x nchannels: %x\n",
|
|
sth->stm.sw_start, sth->stm.sw_end, sth->sw_nmasters,
|
|
sth->stm.sw_nchannels);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int intel_th_sth_probe(struct intel_th_device *thdev)
|
|
{
|
|
struct device *dev = &thdev->dev;
|
|
struct sth_device *sth;
|
|
struct resource *res;
|
|
void __iomem *base, *channels;
|
|
int err;
|
|
|
|
res = intel_th_device_get_resource(thdev, IORESOURCE_MEM, 0);
|
|
if (!res)
|
|
return -ENODEV;
|
|
|
|
base = devm_ioremap(dev, res->start, resource_size(res));
|
|
if (!base)
|
|
return -ENOMEM;
|
|
|
|
res = intel_th_device_get_resource(thdev, IORESOURCE_MEM, 1);
|
|
if (!res)
|
|
return -ENODEV;
|
|
|
|
channels = devm_ioremap(dev, res->start, resource_size(res));
|
|
if (!channels)
|
|
return -ENOMEM;
|
|
|
|
sth = devm_kzalloc(dev, sizeof(*sth), GFP_KERNEL);
|
|
if (!sth)
|
|
return -ENOMEM;
|
|
|
|
sth->dev = dev;
|
|
sth->base = base;
|
|
sth->channels = channels;
|
|
sth->channels_phys = res->start;
|
|
sth->stm.name = dev_name(dev);
|
|
sth->stm.packet = sth_stm_packet;
|
|
sth->stm.mmio_addr = sth_stm_mmio_addr;
|
|
sth->stm.sw_mmiosz = sizeof(struct intel_th_channel);
|
|
sth->stm.link = sth_stm_link;
|
|
|
|
err = intel_th_sw_init(sth);
|
|
if (err)
|
|
return err;
|
|
|
|
err = stm_register_device(dev, &sth->stm, THIS_MODULE);
|
|
if (err) {
|
|
dev_err(dev, "stm_register_device failed\n");
|
|
return err;
|
|
}
|
|
|
|
dev_set_drvdata(dev, sth);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void intel_th_sth_remove(struct intel_th_device *thdev)
|
|
{
|
|
struct sth_device *sth = dev_get_drvdata(&thdev->dev);
|
|
|
|
stm_unregister_device(&sth->stm);
|
|
}
|
|
|
|
static struct intel_th_driver intel_th_sth_driver = {
|
|
.probe = intel_th_sth_probe,
|
|
.remove = intel_th_sth_remove,
|
|
.driver = {
|
|
.name = "sth",
|
|
.owner = THIS_MODULE,
|
|
},
|
|
};
|
|
|
|
module_driver(intel_th_sth_driver,
|
|
intel_th_driver_register,
|
|
intel_th_driver_unregister);
|
|
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_DESCRIPTION("Intel(R) Trace Hub Software Trace Hub driver");
|
|
MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@intel.com>");
|