more s390 updates for 5.13 merge window

- add support for system call stack randomization.
 
 - handle stale PCI deconfiguration events.
 
 - couple of defconfig updates.
 
 - some fixes and cleanups.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEECMNfWEw3SLnmiLkZIg7DeRspbsIFAmCURRgACgkQIg7DeRsp
 bsLiVw//ThqXjgP7koJtawL0MFvSo1V69KTw1QNoMmUvrCynZ8nJlt4sHj1LIuEN
 m7kHoWUsvNcg8r8QbxL1eZ2f/Qf43qrFjXIKi5iTdOtO/LF9NNNQYFnA3cT3h9oE
 7hfycj8o5yi+KYY3Ca2HjlQ0i7zKYfPul1+Yms5h0nAgcvOXuPltVAlyYrrtddrM
 cfpolZZd1IB/lMHSa8/qLviRB5ADlrNx4N6Y1ROeCPCWDbO8flrnDOPTDG8a8sCN
 llQ0/vBTmenkGyT7UjG5bx9P/gX1FsMShBtyZMa8t8leIJfruDiwdo87wvSDf5IT
 I612xdbLpMfGy6i/LnJHhnw61FkpwBKJZ3UrVVkrmjY8IVN8tVdAjy5s4Fplhgjj
 BUbk9Ep03YCqfO6fpqh5DkBxCF0dnj4dZrcHA881/DnZuUkxpMJhyNjJDIx1OLup
 PC+y9eILFAnDveFvhZJZeMpH7wAheyrW/WgKZsZNLYZ+61pKPyGn9RrE5UBgI7ra
 CSIi9Km/lAuNCd9o4n5/5wCd3a9dW47kCrRe3S20oF57v5RU3AVtbC2YSUqPYahf
 NR4ZgL+zDhByLPRVij5FJ1LLeaJJftKM9uUO9egHOk1JnSxDc9EyU41x4838SKYv
 CfhQJw1ISTTRNCGeflE7+CBfEYCKX7h+DySVCtxTsg6PelcQHLs=
 =C1HZ
 -----END PGP SIGNATURE-----

Merge tag 's390-5.13-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

Pull more s390 updates from Heiko Carstens:

 - add support for system call stack randomization

 - handle stale PCI deconfiguration events

 - couple of defconfig updates

 - some fixes and cleanups

* tag 's390-5.13-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
  s390: fix detection of vector enhancements facility 1 vs. vector packed decimal facility
  s390/entry: add support for syscall stack randomization
  s390/configs: change CONFIG_VIRTIO_CONSOLE to "m"
  s390/cio: remove invalid condition on IO_SCH_UNREG
  s390/cpumf: remove call to perf_event_update_userpage
  s390/cpumf: move counter set size calculation to common place
  s390/cpumf: beautify if-then-else indentation
  s390/configs: enable CONFIG_PCI_IOV
  s390/pci: handle stale deconfiguration events
  s390/pci: rename zpci_configure_device()
This commit is contained in:
Linus Torvalds 2021-05-06 14:39:50 -07:00
commit e48661230c
16 changed files with 103 additions and 80 deletions

View file

@ -140,6 +140,7 @@ config S390
select HAVE_ARCH_JUMP_LABEL_RELATIVE select HAVE_ARCH_JUMP_LABEL_RELATIVE
select HAVE_ARCH_KASAN select HAVE_ARCH_KASAN
select HAVE_ARCH_KASAN_VMALLOC select HAVE_ARCH_KASAN_VMALLOC
select HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET
select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_SOFT_DIRTY select HAVE_ARCH_SOFT_DIRTY
select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_TRACEHOOK

View file

@ -387,6 +387,7 @@ CONFIG_CGROUP_NET_PRIO=y
CONFIG_BPF_JIT=y CONFIG_BPF_JIT=y
CONFIG_NET_PKTGEN=m CONFIG_NET_PKTGEN=m
CONFIG_PCI=y CONFIG_PCI=y
CONFIG_PCI_IOV=y
# CONFIG_PCIEASPM is not set # CONFIG_PCIEASPM is not set
CONFIG_PCI_DEBUG=y CONFIG_PCI_DEBUG=y
CONFIG_HOTPLUG_PCI=y CONFIG_HOTPLUG_PCI=y
@ -548,7 +549,7 @@ CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set # CONFIG_SERIO is not set
CONFIG_LEGACY_PTY_COUNT=0 CONFIG_LEGACY_PTY_COUNT=0
CONFIG_VIRTIO_CONSOLE=y CONFIG_VIRTIO_CONSOLE=m
CONFIG_HW_RANDOM_VIRTIO=m CONFIG_HW_RANDOM_VIRTIO=m
CONFIG_RAW_DRIVER=m CONFIG_RAW_DRIVER=m
CONFIG_HANGCHECK_TIMER=m CONFIG_HANGCHECK_TIMER=m

View file

@ -377,6 +377,7 @@ CONFIG_CGROUP_NET_PRIO=y
CONFIG_BPF_JIT=y CONFIG_BPF_JIT=y
CONFIG_NET_PKTGEN=m CONFIG_NET_PKTGEN=m
CONFIG_PCI=y CONFIG_PCI=y
CONFIG_PCI_IOV=y
# CONFIG_PCIEASPM is not set # CONFIG_PCIEASPM is not set
CONFIG_HOTPLUG_PCI=y CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_S390=y CONFIG_HOTPLUG_PCI_S390=y
@ -540,7 +541,7 @@ CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set # CONFIG_SERIO is not set
CONFIG_LEGACY_PTY_COUNT=0 CONFIG_LEGACY_PTY_COUNT=0
CONFIG_VIRTIO_CONSOLE=y CONFIG_VIRTIO_CONSOLE=m
CONFIG_HW_RANDOM_VIRTIO=m CONFIG_HW_RANDOM_VIRTIO=m
CONFIG_RAW_DRIVER=m CONFIG_RAW_DRIVER=m
CONFIG_HANGCHECK_TIMER=m CONFIG_HANGCHECK_TIMER=m

View file

@ -123,4 +123,6 @@ static inline int stccm_avail(void)
return test_facility(142); return test_facility(142);
} }
size_t cpum_cf_ctrset_size(enum cpumf_ctr_set ctrset,
struct cpumf_ctr_info *info);
#endif /* _ASM_S390_CPU_MCF_H */ #endif /* _ASM_S390_CPU_MCF_H */

View file

@ -4,9 +4,11 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/audit.h> #include <linux/audit.h>
#include <linux/randomize_kstack.h>
#include <linux/tracehook.h> #include <linux/tracehook.h>
#include <linux/processor.h> #include <linux/processor.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <asm/timex.h>
#include <asm/fpu/api.h> #include <asm/fpu/api.h>
#define ARCH_EXIT_TO_USER_MODE_WORK (_TIF_GUARDED_STORAGE | _TIF_PER_TRAP) #define ARCH_EXIT_TO_USER_MODE_WORK (_TIF_GUARDED_STORAGE | _TIF_PER_TRAP)
@ -48,6 +50,14 @@ static __always_inline void arch_exit_to_user_mode(void)
#define arch_exit_to_user_mode arch_exit_to_user_mode #define arch_exit_to_user_mode arch_exit_to_user_mode
static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
unsigned long ti_work)
{
choose_random_kstack_offset(get_tod_clock_fast() & 0xff);
}
#define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare
static inline bool on_thread_stack(void) static inline bool on_thread_stack(void)
{ {
return !(((unsigned long)(current->stack) ^ current_stack_pointer()) & ~(THREAD_SIZE - 1)); return !(((unsigned long)(current->stack) ^ current_stack_pointer()) & ~(THREAD_SIZE - 1));

View file

@ -204,7 +204,7 @@ extern unsigned int s390_pci_no_rid;
struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state); struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state);
int zpci_enable_device(struct zpci_dev *); int zpci_enable_device(struct zpci_dev *);
int zpci_disable_device(struct zpci_dev *); int zpci_disable_device(struct zpci_dev *);
int zpci_configure_device(struct zpci_dev *zdev, u32 fh); int zpci_scan_configured_device(struct zpci_dev *zdev, u32 fh);
int zpci_deconfigure_device(struct zpci_dev *zdev); int zpci_deconfigure_device(struct zpci_dev *zdev);
int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64); int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64);

View file

@ -230,9 +230,7 @@ static int __hw_perf_event_init(struct perf_event *event, unsigned int type)
/* No support for kernel space counters only */ /* No support for kernel space counters only */
} else if (!attr->exclude_kernel && attr->exclude_user) { } else if (!attr->exclude_kernel && attr->exclude_user) {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} else { /* Count user and kernel space */
/* Count user and kernel space */
} else {
if (ev >= ARRAY_SIZE(cpumf_generic_events_basic)) if (ev >= ARRAY_SIZE(cpumf_generic_events_basic))
return -EOPNOTSUPP; return -EOPNOTSUPP;
ev = cpumf_generic_events_basic[ev]; ev = cpumf_generic_events_basic[ev];
@ -402,12 +400,12 @@ static void cpumf_pmu_stop(struct perf_event *event, int flags)
*/ */
if (!atomic_dec_return(&cpuhw->ctr_set[hwc->config_base])) if (!atomic_dec_return(&cpuhw->ctr_set[hwc->config_base]))
ctr_set_stop(&cpuhw->state, hwc->config_base); ctr_set_stop(&cpuhw->state, hwc->config_base);
event->hw.state |= PERF_HES_STOPPED; hwc->state |= PERF_HES_STOPPED;
} }
if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) { if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
hw_perf_event_update(event); hw_perf_event_update(event);
event->hw.state |= PERF_HES_UPTODATE; hwc->state |= PERF_HES_UPTODATE;
} }
} }
@ -430,8 +428,6 @@ static int cpumf_pmu_add(struct perf_event *event, int flags)
if (flags & PERF_EF_START) if (flags & PERF_EF_START)
cpumf_pmu_start(event, PERF_EF_RELOAD); cpumf_pmu_start(event, PERF_EF_RELOAD);
perf_event_update_userpage(event);
return 0; return 0;
} }
@ -451,8 +447,6 @@ static void cpumf_pmu_del(struct perf_event *event, int flags)
*/ */
if (!atomic_read(&cpuhw->ctr_set[event->hw.config_base])) if (!atomic_read(&cpuhw->ctr_set[event->hw.config_base]))
ctr_set_disable(&cpuhw->state, event->hw.config_base); ctr_set_disable(&cpuhw->state, event->hw.config_base);
perf_event_update_userpage(event);
} }
/* /*

View file

@ -170,6 +170,52 @@ static int cpum_cf_offline_cpu(unsigned int cpu)
return cpum_cf_setup(cpu, PMC_RELEASE); return cpum_cf_setup(cpu, PMC_RELEASE);
} }
/* Return the maximum possible counter set size (in number of 8 byte counters)
* depending on type and model number.
*/
size_t cpum_cf_ctrset_size(enum cpumf_ctr_set ctrset,
struct cpumf_ctr_info *info)
{
size_t ctrset_size = 0;
switch (ctrset) {
case CPUMF_CTR_SET_BASIC:
if (info->cfvn >= 1)
ctrset_size = 6;
break;
case CPUMF_CTR_SET_USER:
if (info->cfvn == 1)
ctrset_size = 6;
else if (info->cfvn >= 3)
ctrset_size = 2;
break;
case CPUMF_CTR_SET_CRYPTO:
if (info->csvn >= 1 && info->csvn <= 5)
ctrset_size = 16;
else if (info->csvn == 6)
ctrset_size = 20;
break;
case CPUMF_CTR_SET_EXT:
if (info->csvn == 1)
ctrset_size = 32;
else if (info->csvn == 2)
ctrset_size = 48;
else if (info->csvn >= 3 && info->csvn <= 5)
ctrset_size = 128;
else if (info->csvn == 6)
ctrset_size = 160;
break;
case CPUMF_CTR_SET_MT_DIAG:
if (info->csvn > 3)
ctrset_size = 48;
break;
case CPUMF_CTR_SET_MAX:
break;
}
return ctrset_size;
}
static int __init cpum_cf_init(void) static int __init cpum_cf_init(void)
{ {
int rc; int rc;

View file

@ -316,52 +316,6 @@ static void cf_diag_read(struct perf_event *event)
debug_sprintf_event(cf_diag_dbg, 5, "%s event %p\n", __func__, event); debug_sprintf_event(cf_diag_dbg, 5, "%s event %p\n", __func__, event);
} }
/* Return the maximum possible counter set size (in number of 8 byte counters)
* depending on type and model number.
*/
static size_t cf_diag_ctrset_size(enum cpumf_ctr_set ctrset,
struct cpumf_ctr_info *info)
{
size_t ctrset_size = 0;
switch (ctrset) {
case CPUMF_CTR_SET_BASIC:
if (info->cfvn >= 1)
ctrset_size = 6;
break;
case CPUMF_CTR_SET_USER:
if (info->cfvn == 1)
ctrset_size = 6;
else if (info->cfvn >= 3)
ctrset_size = 2;
break;
case CPUMF_CTR_SET_CRYPTO:
if (info->csvn >= 1 && info->csvn <= 5)
ctrset_size = 16;
else if (info->csvn == 6)
ctrset_size = 20;
break;
case CPUMF_CTR_SET_EXT:
if (info->csvn == 1)
ctrset_size = 32;
else if (info->csvn == 2)
ctrset_size = 48;
else if (info->csvn >= 3 && info->csvn <= 5)
ctrset_size = 128;
else if (info->csvn == 6)
ctrset_size = 160;
break;
case CPUMF_CTR_SET_MT_DIAG:
if (info->csvn > 3)
ctrset_size = 48;
break;
case CPUMF_CTR_SET_MAX:
break;
}
return ctrset_size;
}
/* Calculate memory needed to store all counter sets together with header and /* Calculate memory needed to store all counter sets together with header and
* trailer data. This is independend of the counter set authorization which * trailer data. This is independend of the counter set authorization which
* can vary depending on the configuration. * can vary depending on the configuration.
@ -372,7 +326,7 @@ static size_t cf_diag_ctrset_maxsize(struct cpumf_ctr_info *info)
enum cpumf_ctr_set i; enum cpumf_ctr_set i;
for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) {
size_t size = cf_diag_ctrset_size(i, info); size_t size = cpum_cf_ctrset_size(i, info);
if (size) if (size)
max_size += size * sizeof(u64) + max_size += size * sizeof(u64) +
@ -405,7 +359,7 @@ static size_t cf_diag_getctrset(struct cf_ctrset_entry *ctrdata, int ctrset,
ctrdata->def = CF_DIAG_CTRSET_DEF; ctrdata->def = CF_DIAG_CTRSET_DEF;
ctrdata->set = ctrset; ctrdata->set = ctrset;
ctrdata->res1 = 0; ctrdata->res1 = 0;
ctrset_size = cf_diag_ctrset_size(ctrset, &cpuhw->info); ctrset_size = cpum_cf_ctrset_size(ctrset, &cpuhw->info);
if (ctrset_size) { /* Save data */ if (ctrset_size) { /* Save data */
need = ctrset_size * sizeof(u64) + sizeof(*ctrdata); need = ctrset_size * sizeof(u64) + sizeof(*ctrdata);
@ -845,7 +799,7 @@ static void cf_diag_cpu_read(void *parm)
if (!(p->sets & cpumf_ctr_ctl[set])) if (!(p->sets & cpumf_ctr_ctl[set]))
continue; /* Counter set not in list */ continue; /* Counter set not in list */
set_size = cf_diag_ctrset_size(set, &cpuhw->info); set_size = cpum_cf_ctrset_size(set, &cpuhw->info);
space = sizeof(csd->data) - csd->used; space = sizeof(csd->data) - csd->used;
space = cf_diag_cpuset_read(sp, set, set_size, space); space = cf_diag_cpuset_read(sp, set, set_size, space);
if (space) { if (space) {
@ -975,7 +929,7 @@ static size_t cf_diag_needspace(unsigned int sets)
for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) {
if (!(sets & cpumf_ctr_ctl[i])) if (!(sets & cpumf_ctr_ctl[i]))
continue; continue;
bytes += cf_diag_ctrset_size(i, &cpuhw->info) * sizeof(u64) + bytes += cpum_cf_ctrset_size(i, &cpuhw->info) * sizeof(u64) +
sizeof(((struct s390_ctrset_setdata *)0)->set) + sizeof(((struct s390_ctrset_setdata *)0)->set) +
sizeof(((struct s390_ctrset_setdata *)0)->no_cnts); sizeof(((struct s390_ctrset_setdata *)0)->no_cnts);
} }

View file

@ -937,9 +937,9 @@ static int __init setup_hwcaps(void)
if (MACHINE_HAS_VX) { if (MACHINE_HAS_VX) {
elf_hwcap |= HWCAP_S390_VXRS; elf_hwcap |= HWCAP_S390_VXRS;
if (test_facility(134)) if (test_facility(134))
elf_hwcap |= HWCAP_S390_VXRS_EXT;
if (test_facility(135))
elf_hwcap |= HWCAP_S390_VXRS_BCD; elf_hwcap |= HWCAP_S390_VXRS_BCD;
if (test_facility(135))
elf_hwcap |= HWCAP_S390_VXRS_EXT;
if (test_facility(148)) if (test_facility(148))
elf_hwcap |= HWCAP_S390_VXRS_EXT2; elf_hwcap |= HWCAP_S390_VXRS_EXT2;
if (test_facility(152)) if (test_facility(152))

View file

@ -142,6 +142,7 @@ void do_syscall(struct pt_regs *regs)
void noinstr __do_syscall(struct pt_regs *regs, int per_trap) void noinstr __do_syscall(struct pt_regs *regs, int per_trap)
{ {
add_random_kstack_offset();
enter_from_user_mode(regs); enter_from_user_mode(regs);
memcpy(&regs->gprs[8], S390_lowcore.save_area_sync, 8 * sizeof(unsigned long)); memcpy(&regs->gprs[8], S390_lowcore.save_area_sync, 8 * sizeof(unsigned long));

View file

@ -17,6 +17,7 @@
#include "asm/ptrace.h" #include "asm/ptrace.h"
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <linux/kdebug.h> #include <linux/kdebug.h>
#include <linux/randomize_kstack.h>
#include <linux/extable.h> #include <linux/extable.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/sched.h> #include <linux/sched.h>
@ -301,6 +302,7 @@ void noinstr __do_pgm_check(struct pt_regs *regs)
unsigned int trapnr, syscall_redirect = 0; unsigned int trapnr, syscall_redirect = 0;
irqentry_state_t state; irqentry_state_t state;
add_random_kstack_offset();
regs->int_code = *(u32 *)&S390_lowcore.pgm_ilc; regs->int_code = *(u32 *)&S390_lowcore.pgm_ilc;
regs->int_parm_long = S390_lowcore.trans_exc_code; regs->int_parm_long = S390_lowcore.trans_exc_code;

View file

@ -738,17 +738,19 @@ struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
} }
/** /**
* zpci_configure_device() - Configure a zpci_dev * zpci_scan_configured_device() - Scan a freshly configured zpci_dev
* @zdev: The zpci_dev to be configured * @zdev: The zpci_dev to be configured
* @fh: The general function handle supplied by the platform * @fh: The general function handle supplied by the platform
* *
* Given a device in the configuration state Configured, enables, scans and * Given a device in the configuration state Configured, enables, scans and
* adds it to the common code PCI subsystem. If any failure occurs, the * adds it to the common code PCI subsystem if possible. If the PCI device is
* zpci_dev is left disabled. * parked because we can not yet create a PCI bus because we have not seen
* function 0, it is ignored but will be scanned once function 0 appears.
* If any failure occurs, the zpci_dev is left disabled.
* *
* Return: 0 on success, or an error code otherwise * Return: 0 on success, or an error code otherwise
*/ */
int zpci_configure_device(struct zpci_dev *zdev, u32 fh) int zpci_scan_configured_device(struct zpci_dev *zdev, u32 fh)
{ {
int rc; int rc;

View file

@ -76,8 +76,6 @@ void zpci_event_error(void *data)
static void zpci_event_hard_deconfigured(struct zpci_dev *zdev, u32 fh) static void zpci_event_hard_deconfigured(struct zpci_dev *zdev, u32 fh)
{ {
enum zpci_state state;
zdev->fh = fh; zdev->fh = fh;
/* Give the driver a hint that the function is /* Give the driver a hint that the function is
* already unusable. * already unusable.
@ -88,15 +86,12 @@ static void zpci_event_hard_deconfigured(struct zpci_dev *zdev, u32 fh)
*/ */
zpci_disable_device(zdev); zpci_disable_device(zdev);
zdev->state = ZPCI_FN_STATE_STANDBY; zdev->state = ZPCI_FN_STATE_STANDBY;
if (!clp_get_state(zdev->fid, &state) &&
state == ZPCI_FN_STATE_RESERVED) {
zpci_zdev_put(zdev);
}
} }
static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf) static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
{ {
struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
enum zpci_state state;
zpci_err("avail CCDF:\n"); zpci_err("avail CCDF:\n");
zpci_err_hex(ccdf, sizeof(*ccdf)); zpci_err_hex(ccdf, sizeof(*ccdf));
@ -113,7 +108,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
break; break;
zdev->state = ZPCI_FN_STATE_CONFIGURED; zdev->state = ZPCI_FN_STATE_CONFIGURED;
} }
zpci_configure_device(zdev, ccdf->fh); zpci_scan_configured_device(zdev, ccdf->fh);
break; break;
case 0x0302: /* Reserved -> Standby */ case 0x0302: /* Reserved -> Standby */
if (!zdev) if (!zdev)
@ -123,13 +118,28 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
break; break;
case 0x0303: /* Deconfiguration requested */ case 0x0303: /* Deconfiguration requested */
if (zdev) { if (zdev) {
/* The event may have been queued before we confirgured
* the device.
*/
if (zdev->state != ZPCI_FN_STATE_CONFIGURED)
break;
zdev->fh = ccdf->fh; zdev->fh = ccdf->fh;
zpci_deconfigure_device(zdev); zpci_deconfigure_device(zdev);
} }
break; break;
case 0x0304: /* Configured -> Standby|Reserved */ case 0x0304: /* Configured -> Standby|Reserved */
if (zdev) if (zdev) {
zpci_event_hard_deconfigured(zdev, ccdf->fh); /* The event may have been queued before we confirgured
* the device.:
*/
if (zdev->state == ZPCI_FN_STATE_CONFIGURED)
zpci_event_hard_deconfigured(zdev, ccdf->fh);
/* The 0x0304 event may immediately reserve the device */
if (!clp_get_state(zdev->fid, &state) &&
state == ZPCI_FN_STATE_RESERVED) {
zpci_zdev_put(zdev);
}
}
break; break;
case 0x0306: /* 0x308 or 0x302 for multiple devices */ case 0x0306: /* 0x308 or 0x302 for multiple devices */
zpci_remove_reserved_devices(); zpci_remove_reserved_devices();

View file

@ -35,7 +35,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
return rc; return rc;
zdev->state = ZPCI_FN_STATE_CONFIGURED; zdev->state = ZPCI_FN_STATE_CONFIGURED;
return zpci_configure_device(zdev, zdev->fh); return zpci_scan_configured_device(zdev, zdev->fh);
} }
static int disable_slot(struct hotplug_slot *hotplug_slot) static int disable_slot(struct hotplug_slot *hotplug_slot)

View file

@ -1532,8 +1532,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
switch (action) { switch (action) {
case IO_SCH_ORPH_UNREG: case IO_SCH_ORPH_UNREG:
case IO_SCH_UNREG: case IO_SCH_UNREG:
if (!cdev) css_sch_device_unregister(sch);
css_sch_device_unregister(sch);
break; break;
case IO_SCH_ORPH_ATTACH: case IO_SCH_ORPH_ATTACH:
case IO_SCH_UNREG_ATTACH: case IO_SCH_UNREG_ATTACH: