Loading drivers/firmware/tegra/bpmp-debugfs.c +29 −33 Original line number Diff line number Diff line Loading @@ -48,13 +48,9 @@ static int seqbuf_read(struct seqbuf *seqbuf, void *buf, size_t nbyte) return seqbuf_status(seqbuf); } static int seqbuf_read_u32(struct seqbuf *seqbuf, uint32_t *v) static int seqbuf_read_u32(struct seqbuf *seqbuf, u32 *v) { int err; err = seqbuf_read(seqbuf, v, 4); *v = le32_to_cpu(*v); return err; return seqbuf_read(seqbuf, v, 4); } static int seqbuf_read_str(struct seqbuf *seqbuf, const char **str) Loading Loading @@ -109,10 +105,10 @@ static const char *get_filename(struct tegra_bpmp *bpmp, } static int mrq_debug_open(struct tegra_bpmp *bpmp, const char *name, uint32_t *fd, uint32_t *len, bool write) u32 *fd, u32 *len, bool write) { struct mrq_debug_request req = { .cmd = cpu_to_le32(write ? CMD_DEBUG_OPEN_WO : CMD_DEBUG_OPEN_RO), .cmd = write ? CMD_DEBUG_OPEN_WO : CMD_DEBUG_OPEN_RO, }; struct mrq_debug_response resp; struct tegra_bpmp_message msg = { Loading Loading @@ -147,10 +143,10 @@ static int mrq_debug_open(struct tegra_bpmp *bpmp, const char *name, return 0; } static int mrq_debug_close(struct tegra_bpmp *bpmp, uint32_t fd) static int mrq_debug_close(struct tegra_bpmp *bpmp, u32 fd) { struct mrq_debug_request req = { .cmd = cpu_to_le32(CMD_DEBUG_CLOSE), .cmd = CMD_DEBUG_CLOSE, .frd = { .fd = fd, }, Loading Loading @@ -179,10 +175,10 @@ static int mrq_debug_close(struct tegra_bpmp *bpmp, uint32_t fd) } static int mrq_debug_read(struct tegra_bpmp *bpmp, const char *name, char *data, size_t sz_data, uint32_t *nbytes) char *data, size_t sz_data, u32 *nbytes) { struct mrq_debug_request req = { .cmd = cpu_to_le32(CMD_DEBUG_READ), .cmd = CMD_DEBUG_READ, }; struct mrq_debug_response resp; struct tegra_bpmp_message msg = { Loading @@ -196,7 +192,7 @@ static int mrq_debug_read(struct tegra_bpmp *bpmp, const char *name, .size = sizeof(resp), }, }; uint32_t fd = 0, len = 0; u32 fd = 0, len = 0; int remaining, err; mutex_lock(&bpmp_debug_lock); Loading Loading @@ -245,7 +241,7 @@ static int mrq_debug_write(struct tegra_bpmp *bpmp, const char *name, uint8_t *data, size_t sz_data) { struct mrq_debug_request req = { .cmd = cpu_to_le32(CMD_DEBUG_WRITE) .cmd = CMD_DEBUG_WRITE }; struct mrq_debug_response resp; struct tegra_bpmp_message msg = { Loading @@ -259,7 +255,7 @@ static int mrq_debug_write(struct tegra_bpmp *bpmp, const char *name, .size = sizeof(resp), }, }; uint32_t fd = 0, len = 0; u32 fd = 0, len = 0; size_t remaining; int err; Loading Loading @@ -308,7 +304,7 @@ static int bpmp_debug_show(struct seq_file *m, void *p) char fnamebuf[256]; const char *filename; struct mrq_debug_request req = { .cmd = cpu_to_le32(CMD_DEBUG_READ), .cmd = CMD_DEBUG_READ, }; struct mrq_debug_response resp; struct tegra_bpmp_message msg = { Loading @@ -322,7 +318,7 @@ static int bpmp_debug_show(struct seq_file *m, void *p) .size = sizeof(resp), }, }; uint32_t fd = 0, len = 0; u32 fd = 0, len = 0; int remaining, err; filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf)); Loading Loading @@ -406,8 +402,8 @@ static int bpmp_populate_debugfs_inband(struct tegra_bpmp *bpmp, { const size_t pathlen = SZ_256; const size_t bufsize = SZ_16K; uint32_t dsize, attrs = 0; struct dentry *dentry; u32 dsize, attrs = 0; struct seqbuf seqbuf; char *buf, *pathbuf; const char *name; Loading Loading @@ -487,12 +483,12 @@ static int mrq_debugfs_read(struct tegra_bpmp *bpmp, size_t *nbytes) { struct mrq_debugfs_request req = { .cmd = cpu_to_le32(CMD_DEBUGFS_READ), .cmd = CMD_DEBUGFS_READ, .fop = { .fnameaddr = cpu_to_le32((uint32_t)name), .fnamelen = cpu_to_le32((uint32_t)sz_name), .dataaddr = cpu_to_le32((uint32_t)data), .datalen = cpu_to_le32((uint32_t)sz_data), .fnameaddr = (u32)name, .fnamelen = (u32)sz_name, .dataaddr = (u32)data, .datalen = (u32)sz_data, }, }; struct mrq_debugfs_response resp; Loading Loading @@ -525,12 +521,12 @@ static int mrq_debugfs_write(struct tegra_bpmp *bpmp, dma_addr_t data, size_t sz_data) { const struct mrq_debugfs_request req = { .cmd = cpu_to_le32(CMD_DEBUGFS_WRITE), .cmd = CMD_DEBUGFS_WRITE, .fop = { .fnameaddr = cpu_to_le32((uint32_t)name), .fnamelen = cpu_to_le32((uint32_t)sz_name), .dataaddr = cpu_to_le32((uint32_t)data), .datalen = cpu_to_le32((uint32_t)sz_data), .fnameaddr = (u32)name, .fnamelen = (u32)sz_name, .dataaddr = (u32)data, .datalen = (u32)sz_data, }, }; struct tegra_bpmp_message msg = { Loading @@ -548,10 +544,10 @@ static int mrq_debugfs_dumpdir(struct tegra_bpmp *bpmp, dma_addr_t addr, size_t size, size_t *nbytes) { const struct mrq_debugfs_request req = { .cmd = cpu_to_le32(CMD_DEBUGFS_DUMPDIR), .cmd = CMD_DEBUGFS_DUMPDIR, .dumpdir = { .dataaddr = cpu_to_le32((uint32_t)addr), .datalen = cpu_to_le32((uint32_t)size), .dataaddr = (u32)addr, .datalen = (u32)size, }, }; struct mrq_debugfs_response resp; Loading Loading @@ -688,10 +684,10 @@ static const struct file_operations debugfs_fops = { }; static int bpmp_populate_dir(struct tegra_bpmp *bpmp, struct seqbuf *seqbuf, struct dentry *parent, uint32_t depth) struct dentry *parent, u32 depth) { int err; uint32_t d, t; u32 d, t; const char *name; struct dentry *dentry; Loading drivers/firmware/tegra/bpmp-tegra186.c +17 −19 Original line number Diff line number Diff line Loading @@ -18,8 +18,8 @@ struct tegra186_bpmp { struct { struct gen_pool *pool; void __iomem *virt; dma_addr_t phys; void *virt; } tx, rx; struct { Loading @@ -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; } Loading Loading @@ -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; Loading @@ -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", Loading Loading @@ -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; Loading @@ -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; Loading drivers/firmware/tegra/bpmp-tegra210.c +4 −3 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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; Loading drivers/firmware/tegra/bpmp.c +18 −15 Original line number Diff line number Diff line Loading @@ -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; } Loading Loading @@ -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); } Loading Loading @@ -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; Loading @@ -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)) Loading Loading @@ -502,7 +502,7 @@ EXPORT_SYMBOL_GPL(tegra_bpmp_free_mrq); bool tegra_bpmp_mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq) { struct mrq_query_abi_request req = { .mrq = cpu_to_le32(mrq) }; struct mrq_query_abi_request req = { .mrq = mrq }; struct mrq_query_abi_response resp; struct tegra_bpmp_message msg = { .mrq = MRQ_QUERY_ABI, Loading @@ -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)); } Loading Loading @@ -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; Loading @@ -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); Loading drivers/firmware/tegra/ivc.c +92 −58 Original line number Diff line number Diff line Loading @@ -68,6 +68,12 @@ struct tegra_ivc_header { } rx; }; #define tegra_ivc_header_read_field(hdr, field) \ iosys_map_rd_field(hdr, 0, struct tegra_ivc_header, field) #define tegra_ivc_header_write_field(hdr, field, value) \ iosys_map_wr_field(hdr, 0, struct tegra_ivc_header, field, value) static inline void tegra_ivc_invalidate(struct tegra_ivc *ivc, dma_addr_t phys) { if (!ivc->peer) Loading @@ -86,16 +92,15 @@ static inline void tegra_ivc_flush(struct tegra_ivc *ivc, dma_addr_t phys) DMA_TO_DEVICE); } static inline bool tegra_ivc_empty(struct tegra_ivc *ivc, struct tegra_ivc_header *header) static inline bool tegra_ivc_empty(struct tegra_ivc *ivc, struct iosys_map *map) { /* * This function performs multiple checks on the same values with * security implications, so create snapshots with READ_ONCE() to * ensure that these checks use the same values. */ u32 tx = READ_ONCE(header->tx.count); u32 rx = READ_ONCE(header->rx.count); u32 tx = tegra_ivc_header_read_field(map, tx.count); u32 rx = tegra_ivc_header_read_field(map, rx.count); /* * Perform an over-full check to prevent denial of service attacks Loading @@ -113,11 +118,10 @@ static inline bool tegra_ivc_empty(struct tegra_ivc *ivc, return tx == rx; } static inline bool tegra_ivc_full(struct tegra_ivc *ivc, struct tegra_ivc_header *header) static inline bool tegra_ivc_full(struct tegra_ivc *ivc, struct iosys_map *map) { u32 tx = READ_ONCE(header->tx.count); u32 rx = READ_ONCE(header->rx.count); u32 tx = tegra_ivc_header_read_field(map, tx.count); u32 rx = tegra_ivc_header_read_field(map, rx.count); /* * Invalid cases where the counters indicate that the queue is over Loading @@ -126,11 +130,10 @@ static inline bool tegra_ivc_full(struct tegra_ivc *ivc, return tx - rx >= ivc->num_frames; } static inline u32 tegra_ivc_available(struct tegra_ivc *ivc, struct tegra_ivc_header *header) static inline u32 tegra_ivc_available(struct tegra_ivc *ivc, struct iosys_map *map) { u32 tx = READ_ONCE(header->tx.count); u32 rx = READ_ONCE(header->rx.count); u32 tx = tegra_ivc_header_read_field(map, tx.count); u32 rx = tegra_ivc_header_read_field(map, rx.count); /* * This function isn't expected to be used in scenarios where an Loading @@ -143,8 +146,9 @@ static inline u32 tegra_ivc_available(struct tegra_ivc *ivc, static inline void tegra_ivc_advance_tx(struct tegra_ivc *ivc) { WRITE_ONCE(ivc->tx.channel->tx.count, READ_ONCE(ivc->tx.channel->tx.count) + 1); unsigned int count = tegra_ivc_header_read_field(&ivc->tx.map, tx.count); tegra_ivc_header_write_field(&ivc->tx.map, tx.count, count + 1); if (ivc->tx.position == ivc->num_frames - 1) ivc->tx.position = 0; Loading @@ -154,8 +158,9 @@ static inline void tegra_ivc_advance_tx(struct tegra_ivc *ivc) static inline void tegra_ivc_advance_rx(struct tegra_ivc *ivc) { WRITE_ONCE(ivc->rx.channel->rx.count, READ_ONCE(ivc->rx.channel->rx.count) + 1); unsigned int count = tegra_ivc_header_read_field(&ivc->rx.map, rx.count); tegra_ivc_header_write_field(&ivc->rx.map, rx.count, count + 1); if (ivc->rx.position == ivc->num_frames - 1) ivc->rx.position = 0; Loading @@ -166,6 +171,7 @@ static inline void tegra_ivc_advance_rx(struct tegra_ivc *ivc) static inline int tegra_ivc_check_read(struct tegra_ivc *ivc) { unsigned int offset = offsetof(struct tegra_ivc_header, tx.count); unsigned int state; /* * tx.channel->state is set locally, so it is not synchronized with Loading @@ -175,7 +181,8 @@ static inline int tegra_ivc_check_read(struct tegra_ivc *ivc) * asynchronous transition of rx.channel->state to * TEGRA_IVC_STATE_ACK is not allowed. */ if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED) state = tegra_ivc_header_read_field(&ivc->tx.map, tx.state); if (state != TEGRA_IVC_STATE_ESTABLISHED) return -ECONNRESET; /* Loading @@ -185,12 +192,12 @@ static inline int tegra_ivc_check_read(struct tegra_ivc *ivc) * Synchronization is only necessary when these pointers indicate * empty or full. */ if (!tegra_ivc_empty(ivc, ivc->rx.channel)) if (!tegra_ivc_empty(ivc, &ivc->rx.map)) return 0; tegra_ivc_invalidate(ivc, ivc->rx.phys + offset); if (tegra_ivc_empty(ivc, ivc->rx.channel)) if (tegra_ivc_empty(ivc, &ivc->rx.map)) return -ENOSPC; return 0; Loading @@ -199,29 +206,34 @@ static inline int tegra_ivc_check_read(struct tegra_ivc *ivc) static inline int tegra_ivc_check_write(struct tegra_ivc *ivc) { unsigned int offset = offsetof(struct tegra_ivc_header, rx.count); unsigned int state; if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED) state = tegra_ivc_header_read_field(&ivc->tx.map, tx.state); if (state != TEGRA_IVC_STATE_ESTABLISHED) return -ECONNRESET; if (!tegra_ivc_full(ivc, ivc->tx.channel)) if (!tegra_ivc_full(ivc, &ivc->tx.map)) return 0; tegra_ivc_invalidate(ivc, ivc->tx.phys + offset); if (tegra_ivc_full(ivc, ivc->tx.channel)) if (tegra_ivc_full(ivc, &ivc->tx.map)) return -ENOSPC; return 0; } static void *tegra_ivc_frame_virt(struct tegra_ivc *ivc, struct tegra_ivc_header *header, unsigned int frame) static int tegra_ivc_frame_virt(struct tegra_ivc *ivc, const struct iosys_map *header, unsigned int frame, struct iosys_map *map) { size_t offset = sizeof(struct tegra_ivc_header) + ivc->frame_size * frame; if (WARN_ON(frame >= ivc->num_frames)) return ERR_PTR(-EINVAL); return -EINVAL; *map = IOSYS_MAP_INIT_OFFSET(header, offset); return (void *)(header + 1) + ivc->frame_size * frame; return 0; } static inline dma_addr_t tegra_ivc_frame_phys(struct tegra_ivc *ivc, Loading Loading @@ -264,16 +276,16 @@ static inline void tegra_ivc_flush_frame(struct tegra_ivc *ivc, } /* directly peek at the next frame rx'ed */ 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) { int err; if (WARN_ON(ivc == NULL)) return ERR_PTR(-EINVAL); return -EINVAL; err = tegra_ivc_check_read(ivc); if (err < 0) return ERR_PTR(err); return err; /* * Order observation of ivc->rx.position potentially indicating new Loading @@ -284,7 +296,7 @@ void *tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc) tegra_ivc_invalidate_frame(ivc, ivc->rx.phys, ivc->rx.position, 0, ivc->frame_size); return tegra_ivc_frame_virt(ivc, ivc->rx.channel, ivc->rx.position); return tegra_ivc_frame_virt(ivc, &ivc->rx.map, ivc->rx.position, map); } EXPORT_SYMBOL(tegra_ivc_read_get_next_frame); Loading Loading @@ -320,7 +332,7 @@ int tegra_ivc_read_advance(struct tegra_ivc *ivc) */ tegra_ivc_invalidate(ivc, ivc->rx.phys + tx); if (tegra_ivc_available(ivc, ivc->rx.channel) == ivc->num_frames - 1) if (tegra_ivc_available(ivc, &ivc->rx.map) == ivc->num_frames - 1) ivc->notify(ivc, ivc->notify_data); return 0; Loading @@ -328,15 +340,15 @@ int tegra_ivc_read_advance(struct tegra_ivc *ivc) EXPORT_SYMBOL(tegra_ivc_read_advance); /* directly poke at the next frame to be tx'ed */ 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) { int err; err = tegra_ivc_check_write(ivc); if (err < 0) return ERR_PTR(err); return err; return tegra_ivc_frame_virt(ivc, ivc->tx.channel, ivc->tx.position); return tegra_ivc_frame_virt(ivc, &ivc->tx.map, ivc->tx.position, map); } EXPORT_SYMBOL(tegra_ivc_write_get_next_frame); Loading Loading @@ -376,7 +388,7 @@ int tegra_ivc_write_advance(struct tegra_ivc *ivc) */ tegra_ivc_invalidate(ivc, ivc->tx.phys + rx); if (tegra_ivc_available(ivc, ivc->tx.channel) == 1) if (tegra_ivc_available(ivc, &ivc->tx.map) == 1) ivc->notify(ivc, ivc->notify_data); return 0; Loading @@ -387,7 +399,7 @@ void tegra_ivc_reset(struct tegra_ivc *ivc) { unsigned int offset = offsetof(struct tegra_ivc_header, tx.count); ivc->tx.channel->tx.state = TEGRA_IVC_STATE_SYNC; tegra_ivc_header_write_field(&ivc->tx.map, tx.state, TEGRA_IVC_STATE_SYNC); tegra_ivc_flush(ivc, ivc->tx.phys + offset); ivc->notify(ivc, ivc->notify_data); } Loading Loading @@ -416,13 +428,14 @@ EXPORT_SYMBOL(tegra_ivc_reset); int tegra_ivc_notified(struct tegra_ivc *ivc) { unsigned int offset = offsetof(struct tegra_ivc_header, tx.count); enum tegra_ivc_state state; enum tegra_ivc_state rx_state, tx_state; /* Copy the receiver's state out of shared memory. */ tegra_ivc_invalidate(ivc, ivc->rx.phys + offset); state = READ_ONCE(ivc->rx.channel->tx.state); rx_state = tegra_ivc_header_read_field(&ivc->rx.map, tx.state); tx_state = tegra_ivc_header_read_field(&ivc->tx.map, tx.state); if (state == TEGRA_IVC_STATE_SYNC) { if (rx_state == TEGRA_IVC_STATE_SYNC) { offset = offsetof(struct tegra_ivc_header, tx.count); /* Loading @@ -436,8 +449,8 @@ int tegra_ivc_notified(struct tegra_ivc *ivc) * state and won't make progress until we change our state, * so the counters are not in use at this time. */ ivc->tx.channel->tx.count = 0; ivc->rx.channel->rx.count = 0; tegra_ivc_header_write_field(&ivc->tx.map, tx.count, 0); tegra_ivc_header_write_field(&ivc->rx.map, rx.count, 0); ivc->tx.position = 0; ivc->rx.position = 0; Loading @@ -452,7 +465,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc) * Move to ACK state. We have just cleared our counters, so it * is now safe for the remote end to start using these values. */ ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ACK; tegra_ivc_header_write_field(&ivc->tx.map, tx.state, TEGRA_IVC_STATE_ACK); tegra_ivc_flush(ivc, ivc->tx.phys + offset); /* Loading @@ -460,8 +473,8 @@ int tegra_ivc_notified(struct tegra_ivc *ivc) */ ivc->notify(ivc, ivc->notify_data); } else if (ivc->tx.channel->tx.state == TEGRA_IVC_STATE_SYNC && state == TEGRA_IVC_STATE_ACK) { } else if (tx_state == TEGRA_IVC_STATE_SYNC && rx_state == TEGRA_IVC_STATE_ACK) { offset = offsetof(struct tegra_ivc_header, tx.count); /* Loading @@ -475,8 +488,8 @@ int tegra_ivc_notified(struct tegra_ivc *ivc) * state and won't make progress until we change our state, * so the counters are not in use at this time. */ ivc->tx.channel->tx.count = 0; ivc->rx.channel->rx.count = 0; tegra_ivc_header_write_field(&ivc->tx.map, tx.count, 0); tegra_ivc_header_write_field(&ivc->rx.map, rx.count, 0); ivc->tx.position = 0; ivc->rx.position = 0; Loading @@ -492,7 +505,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc) * already cleared its counters, so it is safe to start * writing/reading on this channel. */ ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ESTABLISHED; tegra_ivc_header_write_field(&ivc->tx.map, tx.state, TEGRA_IVC_STATE_ESTABLISHED); tegra_ivc_flush(ivc, ivc->tx.phys + offset); /* Loading @@ -500,7 +513,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc) */ ivc->notify(ivc, ivc->notify_data); } else if (ivc->tx.channel->tx.state == TEGRA_IVC_STATE_ACK) { } else if (tx_state == TEGRA_IVC_STATE_ACK) { offset = offsetof(struct tegra_ivc_header, tx.count); /* Loading @@ -516,7 +529,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc) * cleared its counters, so it is safe to start writing/reading * on this channel. */ ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ESTABLISHED; tegra_ivc_header_write_field(&ivc->tx.map, tx.state, TEGRA_IVC_STATE_ESTABLISHED); tegra_ivc_flush(ivc, ivc->tx.phys + offset); /* Loading @@ -533,7 +546,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc) */ } if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED) if (tx_state != TEGRA_IVC_STATE_ESTABLISHED) return -EAGAIN; return 0; Loading Loading @@ -609,8 +622,29 @@ static int tegra_ivc_check_params(unsigned long rx, unsigned long tx, return 0; } 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, static inline void iosys_map_copy(struct iosys_map *dst, const struct iosys_map *src) { *dst = *src; } static inline unsigned long iosys_map_get_address(const struct iosys_map *map) { if (map->is_iomem) return (unsigned long)map->vaddr_iomem; return (unsigned long)map->vaddr; } static inline void *iosys_map_get_vaddr(const struct iosys_map *map) { if (WARN_ON(map->is_iomem)) return NULL; return map->vaddr; } 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) Loading @@ -628,7 +662,7 @@ int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx, if (frame_size > INT_MAX) return -E2BIG; err = tegra_ivc_check_params((unsigned long)rx, (unsigned long)tx, err = tegra_ivc_check_params(iosys_map_get_address(rx), iosys_map_get_address(tx), num_frames, frame_size); if (err < 0) return err; Loading @@ -636,12 +670,12 @@ int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx, queue_size = tegra_ivc_total_queue_size(num_frames * frame_size); if (peer) { ivc->rx.phys = dma_map_single(peer, rx, queue_size, ivc->rx.phys = dma_map_single(peer, iosys_map_get_vaddr(rx), queue_size, DMA_BIDIRECTIONAL); if (dma_mapping_error(peer, ivc->rx.phys)) return -ENOMEM; ivc->tx.phys = dma_map_single(peer, tx, queue_size, ivc->tx.phys = dma_map_single(peer, iosys_map_get_vaddr(tx), queue_size, DMA_BIDIRECTIONAL); if (dma_mapping_error(peer, ivc->tx.phys)) { dma_unmap_single(peer, ivc->rx.phys, queue_size, Loading @@ -653,8 +687,8 @@ int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx, ivc->tx.phys = tx_phys; } ivc->rx.channel = rx; ivc->tx.channel = tx; iosys_map_copy(&ivc->rx.map, rx); iosys_map_copy(&ivc->tx.map, tx); ivc->peer = peer; ivc->notify = notify; ivc->notify_data = data; Loading Loading
drivers/firmware/tegra/bpmp-debugfs.c +29 −33 Original line number Diff line number Diff line Loading @@ -48,13 +48,9 @@ static int seqbuf_read(struct seqbuf *seqbuf, void *buf, size_t nbyte) return seqbuf_status(seqbuf); } static int seqbuf_read_u32(struct seqbuf *seqbuf, uint32_t *v) static int seqbuf_read_u32(struct seqbuf *seqbuf, u32 *v) { int err; err = seqbuf_read(seqbuf, v, 4); *v = le32_to_cpu(*v); return err; return seqbuf_read(seqbuf, v, 4); } static int seqbuf_read_str(struct seqbuf *seqbuf, const char **str) Loading Loading @@ -109,10 +105,10 @@ static const char *get_filename(struct tegra_bpmp *bpmp, } static int mrq_debug_open(struct tegra_bpmp *bpmp, const char *name, uint32_t *fd, uint32_t *len, bool write) u32 *fd, u32 *len, bool write) { struct mrq_debug_request req = { .cmd = cpu_to_le32(write ? CMD_DEBUG_OPEN_WO : CMD_DEBUG_OPEN_RO), .cmd = write ? CMD_DEBUG_OPEN_WO : CMD_DEBUG_OPEN_RO, }; struct mrq_debug_response resp; struct tegra_bpmp_message msg = { Loading Loading @@ -147,10 +143,10 @@ static int mrq_debug_open(struct tegra_bpmp *bpmp, const char *name, return 0; } static int mrq_debug_close(struct tegra_bpmp *bpmp, uint32_t fd) static int mrq_debug_close(struct tegra_bpmp *bpmp, u32 fd) { struct mrq_debug_request req = { .cmd = cpu_to_le32(CMD_DEBUG_CLOSE), .cmd = CMD_DEBUG_CLOSE, .frd = { .fd = fd, }, Loading Loading @@ -179,10 +175,10 @@ static int mrq_debug_close(struct tegra_bpmp *bpmp, uint32_t fd) } static int mrq_debug_read(struct tegra_bpmp *bpmp, const char *name, char *data, size_t sz_data, uint32_t *nbytes) char *data, size_t sz_data, u32 *nbytes) { struct mrq_debug_request req = { .cmd = cpu_to_le32(CMD_DEBUG_READ), .cmd = CMD_DEBUG_READ, }; struct mrq_debug_response resp; struct tegra_bpmp_message msg = { Loading @@ -196,7 +192,7 @@ static int mrq_debug_read(struct tegra_bpmp *bpmp, const char *name, .size = sizeof(resp), }, }; uint32_t fd = 0, len = 0; u32 fd = 0, len = 0; int remaining, err; mutex_lock(&bpmp_debug_lock); Loading Loading @@ -245,7 +241,7 @@ static int mrq_debug_write(struct tegra_bpmp *bpmp, const char *name, uint8_t *data, size_t sz_data) { struct mrq_debug_request req = { .cmd = cpu_to_le32(CMD_DEBUG_WRITE) .cmd = CMD_DEBUG_WRITE }; struct mrq_debug_response resp; struct tegra_bpmp_message msg = { Loading @@ -259,7 +255,7 @@ static int mrq_debug_write(struct tegra_bpmp *bpmp, const char *name, .size = sizeof(resp), }, }; uint32_t fd = 0, len = 0; u32 fd = 0, len = 0; size_t remaining; int err; Loading Loading @@ -308,7 +304,7 @@ static int bpmp_debug_show(struct seq_file *m, void *p) char fnamebuf[256]; const char *filename; struct mrq_debug_request req = { .cmd = cpu_to_le32(CMD_DEBUG_READ), .cmd = CMD_DEBUG_READ, }; struct mrq_debug_response resp; struct tegra_bpmp_message msg = { Loading @@ -322,7 +318,7 @@ static int bpmp_debug_show(struct seq_file *m, void *p) .size = sizeof(resp), }, }; uint32_t fd = 0, len = 0; u32 fd = 0, len = 0; int remaining, err; filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf)); Loading Loading @@ -406,8 +402,8 @@ static int bpmp_populate_debugfs_inband(struct tegra_bpmp *bpmp, { const size_t pathlen = SZ_256; const size_t bufsize = SZ_16K; uint32_t dsize, attrs = 0; struct dentry *dentry; u32 dsize, attrs = 0; struct seqbuf seqbuf; char *buf, *pathbuf; const char *name; Loading Loading @@ -487,12 +483,12 @@ static int mrq_debugfs_read(struct tegra_bpmp *bpmp, size_t *nbytes) { struct mrq_debugfs_request req = { .cmd = cpu_to_le32(CMD_DEBUGFS_READ), .cmd = CMD_DEBUGFS_READ, .fop = { .fnameaddr = cpu_to_le32((uint32_t)name), .fnamelen = cpu_to_le32((uint32_t)sz_name), .dataaddr = cpu_to_le32((uint32_t)data), .datalen = cpu_to_le32((uint32_t)sz_data), .fnameaddr = (u32)name, .fnamelen = (u32)sz_name, .dataaddr = (u32)data, .datalen = (u32)sz_data, }, }; struct mrq_debugfs_response resp; Loading Loading @@ -525,12 +521,12 @@ static int mrq_debugfs_write(struct tegra_bpmp *bpmp, dma_addr_t data, size_t sz_data) { const struct mrq_debugfs_request req = { .cmd = cpu_to_le32(CMD_DEBUGFS_WRITE), .cmd = CMD_DEBUGFS_WRITE, .fop = { .fnameaddr = cpu_to_le32((uint32_t)name), .fnamelen = cpu_to_le32((uint32_t)sz_name), .dataaddr = cpu_to_le32((uint32_t)data), .datalen = cpu_to_le32((uint32_t)sz_data), .fnameaddr = (u32)name, .fnamelen = (u32)sz_name, .dataaddr = (u32)data, .datalen = (u32)sz_data, }, }; struct tegra_bpmp_message msg = { Loading @@ -548,10 +544,10 @@ static int mrq_debugfs_dumpdir(struct tegra_bpmp *bpmp, dma_addr_t addr, size_t size, size_t *nbytes) { const struct mrq_debugfs_request req = { .cmd = cpu_to_le32(CMD_DEBUGFS_DUMPDIR), .cmd = CMD_DEBUGFS_DUMPDIR, .dumpdir = { .dataaddr = cpu_to_le32((uint32_t)addr), .datalen = cpu_to_le32((uint32_t)size), .dataaddr = (u32)addr, .datalen = (u32)size, }, }; struct mrq_debugfs_response resp; Loading Loading @@ -688,10 +684,10 @@ static const struct file_operations debugfs_fops = { }; static int bpmp_populate_dir(struct tegra_bpmp *bpmp, struct seqbuf *seqbuf, struct dentry *parent, uint32_t depth) struct dentry *parent, u32 depth) { int err; uint32_t d, t; u32 d, t; const char *name; struct dentry *dentry; Loading
drivers/firmware/tegra/bpmp-tegra186.c +17 −19 Original line number Diff line number Diff line Loading @@ -18,8 +18,8 @@ struct tegra186_bpmp { struct { struct gen_pool *pool; void __iomem *virt; dma_addr_t phys; void *virt; } tx, rx; struct { Loading @@ -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; } Loading Loading @@ -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; Loading @@ -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", Loading Loading @@ -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; Loading @@ -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; Loading
drivers/firmware/tegra/bpmp-tegra210.c +4 −3 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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; Loading
drivers/firmware/tegra/bpmp.c +18 −15 Original line number Diff line number Diff line Loading @@ -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; } Loading Loading @@ -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); } Loading Loading @@ -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; Loading @@ -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)) Loading Loading @@ -502,7 +502,7 @@ EXPORT_SYMBOL_GPL(tegra_bpmp_free_mrq); bool tegra_bpmp_mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq) { struct mrq_query_abi_request req = { .mrq = cpu_to_le32(mrq) }; struct mrq_query_abi_request req = { .mrq = mrq }; struct mrq_query_abi_response resp; struct tegra_bpmp_message msg = { .mrq = MRQ_QUERY_ABI, Loading @@ -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)); } Loading Loading @@ -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; Loading @@ -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); Loading
drivers/firmware/tegra/ivc.c +92 −58 Original line number Diff line number Diff line Loading @@ -68,6 +68,12 @@ struct tegra_ivc_header { } rx; }; #define tegra_ivc_header_read_field(hdr, field) \ iosys_map_rd_field(hdr, 0, struct tegra_ivc_header, field) #define tegra_ivc_header_write_field(hdr, field, value) \ iosys_map_wr_field(hdr, 0, struct tegra_ivc_header, field, value) static inline void tegra_ivc_invalidate(struct tegra_ivc *ivc, dma_addr_t phys) { if (!ivc->peer) Loading @@ -86,16 +92,15 @@ static inline void tegra_ivc_flush(struct tegra_ivc *ivc, dma_addr_t phys) DMA_TO_DEVICE); } static inline bool tegra_ivc_empty(struct tegra_ivc *ivc, struct tegra_ivc_header *header) static inline bool tegra_ivc_empty(struct tegra_ivc *ivc, struct iosys_map *map) { /* * This function performs multiple checks on the same values with * security implications, so create snapshots with READ_ONCE() to * ensure that these checks use the same values. */ u32 tx = READ_ONCE(header->tx.count); u32 rx = READ_ONCE(header->rx.count); u32 tx = tegra_ivc_header_read_field(map, tx.count); u32 rx = tegra_ivc_header_read_field(map, rx.count); /* * Perform an over-full check to prevent denial of service attacks Loading @@ -113,11 +118,10 @@ static inline bool tegra_ivc_empty(struct tegra_ivc *ivc, return tx == rx; } static inline bool tegra_ivc_full(struct tegra_ivc *ivc, struct tegra_ivc_header *header) static inline bool tegra_ivc_full(struct tegra_ivc *ivc, struct iosys_map *map) { u32 tx = READ_ONCE(header->tx.count); u32 rx = READ_ONCE(header->rx.count); u32 tx = tegra_ivc_header_read_field(map, tx.count); u32 rx = tegra_ivc_header_read_field(map, rx.count); /* * Invalid cases where the counters indicate that the queue is over Loading @@ -126,11 +130,10 @@ static inline bool tegra_ivc_full(struct tegra_ivc *ivc, return tx - rx >= ivc->num_frames; } static inline u32 tegra_ivc_available(struct tegra_ivc *ivc, struct tegra_ivc_header *header) static inline u32 tegra_ivc_available(struct tegra_ivc *ivc, struct iosys_map *map) { u32 tx = READ_ONCE(header->tx.count); u32 rx = READ_ONCE(header->rx.count); u32 tx = tegra_ivc_header_read_field(map, tx.count); u32 rx = tegra_ivc_header_read_field(map, rx.count); /* * This function isn't expected to be used in scenarios where an Loading @@ -143,8 +146,9 @@ static inline u32 tegra_ivc_available(struct tegra_ivc *ivc, static inline void tegra_ivc_advance_tx(struct tegra_ivc *ivc) { WRITE_ONCE(ivc->tx.channel->tx.count, READ_ONCE(ivc->tx.channel->tx.count) + 1); unsigned int count = tegra_ivc_header_read_field(&ivc->tx.map, tx.count); tegra_ivc_header_write_field(&ivc->tx.map, tx.count, count + 1); if (ivc->tx.position == ivc->num_frames - 1) ivc->tx.position = 0; Loading @@ -154,8 +158,9 @@ static inline void tegra_ivc_advance_tx(struct tegra_ivc *ivc) static inline void tegra_ivc_advance_rx(struct tegra_ivc *ivc) { WRITE_ONCE(ivc->rx.channel->rx.count, READ_ONCE(ivc->rx.channel->rx.count) + 1); unsigned int count = tegra_ivc_header_read_field(&ivc->rx.map, rx.count); tegra_ivc_header_write_field(&ivc->rx.map, rx.count, count + 1); if (ivc->rx.position == ivc->num_frames - 1) ivc->rx.position = 0; Loading @@ -166,6 +171,7 @@ static inline void tegra_ivc_advance_rx(struct tegra_ivc *ivc) static inline int tegra_ivc_check_read(struct tegra_ivc *ivc) { unsigned int offset = offsetof(struct tegra_ivc_header, tx.count); unsigned int state; /* * tx.channel->state is set locally, so it is not synchronized with Loading @@ -175,7 +181,8 @@ static inline int tegra_ivc_check_read(struct tegra_ivc *ivc) * asynchronous transition of rx.channel->state to * TEGRA_IVC_STATE_ACK is not allowed. */ if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED) state = tegra_ivc_header_read_field(&ivc->tx.map, tx.state); if (state != TEGRA_IVC_STATE_ESTABLISHED) return -ECONNRESET; /* Loading @@ -185,12 +192,12 @@ static inline int tegra_ivc_check_read(struct tegra_ivc *ivc) * Synchronization is only necessary when these pointers indicate * empty or full. */ if (!tegra_ivc_empty(ivc, ivc->rx.channel)) if (!tegra_ivc_empty(ivc, &ivc->rx.map)) return 0; tegra_ivc_invalidate(ivc, ivc->rx.phys + offset); if (tegra_ivc_empty(ivc, ivc->rx.channel)) if (tegra_ivc_empty(ivc, &ivc->rx.map)) return -ENOSPC; return 0; Loading @@ -199,29 +206,34 @@ static inline int tegra_ivc_check_read(struct tegra_ivc *ivc) static inline int tegra_ivc_check_write(struct tegra_ivc *ivc) { unsigned int offset = offsetof(struct tegra_ivc_header, rx.count); unsigned int state; if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED) state = tegra_ivc_header_read_field(&ivc->tx.map, tx.state); if (state != TEGRA_IVC_STATE_ESTABLISHED) return -ECONNRESET; if (!tegra_ivc_full(ivc, ivc->tx.channel)) if (!tegra_ivc_full(ivc, &ivc->tx.map)) return 0; tegra_ivc_invalidate(ivc, ivc->tx.phys + offset); if (tegra_ivc_full(ivc, ivc->tx.channel)) if (tegra_ivc_full(ivc, &ivc->tx.map)) return -ENOSPC; return 0; } static void *tegra_ivc_frame_virt(struct tegra_ivc *ivc, struct tegra_ivc_header *header, unsigned int frame) static int tegra_ivc_frame_virt(struct tegra_ivc *ivc, const struct iosys_map *header, unsigned int frame, struct iosys_map *map) { size_t offset = sizeof(struct tegra_ivc_header) + ivc->frame_size * frame; if (WARN_ON(frame >= ivc->num_frames)) return ERR_PTR(-EINVAL); return -EINVAL; *map = IOSYS_MAP_INIT_OFFSET(header, offset); return (void *)(header + 1) + ivc->frame_size * frame; return 0; } static inline dma_addr_t tegra_ivc_frame_phys(struct tegra_ivc *ivc, Loading Loading @@ -264,16 +276,16 @@ static inline void tegra_ivc_flush_frame(struct tegra_ivc *ivc, } /* directly peek at the next frame rx'ed */ 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) { int err; if (WARN_ON(ivc == NULL)) return ERR_PTR(-EINVAL); return -EINVAL; err = tegra_ivc_check_read(ivc); if (err < 0) return ERR_PTR(err); return err; /* * Order observation of ivc->rx.position potentially indicating new Loading @@ -284,7 +296,7 @@ void *tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc) tegra_ivc_invalidate_frame(ivc, ivc->rx.phys, ivc->rx.position, 0, ivc->frame_size); return tegra_ivc_frame_virt(ivc, ivc->rx.channel, ivc->rx.position); return tegra_ivc_frame_virt(ivc, &ivc->rx.map, ivc->rx.position, map); } EXPORT_SYMBOL(tegra_ivc_read_get_next_frame); Loading Loading @@ -320,7 +332,7 @@ int tegra_ivc_read_advance(struct tegra_ivc *ivc) */ tegra_ivc_invalidate(ivc, ivc->rx.phys + tx); if (tegra_ivc_available(ivc, ivc->rx.channel) == ivc->num_frames - 1) if (tegra_ivc_available(ivc, &ivc->rx.map) == ivc->num_frames - 1) ivc->notify(ivc, ivc->notify_data); return 0; Loading @@ -328,15 +340,15 @@ int tegra_ivc_read_advance(struct tegra_ivc *ivc) EXPORT_SYMBOL(tegra_ivc_read_advance); /* directly poke at the next frame to be tx'ed */ 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) { int err; err = tegra_ivc_check_write(ivc); if (err < 0) return ERR_PTR(err); return err; return tegra_ivc_frame_virt(ivc, ivc->tx.channel, ivc->tx.position); return tegra_ivc_frame_virt(ivc, &ivc->tx.map, ivc->tx.position, map); } EXPORT_SYMBOL(tegra_ivc_write_get_next_frame); Loading Loading @@ -376,7 +388,7 @@ int tegra_ivc_write_advance(struct tegra_ivc *ivc) */ tegra_ivc_invalidate(ivc, ivc->tx.phys + rx); if (tegra_ivc_available(ivc, ivc->tx.channel) == 1) if (tegra_ivc_available(ivc, &ivc->tx.map) == 1) ivc->notify(ivc, ivc->notify_data); return 0; Loading @@ -387,7 +399,7 @@ void tegra_ivc_reset(struct tegra_ivc *ivc) { unsigned int offset = offsetof(struct tegra_ivc_header, tx.count); ivc->tx.channel->tx.state = TEGRA_IVC_STATE_SYNC; tegra_ivc_header_write_field(&ivc->tx.map, tx.state, TEGRA_IVC_STATE_SYNC); tegra_ivc_flush(ivc, ivc->tx.phys + offset); ivc->notify(ivc, ivc->notify_data); } Loading Loading @@ -416,13 +428,14 @@ EXPORT_SYMBOL(tegra_ivc_reset); int tegra_ivc_notified(struct tegra_ivc *ivc) { unsigned int offset = offsetof(struct tegra_ivc_header, tx.count); enum tegra_ivc_state state; enum tegra_ivc_state rx_state, tx_state; /* Copy the receiver's state out of shared memory. */ tegra_ivc_invalidate(ivc, ivc->rx.phys + offset); state = READ_ONCE(ivc->rx.channel->tx.state); rx_state = tegra_ivc_header_read_field(&ivc->rx.map, tx.state); tx_state = tegra_ivc_header_read_field(&ivc->tx.map, tx.state); if (state == TEGRA_IVC_STATE_SYNC) { if (rx_state == TEGRA_IVC_STATE_SYNC) { offset = offsetof(struct tegra_ivc_header, tx.count); /* Loading @@ -436,8 +449,8 @@ int tegra_ivc_notified(struct tegra_ivc *ivc) * state and won't make progress until we change our state, * so the counters are not in use at this time. */ ivc->tx.channel->tx.count = 0; ivc->rx.channel->rx.count = 0; tegra_ivc_header_write_field(&ivc->tx.map, tx.count, 0); tegra_ivc_header_write_field(&ivc->rx.map, rx.count, 0); ivc->tx.position = 0; ivc->rx.position = 0; Loading @@ -452,7 +465,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc) * Move to ACK state. We have just cleared our counters, so it * is now safe for the remote end to start using these values. */ ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ACK; tegra_ivc_header_write_field(&ivc->tx.map, tx.state, TEGRA_IVC_STATE_ACK); tegra_ivc_flush(ivc, ivc->tx.phys + offset); /* Loading @@ -460,8 +473,8 @@ int tegra_ivc_notified(struct tegra_ivc *ivc) */ ivc->notify(ivc, ivc->notify_data); } else if (ivc->tx.channel->tx.state == TEGRA_IVC_STATE_SYNC && state == TEGRA_IVC_STATE_ACK) { } else if (tx_state == TEGRA_IVC_STATE_SYNC && rx_state == TEGRA_IVC_STATE_ACK) { offset = offsetof(struct tegra_ivc_header, tx.count); /* Loading @@ -475,8 +488,8 @@ int tegra_ivc_notified(struct tegra_ivc *ivc) * state and won't make progress until we change our state, * so the counters are not in use at this time. */ ivc->tx.channel->tx.count = 0; ivc->rx.channel->rx.count = 0; tegra_ivc_header_write_field(&ivc->tx.map, tx.count, 0); tegra_ivc_header_write_field(&ivc->rx.map, rx.count, 0); ivc->tx.position = 0; ivc->rx.position = 0; Loading @@ -492,7 +505,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc) * already cleared its counters, so it is safe to start * writing/reading on this channel. */ ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ESTABLISHED; tegra_ivc_header_write_field(&ivc->tx.map, tx.state, TEGRA_IVC_STATE_ESTABLISHED); tegra_ivc_flush(ivc, ivc->tx.phys + offset); /* Loading @@ -500,7 +513,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc) */ ivc->notify(ivc, ivc->notify_data); } else if (ivc->tx.channel->tx.state == TEGRA_IVC_STATE_ACK) { } else if (tx_state == TEGRA_IVC_STATE_ACK) { offset = offsetof(struct tegra_ivc_header, tx.count); /* Loading @@ -516,7 +529,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc) * cleared its counters, so it is safe to start writing/reading * on this channel. */ ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ESTABLISHED; tegra_ivc_header_write_field(&ivc->tx.map, tx.state, TEGRA_IVC_STATE_ESTABLISHED); tegra_ivc_flush(ivc, ivc->tx.phys + offset); /* Loading @@ -533,7 +546,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc) */ } if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED) if (tx_state != TEGRA_IVC_STATE_ESTABLISHED) return -EAGAIN; return 0; Loading Loading @@ -609,8 +622,29 @@ static int tegra_ivc_check_params(unsigned long rx, unsigned long tx, return 0; } 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, static inline void iosys_map_copy(struct iosys_map *dst, const struct iosys_map *src) { *dst = *src; } static inline unsigned long iosys_map_get_address(const struct iosys_map *map) { if (map->is_iomem) return (unsigned long)map->vaddr_iomem; return (unsigned long)map->vaddr; } static inline void *iosys_map_get_vaddr(const struct iosys_map *map) { if (WARN_ON(map->is_iomem)) return NULL; return map->vaddr; } 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) Loading @@ -628,7 +662,7 @@ int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx, if (frame_size > INT_MAX) return -E2BIG; err = tegra_ivc_check_params((unsigned long)rx, (unsigned long)tx, err = tegra_ivc_check_params(iosys_map_get_address(rx), iosys_map_get_address(tx), num_frames, frame_size); if (err < 0) return err; Loading @@ -636,12 +670,12 @@ int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx, queue_size = tegra_ivc_total_queue_size(num_frames * frame_size); if (peer) { ivc->rx.phys = dma_map_single(peer, rx, queue_size, ivc->rx.phys = dma_map_single(peer, iosys_map_get_vaddr(rx), queue_size, DMA_BIDIRECTIONAL); if (dma_mapping_error(peer, ivc->rx.phys)) return -ENOMEM; ivc->tx.phys = dma_map_single(peer, tx, queue_size, ivc->tx.phys = dma_map_single(peer, iosys_map_get_vaddr(tx), queue_size, DMA_BIDIRECTIONAL); if (dma_mapping_error(peer, ivc->tx.phys)) { dma_unmap_single(peer, ivc->rx.phys, queue_size, Loading @@ -653,8 +687,8 @@ int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx, ivc->tx.phys = tx_phys; } ivc->rx.channel = rx; ivc->tx.channel = tx; iosys_map_copy(&ivc->rx.map, rx); iosys_map_copy(&ivc->tx.map, tx); ivc->peer = peer; ivc->notify = notify; ivc->notify_data = data; Loading