xref: /openbmc/qemu/hw/intc/xics_pnv.c (revision 99285aae)
1*99285aaeSCédric Le Goater /*
2*99285aaeSCédric Le Goater  * QEMU PowerPC PowerNV Interrupt Control Presenter (ICP) model
3*99285aaeSCédric Le Goater  *
4*99285aaeSCédric Le Goater  * Copyright (c) 2017, IBM Corporation.
5*99285aaeSCédric Le Goater  *
6*99285aaeSCédric Le Goater  * This library is free software; you can redistribute it and/or
7*99285aaeSCédric Le Goater  * modify it under the terms of the GNU Lesser General Public License
8*99285aaeSCédric Le Goater  * as published by the Free Software Foundation; either version 2 of
9*99285aaeSCédric Le Goater  * the License, or (at your option) any later version.
10*99285aaeSCédric Le Goater  *
11*99285aaeSCédric Le Goater  * This library is distributed in the hope that it will be useful, but
12*99285aaeSCédric Le Goater  * WITHOUT ANY WARRANTY; without even the implied warranty of
13*99285aaeSCédric Le Goater  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*99285aaeSCédric Le Goater  * Lesser General Public License for more details.
15*99285aaeSCédric Le Goater  *
16*99285aaeSCédric Le Goater  * You should have received a copy of the GNU Lesser General Public
17*99285aaeSCédric Le Goater  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18*99285aaeSCédric Le Goater  */
19*99285aaeSCédric Le Goater 
20*99285aaeSCédric Le Goater #include "qemu/osdep.h"
21*99285aaeSCédric Le Goater #include "sysemu/sysemu.h"
22*99285aaeSCédric Le Goater #include "qapi/error.h"
23*99285aaeSCédric Le Goater #include "qemu/log.h"
24*99285aaeSCédric Le Goater #include "hw/ppc/xics.h"
25*99285aaeSCédric Le Goater 
26*99285aaeSCédric Le Goater #define ICP_XIRR_POLL    0 /* 1 byte (CPRR) or 4 bytes */
27*99285aaeSCédric Le Goater #define ICP_XIRR         4 /* 1 byte (CPRR) or 4 bytes */
28*99285aaeSCédric Le Goater #define ICP_MFRR        12 /* 1 byte access only */
29*99285aaeSCédric Le Goater 
30*99285aaeSCédric Le Goater #define ICP_LINKA       16 /* unused */
31*99285aaeSCédric Le Goater #define ICP_LINKB       20 /* unused */
32*99285aaeSCédric Le Goater #define ICP_LINKC       24 /* unused */
33*99285aaeSCédric Le Goater 
34*99285aaeSCédric Le Goater static uint64_t pnv_icp_read(void *opaque, hwaddr addr, unsigned width)
35*99285aaeSCédric Le Goater {
36*99285aaeSCédric Le Goater     ICPState *icp = ICP(opaque);
37*99285aaeSCédric Le Goater     PnvICPState *picp = PNV_ICP(opaque);
38*99285aaeSCédric Le Goater     bool byte0 = (width == 1 && (addr & 0x3) == 0);
39*99285aaeSCédric Le Goater     uint64_t val = 0xffffffff;
40*99285aaeSCédric Le Goater 
41*99285aaeSCédric Le Goater     switch (addr & 0xffc) {
42*99285aaeSCédric Le Goater     case ICP_XIRR_POLL:
43*99285aaeSCédric Le Goater         val = icp_ipoll(icp, NULL);
44*99285aaeSCédric Le Goater         if (byte0) {
45*99285aaeSCédric Le Goater             val >>= 24;
46*99285aaeSCédric Le Goater         } else if (width != 4) {
47*99285aaeSCédric Le Goater             goto bad_access;
48*99285aaeSCédric Le Goater         }
49*99285aaeSCédric Le Goater         break;
50*99285aaeSCédric Le Goater     case ICP_XIRR:
51*99285aaeSCédric Le Goater         if (byte0) {
52*99285aaeSCédric Le Goater             val = icp_ipoll(icp, NULL) >> 24;
53*99285aaeSCédric Le Goater         } else if (width == 4) {
54*99285aaeSCédric Le Goater             val = icp_accept(icp);
55*99285aaeSCédric Le Goater         } else {
56*99285aaeSCédric Le Goater             goto bad_access;
57*99285aaeSCédric Le Goater         }
58*99285aaeSCédric Le Goater         break;
59*99285aaeSCédric Le Goater     case ICP_MFRR:
60*99285aaeSCédric Le Goater         if (byte0) {
61*99285aaeSCédric Le Goater             val = icp->mfrr;
62*99285aaeSCédric Le Goater         } else {
63*99285aaeSCédric Le Goater             goto bad_access;
64*99285aaeSCédric Le Goater         }
65*99285aaeSCédric Le Goater         break;
66*99285aaeSCédric Le Goater     case ICP_LINKA:
67*99285aaeSCédric Le Goater         if (width == 4) {
68*99285aaeSCédric Le Goater             val = picp->links[0];
69*99285aaeSCédric Le Goater         } else {
70*99285aaeSCédric Le Goater             goto bad_access;
71*99285aaeSCédric Le Goater         }
72*99285aaeSCédric Le Goater         break;
73*99285aaeSCédric Le Goater     case ICP_LINKB:
74*99285aaeSCédric Le Goater         if (width == 4) {
75*99285aaeSCédric Le Goater             val = picp->links[1];
76*99285aaeSCédric Le Goater         } else {
77*99285aaeSCédric Le Goater             goto bad_access;
78*99285aaeSCédric Le Goater         }
79*99285aaeSCédric Le Goater         break;
80*99285aaeSCédric Le Goater     case ICP_LINKC:
81*99285aaeSCédric Le Goater         if (width == 4) {
82*99285aaeSCédric Le Goater             val = picp->links[2];
83*99285aaeSCédric Le Goater         } else {
84*99285aaeSCédric Le Goater             goto bad_access;
85*99285aaeSCédric Le Goater         }
86*99285aaeSCédric Le Goater         break;
87*99285aaeSCédric Le Goater     default:
88*99285aaeSCédric Le Goater bad_access:
89*99285aaeSCédric Le Goater         qemu_log_mask(LOG_GUEST_ERROR, "XICS: Bad ICP access 0x%"
90*99285aaeSCédric Le Goater                       HWADDR_PRIx"/%d\n", addr, width);
91*99285aaeSCédric Le Goater     }
92*99285aaeSCédric Le Goater 
93*99285aaeSCédric Le Goater     return val;
94*99285aaeSCédric Le Goater }
95*99285aaeSCédric Le Goater 
96*99285aaeSCédric Le Goater static void pnv_icp_write(void *opaque, hwaddr addr, uint64_t val,
97*99285aaeSCédric Le Goater                               unsigned width)
98*99285aaeSCédric Le Goater {
99*99285aaeSCédric Le Goater     ICPState *icp = ICP(opaque);
100*99285aaeSCédric Le Goater     PnvICPState *picp = PNV_ICP(opaque);
101*99285aaeSCédric Le Goater     bool byte0 = (width == 1 && (addr & 0x3) == 0);
102*99285aaeSCédric Le Goater 
103*99285aaeSCédric Le Goater     switch (addr & 0xffc) {
104*99285aaeSCédric Le Goater     case ICP_XIRR:
105*99285aaeSCédric Le Goater         if (byte0) {
106*99285aaeSCédric Le Goater             icp_set_cppr(icp, val);
107*99285aaeSCédric Le Goater         } else if (width == 4) {
108*99285aaeSCédric Le Goater             icp_eoi(icp, val);
109*99285aaeSCédric Le Goater         } else {
110*99285aaeSCédric Le Goater             goto bad_access;
111*99285aaeSCédric Le Goater         }
112*99285aaeSCédric Le Goater         break;
113*99285aaeSCédric Le Goater     case ICP_MFRR:
114*99285aaeSCédric Le Goater         if (byte0) {
115*99285aaeSCédric Le Goater             icp_set_mfrr(icp, val);
116*99285aaeSCédric Le Goater         } else {
117*99285aaeSCédric Le Goater             goto bad_access;
118*99285aaeSCédric Le Goater         }
119*99285aaeSCédric Le Goater         break;
120*99285aaeSCédric Le Goater     case ICP_LINKA:
121*99285aaeSCédric Le Goater         if (width == 4) {
122*99285aaeSCédric Le Goater             picp->links[0] = val;
123*99285aaeSCédric Le Goater         } else {
124*99285aaeSCédric Le Goater             goto bad_access;
125*99285aaeSCédric Le Goater         }
126*99285aaeSCédric Le Goater         break;
127*99285aaeSCédric Le Goater     case ICP_LINKB:
128*99285aaeSCédric Le Goater         if (width == 4) {
129*99285aaeSCédric Le Goater             picp->links[1] = val;
130*99285aaeSCédric Le Goater         } else {
131*99285aaeSCédric Le Goater             goto bad_access;
132*99285aaeSCédric Le Goater         }
133*99285aaeSCédric Le Goater         break;
134*99285aaeSCédric Le Goater     case ICP_LINKC:
135*99285aaeSCédric Le Goater         if (width == 4) {
136*99285aaeSCédric Le Goater             picp->links[2] = val;
137*99285aaeSCédric Le Goater         } else {
138*99285aaeSCédric Le Goater             goto bad_access;
139*99285aaeSCédric Le Goater         }
140*99285aaeSCédric Le Goater         break;
141*99285aaeSCédric Le Goater     default:
142*99285aaeSCédric Le Goater bad_access:
143*99285aaeSCédric Le Goater         qemu_log_mask(LOG_GUEST_ERROR, "XICS: Bad ICP access 0x%"
144*99285aaeSCédric Le Goater                       HWADDR_PRIx"/%d\n", addr, width);
145*99285aaeSCédric Le Goater     }
146*99285aaeSCédric Le Goater }
147*99285aaeSCédric Le Goater 
148*99285aaeSCédric Le Goater static const MemoryRegionOps pnv_icp_ops = {
149*99285aaeSCédric Le Goater     .read = pnv_icp_read,
150*99285aaeSCédric Le Goater     .write = pnv_icp_write,
151*99285aaeSCédric Le Goater     .endianness = DEVICE_BIG_ENDIAN,
152*99285aaeSCédric Le Goater     .valid = {
153*99285aaeSCédric Le Goater         .min_access_size = 1,
154*99285aaeSCédric Le Goater         .max_access_size = 4,
155*99285aaeSCédric Le Goater     },
156*99285aaeSCédric Le Goater     .impl = {
157*99285aaeSCédric Le Goater         .min_access_size = 1,
158*99285aaeSCédric Le Goater         .max_access_size = 4,
159*99285aaeSCédric Le Goater     },
160*99285aaeSCédric Le Goater };
161*99285aaeSCédric Le Goater 
162*99285aaeSCédric Le Goater static void pnv_icp_realize(DeviceState *dev, Error **errp)
163*99285aaeSCédric Le Goater {
164*99285aaeSCédric Le Goater     PnvICPState *icp = PNV_ICP(dev);
165*99285aaeSCédric Le Goater 
166*99285aaeSCédric Le Goater     memory_region_init_io(&icp->mmio, OBJECT(dev), &pnv_icp_ops,
167*99285aaeSCédric Le Goater                           icp, "icp-thread", 0x1000);
168*99285aaeSCédric Le Goater }
169*99285aaeSCédric Le Goater 
170*99285aaeSCédric Le Goater static void pnv_icp_class_init(ObjectClass *klass, void *data)
171*99285aaeSCédric Le Goater {
172*99285aaeSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
173*99285aaeSCédric Le Goater     ICPStateClass *icpc = ICP_CLASS(klass);
174*99285aaeSCédric Le Goater 
175*99285aaeSCédric Le Goater     icpc->realize = pnv_icp_realize;
176*99285aaeSCédric Le Goater     dc->desc = "PowerNV ICP";
177*99285aaeSCédric Le Goater }
178*99285aaeSCédric Le Goater 
179*99285aaeSCédric Le Goater static const TypeInfo pnv_icp_info = {
180*99285aaeSCédric Le Goater     .name          = TYPE_PNV_ICP,
181*99285aaeSCédric Le Goater     .parent        = TYPE_ICP,
182*99285aaeSCédric Le Goater     .instance_size = sizeof(PnvICPState),
183*99285aaeSCédric Le Goater     .class_init    = pnv_icp_class_init,
184*99285aaeSCédric Le Goater     .class_size    = sizeof(ICPStateClass),
185*99285aaeSCédric Le Goater };
186*99285aaeSCédric Le Goater 
187*99285aaeSCédric Le Goater static void pnv_icp_register_types(void)
188*99285aaeSCédric Le Goater {
189*99285aaeSCédric Le Goater     type_register_static(&pnv_icp_info);
190*99285aaeSCédric Le Goater }
191*99285aaeSCédric Le Goater 
192*99285aaeSCédric Le Goater type_init(pnv_icp_register_types)
193