12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120 |
- /*
- * QEMU PowerPC XIVE interrupt controller model
- *
- * Copyright (c) 2017-2024, IBM Corporation.
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
- #include "qemu/osdep.h"
- #include "qemu/log.h"
- #include "qemu/module.h"
- #include "qapi/error.h"
- #include "target/ppc/cpu.h"
- #include "system/cpus.h"
- #include "system/dma.h"
- #include "system/reset.h"
- #include "hw/ppc/fdt.h"
- #include "hw/ppc/pnv.h"
- #include "hw/ppc/pnv_chip.h"
- #include "hw/ppc/pnv_core.h"
- #include "hw/ppc/pnv_xscom.h"
- #include "hw/ppc/pnv_xive.h"
- #include "hw/ppc/xive_regs.h"
- #include "hw/qdev-properties.h"
- #include "hw/ppc/ppc.h"
- #include "trace.h"
- #include <libfdt.h>
- #include "pnv_xive_regs.h"
- #undef XIVE_DEBUG
- /*
- * Virtual structures table (VST)
- */
- #define SBE_PER_BYTE 4
- typedef struct XiveVstInfo {
- const char *name;
- uint32_t size;
- uint32_t max_blocks;
- } XiveVstInfo;
- static const XiveVstInfo vst_infos[] = {
- [VST_TSEL_IVT] = { "EAT", sizeof(XiveEAS), 16 },
- [VST_TSEL_SBE] = { "SBE", 1, 16 },
- [VST_TSEL_EQDT] = { "ENDT", sizeof(XiveEND), 16 },
- [VST_TSEL_VPDT] = { "VPDT", sizeof(XiveNVT), 32 },
- /*
- * Interrupt fifo backing store table (not modeled) :
- *
- * 0 - IPI,
- * 1 - HWD,
- * 2 - First escalate,
- * 3 - Second escalate,
- * 4 - Redistribution,
- * 5 - IPI cascaded queue ?
- */
- [VST_TSEL_IRQ] = { "IRQ", 1, 6 },
- };
- #define xive_error(xive, fmt, ...) \
- qemu_log_mask(LOG_GUEST_ERROR, "XIVE[%x] - " fmt "\n", \
- (xive)->chip->chip_id, ## __VA_ARGS__);
- /*
- * When PC_TCTXT_CHIPID_OVERRIDE is configured, the PC_TCTXT_CHIPID
- * field overrides the hardwired chip ID in the Powerbus operations
- * and for CAM compares
- */
- static uint8_t pnv_xive_block_id(PnvXive *xive)
- {
- uint8_t blk = xive->chip->chip_id;
- uint64_t cfg_val = xive->regs[PC_TCTXT_CFG >> 3];
- if (cfg_val & PC_TCTXT_CHIPID_OVERRIDE) {
- blk = GETFIELD(PC_TCTXT_CHIPID, cfg_val);
- }
- return blk;
- }
- /*
- * VST accessors for SBE, EAT, ENDT, NVT
- *
- * Indirect VST tables are arrays of VSDs pointing to a page (of same
- * size). Each page is a direct VST table.
- */
- #define XIVE_VSD_SIZE 8
- /* Indirect page size can be 4K, 64K, 2M, 16M. */
- static uint64_t pnv_xive_vst_page_size_allowed(uint32_t page_shift)
- {
- return page_shift == 12 || page_shift == 16 ||
- page_shift == 21 || page_shift == 24;
- }
- static uint64_t pnv_xive_vst_addr_direct(PnvXive *xive, uint32_t type,
- uint64_t vsd, uint32_t idx)
- {
- const XiveVstInfo *info = &vst_infos[type];
- uint64_t vst_addr = vsd & VSD_ADDRESS_MASK;
- uint64_t vst_tsize = 1ull << (GETFIELD(VSD_TSIZE, vsd) + 12);
- uint32_t idx_max;
- idx_max = vst_tsize / info->size - 1;
- if (idx > idx_max) {
- #ifdef XIVE_DEBUG
- xive_error(xive, "VST: %s entry %x out of range [ 0 .. %x ] !?",
- info->name, idx, idx_max);
- #endif
- return 0;
- }
- return vst_addr + idx * info->size;
- }
- static uint64_t pnv_xive_vst_addr_indirect(PnvXive *xive, uint32_t type,
- uint64_t vsd, uint32_t idx)
- {
- const XiveVstInfo *info = &vst_infos[type];
- uint64_t vsd_addr;
- uint32_t vsd_idx;
- uint32_t page_shift;
- uint32_t vst_per_page;
- /* Get the page size of the indirect table. */
- vsd_addr = vsd & VSD_ADDRESS_MASK;
- if (ldq_be_dma(&address_space_memory, vsd_addr, &vsd,
- MEMTXATTRS_UNSPECIFIED)) {
- xive_error(xive, "VST: failed to access %s entry %x @0x%" PRIx64,
- info->name, idx, vsd_addr);
- return 0;
- }
- if (!(vsd & VSD_ADDRESS_MASK)) {
- #ifdef XIVE_DEBUG
- xive_error(xive, "VST: invalid %s entry %x !?", info->name, idx);
- #endif
- return 0;
- }
- page_shift = GETFIELD(VSD_TSIZE, vsd) + 12;
- if (!pnv_xive_vst_page_size_allowed(page_shift)) {
- xive_error(xive, "VST: invalid %s page shift %d", info->name,
- page_shift);
- return 0;
- }
- vst_per_page = (1ull << page_shift) / info->size;
- vsd_idx = idx / vst_per_page;
- /* Load the VSD we are looking for, if not already done */
- if (vsd_idx) {
- vsd_addr = vsd_addr + vsd_idx * XIVE_VSD_SIZE;
- if (ldq_be_dma(&address_space_memory, vsd_addr, &vsd,
- MEMTXATTRS_UNSPECIFIED)) {
- xive_error(xive, "VST: failed to access %s entry %x @0x%"
- PRIx64, info->name, vsd_idx, vsd_addr);
- return 0;
- }
- if (!(vsd & VSD_ADDRESS_MASK)) {
- #ifdef XIVE_DEBUG
- xive_error(xive, "VST: invalid %s entry %x !?", info->name, idx);
- #endif
- return 0;
- }
- /*
- * Check that the pages have a consistent size across the
- * indirect table
- */
- if (page_shift != GETFIELD(VSD_TSIZE, vsd) + 12) {
- xive_error(xive, "VST: %s entry %x indirect page size differ !?",
- info->name, idx);
- return 0;
- }
- }
- return pnv_xive_vst_addr_direct(xive, type, vsd, (idx % vst_per_page));
- }
- /*
- * This is a simplified model of operation forwarding on a remote IC.
- *
- * A PC MMIO address is built to identify the NVT structure. The load
- * on the remote IC will return the address of the structure in RAM,
- * which will then be used by pnv_xive_vst_write/read to perform the
- * RAM operation.
- */
- static uint64_t pnv_xive_vst_addr_remote(PnvXive *xive, uint32_t type,
- uint64_t vsd, uint8_t blk,
- uint32_t idx)
- {
- const XiveVstInfo *info = &vst_infos[type];
- uint64_t remote_addr = vsd & VSD_ADDRESS_MASK;
- uint64_t vst_addr;
- MemTxResult result;
- if (type != VST_TSEL_VPDT) {
- xive_error(xive, "VST: invalid access on remote VST %s %x/%x !?",
- info->name, blk, idx);
- return 0;
- }
- remote_addr |= ((uint64_t)idx) << xive->pc_shift;
- vst_addr = address_space_ldq_be(&address_space_memory, remote_addr,
- MEMTXATTRS_UNSPECIFIED, &result);
- if (result != MEMTX_OK) {
- xive_error(xive, "VST: read failed at @0x%" HWADDR_PRIx
- " for NVT %x/%x\n", remote_addr, blk, idx);
- return 0;
- }
- return vst_addr;
- }
- static uint64_t pnv_xive_vst_addr(PnvXive *xive, uint32_t type, uint8_t blk,
- uint32_t idx)
- {
- const XiveVstInfo *info = &vst_infos[type];
- uint64_t vsd;
- if (blk >= info->max_blocks) {
- xive_error(xive, "VST: invalid block id %d for VST %s %d !?",
- blk, info->name, idx);
- return 0;
- }
- vsd = xive->vsds[type][blk];
- /* Remote VST access */
- if (GETFIELD(VSD_MODE, vsd) == VSD_MODE_FORWARD) {
- return pnv_xive_vst_addr_remote(xive, type, vsd, blk, idx);
- }
- if (VSD_INDIRECT & vsd) {
- return pnv_xive_vst_addr_indirect(xive, type, vsd, idx);
- }
- return pnv_xive_vst_addr_direct(xive, type, vsd, idx);
- }
- static int pnv_xive_vst_read(PnvXive *xive, uint32_t type, uint8_t blk,
- uint32_t idx, void *data)
- {
- const XiveVstInfo *info = &vst_infos[type];
- uint64_t addr = pnv_xive_vst_addr(xive, type, blk, idx);
- MemTxResult result;
- if (!addr) {
- return -1;
- }
- result = address_space_read(&address_space_memory, addr,
- MEMTXATTRS_UNSPECIFIED, data,
- info->size);
- if (result != MEMTX_OK) {
- xive_error(xive, "VST: read failed at @0x%" HWADDR_PRIx
- " for VST %s %x/%x\n", addr, info->name, blk, idx);
- return -1;
- }
- return 0;
- }
- #define XIVE_VST_WORD_ALL -1
- static int pnv_xive_vst_write(PnvXive *xive, uint32_t type, uint8_t blk,
- uint32_t idx, void *data, uint32_t word_number)
- {
- const XiveVstInfo *info = &vst_infos[type];
- uint64_t addr = pnv_xive_vst_addr(xive, type, blk, idx);
- MemTxResult result;
- if (!addr) {
- return -1;
- }
- if (word_number == XIVE_VST_WORD_ALL) {
- result = address_space_write(&address_space_memory, addr,
- MEMTXATTRS_UNSPECIFIED, data,
- info->size);
- } else {
- result = address_space_write(&address_space_memory,
- addr + word_number * 4,
- MEMTXATTRS_UNSPECIFIED,
- data + word_number * 4, 4);
- }
- if (result != MEMTX_OK) {
- xive_error(xive, "VST: write failed at @0x%" HWADDR_PRIx
- "for VST %s %x/%x\n", addr, info->name, blk, idx);
- return -1;
- }
- return 0;
- }
- static int pnv_xive_get_end(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
- XiveEND *end)
- {
- PnvXive *xive = PNV_XIVE(xrtr);
- if (pnv_xive_block_id(xive) != blk) {
- xive_error(xive, "VST: END %x/%x is remote !?", blk, idx);
- return -1;
- }
- return pnv_xive_vst_read(PNV_XIVE(xrtr), VST_TSEL_EQDT, blk, idx, end);
- }
- static int pnv_xive_write_end(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
- XiveEND *end, uint8_t word_number)
- {
- PnvXive *xive = PNV_XIVE(xrtr);
- if (pnv_xive_block_id(xive) != blk) {
- xive_error(xive, "VST: END %x/%x is remote !?", blk, idx);
- return -1;
- }
- return pnv_xive_vst_write(PNV_XIVE(xrtr), VST_TSEL_EQDT, blk, idx, end,
- word_number);
- }
- static int pnv_xive_end_update(PnvXive *xive)
- {
- uint8_t blk = GETFIELD(VC_EQC_CWATCH_BLOCKID,
- xive->regs[(VC_EQC_CWATCH_SPEC >> 3)]);
- uint32_t idx = GETFIELD(VC_EQC_CWATCH_OFFSET,
- xive->regs[(VC_EQC_CWATCH_SPEC >> 3)]);
- int i;
- uint64_t eqc_watch[4];
- for (i = 0; i < ARRAY_SIZE(eqc_watch); i++) {
- eqc_watch[i] = cpu_to_be64(xive->regs[(VC_EQC_CWATCH_DAT0 >> 3) + i]);
- }
- return pnv_xive_vst_write(xive, VST_TSEL_EQDT, blk, idx, eqc_watch,
- XIVE_VST_WORD_ALL);
- }
- static void pnv_xive_end_cache_load(PnvXive *xive)
- {
- uint8_t blk = GETFIELD(VC_EQC_CWATCH_BLOCKID,
- xive->regs[(VC_EQC_CWATCH_SPEC >> 3)]);
- uint32_t idx = GETFIELD(VC_EQC_CWATCH_OFFSET,
- xive->regs[(VC_EQC_CWATCH_SPEC >> 3)]);
- uint64_t eqc_watch[4] = { 0 };
- int i;
- if (pnv_xive_vst_read(xive, VST_TSEL_EQDT, blk, idx, eqc_watch)) {
- xive_error(xive, "VST: no END entry %x/%x !?", blk, idx);
- }
- for (i = 0; i < ARRAY_SIZE(eqc_watch); i++) {
- xive->regs[(VC_EQC_CWATCH_DAT0 >> 3) + i] = be64_to_cpu(eqc_watch[i]);
- }
- }
- static int pnv_xive_get_nvt(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
- XiveNVT *nvt)
- {
- return pnv_xive_vst_read(PNV_XIVE(xrtr), VST_TSEL_VPDT, blk, idx, nvt);
- }
- static int pnv_xive_write_nvt(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
- XiveNVT *nvt, uint8_t word_number)
- {
- return pnv_xive_vst_write(PNV_XIVE(xrtr), VST_TSEL_VPDT, blk, idx, nvt,
- word_number);
- }
- static int pnv_xive_nvt_update(PnvXive *xive)
- {
- uint8_t blk = GETFIELD(PC_VPC_CWATCH_BLOCKID,
- xive->regs[(PC_VPC_CWATCH_SPEC >> 3)]);
- uint32_t idx = GETFIELD(PC_VPC_CWATCH_OFFSET,
- xive->regs[(PC_VPC_CWATCH_SPEC >> 3)]);
- int i;
- uint64_t vpc_watch[8];
- for (i = 0; i < ARRAY_SIZE(vpc_watch); i++) {
- vpc_watch[i] = cpu_to_be64(xive->regs[(PC_VPC_CWATCH_DAT0 >> 3) + i]);
- }
- return pnv_xive_vst_write(xive, VST_TSEL_VPDT, blk, idx, vpc_watch,
- XIVE_VST_WORD_ALL);
- }
- static void pnv_xive_nvt_cache_load(PnvXive *xive)
- {
- uint8_t blk = GETFIELD(PC_VPC_CWATCH_BLOCKID,
- xive->regs[(PC_VPC_CWATCH_SPEC >> 3)]);
- uint32_t idx = GETFIELD(PC_VPC_CWATCH_OFFSET,
- xive->regs[(PC_VPC_CWATCH_SPEC >> 3)]);
- uint64_t vpc_watch[8] = { 0 };
- int i;
- if (pnv_xive_vst_read(xive, VST_TSEL_VPDT, blk, idx, vpc_watch)) {
- xive_error(xive, "VST: no NVT entry %x/%x !?", blk, idx);
- }
- for (i = 0; i < ARRAY_SIZE(vpc_watch); i++) {
- xive->regs[(PC_VPC_CWATCH_DAT0 >> 3) + i] = be64_to_cpu(vpc_watch[i]);
- }
- }
- static int pnv_xive_get_eas(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
- XiveEAS *eas)
- {
- PnvXive *xive = PNV_XIVE(xrtr);
- /*
- * EAT lookups should be local to the IC
- */
- if (pnv_xive_block_id(xive) != blk) {
- xive_error(xive, "VST: EAS %x is remote !?", XIVE_EAS(blk, idx));
- return -1;
- }
- return pnv_xive_vst_read(xive, VST_TSEL_IVT, blk, idx, eas);
- }
- static int pnv_xive_get_pq(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
- uint8_t *pq)
- {
- PnvXive *xive = PNV_XIVE(xrtr);
- if (pnv_xive_block_id(xive) != blk) {
- xive_error(xive, "VST: EAS %x is remote !?", XIVE_EAS(blk, idx));
- return -1;
- }
- *pq = xive_source_esb_get(&xive->ipi_source, idx);
- return 0;
- }
- static int pnv_xive_set_pq(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
- uint8_t *pq)
- {
- PnvXive *xive = PNV_XIVE(xrtr);
- if (pnv_xive_block_id(xive) != blk) {
- xive_error(xive, "VST: EAS %x is remote !?", XIVE_EAS(blk, idx));
- return -1;
- }
- *pq = xive_source_esb_set(&xive->ipi_source, idx, *pq);
- return 0;
- }
- /*
- * One bit per thread id. The first register PC_THREAD_EN_REG0 covers
- * the first cores 0-15 (normal) of the chip or 0-7 (fused). The
- * second register covers cores 16-23 (normal) or 8-11 (fused).
- */
- static bool pnv_xive_is_cpu_enabled(PnvXive *xive, PowerPCCPU *cpu)
- {
- int pir = ppc_cpu_pir(cpu);
- uint32_t fc = PNV9_PIR2FUSEDCORE(pir);
- uint64_t reg = fc < 8 ? PC_THREAD_EN_REG0 : PC_THREAD_EN_REG1;
- uint32_t bit = pir & 0x3f;
- return xive->regs[reg >> 3] & PPC_BIT(bit);
- }
- static int pnv_xive_match_nvt(XivePresenter *xptr, uint8_t format,
- uint8_t nvt_blk, uint32_t nvt_idx,
- bool crowd, bool cam_ignore, uint8_t priority,
- uint32_t logic_serv, XiveTCTXMatch *match)
- {
- PnvXive *xive = PNV_XIVE(xptr);
- PnvChip *chip = xive->chip;
- int count = 0;
- int i, j;
- for (i = 0; i < chip->nr_cores; i++) {
- PnvCore *pc = chip->cores[i];
- CPUCore *cc = CPU_CORE(pc);
- for (j = 0; j < cc->nr_threads; j++) {
- PowerPCCPU *cpu = pc->threads[j];
- XiveTCTX *tctx;
- int ring;
- if (!pnv_xive_is_cpu_enabled(xive, cpu)) {
- continue;
- }
- tctx = XIVE_TCTX(pnv_cpu_state(cpu)->intc);
- /*
- * 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);
- /*
- * Save the context and follow on to catch duplicates, that we
- * don't support yet.
- */
- if (ring != -1) {
- if (match->tctx) {
- qemu_log_mask(LOG_GUEST_ERROR, "XIVE: already found a "
- "thread context NVT %x/%x\n",
- nvt_blk, nvt_idx);
- return -1;
- }
- match->ring = ring;
- match->tctx = tctx;
- count++;
- }
- }
- }
- return count;
- }
- static uint32_t pnv_xive_presenter_get_config(XivePresenter *xptr)
- {
- uint32_t cfg = 0;
- /* TIMA GEN1 is all P9 knows */
- cfg |= XIVE_PRESENTER_GEN1_TIMA_OS;
- return cfg;
- }
- static uint8_t pnv_xive_get_block_id(XiveRouter *xrtr)
- {
- return pnv_xive_block_id(PNV_XIVE(xrtr));
- }
- /*
- * The TIMA MMIO space is shared among the chips and to identify the
- * chip from which the access is being done, we extract the chip id
- * from the PIR.
- */
- static PnvXive *pnv_xive_tm_get_xive(PowerPCCPU *cpu)
- {
- int pir = ppc_cpu_pir(cpu);
- XivePresenter *xptr = XIVE_TCTX(pnv_cpu_state(cpu)->intc)->xptr;
- PnvXive *xive = PNV_XIVE(xptr);
- if (!pnv_xive_is_cpu_enabled(xive, cpu)) {
- xive_error(xive, "IC: CPU %x is not enabled", pir);
- }
- return xive;
- }
- /*
- * The internal sources (IPIs) of the interrupt controller have no
- * knowledge of the XIVE chip on which they reside. Encode the block
- * id in the source interrupt number before forwarding the source
- * event notification to the Router. This is required on a multichip
- * system.
- */
- static void pnv_xive_notify(XiveNotifier *xn, uint32_t srcno, bool pq_checked)
- {
- PnvXive *xive = PNV_XIVE(xn);
- uint8_t blk = pnv_xive_block_id(xive);
- xive_router_notify(xn, XIVE_EAS(blk, srcno), pq_checked);
- }
- /*
- * XIVE helpers
- */
- static uint64_t pnv_xive_vc_size(PnvXive *xive)
- {
- return (~xive->regs[CQ_VC_BARM >> 3] + 1) & CQ_VC_BARM_MASK;
- }
- static uint64_t pnv_xive_edt_shift(PnvXive *xive)
- {
- return ctz64(pnv_xive_vc_size(xive) / XIVE_TABLE_EDT_MAX);
- }
- static uint64_t pnv_xive_pc_size(PnvXive *xive)
- {
- return (~xive->regs[CQ_PC_BARM >> 3] + 1) & CQ_PC_BARM_MASK;
- }
- static uint32_t pnv_xive_nr_ipis(PnvXive *xive, uint8_t blk)
- {
- uint64_t vsd = xive->vsds[VST_TSEL_SBE][blk];
- uint64_t vst_tsize = 1ull << (GETFIELD(VSD_TSIZE, vsd) + 12);
- return VSD_INDIRECT & vsd ? 0 : vst_tsize * SBE_PER_BYTE;
- }
- /*
- * Compute the number of entries per indirect subpage.
- */
- static uint64_t pnv_xive_vst_per_subpage(PnvXive *xive, uint32_t type)
- {
- uint8_t blk = pnv_xive_block_id(xive);
- uint64_t vsd = xive->vsds[type][blk];
- const XiveVstInfo *info = &vst_infos[type];
- uint64_t vsd_addr;
- uint32_t page_shift;
- /* For direct tables, fake a valid value */
- if (!(VSD_INDIRECT & vsd)) {
- return 1;
- }
- /* Get the page size of the indirect table. */
- vsd_addr = vsd & VSD_ADDRESS_MASK;
- if (ldq_be_dma(&address_space_memory, vsd_addr, &vsd,
- MEMTXATTRS_UNSPECIFIED)) {
- xive_error(xive, "VST: failed to access %s entry @0x%" PRIx64,
- info->name, vsd_addr);
- return 0;
- }
- if (!(vsd & VSD_ADDRESS_MASK)) {
- #ifdef XIVE_DEBUG
- xive_error(xive, "VST: invalid %s entry %x !?", info->name, idx);
- #endif
- return 0;
- }
- page_shift = GETFIELD(VSD_TSIZE, vsd) + 12;
- if (!pnv_xive_vst_page_size_allowed(page_shift)) {
- xive_error(xive, "VST: invalid %s page shift %d", info->name,
- page_shift);
- return 0;
- }
- return (1ull << page_shift) / info->size;
- }
- /*
- * EDT Table
- *
- * The Virtualization Controller MMIO region containing the IPI ESB
- * pages and END ESB pages is sub-divided into "sets" which map
- * portions of the VC region to the different ESB pages. It is
- * configured at runtime through the EDT "Domain Table" to let the
- * firmware decide how to split the VC address space between IPI ESB
- * pages and END ESB pages.
- */
- /*
- * Computes the overall size of the IPI or the END ESB pages
- */
- static uint64_t pnv_xive_edt_size(PnvXive *xive, uint64_t type)
- {
- uint64_t edt_size = 1ull << pnv_xive_edt_shift(xive);
- uint64_t size = 0;
- int i;
- for (i = 0; i < XIVE_TABLE_EDT_MAX; i++) {
- uint64_t edt_type = GETFIELD(CQ_TDR_EDT_TYPE, xive->edt[i]);
- if (edt_type == type) {
- size += edt_size;
- }
- }
- return size;
- }
- /*
- * Maps an offset of the VC region in the IPI or END region using the
- * layout defined by the EDT "Domaine Table"
- */
- static uint64_t pnv_xive_edt_offset(PnvXive *xive, uint64_t vc_offset,
- uint64_t type)
- {
- int i;
- uint64_t edt_size = 1ull << pnv_xive_edt_shift(xive);
- uint64_t edt_offset = vc_offset;
- for (i = 0; i < XIVE_TABLE_EDT_MAX && (i * edt_size) < vc_offset; i++) {
- uint64_t edt_type = GETFIELD(CQ_TDR_EDT_TYPE, xive->edt[i]);
- if (edt_type != type) {
- edt_offset -= edt_size;
- }
- }
- return edt_offset;
- }
- static void pnv_xive_edt_resize(PnvXive *xive)
- {
- uint64_t ipi_edt_size = pnv_xive_edt_size(xive, CQ_TDR_EDT_IPI);
- uint64_t end_edt_size = pnv_xive_edt_size(xive, CQ_TDR_EDT_EQ);
- memory_region_set_size(&xive->ipi_edt_mmio, ipi_edt_size);
- memory_region_add_subregion(&xive->ipi_mmio, 0, &xive->ipi_edt_mmio);
- memory_region_set_size(&xive->end_edt_mmio, end_edt_size);
- memory_region_add_subregion(&xive->end_mmio, 0, &xive->end_edt_mmio);
- }
- /*
- * XIVE Table configuration. Only EDT is supported.
- */
- static int pnv_xive_table_set_data(PnvXive *xive, uint64_t val)
- {
- uint64_t tsel = xive->regs[CQ_TAR >> 3] & CQ_TAR_TSEL;
- uint8_t tsel_index = GETFIELD(CQ_TAR_TSEL_INDEX, xive->regs[CQ_TAR >> 3]);
- uint64_t *xive_table;
- uint8_t max_index;
- switch (tsel) {
- case CQ_TAR_TSEL_BLK:
- max_index = ARRAY_SIZE(xive->blk);
- xive_table = xive->blk;
- break;
- case CQ_TAR_TSEL_MIG:
- max_index = ARRAY_SIZE(xive->mig);
- xive_table = xive->mig;
- break;
- case CQ_TAR_TSEL_EDT:
- max_index = ARRAY_SIZE(xive->edt);
- xive_table = xive->edt;
- break;
- case CQ_TAR_TSEL_VDT:
- max_index = ARRAY_SIZE(xive->vdt);
- xive_table = xive->vdt;
- break;
- default:
- xive_error(xive, "IC: invalid table %d", (int) tsel);
- return -1;
- }
- if (tsel_index >= max_index) {
- xive_error(xive, "IC: invalid index %d", (int) tsel_index);
- return -1;
- }
- xive_table[tsel_index] = val;
- if (xive->regs[CQ_TAR >> 3] & CQ_TAR_TBL_AUTOINC) {
- xive->regs[CQ_TAR >> 3] =
- SETFIELD(CQ_TAR_TSEL_INDEX, xive->regs[CQ_TAR >> 3], ++tsel_index);
- }
- /*
- * EDT configuration is complete. Resize the MMIO windows exposing
- * the IPI and the END ESBs in the VC region.
- */
- if (tsel == CQ_TAR_TSEL_EDT && tsel_index == ARRAY_SIZE(xive->edt)) {
- pnv_xive_edt_resize(xive);
- }
- return 0;
- }
- /*
- * Virtual Structure Tables (VST) configuration
- */
- static void pnv_xive_vst_set_exclusive(PnvXive *xive, uint8_t type,
- uint8_t blk, uint64_t vsd)
- {
- XiveENDSource *end_xsrc = &xive->end_source;
- XiveSource *xsrc = &xive->ipi_source;
- const XiveVstInfo *info = &vst_infos[type];
- uint32_t page_shift = GETFIELD(VSD_TSIZE, vsd) + 12;
- uint64_t vst_tsize = 1ull << page_shift;
- uint64_t vst_addr = vsd & VSD_ADDRESS_MASK;
- /* Basic checks */
- if (VSD_INDIRECT & vsd) {
- if (!(xive->regs[VC_GLOBAL_CONFIG >> 3] & VC_GCONF_INDIRECT)) {
- xive_error(xive, "VST: %s indirect tables are not enabled",
- info->name);
- return;
- }
- if (!pnv_xive_vst_page_size_allowed(page_shift)) {
- xive_error(xive, "VST: invalid %s page shift %d", info->name,
- page_shift);
- return;
- }
- }
- if (!QEMU_IS_ALIGNED(vst_addr, 1ull << page_shift)) {
- xive_error(xive, "VST: %s table address 0x%"PRIx64" is not aligned with"
- " page shift %d", info->name, vst_addr, page_shift);
- return;
- }
- /* Record the table configuration (in SRAM on HW) */
- xive->vsds[type][blk] = vsd;
- /* Now tune the models with the configuration provided by the FW */
- switch (type) {
- case VST_TSEL_IVT: /* Nothing to be done */
- break;
- case VST_TSEL_EQDT:
- /*
- * Backing store pages for the END.
- *
- * If the table is direct, we can compute the number of PQ
- * entries provisioned by FW (such as skiboot) and resize the
- * END ESB window accordingly.
- */
- if (!(VSD_INDIRECT & vsd)) {
- memory_region_set_size(&end_xsrc->esb_mmio, (vst_tsize / info->size)
- * (1ull << xsrc->esb_shift));
- }
- memory_region_add_subregion(&xive->end_edt_mmio, 0,
- &end_xsrc->esb_mmio);
- break;
- case VST_TSEL_SBE:
- /*
- * Backing store pages for the source PQ bits. The model does
- * not use these PQ bits backed in RAM because the XiveSource
- * model has its own.
- *
- * If the table is direct, we can compute the number of PQ
- * entries provisioned by FW (such as skiboot) and resize the
- * ESB window accordingly.
- */
- if (!(VSD_INDIRECT & vsd)) {
- memory_region_set_size(&xsrc->esb_mmio, vst_tsize * SBE_PER_BYTE
- * (1ull << xsrc->esb_shift));
- }
- memory_region_add_subregion(&xive->ipi_edt_mmio, 0, &xsrc->esb_mmio);
- break;
- case VST_TSEL_VPDT: /* Not modeled */
- case VST_TSEL_IRQ: /* Not modeled */
- /*
- * These tables contains the backing store pages for the
- * interrupt fifos of the VC sub-engine in case of overflow.
- */
- break;
- default:
- g_assert_not_reached();
- }
- }
- /*
- * Both PC and VC sub-engines are configured as each use the Virtual
- * Structure Tables : SBE, EAS, END and NVT.
- */
- static void pnv_xive_vst_set_data(PnvXive *xive, uint64_t vsd, bool pc_engine)
- {
- uint8_t mode = GETFIELD(VSD_MODE, vsd);
- uint8_t type = GETFIELD(VST_TABLE_SELECT,
- xive->regs[VC_VSD_TABLE_ADDR >> 3]);
- uint8_t blk = GETFIELD(VST_TABLE_BLOCK,
- xive->regs[VC_VSD_TABLE_ADDR >> 3]);
- uint64_t vst_addr = vsd & VSD_ADDRESS_MASK;
- if (type > VST_TSEL_IRQ) {
- xive_error(xive, "VST: invalid table type %d", type);
- return;
- }
- if (blk >= vst_infos[type].max_blocks) {
- xive_error(xive, "VST: invalid block id %d for"
- " %s table", blk, vst_infos[type].name);
- return;
- }
- /*
- * Only take the VC sub-engine configuration into account because
- * the XiveRouter model combines both VC and PC sub-engines
- */
- if (pc_engine) {
- return;
- }
- if (!vst_addr) {
- xive_error(xive, "VST: invalid %s table address", vst_infos[type].name);
- return;
- }
- switch (mode) {
- case VSD_MODE_FORWARD:
- xive->vsds[type][blk] = vsd;
- break;
- case VSD_MODE_EXCLUSIVE:
- pnv_xive_vst_set_exclusive(xive, type, blk, vsd);
- break;
- default:
- xive_error(xive, "VST: unsupported table mode %d", mode);
- return;
- }
- }
- /*
- * Interrupt controller MMIO region. The layout is compatible between
- * 4K and 64K pages :
- *
- * Page 0 sub-engine BARs
- * 0x000 - 0x3FF IC registers
- * 0x400 - 0x7FF PC registers
- * 0x800 - 0xFFF VC registers
- *
- * Page 1 Notify page (writes only)
- * 0x000 - 0x7FF HW interrupt triggers (PSI, PHB)
- * 0x800 - 0xFFF forwards and syncs
- *
- * Page 2 LSI Trigger page (writes only) (not modeled)
- * Page 3 LSI SB EOI page (reads only) (not modeled)
- *
- * Page 4-7 indirect TIMA
- */
- /*
- * IC - registers MMIO
- */
- static void pnv_xive_ic_reg_write(void *opaque, hwaddr offset,
- uint64_t val, unsigned size)
- {
- PnvXive *xive = PNV_XIVE(opaque);
- MemoryRegion *sysmem = get_system_memory();
- uint32_t reg = offset >> 3;
- bool is_chip0 = xive->chip->chip_id == 0;
- switch (offset) {
- /*
- * XIVE CQ (PowerBus bridge) settings
- */
- case CQ_MSGSND: /* msgsnd for doorbells */
- case CQ_FIRMASK_OR: /* FIR error reporting */
- break;
- case CQ_PBI_CTL:
- if (val & CQ_PBI_PC_64K) {
- xive->pc_shift = 16;
- }
- if (val & CQ_PBI_VC_64K) {
- xive->vc_shift = 16;
- }
- break;
- case CQ_CFG_PB_GEN: /* PowerBus General Configuration */
- /*
- * TODO: CQ_INT_ADDR_OPT for 1-block-per-chip mode
- */
- break;
- /*
- * XIVE Virtualization Controller settings
- */
- case VC_GLOBAL_CONFIG:
- break;
- /*
- * XIVE Presenter Controller settings
- */
- case PC_GLOBAL_CONFIG:
- /*
- * PC_GCONF_CHIPID_OVR
- * Overrides Int command Chip ID with the Chip ID field (DEBUG)
- */
- break;
- case PC_TCTXT_CFG:
- /*
- * TODO: block group support
- */
- break;
- case PC_TCTXT_TRACK:
- /*
- * PC_TCTXT_TRACK_EN:
- * enable block tracking and exchange of block ownership
- * information between Interrupt controllers
- */
- break;
- /*
- * Misc settings
- */
- case VC_SBC_CONFIG: /* Store EOI configuration */
- /*
- * Configure store EOI if required by firmware (skiboot has removed
- * support recently though)
- */
- if (val & (VC_SBC_CONF_CPLX_CIST | VC_SBC_CONF_CIST_BOTH)) {
- xive->ipi_source.esb_flags |= XIVE_SRC_STORE_EOI;
- }
- break;
- case VC_EQC_CONFIG: /* TODO: silent escalation */
- case VC_AIB_TX_ORDER_TAG2: /* relax ordering */
- break;
- /*
- * XIVE BAR settings (XSCOM only)
- */
- case CQ_RST_CTL:
- /* bit4: resets all BAR registers */
- break;
- case CQ_IC_BAR: /* IC BAR. 8 pages */
- xive->ic_shift = val & CQ_IC_BAR_64K ? 16 : 12;
- if (!(val & CQ_IC_BAR_VALID)) {
- xive->ic_base = 0;
- if (xive->regs[reg] & CQ_IC_BAR_VALID) {
- memory_region_del_subregion(&xive->ic_mmio,
- &xive->ic_reg_mmio);
- memory_region_del_subregion(&xive->ic_mmio,
- &xive->ic_notify_mmio);
- memory_region_del_subregion(&xive->ic_mmio,
- &xive->ic_lsi_mmio);
- memory_region_del_subregion(&xive->ic_mmio,
- &xive->tm_indirect_mmio);
- memory_region_del_subregion(sysmem, &xive->ic_mmio);
- }
- } else {
- xive->ic_base = val & ~(CQ_IC_BAR_VALID | CQ_IC_BAR_64K);
- if (!(xive->regs[reg] & CQ_IC_BAR_VALID)) {
- memory_region_add_subregion(sysmem, xive->ic_base,
- &xive->ic_mmio);
- memory_region_add_subregion(&xive->ic_mmio, 0,
- &xive->ic_reg_mmio);
- memory_region_add_subregion(&xive->ic_mmio,
- 1ul << xive->ic_shift,
- &xive->ic_notify_mmio);
- memory_region_add_subregion(&xive->ic_mmio,
- 2ul << xive->ic_shift,
- &xive->ic_lsi_mmio);
- memory_region_add_subregion(&xive->ic_mmio,
- 4ull << xive->ic_shift,
- &xive->tm_indirect_mmio);
- }
- }
- break;
- case CQ_TM1_BAR: /* TM BAR. 4 pages. Map only once */
- case CQ_TM2_BAR: /* second TM BAR. for hotplug. Not modeled */
- xive->tm_shift = val & CQ_TM_BAR_64K ? 16 : 12;
- if (!(val & CQ_TM_BAR_VALID)) {
- xive->tm_base = 0;
- if (xive->regs[reg] & CQ_TM_BAR_VALID && is_chip0) {
- memory_region_del_subregion(sysmem, &xive->tm_mmio);
- }
- } else {
- xive->tm_base = val & ~(CQ_TM_BAR_VALID | CQ_TM_BAR_64K);
- if (!(xive->regs[reg] & CQ_TM_BAR_VALID) && is_chip0) {
- memory_region_add_subregion(sysmem, xive->tm_base,
- &xive->tm_mmio);
- }
- }
- break;
- case CQ_PC_BARM:
- xive->regs[reg] = val;
- memory_region_set_size(&xive->pc_mmio, pnv_xive_pc_size(xive));
- break;
- case CQ_PC_BAR: /* From 32M to 512G */
- if (!(val & CQ_PC_BAR_VALID)) {
- xive->pc_base = 0;
- if (xive->regs[reg] & CQ_PC_BAR_VALID) {
- memory_region_del_subregion(sysmem, &xive->pc_mmio);
- }
- } else {
- xive->pc_base = val & ~(CQ_PC_BAR_VALID);
- if (!(xive->regs[reg] & CQ_PC_BAR_VALID)) {
- memory_region_add_subregion(sysmem, xive->pc_base,
- &xive->pc_mmio);
- }
- }
- break;
- case CQ_VC_BARM:
- xive->regs[reg] = val;
- memory_region_set_size(&xive->vc_mmio, pnv_xive_vc_size(xive));
- break;
- case CQ_VC_BAR: /* From 64M to 4TB */
- if (!(val & CQ_VC_BAR_VALID)) {
- xive->vc_base = 0;
- if (xive->regs[reg] & CQ_VC_BAR_VALID) {
- memory_region_del_subregion(sysmem, &xive->vc_mmio);
- }
- } else {
- xive->vc_base = val & ~(CQ_VC_BAR_VALID);
- if (!(xive->regs[reg] & CQ_VC_BAR_VALID)) {
- memory_region_add_subregion(sysmem, xive->vc_base,
- &xive->vc_mmio);
- }
- }
- break;
- /*
- * XIVE Table settings.
- */
- case CQ_TAR: /* Table Address */
- break;
- case CQ_TDR: /* Table Data */
- pnv_xive_table_set_data(xive, val);
- break;
- /*
- * XIVE VC & PC Virtual Structure Table settings
- */
- case VC_VSD_TABLE_ADDR:
- case PC_VSD_TABLE_ADDR: /* Virtual table selector */
- break;
- case VC_VSD_TABLE_DATA: /* Virtual table setting */
- case PC_VSD_TABLE_DATA:
- pnv_xive_vst_set_data(xive, val, offset == PC_VSD_TABLE_DATA);
- break;
- /*
- * Interrupt fifo overflow in memory backing store (Not modeled)
- */
- case VC_IRQ_CONFIG_IPI:
- case VC_IRQ_CONFIG_HW:
- case VC_IRQ_CONFIG_CASCADE1:
- case VC_IRQ_CONFIG_CASCADE2:
- case VC_IRQ_CONFIG_REDIST:
- case VC_IRQ_CONFIG_IPI_CASC:
- break;
- /*
- * XIVE hardware thread enablement
- */
- case PC_THREAD_EN_REG0: /* Physical Thread Enable */
- case PC_THREAD_EN_REG1: /* Physical Thread Enable (fused core) */
- break;
- case PC_THREAD_EN_REG0_SET:
- xive->regs[PC_THREAD_EN_REG0 >> 3] |= val;
- break;
- case PC_THREAD_EN_REG1_SET:
- xive->regs[PC_THREAD_EN_REG1 >> 3] |= val;
- break;
- case PC_THREAD_EN_REG0_CLR:
- xive->regs[PC_THREAD_EN_REG0 >> 3] &= ~val;
- break;
- case PC_THREAD_EN_REG1_CLR:
- xive->regs[PC_THREAD_EN_REG1 >> 3] &= ~val;
- break;
- /*
- * Indirect TIMA access set up. Defines the PIR of the HW thread
- * to use.
- */
- case PC_TCTXT_INDIR0 ... PC_TCTXT_INDIR3:
- break;
- /*
- * XIVE PC & VC cache updates for EAS, NVT and END
- */
- case VC_IVC_SCRUB_MASK:
- case VC_IVC_SCRUB_TRIG:
- break;
- case VC_EQC_CWATCH_SPEC:
- val &= ~VC_EQC_CWATCH_CONFLICT; /* HW resets this bit */
- break;
- case VC_EQC_CWATCH_DAT1 ... VC_EQC_CWATCH_DAT3:
- break;
- case VC_EQC_CWATCH_DAT0:
- /* writing to DATA0 triggers the cache write */
- xive->regs[reg] = val;
- pnv_xive_end_update(xive);
- break;
- case VC_EQC_SCRUB_MASK:
- case VC_EQC_SCRUB_TRIG:
- /*
- * The scrubbing registers flush the cache in RAM and can also
- * invalidate.
- */
- break;
- case PC_VPC_CWATCH_SPEC:
- val &= ~PC_VPC_CWATCH_CONFLICT; /* HW resets this bit */
- break;
- case PC_VPC_CWATCH_DAT1 ... PC_VPC_CWATCH_DAT7:
- break;
- case PC_VPC_CWATCH_DAT0:
- /* writing to DATA0 triggers the cache write */
- xive->regs[reg] = val;
- pnv_xive_nvt_update(xive);
- break;
- case PC_VPC_SCRUB_MASK:
- case PC_VPC_SCRUB_TRIG:
- /*
- * The scrubbing registers flush the cache in RAM and can also
- * invalidate.
- */
- break;
- /*
- * XIVE PC & VC cache invalidation
- */
- case PC_AT_KILL:
- break;
- case VC_AT_MACRO_KILL:
- break;
- case PC_AT_KILL_MASK:
- case VC_AT_MACRO_KILL_MASK:
- break;
- default:
- xive_error(xive, "IC: invalid write to reg=0x%"HWADDR_PRIx, offset);
- return;
- }
- xive->regs[reg] = val;
- }
- static uint64_t pnv_xive_ic_reg_read(void *opaque, hwaddr offset, unsigned size)
- {
- PnvXive *xive = PNV_XIVE(opaque);
- uint64_t val = 0;
- uint32_t reg = offset >> 3;
- switch (offset) {
- case CQ_CFG_PB_GEN:
- case CQ_IC_BAR:
- case CQ_TM1_BAR:
- case CQ_TM2_BAR:
- case CQ_PC_BAR:
- case CQ_PC_BARM:
- case CQ_VC_BAR:
- case CQ_VC_BARM:
- case CQ_TAR:
- case CQ_TDR:
- case CQ_PBI_CTL:
- case PC_TCTXT_CFG:
- case PC_TCTXT_TRACK:
- case PC_TCTXT_INDIR0:
- case PC_TCTXT_INDIR1:
- case PC_TCTXT_INDIR2:
- case PC_TCTXT_INDIR3:
- case PC_GLOBAL_CONFIG:
- case PC_VPC_SCRUB_MASK:
- case VC_GLOBAL_CONFIG:
- case VC_AIB_TX_ORDER_TAG2:
- case VC_IRQ_CONFIG_IPI:
- case VC_IRQ_CONFIG_HW:
- case VC_IRQ_CONFIG_CASCADE1:
- case VC_IRQ_CONFIG_CASCADE2:
- case VC_IRQ_CONFIG_REDIST:
- case VC_IRQ_CONFIG_IPI_CASC:
- case VC_EQC_SCRUB_MASK:
- case VC_IVC_SCRUB_MASK:
- case VC_SBC_CONFIG:
- case VC_AT_MACRO_KILL_MASK:
- case VC_VSD_TABLE_ADDR:
- case PC_VSD_TABLE_ADDR:
- case VC_VSD_TABLE_DATA:
- case PC_VSD_TABLE_DATA:
- case PC_THREAD_EN_REG0:
- case PC_THREAD_EN_REG1:
- val = xive->regs[reg];
- break;
- /*
- * XIVE hardware thread enablement
- */
- case PC_THREAD_EN_REG0_SET:
- case PC_THREAD_EN_REG0_CLR:
- val = xive->regs[PC_THREAD_EN_REG0 >> 3];
- break;
- case PC_THREAD_EN_REG1_SET:
- case PC_THREAD_EN_REG1_CLR:
- val = xive->regs[PC_THREAD_EN_REG1 >> 3];
- break;
- case CQ_MSGSND: /* Identifies which cores have msgsnd enabled. */
- val = 0xffffff0000000000;
- break;
- /*
- * XIVE PC & VC cache updates for EAS, NVT and END
- */
- case VC_EQC_CWATCH_SPEC:
- xive->regs[reg] = ~(VC_EQC_CWATCH_FULL | VC_EQC_CWATCH_CONFLICT);
- val = xive->regs[reg];
- break;
- case VC_EQC_CWATCH_DAT0:
- /*
- * Load DATA registers from cache with data requested by the
- * SPEC register
- */
- pnv_xive_end_cache_load(xive);
- val = xive->regs[reg];
- break;
- case VC_EQC_CWATCH_DAT1 ... VC_EQC_CWATCH_DAT3:
- val = xive->regs[reg];
- break;
- case PC_VPC_CWATCH_SPEC:
- xive->regs[reg] = ~(PC_VPC_CWATCH_FULL | PC_VPC_CWATCH_CONFLICT);
- val = xive->regs[reg];
- break;
- case PC_VPC_CWATCH_DAT0:
- /*
- * Load DATA registers from cache with data requested by the
- * SPEC register
- */
- pnv_xive_nvt_cache_load(xive);
- val = xive->regs[reg];
- break;
- case PC_VPC_CWATCH_DAT1 ... PC_VPC_CWATCH_DAT7:
- val = xive->regs[reg];
- break;
- case PC_VPC_SCRUB_TRIG:
- case VC_IVC_SCRUB_TRIG:
- case VC_EQC_SCRUB_TRIG:
- xive->regs[reg] &= ~VC_SCRUB_VALID;
- val = xive->regs[reg];
- break;
- /*
- * XIVE PC & VC cache invalidation
- */
- case PC_AT_KILL:
- xive->regs[reg] &= ~PC_AT_KILL_VALID;
- val = xive->regs[reg];
- break;
- case VC_AT_MACRO_KILL:
- xive->regs[reg] &= ~VC_KILL_VALID;
- val = xive->regs[reg];
- break;
- /*
- * XIVE synchronisation
- */
- case VC_EQC_CONFIG:
- val = VC_EQC_SYNC_MASK;
- break;
- default:
- xive_error(xive, "IC: invalid read reg=0x%"HWADDR_PRIx, offset);
- }
- return val;
- }
- static const MemoryRegionOps pnv_xive_ic_reg_ops = {
- .read = pnv_xive_ic_reg_read,
- .write = pnv_xive_ic_reg_write,
- .endianness = DEVICE_BIG_ENDIAN,
- .valid = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
- };
- /*
- * IC - Notify MMIO port page (write only)
- */
- #define PNV_XIVE_FORWARD_IPI 0x800 /* Forward IPI */
- #define PNV_XIVE_FORWARD_HW 0x880 /* Forward HW */
- #define PNV_XIVE_FORWARD_OS_ESC 0x900 /* Forward OS escalation */
- #define PNV_XIVE_FORWARD_HW_ESC 0x980 /* Forward Hyp escalation */
- #define PNV_XIVE_FORWARD_REDIS 0xa00 /* Forward Redistribution */
- #define PNV_XIVE_RESERVED5 0xa80 /* Cache line 5 PowerBUS operation */
- #define PNV_XIVE_RESERVED6 0xb00 /* Cache line 6 PowerBUS operation */
- #define PNV_XIVE_RESERVED7 0xb80 /* Cache line 7 PowerBUS operation */
- /* VC synchronisation */
- #define PNV_XIVE_SYNC_IPI 0xc00 /* Sync IPI */
- #define PNV_XIVE_SYNC_HW 0xc80 /* Sync HW */
- #define PNV_XIVE_SYNC_OS_ESC 0xd00 /* Sync OS escalation */
- #define PNV_XIVE_SYNC_HW_ESC 0xd80 /* Sync Hyp escalation */
- #define PNV_XIVE_SYNC_REDIS 0xe00 /* Sync Redistribution */
- /* PC synchronisation */
- #define PNV_XIVE_SYNC_PULL 0xe80 /* Sync pull context */
- #define PNV_XIVE_SYNC_PUSH 0xf00 /* Sync push context */
- #define PNV_XIVE_SYNC_VPC 0xf80 /* Sync remove VPC store */
- static void pnv_xive_end_notify(XiveRouter *xrtr, XiveEAS *eas)
- {
- PnvXive *xive = PNV_XIVE(xrtr);
- uint8_t end_blk = xive_get_field64(EAS_END_BLOCK, eas->w);
- uint32_t end_idx = xive_get_field64(EAS_END_INDEX, eas->w);
- uint32_t end_data = xive_get_field64(EAS_END_DATA, eas->w);
- uint64_t end_vsd = xive->vsds[VST_TSEL_EQDT][end_blk];
- switch (GETFIELD(VSD_MODE, end_vsd)) {
- case VSD_MODE_EXCLUSIVE:
- /* Perform the END notification on the local IC. */
- xive_router_end_notify(xrtr, eas);
- break;
- case VSD_MODE_FORWARD: {
- MemTxResult result;
- uint64_t notif_port = end_vsd & VSD_ADDRESS_MASK;
- uint64_t data = XIVE_TRIGGER_END | XIVE_TRIGGER_PQ |
- be64_to_cpu(eas->w);
- /* Forward the store on the remote IC notify page. */
- address_space_stq_be(&address_space_memory, notif_port, data,
- MEMTXATTRS_UNSPECIFIED, &result);
- if (result != MEMTX_OK) {
- xive_error(xive, "IC: Forward notif END %x/%x [%x] failed @%"
- HWADDR_PRIx, end_blk, end_idx, end_data, notif_port);
- return;
- }
- break;
- }
- case VSD_MODE_INVALID:
- default:
- /* Set FIR */
- xive_error(xive, "IC: Invalid END VSD for block %x", end_blk);
- return;
- }
- }
- /*
- * The notify page can either be used to receive trigger events from
- * the HW controllers (PHB, PSI) or to reroute interrupts between
- * Interrupt controllers.
- */
- static void pnv_xive_ic_hw_trigger(PnvXive *xive, hwaddr addr, uint64_t val)
- {
- uint8_t blk;
- uint32_t idx;
- trace_pnv_xive_ic_hw_trigger(addr, val);
- if (val & XIVE_TRIGGER_END) {
- val = cpu_to_be64(val);
- pnv_xive_end_notify(XIVE_ROUTER(xive), (XiveEAS *) &val);
- return;
- }
- /*
- * Forward the source event notification directly to the Router.
- * The source interrupt number should already be correctly encoded
- * with the chip block id by the sending device (PHB, PSI).
- */
- blk = XIVE_EAS_BLOCK(val);
- idx = XIVE_EAS_INDEX(val);
- xive_router_notify(XIVE_NOTIFIER(xive), XIVE_EAS(blk, idx),
- !!(val & XIVE_TRIGGER_PQ));
- }
- static void pnv_xive_ic_notify_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
- {
- PnvXive *xive = PNV_XIVE(opaque);
- /* VC: HW triggers */
- switch (addr) {
- case 0x000 ... 0x7FF:
- pnv_xive_ic_hw_trigger(opaque, addr, val);
- break;
- /* VC: Forwarded IRQs */
- case PNV_XIVE_FORWARD_IPI:
- case PNV_XIVE_FORWARD_HW:
- case PNV_XIVE_FORWARD_OS_ESC:
- case PNV_XIVE_FORWARD_HW_ESC:
- case PNV_XIVE_FORWARD_REDIS:
- /* TODO: forwarded IRQs. Should be like HW triggers */
- xive_error(xive, "IC: forwarded at @0x%"HWADDR_PRIx" IRQ 0x%"PRIx64,
- addr, val);
- break;
- /* VC syncs */
- case PNV_XIVE_SYNC_IPI:
- case PNV_XIVE_SYNC_HW:
- case PNV_XIVE_SYNC_OS_ESC:
- case PNV_XIVE_SYNC_HW_ESC:
- case PNV_XIVE_SYNC_REDIS:
- break;
- /* PC syncs */
- case PNV_XIVE_SYNC_PULL:
- case PNV_XIVE_SYNC_PUSH:
- case PNV_XIVE_SYNC_VPC:
- break;
- default:
- xive_error(xive, "IC: invalid notify write @%"HWADDR_PRIx, addr);
- }
- }
- static uint64_t pnv_xive_ic_notify_read(void *opaque, hwaddr addr,
- unsigned size)
- {
- PnvXive *xive = PNV_XIVE(opaque);
- /* loads are invalid */
- xive_error(xive, "IC: invalid notify read @%"HWADDR_PRIx, addr);
- return -1;
- }
- static const MemoryRegionOps pnv_xive_ic_notify_ops = {
- .read = pnv_xive_ic_notify_read,
- .write = pnv_xive_ic_notify_write,
- .endianness = DEVICE_BIG_ENDIAN,
- .valid = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
- };
- /*
- * IC - LSI MMIO handlers (not modeled)
- */
- static void pnv_xive_ic_lsi_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
- {
- PnvXive *xive = PNV_XIVE(opaque);
- xive_error(xive, "IC: LSI invalid write @%"HWADDR_PRIx, addr);
- }
- static uint64_t pnv_xive_ic_lsi_read(void *opaque, hwaddr addr, unsigned size)
- {
- PnvXive *xive = PNV_XIVE(opaque);
- xive_error(xive, "IC: LSI invalid read @%"HWADDR_PRIx, addr);
- return -1;
- }
- static const MemoryRegionOps pnv_xive_ic_lsi_ops = {
- .read = pnv_xive_ic_lsi_read,
- .write = pnv_xive_ic_lsi_write,
- .endianness = DEVICE_BIG_ENDIAN,
- .valid = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
- };
- /*
- * IC - Indirect TIMA MMIO handlers
- */
- /*
- * When the TIMA is accessed from the indirect page, the thread id of
- * the target CPU is configured in the PC_TCTXT_INDIR0 register before
- * use. This is used for resets and for debug purpose also.
- */
- static XiveTCTX *pnv_xive_get_indirect_tctx(PnvXive *xive)
- {
- PnvChip *chip = xive->chip;
- uint64_t tctxt_indir = xive->regs[PC_TCTXT_INDIR0 >> 3];
- PowerPCCPU *cpu = NULL;
- int pir;
- if (!(tctxt_indir & PC_TCTXT_INDIR_VALID)) {
- xive_error(xive, "IC: no indirect TIMA access in progress");
- return NULL;
- }
- pir = (chip->chip_id << 8) | GETFIELD(PC_TCTXT_INDIR_THRDID, tctxt_indir);
- cpu = pnv_chip_find_cpu(chip, pir);
- if (!cpu) {
- xive_error(xive, "IC: invalid PIR %x for indirect access", pir);
- return NULL;
- }
- /* Check that HW thread is XIVE enabled */
- if (!pnv_xive_is_cpu_enabled(xive, cpu)) {
- xive_error(xive, "IC: CPU %x is not enabled", pir);
- }
- return XIVE_TCTX(pnv_cpu_state(cpu)->intc);
- }
- static void xive_tm_indirect_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
- {
- XiveTCTX *tctx = pnv_xive_get_indirect_tctx(PNV_XIVE(opaque));
- xive_tctx_tm_write(XIVE_PRESENTER(opaque), tctx, offset, value, size);
- }
- static uint64_t xive_tm_indirect_read(void *opaque, hwaddr offset,
- unsigned size)
- {
- XiveTCTX *tctx = pnv_xive_get_indirect_tctx(PNV_XIVE(opaque));
- return xive_tctx_tm_read(XIVE_PRESENTER(opaque), tctx, offset, size);
- }
- static const MemoryRegionOps xive_tm_indirect_ops = {
- .read = xive_tm_indirect_read,
- .write = xive_tm_indirect_write,
- .endianness = DEVICE_BIG_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 1,
- .max_access_size = 8,
- },
- };
- static void pnv_xive_tm_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
- {
- PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
- PnvXive *xive = pnv_xive_tm_get_xive(cpu);
- XiveTCTX *tctx = XIVE_TCTX(pnv_cpu_state(cpu)->intc);
- xive_tctx_tm_write(XIVE_PRESENTER(xive), tctx, offset, value, size);
- }
- static uint64_t pnv_xive_tm_read(void *opaque, hwaddr offset, unsigned size)
- {
- PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
- PnvXive *xive = pnv_xive_tm_get_xive(cpu);
- XiveTCTX *tctx = XIVE_TCTX(pnv_cpu_state(cpu)->intc);
- return xive_tctx_tm_read(XIVE_PRESENTER(xive), tctx, offset, size);
- }
- const MemoryRegionOps pnv_xive_tm_ops = {
- .read = pnv_xive_tm_read,
- .write = pnv_xive_tm_write,
- .endianness = DEVICE_BIG_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 1,
- .max_access_size = 8,
- },
- };
- /*
- * Interrupt controller XSCOM region.
- */
- static uint64_t pnv_xive_xscom_read(void *opaque, hwaddr addr, unsigned size)
- {
- switch (addr >> 3) {
- case X_VC_EQC_CONFIG:
- /* FIXME (skiboot): This is the only XSCOM load. Bizarre. */
- return VC_EQC_SYNC_MASK;
- default:
- return pnv_xive_ic_reg_read(opaque, addr, size);
- }
- }
- static void pnv_xive_xscom_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
- {
- pnv_xive_ic_reg_write(opaque, addr, val, size);
- }
- static const MemoryRegionOps pnv_xive_xscom_ops = {
- .read = pnv_xive_xscom_read,
- .write = pnv_xive_xscom_write,
- .endianness = DEVICE_BIG_ENDIAN,
- .valid = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 8,
- .max_access_size = 8,
- }
- };
- /*
- * Virtualization Controller MMIO region containing the IPI and END ESB pages
- */
- static uint64_t pnv_xive_vc_read(void *opaque, hwaddr offset,
- unsigned size)
- {
- PnvXive *xive = PNV_XIVE(opaque);
- uint64_t edt_index = offset >> pnv_xive_edt_shift(xive);
- uint64_t edt_type = 0;
- uint64_t edt_offset;
- MemTxResult result;
- AddressSpace *edt_as = NULL;
- uint64_t ret = -1;
- if (edt_index < XIVE_TABLE_EDT_MAX) {
- edt_type = GETFIELD(CQ_TDR_EDT_TYPE, xive->edt[edt_index]);
- }
- switch (edt_type) {
- case CQ_TDR_EDT_IPI:
- edt_as = &xive->ipi_as;
- break;
- case CQ_TDR_EDT_EQ:
- edt_as = &xive->end_as;
- break;
- default:
- xive_error(xive, "VC: invalid EDT type for read @%"HWADDR_PRIx, offset);
- return -1;
- }
- /* Remap the offset for the targeted address space */
- edt_offset = pnv_xive_edt_offset(xive, offset, edt_type);
- ret = address_space_ldq(edt_as, edt_offset, MEMTXATTRS_UNSPECIFIED,
- &result);
- if (result != MEMTX_OK) {
- xive_error(xive, "VC: %s read failed at @0x%"HWADDR_PRIx " -> @0x%"
- HWADDR_PRIx, edt_type == CQ_TDR_EDT_IPI ? "IPI" : "END",
- offset, edt_offset);
- return -1;
- }
- return ret;
- }
- static void pnv_xive_vc_write(void *opaque, hwaddr offset,
- uint64_t val, unsigned size)
- {
- PnvXive *xive = PNV_XIVE(opaque);
- uint64_t edt_index = offset >> pnv_xive_edt_shift(xive);
- uint64_t edt_type = 0;
- uint64_t edt_offset;
- MemTxResult result;
- AddressSpace *edt_as = NULL;
- if (edt_index < XIVE_TABLE_EDT_MAX) {
- edt_type = GETFIELD(CQ_TDR_EDT_TYPE, xive->edt[edt_index]);
- }
- switch (edt_type) {
- case CQ_TDR_EDT_IPI:
- edt_as = &xive->ipi_as;
- break;
- case CQ_TDR_EDT_EQ:
- edt_as = &xive->end_as;
- break;
- default:
- xive_error(xive, "VC: invalid EDT type for write @%"HWADDR_PRIx,
- offset);
- return;
- }
- /* Remap the offset for the targeted address space */
- edt_offset = pnv_xive_edt_offset(xive, offset, edt_type);
- address_space_stq(edt_as, edt_offset, val, MEMTXATTRS_UNSPECIFIED, &result);
- if (result != MEMTX_OK) {
- xive_error(xive, "VC: write failed at @0x%"HWADDR_PRIx, edt_offset);
- }
- }
- static const MemoryRegionOps pnv_xive_vc_ops = {
- .read = pnv_xive_vc_read,
- .write = pnv_xive_vc_write,
- .endianness = DEVICE_BIG_ENDIAN,
- .valid = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
- };
- /*
- * Presenter Controller MMIO region. Points to the NVT sets.
- *
- * HW implements all possible mem ops to the underlying NVT structure
- * but QEMU does not need to be so precise. The model implementation
- * simply returns the RAM address of the NVT structure which is then
- * used by pnv_xive_vst_write/read to perform the RAM operation.
- */
- static uint64_t pnv_xive_pc_read(void *opaque, hwaddr offset, unsigned size)
- {
- PnvXive *xive = PNV_XIVE(opaque);
- uint32_t nvt_idx = offset >> xive->pc_shift;
- uint8_t blk = pnv_xive_block_id(xive); /* TODO: VDT -> block xlate */
- return pnv_xive_vst_addr(xive, VST_TSEL_VPDT, blk, nvt_idx);
- }
- static void pnv_xive_pc_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
- {
- PnvXive *xive = PNV_XIVE(opaque);
- xive_error(xive, "PC: invalid write to VC @%"HWADDR_PRIx, addr);
- }
- static const MemoryRegionOps pnv_xive_pc_ops = {
- .read = pnv_xive_pc_read,
- .write = pnv_xive_pc_write,
- .endianness = DEVICE_BIG_ENDIAN,
- .valid = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
- };
- static void xive_nvt_pic_print_info(XiveNVT *nvt, uint32_t nvt_idx,
- GString *buf)
- {
- uint8_t eq_blk = xive_get_field32(NVT_W1_EQ_BLOCK, nvt->w1);
- uint32_t eq_idx = xive_get_field32(NVT_W1_EQ_INDEX, nvt->w1);
- if (!xive_nvt_is_valid(nvt)) {
- return;
- }
- g_string_append_printf(buf, " %08x end:%02x/%04x IPB:%02x\n",
- nvt_idx, eq_blk, eq_idx,
- xive_get_field32(NVT_W4_IPB, nvt->w4));
- }
- void pnv_xive_pic_print_info(PnvXive *xive, GString *buf)
- {
- XiveRouter *xrtr = XIVE_ROUTER(xive);
- uint8_t blk = pnv_xive_block_id(xive);
- uint8_t chip_id = xive->chip->chip_id;
- uint32_t srcno0 = XIVE_EAS(blk, 0);
- uint32_t nr_ipis = pnv_xive_nr_ipis(xive, blk);
- XiveEAS eas;
- XiveEND end;
- XiveNVT nvt;
- int i;
- uint64_t xive_nvt_per_subpage;
- g_string_append_printf(buf, "XIVE[%x] #%d Source %08x .. %08x\n",
- chip_id, blk, srcno0, srcno0 + nr_ipis - 1);
- xive_source_pic_print_info(&xive->ipi_source, srcno0, buf);
- g_string_append_printf(buf, "XIVE[%x] #%d EAT %08x .. %08x\n",
- chip_id, blk, srcno0, srcno0 + nr_ipis - 1);
- for (i = 0; i < nr_ipis; i++) {
- if (xive_router_get_eas(xrtr, blk, i, &eas)) {
- break;
- }
- if (!xive_eas_is_masked(&eas)) {
- xive_eas_pic_print_info(&eas, i, buf);
- }
- }
- g_string_append_printf(buf, "XIVE[%x] #%d ENDT\n", chip_id, blk);
- i = 0;
- while (!xive_router_get_end(xrtr, blk, i, &end)) {
- xive_end_pic_print_info(&end, i++, buf);
- }
- g_string_append_printf(buf, "XIVE[%x] #%d END Escalation EAT\n",
- chip_id, blk);
- i = 0;
- while (!xive_router_get_end(xrtr, blk, i, &end)) {
- xive_end_eas_pic_print_info(&end, i++, buf);
- }
- g_string_append_printf(buf, "XIVE[%x] #%d NVTT %08x .. %08x\n",
- chip_id, blk, 0, XIVE_NVT_COUNT - 1);
- xive_nvt_per_subpage = pnv_xive_vst_per_subpage(xive, VST_TSEL_VPDT);
- for (i = 0; i < XIVE_NVT_COUNT; i += xive_nvt_per_subpage) {
- while (!xive_router_get_nvt(xrtr, blk, i, &nvt)) {
- xive_nvt_pic_print_info(&nvt, i++, buf);
- }
- }
- }
- static void pnv_xive_reset(void *dev)
- {
- PnvXive *xive = PNV_XIVE(dev);
- XiveSource *xsrc = &xive->ipi_source;
- XiveENDSource *end_xsrc = &xive->end_source;
- /* Default page size (Should be changed at runtime to 64k) */
- xive->ic_shift = xive->vc_shift = xive->pc_shift = 12;
- /* Clear subregions */
- if (memory_region_is_mapped(&xsrc->esb_mmio)) {
- memory_region_del_subregion(&xive->ipi_edt_mmio, &xsrc->esb_mmio);
- }
- if (memory_region_is_mapped(&xive->ipi_edt_mmio)) {
- memory_region_del_subregion(&xive->ipi_mmio, &xive->ipi_edt_mmio);
- }
- if (memory_region_is_mapped(&end_xsrc->esb_mmio)) {
- memory_region_del_subregion(&xive->end_edt_mmio, &end_xsrc->esb_mmio);
- }
- if (memory_region_is_mapped(&xive->end_edt_mmio)) {
- memory_region_del_subregion(&xive->end_mmio, &xive->end_edt_mmio);
- }
- }
- static void pnv_xive_init(Object *obj)
- {
- PnvXive *xive = PNV_XIVE(obj);
- object_initialize_child(obj, "ipi_source", &xive->ipi_source,
- TYPE_XIVE_SOURCE);
- object_initialize_child(obj, "end_source", &xive->end_source,
- TYPE_XIVE_END_SOURCE);
- }
- /*
- * Maximum number of IRQs and ENDs supported by HW
- */
- #define PNV_XIVE_NR_IRQS (PNV9_XIVE_VC_SIZE / (1ull << XIVE_ESB_64K_2PAGE))
- #define PNV_XIVE_NR_ENDS (PNV9_XIVE_VC_SIZE / (1ull << XIVE_ESB_64K_2PAGE))
- static void pnv_xive_realize(DeviceState *dev, Error **errp)
- {
- PnvXive *xive = PNV_XIVE(dev);
- PnvXiveClass *pxc = PNV_XIVE_GET_CLASS(dev);
- XiveSource *xsrc = &xive->ipi_source;
- XiveENDSource *end_xsrc = &xive->end_source;
- Error *local_err = NULL;
- pxc->parent_realize(dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- assert(xive->chip);
- /*
- * The XiveSource and XiveENDSource objects are realized with the
- * maximum allowed HW configuration. The ESB MMIO regions will be
- * resized dynamically when the controller is configured by the FW
- * to limit accesses to resources not provisioned.
- */
- object_property_set_int(OBJECT(xsrc), "nr-irqs", PNV_XIVE_NR_IRQS,
- &error_fatal);
- object_property_set_link(OBJECT(xsrc), "xive", OBJECT(xive), &error_abort);
- if (!qdev_realize(DEVICE(xsrc), NULL, errp)) {
- return;
- }
- object_property_set_int(OBJECT(end_xsrc), "nr-ends", PNV_XIVE_NR_ENDS,
- &error_fatal);
- object_property_set_link(OBJECT(end_xsrc), "xive", OBJECT(xive),
- &error_abort);
- if (!qdev_realize(DEVICE(end_xsrc), NULL, errp)) {
- return;
- }
- /* Default page size. Generally changed at runtime to 64k */
- xive->ic_shift = xive->vc_shift = xive->pc_shift = 12;
- /* XSCOM region, used for initial configuration of the BARs */
- memory_region_init_io(&xive->xscom_regs, OBJECT(dev), &pnv_xive_xscom_ops,
- xive, "xscom-xive", PNV9_XSCOM_XIVE_SIZE << 3);
- /* Interrupt controller MMIO regions */
- memory_region_init(&xive->ic_mmio, OBJECT(dev), "xive-ic",
- PNV9_XIVE_IC_SIZE);
- memory_region_init_io(&xive->ic_reg_mmio, OBJECT(dev), &pnv_xive_ic_reg_ops,
- xive, "xive-ic-reg", 1 << xive->ic_shift);
- memory_region_init_io(&xive->ic_notify_mmio, OBJECT(dev),
- &pnv_xive_ic_notify_ops,
- xive, "xive-ic-notify", 1 << xive->ic_shift);
- xive->ic_notify_mmio.disable_reentrancy_guard = true;
- /* The Pervasive LSI trigger and EOI pages (not modeled) */
- memory_region_init_io(&xive->ic_lsi_mmio, OBJECT(dev), &pnv_xive_ic_lsi_ops,
- xive, "xive-ic-lsi", 2 << xive->ic_shift);
- /* Thread Interrupt Management Area (Indirect) */
- memory_region_init_io(&xive->tm_indirect_mmio, OBJECT(dev),
- &xive_tm_indirect_ops,
- xive, "xive-tima-indirect", PNV9_XIVE_TM_SIZE);
- /*
- * Overall Virtualization Controller MMIO region containing the
- * IPI ESB pages and END ESB pages. The layout is defined by the
- * EDT "Domain table" and the accesses are dispatched using
- * address spaces for each.
- */
- memory_region_init_io(&xive->vc_mmio, OBJECT(xive), &pnv_xive_vc_ops, xive,
- "xive-vc", PNV9_XIVE_VC_SIZE);
- memory_region_init(&xive->ipi_mmio, OBJECT(xive), "xive-vc-ipi",
- PNV9_XIVE_VC_SIZE);
- address_space_init(&xive->ipi_as, &xive->ipi_mmio, "xive-vc-ipi");
- memory_region_init(&xive->end_mmio, OBJECT(xive), "xive-vc-end",
- PNV9_XIVE_VC_SIZE);
- address_space_init(&xive->end_as, &xive->end_mmio, "xive-vc-end");
- /*
- * The MMIO windows exposing the IPI ESBs and the END ESBs in the
- * VC region. Their size is configured by the FW in the EDT table.
- */
- memory_region_init(&xive->ipi_edt_mmio, OBJECT(xive), "xive-vc-ipi-edt", 0);
- memory_region_init(&xive->end_edt_mmio, OBJECT(xive), "xive-vc-end-edt", 0);
- /* Presenter Controller MMIO region (not modeled) */
- memory_region_init_io(&xive->pc_mmio, OBJECT(xive), &pnv_xive_pc_ops, xive,
- "xive-pc", PNV9_XIVE_PC_SIZE);
- xive->pc_mmio.disable_reentrancy_guard = true;
- /* Thread Interrupt Management Area (Direct) */
- memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &pnv_xive_tm_ops,
- xive, "xive-tima", PNV9_XIVE_TM_SIZE);
- qemu_register_reset(pnv_xive_reset, dev);
- }
- static int pnv_xive_dt_xscom(PnvXScomInterface *dev, void *fdt,
- int xscom_offset)
- {
- const char compat[] = "ibm,power9-xive-x";
- char *name;
- int offset;
- uint32_t lpc_pcba = PNV9_XSCOM_XIVE_BASE;
- uint32_t reg[] = {
- cpu_to_be32(lpc_pcba),
- cpu_to_be32(PNV9_XSCOM_XIVE_SIZE)
- };
- name = g_strdup_printf("xive@%x", lpc_pcba);
- offset = fdt_add_subnode(fdt, xscom_offset, name);
- _FDT(offset);
- g_free(name);
- _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
- _FDT((fdt_setprop(fdt, offset, "compatible", compat,
- sizeof(compat))));
- return 0;
- }
- static const Property pnv_xive_properties[] = {
- DEFINE_PROP_UINT64("ic-bar", PnvXive, ic_base, 0),
- DEFINE_PROP_UINT64("vc-bar", PnvXive, vc_base, 0),
- DEFINE_PROP_UINT64("pc-bar", PnvXive, pc_base, 0),
- DEFINE_PROP_UINT64("tm-bar", PnvXive, tm_base, 0),
- /* The PnvChip id identifies the XIVE interrupt controller. */
- DEFINE_PROP_LINK("chip", PnvXive, chip, TYPE_PNV_CHIP, PnvChip *),
- };
- static void pnv_xive_class_init(ObjectClass *klass, void *data)
- {
- DeviceClass *dc = DEVICE_CLASS(klass);
- PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
- XiveRouterClass *xrc = XIVE_ROUTER_CLASS(klass);
- XiveNotifierClass *xnc = XIVE_NOTIFIER_CLASS(klass);
- XivePresenterClass *xpc = XIVE_PRESENTER_CLASS(klass);
- PnvXiveClass *pxc = PNV_XIVE_CLASS(klass);
- xdc->dt_xscom = pnv_xive_dt_xscom;
- dc->desc = "PowerNV XIVE Interrupt Controller";
- device_class_set_parent_realize(dc, pnv_xive_realize, &pxc->parent_realize);
- dc->realize = pnv_xive_realize;
- device_class_set_props(dc, pnv_xive_properties);
- xrc->get_eas = pnv_xive_get_eas;
- xrc->get_pq = pnv_xive_get_pq;
- xrc->set_pq = pnv_xive_set_pq;
- xrc->get_end = pnv_xive_get_end;
- xrc->write_end = pnv_xive_write_end;
- xrc->get_nvt = pnv_xive_get_nvt;
- xrc->write_nvt = pnv_xive_write_nvt;
- xrc->get_block_id = pnv_xive_get_block_id;
- xrc->end_notify = pnv_xive_end_notify;
- xnc->notify = pnv_xive_notify;
- xpc->match_nvt = pnv_xive_match_nvt;
- xpc->get_config = pnv_xive_presenter_get_config;
- };
- static const TypeInfo pnv_xive_info = {
- .name = TYPE_PNV_XIVE,
- .parent = TYPE_XIVE_ROUTER,
- .instance_init = pnv_xive_init,
- .instance_size = sizeof(PnvXive),
- .class_init = pnv_xive_class_init,
- .class_size = sizeof(PnvXiveClass),
- .interfaces = (InterfaceInfo[]) {
- { TYPE_PNV_XSCOM_INTERFACE },
- { }
- }
- };
- static void pnv_xive_register_types(void)
- {
- type_register_static(&pnv_xive_info);
- }
- type_init(pnv_xive_register_types)
|