@samitouri / QOSamiQemu / commits / 0b74dd1d80

ppc/pnv: Add OCC FLAG registers

OCCFLG are scratch registers that can be shared with OCC firmware. Log reads and writes to the registers as a reminder when we run into more OCC code. Add RW, WO_CLEAR and WO_OR SCOM Type enums in pnv_occ.c Reviewed-by: Chalapathi V <chalapathi.v@linux.ibm.com> Reviewed-by: Glenn Miles <milesg@linux.ibm.com> Reviewed-by: Aditya Gupta <adityag@linux.ibm.com> Signed-off-by: Chalapathi V <chalapathi.v@linux.ibm.com> Signed-off-by: Caleb Schlossin <calebs@linux.ibm.com> Link: https://lore.kernel.org/qemu-devel/20260210134647.2050821-4-calebs@linux.ibm.com Signed-off-by: Harsh Prateek Bora <harshpb@linux.ibm.com>

Caleb Schlossin committed Feb 10, 2026 at 07:46 UTC 0b74dd1d8054dfff56562ccc6cedc869cebac623
2 files changed +56 -3
hw/ppc/pnv_occ.c
+52 -3
@@ -195,6 +195,49 @@ static const TypeInfo pnv_occ_power8_type_info = {
195 #define P9_OCB_OCI_OCCMISC_CLEAR 0x6081
196 #define P9_OCB_OCI_OCCMISC_OR 0x6082
197
198 +/* OCC scratch registers for flag setting */
199 +#define P9_OCCFLG0 0x60ac
200 +#define P9_OCCFLG7_OR 0x60c3
201 +
202 +enum ScomType {
203 + SCOM_TYPE_RW = 0,
204 + SCOM_TYPE_WO_CLEAR = 1,
205 + SCOM_TYPE_WO_OR = 2,
206 +};
207 +
208 +static void rw_occ_flag_regs(PnvOCC *occ, uint32_t offset, bool read,
209 + uint64_t *val)
210 +{
211 + int flag_num;
212 + int flag_type;
213 +
214 + /*
215 + * Each OCCFLG register has SCOM0 - RW, SCOM1 - WO_CLEAR, SCOM2 - WO_OR
216 + * hence divide by 3 to get flag index and mod 3 to get SCOM type.
217 + */
218 + flag_num = (offset - P9_OCCFLG0) / 3;
219 + flag_type = (offset - P9_OCCFLG0) % 3;
220 +
221 + if (read) {
222 + if (flag_type) {
223 + qemu_log_mask(LOG_GUEST_ERROR, "OCC: Write only register: Ox%"
224 + PRIx32 "\n", offset);
225 + return;
226 + }
227 + *val = occ->occflags[flag_num];
228 + } else {
229 + switch (flag_type) {
230 + case SCOM_TYPE_RW:
231 + occ->occflags[flag_num] = *val;
232 + break;
233 + case SCOM_TYPE_WO_CLEAR:
234 + occ->occflags[flag_num] &= ~(*val);
235 + break;
236 + case SCOM_TYPE_WO_OR:
237 + occ->occflags[flag_num] |= *val;
238 + }
239 + }
240 +}
241
242 static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr,
243 unsigned size)
@@ -207,8 +250,11 @@ static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr,
250 case P9_OCB_OCI_OCCMISC:
251 val = occ->occmisc;
252 break;
253 + case P9_OCCFLG0 ... P9_OCCFLG7_OR:
254 + rw_occ_flag_regs(occ, offset, 1, &val);
255 + break;
256 default:
211 - qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
257 + qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register read: Ox%"
258 HWADDR_PRIx "\n", addr >> 3);
259 }
260 return val;
@@ -229,9 +275,12 @@ static void pnv_occ_power9_xscom_write(void *opaque, hwaddr addr,
275 break;
276 case P9_OCB_OCI_OCCMISC:
277 pnv_occ_set_misc(occ, val);
232 - break;
278 + break;
279 + case P9_OCCFLG0 ... P9_OCCFLG7_OR:
280 + rw_occ_flag_regs(occ, offset, 0, &val);
281 + break;
282 default:
234 - qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
283 + qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register write: Ox%"
284 HWADDR_PRIx "\n", addr >> 3);
285 }
286 }
include/hw/ppc/pnv_occ.h
+4
@@ -47,6 +47,10 @@ struct PnvOCC {
47 /* OCC Misc interrupt */
48 uint64_t occmisc;
49
50 + /* OCC Flags */
51 +#define NR_FLAG_REGS 8
52 + uint32_t occflags[NR_FLAG_REGS];
53 +
54 qemu_irq psi_irq;
55
56 /* OCCs operate on regions of HOMER memory */