aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/hostservices.c10
-rw-r--r--hw/occ.c100
-rw-r--r--include/hostservices.h1
-rw-r--r--include/skiboot.h3
4 files changed, 90 insertions, 24 deletions
diff --git a/core/hostservices.c b/core/hostservices.c
index 1c41a95..769d6f0 100644
--- a/core/hostservices.c
+++ b/core/hostservices.c
@@ -394,6 +394,13 @@ struct hbrt_lid {
};
static LIST_HEAD(hbrt_lid_list);
+static bool hbrt_lid_preload_complete = false;
+
+bool hservices_lid_preload_complete(void)
+{
+ return hbrt_lid_preload_complete;
+}
+
/* TODO: Few of the following routines can be generalized */
static int __hservice_lid_load(uint32_t lid, void **buf, size_t *len)
{
@@ -468,6 +475,9 @@ void hservices_lid_preload(void)
/* Currently HBRT needs only one (OCC) lid */
for (i = 0; i < num_lids; i++)
__hservice_lid_preload(lid_list[i]);
+
+ hbrt_lid_preload_complete = true;
+ occ_poke_load_queue();
}
static int hservice_lid_load(uint32_t lid, void **buf, size_t *len)
diff --git a/hw/occ.c b/hw/occ.c
index 6dbbe6b..7ca1218 100644
--- a/hw/occ.c
+++ b/hw/occ.c
@@ -347,34 +347,36 @@ void occ_pstates_init(void)
}
}
-static void occ_do_load(u8 scope, u32 dbob_id __unused, u32 seq_id)
-{
- struct fsp_msg *rsp, *stat;
- int rc = -ENOMEM;
- int status_word = 0;
- struct proc_chip *chip = next_chip(NULL);
- u8 err = 0;
+struct occ_load_req {
+ u8 scope;
+ u32 dbob_id;
+ u32 seq_id;
+ struct list_node link;
+};
+static LIST_HEAD(occ_load_req_list);
- /* Check arguments */
- if (scope != 0x01 && scope != 0x02) {
- prerror("OCC: Load message with invalid scope 0x%x\n",
- scope);
- err = 0x22;
- }
+static void occ_queue_load(u8 scope, u32 dbob_id, u32 seq_id)
+{
+ struct occ_load_req *occ_req;
- /* First queue up an OK response to the load message itself */
- rsp = fsp_mkmsg(FSP_RSP_LOAD_OCC | err, 0);
- if (rsp)
- rc = fsp_queue_msg(rsp, fsp_freemsg);
- if (rc) {
- log_simple_error(&e_info(OPAL_RC_OCC_LOAD),
- "OCC: Error %d queueing FSP OCC LOAD reply\n", rc);
+ occ_req = zalloc(sizeof(struct occ_load_req));
+ if (!occ_req) {
+ prerror("OCC: Could not allocate occ_load_req\n");
return;
}
- /* If we had an error, return */
- if (err)
- return;
+ occ_req->scope = scope;
+ occ_req->dbob_id = dbob_id;
+ occ_req->seq_id = seq_id;
+ list_add_tail(&occ_load_req_list, &occ_req->link);
+}
+
+static void __occ_do_load(u8 scope, u32 dbob_id __unused, u32 seq_id)
+{
+ struct fsp_msg *stat;
+ int rc = -ENOMEM;
+ int status_word = 0;
+ struct proc_chip *chip = next_chip(NULL);
/* Call HBRT... */
rc = host_services_occ_load();
@@ -397,7 +399,7 @@ static void occ_do_load(u8 scope, u32 dbob_id __unused, u32 seq_id)
break;
}
log_simple_error(&e_info(OPAL_RC_OCC_LOAD),
- "OCC: Error %d in load/start OCC\n", err);
+ "OCC: Error %d in load/start OCC\n", rc);
}
/* Send a single response for all chips */
@@ -410,6 +412,56 @@ static void occ_do_load(u8 scope, u32 dbob_id __unused, u32 seq_id)
}
}
+void occ_poke_load_queue(void)
+{
+ struct occ_load_req *occ_req;
+
+ if (list_empty(&occ_load_req_list))
+ return;
+
+ list_for_each(&occ_load_req_list, occ_req, link) {
+ __occ_do_load(occ_req->scope, occ_req->dbob_id,
+ occ_req->seq_id);
+ list_del(&occ_req->link);
+ free(occ_req);
+ }
+}
+
+static void occ_do_load(u8 scope, u32 dbob_id __unused, u32 seq_id)
+{
+ struct fsp_msg *rsp;
+ int rc = -ENOMEM;
+ u8 err = 0;
+
+ if (scope != 0x01 && scope != 0x02) {
+ prerror("OCC: Load message with invalid scope 0x%x\n",
+ scope);
+ err = 0x22;
+ }
+
+ /* First queue up an OK response to the load message itself */
+ rsp = fsp_mkmsg(FSP_RSP_LOAD_OCC | err, 0);
+ if (rsp)
+ rc = fsp_queue_msg(rsp, fsp_freemsg);
+ if (rc) {
+ log_simple_error(&e_info(OPAL_RC_OCC_LOAD),
+ "OCC: Error %d queueing FSP OCC LOAD reply\n", rc);
+ return;
+ }
+
+ if (err)
+ return;
+
+ /*
+ * Check if hostservices lid caching is complete. If not, queue
+ * the load request.
+ */
+ if (!hservices_lid_preload_complete())
+ occ_queue_load(scope, dbob_id, seq_id);
+
+ __occ_do_load(scope, dbob_id, seq_id);
+}
+
static void occ_do_reset(u8 scope, u32 dbob_id, u32 seq_id)
{
struct fsp_msg *rsp, *stat;
diff --git a/include/hostservices.h b/include/hostservices.h
index c8958a3..e85abc3 100644
--- a/include/hostservices.h
+++ b/include/hostservices.h
@@ -19,6 +19,7 @@
bool hservices_init(void);
void hservices_lid_preload(void);
+bool hservices_lid_preload_complete(void);
int host_services_occ_load(void);
int host_services_occ_start(void);
diff --git a/include/skiboot.h b/include/skiboot.h
index a13b438..d20a9a2 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -215,6 +215,9 @@ extern void uart_setup_opal_console(void);
extern void occ_interrupt(uint32_t chip_id);
extern void occ_send_dummy_interrupt(void);
+/* OCC load support */
+extern void occ_poke_load_queue(void);
+
/* Flatten device-tree */
extern void *create_dtb(const struct dt_node *root);