Merge tag 's390-4.21-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 3 Jan 2019 02:37:01 +0000 (18:37 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 3 Jan 2019 02:37:01 +0000 (18:37 -0800)
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()

17 files changed:
MAINTAINERS
arch/s390/include/asm/ap.h
arch/s390/include/uapi/asm/zcrypt.h
arch/s390/mm/fault.c
arch/s390/pci/pci.c
arch/s390/pci/pci_clp.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_proc.c
drivers/s390/char/tape_proc.c
drivers/s390/cio/qdio_debug.c
drivers/s390/cio/vfio_ccw_fsm.c
drivers/s390/cio/vfio_ccw_private.h
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/ap_queue.c
drivers/s390/crypto/vfio_ap_drv.c
drivers/s390/crypto/zcrypt_error.h
lib/bust_spinlocks.c

index 7ba42fbb2c4ae05830bf0ed04db9cdca82ed6c30..a69c127e357818126c7983799f9247451f7b4d8d 100644 (file)
@@ -13162,7 +13162,9 @@ F:      drivers/pci/hotplug/s390_pci_hpc.c
 
 S390 VFIO-CCW DRIVER
 M:     Cornelia Huck <cohuck@redhat.com>
-M:     Halil Pasic <pasic@linux.ibm.com>
+M:     Farhan Ali <alifm@linux.ibm.com>
+M:     Eric Farman <farman@linux.ibm.com>
+R:     Halil Pasic <pasic@linux.ibm.com>
 L:     linux-s390@vger.kernel.org
 L:     kvm@vger.kernel.org
 S:     Supported
index 8c00fd509c45555fbde5ef9febe6b732c3c4f46b..1a6a7092d94209d4ee330003cfd3d2ccf713b916 100644 (file)
@@ -221,16 +221,22 @@ static inline struct ap_queue_status ap_aqic(ap_qid_t qid,
                                             void *ind)
 {
        register unsigned long reg0 asm ("0") = qid | (3UL << 24);
-       register struct ap_qirq_ctrl reg1_in asm ("1") = qirqctrl;
-       register struct ap_queue_status reg1_out asm ("1");
+       register union {
+               unsigned long value;
+               struct ap_qirq_ctrl qirqctrl;
+               struct ap_queue_status status;
+       } reg1 asm ("1");
        register void *reg2 asm ("2") = ind;
 
+       reg1.qirqctrl = qirqctrl;
+
        asm volatile(
                ".long 0xb2af0000"              /* PQAP(AQIC) */
-               : "=d" (reg1_out)
-               : "d" (reg0), "d" (reg1_in), "d" (reg2)
+               : "+d" (reg1)
+               : "d" (reg0), "d" (reg2)
                : "cc");
-       return reg1_out;
+
+       return reg1.status;
 }
 
 /*
@@ -264,17 +270,21 @@ static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit,
 {
        register unsigned long reg0 asm ("0") = qid | (5UL << 24)
                | ((ifbit & 0x01) << 22);
-       register unsigned long reg1_in asm ("1") = apinfo->val;
-       register struct ap_queue_status reg1_out asm ("1");
+       register union {
+               unsigned long value;
+               struct ap_queue_status status;
+       } reg1 asm ("1");
        register unsigned long reg2 asm ("2");
 
+       reg1.value = apinfo->val;
+
        asm volatile(
                ".long 0xb2af0000"              /* PQAP(QACT) */
-               : "+d" (reg1_in), "=d" (reg1_out), "=d" (reg2)
+               : "+d" (reg1), "=d" (reg2)
                : "d" (reg0)
                : "cc");
        apinfo->val = reg2;
-       return reg1_out;
+       return reg1.status;
 }
 
 /**
index 42c81a95e97ba8aee708388f1c76bcdde12a6e78..494c34c507161ecce23e72fc4dd5cca2e2a0cf9a 100644 (file)
@@ -150,8 +150,8 @@ struct ica_xcRB {
  * @cprb_len:          CPRB header length [0x0020]
  * @cprb_ver_id:       CPRB version id.   [0x04]
  * @pad_000:           Alignment pad bytes
- * @flags:             Admin cmd [0x80] or functional cmd [0x00]
- * @func_id:           Function id / subtype [0x5434]
+ * @flags:             Admin bit [0x80], Special bit [0x20]
+ * @func_id:           Function id / subtype [0x5434] "T4"
  * @source_id:         Source id [originator id]
  * @target_id:         Target id [usage/ctrl domain id]
  * @ret_code:          Return code
index 2b8f32f56e0c20870ef250741562d6d6146d72be..11613362c4e75f9d3668a9618dfed7d7265d9d32 100644 (file)
@@ -81,30 +81,6 @@ static inline int notify_page_fault(struct pt_regs *regs)
        return ret;
 }
 
-
-/*
- * Unlock any spinlocks which will prevent us from getting the
- * message out.
- */
-void bust_spinlocks(int yes)
-{
-       if (yes) {
-               oops_in_progress = 1;
-       } else {
-               int loglevel_save = console_loglevel;
-               console_unblank();
-               oops_in_progress = 0;
-               /*
-                * OK, the message is on the console.  Now we call printk()
-                * without oops_in_progress set so that printk will give klogd
-                * a poke.  Hold onto your hats...
-                */
-               console_loglevel = 15;
-               printk(" ");
-               console_loglevel = loglevel_save;
-       }
-}
-
 /*
  * Find out which address space caused the exception.
  * Access register mode is impossible, ignore space == 3.
index 9f6f392a44619ef41b910f5e6899c69d07a24edf..6df622fb406d7ddcaf6a83c352727a25c35c882c 100644 (file)
@@ -382,9 +382,7 @@ static void zpci_irq_handler(struct airq_struct *airq)
                        if (ai == -1UL)
                                break;
                        inc_irq_stat(IRQIO_MSI);
-                       airq_iv_lock(aibv, ai);
                        generic_handle_irq(airq_iv_get_data(aibv, ai));
-                       airq_iv_unlock(aibv, ai);
                }
        }
 }
@@ -410,7 +408,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
        zdev->aisb = aisb;
 
        /* Create adapter interrupt vector */
-       zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK);
+       zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA);
        if (!zdev->aibv)
                return -ENOMEM;
 
index 19b2d2a9b43db346a4ac3e308582c7a322c9d01c..eeb7450db18c06b8760cd5e1a577234ebc2c95f7 100644 (file)
@@ -436,7 +436,7 @@ int clp_get_state(u32 fid, enum zpci_state *state)
        struct clp_state_data sd = {fid, ZPCI_FN_STATE_RESERVED};
        int rc;
 
-       rrb = clp_alloc_block(GFP_KERNEL);
+       rrb = clp_alloc_block(GFP_ATOMIC);
        if (!rrb)
                return -ENOMEM;
 
index 5e9ebdb0594c537e75fb07b965b7940b6fbc5aab..397af07e4d88df7e488b781634b4e5e33f00be1c 100644 (file)
@@ -1192,20 +1192,7 @@ static int dasd_hosts_show(struct seq_file *m, void *v)
        return rc;
 }
 
-static int dasd_hosts_open(struct inode *inode, struct file *file)
-{
-       struct dasd_device *device = inode->i_private;
-
-       return single_open(file, dasd_hosts_show, device);
-}
-
-static const struct file_operations dasd_hosts_fops = {
-       .owner          = THIS_MODULE,
-       .open           = dasd_hosts_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(dasd_hosts);
 
 static void dasd_hosts_exit(struct dasd_device *device)
 {
index 5cb80c64548932880be2efc7a9d838eb90aa6e42..1770b99f607e6638570fdc39b118a8bf97c41f2b 100644 (file)
@@ -339,8 +339,7 @@ dasd_proc_init(void)
        dasd_proc_root_entry = proc_mkdir("dasd", NULL);
        if (!dasd_proc_root_entry)
                goto out_nodasd;
-       dasd_devices_entry = proc_create_seq("devices",
-                                        S_IFREG | S_IRUGO | S_IWUSR,
+       dasd_devices_entry = proc_create_seq("devices", 0444,
                                         dasd_proc_root_entry,
                                         &dasd_devices_seq_ops);
        if (!dasd_devices_entry)
index 32a14ee31c6b6ed8e8ab9dd1134e2031b8c4ad64..2238d9df6c473ad94608793b85501d9a5fe92b82 100644 (file)
@@ -111,11 +111,8 @@ static const struct seq_operations tape_proc_seq = {
 void
 tape_proc_init(void)
 {
-       tape_proc_devices = proc_create_seq("tapedevices",
-                       S_IFREG | S_IRUGO | S_IWUSR, NULL,  &tape_proc_seq);
-       if (tape_proc_devices == NULL) {
-               return;
-       }
+       tape_proc_devices = proc_create_seq("tapedevices", 0444, NULL,
+                                           &tape_proc_seq);
 }
 
 /*
index 68a82f3e2e92b09951bf30a3094f20285154bdc1..d2f98e5829d493cb553b658838610d66464fb64c 100644 (file)
@@ -190,19 +190,7 @@ static int qstat_show(struct seq_file *m, void *v)
        return 0;
 }
 
-static int qstat_seq_open(struct inode *inode, struct file *filp)
-{
-       return single_open(filp, qstat_show,
-                          file_inode(filp)->i_private);
-}
-
-static const struct file_operations debugfs_fops = {
-       .owner   = THIS_MODULE,
-       .open    = qstat_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(qstat);
 
 static char *qperf_names[] = {
        "Assumed adapter interrupts",
@@ -305,8 +293,8 @@ static void setup_debugfs_entry(struct qdio_q *q)
        snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
                 q->is_input_q ? "input" : "output",
                 q->nr);
-       q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
-                               q->irq_ptr->debugfs_dev, q, &debugfs_fops);
+       q->debugfs_q = debugfs_create_file(name, 0444,
+                               q->irq_ptr->debugfs_dev, q, &qstat_fops);
        if (IS_ERR(q->debugfs_q))
                q->debugfs_q = NULL;
 }
index f94aa01f9c36adb748693a09766cb0ea33dec450..cab17865aafe1adba34b5388af859b1ccbad2457 100644 (file)
@@ -130,7 +130,7 @@ static void fsm_io_request(struct vfio_ccw_private *private,
        struct mdev_device *mdev = private->mdev;
        char *errstr = "request";
 
-       private->state = VFIO_CCW_STATE_BOXED;
+       private->state = VFIO_CCW_STATE_BUSY;
 
        memcpy(scsw, io_region->scsw_area, sizeof(*scsw));
 
@@ -216,11 +216,6 @@ fsm_func_t *vfio_ccw_jumptable[NR_VFIO_CCW_STATES][NR_VFIO_CCW_EVENTS] = {
                [VFIO_CCW_EVENT_IO_REQ]         = fsm_io_request,
                [VFIO_CCW_EVENT_INTERRUPT]      = fsm_irq,
        },
-       [VFIO_CCW_STATE_BOXED] = {
-               [VFIO_CCW_EVENT_NOT_OPER]       = fsm_notoper,
-               [VFIO_CCW_EVENT_IO_REQ]         = fsm_io_busy,
-               [VFIO_CCW_EVENT_INTERRUPT]      = fsm_irq,
-       },
        [VFIO_CCW_STATE_BUSY] = {
                [VFIO_CCW_EVENT_NOT_OPER]       = fsm_notoper,
                [VFIO_CCW_EVENT_IO_REQ]         = fsm_io_busy,
index 078e46f9623d5f4a128ea37e3840867583ff47f8..08e9a7dc9176b8b0899e393fb757f4b0b3c9d117 100644 (file)
@@ -63,7 +63,6 @@ enum vfio_ccw_state {
        VFIO_CCW_STATE_NOT_OPER,
        VFIO_CCW_STATE_STANDBY,
        VFIO_CCW_STATE_IDLE,
-       VFIO_CCW_STATE_BOXED,
        VFIO_CCW_STATE_BUSY,
        /* last element! */
        NR_VFIO_CCW_STATES
index 9f5a201c4c87861f6b77c6081b03a8d58d571366..48ea0004a56da0dfe51c4251f0af62d0b4679a83 100644 (file)
@@ -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);
 }
index 0aa4b3ccc948c10cbbd9ac904d6da353e341fd78..576ac08777c509ee038a50ec95a892fc79776355 100644 (file)
@@ -14,6 +14,9 @@
 #include <asm/facility.h>
 
 #include "ap_bus.h"
+#include "ap_debug.h"
+
+static void __ap_flush_queue(struct ap_queue *aq);
 
 /**
  * ap_queue_enable_interruption(): Enable interruption on an AP queue.
@@ -541,7 +544,25 @@ static ssize_t reset_show(struct device *dev,
        return rc;
 }
 
-static DEVICE_ATTR_RO(reset);
+static ssize_t reset_store(struct device *dev,
+                          struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+       struct ap_queue *aq = to_ap_queue(dev);
+
+       spin_lock_bh(&aq->lock);
+       __ap_flush_queue(aq);
+       aq->state = AP_STATE_RESET_START;
+       ap_wait(ap_sm_event(aq, AP_EVENT_POLL));
+       spin_unlock_bh(&aq->lock);
+
+       AP_DBF(DBF_INFO, "reset queue=%02x.%04x triggered by user\n",
+              AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
+
+       return count;
+}
+
+static DEVICE_ATTR_RW(reset);
 
 static ssize_t interrupt_show(struct device *dev,
                              struct device_attribute *attr, char *buf)
index 7667b38728f016785e588960aa6d2044199e1669..31c6c847eacaefae24fa97ece349d47d515a2bf8 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mod_devicetable.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <asm/facility.h>
 #include "vfio_ap_private.h"
 
 #define VFIO_AP_ROOT_NAME "vfio_ap"
index 240b27f3f5f6ad088b436d0eb843982b5d01dad7..f34ee41cbed88df1ff2a8e870db9e16f97baa3a3 100644 (file)
@@ -51,6 +51,7 @@ struct error_hdr {
 #define REP82_ERROR_FORMAT_FIELD           0x29
 #define REP82_ERROR_INVALID_COMMAND        0x30
 #define REP82_ERROR_MALFORMED_MSG          0x40
+#define REP82_ERROR_INVALID_SPECIAL_CMD            0x41
 #define REP82_ERROR_INVALID_DOMAIN_PRECHECK 0x42
 #define REP82_ERROR_RESERVED_FIELDO        0x50 /* old value   */
 #define REP82_ERROR_WORD_ALIGNMENT         0x60
@@ -89,6 +90,7 @@ static inline int convert_error(struct zcrypt_queue *zq,
        case REP88_ERROR_MESSAGE_MALFORMD:
        case REP82_ERROR_INVALID_DOMAIN_PRECHECK:
        case REP82_ERROR_INVALID_DOMAIN_PENDING:
+       case REP82_ERROR_INVALID_SPECIAL_CMD:
        //   REP88_ERROR_INVALID_KEY            // '82' CEX2A
        //   REP88_ERROR_OPERAND                // '84' CEX2A
        //   REP88_ERROR_OPERAND_EVEN_MOD       // '85' CEX2A
index ab719495e2cb42ba7b8c85e7ef5dfadff4695946..8be59f84eaeaf495e9dcf6b3ca049ab360f04753 100644 (file)
@@ -2,7 +2,8 @@
 /*
  * lib/bust_spinlocks.c
  *
- * Provides a minimal bust_spinlocks for architectures which don't have one of their own.
+ * Provides a minimal bust_spinlocks for architectures which don't
+ * have one of their own.
  *
  * bust_spinlocks() clears any spinlocks which would prevent oops, die(), BUG()
  * and panic() information from reaching the user.
@@ -16,8 +17,7 @@
 #include <linux/vt_kern.h>
 #include <linux/console.h>
 
-
-void __attribute__((weak)) bust_spinlocks(int yes)
+void bust_spinlocks(int yes)
 {
        if (yes) {
                ++oops_in_progress;