xref: /openbmc/qemu/hw/nubus/nubus-bus.c (revision 1d3d62dff8f069c379123690a30817d7aa575cae)
1 /*
2  * QEMU Macintosh Nubus
3  *
4  * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu>
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7  * See the COPYING file in the top-level directory.
8  *
9  */
10 
11 /*
12  * References:
13  *   Nubus Specification (TI)
14  *     http://www.bitsavers.org/pdf/ti/nubus/2242825-0001_NuBus_Spec1983.pdf
15  *
16  *   Designing Cards and Drivers for the Macintosh Family (Apple)
17  */
18 
19 #include "qemu/osdep.h"
20 #include "hw/nubus/nubus.h"
21 #include "qapi/error.h"
22 #include "trace.h"
23 
24 
25 static NubusBus *nubus_find(void)
26 {
27     /* Returns NULL unless there is exactly one nubus device */
28     return NUBUS_BUS(object_resolve_path_type("", TYPE_NUBUS_BUS, NULL));
29 }
30 
31 static MemTxResult nubus_slot_write(void *opaque, hwaddr addr, uint64_t val,
32                                     unsigned size, MemTxAttrs attrs)
33 {
34     trace_nubus_slot_write(addr, val, size);
35     return MEMTX_DECODE_ERROR;
36 }
37 
38 static MemTxResult nubus_slot_read(void *opaque, hwaddr addr, uint64_t *data,
39                                    unsigned size, MemTxAttrs attrs)
40 {
41     trace_nubus_slot_read(addr, size);
42     return MEMTX_DECODE_ERROR;
43 }
44 
45 static const MemoryRegionOps nubus_slot_ops = {
46     .read_with_attrs  = nubus_slot_read,
47     .write_with_attrs = nubus_slot_write,
48     .endianness = DEVICE_BIG_ENDIAN,
49     .valid = {
50         .min_access_size = 1,
51         .max_access_size = 4,
52     },
53 };
54 
55 static MemTxResult nubus_super_slot_write(void *opaque, hwaddr addr,
56                                           uint64_t val, unsigned size,
57                                           MemTxAttrs attrs)
58 {
59     trace_nubus_super_slot_write(addr, val, size);
60     return MEMTX_DECODE_ERROR;
61 }
62 
63 static MemTxResult nubus_super_slot_read(void *opaque, hwaddr addr,
64                                          uint64_t *data, unsigned size,
65                                          MemTxAttrs attrs)
66 {
67     trace_nubus_super_slot_read(addr, size);
68     return MEMTX_DECODE_ERROR;
69 }
70 
71 static const MemoryRegionOps nubus_super_slot_ops = {
72     .read_with_attrs = nubus_super_slot_read,
73     .write_with_attrs = nubus_super_slot_write,
74     .endianness = DEVICE_BIG_ENDIAN,
75     .valid = {
76         .min_access_size = 1,
77         .max_access_size = 4,
78     },
79 };
80 
81 static void nubus_realize(BusState *bus, Error **errp)
82 {
83     if (!nubus_find()) {
84         error_setg(errp, "at most one %s device is permitted", TYPE_NUBUS_BUS);
85         return;
86     }
87 }
88 
89 static void nubus_init(Object *obj)
90 {
91     NubusBus *nubus = NUBUS_BUS(obj);
92 
93     memory_region_init_io(&nubus->super_slot_io, obj, &nubus_super_slot_ops,
94                           nubus, "nubus-super-slots",
95                           (NUBUS_SUPER_SLOT_NB + 1) * NUBUS_SUPER_SLOT_SIZE);
96 
97     memory_region_init_io(&nubus->slot_io, obj, &nubus_slot_ops,
98                           nubus, "nubus-slots",
99                           NUBUS_SLOT_NB * NUBUS_SLOT_SIZE);
100 
101     nubus->slot_available_mask = MAKE_64BIT_MASK(NUBUS_FIRST_SLOT,
102                                                  NUBUS_SLOT_NB);
103 }
104 
105 static char *nubus_get_dev_path(DeviceState *dev)
106 {
107     NubusDevice *nd = NUBUS_DEVICE(dev);
108     BusState *bus = qdev_get_parent_bus(dev);
109     char *p = qdev_get_dev_path(bus->parent);
110 
111     if (p) {
112         char *ret = g_strdup_printf("%s/%s/%02x", p, bus->name, nd->slot);
113         g_free(p);
114         return ret;
115     } else {
116         return g_strdup_printf("%s/%02x", bus->name, nd->slot);
117     }
118 }
119 
120 static bool nubus_check_address(BusState *bus, DeviceState *dev, Error **errp)
121 {
122     NubusDevice *nd = NUBUS_DEVICE(dev);
123     NubusBus *nubus = NUBUS_BUS(bus);
124 
125     if (nd->slot == -1) {
126         /* No slot specified, find first available free slot */
127         int s = ctz32(nubus->slot_available_mask);
128         if (s != 32) {
129             nd->slot = s;
130         } else {
131             error_setg(errp, "Cannot register nubus card, no free slot "
132                              "available");
133             return false;
134         }
135     } else {
136         /* Slot specified, make sure the slot is available */
137         if (!(nubus->slot_available_mask & BIT(nd->slot))) {
138             error_setg(errp, "Cannot register nubus card, slot %d is "
139                              "unavailable or already occupied", nd->slot);
140             return false;
141         }
142     }
143 
144     nubus->slot_available_mask &= ~BIT(nd->slot);
145     return true;
146 }
147 
148 static void nubus_class_init(ObjectClass *oc, void *data)
149 {
150     BusClass *bc = BUS_CLASS(oc);
151 
152     bc->realize = nubus_realize;
153     bc->check_address = nubus_check_address;
154     bc->get_dev_path = nubus_get_dev_path;
155 }
156 
157 static const TypeInfo nubus_bus_info = {
158     .name = TYPE_NUBUS_BUS,
159     .parent = TYPE_BUS,
160     .instance_size = sizeof(NubusBus),
161     .instance_init = nubus_init,
162     .class_init = nubus_class_init,
163 };
164 
165 static void nubus_register_types(void)
166 {
167     type_register_static(&nubus_bus_info);
168 }
169 
170 type_init(nubus_register_types)
171