Commit 4c1e0a97 authored by Thierry Reding's avatar Thierry Reding

firmware: tegra: bpmp: Use iosys-map helpers

The shared memory used for inter-processor communication between the CPU
and the BPMP can reside either in system memory or in I/O memory. Use
the iosys-map helpers to abstract these differences away.
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent 236d3907
......@@ -18,8 +18,8 @@ struct tegra186_bpmp {
struct {
struct gen_pool *pool;
void __iomem *virt;
dma_addr_t phys;
void *virt;
} tx, rx;
struct {
......@@ -40,31 +40,27 @@ mbox_client_to_bpmp(struct mbox_client *client)
static bool tegra186_bpmp_is_message_ready(struct tegra_bpmp_channel *channel)
{
void *frame;
int err;
frame = tegra_ivc_read_get_next_frame(channel->ivc);
if (IS_ERR(frame)) {
channel->ib = NULL;
err = tegra_ivc_read_get_next_frame(channel->ivc, &channel->ib);
if (err) {
iosys_map_clear(&channel->ib);
return false;
}
channel->ib = frame;
return true;
}
static bool tegra186_bpmp_is_channel_free(struct tegra_bpmp_channel *channel)
{
void *frame;
int err;
frame = tegra_ivc_write_get_next_frame(channel->ivc);
if (IS_ERR(frame)) {
channel->ob = NULL;
err = tegra_ivc_write_get_next_frame(channel->ivc, &channel->ob);
if (err) {
iosys_map_clear(&channel->ob);
return false;
}
channel->ob = frame;
return true;
}
......@@ -109,6 +105,7 @@ static int tegra186_bpmp_channel_init(struct tegra_bpmp_channel *channel,
{
struct tegra186_bpmp *priv = bpmp->priv;
size_t message_size, queue_size;
struct iosys_map rx, tx;
unsigned int offset;
int err;
......@@ -121,10 +118,11 @@ static int tegra186_bpmp_channel_init(struct tegra_bpmp_channel *channel,
queue_size = tegra_ivc_total_queue_size(message_size);
offset = queue_size * index;
err = tegra_ivc_init(channel->ivc, NULL,
priv->rx.virt + offset, priv->rx.phys + offset,
priv->tx.virt + offset, priv->tx.phys + offset,
1, message_size, tegra186_bpmp_ivc_notify,
iosys_map_set_vaddr_iomem(&rx, priv->rx.virt + offset);
iosys_map_set_vaddr_iomem(&tx, priv->tx.virt + offset);
err = tegra_ivc_init(channel->ivc, NULL, &rx, priv->rx.phys + offset, &tx,
priv->tx.phys + offset, 1, message_size, tegra186_bpmp_ivc_notify,
bpmp);
if (err < 0) {
dev_err(bpmp->dev, "failed to setup IVC for channel %u: %d\n",
......@@ -179,7 +177,7 @@ static int tegra186_bpmp_init(struct tegra_bpmp *bpmp)
return -EPROBE_DEFER;
}
priv->tx.virt = gen_pool_dma_alloc(priv->tx.pool, 4096, &priv->tx.phys);
priv->tx.virt = (void __iomem *)gen_pool_dma_alloc(priv->tx.pool, 4096, &priv->tx.phys);
if (!priv->tx.virt) {
dev_err(bpmp->dev, "failed to allocate from TX pool\n");
return -ENOMEM;
......@@ -192,7 +190,7 @@ static int tegra186_bpmp_init(struct tegra_bpmp *bpmp)
goto free_tx;
}
priv->rx.virt = gen_pool_dma_alloc(priv->rx.pool, 4096, &priv->rx.phys);
priv->rx.virt = (void __iomem *)gen_pool_dma_alloc(priv->rx.pool, 4096, &priv->rx.phys);
if (!priv->rx.virt) {
dev_err(bpmp->dev, "failed to allocate from RX pool\n");
err = -ENOMEM;
......
......@@ -137,8 +137,8 @@ static int tegra210_bpmp_channel_init(struct tegra_bpmp_channel *channel,
unsigned int index)
{
struct tegra210_bpmp *priv = bpmp->priv;
void __iomem *p;
u32 address;
void *p;
/* Retrieve channel base address from BPMP */
writel(index << TRIGGER_ID_SHIFT | TRIGGER_CMD_GET,
......@@ -149,8 +149,9 @@ static int tegra210_bpmp_channel_init(struct tegra_bpmp_channel *channel,
if (!p)
return -ENOMEM;
channel->ib = p;
channel->ob = p;
iosys_map_set_vaddr_iomem(&channel->ib, p);
iosys_map_set_vaddr_iomem(&channel->ob, p);
channel->index = index;
init_completion(&channel->completion);
channel->bpmp = bpmp;
......
......@@ -201,13 +201,13 @@ static ssize_t __tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel,
int err;
if (data && size > 0)
memcpy_fromio(data, channel->ib->data, size);
tegra_bpmp_mb_read(data, &channel->ib, size);
err = tegra_bpmp_ack_response(channel);
if (err < 0)
return err;
*ret = channel->ib->code;
*ret = tegra_bpmp_mb_read_field(&channel->ib, code);
return 0;
}
......@@ -241,11 +241,11 @@ static ssize_t __tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel,
unsigned int mrq, unsigned long flags,
const void *data, size_t size)
{
channel->ob->code = mrq;
channel->ob->flags = flags;
tegra_bpmp_mb_write_field(&channel->ob, code, mrq);
tegra_bpmp_mb_write_field(&channel->ob, flags, flags);
if (data && size > 0)
memcpy_toio(channel->ob->data, data, size);
tegra_bpmp_mb_write(&channel->ob, data, size);
return tegra_bpmp_post_request(channel);
}
......@@ -400,7 +400,7 @@ static struct tegra_bpmp_mrq *tegra_bpmp_find_mrq(struct tegra_bpmp *bpmp,
void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel, int code,
const void *data, size_t size)
{
unsigned long flags = channel->ib->flags;
unsigned long flags = tegra_bpmp_mb_read_field(&channel->ib, flags);
struct tegra_bpmp *bpmp = channel->bpmp;
int err;
......@@ -417,10 +417,10 @@ void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel, int code,
if (WARN_ON(!tegra_bpmp_is_response_channel_free(channel)))
return;
channel->ob->code = code;
tegra_bpmp_mb_write_field(&channel->ob, code, code);
if (data && size > 0)
memcpy_toio(channel->ob->data, data, size);
tegra_bpmp_mb_write(&channel->ob, data, size);
err = tegra_bpmp_post_response(channel);
if (WARN_ON(err < 0))
......@@ -529,13 +529,13 @@ static void tegra_bpmp_mrq_handle_ping(unsigned int mrq,
struct tegra_bpmp_channel *channel,
void *data)
{
struct mrq_ping_request *request;
struct mrq_ping_request request;
struct mrq_ping_response response;
request = (struct mrq_ping_request *)channel->ib->data;
tegra_bpmp_mb_read(&request, &channel->ib, sizeof(request));
memset(&response, 0, sizeof(response));
response.reply = request->challenge << 1;
response.reply = request.challenge << 1;
tegra_bpmp_mrq_return(channel, 0, &response, sizeof(response));
}
......@@ -648,7 +648,7 @@ static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag,
static void tegra_bpmp_channel_signal(struct tegra_bpmp_channel *channel)
{
unsigned long flags = channel->ob->flags;
unsigned long flags = tegra_bpmp_mb_read_field(&channel->ob, flags);
if ((flags & MSG_RING) == 0)
return;
......@@ -666,8 +666,11 @@ void tegra_bpmp_handle_rx(struct tegra_bpmp *bpmp)
count = bpmp->soc->channels.thread.count;
busy = bpmp->threaded.busy;
if (tegra_bpmp_is_request_ready(channel))
tegra_bpmp_handle_mrq(bpmp, channel->ib->code, channel);
if (tegra_bpmp_is_request_ready(channel)) {
unsigned int mrq = tegra_bpmp_mb_read_field(&channel->ib, code);
tegra_bpmp_handle_mrq(bpmp, mrq, channel);
}
spin_lock(&bpmp->lock);
......
This diff is collapsed.
......@@ -106,21 +106,22 @@ static void tz_device_update_work_fn(struct work_struct *work)
static void bpmp_mrq_thermal(unsigned int mrq, struct tegra_bpmp_channel *ch,
void *data)
{
struct mrq_thermal_bpmp_to_host_request *req;
struct mrq_thermal_bpmp_to_host_request req;
struct tegra_bpmp_thermal *tegra = data;
size_t offset;
int i;
req = (struct mrq_thermal_bpmp_to_host_request *)ch->ib->data;
offset = offsetof(struct tegra_bpmp_mb_data, data);
iosys_map_memcpy_from(&req, &ch->ib, offset, sizeof(req));
if (req->type != CMD_THERMAL_HOST_TRIP_REACHED) {
dev_err(tegra->dev, "%s: invalid request type: %d\n",
__func__, req->type);
if (req.type != CMD_THERMAL_HOST_TRIP_REACHED) {
dev_err(tegra->dev, "%s: invalid request type: %d\n", __func__, req.type);
tegra_bpmp_mrq_return(ch, -EINVAL, NULL, 0);
return;
}
for (i = 0; i < tegra->num_zones; ++i) {
if (tegra->zones[i]->idx != req->host_trip_reached.zone)
if (tegra->zones[i]->idx != req.host_trip_reached.zone)
continue;
schedule_work(&tegra->zones[i]->tz_device_update_work);
......@@ -129,7 +130,7 @@ static void bpmp_mrq_thermal(unsigned int mrq, struct tegra_bpmp_channel *ch,
}
dev_err(tegra->dev, "%s: invalid thermal zone: %d\n", __func__,
req->host_trip_reached.zone);
req.host_trip_reached.zone);
tegra_bpmp_mrq_return(ch, -EINVAL, NULL, 0);
}
......
......@@ -6,6 +6,7 @@
#ifndef __SOC_TEGRA_BPMP_H
#define __SOC_TEGRA_BPMP_H
#include <linux/iosys-map.h>
#include <linux/mailbox_client.h>
#include <linux/pm_domain.h>
#include <linux/reset-controller.h>
......@@ -36,10 +37,22 @@ struct tegra_bpmp_mb_data {
u8 data[MSG_DATA_MIN_SZ];
} __packed;
#define tegra_bpmp_mb_read(dst, mb, size) \
iosys_map_memcpy_from(dst, mb, offsetof(struct tegra_bpmp_mb_data, data), size)
#define tegra_bpmp_mb_write(mb, src, size) \
iosys_map_memcpy_to(mb, offsetof(struct tegra_bpmp_mb_data, data), src, size)
#define tegra_bpmp_mb_read_field(mb, field) \
iosys_map_rd_field(mb, 0, struct tegra_bpmp_mb_data, field)
#define tegra_bpmp_mb_write_field(mb, field, value) \
iosys_map_wr_field(mb, 0, struct tegra_bpmp_mb_data, field, value)
struct tegra_bpmp_channel {
struct tegra_bpmp *bpmp;
struct tegra_bpmp_mb_data *ib;
struct tegra_bpmp_mb_data *ob;
struct iosys_map ib;
struct iosys_map ob;
struct completion completion;
struct tegra_ivc *ivc;
unsigned int index;
......
......@@ -7,6 +7,7 @@
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/iosys-map.h>
#include <linux/types.h>
struct tegra_ivc_header;
......@@ -15,7 +16,7 @@ struct tegra_ivc {
struct device *peer;
struct {
struct tegra_ivc_header *channel;
struct iosys_map map;
unsigned int position;
dma_addr_t phys;
} rx, tx;
......@@ -36,7 +37,7 @@ struct tegra_ivc {
*
* Returns a pointer to the frame, or an error encoded pointer.
*/
void *tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc);
int tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc, struct iosys_map *map);
/**
* tegra_ivc_read_advance - Advance the read queue
......@@ -56,7 +57,7 @@ int tegra_ivc_read_advance(struct tegra_ivc *ivc);
*
* Returns a pointer to the frame, or an error encoded pointer.
*/
void *tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc);
int tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc, struct iosys_map *map);
/**
* tegra_ivc_write_advance - Advance the write queue
......@@ -91,8 +92,8 @@ void tegra_ivc_reset(struct tegra_ivc *ivc);
size_t tegra_ivc_align(size_t size);
unsigned tegra_ivc_total_queue_size(unsigned queue_size);
int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx,
dma_addr_t rx_phys, void *tx, dma_addr_t tx_phys,
int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, const struct iosys_map *rx,
dma_addr_t rx_phys, const struct iosys_map *tx, dma_addr_t tx_phys,
unsigned int num_frames, size_t frame_size,
void (*notify)(struct tegra_ivc *ivc, void *data),
void *data);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment