2 * QEMU PowerPC PowerNV Interrupt Control Presenter (ICP) model
4 * Copyright (c) 2017, IBM Corporation.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
21 #include "qapi/error.h"
23 #include "qemu/module.h"
24 #include "hw/ppc/xics.h"
26 #define ICP_XIRR_POLL 0 /* 1 byte (CPRR) or 4 bytes */
27 #define ICP_XIRR 4 /* 1 byte (CPRR) or 4 bytes */
28 #define ICP_MFRR 12 /* 1 byte access only */
30 #define ICP_LINKA 16 /* unused */
31 #define ICP_LINKB 20 /* unused */
32 #define ICP_LINKC 24 /* unused */
34 static uint64_t pnv_icp_read(void *opaque
, hwaddr addr
, unsigned width
)
36 ICPState
*icp
= ICP(opaque
);
37 PnvICPState
*picp
= PNV_ICP(opaque
);
38 bool byte0
= (width
== 1 && (addr
& 0x3) == 0);
39 uint64_t val
= 0xffffffff;
41 switch (addr
& 0xffc) {
43 val
= icp_ipoll(icp
, NULL
);
46 } else if (width
!= 4) {
52 val
= icp_ipoll(icp
, NULL
) >> 24;
53 } else if (width
== 4) {
54 val
= icp_accept(icp
);
89 qemu_log_mask(LOG_GUEST_ERROR
, "XICS: Bad ICP access 0x%"
90 HWADDR_PRIx
"/%d\n", addr
, width
);
96 static void pnv_icp_write(void *opaque
, hwaddr addr
, uint64_t val
,
99 ICPState
*icp
= ICP(opaque
);
100 PnvICPState
*picp
= PNV_ICP(opaque
);
101 bool byte0
= (width
== 1 && (addr
& 0x3) == 0);
103 switch (addr
& 0xffc) {
106 icp_set_cppr(icp
, val
);
107 } else if (width
== 4) {
115 icp_set_mfrr(icp
, val
);
122 picp
->links
[0] = val
;
129 picp
->links
[1] = val
;
136 picp
->links
[2] = val
;
143 qemu_log_mask(LOG_GUEST_ERROR
, "XICS: Bad ICP access 0x%"
144 HWADDR_PRIx
"/%d\n", addr
, width
);
148 static const MemoryRegionOps pnv_icp_ops
= {
149 .read
= pnv_icp_read
,
150 .write
= pnv_icp_write
,
151 .endianness
= DEVICE_BIG_ENDIAN
,
153 .min_access_size
= 1,
154 .max_access_size
= 4,
157 .min_access_size
= 1,
158 .max_access_size
= 4,
162 static void pnv_icp_realize(DeviceState
*dev
, Error
**errp
)
164 ICPState
*icp
= ICP(dev
);
165 PnvICPState
*pnv_icp
= PNV_ICP(icp
);
166 ICPStateClass
*icpc
= ICP_GET_CLASS(icp
);
167 Error
*local_err
= NULL
;
169 icpc
->parent_realize(dev
, &local_err
);
171 error_propagate(errp
, local_err
);
175 memory_region_init_io(&pnv_icp
->mmio
, OBJECT(icp
), &pnv_icp_ops
,
176 icp
, "icp-thread", 0x1000);
179 static void pnv_icp_class_init(ObjectClass
*klass
, void *data
)
181 DeviceClass
*dc
= DEVICE_CLASS(klass
);
182 ICPStateClass
*icpc
= ICP_CLASS(klass
);
184 device_class_set_parent_realize(dc
, pnv_icp_realize
,
185 &icpc
->parent_realize
);
186 dc
->desc
= "PowerNV ICP";
189 static const TypeInfo pnv_icp_info
= {
190 .name
= TYPE_PNV_ICP
,
192 .instance_size
= sizeof(PnvICPState
),
193 .class_init
= pnv_icp_class_init
,
194 .class_size
= sizeof(ICPStateClass
),
197 static void pnv_icp_register_types(void)
199 type_register_static(&pnv_icp_info
);
202 type_init(pnv_icp_register_types
)