diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-01-02 21:37:01 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-01-02 21:37:01 -0500 |
| commit | 04a17edeca524b71dbb5be41a7002d247fbf34c0 (patch) | |
| tree | ad2809ab91000a6fb5a831c26ff78bba6a52bb0d | |
| parent | e6b92572808467f35fd159d47c45b650de29e722 (diff) | |
| parent | ec10574d00da0d8b6ec9d0099410aae8aad4695a (diff) | |
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()
| -rw-r--r-- | MAINTAINERS | 4 | ||||
| -rw-r--r-- | arch/s390/include/asm/ap.h | 28 | ||||
| -rw-r--r-- | arch/s390/include/uapi/asm/zcrypt.h | 4 | ||||
| -rw-r--r-- | arch/s390/mm/fault.c | 24 | ||||
| -rw-r--r-- | arch/s390/pci/pci.c | 4 | ||||
| -rw-r--r-- | arch/s390/pci/pci_clp.c | 2 | ||||
| -rw-r--r-- | drivers/s390/block/dasd.c | 15 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_proc.c | 3 | ||||
| -rw-r--r-- | drivers/s390/char/tape_proc.c | 7 | ||||
| -rw-r--r-- | drivers/s390/cio/qdio_debug.c | 18 | ||||
| -rw-r--r-- | drivers/s390/cio/vfio_ccw_fsm.c | 7 | ||||
| -rw-r--r-- | drivers/s390/cio/vfio_ccw_private.h | 1 | ||||
| -rw-r--r-- | drivers/s390/crypto/ap_bus.c | 277 | ||||
| -rw-r--r-- | drivers/s390/crypto/ap_queue.c | 23 | ||||
| -rw-r--r-- | drivers/s390/crypto/vfio_ap_drv.c | 1 | ||||
| -rw-r--r-- | drivers/s390/crypto/zcrypt_error.h | 2 | ||||
| -rw-r--r-- | lib/bust_spinlocks.c | 6 |
17 files changed, 222 insertions, 204 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 7ba42fbb2c4a..a69c127e3578 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -13162,7 +13162,9 @@ F: drivers/pci/hotplug/s390_pci_hpc.c | |||
| 13162 | 13162 | ||
| 13163 | S390 VFIO-CCW DRIVER | 13163 | S390 VFIO-CCW DRIVER |
| 13164 | M: Cornelia Huck <cohuck@redhat.com> | 13164 | M: Cornelia Huck <cohuck@redhat.com> |
| 13165 | M: Halil Pasic <pasic@linux.ibm.com> | 13165 | M: Farhan Ali <alifm@linux.ibm.com> |
| 13166 | M: Eric Farman <farman@linux.ibm.com> | ||
| 13167 | R: Halil Pasic <pasic@linux.ibm.com> | ||
| 13166 | L: linux-s390@vger.kernel.org | 13168 | L: linux-s390@vger.kernel.org |
| 13167 | L: kvm@vger.kernel.org | 13169 | L: kvm@vger.kernel.org |
| 13168 | S: Supported | 13170 | S: Supported |
diff --git a/arch/s390/include/asm/ap.h b/arch/s390/include/asm/ap.h index 8c00fd509c45..1a6a7092d942 100644 --- a/arch/s390/include/asm/ap.h +++ b/arch/s390/include/asm/ap.h | |||
| @@ -221,16 +221,22 @@ static inline struct ap_queue_status ap_aqic(ap_qid_t qid, | |||
| 221 | void *ind) | 221 | void *ind) |
| 222 | { | 222 | { |
| 223 | register unsigned long reg0 asm ("0") = qid | (3UL << 24); | 223 | register unsigned long reg0 asm ("0") = qid | (3UL << 24); |
| 224 | register struct ap_qirq_ctrl reg1_in asm ("1") = qirqctrl; | 224 | register union { |
| 225 | register struct ap_queue_status reg1_out asm ("1"); | 225 | unsigned long value; |
| 226 | struct ap_qirq_ctrl qirqctrl; | ||
| 227 | struct ap_queue_status status; | ||
| 228 | } reg1 asm ("1"); | ||
| 226 | register void *reg2 asm ("2") = ind; | 229 | register void *reg2 asm ("2") = ind; |
| 227 | 230 | ||
| 231 | reg1.qirqctrl = qirqctrl; | ||
| 232 | |||
| 228 | asm volatile( | 233 | asm volatile( |
| 229 | ".long 0xb2af0000" /* PQAP(AQIC) */ | 234 | ".long 0xb2af0000" /* PQAP(AQIC) */ |
| 230 | : "=d" (reg1_out) | 235 | : "+d" (reg1) |
| 231 | : "d" (reg0), "d" (reg1_in), "d" (reg2) | 236 | : "d" (reg0), "d" (reg2) |
| 232 | : "cc"); | 237 | : "cc"); |
| 233 | return reg1_out; | 238 | |
| 239 | return reg1.status; | ||
| 234 | } | 240 | } |
| 235 | 241 | ||
| 236 | /* | 242 | /* |
| @@ -264,17 +270,21 @@ static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit, | |||
| 264 | { | 270 | { |
| 265 | register unsigned long reg0 asm ("0") = qid | (5UL << 24) | 271 | register unsigned long reg0 asm ("0") = qid | (5UL << 24) |
| 266 | | ((ifbit & 0x01) << 22); | 272 | | ((ifbit & 0x01) << 22); |
| 267 | register unsigned long reg1_in asm ("1") = apinfo->val; | 273 | register union { |
| 268 | register struct ap_queue_status reg1_out asm ("1"); | 274 | unsigned long value; |
| 275 | struct ap_queue_status status; | ||
| 276 | } reg1 asm ("1"); | ||
| 269 | register unsigned long reg2 asm ("2"); | 277 | register unsigned long reg2 asm ("2"); |
| 270 | 278 | ||
| 279 | reg1.value = apinfo->val; | ||
| 280 | |||
| 271 | asm volatile( | 281 | asm volatile( |
| 272 | ".long 0xb2af0000" /* PQAP(QACT) */ | 282 | ".long 0xb2af0000" /* PQAP(QACT) */ |
| 273 | : "+d" (reg1_in), "=d" (reg1_out), "=d" (reg2) | 283 | : "+d" (reg1), "=d" (reg2) |
| 274 | : "d" (reg0) | 284 | : "d" (reg0) |
| 275 | : "cc"); | 285 | : "cc"); |
| 276 | apinfo->val = reg2; | 286 | apinfo->val = reg2; |
| 277 | return reg1_out; | 287 | return reg1.status; |
| 278 | } | 288 | } |
| 279 | 289 | ||
| 280 | /** | 290 | /** |
diff --git a/arch/s390/include/uapi/asm/zcrypt.h b/arch/s390/include/uapi/asm/zcrypt.h index 42c81a95e97b..494c34c50716 100644 --- a/arch/s390/include/uapi/asm/zcrypt.h +++ b/arch/s390/include/uapi/asm/zcrypt.h | |||
| @@ -150,8 +150,8 @@ struct ica_xcRB { | |||
| 150 | * @cprb_len: CPRB header length [0x0020] | 150 | * @cprb_len: CPRB header length [0x0020] |
| 151 | * @cprb_ver_id: CPRB version id. [0x04] | 151 | * @cprb_ver_id: CPRB version id. [0x04] |
| 152 | * @pad_000: Alignment pad bytes | 152 | * @pad_000: Alignment pad bytes |
| 153 | * @flags: Admin cmd [0x80] or functional cmd [0x00] | 153 | * @flags: Admin bit [0x80], Special bit [0x20] |
| 154 | * @func_id: Function id / subtype [0x5434] | 154 | * @func_id: Function id / subtype [0x5434] "T4" |
| 155 | * @source_id: Source id [originator id] | 155 | * @source_id: Source id [originator id] |
| 156 | * @target_id: Target id [usage/ctrl domain id] | 156 | * @target_id: Target id [usage/ctrl domain id] |
| 157 | * @ret_code: Return code | 157 | * @ret_code: Return code |
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 2b8f32f56e0c..11613362c4e7 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
| @@ -81,30 +81,6 @@ static inline int notify_page_fault(struct pt_regs *regs) | |||
| 81 | return ret; | 81 | return ret; |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | |||
| 85 | /* | ||
| 86 | * Unlock any spinlocks which will prevent us from getting the | ||
| 87 | * message out. | ||
| 88 | */ | ||
| 89 | void bust_spinlocks(int yes) | ||
| 90 | { | ||
| 91 | if (yes) { | ||
| 92 | oops_in_progress = 1; | ||
| 93 | } else { | ||
| 94 | int loglevel_save = console_loglevel; | ||
| 95 | console_unblank(); | ||
| 96 | oops_in_progress = 0; | ||
| 97 | /* | ||
| 98 | * OK, the message is on the console. Now we call printk() | ||
| 99 | * without oops_in_progress set so that printk will give klogd | ||
| 100 | * a poke. Hold onto your hats... | ||
| 101 | */ | ||
| 102 | console_loglevel = 15; | ||
| 103 | printk(" "); | ||
| 104 | console_loglevel = loglevel_save; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | /* | 84 | /* |
| 109 | * Find out which address space caused the exception. | 85 | * Find out which address space caused the exception. |
| 110 | * Access register mode is impossible, ignore space == 3. | 86 | * Access register mode is impossible, ignore space == 3. |
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 9f6f392a4461..6df622fb406d 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c | |||
| @@ -382,9 +382,7 @@ static void zpci_irq_handler(struct airq_struct *airq) | |||
| 382 | if (ai == -1UL) | 382 | if (ai == -1UL) |
| 383 | break; | 383 | break; |
| 384 | inc_irq_stat(IRQIO_MSI); | 384 | inc_irq_stat(IRQIO_MSI); |
| 385 | airq_iv_lock(aibv, ai); | ||
| 386 | generic_handle_irq(airq_iv_get_data(aibv, ai)); | 385 | generic_handle_irq(airq_iv_get_data(aibv, ai)); |
| 387 | airq_iv_unlock(aibv, ai); | ||
| 388 | } | 386 | } |
| 389 | } | 387 | } |
| 390 | } | 388 | } |
| @@ -410,7 +408,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
| 410 | zdev->aisb = aisb; | 408 | zdev->aisb = aisb; |
| 411 | 409 | ||
| 412 | /* Create adapter interrupt vector */ | 410 | /* Create adapter interrupt vector */ |
| 413 | zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK); | 411 | zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA); |
| 414 | if (!zdev->aibv) | 412 | if (!zdev->aibv) |
| 415 | return -ENOMEM; | 413 | return -ENOMEM; |
| 416 | 414 | ||
diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c index 19b2d2a9b43d..eeb7450db18c 100644 --- a/arch/s390/pci/pci_clp.c +++ b/arch/s390/pci/pci_clp.c | |||
| @@ -436,7 +436,7 @@ int clp_get_state(u32 fid, enum zpci_state *state) | |||
| 436 | struct clp_state_data sd = {fid, ZPCI_FN_STATE_RESERVED}; | 436 | struct clp_state_data sd = {fid, ZPCI_FN_STATE_RESERVED}; |
| 437 | int rc; | 437 | int rc; |
| 438 | 438 | ||
| 439 | rrb = clp_alloc_block(GFP_KERNEL); | 439 | rrb = clp_alloc_block(GFP_ATOMIC); |
| 440 | if (!rrb) | 440 | if (!rrb) |
| 441 | return -ENOMEM; | 441 | return -ENOMEM; |
| 442 | 442 | ||
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 5e9ebdb0594c..397af07e4d88 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
| @@ -1192,20 +1192,7 @@ static int dasd_hosts_show(struct seq_file *m, void *v) | |||
| 1192 | return rc; | 1192 | return rc; |
| 1193 | } | 1193 | } |
| 1194 | 1194 | ||
| 1195 | static int dasd_hosts_open(struct inode *inode, struct file *file) | 1195 | DEFINE_SHOW_ATTRIBUTE(dasd_hosts); |
| 1196 | { | ||
| 1197 | struct dasd_device *device = inode->i_private; | ||
| 1198 | |||
| 1199 | return single_open(file, dasd_hosts_show, device); | ||
| 1200 | } | ||
| 1201 | |||
| 1202 | static const struct file_operations dasd_hosts_fops = { | ||
| 1203 | .owner = THIS_MODULE, | ||
| 1204 | .open = dasd_hosts_open, | ||
| 1205 | .read = seq_read, | ||
| 1206 | .llseek = seq_lseek, | ||
| 1207 | .release = single_release, | ||
| 1208 | }; | ||
| 1209 | 1196 | ||
| 1210 | static void dasd_hosts_exit(struct dasd_device *device) | 1197 | static void dasd_hosts_exit(struct dasd_device *device) |
| 1211 | { | 1198 | { |
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 5cb80c645489..1770b99f607e 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c | |||
| @@ -339,8 +339,7 @@ dasd_proc_init(void) | |||
| 339 | dasd_proc_root_entry = proc_mkdir("dasd", NULL); | 339 | dasd_proc_root_entry = proc_mkdir("dasd", NULL); |
| 340 | if (!dasd_proc_root_entry) | 340 | if (!dasd_proc_root_entry) |
| 341 | goto out_nodasd; | 341 | goto out_nodasd; |
| 342 | dasd_devices_entry = proc_create_seq("devices", | 342 | dasd_devices_entry = proc_create_seq("devices", 0444, |
| 343 | S_IFREG | S_IRUGO | S_IWUSR, | ||
| 344 | dasd_proc_root_entry, | 343 | dasd_proc_root_entry, |
| 345 | &dasd_devices_seq_ops); | 344 | &dasd_devices_seq_ops); |
| 346 | if (!dasd_devices_entry) | 345 | if (!dasd_devices_entry) |
diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c index 32a14ee31c6b..2238d9df6c47 100644 --- a/drivers/s390/char/tape_proc.c +++ b/drivers/s390/char/tape_proc.c | |||
| @@ -111,11 +111,8 @@ static const struct seq_operations tape_proc_seq = { | |||
| 111 | void | 111 | void |
| 112 | tape_proc_init(void) | 112 | tape_proc_init(void) |
| 113 | { | 113 | { |
| 114 | tape_proc_devices = proc_create_seq("tapedevices", | 114 | tape_proc_devices = proc_create_seq("tapedevices", 0444, NULL, |
| 115 | S_IFREG | S_IRUGO | S_IWUSR, NULL, &tape_proc_seq); | 115 | &tape_proc_seq); |
| 116 | if (tape_proc_devices == NULL) { | ||
| 117 | return; | ||
| 118 | } | ||
| 119 | } | 116 | } |
| 120 | 117 | ||
| 121 | /* | 118 | /* |
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index 68a82f3e2e92..d2f98e5829d4 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c | |||
| @@ -190,19 +190,7 @@ static int qstat_show(struct seq_file *m, void *v) | |||
| 190 | return 0; | 190 | return 0; |
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | static int qstat_seq_open(struct inode *inode, struct file *filp) | 193 | DEFINE_SHOW_ATTRIBUTE(qstat); |
| 194 | { | ||
| 195 | return single_open(filp, qstat_show, | ||
| 196 | file_inode(filp)->i_private); | ||
| 197 | } | ||
| 198 | |||
| 199 | static const struct file_operations debugfs_fops = { | ||
| 200 | .owner = THIS_MODULE, | ||
| 201 | .open = qstat_seq_open, | ||
| 202 | .read = seq_read, | ||
| 203 | .llseek = seq_lseek, | ||
| 204 | .release = single_release, | ||
| 205 | }; | ||
| 206 | 194 | ||
| 207 | static char *qperf_names[] = { | 195 | static char *qperf_names[] = { |
| 208 | "Assumed adapter interrupts", | 196 | "Assumed adapter interrupts", |
| @@ -305,8 +293,8 @@ static void setup_debugfs_entry(struct qdio_q *q) | |||
| 305 | snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d", | 293 | snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d", |
| 306 | q->is_input_q ? "input" : "output", | 294 | q->is_input_q ? "input" : "output", |
| 307 | q->nr); | 295 | q->nr); |
| 308 | q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR, | 296 | q->debugfs_q = debugfs_create_file(name, 0444, |
| 309 | q->irq_ptr->debugfs_dev, q, &debugfs_fops); | 297 | q->irq_ptr->debugfs_dev, q, &qstat_fops); |
| 310 | if (IS_ERR(q->debugfs_q)) | 298 | if (IS_ERR(q->debugfs_q)) |
| 311 | q->debugfs_q = NULL; | 299 | q->debugfs_q = NULL; |
| 312 | } | 300 | } |
diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c index f94aa01f9c36..cab17865aafe 100644 --- a/drivers/s390/cio/vfio_ccw_fsm.c +++ b/drivers/s390/cio/vfio_ccw_fsm.c | |||
| @@ -130,7 +130,7 @@ static void fsm_io_request(struct vfio_ccw_private *private, | |||
| 130 | struct mdev_device *mdev = private->mdev; | 130 | struct mdev_device *mdev = private->mdev; |
| 131 | char *errstr = "request"; | 131 | char *errstr = "request"; |
| 132 | 132 | ||
| 133 | private->state = VFIO_CCW_STATE_BOXED; | 133 | private->state = VFIO_CCW_STATE_BUSY; |
| 134 | 134 | ||
| 135 | memcpy(scsw, io_region->scsw_area, sizeof(*scsw)); | 135 | memcpy(scsw, io_region->scsw_area, sizeof(*scsw)); |
| 136 | 136 | ||
| @@ -216,11 +216,6 @@ fsm_func_t *vfio_ccw_jumptable[NR_VFIO_CCW_STATES][NR_VFIO_CCW_EVENTS] = { | |||
| 216 | [VFIO_CCW_EVENT_IO_REQ] = fsm_io_request, | 216 | [VFIO_CCW_EVENT_IO_REQ] = fsm_io_request, |
| 217 | [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq, | 217 | [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq, |
| 218 | }, | 218 | }, |
| 219 | [VFIO_CCW_STATE_BOXED] = { | ||
| 220 | [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper, | ||
| 221 | [VFIO_CCW_EVENT_IO_REQ] = fsm_io_busy, | ||
| 222 | [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq, | ||
| 223 | }, | ||
| 224 | [VFIO_CCW_STATE_BUSY] = { | 219 | [VFIO_CCW_STATE_BUSY] = { |
| 225 | [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper, | 220 | [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper, |
| 226 | [VFIO_CCW_EVENT_IO_REQ] = fsm_io_busy, | 221 | [VFIO_CCW_EVENT_IO_REQ] = fsm_io_busy, |
diff --git a/drivers/s390/cio/vfio_ccw_private.h b/drivers/s390/cio/vfio_ccw_private.h index 078e46f9623d..08e9a7dc9176 100644 --- a/drivers/s390/cio/vfio_ccw_private.h +++ b/drivers/s390/cio/vfio_ccw_private.h | |||
| @@ -63,7 +63,6 @@ enum vfio_ccw_state { | |||
| 63 | VFIO_CCW_STATE_NOT_OPER, | 63 | VFIO_CCW_STATE_NOT_OPER, |
| 64 | VFIO_CCW_STATE_STANDBY, | 64 | VFIO_CCW_STATE_STANDBY, |
| 65 | VFIO_CCW_STATE_IDLE, | 65 | VFIO_CCW_STATE_IDLE, |
| 66 | VFIO_CCW_STATE_BOXED, | ||
| 67 | VFIO_CCW_STATE_BUSY, | 66 | VFIO_CCW_STATE_BUSY, |
| 68 | /* last element! */ | 67 | /* last element! */ |
| 69 | NR_VFIO_CCW_STATES | 68 | NR_VFIO_CCW_STATES |
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, | |||
| 299 | ap_max_domain_id = 15; | 299 | ap_max_domain_id = 15; |
| 300 | switch (*device_type) { | 300 | switch (*device_type) { |
| 301 | /* For CEX2 and CEX3 the available functions | 301 | /* For CEX2 and CEX3 the available functions |
| 302 | * are not refrected by the facilities bits. | 302 | * are not reflected by the facilities bits. |
| 303 | * Instead it is coded into the type. So here | 303 | * Instead it is coded into the type. So here |
| 304 | * modify the function bits based on the type. | 304 | * modify the function bits based on the type. |
| 305 | */ | 305 | */ |
| @@ -1317,7 +1317,7 @@ static int ap_get_compatible_type(ap_qid_t qid, int rawtype, unsigned int func) | |||
| 1317 | } | 1317 | } |
| 1318 | 1318 | ||
| 1319 | /* | 1319 | /* |
| 1320 | * helper function to be used with bus_find_dev | 1320 | * Helper function to be used with bus_find_dev |
| 1321 | * matches for the card device with the given id | 1321 | * matches for the card device with the given id |
| 1322 | */ | 1322 | */ |
| 1323 | static int __match_card_device_with_id(struct device *dev, void *data) | 1323 | 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) | |||
| 1325 | return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long) data; | 1325 | return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long) data; |
| 1326 | } | 1326 | } |
| 1327 | 1327 | ||
| 1328 | /* helper function to be used with bus_find_dev | 1328 | /* |
| 1329 | * Helper function to be used with bus_find_dev | ||
| 1329 | * matches for the queue device with a given qid | 1330 | * matches for the queue device with a given qid |
| 1330 | */ | 1331 | */ |
| 1331 | static int __match_queue_device_with_qid(struct device *dev, void *data) | 1332 | 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) | |||
| 1333 | return is_queue_dev(dev) && to_ap_queue(dev)->qid == (int)(long) data; | 1334 | return is_queue_dev(dev) && to_ap_queue(dev)->qid == (int)(long) data; |
| 1334 | } | 1335 | } |
| 1335 | 1336 | ||
| 1336 | /** | 1337 | /* |
| 1337 | * ap_scan_bus(): Scan the AP bus for new devices | 1338 | * Helper function for ap_scan_bus(). |
| 1338 | * Runs periodically, workqueue timer (ap_config_time) | 1339 | * Does the scan bus job for the given adapter id. |
| 1339 | */ | 1340 | */ |
| 1340 | static void ap_scan_bus(struct work_struct *unused) | 1341 | static void _ap_scan_bus_adapter(int id) |
| 1341 | { | 1342 | { |
| 1342 | struct ap_queue *aq; | 1343 | ap_qid_t qid; |
| 1344 | unsigned int func; | ||
| 1343 | struct ap_card *ac; | 1345 | struct ap_card *ac; |
| 1344 | struct device *dev; | 1346 | struct device *dev; |
| 1345 | ap_qid_t qid; | 1347 | struct ap_queue *aq; |
| 1346 | int comp_type, depth = 0, type = 0; | 1348 | int rc, dom, depth, type, comp_type, borked; |
| 1347 | unsigned int func = 0; | 1349 | |
| 1348 | int rc, id, dom, borked, domains, defdomdevs = 0; | 1350 | /* check if there is a card device registered with this id */ |
| 1349 | 1351 | dev = bus_find_device(&ap_bus_type, NULL, | |
| 1350 | AP_DBF(DBF_DEBUG, "%s running\n", __func__); | 1352 | (void *)(long) id, |
| 1353 | __match_card_device_with_id); | ||
| 1354 | ac = dev ? to_ap_card(dev) : NULL; | ||
| 1355 | if (!ap_test_config_card_id(id)) { | ||
| 1356 | if (dev) { | ||
| 1357 | /* Card device has been removed from configuration */ | ||
| 1358 | bus_for_each_dev(&ap_bus_type, NULL, | ||
| 1359 | (void *)(long) id, | ||
| 1360 | __ap_queue_devices_with_id_unregister); | ||
| 1361 | device_unregister(dev); | ||
| 1362 | put_device(dev); | ||
| 1363 | } | ||
| 1364 | return; | ||
| 1365 | } | ||
| 1351 | 1366 | ||
| 1352 | ap_query_configuration(ap_configuration); | 1367 | /* |
| 1353 | ap_select_domain(); | 1368 | * This card id is enabled in the configuration. If we already have |
| 1369 | * a card device with this id, check if type and functions are still | ||
| 1370 | * the very same. Also verify that at least one queue is available. | ||
| 1371 | */ | ||
| 1372 | if (ac) { | ||
| 1373 | /* find the first valid queue */ | ||
| 1374 | for (dom = 0; dom < AP_DOMAINS; dom++) { | ||
| 1375 | qid = AP_MKQID(id, dom); | ||
| 1376 | if (ap_query_queue(qid, &depth, &type, &func) == 0) | ||
| 1377 | break; | ||
| 1378 | } | ||
| 1379 | borked = 0; | ||
| 1380 | if (dom >= AP_DOMAINS) { | ||
| 1381 | /* no accessible queue on this card */ | ||
| 1382 | borked = 1; | ||
| 1383 | } else if (ac->raw_hwtype != type) { | ||
| 1384 | /* card type has changed */ | ||
| 1385 | AP_DBF(DBF_INFO, "card=%02x type changed.\n", id); | ||
| 1386 | borked = 1; | ||
| 1387 | } else if (ac->functions != func) { | ||
| 1388 | /* card functions have changed */ | ||
| 1389 | AP_DBF(DBF_INFO, "card=%02x functions changed.\n", id); | ||
| 1390 | borked = 1; | ||
| 1391 | } | ||
| 1392 | if (borked) { | ||
| 1393 | /* unregister card device and associated queues */ | ||
| 1394 | bus_for_each_dev(&ap_bus_type, NULL, | ||
| 1395 | (void *)(long) id, | ||
| 1396 | __ap_queue_devices_with_id_unregister); | ||
| 1397 | device_unregister(dev); | ||
| 1398 | put_device(dev); | ||
| 1399 | /* go back if there is no valid queue on this card */ | ||
| 1400 | if (dom >= AP_DOMAINS) | ||
| 1401 | return; | ||
| 1402 | ac = NULL; | ||
| 1403 | } | ||
| 1404 | } | ||
| 1354 | 1405 | ||
| 1355 | for (id = 0; id < AP_DEVICES; id++) { | 1406 | /* |
| 1356 | /* check if device is registered */ | 1407 | * Go through all possible queue ids. Check and maybe create or release |
| 1408 | * queue devices for this card. If there exists no card device yet, | ||
| 1409 | * create a card device also. | ||
| 1410 | */ | ||
| 1411 | for (dom = 0; dom < AP_DOMAINS; dom++) { | ||
| 1412 | qid = AP_MKQID(id, dom); | ||
| 1357 | dev = bus_find_device(&ap_bus_type, NULL, | 1413 | dev = bus_find_device(&ap_bus_type, NULL, |
| 1358 | (void *)(long) id, | 1414 | (void *)(long) qid, |
| 1359 | __match_card_device_with_id); | 1415 | __match_queue_device_with_qid); |
| 1360 | ac = dev ? to_ap_card(dev) : NULL; | 1416 | aq = dev ? to_ap_queue(dev) : NULL; |
| 1361 | if (!ap_test_config_card_id(id)) { | 1417 | if (!ap_test_config_domain(dom)) { |
| 1362 | if (dev) { | 1418 | if (dev) { |
| 1363 | /* Card device has been removed from | 1419 | /* Queue device exists but has been |
| 1364 | * configuration, remove the belonging | 1420 | * removed from configuration. |
| 1365 | * queue devices. | ||
| 1366 | */ | 1421 | */ |
| 1367 | bus_for_each_dev(&ap_bus_type, NULL, | ||
| 1368 | (void *)(long) id, | ||
| 1369 | __ap_queue_devices_with_id_unregister); | ||
| 1370 | /* now remove the card device */ | ||
| 1371 | device_unregister(dev); | 1422 | device_unregister(dev); |
| 1372 | put_device(dev); | 1423 | put_device(dev); |
| 1373 | } | 1424 | } |
| 1374 | continue; | 1425 | continue; |
| 1375 | } | 1426 | } |
| 1376 | /* According to the configuration there should be a card | 1427 | /* try to fetch infos about this queue */ |
| 1377 | * device, so check if there is at least one valid queue | 1428 | rc = ap_query_queue(qid, &depth, &type, &func); |
| 1378 | * and maybe create queue devices and the card device. | 1429 | if (dev) { |
| 1379 | */ | 1430 | if (rc == -ENODEV) |
| 1380 | domains = 0; | 1431 | borked = 1; |
| 1381 | for (dom = 0; dom < AP_DOMAINS; dom++) { | 1432 | else { |
| 1382 | qid = AP_MKQID(id, dom); | ||
| 1383 | dev = bus_find_device(&ap_bus_type, NULL, | ||
| 1384 | (void *)(long) qid, | ||
| 1385 | __match_queue_device_with_qid); | ||
| 1386 | aq = dev ? to_ap_queue(dev) : NULL; | ||
| 1387 | if (!ap_test_config_domain(dom)) { | ||
| 1388 | if (dev) { | ||
| 1389 | /* Queue device exists but has been | ||
| 1390 | * removed from configuration. | ||
| 1391 | */ | ||
| 1392 | device_unregister(dev); | ||
| 1393 | put_device(dev); | ||
| 1394 | } | ||
| 1395 | continue; | ||
| 1396 | } | ||
| 1397 | rc = ap_query_queue(qid, &depth, &type, &func); | ||
| 1398 | if (dev) { | ||
| 1399 | spin_lock_bh(&aq->lock); | 1433 | spin_lock_bh(&aq->lock); |
| 1400 | if (rc == -ENODEV || | ||
| 1401 | /* adapter reconfiguration */ | ||
| 1402 | (ac && ac->functions != func)) | ||
| 1403 | aq->state = AP_STATE_BORKED; | ||
| 1404 | borked = aq->state == AP_STATE_BORKED; | 1434 | borked = aq->state == AP_STATE_BORKED; |
| 1405 | spin_unlock_bh(&aq->lock); | 1435 | spin_unlock_bh(&aq->lock); |
| 1406 | if (borked) /* Remove broken device */ | ||
| 1407 | device_unregister(dev); | ||
| 1408 | put_device(dev); | ||
| 1409 | if (!borked) { | ||
| 1410 | domains++; | ||
| 1411 | if (dom == ap_domain_index) | ||
| 1412 | defdomdevs++; | ||
| 1413 | continue; | ||
| 1414 | } | ||
| 1415 | } | ||
| 1416 | if (rc) | ||
| 1417 | continue; | ||
| 1418 | /* a new queue device is needed, check out comp type */ | ||
| 1419 | comp_type = ap_get_compatible_type(qid, type, func); | ||
| 1420 | if (!comp_type) | ||
| 1421 | continue; | ||
| 1422 | /* maybe a card device needs to be created first */ | ||
| 1423 | if (!ac) { | ||
| 1424 | ac = ap_card_create(id, depth, type, | ||
| 1425 | comp_type, func); | ||
| 1426 | if (!ac) | ||
| 1427 | continue; | ||
| 1428 | ac->ap_dev.device.bus = &ap_bus_type; | ||
| 1429 | ac->ap_dev.device.parent = ap_root_device; | ||
| 1430 | dev_set_name(&ac->ap_dev.device, | ||
| 1431 | "card%02x", id); | ||
| 1432 | /* Register card with AP bus */ | ||
| 1433 | rc = device_register(&ac->ap_dev.device); | ||
| 1434 | if (rc) { | ||
| 1435 | put_device(&ac->ap_dev.device); | ||
| 1436 | ac = NULL; | ||
| 1437 | break; | ||
| 1438 | } | ||
| 1439 | /* get it and thus adjust reference counter */ | ||
| 1440 | get_device(&ac->ap_dev.device); | ||
| 1441 | } | 1436 | } |
| 1442 | /* now create the new queue device */ | 1437 | if (borked) /* Remove broken device */ |
| 1443 | aq = ap_queue_create(qid, comp_type); | 1438 | device_unregister(dev); |
| 1444 | if (!aq) | 1439 | put_device(dev); |
| 1440 | continue; | ||
| 1441 | } | ||
| 1442 | if (rc) | ||
| 1443 | continue; | ||
| 1444 | /* a new queue device is needed, check out comp type */ | ||
| 1445 | comp_type = ap_get_compatible_type(qid, type, func); | ||
| 1446 | if (!comp_type) | ||
| 1447 | continue; | ||
| 1448 | /* maybe a card device needs to be created first */ | ||
| 1449 | if (!ac) { | ||
| 1450 | ac = ap_card_create(id, depth, type, comp_type, func); | ||
| 1451 | if (!ac) | ||
| 1445 | continue; | 1452 | continue; |
| 1446 | aq->card = ac; | 1453 | ac->ap_dev.device.bus = &ap_bus_type; |
| 1447 | aq->ap_dev.device.bus = &ap_bus_type; | 1454 | ac->ap_dev.device.parent = ap_root_device; |
| 1448 | aq->ap_dev.device.parent = &ac->ap_dev.device; | 1455 | dev_set_name(&ac->ap_dev.device, "card%02x", id); |
| 1449 | dev_set_name(&aq->ap_dev.device, | 1456 | /* Register card device with AP bus */ |
| 1450 | "%02x.%04x", id, dom); | 1457 | rc = device_register(&ac->ap_dev.device); |
| 1451 | /* Register device */ | ||
| 1452 | rc = device_register(&aq->ap_dev.device); | ||
| 1453 | if (rc) { | 1458 | if (rc) { |
| 1454 | put_device(&aq->ap_dev.device); | 1459 | put_device(&ac->ap_dev.device); |
| 1455 | continue; | 1460 | ac = NULL; |
| 1461 | break; | ||
| 1456 | } | 1462 | } |
| 1457 | domains++; | 1463 | /* get it and thus adjust reference counter */ |
| 1458 | if (dom == ap_domain_index) | 1464 | get_device(&ac->ap_dev.device); |
| 1459 | defdomdevs++; | 1465 | } |
| 1460 | } /* end domain loop */ | 1466 | /* now create the new queue device */ |
| 1461 | if (ac) { | 1467 | aq = ap_queue_create(qid, comp_type); |
| 1462 | /* remove card dev if there are no queue devices */ | 1468 | if (!aq) |
| 1463 | if (!domains) | 1469 | continue; |
| 1464 | device_unregister(&ac->ap_dev.device); | 1470 | aq->card = ac; |
| 1465 | put_device(&ac->ap_dev.device); | 1471 | aq->ap_dev.device.bus = &ap_bus_type; |
| 1472 | aq->ap_dev.device.parent = &ac->ap_dev.device; | ||
| 1473 | dev_set_name(&aq->ap_dev.device, "%02x.%04x", id, dom); | ||
| 1474 | /* Register queue device */ | ||
| 1475 | rc = device_register(&aq->ap_dev.device); | ||
| 1476 | if (rc) { | ||
| 1477 | put_device(&aq->ap_dev.device); | ||
| 1478 | continue; | ||
| 1466 | } | 1479 | } |
| 1467 | } /* end device loop */ | 1480 | } /* end domain loop */ |
| 1481 | |||
| 1482 | if (ac) | ||
| 1483 | put_device(&ac->ap_dev.device); | ||
| 1484 | } | ||
| 1468 | 1485 | ||
| 1469 | if (ap_domain_index >= 0 && defdomdevs < 1) | 1486 | /** |
| 1470 | AP_DBF(DBF_INFO, | 1487 | * ap_scan_bus(): Scan the AP bus for new devices |
| 1471 | "no queue device with default domain %d available\n", | 1488 | * Runs periodically, workqueue timer (ap_config_time) |
| 1472 | ap_domain_index); | 1489 | */ |
| 1490 | static void ap_scan_bus(struct work_struct *unused) | ||
| 1491 | { | ||
| 1492 | int id; | ||
| 1493 | |||
| 1494 | AP_DBF(DBF_DEBUG, "%s running\n", __func__); | ||
| 1495 | |||
| 1496 | ap_query_configuration(ap_configuration); | ||
| 1497 | ap_select_domain(); | ||
| 1498 | |||
| 1499 | /* loop over all possible adapters */ | ||
| 1500 | for (id = 0; id < AP_DEVICES; id++) | ||
| 1501 | _ap_scan_bus_adapter(id); | ||
| 1502 | |||
| 1503 | /* check if there is at least one queue available with default domain */ | ||
| 1504 | if (ap_domain_index >= 0) { | ||
| 1505 | struct device *dev = | ||
| 1506 | bus_find_device(&ap_bus_type, NULL, | ||
| 1507 | (void *)(long) ap_domain_index, | ||
| 1508 | __match_queue_device_with_qid); | ||
| 1509 | if (dev) | ||
| 1510 | put_device(dev); | ||
| 1511 | else | ||
| 1512 | AP_DBF(DBF_INFO, | ||
| 1513 | "no queue device with default domain %d available\n", | ||
| 1514 | ap_domain_index); | ||
| 1515 | } | ||
| 1473 | 1516 | ||
| 1474 | mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ); | 1517 | mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ); |
| 1475 | } | 1518 | } |
diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index 0aa4b3ccc948..576ac08777c5 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c | |||
| @@ -14,6 +14,9 @@ | |||
| 14 | #include <asm/facility.h> | 14 | #include <asm/facility.h> |
| 15 | 15 | ||
| 16 | #include "ap_bus.h" | 16 | #include "ap_bus.h" |
| 17 | #include "ap_debug.h" | ||
| 18 | |||
| 19 | static void __ap_flush_queue(struct ap_queue *aq); | ||
| 17 | 20 | ||
| 18 | /** | 21 | /** |
| 19 | * ap_queue_enable_interruption(): Enable interruption on an AP queue. | 22 | * ap_queue_enable_interruption(): Enable interruption on an AP queue. |
| @@ -541,7 +544,25 @@ static ssize_t reset_show(struct device *dev, | |||
| 541 | return rc; | 544 | return rc; |
| 542 | } | 545 | } |
| 543 | 546 | ||
| 544 | static DEVICE_ATTR_RO(reset); | 547 | static ssize_t reset_store(struct device *dev, |
| 548 | struct device_attribute *attr, | ||
| 549 | const char *buf, size_t count) | ||
| 550 | { | ||
| 551 | struct ap_queue *aq = to_ap_queue(dev); | ||
| 552 | |||
| 553 | spin_lock_bh(&aq->lock); | ||
| 554 | __ap_flush_queue(aq); | ||
| 555 | aq->state = AP_STATE_RESET_START; | ||
| 556 | ap_wait(ap_sm_event(aq, AP_EVENT_POLL)); | ||
| 557 | spin_unlock_bh(&aq->lock); | ||
| 558 | |||
| 559 | AP_DBF(DBF_INFO, "reset queue=%02x.%04x triggered by user\n", | ||
| 560 | AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); | ||
| 561 | |||
| 562 | return count; | ||
| 563 | } | ||
| 564 | |||
| 565 | static DEVICE_ATTR_RW(reset); | ||
| 545 | 566 | ||
| 546 | static ssize_t interrupt_show(struct device *dev, | 567 | static ssize_t interrupt_show(struct device *dev, |
| 547 | struct device_attribute *attr, char *buf) | 568 | struct device_attribute *attr, char *buf) |
diff --git a/drivers/s390/crypto/vfio_ap_drv.c b/drivers/s390/crypto/vfio_ap_drv.c index 7667b38728f0..31c6c847eaca 100644 --- a/drivers/s390/crypto/vfio_ap_drv.c +++ b/drivers/s390/crypto/vfio_ap_drv.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include <linux/mod_devicetable.h> | 11 | #include <linux/mod_devicetable.h> |
| 12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
| 13 | #include <linux/string.h> | 13 | #include <linux/string.h> |
| 14 | #include <asm/facility.h> | ||
| 14 | #include "vfio_ap_private.h" | 15 | #include "vfio_ap_private.h" |
| 15 | 16 | ||
| 16 | #define VFIO_AP_ROOT_NAME "vfio_ap" | 17 | #define VFIO_AP_ROOT_NAME "vfio_ap" |
diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h index 240b27f3f5f6..f34ee41cbed8 100644 --- a/drivers/s390/crypto/zcrypt_error.h +++ b/drivers/s390/crypto/zcrypt_error.h | |||
| @@ -51,6 +51,7 @@ struct error_hdr { | |||
| 51 | #define REP82_ERROR_FORMAT_FIELD 0x29 | 51 | #define REP82_ERROR_FORMAT_FIELD 0x29 |
| 52 | #define REP82_ERROR_INVALID_COMMAND 0x30 | 52 | #define REP82_ERROR_INVALID_COMMAND 0x30 |
| 53 | #define REP82_ERROR_MALFORMED_MSG 0x40 | 53 | #define REP82_ERROR_MALFORMED_MSG 0x40 |
| 54 | #define REP82_ERROR_INVALID_SPECIAL_CMD 0x41 | ||
| 54 | #define REP82_ERROR_INVALID_DOMAIN_PRECHECK 0x42 | 55 | #define REP82_ERROR_INVALID_DOMAIN_PRECHECK 0x42 |
| 55 | #define REP82_ERROR_RESERVED_FIELDO 0x50 /* old value */ | 56 | #define REP82_ERROR_RESERVED_FIELDO 0x50 /* old value */ |
| 56 | #define REP82_ERROR_WORD_ALIGNMENT 0x60 | 57 | #define REP82_ERROR_WORD_ALIGNMENT 0x60 |
| @@ -89,6 +90,7 @@ static inline int convert_error(struct zcrypt_queue *zq, | |||
| 89 | case REP88_ERROR_MESSAGE_MALFORMD: | 90 | case REP88_ERROR_MESSAGE_MALFORMD: |
| 90 | case REP82_ERROR_INVALID_DOMAIN_PRECHECK: | 91 | case REP82_ERROR_INVALID_DOMAIN_PRECHECK: |
| 91 | case REP82_ERROR_INVALID_DOMAIN_PENDING: | 92 | case REP82_ERROR_INVALID_DOMAIN_PENDING: |
| 93 | case REP82_ERROR_INVALID_SPECIAL_CMD: | ||
| 92 | // REP88_ERROR_INVALID_KEY // '82' CEX2A | 94 | // REP88_ERROR_INVALID_KEY // '82' CEX2A |
| 93 | // REP88_ERROR_OPERAND // '84' CEX2A | 95 | // REP88_ERROR_OPERAND // '84' CEX2A |
| 94 | // REP88_ERROR_OPERAND_EVEN_MOD // '85' CEX2A | 96 | // REP88_ERROR_OPERAND_EVEN_MOD // '85' CEX2A |
diff --git a/lib/bust_spinlocks.c b/lib/bust_spinlocks.c index ab719495e2cb..8be59f84eaea 100644 --- a/lib/bust_spinlocks.c +++ b/lib/bust_spinlocks.c | |||
| @@ -2,7 +2,8 @@ | |||
| 2 | /* | 2 | /* |
| 3 | * lib/bust_spinlocks.c | 3 | * lib/bust_spinlocks.c |
| 4 | * | 4 | * |
| 5 | * Provides a minimal bust_spinlocks for architectures which don't have one of their own. | 5 | * Provides a minimal bust_spinlocks for architectures which don't |
| 6 | * have one of their own. | ||
| 6 | * | 7 | * |
| 7 | * bust_spinlocks() clears any spinlocks which would prevent oops, die(), BUG() | 8 | * bust_spinlocks() clears any spinlocks which would prevent oops, die(), BUG() |
| 8 | * and panic() information from reaching the user. | 9 | * and panic() information from reaching the user. |
| @@ -16,8 +17,7 @@ | |||
| 16 | #include <linux/vt_kern.h> | 17 | #include <linux/vt_kern.h> |
| 17 | #include <linux/console.h> | 18 | #include <linux/console.h> |
| 18 | 19 | ||
| 19 | 20 | void bust_spinlocks(int yes) | |
| 20 | void __attribute__((weak)) bust_spinlocks(int yes) | ||
| 21 | { | 21 | { |
| 22 | if (yes) { | 22 | if (yes) { |
| 23 | ++oops_in_progress; | 23 | ++oops_in_progress; |
