goto out;
}
- if (pbdev) {
- if (pbdev->configured) {
- rc = SCLP_RC_NO_ACTION_REQUIRED;
- } else {
- pbdev->configured = true;
- rc = SCLP_RC_NORMAL_COMPLETION;
- }
- } else {
+ if (!pbdev) {
DPRINTF("sclp config no dev found\n");
rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED;
+ goto out;
+ }
+
+ switch (pbdev->state) {
+ case ZPCI_FS_RESERVED:
+ rc = SCLP_RC_ADAPTER_IN_RESERVED_STATE;
+ break;
+ case ZPCI_FS_STANDBY:
+ pbdev->state = ZPCI_FS_DISABLED;
+ rc = SCLP_RC_NORMAL_COMPLETION;
+ break;
+ default:
+ rc = SCLP_RC_NO_ACTION_REQUIRED;
}
out:
psccb->header.response_code = cpu_to_be16(rc);
goto out;
}
- if (pbdev) {
- if (!pbdev->configured) {
- rc = SCLP_RC_NO_ACTION_REQUIRED;
- } else {
- if (pbdev->summary_ind) {
- pci_dereg_irqs(pbdev);
- }
- if (pbdev->iommu_enabled) {
- pci_dereg_ioat(pbdev);
- }
- pbdev->configured = false;
- rc = SCLP_RC_NORMAL_COMPLETION;
- }
- } else {
+ if (!pbdev) {
DPRINTF("sclp deconfig no dev found\n");
rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED;
+ goto out;
+ }
+
+ switch (pbdev->state) {
+ case ZPCI_FS_RESERVED:
+ rc = SCLP_RC_ADAPTER_IN_RESERVED_STATE;
+ break;
+ case ZPCI_FS_STANDBY:
+ rc = SCLP_RC_NO_ACTION_REQUIRED;
+ break;
+ default:
+ if (pbdev->summary_ind) {
+ pci_dereg_irqs(pbdev);
+ }
+ if (pbdev->iommu_enabled) {
+ pci_dereg_ioat(pbdev);
+ }
+ pbdev->state = ZPCI_FS_STANDBY;
+ rc = SCLP_RC_NORMAL_COMPLETION;
}
out:
psccb->header.response_code = cpu_to_be16(rc);
for (i = 0; i < PCI_SLOT_MAX; i++) {
pbdev = &s->pbdev[i];
- if (pbdev->fh == 0) {
+ if (pbdev->state == ZPCI_FS_RESERVED) {
continue;
}
s390_pci_generate_event(2, pec, fh, fid, 0, 0);
}
-static void s390_pci_generate_error_event(uint16_t pec, uint32_t fh,
- uint32_t fid, uint64_t faddr,
- uint32_t e)
+void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, uint32_t fid,
+ uint64_t faddr, uint32_t e)
{
s390_pci_generate_event(1, pec, fh, fid, faddr, e);
}
.perm = IOMMU_NONE,
};
- if (!pbdev->configured || !pbdev->pdev ||
- !(pbdev->fh & FH_MASK_ENABLE) || !pbdev->iommu_enabled) {
+ switch (pbdev->state) {
+ case ZPCI_FS_ENABLED:
+ case ZPCI_FS_BLOCKED:
+ if (!pbdev->iommu_enabled) {
+ return ret;
+ }
+ break;
+ default:
return ret;
}
return ret;
}
- if (!pbdev->g_iota) {
- pbdev->error_state = true;
- pbdev->lgstg_blocked = true;
- s390_pci_generate_error_event(ERR_EVENT_INVALAS, pbdev->fh, pbdev->fid,
- addr, 0);
- return ret;
- }
-
if (addr < pbdev->pba || addr > pbdev->pal) {
- pbdev->error_state = true;
- pbdev->lgstg_blocked = true;
- s390_pci_generate_error_event(ERR_EVENT_OORANGE, pbdev->fh, pbdev->fid,
- addr, 0);
return ret;
}
pte = s390_guest_io_table_walk(s390_pci_get_table_origin(pbdev->g_iota),
addr);
-
if (!pte) {
- pbdev->error_state = true;
- pbdev->lgstg_blocked = true;
- s390_pci_generate_error_event(ERR_EVENT_SERR, pbdev->fh, pbdev->fid,
- addr, ERR_EVENT_Q_BIT);
return ret;
}
return;
}
- if (!(pbdev->fh & FH_MASK_ENABLE)) {
+ if (pbdev->state != ZPCI_FS_ENABLED) {
return;
}
pbdev->fid = s390_pci_get_pfid(pci_dev);
pbdev->pdev = pci_dev;
- pbdev->configured = true;
+ pbdev->state = ZPCI_FS_DISABLED;
pbdev->fh = s390_pci_get_pfh(pci_dev);
s390_pcihost_setup_msix(pbdev);
->qbus.parent);
S390PCIBusDevice *pbdev = &s->pbdev[PCI_SLOT(pci_dev->devfn)];
- if (pbdev->configured) {
- pbdev->configured = false;
+ switch (pbdev->state) {
+ case ZPCI_FS_RESERVED:
+ goto out;
+ case ZPCI_FS_STANDBY:
+ break;
+ default:
s390_pci_generate_plug_event(HP_EVENT_CONFIGURED_TO_STBRES,
pbdev->fh, pbdev->fid);
}
pbdev->fh = 0;
pbdev->fid = 0;
pbdev->pdev = NULL;
+ pbdev->state = ZPCI_FS_RESERVED;
+out:
object_unparent(OBJECT(pci_dev));
}
pci_get_word(pbdev->pdev->config + PCI_DEVICE_ID));
stw_p(&rrb->response.fh_list[idx - resume_token].vendor_id,
pci_get_word(pbdev->pdev->config + PCI_VENDOR_ID));
+ /* Ignore RESERVED devices. */
stl_p(&rrb->response.fh_list[idx - resume_token].config,
- pbdev->configured << 31);
+ pbdev->state == ZPCI_FS_STANDBY ? 0 : 1 << 31);
stl_p(&rrb->response.fh_list[idx - resume_token].fid, pbdev->fid);
stl_p(&rrb->response.fh_list[idx - resume_token].fh, pbdev->fh);
switch (reqsetpci->oc) {
case CLP_SET_ENABLE_PCI_FN:
pbdev->fh |= FH_MASK_ENABLE;
+ pbdev->state = ZPCI_FS_ENABLED;
stl_p(&ressetpci->fh, pbdev->fh);
stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
break;
case CLP_SET_DISABLE_PCI_FN:
pbdev->fh &= ~FH_MASK_ENABLE;
- pbdev->error_state = false;
- pbdev->lgstg_blocked = false;
+ pbdev->state = ZPCI_FS_DISABLED;
stl_p(&ressetpci->fh, pbdev->fh);
stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
break;
offset = env->regs[r2 + 1];
pbdev = s390_pci_find_dev_by_fh(fh);
- if (!pbdev || !(pbdev->fh & FH_MASK_ENABLE)) {
+ if (!pbdev) {
DPRINTF("pcilg no pci dev\n");
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
return 0;
}
- if (pbdev->lgstg_blocked) {
+ switch (pbdev->state) {
+ case ZPCI_FS_RESERVED:
+ case ZPCI_FS_STANDBY:
+ case ZPCI_FS_DISABLED:
+ case ZPCI_FS_PERMANENT_ERROR:
+ setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
+ return 0;
+ case ZPCI_FS_ERROR:
setcc(cpu, ZPCI_PCI_LS_ERR);
s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED);
return 0;
+ default:
+ break;
}
if (pcias < 6) {
offset = env->regs[r2 + 1];
pbdev = s390_pci_find_dev_by_fh(fh);
- if (!pbdev || !(pbdev->fh & FH_MASK_ENABLE)) {
+ if (!pbdev) {
DPRINTF("pcistg no pci dev\n");
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
return 0;
}
- if (pbdev->lgstg_blocked) {
+ switch (pbdev->state) {
+ case ZPCI_FS_RESERVED:
+ case ZPCI_FS_STANDBY:
+ case ZPCI_FS_DISABLED:
+ case ZPCI_FS_PERMANENT_ERROR:
+ setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
+ return 0;
+ case ZPCI_FS_ERROR:
setcc(cpu, ZPCI_PCI_LS_ERR);
s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED);
return 0;
+ default:
+ break;
}
data = env->regs[r1];
end = start + env->regs[r2 + 1];
pbdev = s390_pci_find_dev_by_fh(fh);
- if (!pbdev || !(pbdev->fh & FH_MASK_ENABLE)) {
+ if (!pbdev) {
DPRINTF("rpcit no pci dev\n");
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
goto out;
}
+ switch (pbdev->state) {
+ case ZPCI_FS_RESERVED:
+ case ZPCI_FS_STANDBY:
+ case ZPCI_FS_DISABLED:
+ case ZPCI_FS_PERMANENT_ERROR:
+ setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
+ return 0;
+ case ZPCI_FS_ERROR:
+ setcc(cpu, ZPCI_PCI_LS_ERR);
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_ERROR_RECOVER);
+ return 0;
+ default:
+ break;
+ }
+
+ if (!pbdev->g_iota) {
+ pbdev->state = ZPCI_FS_ERROR;
+ setcc(cpu, ZPCI_PCI_LS_ERR);
+ s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES);
+ s390_pci_generate_error_event(ERR_EVENT_INVALAS, pbdev->fh, pbdev->fid,
+ start, 0);
+ goto out;
+ }
+
+ if (end < pbdev->pba || start > pbdev->pal) {
+ pbdev->state = ZPCI_FS_ERROR;
+ setcc(cpu, ZPCI_PCI_LS_ERR);
+ s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES);
+ s390_pci_generate_error_event(ERR_EVENT_OORANGE, pbdev->fh, pbdev->fid,
+ start, 0);
+ goto out;
+ }
+
mr = &pbdev->iommu_mr;
while (start < end) {
entry = mr->iommu_ops->translate(mr, start, 0);
if (!entry.translated_addr) {
+ pbdev->state = ZPCI_FS_ERROR;
setcc(cpu, ZPCI_PCI_LS_ERR);
+ s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES);
+ s390_pci_generate_error_event(ERR_EVENT_SERR, pbdev->fh, pbdev->fid,
+ start, ERR_EVENT_Q_BIT);
goto out;
}
}
pbdev = s390_pci_find_dev_by_fh(fh);
- if (!pbdev || !(pbdev->fh & FH_MASK_ENABLE)) {
+ if (!pbdev) {
DPRINTF("pcistb no pci dev fh 0x%x\n", fh);
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
return 0;
}
- if (pbdev->lgstg_blocked) {
+ switch (pbdev->state) {
+ case ZPCI_FS_RESERVED:
+ case ZPCI_FS_STANDBY:
+ case ZPCI_FS_DISABLED:
+ case ZPCI_FS_PERMANENT_ERROR:
+ setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
+ return 0;
+ case ZPCI_FS_ERROR:
setcc(cpu, ZPCI_PCI_LS_ERR);
s390_set_status_code(env, r1, ZPCI_PCI_ST_BLOCKED);
return 0;
+ default:
+ break;
}
mr = pbdev->pdev->io_regions[pcias].memory;
}
pbdev = s390_pci_find_dev_by_fh(fh);
- if (!pbdev || !(pbdev->fh & FH_MASK_ENABLE)) {
+ if (!pbdev) {
DPRINTF("mpcifc no pci dev fh 0x%x\n", fh);
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
return 0;
}
+ switch (pbdev->state) {
+ case ZPCI_FS_RESERVED:
+ case ZPCI_FS_STANDBY:
+ case ZPCI_FS_DISABLED:
+ case ZPCI_FS_PERMANENT_ERROR:
+ setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
+ return 0;
+ default:
+ break;
+ }
+
if (s390_cpu_virt_mem_read(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) {
return 0;
}
}
break;
case ZPCI_MOD_FC_RESET_ERROR:
- pbdev->error_state = false;
- pbdev->lgstg_blocked = false;
+ switch (pbdev->state) {
+ case ZPCI_FS_BLOCKED:
+ case ZPCI_FS_ERROR:
+ pbdev->state = ZPCI_FS_ENABLED;
+ break;
+ default:
+ cc = ZPCI_PCI_LS_ERR;
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
+ }
break;
case ZPCI_MOD_FC_RESET_BLOCK:
- pbdev->lgstg_blocked = false;
+ switch (pbdev->state) {
+ case ZPCI_FS_ERROR:
+ pbdev->state = ZPCI_FS_BLOCKED;
+ break;
+ default:
+ cc = ZPCI_PCI_LS_ERR;
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
+ }
break;
case ZPCI_MOD_FC_SET_MEASURE:
pbdev->fmb_addr = ldq_p(&fib.fmb_addr);
}
memset(&fib, 0, sizeof(fib));
+
+ switch (pbdev->state) {
+ case ZPCI_FS_RESERVED:
+ case ZPCI_FS_STANDBY:
+ setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
+ return 0;
+ case ZPCI_FS_DISABLED:
+ if (fh & FH_MASK_ENABLE) {
+ setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
+ return 0;
+ }
+ goto out;
+ /* BLOCKED bit is set to one coincident with the setting of ERROR bit.
+ * FH Enabled bit is set to one in states of ENABLED, BLOCKED or ERROR. */
+ case ZPCI_FS_ERROR:
+ fib.fc |= 0x20;
+ case ZPCI_FS_BLOCKED:
+ fib.fc |= 0x40;
+ case ZPCI_FS_ENABLED:
+ fib.fc |= 0x80;
+ if (pbdev->iommu_enabled) {
+ fib.fc |= 0x10;
+ }
+ if (!(fh & FH_MASK_ENABLE)) {
+ env->regs[r1] |= 1ULL << 63;
+ }
+ break;
+ case ZPCI_FS_PERMANENT_ERROR:
+ setcc(cpu, ZPCI_PCI_LS_ERR);
+ s390_set_status_code(env, r1, ZPCI_STPCIFC_ST_PERM_ERROR);
+ return 0;
+ }
+
stq_p(&fib.pba, pbdev->pba);
stq_p(&fib.pal, pbdev->pal);
stq_p(&fib.iota, pbdev->g_iota);
((uint32_t)pbdev->sum << 7) | pbdev->routes.adapter.summary_offset;
stl_p(&fib.data, data);
- if (pbdev->fh & FH_MASK_ENABLE) {
- fib.fc |= 0x80;
- }
-
- if (pbdev->error_state) {
- fib.fc |= 0x40;
- }
-
- if (pbdev->lgstg_blocked) {
- fib.fc |= 0x20;
- }
-
- if (pbdev->g_iota) {
- fib.fc |= 0x10;
- }
-
+out:
if (s390_cpu_virt_mem_write(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) {
return 0;
}