ARM SCPI updates/cleanups for v4.17

1. Fixes to get rid of sparse warnings
 2. Use of FIELD_GET and GENMASK for better subfields handling
 3. Make mbox_free_channels device-managed helping in removing unnecessary code
 4. Various other cleanups to simplify and improve code readability
 
 Note that similar set of changes were merged in v4.15, however got reverted
 through the commit 81faa55668 ("firmware: arm_scpi: Revert updates made
 during v4.15 merge window") for reasons mentioned in that commit.
 
 This is the resend with the culprit patch removed. Kevin Hilman tested this
 series on Amlogic and reported it to be fine.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJaltUpAAoJEABBurwxfuKYrowP/jPI9HyOol+DgSe+3Sj6LV50
 lnTQdcMNfvh/kFu/ZhdnVauMTHWLbPFaF/f+f4SGnSlSbRh4qFCGLbyRtglBeqEc
 nSrv0f1CFFXN6iVmN+DSV97cEcJUAylY3lvzyKKeP6QaFohYcGOJNg5+nUUsd8jw
 GvqaBe7aGDpujLHltaStia+U97QbXBqzBLCQHjcnfOM+ZaUPTQVPhBOkS5Y5caLy
 gVSFaOKv9WW4rjU6EdD952FM1XSJWFhb71FADAQ8/zceCqW6y04QCb8KhzaLdSXh
 InghoPkYbBOcz02WhVLSpm+GOwk6jj3f22ALUE5d5c9PBSyDz4D9QmYB6C3KD8Ia
 78Sj780beFAlQDqdXpMEKGOvinV+m3dzI7/jW8/hhCQZBLuJxzF2tRygD/DAwZgn
 x73lMH1cvyoqvmKAr6lKZghO1EZcubkG+TlPVfCL7FmcE3VK1bHHc/ErHdmMDMvV
 U7PCF2OkcoP46l0oh2/ztl8J4IILez9oK5/XR5GSd1pmaTmXHBmNBrGSWev/wweY
 CaMZflE1Z7Nx03ZsDuIyFydSoIEbOJXNuL/Nrvsb7nBsKatSsojzytMXx9w34Ywu
 70z/n/e1eS1o3uiRoV6xf5NRWdGmtybztqTemM96VyA2jQn/GAiDjCCOmrwDyij0
 1aUJpBnt6x8nM9bZ8QnS
 =0w4/
 -----END PGP SIGNATURE-----

Merge tag 'scpi-updates-4.17' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into next/drivers

Pull "ARM SCPI updates/cleanups for v4.17" from Sudeep Holla:

1. Fixes to get rid of sparse warnings
2. Use of FIELD_GET and GENMASK for better subfields handling
3. Make mbox_free_channels device-managed helping in removing unnecessary code
4. Various other cleanups to simplify and improve code readability

Note that similar set of changes were merged in v4.15, however got reverted
through the commit 81faa55668 ("firmware: arm_scpi: Revert updates made
during v4.15 merge window") for reasons mentioned in that commit.

This is the resend with the culprit patch removed. Kevin Hilman tested this
series on Amlogic and reported it to be fine.

* tag 'scpi-updates-4.17' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
  firmware: arm_scpi: improve info message for pre-1.0 firmware
  firmware: arm_scpi: use FIELD_GET/_PREP to simplify macro definitions
  firmware: arm_scpi: remove struct sensor_capabilities
  firmware: arm_scpi: fix incorrect __iomem accesses using correct accessors
  firmware: arm_scpi: remove all single element structures
  firmware: arm_scpi: drop unnecessary type cast to scpi_shared_mem
  firmware: arm_scpi: improve struct sensor_value
  firmware: arm_scpi: improve handling of protocol and firmware version subfields
  firmware: arm_scpi: improve struct dvfs_info to make code better readable
  firmware: arm_scpi: make scpi_probe completely device-managed
  firmware: arm_scpi: make freeing mbox channels device-managed
  firmware: arm_scpi: remove two unneeded devm_kfree's in scpi_remove
This commit is contained in:
Arnd Bergmann 2018-03-07 16:43:42 +01:00
commit 819d38e95f

View File

@ -28,6 +28,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bitmap.h>
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/export.h>
@ -45,48 +46,32 @@
#include <linux/sort.h>
#include <linux/spinlock.h>
#define CMD_ID_SHIFT 0
#define CMD_ID_MASK 0x7f
#define CMD_TOKEN_ID_SHIFT 8
#define CMD_TOKEN_ID_MASK 0xff
#define CMD_DATA_SIZE_SHIFT 16
#define CMD_DATA_SIZE_MASK 0x1ff
#define CMD_LEGACY_DATA_SIZE_SHIFT 20
#define CMD_LEGACY_DATA_SIZE_MASK 0x1ff
#define PACK_SCPI_CMD(cmd_id, tx_sz) \
((((cmd_id) & CMD_ID_MASK) << CMD_ID_SHIFT) | \
(((tx_sz) & CMD_DATA_SIZE_MASK) << CMD_DATA_SIZE_SHIFT))
#define ADD_SCPI_TOKEN(cmd, token) \
((cmd) |= (((token) & CMD_TOKEN_ID_MASK) << CMD_TOKEN_ID_SHIFT))
#define PACK_LEGACY_SCPI_CMD(cmd_id, tx_sz) \
((((cmd_id) & CMD_ID_MASK) << CMD_ID_SHIFT) | \
(((tx_sz) & CMD_LEGACY_DATA_SIZE_MASK) << CMD_LEGACY_DATA_SIZE_SHIFT))
#define CMD_ID_MASK GENMASK(6, 0)
#define CMD_TOKEN_ID_MASK GENMASK(15, 8)
#define CMD_DATA_SIZE_MASK GENMASK(24, 16)
#define CMD_LEGACY_DATA_SIZE_MASK GENMASK(28, 20)
#define PACK_SCPI_CMD(cmd_id, tx_sz) \
(FIELD_PREP(CMD_ID_MASK, cmd_id) | \
FIELD_PREP(CMD_DATA_SIZE_MASK, tx_sz))
#define PACK_LEGACY_SCPI_CMD(cmd_id, tx_sz) \
(FIELD_PREP(CMD_ID_MASK, cmd_id) | \
FIELD_PREP(CMD_LEGACY_DATA_SIZE_MASK, tx_sz))
#define CMD_SIZE(cmd) (((cmd) >> CMD_DATA_SIZE_SHIFT) & CMD_DATA_SIZE_MASK)
#define CMD_LEGACY_SIZE(cmd) (((cmd) >> CMD_LEGACY_DATA_SIZE_SHIFT) & \
CMD_LEGACY_DATA_SIZE_MASK)
#define CMD_UNIQ_MASK (CMD_TOKEN_ID_MASK << CMD_TOKEN_ID_SHIFT | CMD_ID_MASK)
#define CMD_SIZE(cmd) FIELD_GET(CMD_DATA_SIZE_MASK, cmd)
#define CMD_UNIQ_MASK (CMD_TOKEN_ID_MASK | CMD_ID_MASK)
#define CMD_XTRACT_UNIQ(cmd) ((cmd) & CMD_UNIQ_MASK)
#define SCPI_SLOT 0
#define MAX_DVFS_DOMAINS 8
#define MAX_DVFS_OPPS 16
#define DVFS_LATENCY(hdr) (le32_to_cpu(hdr) >> 16)
#define DVFS_OPP_COUNT(hdr) ((le32_to_cpu(hdr) >> 8) & 0xff)
#define PROTOCOL_REV_MINOR_BITS 16
#define PROTOCOL_REV_MINOR_MASK ((1U << PROTOCOL_REV_MINOR_BITS) - 1)
#define PROTOCOL_REV_MAJOR(x) ((x) >> PROTOCOL_REV_MINOR_BITS)
#define PROTOCOL_REV_MINOR(x) ((x) & PROTOCOL_REV_MINOR_MASK)
#define PROTO_REV_MAJOR_MASK GENMASK(31, 16)
#define PROTO_REV_MINOR_MASK GENMASK(15, 0)
#define FW_REV_MAJOR_BITS 24
#define FW_REV_MINOR_BITS 16
#define FW_REV_PATCH_MASK ((1U << FW_REV_MINOR_BITS) - 1)
#define FW_REV_MINOR_MASK ((1U << FW_REV_MAJOR_BITS) - 1)
#define FW_REV_MAJOR(x) ((x) >> FW_REV_MAJOR_BITS)
#define FW_REV_MINOR(x) (((x) & FW_REV_MINOR_MASK) >> FW_REV_MINOR_BITS)
#define FW_REV_PATCH(x) ((x) & FW_REV_PATCH_MASK)
#define FW_REV_MAJOR_MASK GENMASK(31, 24)
#define FW_REV_MINOR_MASK GENMASK(23, 16)
#define FW_REV_PATCH_MASK GENMASK(15, 0)
#define MAX_RX_TIMEOUT (msecs_to_jiffies(30))
@ -311,10 +296,6 @@ struct clk_get_info {
u8 name[20];
} __packed;
struct clk_get_value {
__le32 rate;
} __packed;
struct clk_set_value {
__le16 id;
__le16 reserved;
@ -328,7 +309,9 @@ struct legacy_clk_set_value {
} __packed;
struct dvfs_info {
__le32 header;
u8 domain;
u8 opp_count;
__le16 latency;
struct {
__le32 freq;
__le32 m_volt;
@ -340,10 +323,6 @@ struct dvfs_set {
u8 index;
} __packed;
struct sensor_capabilities {
__le16 sensors;
} __packed;
struct _scpi_sensor_info {
__le16 sensor_id;
u8 class;
@ -351,11 +330,6 @@ struct _scpi_sensor_info {
char name[20];
};
struct sensor_value {
__le32 lo_val;
__le32 hi_val;
} __packed;
struct dev_pstate_set {
__le16 dev_id;
u8 pstate;
@ -419,19 +393,20 @@ static void scpi_process_cmd(struct scpi_chan *ch, u32 cmd)
unsigned int len;
if (scpi_info->is_legacy) {
struct legacy_scpi_shared_mem *mem = ch->rx_payload;
struct legacy_scpi_shared_mem __iomem *mem =
ch->rx_payload;
/* RX Length is not replied by the legacy Firmware */
len = match->rx_len;
match->status = le32_to_cpu(mem->status);
match->status = ioread32(&mem->status);
memcpy_fromio(match->rx_buf, mem->payload, len);
} else {
struct scpi_shared_mem *mem = ch->rx_payload;
struct scpi_shared_mem __iomem *mem = ch->rx_payload;
len = min(match->rx_len, CMD_SIZE(cmd));
len = min_t(unsigned int, match->rx_len, CMD_SIZE(cmd));
match->status = le32_to_cpu(mem->status);
match->status = ioread32(&mem->status);
memcpy_fromio(match->rx_buf, mem->payload, len);
}
@ -445,11 +420,11 @@ static void scpi_process_cmd(struct scpi_chan *ch, u32 cmd)
static void scpi_handle_remote_msg(struct mbox_client *c, void *msg)
{
struct scpi_chan *ch = container_of(c, struct scpi_chan, cl);
struct scpi_shared_mem *mem = ch->rx_payload;
struct scpi_shared_mem __iomem *mem = ch->rx_payload;
u32 cmd = 0;
if (!scpi_info->is_legacy)
cmd = le32_to_cpu(mem->command);
cmd = ioread32(&mem->command);
scpi_process_cmd(ch, cmd);
}
@ -459,7 +434,7 @@ static void scpi_tx_prepare(struct mbox_client *c, void *msg)
unsigned long flags;
struct scpi_xfer *t = msg;
struct scpi_chan *ch = container_of(c, struct scpi_chan, cl);
struct scpi_shared_mem *mem = (struct scpi_shared_mem *)ch->tx_payload;
struct scpi_shared_mem __iomem *mem = ch->tx_payload;
if (t->tx_buf) {
if (scpi_info->is_legacy)
@ -471,14 +446,14 @@ static void scpi_tx_prepare(struct mbox_client *c, void *msg)
if (t->rx_buf) {
if (!(++ch->token))
++ch->token;
ADD_SCPI_TOKEN(t->cmd, ch->token);
t->cmd |= FIELD_PREP(CMD_TOKEN_ID_MASK, ch->token);
spin_lock_irqsave(&ch->rx_lock, flags);
list_add_tail(&t->node, &ch->rx_pending);
spin_unlock_irqrestore(&ch->rx_lock, flags);
}
if (!scpi_info->is_legacy)
mem->command = cpu_to_le32(t->cmd);
iowrite32(t->cmd, &mem->command);
}
static struct scpi_xfer *get_scpi_xfer(struct scpi_chan *ch)
@ -583,13 +558,13 @@ scpi_clk_get_range(u16 clk_id, unsigned long *min, unsigned long *max)
static unsigned long scpi_clk_get_val(u16 clk_id)
{
int ret;
struct clk_get_value clk;
__le32 rate;
__le16 le_clk_id = cpu_to_le16(clk_id);
ret = scpi_send_message(CMD_GET_CLOCK_VALUE, &le_clk_id,
sizeof(le_clk_id), &clk, sizeof(clk));
sizeof(le_clk_id), &rate, sizeof(rate));
return ret ? ret : le32_to_cpu(clk.rate);
return ret ? ret : le32_to_cpu(rate);
}
static int scpi_clk_set_val(u16 clk_id, unsigned long rate)
@ -665,8 +640,8 @@ static struct scpi_dvfs_info *scpi_dvfs_get_info(u8 domain)
if (!info)
return ERR_PTR(-ENOMEM);
info->count = DVFS_OPP_COUNT(buf.header);
info->latency = DVFS_LATENCY(buf.header) * 1000; /* uS to nS */
info->count = buf.opp_count;
info->latency = le16_to_cpu(buf.latency) * 1000; /* uS to nS */
info->opps = kcalloc(info->count, sizeof(*opp), GFP_KERNEL);
if (!info->opps) {
@ -713,9 +688,6 @@ static int scpi_dvfs_get_transition_latency(struct device *dev)
if (IS_ERR(info))
return PTR_ERR(info);
if (!info->latency)
return 0;
return info->latency;
}
@ -746,13 +718,13 @@ static int scpi_dvfs_add_opps_to_device(struct device *dev)
static int scpi_sensor_get_capability(u16 *sensors)
{
struct sensor_capabilities cap_buf;
__le16 cap;
int ret;
ret = scpi_send_message(CMD_SENSOR_CAPABILITIES, NULL, 0, &cap_buf,
sizeof(cap_buf));
ret = scpi_send_message(CMD_SENSOR_CAPABILITIES, NULL, 0, &cap,
sizeof(cap));
if (!ret)
*sensors = le16_to_cpu(cap_buf.sensors);
*sensors = le16_to_cpu(cap);
return ret;
}
@ -776,20 +748,19 @@ static int scpi_sensor_get_info(u16 sensor_id, struct scpi_sensor_info *info)
static int scpi_sensor_get_value(u16 sensor, u64 *val)
{
__le16 id = cpu_to_le16(sensor);
struct sensor_value buf;
__le64 value;
int ret;
ret = scpi_send_message(CMD_SENSOR_VALUE, &id, sizeof(id),
&buf, sizeof(buf));
&value, sizeof(value));
if (ret)
return ret;
if (scpi_info->is_legacy)
/* only 32-bits supported, hi_val can be junk */
*val = le32_to_cpu(buf.lo_val);
/* only 32-bits supported, upper 32 bits can be junk */
*val = le32_to_cpup((__le32 *)&value);
else
*val = (u64)le32_to_cpu(buf.hi_val) << 32 |
le32_to_cpu(buf.lo_val);
*val = le64_to_cpu(value);
return 0;
}
@ -864,9 +835,9 @@ static ssize_t protocol_version_show(struct device *dev,
{
struct scpi_drvinfo *scpi_info = dev_get_drvdata(dev);
return sprintf(buf, "%d.%d\n",
PROTOCOL_REV_MAJOR(scpi_info->protocol_version),
PROTOCOL_REV_MINOR(scpi_info->protocol_version));
return sprintf(buf, "%lu.%lu\n",
FIELD_GET(PROTO_REV_MAJOR_MASK, scpi_info->protocol_version),
FIELD_GET(PROTO_REV_MINOR_MASK, scpi_info->protocol_version));
}
static DEVICE_ATTR_RO(protocol_version);
@ -875,10 +846,10 @@ static ssize_t firmware_version_show(struct device *dev,
{
struct scpi_drvinfo *scpi_info = dev_get_drvdata(dev);
return sprintf(buf, "%d.%d.%d\n",
FW_REV_MAJOR(scpi_info->firmware_version),
FW_REV_MINOR(scpi_info->firmware_version),
FW_REV_PATCH(scpi_info->firmware_version));
return sprintf(buf, "%lu.%lu.%lu\n",
FIELD_GET(FW_REV_MAJOR_MASK, scpi_info->firmware_version),
FIELD_GET(FW_REV_MINOR_MASK, scpi_info->firmware_version),
FIELD_GET(FW_REV_PATCH_MASK, scpi_info->firmware_version));
}
static DEVICE_ATTR_RO(firmware_version);
@ -889,37 +860,26 @@ static struct attribute *versions_attrs[] = {
};
ATTRIBUTE_GROUPS(versions);
static void
scpi_free_channels(struct device *dev, struct scpi_chan *pchan, int count)
static void scpi_free_channels(void *data)
{
struct scpi_drvinfo *info = data;
int i;
for (i = 0; i < count && pchan->chan; i++, pchan++) {
mbox_free_channel(pchan->chan);
devm_kfree(dev, pchan->xfers);
devm_iounmap(dev, pchan->rx_payload);
}
for (i = 0; i < info->num_chans; i++)
mbox_free_channel(info->channels[i].chan);
}
static int scpi_remove(struct platform_device *pdev)
{
int i;
struct device *dev = &pdev->dev;
struct scpi_drvinfo *info = platform_get_drvdata(pdev);
scpi_info = NULL; /* stop exporting SCPI ops through get_scpi_ops */
of_platform_depopulate(dev);
sysfs_remove_groups(&dev->kobj, versions_groups);
scpi_free_channels(dev, info->channels, info->num_chans);
platform_set_drvdata(pdev, NULL);
for (i = 0; i < MAX_DVFS_DOMAINS && info->dvfs[i]; i++) {
kfree(info->dvfs[i]->opps);
kfree(info->dvfs[i]);
}
devm_kfree(dev, info->channels);
devm_kfree(dev, info);
return 0;
}
@ -952,7 +912,6 @@ static int scpi_probe(struct platform_device *pdev)
{
int count, idx, ret;
struct resource res;
struct scpi_chan *scpi_chan;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
@ -969,13 +928,19 @@ static int scpi_probe(struct platform_device *pdev)
return -ENODEV;
}
scpi_chan = devm_kcalloc(dev, count, sizeof(*scpi_chan), GFP_KERNEL);
if (!scpi_chan)
scpi_info->channels = devm_kcalloc(dev, count, sizeof(struct scpi_chan),
GFP_KERNEL);
if (!scpi_info->channels)
return -ENOMEM;
for (idx = 0; idx < count; idx++) {
ret = devm_add_action(dev, scpi_free_channels, scpi_info);
if (ret)
return ret;
for (; scpi_info->num_chans < count; scpi_info->num_chans++) {
resource_size_t size;
struct scpi_chan *pchan = scpi_chan + idx;
int idx = scpi_info->num_chans;
struct scpi_chan *pchan = scpi_info->channels + idx;
struct mbox_client *cl = &pchan->cl;
struct device_node *shmem = of_parse_phandle(np, "shmem", idx);
@ -983,15 +948,14 @@ static int scpi_probe(struct platform_device *pdev)
of_node_put(shmem);
if (ret) {
dev_err(dev, "failed to get SCPI payload mem resource\n");
goto err;
return ret;
}
size = resource_size(&res);
pchan->rx_payload = devm_ioremap(dev, res.start, size);
if (!pchan->rx_payload) {
dev_err(dev, "failed to ioremap SCPI payload\n");
ret = -EADDRNOTAVAIL;
goto err;
return -EADDRNOTAVAIL;
}
pchan->tx_payload = pchan->rx_payload + (size >> 1);
@ -1017,14 +981,9 @@ static int scpi_probe(struct platform_device *pdev)
dev_err(dev, "failed to get channel%d err %d\n",
idx, ret);
}
err:
scpi_free_channels(dev, scpi_chan, idx);
scpi_info = NULL;
return ret;
}
scpi_info->channels = scpi_chan;
scpi_info->num_chans = count;
scpi_info->commands = scpi_std_commands;
platform_set_drvdata(pdev, scpi_info);
@ -1043,23 +1002,31 @@ static int scpi_probe(struct platform_device *pdev)
ret = scpi_init_versions(scpi_info);
if (ret) {
dev_err(dev, "incorrect or no SCP firmware found\n");
scpi_remove(pdev);
return ret;
}
_dev_info(dev, "SCP Protocol %d.%d Firmware %d.%d.%d version\n",
PROTOCOL_REV_MAJOR(scpi_info->protocol_version),
PROTOCOL_REV_MINOR(scpi_info->protocol_version),
FW_REV_MAJOR(scpi_info->firmware_version),
FW_REV_MINOR(scpi_info->firmware_version),
FW_REV_PATCH(scpi_info->firmware_version));
if (scpi_info->is_legacy && !scpi_info->protocol_version &&
!scpi_info->firmware_version)
dev_info(dev, "SCP Protocol legacy pre-1.0 firmware\n");
else
dev_info(dev, "SCP Protocol %lu.%lu Firmware %lu.%lu.%lu version\n",
FIELD_GET(PROTO_REV_MAJOR_MASK,
scpi_info->protocol_version),
FIELD_GET(PROTO_REV_MINOR_MASK,
scpi_info->protocol_version),
FIELD_GET(FW_REV_MAJOR_MASK,
scpi_info->firmware_version),
FIELD_GET(FW_REV_MINOR_MASK,
scpi_info->firmware_version),
FIELD_GET(FW_REV_PATCH_MASK,
scpi_info->firmware_version));
scpi_info->scpi_ops = &scpi_ops;
ret = sysfs_create_groups(&dev->kobj, versions_groups);
ret = devm_device_add_groups(dev, versions_groups);
if (ret)
dev_err(dev, "unable to create sysfs version group\n");
return of_platform_populate(dev->of_node, NULL, NULL, dev);
return devm_of_platform_populate(dev);
}
static const struct of_device_id scpi_of_match[] = {