]> git.proxmox.com Git - qemu.git/blame - hw/syborg_interrupt.c
savevm: Add DeviceState param
[qemu.git] / hw / syborg_interrupt.c
CommitLineData
4af39611
PB
1/*
2 * Syborg interrupt controller.
3 *
4 * Copyright (c) 2008 CodeSourcery
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25#include "sysbus.h"
26#include "syborg.h"
27
28//#define DEBUG_SYBORG_INT
29
30#ifdef DEBUG_SYBORG_INT
31#define DPRINTF(fmt, ...) \
32do { printf("syborg_int: " fmt , ## __VA_ARGS__); } while (0)
33#define BADF(fmt, ...) \
34do { fprintf(stderr, "syborg_int: error: " fmt , ## __VA_ARGS__); \
35 exit(1);} while (0)
36#else
37#define DPRINTF(fmt, ...) do {} while(0)
38#define BADF(fmt, ...) \
39do { fprintf(stderr, "syborg_int: error: " fmt , ## __VA_ARGS__);} while (0)
40#endif
41enum {
42 INT_ID = 0,
43 INT_STATUS = 1, /* number of pending interrupts */
44 INT_CURRENT = 2, /* next interrupt to be serviced */
45 INT_DISABLE_ALL = 3,
46 INT_DISABLE = 4,
47 INT_ENABLE = 5,
48 INT_TOTAL = 6
49};
50
51typedef struct {
52 unsigned level:1;
53 unsigned enabled:1;
54} syborg_int_flags;
55
56typedef struct {
57 SysBusDevice busdev;
58 int pending_count;
ee6847d1 59 uint32_t num_irqs;
4af39611
PB
60 syborg_int_flags *flags;
61 qemu_irq parent_irq;
62} SyborgIntState;
63
64static void syborg_int_update(SyborgIntState *s)
65{
66 DPRINTF("pending %d\n", s->pending_count);
67 qemu_set_irq(s->parent_irq, s->pending_count > 0);
68}
69
70static void syborg_int_set_irq(void *opaque, int irq, int level)
71{
72 SyborgIntState *s = (SyborgIntState *)opaque;
73
74 if (s->flags[irq].level == level)
75 return;
76
77 s->flags[irq].level = level;
78 if (s->flags[irq].enabled) {
79 if (level)
80 s->pending_count++;
81 else
82 s->pending_count--;
83 syborg_int_update(s);
84 }
85}
86
c227f099 87static uint32_t syborg_int_read(void *opaque, target_phys_addr_t offset)
4af39611
PB
88{
89 SyborgIntState *s = (SyborgIntState *)opaque;
90 int i;
91
92 offset &= 0xfff;
93 switch (offset >> 2) {
94 case INT_ID:
95 return SYBORG_ID_INT;
96 case INT_STATUS:
97 DPRINTF("read status=%d\n", s->pending_count);
98 return s->pending_count;
99
100 case INT_CURRENT:
101 for (i = 0; i < s->num_irqs; i++) {
102 if (s->flags[i].level & s->flags[i].enabled) {
103 DPRINTF("read current=%d\n", i);
104 return i;
105 }
106 }
107 DPRINTF("read current=none\n");
108 return 0xffffffffu;
109
110 default:
111 cpu_abort(cpu_single_env, "syborg_int_read: Bad offset %x\n",
112 (int)offset);
113 return 0;
114 }
115}
116
c227f099 117static void syborg_int_write(void *opaque, target_phys_addr_t offset, uint32_t value)
4af39611
PB
118{
119 SyborgIntState *s = (SyborgIntState *)opaque;
120 int i;
121 offset &= 0xfff;
122
123 DPRINTF("syborg_int_write offset=%d val=%d\n", (int)offset, (int)value);
124 switch (offset >> 2) {
125 case INT_DISABLE_ALL:
126 s->pending_count = 0;
127 for (i = 0; i < s->num_irqs; i++)
128 s->flags[i].enabled = 0;
129 break;
130
131 case INT_DISABLE:
132 if (value >= s->num_irqs)
133 break;
134 if (s->flags[value].enabled) {
135 if (s->flags[value].enabled)
136 s->pending_count--;
137 s->flags[value].enabled = 0;
138 }
139 break;
140
141 case INT_ENABLE:
142 if (value >= s->num_irqs)
143 break;
144 if (!(s->flags[value].enabled)) {
145 if(s->flags[value].level)
146 s->pending_count++;
147 s->flags[value].enabled = 1;
148 }
149 break;
150
151 default:
152 cpu_abort(cpu_single_env, "syborg_int_write: Bad offset %x\n",
153 (int)offset);
154 return;
155 }
156 syborg_int_update(s);
157}
158
d60efc6b 159static CPUReadMemoryFunc * const syborg_int_readfn[] = {
4af39611
PB
160 syborg_int_read,
161 syborg_int_read,
162 syborg_int_read
163};
164
d60efc6b 165static CPUWriteMemoryFunc * const syborg_int_writefn[] = {
4af39611
PB
166 syborg_int_write,
167 syborg_int_write,
168 syborg_int_write
169};
170
171static void syborg_int_save(QEMUFile *f, void *opaque)
172{
173 SyborgIntState *s = (SyborgIntState *)opaque;
174 int i;
175
176 qemu_put_be32(f, s->num_irqs);
177 qemu_put_be32(f, s->pending_count);
178 for (i = 0; i < s->num_irqs; i++) {
179 qemu_put_be32(f, s->flags[i].enabled
180 | ((unsigned)s->flags[i].level << 1));
181 }
182}
183
184static int syborg_int_load(QEMUFile *f, void *opaque, int version_id)
185{
186 SyborgIntState *s = (SyborgIntState *)opaque;
187 uint32_t val;
188 int i;
189
190 if (version_id != 1)
191 return -EINVAL;
192
193 val = qemu_get_be32(f);
194 if (val != s->num_irqs)
195 return -EINVAL;
196 s->pending_count = qemu_get_be32(f);
197 for (i = 0; i < s->num_irqs; i++) {
198 val = qemu_get_be32(f);
199 s->flags[i].enabled = val & 1;
200 s->flags[i].level = (val >> 1) & 1;
201 }
202 return 0;
203}
204
81a322d4 205static int syborg_int_init(SysBusDevice *dev)
4af39611
PB
206{
207 SyborgIntState *s = FROM_SYSBUS(SyborgIntState, dev);
208 int iomemtype;
209
210 sysbus_init_irq(dev, &s->parent_irq);
067a3ddc 211 qdev_init_gpio_in(&dev->qdev, syborg_int_set_irq, s->num_irqs);
1eed09cb 212 iomemtype = cpu_register_io_memory(syborg_int_readfn,
4af39611
PB
213 syborg_int_writefn, s);
214 sysbus_init_mmio(dev, 0x1000, iomemtype);
215 s->flags = qemu_mallocz(s->num_irqs * sizeof(syborg_int_flags));
216
0be71e32
AW
217 register_savevm(&dev->qdev, "syborg_int", -1, 1, syborg_int_save,
218 syborg_int_load, s);
81a322d4 219 return 0;
4af39611
PB
220}
221
ee6847d1
GH
222static SysBusDeviceInfo syborg_int_info = {
223 .init = syborg_int_init,
224 .qdev.name = "syborg,interrupt",
225 .qdev.size = sizeof(SyborgIntState),
226 .qdev.props = (Property[]) {
3c2aed8b
GH
227 DEFINE_PROP_UINT32("num-interrupts", SyborgIntState, num_irqs, 64),
228 DEFINE_PROP_END_OF_LIST(),
ee6847d1
GH
229 }
230};
231
4af39611
PB
232static void syborg_interrupt_register_devices(void)
233{
ee6847d1 234 sysbus_register_withprop(&syborg_int_info);
4af39611
PB
235}
236
237device_init(syborg_interrupt_register_devices)