s390x/pci: enforce zPCI state checking
Current code uses some fields combinatorially to indicate the state of a s390 pci device. This patch introduces device states in order to make the code more readable and more logical. Signed-off-by: Yi Min Zhao <zyimin@linux.vnet.ibm.com> Reviewed-by: Pierre Morel <pmorel@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
This commit is contained in:
parent
06a96dae11
commit
5d1abf2344
@ -116,16 +116,22 @@ void s390_pci_sclp_configure(SCCB *sccb)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pbdev) {
|
if (!pbdev) {
|
||||||
if (pbdev->configured) {
|
|
||||||
rc = SCLP_RC_NO_ACTION_REQUIRED;
|
|
||||||
} else {
|
|
||||||
pbdev->configured = true;
|
|
||||||
rc = SCLP_RC_NORMAL_COMPLETION;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DPRINTF("sclp config no dev found\n");
|
DPRINTF("sclp config no dev found\n");
|
||||||
rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED;
|
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:
|
out:
|
||||||
psccb->header.response_code = cpu_to_be16(rc);
|
psccb->header.response_code = cpu_to_be16(rc);
|
||||||
@ -142,22 +148,28 @@ void s390_pci_sclp_deconfigure(SCCB *sccb)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pbdev) {
|
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 {
|
|
||||||
DPRINTF("sclp deconfig no dev found\n");
|
DPRINTF("sclp deconfig no dev found\n");
|
||||||
rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED;
|
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:
|
out:
|
||||||
psccb->header.response_code = cpu_to_be16(rc);
|
psccb->header.response_code = cpu_to_be16(rc);
|
||||||
@ -183,7 +195,7 @@ S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx)
|
|||||||
for (i = 0; i < PCI_SLOT_MAX; i++) {
|
for (i = 0; i < PCI_SLOT_MAX; i++) {
|
||||||
pbdev = &s->pbdev[i];
|
pbdev = &s->pbdev[i];
|
||||||
|
|
||||||
if (pbdev->fh == 0) {
|
if (pbdev->state == ZPCI_FS_RESERVED) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,9 +245,8 @@ static void s390_pci_generate_plug_event(uint16_t pec, uint32_t fh,
|
|||||||
s390_pci_generate_event(2, pec, fh, fid, 0, 0);
|
s390_pci_generate_event(2, pec, fh, fid, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void s390_pci_generate_error_event(uint16_t pec, uint32_t fh,
|
void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, uint32_t fid,
|
||||||
uint32_t fid, uint64_t faddr,
|
uint64_t faddr, uint32_t e)
|
||||||
uint32_t e)
|
|
||||||
{
|
{
|
||||||
s390_pci_generate_event(1, pec, fh, fid, faddr, e);
|
s390_pci_generate_event(1, pec, fh, fid, faddr, e);
|
||||||
}
|
}
|
||||||
@ -337,8 +348,14 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,
|
|||||||
.perm = IOMMU_NONE,
|
.perm = IOMMU_NONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!pbdev->configured || !pbdev->pdev ||
|
switch (pbdev->state) {
|
||||||
!(pbdev->fh & FH_MASK_ENABLE) || !pbdev->iommu_enabled) {
|
case ZPCI_FS_ENABLED:
|
||||||
|
case ZPCI_FS_BLOCKED:
|
||||||
|
if (!pbdev->iommu_enabled) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,30 +374,13 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,
|
|||||||
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) {
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pte = s390_guest_io_table_walk(s390_pci_get_table_origin(pbdev->g_iota),
|
pte = s390_guest_io_table_walk(s390_pci_get_table_origin(pbdev->g_iota),
|
||||||
addr);
|
addr);
|
||||||
|
|
||||||
if (!pte) {
|
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 ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,7 +449,7 @@ static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(pbdev->fh & FH_MASK_ENABLE)) {
|
if (pbdev->state != ZPCI_FS_ENABLED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -571,7 +571,7 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
|
|||||||
|
|
||||||
pbdev->fid = s390_pci_get_pfid(pci_dev);
|
pbdev->fid = s390_pci_get_pfid(pci_dev);
|
||||||
pbdev->pdev = pci_dev;
|
pbdev->pdev = pci_dev;
|
||||||
pbdev->configured = true;
|
pbdev->state = ZPCI_FS_DISABLED;
|
||||||
pbdev->fh = s390_pci_get_pfh(pci_dev);
|
pbdev->fh = s390_pci_get_pfh(pci_dev);
|
||||||
|
|
||||||
s390_pcihost_setup_msix(pbdev);
|
s390_pcihost_setup_msix(pbdev);
|
||||||
@ -592,8 +592,12 @@ static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
|
|||||||
->qbus.parent);
|
->qbus.parent);
|
||||||
S390PCIBusDevice *pbdev = &s->pbdev[PCI_SLOT(pci_dev->devfn)];
|
S390PCIBusDevice *pbdev = &s->pbdev[PCI_SLOT(pci_dev->devfn)];
|
||||||
|
|
||||||
if (pbdev->configured) {
|
switch (pbdev->state) {
|
||||||
pbdev->configured = false;
|
case ZPCI_FS_RESERVED:
|
||||||
|
goto out;
|
||||||
|
case ZPCI_FS_STANDBY:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
s390_pci_generate_plug_event(HP_EVENT_CONFIGURED_TO_STBRES,
|
s390_pci_generate_plug_event(HP_EVENT_CONFIGURED_TO_STBRES,
|
||||||
pbdev->fh, pbdev->fid);
|
pbdev->fh, pbdev->fid);
|
||||||
}
|
}
|
||||||
@ -603,6 +607,8 @@ static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
|
|||||||
pbdev->fh = 0;
|
pbdev->fh = 0;
|
||||||
pbdev->fid = 0;
|
pbdev->fid = 0;
|
||||||
pbdev->pdev = NULL;
|
pbdev->pdev = NULL;
|
||||||
|
pbdev->state = ZPCI_FS_RESERVED;
|
||||||
|
out:
|
||||||
object_unparent(OBJECT(pci_dev));
|
object_unparent(OBJECT(pci_dev));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,6 +153,34 @@ enum ZpciIoatDtype {
|
|||||||
#define ZPCI_TABLE_VALID_MASK 0x20
|
#define ZPCI_TABLE_VALID_MASK 0x20
|
||||||
#define ZPCI_TABLE_PROT_MASK 0x200
|
#define ZPCI_TABLE_PROT_MASK 0x200
|
||||||
|
|
||||||
|
/* PCI Function States
|
||||||
|
*
|
||||||
|
* reserved: default; device has just been plugged or is in progress of being
|
||||||
|
* unplugged
|
||||||
|
* standby: device is present but not configured; transition from any
|
||||||
|
* configured state/to this state via sclp configure/deconfigure
|
||||||
|
*
|
||||||
|
* The following states make up the "configured" meta-state:
|
||||||
|
* disabled: device is configured but not enabled; transition between this
|
||||||
|
* state and enabled via clp enable/disable
|
||||||
|
* enbaled: device is ready for use; transition to disabled via clp disable;
|
||||||
|
* may enter an error state
|
||||||
|
* blocked: ignore all DMA and interrupts; transition back to enabled or from
|
||||||
|
* error state via mpcifc
|
||||||
|
* error: an error occured; transition back to enabled via mpcifc
|
||||||
|
* permanent error: an unrecoverable error occured; transition to standby via
|
||||||
|
* sclp deconfigure
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
ZPCI_FS_RESERVED,
|
||||||
|
ZPCI_FS_STANDBY,
|
||||||
|
ZPCI_FS_DISABLED,
|
||||||
|
ZPCI_FS_ENABLED,
|
||||||
|
ZPCI_FS_BLOCKED,
|
||||||
|
ZPCI_FS_ERROR,
|
||||||
|
ZPCI_FS_PERMANENT_ERROR,
|
||||||
|
} ZpciState;
|
||||||
|
|
||||||
typedef struct SeiContainer {
|
typedef struct SeiContainer {
|
||||||
QTAILQ_ENTRY(SeiContainer) link;
|
QTAILQ_ENTRY(SeiContainer) link;
|
||||||
uint32_t fid;
|
uint32_t fid;
|
||||||
@ -219,9 +247,7 @@ typedef struct S390MsixInfo {
|
|||||||
|
|
||||||
typedef struct S390PCIBusDevice {
|
typedef struct S390PCIBusDevice {
|
||||||
PCIDevice *pdev;
|
PCIDevice *pdev;
|
||||||
bool configured;
|
ZpciState state;
|
||||||
bool error_state;
|
|
||||||
bool lgstg_blocked;
|
|
||||||
bool iommu_enabled;
|
bool iommu_enabled;
|
||||||
uint32_t fh;
|
uint32_t fh;
|
||||||
uint32_t fid;
|
uint32_t fid;
|
||||||
@ -255,6 +281,8 @@ void s390_pci_sclp_configure(SCCB *sccb);
|
|||||||
void s390_pci_sclp_deconfigure(SCCB *sccb);
|
void s390_pci_sclp_deconfigure(SCCB *sccb);
|
||||||
void s390_pci_iommu_enable(S390PCIBusDevice *pbdev);
|
void s390_pci_iommu_enable(S390PCIBusDevice *pbdev);
|
||||||
void s390_pci_iommu_disable(S390PCIBusDevice *pbdev);
|
void s390_pci_iommu_disable(S390PCIBusDevice *pbdev);
|
||||||
|
void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, uint32_t fid,
|
||||||
|
uint64_t faddr, uint32_t e);
|
||||||
S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx);
|
S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx);
|
||||||
S390PCIBusDevice *s390_pci_find_dev_by_fh(uint32_t fh);
|
S390PCIBusDevice *s390_pci_find_dev_by_fh(uint32_t fh);
|
||||||
S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid);
|
S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid);
|
||||||
|
@ -108,8 +108,9 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
|
|||||||
pci_get_word(pbdev->pdev->config + PCI_DEVICE_ID));
|
pci_get_word(pbdev->pdev->config + PCI_DEVICE_ID));
|
||||||
stw_p(&rrb->response.fh_list[idx - resume_token].vendor_id,
|
stw_p(&rrb->response.fh_list[idx - resume_token].vendor_id,
|
||||||
pci_get_word(pbdev->pdev->config + PCI_VENDOR_ID));
|
pci_get_word(pbdev->pdev->config + PCI_VENDOR_ID));
|
||||||
|
/* Ignore RESERVED devices. */
|
||||||
stl_p(&rrb->response.fh_list[idx - resume_token].config,
|
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].fid, pbdev->fid);
|
||||||
stl_p(&rrb->response.fh_list[idx - resume_token].fh, pbdev->fh);
|
stl_p(&rrb->response.fh_list[idx - resume_token].fh, pbdev->fh);
|
||||||
|
|
||||||
@ -213,13 +214,13 @@ int clp_service_call(S390CPU *cpu, uint8_t r2)
|
|||||||
switch (reqsetpci->oc) {
|
switch (reqsetpci->oc) {
|
||||||
case CLP_SET_ENABLE_PCI_FN:
|
case CLP_SET_ENABLE_PCI_FN:
|
||||||
pbdev->fh |= FH_MASK_ENABLE;
|
pbdev->fh |= FH_MASK_ENABLE;
|
||||||
|
pbdev->state = ZPCI_FS_ENABLED;
|
||||||
stl_p(&ressetpci->fh, pbdev->fh);
|
stl_p(&ressetpci->fh, pbdev->fh);
|
||||||
stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
|
stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
|
||||||
break;
|
break;
|
||||||
case CLP_SET_DISABLE_PCI_FN:
|
case CLP_SET_DISABLE_PCI_FN:
|
||||||
pbdev->fh &= ~FH_MASK_ENABLE;
|
pbdev->fh &= ~FH_MASK_ENABLE;
|
||||||
pbdev->error_state = false;
|
pbdev->state = ZPCI_FS_DISABLED;
|
||||||
pbdev->lgstg_blocked = false;
|
|
||||||
stl_p(&ressetpci->fh, pbdev->fh);
|
stl_p(&ressetpci->fh, pbdev->fh);
|
||||||
stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
|
stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
|
||||||
break;
|
break;
|
||||||
@ -318,16 +319,25 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
|
|||||||
offset = env->regs[r2 + 1];
|
offset = env->regs[r2 + 1];
|
||||||
|
|
||||||
pbdev = s390_pci_find_dev_by_fh(fh);
|
pbdev = s390_pci_find_dev_by_fh(fh);
|
||||||
if (!pbdev || !(pbdev->fh & FH_MASK_ENABLE)) {
|
if (!pbdev) {
|
||||||
DPRINTF("pcilg no pci dev\n");
|
DPRINTF("pcilg no pci dev\n");
|
||||||
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
|
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
|
||||||
return 0;
|
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);
|
setcc(cpu, ZPCI_PCI_LS_ERR);
|
||||||
s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED);
|
s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED);
|
||||||
return 0;
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pcias < 6) {
|
if (pcias < 6) {
|
||||||
@ -435,16 +445,25 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
|
|||||||
offset = env->regs[r2 + 1];
|
offset = env->regs[r2 + 1];
|
||||||
|
|
||||||
pbdev = s390_pci_find_dev_by_fh(fh);
|
pbdev = s390_pci_find_dev_by_fh(fh);
|
||||||
if (!pbdev || !(pbdev->fh & FH_MASK_ENABLE)) {
|
if (!pbdev) {
|
||||||
DPRINTF("pcistg no pci dev\n");
|
DPRINTF("pcistg no pci dev\n");
|
||||||
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
|
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
|
||||||
return 0;
|
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);
|
setcc(cpu, ZPCI_PCI_LS_ERR);
|
||||||
s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED);
|
s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED);
|
||||||
return 0;
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = env->regs[r1];
|
data = env->regs[r1];
|
||||||
@ -526,18 +545,55 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
|
|||||||
end = start + env->regs[r2 + 1];
|
end = start + env->regs[r2 + 1];
|
||||||
|
|
||||||
pbdev = s390_pci_find_dev_by_fh(fh);
|
pbdev = s390_pci_find_dev_by_fh(fh);
|
||||||
if (!pbdev || !(pbdev->fh & FH_MASK_ENABLE)) {
|
if (!pbdev) {
|
||||||
DPRINTF("rpcit no pci dev\n");
|
DPRINTF("rpcit no pci dev\n");
|
||||||
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
|
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
|
||||||
goto out;
|
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;
|
mr = &pbdev->iommu_mr;
|
||||||
while (start < end) {
|
while (start < end) {
|
||||||
entry = mr->iommu_ops->translate(mr, start, 0);
|
entry = mr->iommu_ops->translate(mr, start, 0);
|
||||||
|
|
||||||
if (!entry.translated_addr) {
|
if (!entry.translated_addr) {
|
||||||
|
pbdev->state = ZPCI_FS_ERROR;
|
||||||
setcc(cpu, ZPCI_PCI_LS_ERR);
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -590,16 +646,25 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pbdev = s390_pci_find_dev_by_fh(fh);
|
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);
|
DPRINTF("pcistb no pci dev fh 0x%x\n", fh);
|
||||||
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
|
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
|
||||||
return 0;
|
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);
|
setcc(cpu, ZPCI_PCI_LS_ERR);
|
||||||
s390_set_status_code(env, r1, ZPCI_PCI_ST_BLOCKED);
|
s390_set_status_code(env, r1, ZPCI_PCI_ST_BLOCKED);
|
||||||
return 0;
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mr = pbdev->pdev->io_regions[pcias].memory;
|
mr = pbdev->pdev->io_regions[pcias].memory;
|
||||||
@ -743,12 +808,23 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pbdev = s390_pci_find_dev_by_fh(fh);
|
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);
|
DPRINTF("mpcifc no pci dev fh 0x%x\n", fh);
|
||||||
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
|
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
|
||||||
return 0;
|
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))) {
|
if (s390_cpu_virt_mem_read(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -815,11 +891,25 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ZPCI_MOD_FC_RESET_ERROR:
|
case ZPCI_MOD_FC_RESET_ERROR:
|
||||||
pbdev->error_state = false;
|
switch (pbdev->state) {
|
||||||
pbdev->lgstg_blocked = false;
|
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;
|
break;
|
||||||
case ZPCI_MOD_FC_RESET_BLOCK:
|
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;
|
break;
|
||||||
case ZPCI_MOD_FC_SET_MEASURE:
|
case ZPCI_MOD_FC_SET_MEASURE:
|
||||||
pbdev->fmb_addr = ldq_p(&fib.fmb_addr);
|
pbdev->fmb_addr = ldq_p(&fib.fmb_addr);
|
||||||
@ -861,6 +951,39 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(&fib, 0, sizeof(fib));
|
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.pba, pbdev->pba);
|
||||||
stq_p(&fib.pal, pbdev->pal);
|
stq_p(&fib.pal, pbdev->pal);
|
||||||
stq_p(&fib.iota, pbdev->g_iota);
|
stq_p(&fib.iota, pbdev->g_iota);
|
||||||
@ -873,22 +996,7 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
|
|||||||
((uint32_t)pbdev->sum << 7) | pbdev->routes.adapter.summary_offset;
|
((uint32_t)pbdev->sum << 7) | pbdev->routes.adapter.summary_offset;
|
||||||
stl_p(&fib.data, data);
|
stl_p(&fib.data, data);
|
||||||
|
|
||||||
if (pbdev->fh & FH_MASK_ENABLE) {
|
out:
|
||||||
fib.fc |= 0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pbdev->error_state) {
|
|
||||||
fib.fc |= 0x40;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pbdev->lgstg_blocked) {
|
|
||||||
fib.fc |= 0x20;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pbdev->g_iota) {
|
|
||||||
fib.fc |= 0x10;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s390_cpu_virt_mem_write(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) {
|
if (s390_cpu_virt_mem_write(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -249,6 +249,11 @@ typedef struct ClpReqRspQueryPciGrp {
|
|||||||
#define ZPCI_MOD_FC_RESET_BLOCK 9
|
#define ZPCI_MOD_FC_RESET_BLOCK 9
|
||||||
#define ZPCI_MOD_FC_SET_MEASURE 10
|
#define ZPCI_MOD_FC_SET_MEASURE 10
|
||||||
|
|
||||||
|
/* Store PCI Function Controls status codes */
|
||||||
|
#define ZPCI_STPCIFC_ST_PERM_ERROR 8
|
||||||
|
#define ZPCI_STPCIFC_ST_INVAL_DMAAS 28
|
||||||
|
#define ZPCI_STPCIFC_ST_ERROR_RECOVER 40
|
||||||
|
|
||||||
/* FIB function controls */
|
/* FIB function controls */
|
||||||
#define ZPCI_FIB_FC_ENABLED 0x80
|
#define ZPCI_FIB_FC_ENABLED 0x80
|
||||||
#define ZPCI_FIB_FC_ERROR 0x40
|
#define ZPCI_FIB_FC_ERROR 0x40
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
#define SCLP_RC_CONTAINED_EQUIPMENT_CHECK 0x0340
|
#define SCLP_RC_CONTAINED_EQUIPMENT_CHECK 0x0340
|
||||||
#define SCLP_RC_INSUFFICIENT_SCCB_LENGTH 0x0300
|
#define SCLP_RC_INSUFFICIENT_SCCB_LENGTH 0x0300
|
||||||
#define SCLP_RC_STANDBY_READ_COMPLETION 0x0410
|
#define SCLP_RC_STANDBY_READ_COMPLETION 0x0410
|
||||||
|
#define SCLP_RC_ADAPTER_IN_RESERVED_STATE 0x05f0
|
||||||
#define SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED 0x09f0
|
#define SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED 0x09f0
|
||||||
#define SCLP_RC_INVALID_FUNCTION 0x40f0
|
#define SCLP_RC_INVALID_FUNCTION 0x40f0
|
||||||
#define SCLP_RC_NO_EVENT_BUFFERS_STORED 0x60f0
|
#define SCLP_RC_NO_EVENT_BUFFERS_STORED 0x60f0
|
||||||
|
Loading…
Reference in New Issue
Block a user