diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2016-07-11 18:46:38 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2016-07-11 18:46:38 +0100 |
commit | f1ef55786691a1bf79db0b74ba1e5347a0d38c1b (patch) | |
tree | e42476d052ce6815b18f2a2460c30d64a99585d6 /hw/s390x/css.c | |
parent | 7de2cc8f787a9cf8edff616c75ea9e73a86db9ca (diff) | |
parent | 93d16d81c8af0fe93a04bee8a4cb3259f480cab6 (diff) |
Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20160711' into staging
Last round of s390x patches for 2.7:
- A large update of the s390x PCI code, bringing it in line with
the architecture
- Fixes and improvements in the ipl (boot) code
- Refactoring in the css code
# gpg: Signature made Mon 11 Jul 2016 09:04:51 BST
# gpg: using RSA key 0xDECF6B93C6F02FAF
# gpg: Good signature from "Cornelia Huck <huckc@linux.vnet.ibm.com>"
# gpg: aka "Cornelia Huck <cornelia.huck@de.ibm.com>"
# Primary key fingerprint: C3D0 D66D C362 4FF6 A8C0 18CE DECF 6B93 C6F0 2FAF
* remotes/cohuck/tags/s390x-20160711: (25 commits)
s390x/pci: make hot-unplug handler smoother
s390x/pci: replace fid with idx in msg data of msix
s390x/pci: fix stpcifc_service_call
s390x/pci: refactor list_pci
s390x/pci: refactor s390_pci_find_dev_by_idx
s390x/pci: add checkings in CLP_SET_PCI_FN
s390x/pci: enable zpci hot-plug/hot-unplug
s390x/pci: enable uid-checking
s390x/pci: introduce S390PCIBusDevice qdev
s390x/pci: introduce S390PCIIOMMU
s390x/pci: introduce S390PCIBus
s390x/pci: enforce zPCI state checking
s390x/pci: refactor s390_pci_find_dev_by_fh
s390x/pci: unify FH_ macros
s390x/pci: write fid in CLP_QUERY_PCI_FN
s390x/pci: acceleration for getting S390pciState
s390x/pci: fix failures of dma map/unmap
s390x/css: Unplug handler of virtual css bridge
s390x/css: Factor out virtual css bridge and bus
s390x/css: use define for "virtual-css-bridge" literal
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/s390x/css.c')
-rw-r--r-- | hw/s390x/css.c | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 76668814da..54991f5d6f 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -1340,6 +1340,116 @@ SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, uint16_t schid) return channel_subsys.css[real_cssid]->sch_set[ssid]->sch[schid]; } +/** + * Return free device number in subchannel set. + * + * Return index of the first free device number in the subchannel set + * identified by @p cssid and @p ssid, beginning the search at @p + * start and wrapping around at MAX_DEVNO. Return a value exceeding + * MAX_SCHID if there are no free device numbers in the subchannel + * set. + */ +static uint32_t css_find_free_devno(uint8_t cssid, uint8_t ssid, + uint16_t start) +{ + uint32_t round; + + for (round = 0; round <= MAX_DEVNO; round++) { + uint16_t devno = (start + round) % MAX_DEVNO; + + if (!css_devno_used(cssid, ssid, devno)) { + return devno; + } + } + return MAX_DEVNO + 1; +} + +/** + * Return first free subchannel (id) in subchannel set. + * + * Return index of the first free subchannel in the subchannel set + * identified by @p cssid and @p ssid, if there is any. Return a value + * exceeding MAX_SCHID if there are no free subchannels in the + * subchannel set. + */ +static uint32_t css_find_free_subch(uint8_t cssid, uint8_t ssid) +{ + uint32_t schid; + + for (schid = 0; schid <= MAX_SCHID; schid++) { + if (!css_find_subch(1, cssid, ssid, schid)) { + return schid; + } + } + return MAX_SCHID + 1; +} + +/** + * Return first free subchannel (id) in subchannel set for a device number + * + * Verify the device number @p devno is not used yet in the subchannel + * set identified by @p cssid and @p ssid. Set @p schid to the index + * of the first free subchannel in the subchannel set, if there is + * any. Return true if everything succeeded and false otherwise. + */ +static bool css_find_free_subch_for_devno(uint8_t cssid, uint8_t ssid, + uint16_t devno, uint16_t *schid, + Error **errp) +{ + uint32_t free_schid; + + assert(schid); + if (css_devno_used(cssid, ssid, devno)) { + error_setg(errp, "Device %x.%x.%04x already exists", + cssid, ssid, devno); + return false; + } + free_schid = css_find_free_subch(cssid, ssid); + if (free_schid > MAX_SCHID) { + error_setg(errp, "No free subchannel found for %x.%x.%04x", + cssid, ssid, devno); + return false; + } + *schid = free_schid; + return true; +} + +/** + * Return first free subchannel (id) and device number + * + * Locate the first free subchannel and first free device number in + * any of the subchannel sets of the channel subsystem identified by + * @p cssid. Return false if no free subchannel / device number could + * be found. Otherwise set @p ssid, @p devno and @p schid to identify + * the available subchannel and device number and return true. + * + * May modify @p ssid, @p devno and / or @p schid even if no free + * subchannel / device number could be found. + */ +static bool css_find_free_subch_and_devno(uint8_t cssid, uint8_t *ssid, + uint16_t *devno, uint16_t *schid, + Error **errp) +{ + uint32_t free_schid, free_devno; + + assert(ssid && devno && schid); + for (*ssid = 0; *ssid <= MAX_SSID; (*ssid)++) { + free_schid = css_find_free_subch(cssid, *ssid); + if (free_schid > MAX_SCHID) { + continue; + } + free_devno = css_find_free_devno(cssid, *ssid, free_schid); + if (free_devno > MAX_DEVNO) { + continue; + } + *schid = free_schid; + *devno = free_devno; + return true; + } + error_setg(errp, "Virtual channel subsystem is full!"); + return false; +} + bool css_subch_visible(SubchDev *sch) { if (sch->ssid > channel_subsys.max_ssid) { @@ -1762,3 +1872,36 @@ PropertyInfo css_devid_propinfo = { .get = get_css_devid, .set = set_css_devid, }; + +SubchDev *css_create_virtual_sch(CssDevId bus_id, Error **errp) +{ + uint16_t schid = 0; + SubchDev *sch; + + if (bus_id.valid) { + /* Enforce use of virtual cssid. */ + if (bus_id.cssid != VIRTUAL_CSSID) { + error_setg(errp, "cssid %hhx not valid for virtual devices", + bus_id.cssid); + return NULL; + } + if (!css_find_free_subch_for_devno(bus_id.cssid, bus_id.ssid, + bus_id.devid, &schid, errp)) { + return NULL; + } + } else { + bus_id.cssid = VIRTUAL_CSSID; + if (!css_find_free_subch_and_devno(bus_id.cssid, &bus_id.ssid, + &bus_id.devid, &schid, errp)) { + return NULL; + } + } + + sch = g_malloc0(sizeof(*sch)); + sch->cssid = bus_id.cssid; + sch->ssid = bus_id.ssid; + sch->devno = bus_id.devid; + sch->schid = schid; + css_subch_assign(sch->cssid, sch->ssid, schid, sch->devno, sch); + return sch; +} |