libtx2bpmp: Change BPMP public interface The BPMP interface was a little unique in that it did not follow the structure of similar interfaces like those in libplatsupport where there are function pointers with space to place a pointer to private data. This presents integration issues with the interface registration service in libplatsupport. Hence, this commit adapts the BPMP public interface so that it makes it easier to work with the interface registration service.
diff --git a/libtx2bpmp/include/tx2bpmp/bpmp.h b/libtx2bpmp/include/tx2bpmp/bpmp.h index a6575ff..df83ed5 100644 --- a/libtx2bpmp/include/tx2bpmp/bpmp.h +++ b/libtx2bpmp/include/tx2bpmp/bpmp.h
@@ -26,6 +26,7 @@ #include <platsupport/io.h> #include <tx2bpmp/hsp.h> #include <tx2bpmp/ivc.h> +#include <utils/util.h> #ifndef __ABI_PACKED #define __ABI_PACKED __attribute__((packed)) @@ -51,9 +52,17 @@ #define TX2_BPMP_RX_SHMEM_PADDR 0x3004f000 #define TX2_BPMP_RX_SHMEM_SIZE 0x1000 -/* Forward declare the tx2_bpmp struct, this struct is private to the bpmp - * source file. */ -struct tx2_bpmp; +#define __BPMP_CHECK_ARGS(function) \ + do { \ + if (!bpmp) { ZF_LOGE("bpmp is NULL"); return -EINVAL; } \ + if (!function) { ZF_LOGE(#function " not implemented"); return -ENOSYS; } \ + } while(0) + +struct tx2_bpmp { + void *data; + int (*call)(void *data, int mrq, void *tx_msg, size_t tx_size, void *rx_msg, size_t rx_size); + int (*destroy)(void *data); +}; /* * Initialises the BPMP interfaces. @@ -63,17 +72,20 @@ * * @return 0 on success, otherwise an error code. */ -int tx2_bpmp_init(ps_io_ops_t *io_ops, struct tx2_bpmp **bpmp); +int tx2_bpmp_init(ps_io_ops_t *io_ops, struct tx2_bpmp *bpmp); /* * Destroys an initialised BPMP interface. * - * @param io_ops The same IO ops interface that was used to initialise the BPMP interface. - * @param bpmp Initialise BPMP interface that will be destroyed. + * @param bpmp Initialised BPMP interface that will be destroyed. * * @return 0 on success, otherwise an error code. */ -int tx2_bpmp_destroy(ps_io_ops_t *io_ops, struct tx2_bpmp *bpmp); +static inline int tx2_bpmp_destroy(struct tx2_bpmp *bpmp) +{ + __BPMP_CHECK_ARGS(bpmp->destroy); + return bpmp->destroy(bpmp->data); +} /* * Sends a request to the BPMP device module and waits for a response. @@ -87,7 +99,12 @@ * for the valid response layouts. * @param rx_size Size in bytes of the response buffer. */ -int tx2_bpmp_call(struct tx2_bpmp *bpmp, int mrq, void *tx_msg, size_t tx_size, void *rx_msg, size_t rx_size); +static inline int tx2_bpmp_call(struct tx2_bpmp *bpmp, int mrq, void *tx_msg, size_t tx_size, void *rx_msg, + size_t rx_size) +{ + __BPMP_CHECK_ARGS(bpmp->call); + return bpmp->call(bpmp->data, mrq, tx_msg, tx_size, rx_msg, rx_size); +} /** * @defgroup MRQ MRQ Messages
diff --git a/libtx2bpmp/src/bpmp.c b/libtx2bpmp/src/bpmp.c index b474fbf..ef6fab1 100644 --- a/libtx2bpmp/src/bpmp.c +++ b/libtx2bpmp/src/bpmp.c
@@ -37,7 +37,8 @@ #define TIMEOUT_THRESHOLD 2000000ul -struct tx2_bpmp { +struct tx2_bpmp_priv { + ps_io_ops_t *io_ops; tx2_hsp_t hsp; bool hsp_initialised; struct tegra_ivc ivc; @@ -60,9 +61,9 @@ static bool bpmp_initialised = false; static unsigned int bpmp_refcount = 0; -static struct tx2_bpmp bpmp_data = {0}; +static struct tx2_bpmp_priv bpmp_data = {0}; -int tx2_bpmp_call(struct tx2_bpmp *bpmp, int mrq, void *tx_msg, size_t tx_size, void *rx_msg, size_t rx_size) +static int bpmp_call(void *data, int mrq, void *tx_msg, size_t tx_size, void *rx_msg, size_t rx_size) { int ret, err; void *ivc_frame; @@ -70,10 +71,12 @@ struct mrq_response *resp; unsigned long timeout = TIMEOUT_THRESHOLD; + struct tx2_bpmp_priv *bpmp_priv = data; + if ((tx_size > BPMP_IVC_FRAME_SIZE) || (rx_size > BPMP_IVC_FRAME_SIZE)) return -EINVAL; - ret = tegra_ivc_write_get_next_frame(&bpmp->ivc, &ivc_frame); + ret = tegra_ivc_write_get_next_frame(&bpmp_priv->ivc, &ivc_frame); if (ret) { ZF_LOGE("tegra_ivc_write_get_next_frame() failed: %d\n", ret); return ret; @@ -84,20 +87,20 @@ req->flags = BPMP_FLAG_DO_ACK | BPMP_FLAG_RING_DOORBELL; memcpy(req + 1, tx_msg, tx_size); - ret = tegra_ivc_write_advance(&bpmp->ivc); + ret = tegra_ivc_write_advance(&bpmp_priv->ivc); if (ret) { ZF_LOGE("tegra_ivc_write_advance() failed: %d\n", ret); return ret; } for (; timeout > 0; timeout--) { - ret = tegra_ivc_channel_notified(&bpmp->ivc); + ret = tegra_ivc_channel_notified(&bpmp_priv->ivc); if (ret) { ZF_LOGE("tegra_ivc_channel_notified() failed: %d\n", ret); return ret; } - ret = tegra_ivc_read_get_next_frame(&bpmp->ivc, &ivc_frame); + ret = tegra_ivc_read_get_next_frame(&bpmp_priv->ivc, &ivc_frame); if (!ret) break; } @@ -112,7 +115,7 @@ if (!err && rx_msg && rx_size) memcpy(rx_msg, resp + 1, rx_size); - ret = tegra_ivc_read_advance(&bpmp->ivc); + ret = tegra_ivc_read_advance(&bpmp_priv->ivc); if (ret) { ZF_LOGE("tegra_ivc_write_advance() failed: %d\n", ret); return ret; @@ -127,17 +130,45 @@ return rx_size; } -static void tx2_bpmp_ivc_notify(struct tegra_ivc *ivc, void *token) +static void bpmp_ivc_notify(struct tegra_ivc *ivc, void *token) { - struct tx2_bpmp *bpmp = token; + struct tx2_bpmp_priv *bpmp_priv = token; int ret; - ret = tx2_hsp_doorbell_ring(&bpmp->hsp, BPMP_DBELL); + ret = tx2_hsp_doorbell_ring(&bpmp_priv->hsp, BPMP_DBELL); if (ret) ZF_LOGF("Failed to ring BPMP's doorbell in the HSP: %d\n", ret); } -int tx2_bpmp_init(ps_io_ops_t *io_ops, struct tx2_bpmp **bpmp) +static int bpmp_destroy(void *data) +{ + struct tx2_bpmp_priv *bpmp_priv = data; + + bpmp_refcount--; + + if (bpmp_refcount != 0) { + /* Only cleanup the BPMP structure if there are no more references that are valid. */ + return 0; + } + + if (bpmp_priv->hsp_initialised) { + ZF_LOGF_IF(tx2_hsp_destroy(&bpmp_priv->hsp), + "Failed to clean up after a failed BPMP initialisation process!"); + } + + /* Unmapping the shared memory also destroys the IVC */ + if (bpmp_priv->tx_base) { + ps_io_unmap(&bpmp_priv->io_ops->io_mapper, bpmp_priv->tx_base, bpmp_shmems[TX_SHMEM].length); + } + + if (bpmp_priv->rx_base) { + ps_io_unmap(&bpmp_priv->io_ops->io_mapper, bpmp_priv->rx_base, bpmp_shmems[RX_SHMEM].length); + } + + return 0; +} + +int tx2_bpmp_init(ps_io_ops_t *io_ops, struct tx2_bpmp *bpmp) { if (!io_ops || !bpmp) { ZF_LOGE("Arguments are NULL!"); @@ -145,11 +176,9 @@ } if (bpmp_initialised) { - /* If we've initialised the BPMP once, just return the initialised - * structure */ - *bpmp = &bpmp_data; - bpmp_refcount++; - return 0; + /* If we've initialised the BPMP once, just fill the private data with + * what we've initialised */ + goto success; } int ret = 0; @@ -162,6 +191,8 @@ return ret; } + bpmp_data.io_ops = io_ops; + bpmp_data.hsp_initialised = true; bpmp_data.tx_base = ps_pmem_map(io_ops, bpmp_shmems[TX_SHMEM], false, PS_MEM_NORMAL); @@ -179,7 +210,7 @@ } ret = tegra_ivc_init(&bpmp_data.ivc, (unsigned long) bpmp_data.rx_base, (unsigned long) bpmp_data.tx_base, - BPMP_IVC_FRAME_COUNT, BPMP_IVC_FRAME_SIZE, tx2_bpmp_ivc_notify, (void *) &bpmp_data); + BPMP_IVC_FRAME_COUNT, BPMP_IVC_FRAME_SIZE, bpmp_ivc_notify, (void *) &bpmp_data); if (ret) { ZF_LOGE("tegra_ivc_init() failed: %d", ret); goto fail; @@ -199,44 +230,19 @@ goto fail; } - *bpmp = &bpmp_data; +success: bpmp_refcount++; + + bpmp->data = &bpmp_data; + bpmp->call = bpmp_call; + bpmp->destroy = bpmp_destroy; bpmp_initialised = true; return 0; fail: - ZF_LOGF_IF(tx2_bpmp_destroy(io_ops, &bpmp_data), "Failed to cleanup the BPMP after a failed initialisation"); + ZF_LOGF_IF(bpmp_destroy(&bpmp_data), "Failed to cleanup the BPMP after a failed initialisation"); return ret; } -int tx2_bpmp_destroy(ps_io_ops_t *io_ops, struct tx2_bpmp *bpmp) -{ - if (io_ops || bpmp) { - ZF_LOGE("Invalid arguments!"); - return -EINVAL; - } - bpmp_refcount--; - - if (bpmp_refcount != 0) { - /* Only cleanup the BPMP structure if there are no more references that are valid. */ - return 0; - } - - if (bpmp_data.hsp_initialised) { - ZF_LOGF_IF(tx2_hsp_destroy(io_ops, &bpmp_data.hsp), - "Failed to clean up after a failed BPMP initialisation process!"); - } - - /* Unmapping the shared memory also destroys the IVC */ - if (bpmp_data.tx_base) { - ps_io_unmap(&io_ops->io_mapper, bpmp_data.tx_base, bpmp_shmems[TX_SHMEM].length); - } - - if (bpmp_data.rx_base) { - ps_io_unmap(&io_ops->io_mapper, bpmp_data.tx_base, bpmp_shmems[RX_SHMEM].length); - } - - return 0; -}