From a28d8391e323ef586c44e9313826097f884eebc6 Mon Sep 17 00:00:00 2001 From: Yi Min Zhao Date: Wed, 27 Jan 2016 16:05:26 +0800 Subject: 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 Reviewed-by: Cornelia Huck Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'hw/s390x/css.c') 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); -- cgit 1.4.1