Commit 740eaf7d authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 's390-5.6-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

Pull s390 updates from Vasily Gorbik:

 - Add clang 10 build support.

 - Fix BUG() implementation to contain precise bug address, which is
   relevant for kprobes.

 - Make ftraced function appear in a stacktrace.

 - Minor perf improvements and refactoring.

 - Possible deadlock and recovery fixes in pci code.

* tag 's390-5.6-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
  s390: fix __EMIT_BUG() macro
  s390/ftrace: generate traced function stack frame
  s390: adjust -mpacked-stack support check for clang 10
  s390/jump_label: use "i" constraint for clang
  s390/cpum_sf: Use DIV_ROUND_UP
  s390/cpum_sf: Use kzalloc and minor changes
  s390/cpum_sf: Convert debug trace to common layout
  s390/pci: Fix possible deadlock in recover_store()
  s390/pci: Recover handle in clp_set_pci_fn()
parents fad7bdc9 17248ea0
...@@ -69,7 +69,7 @@ cflags-y += -Wa,-I$(srctree)/arch/$(ARCH)/include ...@@ -69,7 +69,7 @@ cflags-y += -Wa,-I$(srctree)/arch/$(ARCH)/include
# #
cflags-$(CONFIG_FRAME_POINTER) += -fno-optimize-sibling-calls cflags-$(CONFIG_FRAME_POINTER) += -fno-optimize-sibling-calls
ifeq ($(call cc-option-yn,-mpacked-stack),y) ifeq ($(call cc-option-yn,-mpacked-stack -mbackchain -msoft-float),y)
cflags-$(CONFIG_PACK_STACK) += -mpacked-stack -D__PACK_STACK cflags-$(CONFIG_PACK_STACK) += -mpacked-stack -D__PACK_STACK
aflags-$(CONFIG_PACK_STACK) += -D__PACK_STACK aflags-$(CONFIG_PACK_STACK) += -D__PACK_STACK
endif endif
......
...@@ -329,7 +329,7 @@ ENTRY(startup_kdump) ...@@ -329,7 +329,7 @@ ENTRY(startup_kdump)
.quad .Lduct # cr5: primary-aste origin .quad .Lduct # cr5: primary-aste origin
.quad 0 # cr6: I/O interrupts .quad 0 # cr6: I/O interrupts
.quad 0 # cr7: secondary space segment table .quad 0 # cr7: secondary space segment table
.quad 0 # cr8: access registers translation .quad 0x0000000000008000 # cr8: access registers translation
.quad 0 # cr9: tracing off .quad 0 # cr9: tracing off
.quad 0 # cr10: tracing off .quad 0 # cr10: tracing off
.quad 0 # cr11: tracing off .quad 0 # cr11: tracing off
......
...@@ -10,15 +10,14 @@ ...@@ -10,15 +10,14 @@
#define __EMIT_BUG(x) do { \ #define __EMIT_BUG(x) do { \
asm_inline volatile( \ asm_inline volatile( \
"0: j 0b+2\n" \ "0: mc 0,0\n" \
"1:\n" \
".section .rodata.str,\"aMS\",@progbits,1\n" \ ".section .rodata.str,\"aMS\",@progbits,1\n" \
"2: .asciz \""__FILE__"\"\n" \ "1: .asciz \""__FILE__"\"\n" \
".previous\n" \ ".previous\n" \
".section __bug_table,\"awM\",@progbits,%2\n" \ ".section __bug_table,\"awM\",@progbits,%2\n" \
"3: .long 1b-3b,2b-3b\n" \ "2: .long 0b-2b,1b-2b\n" \
" .short %0,%1\n" \ " .short %0,%1\n" \
" .org 3b+%2\n" \ " .org 2b+%2\n" \
".previous\n" \ ".previous\n" \
: : "i" (__LINE__), \ : : "i" (__LINE__), \
"i" (x), \ "i" (x), \
...@@ -29,12 +28,11 @@ ...@@ -29,12 +28,11 @@
#define __EMIT_BUG(x) do { \ #define __EMIT_BUG(x) do { \
asm_inline volatile( \ asm_inline volatile( \
"0: j 0b+2\n" \ "0: mc 0,0\n" \
"1:\n" \
".section __bug_table,\"awM\",@progbits,%1\n" \ ".section __bug_table,\"awM\",@progbits,%1\n" \
"2: .long 1b-2b\n" \ "1: .long 0b-1b\n" \
" .short %0\n" \ " .short %0\n" \
" .org 2b+%1\n" \ " .org 1b+%1\n" \
".previous\n" \ ".previous\n" \
: : "i" (x), \ : : "i" (x), \
"i" (sizeof(struct bug_entry))); \ "i" (sizeof(struct bug_entry))); \
......
...@@ -10,7 +10,9 @@ ...@@ -10,7 +10,9 @@
#define JUMP_LABEL_NOP_SIZE 6 #define JUMP_LABEL_NOP_SIZE 6
#define JUMP_LABEL_NOP_OFFSET 2 #define JUMP_LABEL_NOP_OFFSET 2
#if __GNUC__ < 9 #ifdef CONFIG_CC_IS_CLANG
#define JUMP_LABEL_STATIC_KEY_CONSTRAINT "i"
#elif __GNUC__ < 9
#define JUMP_LABEL_STATIC_KEY_CONSTRAINT "X" #define JUMP_LABEL_STATIC_KEY_CONSTRAINT "X"
#else #else
#define JUMP_LABEL_STATIC_KEY_CONSTRAINT "jdd" #define JUMP_LABEL_STATIC_KEY_CONSTRAINT "jdd"
......
...@@ -180,7 +180,7 @@ void zpci_remove_reserved_devices(void); ...@@ -180,7 +180,7 @@ void zpci_remove_reserved_devices(void);
/* CLP */ /* CLP */
int clp_scan_pci_devices(void); int clp_scan_pci_devices(void);
int clp_rescan_pci_devices(void); int clp_rescan_pci_devices(void);
int clp_rescan_pci_devices_simple(void); int clp_rescan_pci_devices_simple(u32 *fid);
int clp_add_pci_device(u32, u32, int); int clp_add_pci_device(u32, u32, int);
int clp_enable_fh(struct zpci_dev *, u8); int clp_enable_fh(struct zpci_dev *, u8);
int clp_disable_fh(struct zpci_dev *); int clp_disable_fh(struct zpci_dev *);
......
...@@ -45,6 +45,7 @@ void specification_exception(struct pt_regs *regs); ...@@ -45,6 +45,7 @@ void specification_exception(struct pt_regs *regs);
void transaction_exception(struct pt_regs *regs); void transaction_exception(struct pt_regs *regs);
void translation_exception(struct pt_regs *regs); void translation_exception(struct pt_regs *regs);
void vector_exception(struct pt_regs *regs); void vector_exception(struct pt_regs *regs);
void monitor_event_exception(struct pt_regs *regs);
void do_per_trap(struct pt_regs *regs); void do_per_trap(struct pt_regs *regs);
void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str); void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str);
......
...@@ -26,6 +26,12 @@ ENDPROC(ftrace_stub) ...@@ -26,6 +26,12 @@ ENDPROC(ftrace_stub)
#define STACK_PTREGS (STACK_FRAME_OVERHEAD) #define STACK_PTREGS (STACK_FRAME_OVERHEAD)
#define STACK_PTREGS_GPRS (STACK_PTREGS + __PT_GPRS) #define STACK_PTREGS_GPRS (STACK_PTREGS + __PT_GPRS)
#define STACK_PTREGS_PSW (STACK_PTREGS + __PT_PSW) #define STACK_PTREGS_PSW (STACK_PTREGS + __PT_PSW)
#ifdef __PACK_STACK
/* allocate just enough for r14, r15 and backchain */
#define TRACED_FUNC_FRAME_SIZE 24
#else
#define TRACED_FUNC_FRAME_SIZE STACK_FRAME_OVERHEAD
#endif
ENTRY(_mcount) ENTRY(_mcount)
BR_EX %r14 BR_EX %r14
...@@ -40,9 +46,16 @@ ENTRY(ftrace_caller) ...@@ -40,9 +46,16 @@ ENTRY(ftrace_caller)
#if !(defined(CC_USING_HOTPATCH) || defined(CC_USING_NOP_MCOUNT)) #if !(defined(CC_USING_HOTPATCH) || defined(CC_USING_NOP_MCOUNT))
aghi %r0,MCOUNT_RETURN_FIXUP aghi %r0,MCOUNT_RETURN_FIXUP
#endif #endif
aghi %r15,-STACK_FRAME_SIZE # allocate stack frame for ftrace_caller to contain traced function
aghi %r15,-TRACED_FUNC_FRAME_SIZE
stg %r1,__SF_BACKCHAIN(%r15) stg %r1,__SF_BACKCHAIN(%r15)
stg %r0,(__SF_GPRS+8*8)(%r15)
stg %r15,(__SF_GPRS+9*8)(%r15)
# allocate pt_regs and stack frame for ftrace_trace_function
aghi %r15,-STACK_FRAME_SIZE
stg %r1,(STACK_PTREGS_GPRS+15*8)(%r15) stg %r1,(STACK_PTREGS_GPRS+15*8)(%r15)
aghi %r1,-TRACED_FUNC_FRAME_SIZE
stg %r1,__SF_BACKCHAIN(%r15)
stg %r0,(STACK_PTREGS_PSW+8)(%r15) stg %r0,(STACK_PTREGS_PSW+8)(%r15)
stmg %r2,%r14,(STACK_PTREGS_GPRS+2*8)(%r15) stmg %r2,%r14,(STACK_PTREGS_GPRS+2*8)(%r15)
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES #ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
......
...@@ -1383,7 +1383,8 @@ static void aux_output_end(struct perf_output_handle *handle) ...@@ -1383,7 +1383,8 @@ static void aux_output_end(struct perf_output_handle *handle)
te = aux_sdb_trailer(aux, aux->alert_mark); te = aux_sdb_trailer(aux, aux->alert_mark);
te->flags &= ~SDB_TE_ALERT_REQ_MASK; te->flags &= ~SDB_TE_ALERT_REQ_MASK;
debug_sprintf_event(sfdbg, 6, "%s: collect %#lx SDBs\n", __func__, i); debug_sprintf_event(sfdbg, 6, "%s: SDBs %ld range %ld head %ld\n",
__func__, i, range_scan, aux->head);
} }
/* /*
...@@ -1416,13 +1417,17 @@ static int aux_output_begin(struct perf_output_handle *handle, ...@@ -1416,13 +1417,17 @@ static int aux_output_begin(struct perf_output_handle *handle,
* SDBs between aux->head and aux->empty_mark are already ready * SDBs between aux->head and aux->empty_mark are already ready
* for new data. range_scan is num of SDBs not within them. * for new data. range_scan is num of SDBs not within them.
*/ */
debug_sprintf_event(sfdbg, 6,
"%s: range %ld head %ld alert %ld empty %ld\n",
__func__, range, aux->head, aux->alert_mark,
aux->empty_mark);
if (range > AUX_SDB_NUM_EMPTY(aux)) { if (range > AUX_SDB_NUM_EMPTY(aux)) {
range_scan = range - AUX_SDB_NUM_EMPTY(aux); range_scan = range - AUX_SDB_NUM_EMPTY(aux);
idx = aux->empty_mark + 1; idx = aux->empty_mark + 1;
for (i = 0; i < range_scan; i++, idx++) { for (i = 0; i < range_scan; i++, idx++) {
te = aux_sdb_trailer(aux, idx); te = aux_sdb_trailer(aux, idx);
te->flags = te->flags & ~SDB_TE_BUFFER_FULL_MASK; te->flags &= ~(SDB_TE_BUFFER_FULL_MASK |
te->flags = te->flags & ~SDB_TE_ALERT_REQ_MASK; SDB_TE_ALERT_REQ_MASK);
te->overflow = 0; te->overflow = 0;
} }
/* Save the position of empty SDBs */ /* Save the position of empty SDBs */
...@@ -1441,15 +1446,11 @@ static int aux_output_begin(struct perf_output_handle *handle, ...@@ -1441,15 +1446,11 @@ static int aux_output_begin(struct perf_output_handle *handle,
cpuhw->lsctl.tear = base + offset * sizeof(unsigned long); cpuhw->lsctl.tear = base + offset * sizeof(unsigned long);
cpuhw->lsctl.dear = aux->sdb_index[head]; cpuhw->lsctl.dear = aux->sdb_index[head];
debug_sprintf_event(sfdbg, 6, "%s: " debug_sprintf_event(sfdbg, 6, "%s: head %ld alert %ld empty %ld "
"head->alert_mark->empty_mark (num_alert, range)" "index %ld tear %#lx dear %#lx\n", __func__,
"[%#lx -> %#lx -> %#lx] (%#lx, %#lx) "
"tear index %#lx, tear %#lx dear %#lx\n", __func__,
aux->head, aux->alert_mark, aux->empty_mark, aux->head, aux->alert_mark, aux->empty_mark,
AUX_SDB_NUM_ALERT(aux), range,
head / CPUM_SF_SDB_PER_TABLE, head / CPUM_SF_SDB_PER_TABLE,
cpuhw->lsctl.tear, cpuhw->lsctl.tear, cpuhw->lsctl.dear);
cpuhw->lsctl.dear);
return 0; return 0;
} }
...@@ -1469,8 +1470,7 @@ static bool aux_set_alert(struct aux_buffer *aux, unsigned long alert_index, ...@@ -1469,8 +1470,7 @@ static bool aux_set_alert(struct aux_buffer *aux, unsigned long alert_index,
te = aux_sdb_trailer(aux, alert_index); te = aux_sdb_trailer(aux, alert_index);
do { do {
orig_flags = te->flags; orig_flags = te->flags;
orig_overflow = te->overflow; *overflow = orig_overflow = te->overflow;
*overflow = orig_overflow;
if (orig_flags & SDB_TE_BUFFER_FULL_MASK) { if (orig_flags & SDB_TE_BUFFER_FULL_MASK) {
/* /*
* SDB is already set by hardware. * SDB is already set by hardware.
...@@ -1512,9 +1512,12 @@ static bool aux_reset_buffer(struct aux_buffer *aux, unsigned long range, ...@@ -1512,9 +1512,12 @@ static bool aux_reset_buffer(struct aux_buffer *aux, unsigned long range,
unsigned long long *overflow) unsigned long long *overflow)
{ {
unsigned long long orig_overflow, orig_flags, new_flags; unsigned long long orig_overflow, orig_flags, new_flags;
unsigned long i, range_scan, idx; unsigned long i, range_scan, idx, idx_old;
struct hws_trailer_entry *te; struct hws_trailer_entry *te;
debug_sprintf_event(sfdbg, 6, "%s: range %ld head %ld alert %ld "
"empty %ld\n", __func__, range, aux->head,
aux->alert_mark, aux->empty_mark);
if (range <= AUX_SDB_NUM_EMPTY(aux)) if (range <= AUX_SDB_NUM_EMPTY(aux))
/* /*
* No need to scan. All SDBs in range are marked as empty. * No need to scan. All SDBs in range are marked as empty.
...@@ -1537,7 +1540,7 @@ static bool aux_reset_buffer(struct aux_buffer *aux, unsigned long range, ...@@ -1537,7 +1540,7 @@ static bool aux_reset_buffer(struct aux_buffer *aux, unsigned long range,
* indicator fall into this range, set it. * indicator fall into this range, set it.
*/ */
range_scan = range - AUX_SDB_NUM_EMPTY(aux); range_scan = range - AUX_SDB_NUM_EMPTY(aux);
idx = aux->empty_mark + 1; idx_old = idx = aux->empty_mark + 1;
for (i = 0; i < range_scan; i++, idx++) { for (i = 0; i < range_scan; i++, idx++) {
te = aux_sdb_trailer(aux, idx); te = aux_sdb_trailer(aux, idx);
do { do {
...@@ -1557,6 +1560,9 @@ static bool aux_reset_buffer(struct aux_buffer *aux, unsigned long range, ...@@ -1557,6 +1560,9 @@ static bool aux_reset_buffer(struct aux_buffer *aux, unsigned long range,
/* Update empty_mark to new position */ /* Update empty_mark to new position */
aux->empty_mark = aux->head + range - 1; aux->empty_mark = aux->head + range - 1;
debug_sprintf_event(sfdbg, 6, "%s: range_scan %ld idx %ld..%ld "
"empty %ld\n", __func__, range_scan, idx_old,
idx - 1, aux->empty_mark);
return true; return true;
} }
...@@ -1570,7 +1576,6 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw) ...@@ -1570,7 +1576,6 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw)
unsigned long range = 0, size; unsigned long range = 0, size;
unsigned long long overflow = 0; unsigned long long overflow = 0;
struct perf_output_handle *handle = &cpuhw->handle; struct perf_output_handle *handle = &cpuhw->handle;
unsigned long num_sdb;
aux = perf_get_aux(handle); aux = perf_get_aux(handle);
if (WARN_ON_ONCE(!aux)) if (WARN_ON_ONCE(!aux))
...@@ -1578,8 +1583,9 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw) ...@@ -1578,8 +1583,9 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw)
/* Inform user space new data arrived */ /* Inform user space new data arrived */
size = AUX_SDB_NUM_ALERT(aux) << PAGE_SHIFT; size = AUX_SDB_NUM_ALERT(aux) << PAGE_SHIFT;
debug_sprintf_event(sfdbg, 6, "%s: #alert %ld\n", __func__,
size >> PAGE_SHIFT);
perf_aux_output_end(handle, size); perf_aux_output_end(handle, size);
num_sdb = aux->sfb.num_sdb;
while (!done) { while (!done) {
/* Get an output handle */ /* Get an output handle */
...@@ -1587,7 +1593,7 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw) ...@@ -1587,7 +1593,7 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw)
if (handle->size == 0) { if (handle->size == 0) {
pr_err("The AUX buffer with %lu pages for the " pr_err("The AUX buffer with %lu pages for the "
"diagnostic-sampling mode is full\n", "diagnostic-sampling mode is full\n",
num_sdb); aux->sfb.num_sdb);
debug_sprintf_event(sfdbg, 1, debug_sprintf_event(sfdbg, 1,
"%s: AUX buffer used up\n", "%s: AUX buffer used up\n",
__func__); __func__);
...@@ -1612,14 +1618,14 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw) ...@@ -1612,14 +1618,14 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw)
size = range << PAGE_SHIFT; size = range << PAGE_SHIFT;
perf_aux_output_end(&cpuhw->handle, size); perf_aux_output_end(&cpuhw->handle, size);
pr_err("Sample data caused the AUX buffer with %lu " pr_err("Sample data caused the AUX buffer with %lu "
"pages to overflow\n", num_sdb); "pages to overflow\n", aux->sfb.num_sdb);
debug_sprintf_event(sfdbg, 1, "%s: head %#lx range %#lx " debug_sprintf_event(sfdbg, 1, "%s: head %ld range %ld "
"overflow %#llx\n", __func__, "overflow %lld\n", __func__,
aux->head, range, overflow); aux->head, range, overflow);
} else { } else {
size = AUX_SDB_NUM_ALERT(aux) << PAGE_SHIFT; size = AUX_SDB_NUM_ALERT(aux) << PAGE_SHIFT;
perf_aux_output_end(&cpuhw->handle, size); perf_aux_output_end(&cpuhw->handle, size);
debug_sprintf_event(sfdbg, 6, "%s: head %#lx alert %#lx " debug_sprintf_event(sfdbg, 6, "%s: head %ld alert %ld "
"already full, try another\n", "already full, try another\n",
__func__, __func__,
aux->head, aux->alert_mark); aux->head, aux->alert_mark);
...@@ -1627,11 +1633,9 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw) ...@@ -1627,11 +1633,9 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw)
} }
if (done) if (done)
debug_sprintf_event(sfdbg, 6, "%s: aux_reset_buffer " debug_sprintf_event(sfdbg, 6, "%s: head %ld alert %ld "
"[%#lx -> %#lx -> %#lx] (%#lx, %#lx)\n", "empty %ld\n", __func__, aux->head,
__func__, aux->head, aux->alert_mark, aux->alert_mark, aux->empty_mark);
aux->empty_mark, AUX_SDB_NUM_ALERT(aux),
range);
} }
/* /*
...@@ -1654,8 +1658,7 @@ static void aux_buffer_free(void *data) ...@@ -1654,8 +1658,7 @@ static void aux_buffer_free(void *data)
kfree(aux->sdb_index); kfree(aux->sdb_index);
kfree(aux); kfree(aux);
debug_sprintf_event(sfdbg, 4, "%s: free " debug_sprintf_event(sfdbg, 4, "%s: SDBTs %lu\n", __func__, num_sdbt);
"%lu SDBTs\n", __func__, num_sdbt);
} }
static void aux_sdb_init(unsigned long sdb) static void aux_sdb_init(unsigned long sdb)
...@@ -1707,13 +1710,13 @@ static void *aux_buffer_setup(struct perf_event *event, void **pages, ...@@ -1707,13 +1710,13 @@ static void *aux_buffer_setup(struct perf_event *event, void **pages,
} }
/* Allocate aux_buffer struct for the event */ /* Allocate aux_buffer struct for the event */
aux = kmalloc(sizeof(struct aux_buffer), GFP_KERNEL); aux = kzalloc(sizeof(struct aux_buffer), GFP_KERNEL);
if (!aux) if (!aux)
goto no_aux; goto no_aux;
sfb = &aux->sfb; sfb = &aux->sfb;
/* Allocate sdbt_index for fast reference */ /* Allocate sdbt_index for fast reference */
n_sdbt = (nr_pages + CPUM_SF_SDB_PER_TABLE - 1) / CPUM_SF_SDB_PER_TABLE; n_sdbt = DIV_ROUND_UP(nr_pages, CPUM_SF_SDB_PER_TABLE);
aux->sdbt_index = kmalloc_array(n_sdbt, sizeof(void *), GFP_KERNEL); aux->sdbt_index = kmalloc_array(n_sdbt, sizeof(void *), GFP_KERNEL);
if (!aux->sdbt_index) if (!aux->sdbt_index)
goto no_sdbt_index; goto no_sdbt_index;
...@@ -1763,8 +1766,8 @@ static void *aux_buffer_setup(struct perf_event *event, void **pages, ...@@ -1763,8 +1766,8 @@ static void *aux_buffer_setup(struct perf_event *event, void **pages,
*/ */
aux->empty_mark = sfb->num_sdb - 1; aux->empty_mark = sfb->num_sdb - 1;
debug_sprintf_event(sfdbg, 4, "%s: setup %lu SDBTs and %lu SDBs\n", debug_sprintf_event(sfdbg, 4, "%s: SDBTs %lu SDBs %lu\n", __func__,
__func__, sfb->num_sdbt, sfb->num_sdb); sfb->num_sdbt, sfb->num_sdb);
return aux; return aux;
......
...@@ -81,7 +81,7 @@ PGM_CHECK_DEFAULT /* 3c */ ...@@ -81,7 +81,7 @@ PGM_CHECK_DEFAULT /* 3c */
PGM_CHECK_DEFAULT /* 3d */ PGM_CHECK_DEFAULT /* 3d */
PGM_CHECK_DEFAULT /* 3e */ PGM_CHECK_DEFAULT /* 3e */
PGM_CHECK_DEFAULT /* 3f */ PGM_CHECK_DEFAULT /* 3f */
PGM_CHECK_DEFAULT /* 40 */ PGM_CHECK(monitor_event_exception) /* 40 */
PGM_CHECK_DEFAULT /* 41 */ PGM_CHECK_DEFAULT /* 41 */
PGM_CHECK_DEFAULT /* 42 */ PGM_CHECK_DEFAULT /* 42 */
PGM_CHECK_DEFAULT /* 43 */ PGM_CHECK_DEFAULT /* 43 */
......
...@@ -53,11 +53,6 @@ void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str) ...@@ -53,11 +53,6 @@ void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str)
if (fixup) if (fixup)
regs->psw.addr = extable_fixup(fixup); regs->psw.addr = extable_fixup(fixup);
else { else {
enum bug_trap_type btt;
btt = report_bug(regs->psw.addr, regs);
if (btt == BUG_TRAP_TYPE_WARN)
return;
die(regs, str); die(regs, str);
} }
} }
...@@ -245,6 +240,27 @@ void space_switch_exception(struct pt_regs *regs) ...@@ -245,6 +240,27 @@ void space_switch_exception(struct pt_regs *regs)
do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event"); do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event");
} }
void monitor_event_exception(struct pt_regs *regs)
{
const struct exception_table_entry *fixup;
if (user_mode(regs))
return;
switch (report_bug(regs->psw.addr - (regs->int_code >> 16), regs)) {
case BUG_TRAP_TYPE_NONE:
fixup = s390_search_extables(regs->psw.addr);
if (fixup)
regs->psw.addr = extable_fixup(fixup);
break;
case BUG_TRAP_TYPE_WARN:
break;
case BUG_TRAP_TYPE_BUG:
die(regs, "monitor event");
break;
}
}
void kernel_stack_overflow(struct pt_regs *regs) void kernel_stack_overflow(struct pt_regs *regs)
{ {
bust_spinlocks(1); bust_spinlocks(1);
...@@ -255,8 +271,23 @@ void kernel_stack_overflow(struct pt_regs *regs) ...@@ -255,8 +271,23 @@ void kernel_stack_overflow(struct pt_regs *regs)
} }
NOKPROBE_SYMBOL(kernel_stack_overflow); NOKPROBE_SYMBOL(kernel_stack_overflow);
static void test_monitor_call(void)
{
int val = 1;
asm volatile(
" mc 0,0\n"
"0: xgr %0,%0\n"
"1:\n"
EX_TABLE(0b,1b)
: "+d" (val));
if (!val)
panic("Monitor call doesn't work!\n");
}
void __init trap_init(void) void __init trap_init(void)
{ {
sort_extable(__start_dma_ex_table, __stop_dma_ex_table); sort_extable(__start_dma_ex_table, __stop_dma_ex_table);
local_mcck_enable(); local_mcck_enable();
test_monitor_call();
} }
...@@ -939,5 +939,5 @@ subsys_initcall_sync(pci_base_init); ...@@ -939,5 +939,5 @@ subsys_initcall_sync(pci_base_init);
void zpci_rescan(void) void zpci_rescan(void)
{ {
if (zpci_is_enabled()) if (zpci_is_enabled())
clp_rescan_pci_devices_simple(); clp_rescan_pci_devices_simple(NULL);
} }
...@@ -240,12 +240,14 @@ int clp_add_pci_device(u32 fid, u32 fh, int configured) ...@@ -240,12 +240,14 @@ int clp_add_pci_device(u32 fid, u32 fh, int configured)
} }
/* /*
* Enable/Disable a given PCI function defined by its function handle. * Enable/Disable a given PCI function and update its function handle if
* necessary
*/ */
static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command) static int clp_set_pci_fn(struct zpci_dev *zdev, u8 nr_dma_as, u8 command)
{ {
struct clp_req_rsp_set_pci *rrb; struct clp_req_rsp_set_pci *rrb;
int rc, retries = 100; int rc, retries = 100;
u32 fid = zdev->fid;
rrb = clp_alloc_block(GFP_KERNEL); rrb = clp_alloc_block(GFP_KERNEL);
if (!rrb) if (!rrb)
...@@ -256,7 +258,7 @@ static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command) ...@@ -256,7 +258,7 @@ static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command)
rrb->request.hdr.len = sizeof(rrb->request); rrb->request.hdr.len = sizeof(rrb->request);
rrb->request.hdr.cmd = CLP_SET_PCI_FN; rrb->request.hdr.cmd = CLP_SET_PCI_FN;
rrb->response.hdr.len = sizeof(rrb->response); rrb->response.hdr.len = sizeof(rrb->response);
rrb->request.fh = *fh; rrb->request.fh = zdev->fh;
rrb->request.oc = command; rrb->request.oc = command;
rrb->request.ndas = nr_dma_as; rrb->request.ndas = nr_dma_as;
...@@ -269,12 +271,17 @@ static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command) ...@@ -269,12 +271,17 @@ static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command)
} }
} while (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY); } while (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY);
if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) if (rc || rrb->response.hdr.rsp != CLP_RC_OK) {
*fh = rrb->response.fh;
else {
zpci_err("Set PCI FN:\n"); zpci_err("Set PCI FN:\n");
zpci_err_clp(rrb->response.hdr.rsp, rc); zpci_err_clp(rrb->response.hdr.rsp, rc);
rc = -EIO; }
if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) {
zdev->fh = rrb->response.fh;
} else if (!rc && rrb->response.hdr.rsp == CLP_RC_SETPCIFN_ALRDY &&
rrb->response.fh == 0) {
/* Function is already in desired state - update handle */
rc = clp_rescan_pci_devices_simple(&fid);
} }
clp_free_block(rrb); clp_free_block(rrb);
return rc; return rc;
...@@ -282,18 +289,17 @@ static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command) ...@@ -282,18 +289,17 @@ static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command)
int clp_enable_fh(struct zpci_dev *zdev, u8 nr_dma_as) int clp_enable_fh(struct zpci_dev *zdev, u8 nr_dma_as)
{ {
u32 fh = zdev->fh;
int rc; int rc;
rc = clp_set_pci_fn(&fh, nr_dma_as, CLP_SET_ENABLE_PCI_FN); rc = clp_set_pci_fn(zdev, nr_dma_as, CLP_SET_ENABLE_PCI_FN);
zpci_dbg(3, "ena fid:%x, fh:%x, rc:%d\n", zdev->fid, fh, rc); zpci_dbg(3, "ena fid:%x, fh:%x, rc:%d\n", zdev->fid, zdev->fh, rc);
if (rc) if (rc)
goto out; goto out;
zdev->fh = fh;
if (zpci_use_mio(zdev)) { if (zpci_use_mio(zdev)) {
rc = clp_set_pci_fn(&fh, nr_dma_as, CLP_SET_ENABLE_MIO); rc = clp_set_pci_fn(zdev, nr_dma_as, CLP_SET_ENABLE_MIO);
zpci_dbg(3, "ena mio fid:%x, fh:%x, rc:%d\n", zdev->fid, fh, rc); zpci_dbg(3, "ena mio fid:%x, fh:%x, rc:%d\n",
zdev->fid, zdev->fh, rc);
if (rc) if (rc)
clp_disable_fh(zdev); clp_disable_fh(zdev);
} }
...@@ -309,11 +315,8 @@ int clp_disable_fh(struct zpci_dev *zdev) ...@@ -309,11 +315,8 @@ int clp_disable_fh(struct zpci_dev *zdev)
if (!zdev_enabled(zdev)) if (!zdev_enabled(zdev))
return 0; return 0;
rc = clp_set_pci_fn(&fh, 0, CLP_SET_DISABLE_PCI_FN); rc = clp_set_pci_fn(zdev, 0, CLP_SET_DISABLE_PCI_FN);
zpci_dbg(3, "dis fid:%x, fh:%x, rc:%d\n", zdev->fid, fh, rc); zpci_dbg(3, "dis fid:%x, fh:%x, rc:%d\n", zdev->fid, fh, rc);
if (!rc)
zdev->fh = fh;
return rc; return rc;
} }
...@@ -370,10 +373,14 @@ static void __clp_add(struct clp_fh_list_entry *entry, void *data) ...@@ -370,10 +373,14 @@ static void __clp_add(struct clp_fh_list_entry *entry, void *data)
static void __clp_update(struct clp_fh_list_entry *entry, void *data) static void __clp_update(struct clp_fh_list_entry *entry, void *data)
{ {
struct zpci_dev *zdev; struct zpci_dev *zdev;
u32 *fid = data;
if (!entry->vendor_id) if (!entry->vendor_id)
return; return;
if (fid && *fid != entry->fid)
return;
zdev = get_zdev_by_fid(entry->fid); zdev = get_zdev_by_fid(entry->fid);
if (!zdev) if (!zdev)
return; return;
...@@ -413,7 +420,10 @@ int clp_rescan_pci_devices(void) ...@@ -413,7 +420,10 @@ int clp_rescan_pci_devices(void)
return rc; return rc;
} }
int clp_rescan_pci_devices_simple(void) /* Rescan PCI functions and refresh function handles. If fid is non-NULL only
* refresh the handle of the function matching @fid
*/
int clp_rescan_pci_devices_simple(u32 *fid)
{ {
struct clp_req_rsp_list_pci *rrb; struct clp_req_rsp_list_pci *rrb;
int rc; int rc;
...@@ -422,7 +432,7 @@ int clp_rescan_pci_devices_simple(void) ...@@ -422,7 +432,7 @@ int clp_rescan_pci_devices_simple(void)
if (!rrb) if (!rrb)
return -ENOMEM; return -ENOMEM;
rc = clp_list_pci(rrb, NULL, __clp_update); rc = clp_list_pci(rrb, fid, __clp_update);
clp_free_block(rrb); clp_free_block(rrb);
return rc; return rc;
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/pci.h> #include <linux/pci.h>
#include "../../../drivers/pci/pci.h"
#include <asm/sclp.h> #include <asm/sclp.h>
#define zpci_attr(name, fmt, member) \ #define zpci_attr(name, fmt, member) \
...@@ -49,31 +51,50 @@ static DEVICE_ATTR_RO(mio_enabled); ...@@ -49,31 +51,50 @@ static DEVICE_ATTR_RO(mio_enabled);
static ssize_t recover_store(struct device *dev, struct device_attribute *attr, static ssize_t recover_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct kernfs_node *kn;
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct zpci_dev *zdev = to_zpci(pdev); struct zpci_dev *zdev = to_zpci(pdev);
int ret; int ret = 0;
if (!device_remove_file_self(dev, attr)) /* Can't use device_remove_self() here as that would lead us to lock
return count; * the pci_rescan_remove_lock while holding the device' kernfs lock.
* This would create a possible deadlock with disable_slot() which is
* not directly protected by the device' kernfs lock but takes it
* during the device removal which happens under
* pci_rescan_remove_lock.
*
* This is analogous to sdev_store_delete() in
* drivers/scsi/scsi_sysfs.c
*/
kn = sysfs_break_active_protection(&dev->kobj, &attr->attr);
WARN_ON_ONCE(!kn);
/* device_remove_file() serializes concurrent calls ignoring all but
* the first
*/
device_remove_file(dev, attr);
/* A concurrent call to recover_store() may slip between
* sysfs_break_active_protection() and the sysfs file removal.
* Once it unblocks from pci_lock_rescan_remove() the original pdev
* will already be removed.
*/
pci_lock_rescan_remove(); pci_lock_rescan_remove();
if (pci_dev_is_added(pdev)) {
pci_stop_and_remove_bus_device(pdev); pci_stop_and_remove_bus_device(pdev);
ret = zpci_disable_device(zdev); ret = zpci_disable_device(zdev);
if (ret) if (ret)
goto error; goto out;
ret = zpci_enable_device(zdev); ret = zpci_enable_device(zdev);
if (ret) if (ret)
goto error; goto out;
pci_rescan_bus(zdev->bus); pci_rescan_bus(zdev->bus);
}
out:
pci_unlock_rescan_remove(); pci_unlock_rescan_remove();
if (kn)
return count; sysfs_unbreak_active_protection(kn);
return ret ? ret : count;
error:
pci_unlock_rescan_remove();
return ret;
} }
static DEVICE_ATTR_WO(recover); static DEVICE_ATTR_WO(recover);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment