aboutsummaryrefslogtreecommitdiff
path: root/hw/s390x/css.c
diff options
context:
space:
mode:
authorYi Min Zhao <zyimin@linux.vnet.ibm.com>2016-01-27 16:05:26 +0800
committerCornelia Huck <cornelia.huck@de.ibm.com>2016-03-01 12:15:28 +0100
commita28d8391e323ef586c44e9313826097f884eebc6 (patch)
tree16f83d31f7a36d0cc7ed380d03781d786bad04c9 /hw/s390x/css.c
parent99abd0d6f75109b58dbd662134d8d013999e1e8f (diff)
s390x/css: introduce indicator refcounting interfaces
Currently, virtio-ccw uses its own interfaces to keep indicators mapped just once even if the same address has been registered multiple times. These interfaces fit the PCI use case as well. Therefore, move them to css and make them generic interfaces. Signed-off-by: Yi Min Zhao <zyimin@linux.vnet.ibm.com> Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Diffstat (limited to 'hw/s390x/css.c')
-rw-r--r--hw/s390x/css.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index c29068b30d..c02f5bca8d 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -60,10 +60,72 @@ typedef struct ChannelSubSys {
CssImage *css[MAX_CSSID + 1];
uint8_t default_cssid;
QTAILQ_HEAD(, IoAdapter) io_adapters;
+ QTAILQ_HEAD(, IndAddr) indicator_addresses;
} ChannelSubSys;
static ChannelSubSys *channel_subsys;
+IndAddr *get_indicator(hwaddr ind_addr, int len)
+{
+ IndAddr *indicator;
+
+ QTAILQ_FOREACH(indicator, &channel_subsys->indicator_addresses, sibling) {
+ if (indicator->addr == ind_addr) {
+ indicator->refcnt++;
+ return indicator;
+ }
+ }
+ indicator = g_new0(IndAddr, 1);
+ indicator->addr = ind_addr;
+ indicator->len = len;
+ indicator->refcnt = 1;
+ QTAILQ_INSERT_TAIL(&channel_subsys->indicator_addresses,
+ indicator, sibling);
+ return indicator;
+}
+
+static int s390_io_adapter_map(AdapterInfo *adapter, uint64_t map_addr,
+ bool do_map)
+{
+ S390FLICState *fs = s390_get_flic();
+ S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
+
+ return fsc->io_adapter_map(fs, adapter->adapter_id, map_addr, do_map);
+}
+
+void release_indicator(AdapterInfo *adapter, IndAddr *indicator)
+{
+ assert(indicator->refcnt > 0);
+ indicator->refcnt--;
+ if (indicator->refcnt > 0) {
+ return;
+ }
+ QTAILQ_REMOVE(&channel_subsys->indicator_addresses, indicator, sibling);
+ if (indicator->map) {
+ s390_io_adapter_map(adapter, indicator->map, false);
+ }
+ g_free(indicator);
+}
+
+int map_indicator(AdapterInfo *adapter, IndAddr *indicator)
+{
+ int ret;
+
+ if (indicator->map) {
+ return 0; /* already mapped is not an error */
+ }
+ indicator->map = indicator->addr;
+ ret = s390_io_adapter_map(adapter, indicator->map, true);
+ if ((ret != 0) && (ret != -ENOSYS)) {
+ goto out_err;
+ }
+ return 0;
+
+out_err:
+ indicator->map = 0;
+ return ret;
+}
+
int css_create_css_image(uint8_t cssid, bool default_image)
{
trace_css_new_image(cssid, default_image ? "(default)" : "");
@@ -1524,6 +1586,7 @@ static void css_init(void)
channel_subsys->crws_lost = false;
channel_subsys->chnmon_active = false;
QTAILQ_INIT(&channel_subsys->io_adapters);
+ QTAILQ_INIT(&channel_subsys->indicator_addresses);
}
machine_init(css_init);