util/hbitmap: update orig_size on truncate
[qemu/ar7.git] / hw / intc / xics_pnv.c
blob67f2702e521c842fc97ca4f95aba3488939d551b
1 /*
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"
23 #include "qemu/log.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) {
43 case ICP_XIRR_POLL:
44 val = icp_ipoll(icp, NULL);
45 if (byte0) {
46 val >>= 24;
47 } else if (width != 4) {
48 goto bad_access;
50 break;
51 case ICP_XIRR:
52 if (byte0) {
53 val = icp_ipoll(icp, NULL) >> 24;
54 } else if (width == 4) {
55 val = icp_accept(icp);
56 } else {
57 goto bad_access;
59 break;
60 case ICP_MFRR:
61 if (byte0) {
62 val = icp->mfrr;
63 } else {
64 goto bad_access;
66 break;
67 case ICP_LINKA:
68 if (width == 4) {
69 val = picp->links[0];
70 } else {
71 goto bad_access;
73 break;
74 case ICP_LINKB:
75 if (width == 4) {
76 val = picp->links[1];
77 } else {
78 goto bad_access;
80 break;
81 case ICP_LINKC:
82 if (width == 4) {
83 val = picp->links[2];
84 } else {
85 goto bad_access;
87 break;
88 default:
89 bad_access:
90 qemu_log_mask(LOG_GUEST_ERROR, "XICS: Bad ICP access 0x%"
91 HWADDR_PRIx"/%d\n", addr, width);
94 return val;
97 static void pnv_icp_write(void *opaque, hwaddr addr, uint64_t val,
98 unsigned width)
100 ICPState *icp = ICP(opaque);
101 PnvICPState *picp = PNV_ICP(opaque);
102 bool byte0 = (width == 1 && (addr & 0x3) == 0);
104 switch (addr & 0xffc) {
105 case ICP_XIRR:
106 if (byte0) {
107 icp_set_cppr(icp, val);
108 } else if (width == 4) {
109 icp_eoi(icp, val);
110 } else {
111 goto bad_access;
113 break;
114 case ICP_MFRR:
115 if (byte0) {
116 icp_set_mfrr(icp, val);
117 } else {
118 goto bad_access;
120 break;
121 case ICP_LINKA:
122 if (width == 4) {
123 picp->links[0] = val;
124 } else {
125 goto bad_access;
127 break;
128 case ICP_LINKB:
129 if (width == 4) {
130 picp->links[1] = val;
131 } else {
132 goto bad_access;
134 break;
135 case ICP_LINKC:
136 if (width == 4) {
137 picp->links[2] = val;
138 } else {
139 goto bad_access;
141 break;
142 default:
143 bad_access:
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,
153 .valid = {
154 .min_access_size = 1,
155 .max_access_size = 4,
157 .impl = {
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);
171 if (local_err) {
172 error_propagate(errp, local_err);
173 return;
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,
192 .parent = TYPE_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)