@@ -440,13 +440,13 @@ struct XivePresenterClass {
InterfaceClass parent;
int (*match_nvt)(XivePresenter *xptr, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore, uint8_t priority,
uint32_t logic_serv, XiveTCTXMatch *match);
bool (*in_kernel)(const XivePresenter *xptr);
uint32_t (*get_config)(XivePresenter *xptr);
int (*broadcast)(XivePresenter *xptr,
uint8_t nvt_blk, uint32_t nvt_idx,
- uint8_t priority);
+ bool crowd, bool cam_ignore, uint8_t priority);
};
int xive_presenter_tctx_match(XivePresenter *xptr, XiveTCTX *tctx,
@@ -455,7 +455,7 @@ int xive_presenter_tctx_match(XivePresenter *xptr, XiveTCTX *tctx,
bool cam_ignore, uint32_t logic_serv);
bool xive_presenter_notify(XiveFabric *xfb, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore, uint8_t priority,
uint32_t logic_serv, bool *precluded);
uint32_t xive_get_vpgroup_size(uint32_t nvp_index);
@@ -475,10 +475,10 @@ struct XiveFabricClass {
InterfaceClass parent;
int (*match_nvt)(XiveFabric *xfb, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore, uint8_t priority,
uint32_t logic_serv, XiveTCTXMatch *match);
int (*broadcast)(XiveFabric *xfb, uint8_t nvt_blk, uint32_t nvt_idx,
- uint8_t priority);
+ bool crowd, bool cam_ignore, uint8_t priority);
};
/*
@@ -90,7 +90,8 @@ void xive2_router_notify(XiveNotifier *xn, uint32_t lisn, bool pq_checked);
int xive2_presenter_tctx_match(XivePresenter *xptr, XiveTCTX *tctx,
uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint32_t logic_serv);
+ bool crowd, bool cam_ignore,
+ uint32_t logic_serv);
uint64_t xive2_presenter_nvp_backlog_op(XivePresenter *xptr,
uint8_t blk, uint32_t idx,
@@ -473,7 +473,7 @@ static bool pnv_xive_is_cpu_enabled(PnvXive *xive, PowerPCCPU *cpu)
static int pnv_xive_match_nvt(XivePresenter *xptr, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore, uint8_t priority,
uint32_t logic_serv, XiveTCTXMatch *match)
{
PnvXive *xive = PNV_XIVE(xptr);
@@ -500,7 +500,8 @@ static int pnv_xive_match_nvt(XivePresenter *xptr, uint8_t format,
* Check the thread context CAM lines and record matches.
*/
ring = xive_presenter_tctx_match(xptr, tctx, format, nvt_blk,
- nvt_idx, cam_ignore, logic_serv);
+ nvt_idx, cam_ignore,
+ logic_serv);
/*
* Save the context and follow on to catch duplicates, that we
* don't support yet.
@@ -625,7 +625,7 @@ static bool pnv_xive2_is_cpu_enabled(PnvXive2 *xive, PowerPCCPU *cpu)
static int pnv_xive2_match_nvt(XivePresenter *xptr, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore, uint8_t priority,
uint32_t logic_serv, XiveTCTXMatch *match)
{
PnvXive2 *xive = PNV_XIVE2(xptr);
@@ -656,8 +656,8 @@ static int pnv_xive2_match_nvt(XivePresenter *xptr, uint8_t format,
logic_serv);
} else {
ring = xive2_presenter_tctx_match(xptr, tctx, format, nvt_blk,
- nvt_idx, cam_ignore,
- logic_serv);
+ nvt_idx, crowd, cam_ignore,
+ logic_serv);
}
if (ring != -1) {
@@ -708,7 +708,7 @@ static uint32_t pnv_xive2_presenter_get_config(XivePresenter *xptr)
static int pnv_xive2_broadcast(XivePresenter *xptr,
uint8_t nvt_blk, uint32_t nvt_idx,
- uint8_t priority)
+ bool crowd, bool ignore, uint8_t priority)
{
PnvXive2 *xive = PNV_XIVE2(xptr);
PnvChip *chip = xive->chip;
@@ -733,10 +733,10 @@ static int pnv_xive2_broadcast(XivePresenter *xptr,
if (gen1_tima_os) {
ring = xive_presenter_tctx_match(xptr, tctx, 0, nvt_blk,
- nvt_idx, true, 0);
+ nvt_idx, ignore, 0);
} else {
ring = xive2_presenter_tctx_match(xptr, tctx, 0, nvt_blk,
- nvt_idx, true, 0);
+ nvt_idx, crowd, ignore, 0);
}
if (ring != -1) {
@@ -431,7 +431,8 @@ static int spapr_xive_write_nvt(XiveRouter *xrtr, uint8_t nvt_blk,
static int spapr_xive_match_nvt(XivePresenter *xptr, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore,
+ uint8_t priority,
uint32_t logic_serv, XiveTCTXMatch *match)
{
CPUState *cs;
@@ -1681,10 +1681,18 @@ uint32_t xive_get_vpgroup_size(uint32_t nvp_index)
return 1 << (ctz32(~nvp_index) + 1);
}
-static uint8_t xive_get_group_level(uint32_t nvp_index)
+static uint8_t xive_get_group_level(bool crowd, bool ignore,
+ uint32_t nvp_blk, uint32_t nvp_index)
{
- /* FIXME add crowd encoding */
- return ctz32(~nvp_index) + 1;
+ uint8_t level = 0;
+
+ if (crowd) {
+ level = ((ctz32(~nvp_blk) + 1) & 0b11) << 4;
+ }
+ if (ignore) {
+ level |= (ctz32(~nvp_index) + 1) & 0b1111;
+ }
+ return level;
}
/*
@@ -1756,7 +1764,7 @@ int xive_presenter_tctx_match(XivePresenter *xptr, XiveTCTX *tctx,
*/
bool xive_presenter_notify(XiveFabric *xfb, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore, uint8_t priority,
uint32_t logic_serv, bool *precluded)
{
XiveFabricClass *xfc = XIVE_FABRIC_GET_CLASS(xfb);
@@ -1787,7 +1795,7 @@ bool xive_presenter_notify(XiveFabric *xfb, uint8_t format,
* a new command to the presenters (the equivalent of the "assign"
* power bus command in the documented full notify sequence.
*/
- count = xfc->match_nvt(xfb, format, nvt_blk, nvt_idx, cam_ignore,
+ count = xfc->match_nvt(xfb, format, nvt_blk, nvt_idx, crowd, cam_ignore,
priority, logic_serv, &match);
if (count < 0) {
return false;
@@ -1795,7 +1803,7 @@ bool xive_presenter_notify(XiveFabric *xfb, uint8_t format,
/* handle CPU exception delivery */
if (count) {
- group_level = cam_ignore ? xive_get_group_level(nvt_idx) : 0;
+ group_level = xive_get_group_level(crowd, cam_ignore, nvt_blk, nvt_idx);
trace_xive_presenter_notify(nvt_blk, nvt_idx, match.ring, group_level);
xive_tctx_pipr_update(match.tctx, match.ring, priority, group_level);
} else {
@@ -1920,6 +1928,7 @@ void xive_router_end_notify(XiveRouter *xrtr, XiveEAS *eas)
}
found = xive_presenter_notify(xrtr->xfb, format, nvt_blk, nvt_idx,
+ false /* crowd */,
xive_get_field32(END_W7_F0_IGNORE, end.w7),
priority,
xive_get_field32(END_W7_F1_LOG_SERVER_ID, end.w7),
@@ -1117,13 +1117,42 @@ static bool xive2_vp_match_mask(uint32_t cam1, uint32_t cam2,
return (cam1 & vp_mask) == (cam2 & vp_mask);
}
+static uint8_t xive2_get_vp_block_mask(uint32_t nvt_blk, bool crowd)
+{
+ uint8_t size, block_mask = 0b1111;
+
+ /* 3 supported crowd sizes: 2, 4, 16 */
+ if (crowd) {
+ size = xive_get_vpgroup_size(nvt_blk);
+ if (size == 8) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid crowd size of 8n");
+ return block_mask;
+ }
+ block_mask = ~(size - 1);
+ block_mask &= 0b1111;
+ }
+ return block_mask;
+}
+
+static uint32_t xive2_get_vp_index_mask(uint32_t nvt_index, bool cam_ignore)
+{
+ uint32_t index_mask = 0xFFFFFF; /* 24 bits */
+
+ if (cam_ignore) {
+ index_mask = ~(xive_get_vpgroup_size(nvt_index) - 1);
+ index_mask &= 0xFFFFFF;
+ }
+ return index_mask;
+}
+
/*
* The thread context register words are in big-endian format.
*/
int xive2_presenter_tctx_match(XivePresenter *xptr, XiveTCTX *tctx,
uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint32_t logic_serv)
+ bool crowd, bool cam_ignore,
+ uint32_t logic_serv)
{
uint32_t cam = xive2_nvp_cam_line(nvt_blk, nvt_idx);
uint32_t qw3w2 = xive_tctx_word2(&tctx->regs[TM_QW3_HV_PHYS]);
@@ -1131,7 +1160,8 @@ int xive2_presenter_tctx_match(XivePresenter *xptr, XiveTCTX *tctx,
uint32_t qw1w2 = xive_tctx_word2(&tctx->regs[TM_QW1_OS]);
uint32_t qw0w2 = xive_tctx_word2(&tctx->regs[TM_QW0_USER]);
- uint32_t vp_mask = 0xFFFFFFFF;
+ uint32_t index_mask, vp_mask;
+ uint8_t block_mask;
if (format == 0) {
/*
@@ -1139,9 +1169,9 @@ int xive2_presenter_tctx_match(XivePresenter *xptr, XiveTCTX *tctx,
* i=1: VP-group notification (bits ignored at the end of the
* NVT identifier)
*/
- if (cam_ignore) {
- vp_mask = ~(xive_get_vpgroup_size(nvt_idx) - 1);
- }
+ block_mask = xive2_get_vp_block_mask(nvt_blk, crowd);
+ index_mask = xive2_get_vp_index_mask(nvt_idx, cam_ignore);
+ vp_mask = xive2_nvp_cam_line(block_mask, index_mask);
/* For VP-group notifications, threads with LGS=0 are excluded */
@@ -1274,6 +1304,12 @@ static void xive2_router_end_notify(Xive2Router *xrtr, uint8_t end_blk,
return;
}
+ if (xive2_end_is_crowd(&end) & !xive2_end_is_ignore(&end)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "XIVE: invalid END, 'crowd' bit requires 'ignore' bit\n");
+ return;
+ }
+
if (xive2_end_is_enqueue(&end)) {
xive2_end_enqueue(&end, end_data);
/* Enqueuing event data modifies the EQ toggle and index */
@@ -1335,7 +1371,7 @@ static void xive2_router_end_notify(Xive2Router *xrtr, uint8_t end_blk,
}
found = xive_presenter_notify(xrtr->xfb, format, nvp_blk, nvp_idx,
- xive2_end_is_ignore(&end),
+ xive2_end_is_crowd(&end), xive2_end_is_ignore(&end),
priority,
xive_get_field32(END2_W7_F1_LOG_SERVER_ID, end.w7),
&precluded);
@@ -1372,17 +1408,24 @@ static void xive2_router_end_notify(Xive2Router *xrtr, uint8_t end_blk,
nvp.w2 = xive_set_field32(NVP2_W2_IPB, nvp.w2, ipb);
xive2_router_write_nvp(xrtr, nvp_blk, nvp_idx, &nvp, 2);
} else {
- Xive2Nvgc nvg;
+ Xive2Nvgc nvgc;
uint32_t backlog;
+ bool crowd;
- /* For groups, the per-priority backlog counters are in the NVG */
- if (xive2_router_get_nvgc(xrtr, false, nvp_blk, nvp_idx, &nvg)) {
- qemu_log_mask(LOG_GUEST_ERROR, "XIVE: no NVG %x/%x\n",
- nvp_blk, nvp_idx);
+ crowd = xive2_end_is_crowd(&end);
+
+ /*
+ * For groups and crowds, the per-priority backlog
+ * counters are stored in the NVG/NVC structures
+ */
+ if (xive2_router_get_nvgc(xrtr, crowd,
+ nvp_blk, nvp_idx, &nvgc)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: no %s %x/%x\n",
+ crowd ? "NVC" : "NVG", nvp_blk, nvp_idx);
return;
}
- if (!xive2_nvgc_is_valid(&nvg)) {
+ if (!xive2_nvgc_is_valid(&nvgc)) {
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVG %x/%x is invalid\n",
nvp_blk, nvp_idx);
return;
@@ -1395,13 +1438,16 @@ static void xive2_router_end_notify(Xive2Router *xrtr, uint8_t end_blk,
* set the LSMFB field of the TIMA of relevant threads so
* that they know an interrupt is pending.
*/
- backlog = xive2_nvgc_get_backlog(&nvg, priority) + 1;
- xive2_nvgc_set_backlog(&nvg, priority, backlog);
- xive2_router_write_nvgc(xrtr, false, nvp_blk, nvp_idx, &nvg);
+ backlog = xive2_nvgc_get_backlog(&nvgc, priority) + 1;
+ xive2_nvgc_set_backlog(&nvgc, priority, backlog);
+ xive2_router_write_nvgc(xrtr, crowd, nvp_blk, nvp_idx, &nvgc);
if (precluded && backlog == 1) {
XiveFabricClass *xfc = XIVE_FABRIC_GET_CLASS(xrtr->xfb);
- xfc->broadcast(xrtr->xfb, nvp_blk, nvp_idx, priority);
+ xfc->broadcast(xrtr->xfb, nvp_blk, nvp_idx,
+ xive2_end_is_crowd(&end),
+ xive2_end_is_ignore(&end),
+ priority);
if (!xive2_end_is_precluded_escalation(&end)) {
/*
@@ -2583,7 +2583,7 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj, GString *buf)
static int pnv_match_nvt(XiveFabric *xfb, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore, uint8_t priority,
uint32_t logic_serv,
XiveTCTXMatch *match)
{
@@ -2597,8 +2597,8 @@ static int pnv_match_nvt(XiveFabric *xfb, uint8_t format,
XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
int count;
- count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, cam_ignore,
- priority, logic_serv, match);
+ count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, crowd,
+ cam_ignore, priority, logic_serv, match);
if (count < 0) {
return count;
@@ -2612,7 +2612,7 @@ static int pnv_match_nvt(XiveFabric *xfb, uint8_t format,
static int pnv10_xive_match_nvt(XiveFabric *xfb, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore, uint8_t priority,
uint32_t logic_serv,
XiveTCTXMatch *match)
{
@@ -2626,8 +2626,8 @@ static int pnv10_xive_match_nvt(XiveFabric *xfb, uint8_t format,
XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
int count;
- count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, cam_ignore,
- priority, logic_serv, match);
+ count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, crowd,
+ cam_ignore, priority, logic_serv, match);
if (count < 0) {
return count;
@@ -2641,6 +2641,7 @@ static int pnv10_xive_match_nvt(XiveFabric *xfb, uint8_t format,
static int pnv10_xive_broadcast(XiveFabric *xfb,
uint8_t nvt_blk, uint32_t nvt_idx,
+ bool crowd, bool cam_ignore,
uint8_t priority)
{
PnvMachineState *pnv = PNV_MACHINE(xfb);
@@ -2651,7 +2652,7 @@ static int pnv10_xive_broadcast(XiveFabric *xfb,
XivePresenter *xptr = XIVE_PRESENTER(&chip10->xive);
XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
- xpc->broadcast(xptr, nvt_blk, nvt_idx, priority);
+ xpc->broadcast(xptr, nvt_blk, nvt_idx, crowd, cam_ignore, priority);
}
return 0;
}
@@ -4437,7 +4437,7 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj, GString *buf)
*/
static int spapr_match_nvt(XiveFabric *xfb, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore, uint8_t priority,
uint32_t logic_serv, XiveTCTXMatch *match)
{
SpaprMachineState *spapr = SPAPR_MACHINE(xfb);
@@ -4445,7 +4445,7 @@ static int spapr_match_nvt(XiveFabric *xfb, uint8_t format,
XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
int count;
- count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, cam_ignore,
+ count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, crowd, cam_ignore,
priority, logic_serv, match);
if (count < 0) {
return count;