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 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"
22 #include "sysemu/sysemu.h"
24 #include "qemu/module.h"
25 #include "hw/ppc/xics.h"
27 #define ICP_XIRR_POLL 0 /* 1 byte (CPRR) or 4 bytes */
28 #define ICP_XIRR 4 /* 1 byte (CPRR) or 4 bytes */
29 #define ICP_MFRR 12 /* 1 byte access only */
31 #define ICP_LINKA 16 /* unused */
32 #define ICP_LINKB 20 /* unused */
33 #define ICP_LINKC 24 /* unused */
35 static uint64_t pnv_icp_read(void *opaque
, hwaddr addr
, unsigned width
)
37 ICPState
*icp
= ICP(opaque
);
38 PnvICPState
*picp
= PNV_ICP(opaque
);
39 bool byte0
= (width
== 1 && (addr
& 0x3) == 0);
40 uint64_t val
= 0xffffffff;
42 switch (addr
& 0xffc) {
44 val
= icp_ipoll(icp
, NULL
);
47 } else if (width
!= 4) {
53 val
= icp_ipoll(icp
, NULL
) >> 24;
54 } else if (width
== 4) {
55 val
= icp_accept(icp
);
90 qemu_log_mask(LOG_GUEST_ERROR
, "XICS: Bad ICP access 0x%"
91 HWADDR_PRIx
"/%d\n", addr
, width
);
97 static void pnv_icp_write(void *opaque
, hwaddr addr
, uint64_t val
,
100 ICPState
*icp
= ICP(opaque
);
101 PnvICPState
*picp
= PNV_ICP(opaque
);
102 bool byte0
= (width
== 1 && (addr
& 0x3) == 0);
104 switch (addr
& 0xffc) {
107 icp_set_cppr(icp
, val
);
108 } else if (width
== 4) {
116 icp_set_mfrr(icp
, val
);
123 picp
->links
[0] = val
;
130 picp
->links
[1] = val
;
137 picp
->links
[2] = val
;
144 qemu_log_mask(LOG_GUEST_ERROR
, "XICS: Bad ICP access 0x%"
145 HWADDR_PRIx
"/%d\n", addr
, width
);
149 static const MemoryRegionOps pnv_icp_ops
= {
150 .read
= pnv_icp_read
,
151 .write
= pnv_icp_write
,
152 .endianness
= DEVICE_BIG_ENDIAN
,
154 .min_access_size
= 1,
155 .max_access_size
= 4,
158 .min_access_size
= 1,
159 .max_access_size
= 4,
163 static void pnv_icp_realize(DeviceState
*dev
, Error
**errp
)
165 ICPState
*icp
= ICP(dev
);
166 PnvICPState
*pnv_icp
= PNV_ICP(icp
);
167 ICPStateClass
*icpc
= ICP_GET_CLASS(icp
);
168 Error
*local_err
= NULL
;
170 icpc
->parent_realize(dev
, &local_err
);
172 error_propagate(errp
, local_err
);
176 memory_region_init_io(&pnv_icp
->mmio
, OBJECT(icp
), &pnv_icp_ops
,
177 icp
, "icp-thread", 0x1000);
180 static void pnv_icp_class_init(ObjectClass
*klass
, void *data
)
182 DeviceClass
*dc
= DEVICE_CLASS(klass
);
183 ICPStateClass
*icpc
= ICP_CLASS(klass
);
185 device_class_set_parent_realize(dc
, pnv_icp_realize
,
186 &icpc
->parent_realize
);
187 dc
->desc
= "PowerNV ICP";
190 static const TypeInfo pnv_icp_info
= {
191 .name
= TYPE_PNV_ICP
,
193 .instance_size
= sizeof(PnvICPState
),
194 .class_init
= pnv_icp_class_init
,
195 .class_size
= sizeof(ICPStateClass
),
198 static void pnv_icp_register_types(void)
200 type_register_static(&pnv_icp_info
);
203 type_init(pnv_icp_register_types
)