summaryrefslogtreecommitdiffstats
path: root/drivers/platform/tegra
diff options
context:
space:
mode:
authorMantravadi Karthik <mkarthik@nvidia.com>2021-05-20 13:19:26 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2021-06-02 16:39:07 -0400
commitd9ca6d86e9a96e966a111ff1edd421c095b14ffa (patch)
treece033b0f26695edec95520be0c65589f9ee32052 /drivers/platform/tegra
parent28114d7d9fc9192a827c0daed4199f6f0a724b3c (diff)
tegra: safety-ivc: Add support for HB CMD
Why? L2SS expects a heartbeat ping every 40ms. CCPLEX is expected to write the Boot status in the IVC channel for the first time and the consective pings will be just to send Alive check. How? Create a new callback API for the HB command which fills the bit fields for the HB data and sends it over the cmd-resp IVC channel. * Added mutex lock support for l1ss_cmd_resp_send_frame for syncronizing the ivc writes. * Waiting for empty interrupts hogs the system. Time critical features such as HB fail while waiting for empty interrupts. Hence, removing the HSP SM empty isr support. Bug 200700400 Change-Id: I7f124c9f7336df9d387536aa3f2dda80d9234db8 Signed-off-by: Mantravadi Karthik <mkarthik@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2519655 Tested-by: mobile promotions <svcmobile_promotions@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/platform/tegra')
-rw-r--r--drivers/platform/tegra/tegra-safety-ivc.c81
-rw-r--r--drivers/platform/tegra/tegra_l1ss.c64
-rw-r--r--drivers/platform/tegra/tegra_l1ss.h24
-rw-r--r--drivers/platform/tegra/tegra_l1ss_cmd_resp_exec_config.h2
-rw-r--r--drivers/platform/tegra/tegra_l1ss_cmd_resp_l2_interface.c102
-rw-r--r--drivers/platform/tegra/tegra_l1ss_cmd_resp_l2_interface.h4
-rw-r--r--drivers/platform/tegra/tegra_l1ss_heartbeat.h217
7 files changed, 410 insertions, 84 deletions
diff --git a/drivers/platform/tegra/tegra-safety-ivc.c b/drivers/platform/tegra/tegra-safety-ivc.c
index 85bbd8bfd..d468639d9 100644
--- a/drivers/platform/tegra/tegra-safety-ivc.c
+++ b/drivers/platform/tegra/tegra-safety-ivc.c
@@ -29,7 +29,6 @@
29#include "tegra_l1ss.h" 29#include "tegra_l1ss.h"
30 30
31#define NV(p) "nvidia," #p 31#define NV(p) "nvidia," #p
32#define TEGRA_SAFETY_IVC_READ_TIMEOUT 2 * HZ
33 32
34int ivc_chan_count; 33int ivc_chan_count;
35struct tegra_safety_ivc_chan *tegra_safety_get_ivc_chan_from_str( 34struct tegra_safety_ivc_chan *tegra_safety_get_ivc_chan_from_str(
@@ -60,18 +59,29 @@ static void tegra_safety_decode_cmd_resp(struct tegra_safety_ivc *safety_ivc)
60 } 59 }
61 60
62 ivc = &ivc_ch->ivc; 61 ivc = &ivc_ch->ivc;
63 if (tegra_ivc_can_read(ivc)) { 62 mutex_lock(&safety_ivc->rlock);
64 pr_err("%s: Reading IVC channel\n", __func__); 63 if (tegra_ivc_can_read(ivc))
65 ivc_frame = tegra_ivc_read_get_next_frame(ivc); 64 ivc_frame = tegra_ivc_read_get_next_frame(ivc);
66 if (ivc_frame == NULL) 65 mutex_unlock(&safety_ivc->rlock);
67 pr_err("%s: No IVC frame to read\n", __func__);
68 66
69 memcpy(cmd_resp, ivc_frame, sizeof(cmdresp_frame_ex_t)); 67 if (ivc_frame == NULL) {
70 68 pr_err("%s: No IVC frame to read\n", __func__);
71 tegra_ivc_read_advance(ivc); 69 return;
72 tegra_safety_handle_cmd((cmdresp_frame_ex_t *)&cmd_resp,
73 safety_ivc->ldata);
74 } 70 }
71
72 memcpy(cmd_resp, ivc_frame, sizeof(cmdresp_frame_ex_t));
73
74 tegra_ivc_read_advance(ivc);
75 tegra_safety_handle_cmd((cmdresp_frame_ex_t *)&cmd_resp,
76 safety_ivc->ldata);
77}
78
79static void tegra_safety_cmdresp_work_func(struct work_struct *work)
80{
81 struct tegra_safety_ivc *safety_ivc = container_of(work,
82 struct tegra_safety_ivc, work);
83
84 tegra_safety_decode_cmd_resp(safety_ivc);
75} 85}
76 86
77/* wake up cmd-resp threads */ 87/* wake up cmd-resp threads */
@@ -86,34 +96,10 @@ static u32 tegra_safety_ivc_full_notify(void *data, u32 response)
86 l1ss_set_ivc_ready(); 96 l1ss_set_ivc_ready();
87 wake_up(&safety_ivc->cmd.response_waitq); 97 wake_up(&safety_ivc->cmd.response_waitq);
88 l1ss_notify_client(L1SS_READY); 98 l1ss_notify_client(L1SS_READY);
89 } else if (response == 0) { 99 } else if (response == TEGRA_SAFETY_SM_CMDRESP_CH) {
90 tegra_safety_decode_cmd_resp(safety_ivc); 100 queue_work(safety_ivc->wq, &safety_ivc->work);
91 } 101 } else
92 102 pr_err("%s: Invalid response %d received", __func__, response);
93 return 0;
94}
95
96static void tegra_safety_ivc_empty_notify(void *data, u32 response)
97{
98 struct tegra_safety_ivc *safety_ivc = (struct tegra_safety_ivc *)data;
99 wake_up(&safety_ivc->cmd.empty_waitq);
100}
101
102static int tegra_safety_ivc_command(struct device *dev, u32 command,
103 long timeout)
104{
105 struct tegra_safety_ivc *safety_ivc = dev_get_drvdata(dev);
106
107 tegra_hsp_sm_pair_write(safety_ivc->ivc_pair, command);
108
109 timeout = wait_event_interruptible_timeout(
110 safety_ivc->cmd.empty_waitq,
111 tegra_hsp_sm_pair_is_empty(safety_ivc->ivc_pair),
112 timeout);
113 if (timeout <= 0) {
114 dev_err(dev, "Timed out waiting for empty SM");
115 return -ETIMEDOUT;
116 }
117 103
118 return 0; 104 return 0;
119} 105}
@@ -128,10 +114,7 @@ static int tegra_safety_ivc_setup_ready(struct device *dev)
128 114
129 command = SAFETY_CONF(IVC_READY, (region->dma >> 8)); 115 command = SAFETY_CONF(IVC_READY, (region->dma >> 8));
130 116
131 ret = tegra_safety_ivc_command(dev, command, 117 tegra_hsp_sm_pair_write(safety_ivc->ivc_pair, command);
132 TEGRA_SAFETY_IVC_READ_TIMEOUT);
133 if (ret < 0)
134 return ret;
135 118
136 timeout = wait_event_interruptible_timeout( 119 timeout = wait_event_interruptible_timeout(
137 safety_ivc->cmd.response_waitq, 120 safety_ivc->cmd.response_waitq,
@@ -151,7 +134,8 @@ static void tegra_ivc_channel_ring(struct ivc *ivc)
151 container_of(ivc, struct tegra_safety_ivc_chan, ivc); 134 container_of(ivc, struct tegra_safety_ivc_chan, ivc);
152 struct tegra_safety_ivc *safety_ivc = ivc_chan->safety_ivc; 135 struct tegra_safety_ivc *safety_ivc = ivc_chan->safety_ivc;
153 136
154 tegra_hsp_sm_pair_write(safety_ivc->ivc_pair, 1); 137 tegra_hsp_sm_pair_write(safety_ivc->ivc_pair,
138 TEGRA_SAFETY_SM_CMDRESP_CH);
155} 139}
156 140
157static int tegra_ivc_channel_create( 141static int tegra_ivc_channel_create(
@@ -325,7 +309,7 @@ static int tegra_safety_ivc_parse_hsp(struct device *dev)
325 hsp_node = of_get_child_by_name(dev->of_node, "hsp"); 309 hsp_node = of_get_child_by_name(dev->of_node, "hsp");
326 safety_ivc->ivc_pair = of_tegra_hsp_sm_pair_by_name(hsp_node, 310 safety_ivc->ivc_pair = of_tegra_hsp_sm_pair_by_name(hsp_node,
327 "ivc-pair", tegra_safety_ivc_full_notify, 311 "ivc-pair", tegra_safety_ivc_full_notify,
328 tegra_safety_ivc_empty_notify, safety_ivc); 312 NULL, safety_ivc);
329 of_node_put(hsp_node); 313 of_node_put(hsp_node);
330 if (IS_ERR(safety_ivc->ivc_pair)) { 314 if (IS_ERR(safety_ivc->ivc_pair)) {
331 ret = PTR_ERR(safety_ivc->ivc_pair); 315 ret = PTR_ERR(safety_ivc->ivc_pair);
@@ -359,6 +343,7 @@ static int tegra_safety_ivc_remove(struct platform_device *pdev)
359 343
360 tegra_safety_ast_region_free(dev); 344 tegra_safety_ast_region_free(dev);
361 tegra_hsp_sm_pair_free(safety_ivc->ivc_pair); 345 tegra_hsp_sm_pair_free(safety_ivc->ivc_pair);
346 destroy_workqueue(safety_ivc->wq);
362 ivc_chan_count = 0; 347 ivc_chan_count = 0;
363 348
364 return 0; 349 return 0;
@@ -370,7 +355,7 @@ static int tegra_safety_ivc_probe(struct platform_device *pdev)
370 struct device *dev = &pdev->dev; 355 struct device *dev = &pdev->dev;
371 int ret, i; 356 int ret, i;
372 357
373 dev_info(dev, "probing sce safety driver\n"); 358 dev_info(dev, "Probing sce safety driver\n");
374 359
375 safety_ivc = devm_kzalloc(dev, sizeof(*safety_ivc), GFP_KERNEL); 360 safety_ivc = devm_kzalloc(dev, sizeof(*safety_ivc), GFP_KERNEL);
376 if (!safety_ivc) 361 if (!safety_ivc)
@@ -380,6 +365,10 @@ static int tegra_safety_ivc_probe(struct platform_device *pdev)
380 365
381 init_waitqueue_head(&safety_ivc->cmd.response_waitq); 366 init_waitqueue_head(&safety_ivc->cmd.response_waitq);
382 init_waitqueue_head(&safety_ivc->cmd.empty_waitq); 367 init_waitqueue_head(&safety_ivc->cmd.empty_waitq);
368 safety_ivc->wq = alloc_workqueue("safety_cmdresp", WQ_HIGHPRI, 0);
369 INIT_WORK(&safety_ivc->work, tegra_safety_cmdresp_work_func);
370 mutex_init(&safety_ivc->rlock);
371 mutex_init(&safety_ivc->wlock);
383 372
384 ret = tegra_safety_ivc_parse_hsp(dev); 373 ret = tegra_safety_ivc_parse_hsp(dev);
385 if (ret) { 374 if (ret) {
@@ -420,7 +409,7 @@ static int tegra_safety_ivc_probe(struct platform_device *pdev)
420 } 409 }
421 } 410 }
422 411
423 dev_info(dev, "successfully probed safety ivc driver\n"); 412 dev_info(dev, "Successfully probed safety ivc driver\n");
424