diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-01-02 18:37:01 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-01-02 18:37:01 -0800 |
commit | 04a17edeca524b71dbb5be41a7002d247fbf34c0 (patch) | |
tree | ad2809ab91000a6fb5a831c26ff78bba6a52bb0d /drivers/s390/crypto/ap_bus.c | |
parent | e6b92572808467f35fd159d47c45b650de29e722 (diff) | |
parent | ec10574d00da0d8b6ec9d0099410aae8aad4695a (diff) | |
download | linux-04a17edeca524b71dbb5be41a7002d247fbf34c0.tar.bz2 |
Merge tag 's390-4.21-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Martin Schwidefsky:
- A larger update for the zcrypt / AP bus code:
+ Update two inline assemblies in the zcrypt driver to make gcc happy
+ Add a missing reply code for invalid special commands for zcrypt
+ Allow AP device reset to be triggered from user space
+ Split the AP scan function into smaller, more readable functions
- Updates for vfio-ccw and vfio-ap
+ Add maintainers and reviewer for vfio-ccw
+ Include facility.h in vfio_ap_drv.c to avoid fragile include chain
+ Simplicy vfio-ccw state machine
- Use the common code version of bust_spinlocks
- Make use of the DEFINE_SHOW_ATTRIBUTE
- Fix three incorrect file permissions in the DASD driver
- Remove bit spin-lock from the PCI interrupt handler
- Fix GFP_ATOMIC vs GFP_KERNEL in the PCI code
* tag 's390-4.21-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
s390/zcrypt: rework ap scan bus code
s390/zcrypt: make sysfs reset attribute trigger queue reset
s390/pci: fix sleeping in atomic during hotplug
s390/pci: remove bit_lock usage in interrupt handler
s390/drivers: fix proc/debugfs file permissions
s390: convert to DEFINE_SHOW_ATTRIBUTE
MAINTAINERS/vfio-ccw: add Farhan and Eric, make Halil Reviewer
vfio: ccw: Merge BUSY and BOXED states
s390: use common bust_spinlocks()
s390/zcrypt: improve special ap message cmd handling
s390/ap: rework assembler functions to use unions for in/out register variables
s390: vfio-ap: include <asm/facility> for test_facility()
Diffstat (limited to 'drivers/s390/crypto/ap_bus.c')
-rw-r--r-- | drivers/s390/crypto/ap_bus.c | 277 |
1 files changed, 160 insertions, 117 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 9f5a201c4c87..48ea0004a56d 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -299,7 +299,7 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type, ap_max_domain_id = 15; switch (*device_type) { /* For CEX2 and CEX3 the available functions - * are not refrected by the facilities bits. + * are not reflected by the facilities bits. * Instead it is coded into the type. So here * modify the function bits based on the type. */ @@ -1317,7 +1317,7 @@ static int ap_get_compatible_type(ap_qid_t qid, int rawtype, unsigned int func) } /* - * helper function to be used with bus_find_dev + * Helper function to be used with bus_find_dev * matches for the card device with the given id */ static int __match_card_device_with_id(struct device *dev, void *data) @@ -1325,7 +1325,8 @@ static int __match_card_device_with_id(struct device *dev, void *data) return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long) data; } -/* helper function to be used with bus_find_dev +/* + * Helper function to be used with bus_find_dev * matches for the queue device with a given qid */ static int __match_queue_device_with_qid(struct device *dev, void *data) @@ -1333,143 +1334,185 @@ static int __match_queue_device_with_qid(struct device *dev, void *data) return is_queue_dev(dev) && to_ap_queue(dev)->qid == (int)(long) data; } -/** - * ap_scan_bus(): Scan the AP bus for new devices - * Runs periodically, workqueue timer (ap_config_time) +/* + * Helper function for ap_scan_bus(). + * Does the scan bus job for the given adapter id. */ -static void ap_scan_bus(struct work_struct *unused) +static void _ap_scan_bus_adapter(int id) { - struct ap_queue *aq; + ap_qid_t qid; + unsigned int func; struct ap_card *ac; struct device *dev; - ap_qid_t qid; - int comp_type, depth = 0, type = 0; - unsigned int func = 0; - int rc, id, dom, borked, domains, defdomdevs = 0; - - AP_DBF(DBF_DEBUG, "%s running\n", __func__); + struct ap_queue *aq; + int rc, dom, depth, type, comp_type, borked; + + /* check if there is a card device registered with this id */ + dev = bus_find_device(&ap_bus_type, NULL, + (void *)(long) id, + __match_card_device_with_id); + ac = dev ? to_ap_card(dev) : NULL; + if (!ap_test_config_card_id(id)) { + if (dev) { + /* Card device has been removed from configuration */ + bus_for_each_dev(&ap_bus_type, NULL, + (void *)(long) id, + __ap_queue_devices_with_id_unregister); + device_unregister(dev); + put_device(dev); + } + return; + } - ap_query_configuration(ap_configuration); - ap_select_domain(); + /* + * This card id is enabled in the configuration. If we already have + * a card device with this id, check if type and functions are still + * the very same. Also verify that at least one queue is available. + */ + if (ac) { + /* find the first valid queue */ + for (dom = 0; dom < AP_DOMAINS; dom++) { + qid = AP_MKQID(id, dom); + if (ap_query_queue(qid, &depth, &type, &func) == 0) + break; + } + borked = 0; + if (dom >= AP_DOMAINS) { + /* no accessible queue on this card */ + borked = 1; + } else if (ac->raw_hwtype != type) { + /* card type has changed */ + AP_DBF(DBF_INFO, "card=%02x type changed.\n", id); + borked = 1; + } else if (ac->functions != func) { + /* card functions have changed */ + AP_DBF(DBF_INFO, "card=%02x functions changed.\n", id); + borked = 1; + } + if (borked) { + /* unregister card device and associated queues */ + bus_for_each_dev(&ap_bus_type, NULL, + (void *)(long) id, + __ap_queue_devices_with_id_unregister); + device_unregister(dev); + put_device(dev); + /* go back if there is no valid queue on this card */ + if (dom >= AP_DOMAINS) + return; + ac = NULL; + } + } - for (id = 0; id < AP_DEVICES; id++) { - /* check if device is registered */ + /* + * Go through all possible queue ids. Check and maybe create or release + * queue devices for this card. If there exists no card device yet, + * create a card device also. + */ + for (dom = 0; dom < AP_DOMAINS; dom++) { + qid = AP_MKQID(id, dom); dev = bus_find_device(&ap_bus_type, NULL, - (void *)(long) id, - __match_card_device_with_id); - ac = dev ? to_ap_card(dev) : NULL; - if (!ap_test_config_card_id(id)) { + (void *)(long) qid, + __match_queue_device_with_qid); + aq = dev ? to_ap_queue(dev) : NULL; + if (!ap_test_config_domain(dom)) { if (dev) { - /* Card device has been removed from - * configuration, remove the belonging - * queue devices. + /* Queue device exists but has been + * removed from configuration. */ - bus_for_each_dev(&ap_bus_type, NULL, - (void *)(long) id, - __ap_queue_devices_with_id_unregister); - /* now remove the card device */ device_unregister(dev); put_device(dev); } continue; } - /* According to the configuration there should be a card - * device, so check if there is at least one valid queue - * and maybe create queue devices and the card device. - */ - domains = 0; - for (dom = 0; dom < AP_DOMAINS; dom++) { - qid = AP_MKQID(id, dom); - dev = bus_find_device(&ap_bus_type, NULL, - (void *)(long) qid, - __match_queue_device_with_qid); - aq = dev ? to_ap_queue(dev) : NULL; - if (!ap_test_config_domain(dom)) { - if (dev) { - /* Queue device exists but has been - * removed from configuration. - */ - device_unregister(dev); - put_device(dev); - } - continue; - } - rc = ap_query_queue(qid, &depth, &type, &func); - if (dev) { + /* try to fetch infos about this queue */ + rc = ap_query_queue(qid, &depth, &type, &func); + if (dev) { + if (rc == -ENODEV) + borked = 1; + else { spin_lock_bh(&aq->lock); - if (rc == -ENODEV || - /* adapter reconfiguration */ - (ac && ac->functions != func)) - aq->state = AP_STATE_BORKED; borked = aq->state == AP_STATE_BORKED; spin_unlock_bh(&aq->lock); - if (borked) /* Remove broken device */ - device_unregister(dev); - put_device(dev); - if (!borked) { - domains++; - if (dom == ap_domain_index) - defdomdevs++; - continue; - } - } - if (rc) - continue; - /* a new queue device is needed, check out comp type */ - comp_type = ap_get_compatible_type(qid, type, func); - if (!comp_type) - continue; - /* maybe a card device needs to be created first */ - if (!ac) { - ac = ap_card_create(id, depth, type, - comp_type, func); - if (!ac) - continue; - ac->ap_dev.device.bus = &ap_bus_type; - ac->ap_dev.device.parent = ap_root_device; - dev_set_name(&ac->ap_dev.device, - "card%02x", id); - /* Register card with AP bus */ - rc = device_register(&ac->ap_dev.device); - if (rc) { - put_device(&ac->ap_dev.device); - ac = NULL; - break; - } - /* get it and thus adjust reference counter */ - get_device(&ac->ap_dev.device); } - /* now create the new queue device */ - aq = ap_queue_create(qid, comp_type); - if (!aq) + if (borked) /* Remove broken device */ + device_unregister(dev); + put_device(dev); + continue; + } + if (rc) + continue; + /* a new queue device is needed, check out comp type */ + comp_type = ap_get_compatible_type(qid, type, func); + if (!comp_type) + continue; + /* maybe a card device needs to be created first */ + if (!ac) { + ac = ap_card_create(id, depth, type, comp_type, func); + if (!ac) continue; - aq->card = ac; - aq->ap_dev.device.bus = &ap_bus_type; - aq->ap_dev.device.parent = &ac->ap_dev.device; - dev_set_name(&aq->ap_dev.device, - "%02x.%04x", id, dom); - /* Register device */ - rc = device_register(&aq->ap_dev.device); + ac->ap_dev.device.bus = &ap_bus_type; + ac->ap_dev.device.parent = ap_root_device; + dev_set_name(&ac->ap_dev.device, "card%02x", id); + /* Register card device with AP bus */ + rc = device_register(&ac->ap_dev.device); if (rc) { - put_device(&aq->ap_dev.device); - continue; + put_device(&ac->ap_dev.device); + ac = NULL; + break; } - domains++; - if (dom == ap_domain_index) - defdomdevs++; - } /* end domain loop */ - if (ac) { - /* remove card dev if there are no queue devices */ - if (!domains) - device_unregister(&ac->ap_dev.device); - put_device(&ac->ap_dev.device); + /* get it and thus adjust reference counter */ + get_device(&ac->ap_dev.device); + } + /* now create the new queue device */ + aq = ap_queue_create(qid, comp_type); + if (!aq) + continue; + aq->card = ac; + aq->ap_dev.device.bus = &ap_bus_type; + aq->ap_dev.device.parent = &ac->ap_dev.device; + dev_set_name(&aq->ap_dev.device, "%02x.%04x", id, dom); + /* Register queue device */ + rc = device_register(&aq->ap_dev.device); + if (rc) { + put_device(&aq->ap_dev.device); + continue; } - } /* end device loop */ + } /* end domain loop */ + + if (ac) + put_device(&ac->ap_dev.device); +} - if (ap_domain_index >= 0 && defdomdevs < 1) - AP_DBF(DBF_INFO, - "no queue device with default domain %d available\n", - ap_domain_index); +/** + * ap_scan_bus(): Scan the AP bus for new devices + * Runs periodically, workqueue timer (ap_config_time) + */ +static void ap_scan_bus(struct work_struct *unused) +{ + int id; + + AP_DBF(DBF_DEBUG, "%s running\n", __func__); + + ap_query_configuration(ap_configuration); + ap_select_domain(); + + /* loop over all possible adapters */ + for (id = 0; id < AP_DEVICES; id++) + _ap_scan_bus_adapter(id); + + /* check if there is at least one queue available with default domain */ + if (ap_domain_index >= 0) { + struct device *dev = + bus_find_device(&ap_bus_type, NULL, + (void *)(long) ap_domain_index, + __match_queue_device_with_qid); + if (dev) + put_device(dev); + else + AP_DBF(DBF_INFO, + "no queue device with default domain %d available\n", + ap_domain_index); + } mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ); } |