diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-07 11:41:00 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-07 11:41:00 -0400 |
| commit | ebb067d2f4e2db59b076f9c9cba0375a8ad1e07c (patch) | |
| tree | 8d4fc065ab0fd45fca9483acfff93d4a6c74e981 | |
| parent | 33caee39925b887a99a2400dc5c980097c3573f9 (diff) | |
| parent | 36e7fdaa1a04fcf65b864232e1af56a51c7814d6 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Martin Schwidefsky:
"Mostly cleanups and bug-fixes, with two exceptions.
The first is lazy flushing of I/O-TLBs for PCI to improve performance,
the second is software dirty bits in the pmd for the madvise-free
implementation"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (24 commits)
s390/locking: Reenable optimistic spinning
s390/mm: implement dirty bits for large segment table entries
KVM: s390/mm: Fix page table locking vs. split pmd lock
s390/dasd: fix camel case
s390/3215: fix hanging console issue
s390/irq: improve displayed interrupt order in /proc/interrupts
s390/seccomp: fix error return for filtered system calls
s390/pci: introduce lazy IOTLB flushing for DMA unmap
dasd: fix error recovery for alias devices during format
dasd: fix list_del corruption during format
dasd: fix unresponsive device during format
dasd: use aliases for formatted devices during format
s390/pci: fix kmsg component
s390/kdump: Return NOTIFY_OK for all actions other than MEM_GOING_OFFLINE
s390/watchdog: Fix module name in Kconfig help text
s390/dasd: replace seq_printf by seq_puts
s390/dasd: replace pr_warning by pr_warn
s390/dasd: Move EXPORT_SYMBOL after function/variable
s390/dasd: remove unnecessary null test before debugfs_remove
s390/zfcp: use qdio buffer helpers
...
26 files changed, 619 insertions, 443 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 9344d833b7ea..21ae0e4b9e7e 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
| @@ -3058,6 +3058,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
| 3058 | 3058 | ||
| 3059 | S [KNL] Run init in single mode | 3059 | S [KNL] Run init in single mode |
| 3060 | 3060 | ||
| 3061 | s390_iommu= [HW,S390] | ||
| 3062 | Set s390 IOTLB flushing mode | ||
| 3063 | strict | ||
| 3064 | With strict flushing every unmap operation will result in | ||
| 3065 | an IOTLB flush. Default is lazy flushing before reuse, | ||
| 3066 | which is faster. | ||
| 3067 | |||
| 3061 | sa1100ir [NET] | 3068 | sa1100ir [NET] |
| 3062 | See drivers/net/irda/sa1100_ir.c. | 3069 | See drivers/net/irda/sa1100_ir.c. |
| 3063 | 3070 | ||
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 720a11d339eb..8ca60f8d5683 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
| @@ -92,6 +92,7 @@ config S390 | |||
| 92 | select ARCH_INLINE_WRITE_UNLOCK_IRQ | 92 | select ARCH_INLINE_WRITE_UNLOCK_IRQ |
| 93 | select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE | 93 | select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE |
| 94 | select ARCH_SAVE_PAGE_KEYS if HIBERNATION | 94 | select ARCH_SAVE_PAGE_KEYS if HIBERNATION |
| 95 | select ARCH_SUPPORTS_ATOMIC_RMW | ||
| 95 | select ARCH_USE_CMPXCHG_LOCKREF | 96 | select ARCH_USE_CMPXCHG_LOCKREF |
| 96 | select ARCH_WANT_IPC_PARSE_VERSION | 97 | select ARCH_WANT_IPC_PARSE_VERSION |
| 97 | select BUILDTIME_EXTABLE_SORT | 98 | select BUILDTIME_EXTABLE_SORT |
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index fcba5e03839f..b76317c1f3eb 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
| @@ -287,7 +287,14 @@ extern unsigned long MODULES_END; | |||
| 287 | #define _SEGMENT_ENTRY_INVALID 0x20 /* invalid segment table entry */ | 287 | #define _SEGMENT_ENTRY_INVALID 0x20 /* invalid segment table entry */ |
| 288 | #define _SEGMENT_ENTRY_COMMON 0x10 /* common segment bit */ | 288 | #define _SEGMENT_ENTRY_COMMON 0x10 /* common segment bit */ |
| 289 | #define _SEGMENT_ENTRY_PTL 0x0f /* page table length */ | 289 | #define _SEGMENT_ENTRY_PTL 0x0f /* page table length */ |
| 290 | #define _SEGMENT_ENTRY_NONE _SEGMENT_ENTRY_PROTECT | 290 | |
| 291 | #define _SEGMENT_ENTRY_DIRTY 0 /* No sw dirty bit for 31-bit */ | ||
| 292 | #define _SEGMENT_ENTRY_YOUNG 0 /* No sw young bit for 31-bit */ | ||
| 293 | #define _SEGMENT_ENTRY_READ 0 /* No sw read bit for 31-bit */ | ||
| 294 | #define _SEGMENT_ENTRY_WRITE 0 /* No sw write bit for 31-bit */ | ||
| 295 | #define _SEGMENT_ENTRY_LARGE 0 /* No large pages for 31-bit */ | ||
| 296 | #define _SEGMENT_ENTRY_BITS_LARGE 0 | ||
| 297 | #define _SEGMENT_ENTRY_ORIGIN_LARGE 0 | ||
| 291 | 298 | ||
| 292 | #define _SEGMENT_ENTRY (_SEGMENT_ENTRY_PTL) | 299 | #define _SEGMENT_ENTRY (_SEGMENT_ENTRY_PTL) |
| 293 | #define _SEGMENT_ENTRY_EMPTY (_SEGMENT_ENTRY_INVALID) | 300 | #define _SEGMENT_ENTRY_EMPTY (_SEGMENT_ENTRY_INVALID) |
| @@ -350,7 +357,7 @@ extern unsigned long MODULES_END; | |||
| 350 | 357 | ||
| 351 | /* Bits in the segment table entry */ | 358 | /* Bits in the segment table entry */ |
| 352 | #define _SEGMENT_ENTRY_BITS 0xfffffffffffffe33UL | 359 | #define _SEGMENT_ENTRY_BITS 0xfffffffffffffe33UL |
| 353 | #define _SEGMENT_ENTRY_BITS_LARGE 0xfffffffffff1ff33UL | 360 | #define _SEGMENT_ENTRY_BITS_LARGE 0xfffffffffff0ff33UL |
| 354 | #define _SEGMENT_ENTRY_ORIGIN_LARGE ~0xfffffUL /* large page address */ | 361 | #define _SEGMENT_ENTRY_ORIGIN_LARGE ~0xfffffUL /* large page address */ |
| 355 | #define _SEGMENT_ENTRY_ORIGIN ~0x7ffUL/* segment table origin */ | 362 | #define _SEGMENT_ENTRY_ORIGIN ~0x7ffUL/* segment table origin */ |
| 356 | #define _SEGMENT_ENTRY_PROTECT 0x200 /* page protection bit */ | 363 | #define _SEGMENT_ENTRY_PROTECT 0x200 /* page protection bit */ |
| @@ -359,30 +366,34 @@ extern unsigned long MODULES_END; | |||
| 359 | #define _SEGMENT_ENTRY (0) | 366 | #define _SEGMENT_ENTRY (0) |
| 360 | #define _SEGMENT_ENTRY_EMPTY (_SEGMENT_ENTRY_INVALID) | 367 | #define _SEGMENT_ENTRY_EMPTY (_SEGMENT_ENTRY_INVALID) |
| 361 | 368 | ||
| 362 | #define _SEGMENT_ENTRY_LARGE 0x400 /* STE-format control, large page */ | 369 | #define _SEGMENT_ENTRY_DIRTY 0x2000 /* SW segment dirty bit */ |
| 363 | #define _SEGMENT_ENTRY_CO 0x100 /* change-recording override */ | 370 | #define _SEGMENT_ENTRY_YOUNG 0x1000 /* SW segment young bit */ |
| 364 | #define _SEGMENT_ENTRY_SPLIT 0x001 /* THP splitting bit */ | 371 | #define _SEGMENT_ENTRY_SPLIT 0x0800 /* THP splitting bit */ |
| 365 | #define _SEGMENT_ENTRY_YOUNG 0x002 /* SW segment young bit */ | 372 | #define _SEGMENT_ENTRY_LARGE 0x0400 /* STE-format control, large page */ |
| 366 | #define _SEGMENT_ENTRY_NONE _SEGMENT_ENTRY_YOUNG | 373 | #define _SEGMENT_ENTRY_CO 0x0100 /* change-recording override */ |
| 374 | #define _SEGMENT_ENTRY_READ 0x0002 /* SW segment read bit */ | ||
| 375 | #define _SEGMENT_ENTRY_WRITE 0x0001 /* SW segment write bit */ | ||
| 367 | 376 | ||
| 368 | /* | 377 | /* |
| 369 | * Segment table entry encoding (R = read-only, I = invalid, y = young bit): | 378 | * Segment table entry encoding (R = read-only, I = invalid, y = young bit): |
| 370 | * ..R...I...y. | 379 | * dy..R...I...wr |
| 371 | * prot-none, old ..0...1...1. | 380 | * prot-none, clean, old 00..1...1...00 |
| 372 | * prot-none, young ..1...1...1. | 381 | * prot-none, clean, young 01..1...1...00 |
| 373 | * read-only, old ..1...1...0. | 382 | * prot-none, dirty, old 10..1...1...00 |
| 374 | * read-only, young ..1...0...1. | 383 | * prot-none, dirty, young 11..1...1...00 |
| 375 | * read-write, old ..0...1...0. | 384 | * read-only, clean, old 00..1...1...01 |
| 376 | * read-write, young ..0...0...1. | 385 | * read-only, clean, young 01..1...0...01 |
| 386 | * read-only, dirty, old 10..1...1...01 | ||
| 387 | * read-only, dirty, young 11..1...0...01 | ||
| 388 | * read-write, clean, old 00..1...1...11 | ||
| 389 | * read-write, clean, young 01..1...0...11 | ||
| 390 | * read-write, dirty, old 10..0...1...11 | ||
| 391 | * read-write, dirty, young 11..0...0...11 | ||
| 377 | * The segment table origin is used to distinguish empty (origin==0) from | 392 | * The segment table origin is used to distinguish empty (origin==0) from |
| 378 | * read-write, old segment table entries (origin!=0) | 393 | * read-write, old segment table entries (origin!=0) |
| 379 | */ | 394 | */ |
| 380 | 395 | ||
| 381 | #define _SEGMENT_ENTRY_SPLIT_BIT 0 /* THP splitting bit number */ | 396 | #define _SEGMENT_ENTRY_SPLIT_BIT 11 /* THP splitting bit number */ |
| 382 | |||
| 383 | /* Set of bits not changed in pmd_modify */ | ||
| 384 | #define _SEGMENT_CHG_MASK (_SEGMENT_ENTRY_ORIGIN | _SEGMENT_ENTRY_LARGE \ | ||
| 385 | | _SEGMENT_ENTRY_SPLIT | _SEGMENT_ENTRY_CO) | ||
| 386 | 397 | ||
| 387 | /* Page status table bits for virtualization */ | 398 | /* Page status table bits for virtualization */ |
| 388 | #define PGSTE_ACC_BITS 0xf000000000000000UL | 399 | #define PGSTE_ACC_BITS 0xf000000000000000UL |
| @@ -455,10 +466,11 @@ extern unsigned long MODULES_END; | |||
| 455 | * Segment entry (large page) protection definitions. | 466 | * Segment entry (large page) protection definitions. |
| 456 | */ | 467 | */ |
| 457 | #define SEGMENT_NONE __pgprot(_SEGMENT_ENTRY_INVALID | \ | 468 | #define SEGMENT_NONE __pgprot(_SEGMENT_ENTRY_INVALID | \ |
| 458 | _SEGMENT_ENTRY_NONE) | ||
| 459 | #define SEGMENT_READ __pgprot(_SEGMENT_ENTRY_INVALID | \ | ||
| 460 | _SEGMENT_ENTRY_PROTECT) | 469 | _SEGMENT_ENTRY_PROTECT) |
| 461 | #define SEGMENT_WRITE __pgprot(_SEGMENT_ENTRY_INVALID) | 470 | #define SEGMENT_READ __pgprot(_SEGMENT_ENTRY_PROTECT | \ |
| 471 | _SEGMENT_ENTRY_READ) | ||
| 472 | #define SEGMENT_WRITE __pgprot(_SEGMENT_ENTRY_READ | \ | ||
| 473 | _SEGMENT_ENTRY_WRITE) | ||
| 462 | 474 | ||
| 463 | static inline int mm_has_pgste(struct mm_struct *mm) | 475 | static inline int mm_has_pgste(struct mm_struct *mm) |
| 464 | { | 476 | { |
| @@ -569,25 +581,23 @@ static inline int pmd_none(pmd_t pmd) | |||
| 569 | 581 | ||
| 570 | static inline int pmd_large(pmd_t pmd) | 582 | static inline int pmd_large(pmd_t pmd) |
| 571 | { | 583 | { |
| 572 | #ifdef CONFIG_64BIT | ||
| 573 | return (pmd_val(pmd) & _SEGMENT_ENTRY_LARGE) != 0; | 584 | return (pmd_val(pmd) & _SEGMENT_ENTRY_LARGE) != 0; |
| 574 | #else | ||
| 575 | return 0; | ||
| 576 | #endif | ||
| 577 | } | 585 | } |
| 578 | 586 | ||
| 579 | static inline int pmd_prot_none(pmd_t pmd) | 587 | static inline int pmd_pfn(pmd_t pmd) |
| 580 | { | 588 | { |
| 581 | return (pmd_val(pmd) & _SEGMENT_ENTRY_INVALID) && | 589 | unsigned long origin_mask; |
| 582 | (pmd_val(pmd) & _SEGMENT_ENTRY_NONE); | 590 | |
| 591 | origin_mask = _SEGMENT_ENTRY_ORIGIN; | ||
| 592 | if (pmd_large(pmd)) | ||
| 593 | origin_mask = _SEGMENT_ENTRY_ORIGIN_LARGE; | ||
| 594 | return (pmd_val(pmd) & origin_mask) >> PAGE_SHIFT; | ||
| 583 | } | 595 | } |
| 584 | 596 | ||
| 585 | static inline int pmd_bad(pmd_t pmd) | 597 | static inline int pmd_bad(pmd_t pmd) |
| 586 | { | 598 | { |
| 587 | #ifdef CONFIG_64BIT | ||
| 588 | if (pmd_large(pmd)) | 599 | if (pmd_large(pmd)) |
| 589 | return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS_LARGE) != 0; | 600 | return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS_LARGE) != 0; |
| 590 | #endif | ||
| 591 | return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS) != 0; | 601 | return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS) != 0; |
| 592 | } | 602 | } |
| 593 | 603 | ||
| @@ -607,20 +617,22 @@ extern int pmdp_clear_flush_young(struct vm_area_struct *vma, | |||
| 607 | #define __HAVE_ARCH_PMD_WRITE | 617 | #define __HAVE_ARCH_PMD_WRITE |
| 608 | static inline int pmd_write(pmd_t pmd) | 618 | static inline int pmd_write(pmd_t pmd) |
| 609 | { | 619 | { |
| 610 | if (pmd_prot_none(pmd)) | 620 | return (pmd_val(pmd) & _SEGMENT_ENTRY_WRITE) != 0; |
| 611 | return 0; | 621 | } |
| 612 | return (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT) == 0; | 622 | |
| 623 | static inline int pmd_dirty(pmd_t pmd) | ||
| 624 | { | ||
| 625 | int dirty = 1; | ||
| 626 | if (pmd_large(pmd)) | ||
| 627 | dirty = (pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY) != 0; | ||
| 628 | return dirty; | ||
| 613 | } | 629 | } |
| 614 | 630 | ||
| 615 | static inline int pmd_young(pmd_t pmd) | 631 | static inline int pmd_young(pmd_t pmd) |
| 616 | { | 632 | { |
| 617 | int young = 0; | 633 | int young = 1; |
| 618 | #ifdef CONFIG_64BIT | 634 | if (pmd_large(pmd)) |
| 619 | if (pmd_prot_none(pmd)) | ||
| 620 | young = (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT) != 0; | ||
| 621 | else | ||
| 622 | young = (pmd_val(pmd) & _SEGMENT_ENTRY_YOUNG) != 0; | 635 | young = (pmd_val(pmd) & _SEGMENT_ENTRY_YOUNG) != 0; |
| 623 | #endif | ||
| 624 | return young; | 636 | return young; |
| 625 | } | 637 | } |
| 626 | 638 | ||
| @@ -1391,7 +1403,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address) | |||
| 1391 | #define pte_pfn(x) (pte_val(x) >> PAGE_SHIFT) | 1403 | #define pte_pfn(x) (pte_val(x) >> PAGE_SHIFT) |
| 1392 | #define pte_page(x) pfn_to_page(pte_pfn(x)) | 1404 | #define pte_page(x) pfn_to_page(pte_pfn(x)) |
| 1393 | 1405 | ||
| 1394 | #define pmd_page(pmd) pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT) | 1406 | #define pmd_page(pmd) pfn_to_page(pmd_pfn(pmd)) |
| 1395 | 1407 | ||
| 1396 | /* Find an entry in the lowest level page table.. */ | 1408 | /* Find an entry in the lowest level page table.. */ |
| 1397 | #define pte_offset(pmd, addr) ((pte_t *) pmd_deref(*(pmd)) + pte_index(addr)) | 1409 | #define pte_offset(pmd, addr) ((pte_t *) pmd_deref(*(pmd)) + pte_index(addr)) |
| @@ -1413,41 +1425,75 @@ static inline unsigned long massage_pgprot_pmd(pgprot_t pgprot) | |||
| 1413 | return pgprot_val(SEGMENT_WRITE); | 1425 | return pgprot_val(SEGMENT_WRITE); |
| 1414 | } | 1426 | } |
| 1415 | 1427 | ||
| 1416 | static inline pmd_t pmd_mkyoung(pmd_t pmd) | 1428 | static inline pmd_t pmd_wrprotect(pmd_t pmd) |
| 1417 | { | 1429 | { |
| 1418 | #ifdef CONFIG_64BIT | 1430 | pmd_val(pmd) &= ~_SEGMENT_ENTRY_WRITE; |
| 1419 | if (pmd_prot_none(pmd)) { | 1431 | pmd_val(pmd) |= _SEGMENT_ENTRY_PROTECT; |
| 1432 | return pmd; | ||
| 1433 | } | ||
| 1434 | |||
| 1435 | static inline pmd_t pmd_mkwrite(pmd_t pmd) | ||
| 1436 | { | ||
| 1437 | pmd_val(pmd) |= _SEGMENT_ENTRY_WRITE; | ||
| 1438 | if (pmd_large(pmd) && !(pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY)) | ||
| 1439 | return pmd; | ||
| 1440 | pmd_val(pmd) &= ~_SEGMENT_ENTRY_PROTECT; | ||
| 1441 | return pmd; | ||
| 1442 | } | ||
| 1443 | |||
| 1444 | static inline pmd_t pmd_mkclean(pmd_t pmd) | ||
| 1445 | { | ||
| 1446 | if (pmd_large(pmd)) { | ||
| 1447 | pmd_val(pmd) &= ~_SEGMENT_ENTRY_DIRTY; | ||
| 1420 | pmd_val(pmd) |= _SEGMENT_ENTRY_PROTECT; | 1448 | pmd_val(pmd) |= _SEGMENT_ENTRY_PROTECT; |
| 1421 | } else { | 1449 | } |
| 1450 | return pmd; | ||
| 1451 | } | ||
| 1452 | |||
| 1453 | static inline pmd_t pmd_mkdirty(pmd_t pmd) | ||
| 1454 | { | ||
| 1455 | if (pmd_large(pmd)) { | ||
| 1456 | pmd_val(pmd) |= _SEGMENT_ENTRY_DIRTY; | ||
| 1457 | if (pmd_val(pmd) & _SEGMENT_ENTRY_WRITE) | ||
| 1458 | pmd_val(pmd) &= ~_SEGMENT_ENTRY_PROTECT; | ||
| 1459 | } | ||
| 1460 | return pmd; | ||
| 1461 | } | ||
| 1462 | |||
| 1463 | static inline pmd_t pmd_mkyoung(pmd_t pmd) | ||
| 1464 | { | ||
| 1465 | if (pmd_large(pmd)) { | ||
| 1422 | pmd_val(pmd) |= _SEGMENT_ENTRY_YOUNG; | 1466 | pmd_val(pmd) |= _SEGMENT_ENTRY_YOUNG; |
| 1423 | pmd_val(pmd) &= ~_SEGMENT_ENTRY_INVALID; | 1467 | if (pmd_val(pmd) & _SEGMENT_ENTRY_READ) |
| 1468 | pmd_val(pmd) &= ~_SEGMENT_ENTRY_INVALID; | ||
| 1424 | } | 1469 | } |
| 1425 | #endif | ||
| 1426 | return pmd; | 1470 | return pmd; |
| 1427 | } | 1471 | } |
| 1428 | 1472 | ||
| 1429 | static inline pmd_t pmd_mkold(pmd_t pmd) | 1473 | static inline pmd_t pmd_mkold(pmd_t pmd) |
| 1430 | { | 1474 | { |
| 1431 | #ifdef CONFIG_64BIT | 1475 | if (pmd_large(pmd)) { |
| 1432 | if (pmd_prot_none(pmd)) { | ||
| 1433 | pmd_val(pmd) &= ~_SEGMENT_ENTRY_PROTECT; | ||
| 1434 | } else { | ||
| 1435 | pmd_val(pmd) &= ~_SEGMENT_ENTRY_YOUNG; | 1476 | pmd_val(pmd) &= ~_SEGMENT_ENTRY_YOUNG; |
| 1436 | pmd_val(pmd) |= _SEGMENT_ENTRY_INVALID; | 1477 | pmd_val(pmd) |= _SEGMENT_ENTRY_INVALID; |
| 1437 | } | 1478 | } |
| 1438 | #endif | ||
| 1439 | return pmd; | 1479 | return pmd; |
| 1440 | } | 1480 | } |
| 1441 | 1481 | ||
| 1442 | static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) | 1482 | static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) |
| 1443 | { | 1483 | { |
| 1444 | int young; | 1484 | if (pmd_large(pmd)) { |
| 1445 | 1485 | pmd_val(pmd) &= _SEGMENT_ENTRY_ORIGIN_LARGE | | |
| 1446 | young = pmd_young(pmd); | 1486 | _SEGMENT_ENTRY_DIRTY | _SEGMENT_ENTRY_YOUNG | |
| 1447 | pmd_val(pmd) &= _SEGMENT_CHG_MASK; | 1487 | _SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_SPLIT; |
| 1488 | pmd_val(pmd) |= massage_pgprot_pmd(newprot); | ||
| 1489 | if (!(pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY)) | ||
| 1490 | pmd_val(pmd) |= _SEGMENT_ENTRY_PROTECT; | ||
| 1491 | if (!(pmd_val(pmd) & _SEGMENT_ENTRY_YOUNG)) | ||
| 1492 | pmd_val(pmd) |= _SEGMENT_ENTRY_INVALID; | ||
| 1493 | return pmd; | ||
| 1494 | } | ||
| 1495 | pmd_val(pmd) &= _SEGMENT_ENTRY_ORIGIN; | ||
| 1448 | pmd_val(pmd) |= massage_pgprot_pmd(newprot); | 1496 | pmd_val(pmd) |= massage_pgprot_pmd(newprot); |
| 1449 | if (young) | ||
| 1450 | pmd = pmd_mkyoung(pmd); | ||
| 1451 | return pmd; | 1497 | return pmd; |
| 1452 | } | 1498 | } |
| 1453 | 1499 | ||
| @@ -1455,16 +1501,9 @@ static inline pmd_t mk_pmd_phys(unsigned long physpage, pgprot_t pgprot) | |||
| 1455 | { | 1501 | { |
| 1456 | pmd_t __pmd; | 1502 | pmd_t __pmd; |
| 1457 | pmd_val(__pmd) = physpage + massage_pgprot_pmd(pgprot); | 1503 | pmd_val(__pmd) = physpage + massage_pgprot_pmd(pgprot); |
| 1458 | return pmd_mkyoung(__pmd); | 1504 | return __pmd; |
| 1459 | } | 1505 | } |
| 1460 | 1506 | ||
| 1461 | static inline pmd_t pmd_mkwrite(pmd_t pmd) | ||
| 1462 | { | ||
| 1463 | /* Do not clobber PROT_NONE segments! */ | ||
| 1464 | if (!pmd_prot_none(pmd)) | ||
| 1465 | pmd_val(pmd) &= ~_SEGMENT_ENTRY_PROTECT; | ||
| 1466 | return pmd; | ||
| 1467 | } | ||
| 1468 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_HUGETLB_PAGE */ | 1507 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_HUGETLB_PAGE */ |
| 1469 | 1508 | ||
| 1470 | static inline void __pmdp_csp(pmd_t *pmdp) | 1509 | static inline void __pmdp_csp(pmd_t *pmdp) |
| @@ -1555,34 +1594,21 @@ extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp); | |||
| 1555 | 1594 | ||
| 1556 | static inline int pmd_trans_splitting(pmd_t pmd) | 1595 | static inline int pmd_trans_splitting(pmd_t pmd) |
| 1557 | { | 1596 | { |
| 1558 | return pmd_val(pmd) & _SEGMENT_ENTRY_SPLIT; | 1597 | return (pmd_val(pmd) & _SEGMENT_ENTRY_LARGE) && |
| 1598 | (pmd_val(pmd) & _SEGMENT_ENTRY_SPLIT); | ||
| 1559 | } | 1599 | } |
| 1560 | 1600 | ||
| 1561 | static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, | 1601 | static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, |
| 1562 | pmd_t *pmdp, pmd_t entry) | 1602 | pmd_t *pmdp, pmd_t entry) |
| 1563 | { | 1603 | { |
| 1564 | if (!(pmd_val(entry) & _SEGMENT_ENTRY_INVALID) && MACHINE_HAS_EDAT1) | ||
| 1565 | pmd_val(entry) |= _SEGMENT_ENTRY_CO; | ||
| 1566 | *pmdp = entry; | 1604 | *pmdp = entry; |
| 1567 | } | 1605 | } |
| 1568 | 1606 | ||
| 1569 | static inline pmd_t pmd_mkhuge(pmd_t pmd) | 1607 | static inline pmd_t pmd_mkhuge(pmd_t pmd) |
| 1570 | { | 1608 | { |
| 1571 | pmd_val(pmd) |= _SEGMENT_ENTRY_LARGE; | 1609 | pmd_val(pmd) |= _SEGMENT_ENTRY_LARGE; |
| 1572 | return pmd; | 1610 | pmd_val(pmd) |= _SEGMENT_ENTRY_YOUNG; |
| 1573 | } | 1611 | pmd_val(pmd) |= _SEGMENT_ENTRY_PROTECT; |
| 1574 | |||
| 1575 | static inline pmd_t pmd_wrprotect(pmd_t pmd) | ||
| 1576 | { | ||
| 1577 | /* Do not clobber PROT_NONE segments! */ | ||
| 1578 | if (!pmd_prot_none(pmd)) | ||
| 1579 | pmd_val(pmd) |= _SEGMENT_ENTRY_PROTECT; | ||
| 1580 | return pmd; | ||
| 1581 | } | ||
| 1582 | |||
| 1583 | static inline pmd_t pmd_mkdirty(pmd_t pmd) | ||
| 1584 | { | ||
| 1585 | /* No dirty bit in the segment table entry. */ | ||
| 1586 | return pmd; | 1612 | return pmd; |
| 1587 | } | 1613 | } |
| 1588 | 1614 | ||
| @@ -1647,11 +1673,6 @@ static inline int has_transparent_hugepage(void) | |||
| 1647 | { | 1673 | { |
| 1648 | return MACHINE_HAS_HPAGE ? 1 : 0; | 1674 | return MACHINE_HAS_HPAGE ? 1 : 0; |
| 1649 | } | 1675 | } |
| 1650 | |||
| 1651 | static inline unsigned long pmd_pfn(pmd_t pmd) | ||
| 1652 | { | ||
| 1653 | return pmd_val(pmd) >> PAGE_SHIFT; | ||
| 1654 | } | ||
| 1655 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ | 1676 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ |
| 1656 | 1677 | ||
| 1657 | /* | 1678 | /* |
diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index d786c634e052..06f3034605a1 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h | |||
| @@ -415,6 +415,10 @@ struct qdio_brinfo_entry_l2 { | |||
| 415 | #define QDIO_FLAG_SYNC_OUTPUT 0x02 | 415 | #define QDIO_FLAG_SYNC_OUTPUT 0x02 |
| 416 | #define QDIO_FLAG_PCI_OUT 0x10 | 416 | #define QDIO_FLAG_PCI_OUT 0x10 |
| 417 | 417 | ||
| 418 | int qdio_alloc_buffers(struct qdio_buffer **buf, unsigned int count); | ||
| 419 | void qdio_free_buffers(struct qdio_buffer **buf, unsigned int count); | ||
| 420 | void qdio_reset_buffers(struct qdio_buffer **buf, unsigned int count); | ||
| 421 | |||
| 418 | extern int qdio_allocate(struct qdio_initialize *); | 422 | extern int qdio_allocate(struct qdio_initialize *); |
| 419 | extern int qdio_establish(struct qdio_initialize *); | 423 | extern int qdio_establish(struct qdio_initialize *); |
| 420 | extern int qdio_activate(struct ccw_device *); | 424 | extern int qdio_activate(struct ccw_device *); |
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h index abad78d5b10c..5bc12598ae9e 100644 --- a/arch/s390/include/asm/syscall.h +++ b/arch/s390/include/asm/syscall.h | |||
| @@ -54,7 +54,7 @@ static inline void syscall_set_return_value(struct task_struct *task, | |||
| 54 | struct pt_regs *regs, | 54 | struct pt_regs *regs, |
| 55 | int error, long val) | 55 | int error, long val) |
| 56 | { | 56 | { |
| 57 | regs->gprs[2] = error ? -error : val; | 57 | regs->gprs[2] = error ? error : val; |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | static inline void syscall_get_arguments(struct task_struct *task, | 60 | static inline void syscall_get_arguments(struct task_struct *task, |
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 99b0b09646ca..8eb82443cfbd 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c | |||
| @@ -30,6 +30,7 @@ DEFINE_PER_CPU_SHARED_ALIGNED(struct irq_stat, irq_stat); | |||
| 30 | EXPORT_PER_CPU_SYMBOL_GPL(irq_stat); | 30 | EXPORT_PER_CPU_SYMBOL_GPL(irq_stat); |
| 31 | 31 | ||
| 32 | struct irq_class { | 32 | struct irq_class { |
| 33 | int irq; | ||
| 33 | char *name; | 34 | char *name; |
| 34 | char *desc; | 35 | char *desc; |
| 35 | }; | 36 | }; |
| @@ -45,9 +46,9 @@ struct irq_class { | |||
| 45 | * up with having a sum which accounts each interrupt twice. | 46 | * up with having a sum which accounts each interrupt twice. |
| 46 | */ | 47 | */ |
| 47 | static const struct irq_class irqclass_main_desc[NR_IRQS_BASE] = { | 48 | static const struct irq_class irqclass_main_desc[NR_IRQS_BASE] = { |
| 48 | [EXT_INTERRUPT] = {.name = "EXT"}, | 49 | {.irq = EXT_INTERRUPT, .name = "EXT"}, |
| 49 | [IO_INTERRUPT] = {.name = "I/O"}, | 50 | {.irq = IO_INTERRUPT, .name = "I/O"}, |
| 50 | [THIN_INTERRUPT] = {.name = "AIO"}, | 51 | {.irq = THIN_INTERRUPT, .name = "AIO"}, |
| 51 | }; | 52 | }; |
| 52 | 53 | ||
| 53 | /* | 54 | /* |
| @@ -56,38 +57,38 @@ static const struct irq_class irqclass_main_desc[NR_IRQS_BASE] = { | |||
| 56 | * In addition this list contains non external / I/O events like NMIs. | 57 | * In addition this list contains non external / I/O events like NMIs. |
| 57 | */ | 58 | */ |
| 58 | static const struct irq_class irqclass_sub_desc[NR_ARCH_IRQS] = { | 59 | static const struct irq_class irqclass_sub_desc[NR_ARCH_IRQS] = { |
| 59 | [IRQEXT_CLK] = {.name = "CLK", .desc = "[EXT] Clock Comparator"}, | 60 | {.irq = IRQEXT_CLK, .name = "CLK", .desc = "[EXT] Clock Comparator"}, |
| 60 | [IRQEXT_EXC] = {.name = "EXC", .desc = "[EXT] External Call"}, | 61 | {.irq = IRQEXT_EXC, .name = "EXC", .desc = "[EXT] External Call"}, |
| 61 | [IRQEXT_EMS] = {.name = "EMS", .desc = "[EXT] Emergency Signal"}, | 62 | {.irq = IRQEXT_EMS, .name = "EMS", .desc = "[EXT] Emergency Signal"}, |
| 62 | [IRQEXT_TMR] = {.name = "TMR", .desc = "[EXT] CPU Timer"}, | 63 | {.irq = IRQEXT_TMR, .name = "TMR", .desc = "[EXT] CPU Timer"}, |
| 63 | [IRQEXT_TLA] = {.name = "TAL", .desc = "[EXT] Timing Alert"}, | 64 | {.irq = IRQEXT_TLA, .name = "TAL", .desc = "[EXT] Timing Alert"}, |
| 64 | [IRQEXT_PFL] = {.name = "PFL", .desc = "[EXT] Pseudo Page Fault"}, | 65 | {.irq = IRQEXT_PFL, .name = "PFL", .desc = "[EXT] Pseudo Page Fault"}, |
| 65 | [IRQEXT_DSD] = {.name = "DSD", .desc = "[EXT] DASD Diag"}, | 66 | {.irq = IRQEXT_DSD, .name = "DSD", .desc = "[EXT] DASD Diag"}, |
| 66 | [IRQEXT_VRT] = {.name = "VRT", .desc = "[EXT] Virtio"}, | 67 | {.irq = IRQEXT_VRT, .name = "VRT", .desc = "[EXT] Virtio"}, |
| 67 | [IRQEXT_SCP] = {.name = "SCP", .desc = "[EXT] Service Call"}, | 68 | {.irq = IRQEXT_SCP, .name = "SCP", .desc = "[EXT] Service Call"}, |
| 68 | [IRQEXT_IUC] = {.name = "IUC", .desc = "[EXT] IUCV"}, | 69 | {.irq = IRQEXT_IUC, .name = "IUC", .desc = "[EXT] IUCV"}, |
| 69 | [IRQEXT_CMS] = {.name = "CMS", .desc = "[EXT] CPU-Measurement: Sampling"}, | 70 | {.irq = IRQEXT_CMS, .name = "CMS", .desc = "[EXT] CPU-Measurement: Sampling"}, |
| 70 | [IRQEXT_CMC] = {.name = "CMC", .desc = "[EXT] CPU-Measurement: Counter"}, | 71 | {.irq = IRQEXT_CMC, .name = "CMC", .desc = "[EXT] CPU-Measurement: Counter"}, |
| 71 | [IRQEXT_CMR] = {.name = "CMR", .desc = "[EXT] CPU-Measurement: RI"}, | 72 | {.irq = IRQEXT_CMR, .name = "CMR", .desc = "[EXT] CPU-Measurement: RI"}, |
| 72 | [IRQIO_CIO] = {.name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt"}, | 73 | {.irq = IRQIO_CIO, .name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt"}, |
| 73 | [IRQIO_QAI] = {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt"}, | 74 | {.irq = IRQIO_QAI, .name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt"}, |
| 74 | [IRQIO_DAS] = {.name = "DAS", .desc = "[I/O] DASD"}, | 75 | {.irq = IRQIO_DAS, .name = "DAS", .desc = "[I/O] DASD"}, |
| 75 | [IRQIO_C15] = {.name = "C15", .desc = "[I/O] 3215"}, | 76 | {.irq = IRQIO_C15, .name = "C15", .desc = "[I/O] 3215"}, |
| 76 | [IRQIO_C70] = {.name = "C70", .desc = "[I/O] 3270"}, | 77 | {.irq = IRQIO_C70, .name = "C70", .desc = "[I/O] 3270"}, |
| 77 | [IRQIO_TAP] = {.name = "TAP", .desc = "[I/O] Tape"}, | 78 | {.irq = IRQIO_TAP, .name = "TAP", .desc = "[I/O] Tape"}, |
| 78 | [IRQIO_VMR] = {.name = "VMR", .desc = "[I/O] Unit Record Devices"}, | 79 | {.irq = IRQIO_VMR, .name = "VMR", .desc = "[I/O] Unit Record Devices"}, |
| 79 | [IRQIO_LCS] = {.name = "LCS", .desc = "[I/O] LCS"}, | 80 | {.irq = IRQIO_LCS, .name = "LCS", .desc = "[I/O] LCS"}, |
| 80 | [IRQIO_CLW] = {.name = "CLW", .desc = "[I/O] CLAW"}, | 81 | {.irq = IRQIO_CLW, .name = "CLW", .desc = "[I/O] CLAW"}, |
| 81 | [IRQIO_CTC] = {.name = "CTC", .desc = "[I/O] CTC"}, | 82 | {.irq = IRQIO_CTC, .name = "CTC", .desc = "[I/O] CTC"}, |
| 82 | [IRQIO_APB] = {.name = "APB", .desc = "[I/O] AP Bus"}, | 83 | {.irq = IRQIO_APB, .name = "APB", .desc = "[I/O] AP Bus"}, |
| 83 | [IRQIO_ADM] = {.name = "ADM", .desc = "[I/O] EADM Subchannel"}, | 84 | {.irq = IRQIO_ADM, .name = "ADM", .desc = "[I/O] EADM Subchannel"}, |
| 84 | [IRQIO_CSC] = {.name = "CSC", .desc = "[I/O] CHSC Subchannel"}, | 85 | {.irq = IRQIO_CSC, .name = "CSC", .desc = "[I/O] CHSC Subchannel"}, |
| 85 | [IRQIO_PCI] = {.name = "PCI", .desc = "[I/O] PCI Interrupt" }, | 86 | {.irq = IRQIO_PCI, .name = "PCI", .desc = "[I/O] PCI Interrupt" }, |
| 86 | [IRQIO_MSI] = {.name = "MSI", .desc = "[I/O] MSI Interrupt" }, | 87 | {.irq = IRQIO_MSI, .name = "MSI", .desc = "[I/O] MSI Interrupt" }, |
| 87 | [IRQIO_VIR] = {.name = "VIR", .desc = "[I/O] Virtual I/O Devices"}, | 88 | {.irq = IRQIO_VIR, .name = "VIR", .desc = "[I/O] Virtual I/O Devices"}, |
| 88 | [IRQIO_VAI] = {.name = "VAI", .desc = "[I/O] Virtual I/O Devices AI"}, | 89 | {.irq = IRQIO_VAI, .name = "VAI", .desc = "[I/O] Virtual I/O Devices AI"}, |
| 89 | [NMI_NMI] = {.name = "NMI", .desc = "[NMI] Machine Check"}, | 90 | {.irq = NMI_NMI, .name = "NMI", .desc = "[NMI] Machine Check"}, |
| 90 | [CPU_RST] = {.name = "RST", .desc = "[CPU] CPU Restart"}, | 91 | {.irq = CPU_RST, .name = "RST", .desc = "[CPU] CPU Restart"}, |
| 91 | }; | 92 | }; |
| 92 | 93 | ||
| 93 | void __init init_IRQ(void) | 94 | void __init init_IRQ(void) |
| @@ -116,33 +117,37 @@ void do_IRQ(struct pt_regs *regs, int irq) | |||
| 116 | */ | 117 | */ |
| 117 | int show_interrupts(struct seq_file *p, void *v) | 118 | int show_interrupts(struct seq_file *p, void *v) |
| 118 | { | 119 | { |
| 119 | int irq = *(loff_t *) v; | 120 | int index = *(loff_t *) v; |
| 120 | int cpu; | 121 | int cpu, irq; |
| 121 | 122 | ||
| 122 | get_online_cpus(); | 123 | get_online_cpus(); |
| 123 | if (irq == 0) { | 124 | if (index == 0) { |
| 124 | seq_puts(p, " "); | 125 | seq_puts(p, " "); |
| 125 | for_each_online_cpu(cpu) | 126 | for_each_online_cpu(cpu) |
| 126 | seq_printf(p, "CPU%d ", cpu); | 127 | seq_printf(p, "CPU%d ", cpu); |
| 127 | seq_putc(p, '\n'); | 128 | seq_putc(p, '\n'); |
| 128 | goto out; | 129 | goto out; |
| 129 | } | 130 | } |
| 130 | if (irq < NR_IRQS) { | 131 | if (index < NR_IRQS) { |
| 131 | if (irq >= NR_IRQS_BASE) | 132 | if (index >= NR_IRQS_BASE) |
| 132 | goto out; | 133 | goto out; |
| 133 | seq_printf(p, "%s: ", irqclass_main_desc[irq].name); | 134 | /* Adjust index to process irqclass_main_desc array entries */ |
| 135 | index--; | ||
| 136 | seq_printf(p, "%s: ", irqclass_main_desc[index].name); | ||
| 137 | irq = irqclass_main_desc[index].irq; | ||
| 134 | for_each_online_cpu(cpu) | 138 | for_each_online_cpu(cpu) |
| 135 | seq_printf(p, "%10u ", kstat_irqs_cpu(irq, cpu)); | 139 | seq_printf(p, "%10u ", kstat_irqs_cpu(irq, cpu)); |
| 136 | seq_putc(p, '\n'); | 140 | seq_putc(p, '\n'); |
| 137 | goto out; | 141 | goto out; |
| 138 | } | 142 | } |
| 139 | for (irq = 0; irq < NR_ARCH_IRQS; irq++) { | 143 | for (index = 0; index < NR_ARCH_IRQS; index++) { |
| 140 | seq_printf(p, "%s: ", irqclass_sub_desc[irq].name); | 144 | seq_printf(p, "%s: ", irqclass_sub_desc[index].name); |
| 145 | irq = irqclass_sub_desc[index].irq; | ||
| 141 | for_each_online_cpu(cpu) | 146 | for_each_online_cpu(cpu) |
| 142 | seq_printf(p, "%10u ", | 147 | seq_printf(p, "%10u ", |
| 143 | per_cpu(irq_stat, cpu).irqs[irq]); | 148 | per_cpu(irq_stat, cpu).irqs[irq]); |
| 144 | if (irqclass_sub_desc[irq].desc) | 149 | if (irqclass_sub_desc[index].desc) |
| 145 | seq_printf(p, " %s", irqclass_sub_desc[irq].desc); | 150 | seq_printf(p, " %s", irqclass_sub_desc[index].desc); |
| 146 | seq_putc(p, '\n'); | 151 | seq_putc(p, '\n'); |
| 147 | } | 152 | } |
| 148 | out: | 153 | out: |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 1e2264b46e4c..ae1d5be7dd88 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
| @@ -501,6 +501,8 @@ static int kdump_mem_notifier(struct notifier_block *nb, | |||
| 501 | { | 501 | { |
| 502 | struct memory_notify *arg = data; | 502 | struct memory_notify *arg = data; |
| 503 | 503 | ||
| 504 | if (action != MEM_GOING_OFFLINE) | ||
| 505 | return NOTIFY_OK; | ||
| 504 | if (arg->start_pfn < PFN_DOWN(resource_size(&crashk_res))) | 506 | if (arg->start_pfn < PFN_DOWN(resource_size(&crashk_res))) |
| 505 | return NOTIFY_BAD; | 507 | return NOTIFY_BAD; |
| 506 | if (arg->start_pfn > PFN_DOWN(crashk_res.end)) | 508 | if (arg->start_pfn > PFN_DOWN(crashk_res.end)) |
diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c index 0ff66a7e29bb..389bc17934b7 100644 --- a/arch/s390/mm/hugetlbpage.c +++ b/arch/s390/mm/hugetlbpage.c | |||
| @@ -10,42 +10,33 @@ | |||
| 10 | 10 | ||
| 11 | static inline pmd_t __pte_to_pmd(pte_t pte) | 11 | static inline pmd_t __pte_to_pmd(pte_t pte) |
| 12 | { | 12 | { |
| 13 | int none, young, prot; | ||
| 14 | pmd_t pmd; | 13 | pmd_t pmd; |
| 15 | 14 | ||
| 16 | /* | 15 | /* |
| 17 | * Convert encoding pte bits pmd bits | 16 | * Convert encoding pte bits pmd bits |
| 18 | * .IR...wrdytp ..R...I...y. | 17 | * .IR...wrdytp dy..R...I...wr |
| 19 | * empty .10...000000 -> ..0...1...0. | 18 | * empty .10...000000 -> 00..0...1...00 |
| 20 | * prot-none, clean, old .11...000001 -> ..0...1...1. | 19 | * prot-none, clean, old .11...000001 -> 00..1...1...00 |
| 21 | * prot-none, clean, young .11...000101 -> ..1...1...1. | 20 | * prot-none, clean, young .11...000101 -> 01..1...1...00 |
| 22 | * prot-none, dirty, old .10...001001 -> ..0...1...1. | 21 | * prot-none, dirty, old .10...001001 -> 10..1...1...00 |
| 23 | * prot-none, dirty, young .10...001101 -> ..1...1...1. | 22 | * prot-none, dirty, young .10...001101 -> 11..1...1...00 |
| 24 | * read-only, clean, old .11...010001 -> ..1...1...0. | 23 | * read-only, clean, old .11...010001 -> 00..1...1...01 |
| 25 | * read-only, clean, young .01...010101 -> ..1...0...1. | 24 | * read-only, clean, young .01...010101 -> 01..1...0...01 |
| 26 | * read-only, dirty, old .11...011001 -> ..1...1...0. | 25 | * read-only, dirty, old .11...011001 -> 10..1...1...01 |
| 27 | * read-only, dirty, young .01...011101 -> ..1...0...1. | 26 | * read-only, dirty, young .01...011101 -> 11..1...0...01 |
| 28 | * read-write, clean, old .11...110001 -> ..0...1...0. | 27 | * read-write, clean, old .11...110001 -> 00..0...1...11 |
| 29 | * read-write, clean, young .01...110101 -> ..0...0...1. | 28 | * read-write, clean, young .01...110101 -> 01..0...0...11 |
| 30 | * read-write, dirty, old .10...111001 -> ..0...1...0. | 29 | * read-write, dirty, old .10...111001 -> 10..0...1...11 |
| 31 | * read-write, dirty, young .00...111101 -> ..0...0...1. | 30 | * read-write, dirty, young .00...111101 -> 11..0...0...11 |
| 32 | * Huge ptes are dirty by definition, a clean pte is made dirty | ||
| 33 | * by the conversion. | ||
| 34 | */ | 31 | */ |
| 35 | if (pte_present(pte)) { | 32 | if (pte_present(pte)) { |
| 36 | pmd_val(pmd) = pte_val(pte) & PAGE_MASK; | 33 | pmd_val(pmd) = pte_val(pte) & PAGE_MASK; |
| 37 | if (pte_val(pte) & _PAGE_INVALID) | 34 | pmd_val(pmd) |= (pte_val(pte) & _PAGE_READ) >> 4; |
| 38 | pmd_val(pmd) |= _SEGMENT_ENTRY_INVALID; | 35 | pmd_val(pmd) |= (pte_val(pte) & _PAGE_WRITE) >> 4; |
| 39 | none = (pte_val(pte) & _PAGE_PRESENT) && | 36 | pmd_val(pmd) |= (pte_val(pte) & _PAGE_INVALID) >> 5; |
| 40 | !(pte_val(pte) & _PAGE_READ) && | 37 | pmd_val(pmd) |= (pte_val(pte) & _PAGE_PROTECT); |
| 41 | !(pte_val(pte) & _PAGE_WRITE); | 38 | pmd_val(pmd) |= (pte_val(pte) & _PAGE_DIRTY) << 10; |
| 42 | prot = (pte_val(pte) & _PAGE_PROTECT) && | 39 | pmd_val(pmd) |= (pte_val(pte) & _PAGE_YOUNG) << 10; |
| 43 | !(pte_val(pte) & _PAGE_WRITE); | ||
| 44 | young = pte_val(pte) & _PAGE_YOUNG; | ||
| 45 | if (none || young) | ||
| 46 | pmd_val(pmd) |= _SEGMENT_ENTRY_YOUNG; | ||
| 47 | if (prot || (none && young)) | ||
| 48 | pmd_val(pmd) |= _SEGMENT_ENTRY_PROTECT; | ||
| 49 | } else | 40 | } else |
| 50 | pmd_val(pmd) = _SEGMENT_ENTRY_INVALID; | 41 | pmd_val(pmd) = _SEGMENT_ENTRY_INVALID; |
| 51 | return pmd; | 42 | return pmd; |
| @@ -56,34 +47,31 @@ static inline pte_t __pmd_to_pte(pmd_t pmd) | |||
| 56 | pte_t pte; | 47 | pte_t pte; |
| 57 | 48 | ||
| 58 | /* | 49 | /* |
| 59 | * Convert encoding pmd bits pte bits | 50 | * Convert encoding pmd bits pte bits |
| 60 | * ..R...I...y. .IR...wrdytp | 51 | * dy..R...I...wr .IR...wrdytp |
| 61 | * empty ..0...1...0. -> .10...000000 | 52 | * empty 00..0...1...00 -> .10...001100 |
| 62 | * prot-none, old ..0...1...1. -> .10...001001 | 53 | * prot-none, clean, old 00..0...1...00 -> .10...000001 |
| 63 | * prot-none, young ..1...1...1. -> .10...001101 | 54 | * prot-none, clean, young 01..0...1...00 -> .10...000101 |
| 64 | * read-only, old ..1...1...0. -> .11...011001 | 55 | * prot-none, dirty, old 10..0...1...00 -> .10...001001 |
| 65 | * read-only, young ..1...0...1. -> .01...011101 | 56 | * prot-none, dirty, young 11..0...1...00 -> .10...001101 |
| 66 | * read-write, old ..0...1...0. -> .10...111001 | 57 | * read-only, clean, old 00..1...1...01 -> .11...010001 |
| 67 | * read-write, young ..0...0...1. -> .00...111101 | 58 | * read-only, clean, young 01..1...1...01 -> .11...010101 |
| 68 | * Huge ptes are dirty by definition | 59 | * read-only, dirty, old 10..1...1...01 -> .11...011001 |
| 60 | * read-only, dirty, young 11..1...1...01 -> .11...011101 | ||
| 61 | * read-write, clean, old 00..0...1...11 -> .10...110001 | ||
| 62 | * read-write, clean, young 01..0...1...11 -> .10...110101 | ||
| 63 | * read-write, dirty, old 10..0...1...11 -> .10...111001 | ||
| 64 | * read-write, dirty, young 11..0...1...11 -> .10...111101 | ||
| 69 | */ | 65 | */ |
| 70 | if (pmd_present(pmd)) { | 66 | if (pmd_present(pmd)) { |
| 71 | pte_val(pte) = _PAGE_PRESENT | _PAGE_LARGE | _PAGE_DIRTY | | 67 | pte_val(pte) = pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN_LARGE; |
| 72 | (pmd_val(pmd) & PAGE_MASK); | 68 | pte_val(pte) |= _PAGE_LARGE | _PAGE_PRESENT; |
| 73 | if (pmd_val(pmd) & _SEGMENT_ENTRY_INVALID) | 69 | pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_READ) << 4; |
| 74 | pte_val(pte) |= _PAGE_INVALID; | 70 | pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_WRITE) << 4; |
| 75 | if (pmd_prot_none(pmd)) { | 71 | pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_INVALID) << 5; |
| 76 | if (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT) | 72 | pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT); |
| 77 | pte_val(pte) |= _PAGE_YOUNG; | 73 | pmd_val(pmd) |= (pte_val(pte) & _PAGE_DIRTY) << 10; |
| 78 | } else { | 74 | pmd_val(pmd) |= (pte_val(pte) & _PAGE_YOUNG) << 10; |
| 79 | pte_val(pte) |= _PAGE_READ; | ||
| 80 | if (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT) | ||
| 81 | pte_val(pte) |= _PAGE_PROTECT; | ||
| 82 | else | ||
| 83 | pte_val(pte) |= _PAGE_WRITE; | ||
| 84 | if (pmd_val(pmd) & _SEGMENT_ENTRY_YOUNG) | ||
| 85 | pte_val(pte) |= _PAGE_YOUNG; | ||
| 86 | } | ||
| 87 | } else | 75 | } else |
| 88 | pte_val(pte) = _PAGE_INVALID; | 76 | pte_val(pte) = _PAGE_INVALID; |
| 89 | return pte; | 77 | return pte; |
| @@ -96,6 +84,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, | |||
| 96 | 84 | ||
| 97 | pmd = __pte_to_pmd(pte); | 85 | pmd = __pte_to_pmd(pte); |
| 98 | if (!MACHINE_HAS_HPAGE) { | 86 | if (!MACHINE_HAS_HPAGE) { |
| 87 | /* Emulated huge ptes loose the dirty and young bit */ | ||
| 99 | pmd_val(pmd) &= ~_SEGMENT_ENTRY_ORIGIN; | 88 | pmd_val(pmd) &= ~_SEGMENT_ENTRY_ORIGIN; |
| 100 | pmd_val(pmd) |= pte_page(pte)[1].index; | 89 | pmd_val(pmd) |= pte_page(pte)[1].index; |
| 101 | } else | 90 | } else |
| @@ -113,6 +102,8 @@ pte_t huge_ptep_get(pte_t *ptep) | |||
| 113 | origin = pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN; | 102 | origin = pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN; |
| 114 | pmd_val(pmd) &= ~_SEGMENT_ENTRY_ORIGIN; | 103 | pmd_val(pmd) &= ~_SEGMENT_ENTRY_ORIGIN; |
| 115 | pmd_val(pmd) |= *(unsigned long *) origin; | 104 | pmd_val(pmd) |= *(unsigned long *) origin; |
| 105 | /* Emulated huge ptes are young and dirty by definition */ | ||
| 106 | pmd_val(pmd) |= _SEGMENT_ENTRY_YOUNG | _SEGMENT_ENTRY_DIRTY; | ||
| 116 | } | 107 | } |
| 117 | return __pmd_to_pte(pmd); | 108 | return __pmd_to_pte(pmd); |
| 118 | } | 109 | } |
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 37b8241ec784..19daa53a3da4 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
| @@ -1279,6 +1279,7 @@ static unsigned long page_table_realloc_pmd(struct mmu_gather *tlb, | |||
| 1279 | { | 1279 | { |
| 1280 | unsigned long next, *table, *new; | 1280 | unsigned long next, *table, *new; |
| 1281 | struct page *page; | 1281 | struct page *page; |
| 1282 | spinlock_t *ptl; | ||
| 1282 | pmd_t *pmd; | 1283 | pmd_t *pmd; |
| 1283 | 1284 | ||
| 1284 | pmd = pmd_offset(pud, addr); | 1285 | pmd = pmd_offset(pud, addr); |
| @@ -1296,7 +1297,7 @@ again: | |||
| 1296 | if (!new) | 1297 | if (!new) |
| 1297 | return -ENOMEM; | 1298 | return -ENOMEM; |
| 1298 | 1299 | ||
| 1299 | spin_lock(&mm->page_table_lock); | 1300 | ptl = pmd_lock(mm, pmd); |
| 1300 | if (likely((unsigned long *) pmd_deref(*pmd) == table)) { | 1301 | if (likely((unsigned long *) pmd_deref(*pmd) == table)) { |
| 1301 | /* Nuke pmd entry pointing to the "short" page table */ | 1302 | /* Nuke pmd entry pointing to the "short" page table */ |
| 1302 | pmdp_flush_lazy(mm, addr, pmd); | 1303 | pmdp_flush_lazy(mm, addr, pmd); |
| @@ -1310,7 +1311,7 @@ again: | |||
| 1310 | page_table_free_rcu(tlb, table); | 1311 | page_table_free_rcu(tlb, table); |
| 1311 | new = NULL; | 1312 | new = NULL; |
| 1312 | } | 1313 | } |
| 1313 | spin_unlock(&mm->page_table_lock); | 1314 | spin_unlock(ptl); |
| 1314 | if (new) { | 1315 | if (new) { |
| 1315 | page_table_free_pgste(new); | 1316 | page_table_free_pgste(new); |
| 1316 | goto again; | 1317 | goto again; |
| @@ -1432,6 +1433,9 @@ int pmdp_set_access_flags(struct vm_area_struct *vma, | |||
| 1432 | { | 1433 | { |
| 1433 | VM_BUG_ON(address & ~HPAGE_PMD_MASK); | 1434 | VM_BUG_ON(address & ~HPAGE_PMD_MASK); |
| 1434 | 1435 | ||
| 1436 | entry = pmd_mkyoung(entry); | ||
| 1437 | if (dirty) | ||
| 1438 | entry = pmd_mkdirty(entry); | ||
| 1435 | if (pmd_same(*pmdp, entry)) | 1439 | if (pmd_same(*pmdp, entry)) |
| 1436 | return 0; | 1440 | return 0; |
| 1437 | pmdp_invalidate(vma, address, pmdp); | 1441 | pmdp_invalidate(vma, address, pmdp); |
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 30de42730b2f..2fa7b14b9c08 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c | |||
| @@ -15,8 +15,8 @@ | |||
| 15 | * Thomas Klein | 15 | * Thomas Klein |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #define COMPONENT "zPCI" | 18 | #define KMSG_COMPONENT "zpci" |
| 19 | #define pr_fmt(fmt) COMPONENT ": " fmt | 19 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
| 20 | 20 | ||
| 21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
| 22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c index 96545d7659fd..6e22a247de9b 100644 --- a/arch/s390/pci/pci_clp.c +++ b/arch/s390/pci/pci_clp.c | |||
| @@ -5,8 +5,8 @@ | |||
| 5 | * Jan Glauber <jang@linux.vnet.ibm.com> | 5 | * Jan Glauber <jang@linux.vnet.ibm.com> |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #define COMPONENT "zPCI" | 8 | #define KMSG_COMPONENT "zpci" |
| 9 | #define pr_fmt(fmt) COMPONENT ": " fmt | 9 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
| 10 | 10 | ||
| 11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
| 12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c index c5c66840ac00..eec598c5939f 100644 --- a/arch/s390/pci/pci_debug.c +++ b/arch/s390/pci/pci_debug.c | |||
| @@ -5,8 +5,8 @@ | |||
| 5 | * Jan Glauber <jang@linux.vnet.ibm.com> | 5 | * Jan Glauber <jang@linux.vnet.ibm.com> |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #define COMPONENT "zPCI" | 8 | #define KMSG_COMPONENT "zpci" |
| 9 | #define pr_fmt(fmt) COMPONENT ": " fmt | 9 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
| 10 | 10 | ||
| 11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
| 12 | #include <linux/seq_file.h> | 12 | #include <linux/seq_file.h> |
diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c index f91c03119804..4cbb29a4d615 100644 --- a/arch/s390/pci/pci_dma.c +++ b/arch/s390/pci/pci_dma.c | |||
| @@ -16,6 +16,13 @@ | |||
| 16 | 16 | ||
| 17 | static struct kmem_cache *dma_region_table_cache; | 17 | static struct kmem_cache *dma_region_table_cache; |
| 18 | static struct kmem_cache *dma_page_table_cache; | 18 | static struct kmem_cache *dma_page_table_cache; |
| 19 | static int s390_iommu_strict; | ||
| 20 | |||
| 21 | static int zpci_refresh_global(struct zpci_dev *zdev) | ||
| 22 | { | ||
| 23 | return zpci_refresh_trans((u64) zdev->fh << 32, zdev->start_dma, | ||
| 24 | zdev->iommu_pages * PAGE_SIZE); | ||
| 25 | } | ||
| 19 | 26 | ||
| 20 | static unsigned long *dma_alloc_cpu_table(void) | 27 | static unsigned long *dma_alloc_cpu_table(void) |
| 21 | { | 28 | { |
| @@ -155,18 +162,15 @@ static int dma_update_trans(struct zpci_dev *zdev, unsigned long pa, | |||
| 155 | } | 162 | } |
| 156 | 163 | ||
| 157 | /* | 164 | /* |
| 158 | * rpcit is not required to establish new translations when previously | 165 | * With zdev->tlb_refresh == 0, rpcit is not required to establish new |
| 159 | * invalid translation-table entries are validated, however it is | 166 | * translations when previously invalid translation-table entries are |
| 160 | * required when altering previously valid entries. | 167 | * validated. With lazy unmap, it also is skipped for previously valid |
| 168 | * entries, but a global rpcit is then required before any address can | ||
| 169 | * be re-used, i.e. after each iommu bitmap wrap-around. | ||
| 161 | */ | 170 | */ |
| 162 | if (!zdev->tlb_refresh && | 171 | if (!zdev->tlb_refresh && |
| 163 | ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID)) | 172 | (!s390_iommu_strict || |
| 164 | /* | 173 | ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID))) |
| 165 | * TODO: also need to check that the old entry is indeed INVALID | ||
| 166 | * and not only for one page but for the whole range... | ||
| 167 | * -> now we WARN_ON in that case but with lazy unmap that | ||
| 168 | * needs to be redone! | ||
| 169 | */ | ||
| 170 | goto no_refresh; | 174 | goto no_refresh; |
| 171 | 175 | ||
| 172 | rc = zpci_refresh_trans((u64) zdev->fh << 32, start_dma_addr, | 176 | rc = zpci_refresh_trans((u64) zdev->fh << 32, start_dma_addr, |
| @@ -220,16 +224,21 @@ static unsigned long __dma_alloc_iommu(struct zpci_dev *zdev, | |||
| 220 | static unsigned long dma_alloc_iommu(struct zpci_dev *zdev, int size) | 224 | static unsigned long dma_alloc_iommu(struct zpci_dev *zdev, int size) |
| 221 | { | 225 | { |
| 222 | unsigned long offset, flags; | 226 | unsigned long offset, flags; |
| 227 | int wrap = 0; | ||
| 223 | 228 | ||
| 224 | spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags); | 229 | spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags); |
| 225 | offset = __dma_alloc_iommu(zdev, zdev->next_bit, size); | 230 | offset = __dma_alloc_iommu(zdev, zdev->next_bit, size); |
| 226 | if (offset == -1) | 231 | if (offset == -1) { |
| 232 | /* wrap-around */ | ||
| 227 | offset = __dma_alloc_iommu(zdev, 0, size); | 233 | offset = __dma_alloc_iommu(zdev, 0, size); |
| 234 | wrap = 1; | ||
| 235 | } | ||
| 228 | 236 | ||
| 229 | if (offset != -1) { | 237 | if (offset != -1) { |
| 230 | zdev->next_bit = offset + size; | 238 | zdev->next_bit = offset + size; |
| 231 | if (zdev->next_bit >= zdev->iommu_pages) | 239 | if (!zdev->tlb_refresh && !s390_iommu_strict && wrap) |
| 232 | zdev->next_bit = 0; | 240 | /* global flush after wrap-around with lazy unmap */ |
| 241 | zpci_refresh_global(zdev); | ||
| 233 | } | 242 | } |
| 234 | spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags); | 243 | spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags); |
| 235 | return offset; | 244 | return offset; |
| @@ -243,7 +252,11 @@ static void dma_free_iommu(struct zpci_dev *zdev, unsigned long offset, int size | |||
| 243 | if (!zdev->iommu_bitmap) | 252 | if (!zdev->iommu_bitmap) |
| 244 | goto out; | 253 | goto out; |
| 245 | bitmap_clear(zdev->iommu_bitmap, offset, size); | 254 | bitmap_clear(zdev->iommu_bitmap, offset, size); |
| 246 | if (offset >= zdev->next_bit) | 255 | /* |
| 256 | * Lazy flush for unmap: need to move next_bit to avoid address re-use | ||
| 257 | * until wrap-around. | ||
| 258 | */ | ||
| 259 | if (!s390_iommu_strict && offset >= zdev->next_bit) | ||
| 247 | zdev->next_bit = offset + size; | 260 | zdev->next_bit = offset + size; |
| 248 | out: | 261 | out: |
| 249 | spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags); | 262 | spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags); |
| @@ -504,3 +517,12 @@ struct dma_map_ops s390_dma_ops = { | |||
| 504 | /* dma_supported is unconditionally true without a callback */ | 517 | /* dma_supported is unconditionally true without a callback */ |
| 505 | }; | 518 | }; |
| 506 | EXPORT_SYMBOL_GPL(s390_dma_ops); | 519 | EXPORT_SYMBOL_GPL(s390_dma_ops); |
| 520 | |||
| 521 | static int __init s390_iommu_setup(char *str) | ||
| 522 | { | ||
| 523 | if (!strncmp(str, "strict", 6)) | ||
| 524 | s390_iommu_strict = 1; | ||
| 525 | return 0; | ||
| 526 | } | ||
| 527 | |||
| 528 | __setup("s390_iommu=", s390_iommu_setup); | ||
diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c index 6d7f5a3016ca..460fdb21cf61 100644 --- a/arch/s390/pci/pci_event.c +++ b/arch/s390/pci/pci_event.c | |||
| @@ -5,8 +5,8 @@ | |||
| 5 | * Jan Glauber <jang@linux.vnet.ibm.com> | 5 | * Jan Glauber <jang@linux.vnet.ibm.com> |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #define COMPONENT "zPCI" | 8 | #define KMSG_COMPONENT "zpci" |
| 9 | #define pr_fmt(fmt) COMPONENT ": " fmt | 9 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
| 10 | 10 | ||
| 11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
| 12 | #include <linux/pci.h> | 12 | #include <linux/pci.h> |
diff --git a/arch/s390/pci/pci_sysfs.c b/arch/s390/pci/pci_sysfs.c index 9190214b8702..fa3ce891e597 100644 --- a/arch/s390/pci/pci_sysfs.c +++ b/arch/s390/pci/pci_sysfs.c | |||
| @@ -5,8 +5,8 @@ | |||
| 5 | * Jan Glauber <jang@linux.vnet.ibm.com> | 5 | * Jan Glauber <jang@linux.vnet.ibm.com> |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #define COMPONENT "zPCI" | 8 | #define KMSG_COMPONENT "zpci" |
| 9 | #define pr_fmt(fmt) COMPONENT ": " fmt | 9 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
| 10 | 10 | ||
| 11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
| 12 | #include <linux/stat.h> | 12 | #include <linux/stat.h> |
diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c index d1332d2f8730..d77e46bca54c 100644 --- a/drivers/pci/hotplug/s390_pci_hpc.c +++ b/drivers/pci/hotplug/s390_pci_hpc.c | |||
| @@ -7,8 +7,8 @@ | |||
| 7 | * Jan Glauber <jang@linux.vnet.ibm.com> | 7 | * Jan Glauber <jang@linux.vnet.ibm.com> |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #define COMPONENT "zPCI hpc" | 10 | #define KMSG_COMPONENT "zpci" |
| 11 | #define pr_fmt(fmt) COMPONENT ": " fmt | 11 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
| 12 | 12 | ||
| 13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 1eef0f586950..5df05f26b7d9 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
| @@ -42,8 +42,10 @@ | |||
| 42 | * SECTION: exported variables of dasd.c | 42 | * SECTION: exported variables of dasd.c |
| 43 | */ | 43 | */ |
| 44 | debug_info_t *dasd_debug_area; | 44 | debug_info_t *dasd_debug_area; |
| 45 | EXPORT_SYMBOL(dasd_debug_area); | ||
| 45 | static struct dentry *dasd_debugfs_root_entry; | 46 | static struct dentry *dasd_debugfs_root_entry; |
| 46 | struct dasd_discipline *dasd_diag_discipline_pointer; | 47 | struct dasd_discipline *dasd_diag_discipline_pointer; |
| 48 | EXPORT_SYMBOL(dasd_diag_discipline_pointer); | ||
| 47 | void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *); | 49 | void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *); |
| 48 | 50 | ||
| 49 | MODULE_AUTHOR("Holger Smolinski <Holger.Smolinski@de.ibm.com>"); | 51 | MODULE_AUTHOR("Holger Smolinski <Holger.Smolinski@de.ibm.com>"); |
| @@ -164,6 +166,7 @@ struct dasd_block *dasd_alloc_block(void) | |||
| 164 | 166 | ||
| 165 | return block; | 167 | return block; |
| 166 | } | 168 | } |
| 169 | EXPORT_SYMBOL_GPL(dasd_alloc_block); | ||
| 167 | 170 | ||
| 168 | /* | 171 | /* |
| 169 | * Free memory of a device structure. | 172 | * Free memory of a device structure. |
| @@ -172,6 +175,7 @@ void dasd_free_block(struct dasd_block *block) | |||
| 172 | { | 175 | { |
| 173 | kfree(block); | 176 | kfree(block); |
| 174 | } | 177 | } |
| 178 | EXPORT_SYMBOL_GPL(dasd_free_block); | ||
| 175 | 179 | ||
| 176 | /* | 180 | /* |
| 177 | * Make a new device known to the system. | 181 | * Make a new device known to the system. |
| @@ -281,10 +285,15 @@ static int dasd_state_basic_to_known(struct dasd_device *device) | |||
| 281 | { | 285 | { |
| 282 | int rc; | 286 | int rc; |
| 283 | 287 | ||
| 288 | if (device->discipline->basic_to_known) { | ||
| 289 | rc = device->discipline->basic_to_known(device); | ||
| 290 | if (rc) | ||
| 291 | return rc; | ||
| 292 | } | ||
| 293 | |||
| 284 | if (device->block) { | 294 | if (device->block) { |
| 285 | dasd_profile_exit(&device->block->profile); | 295 | dasd_profile_exit(&device->block->profile); |
| 286 | if (device->block->debugfs_dentry) | 296 | debugfs_remove(device->block->debugfs_dentry); |
| 287 | debugfs_remove(device->block->debugfs_dentry); | ||
| 288 | dasd_gendisk_free(device->block); | 297 | dasd_gendisk_free(device->block); |
| 289 | dasd_block_clear_timer(device->block); | 298 | dasd_block_clear_timer(device->block); |
| 290 | } | 299 | } |
| @@ -293,9 +302,7 @@ static int dasd_state_basic_to_known(struct dasd_device *device) | |||
| 293 | return rc; | 302 | return rc; |
| 294 | dasd_device_clear_timer(device); | 303 | dasd_device_clear_timer(device); |
| 295 | dasd_profile_exit(&device->profile); | 304 | dasd_profile_exit(&device->profile); |
| 296 | if (device->debugfs_dentry) | 305 | debugfs_remove(device->debugfs_dentry); |
| 297 | debugfs_remove(device->debugfs_dentry); | ||
| 298 | |||
| 299 | DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device); | 306 | DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device); |
| 300 | if (device->debug_area != NULL) { | 307 | if (device->debug_area != NULL) { |
| 301 | debug_unregister(device->debug_area); | 308 | debug_unregister(device->debug_area); |
| @@ -374,11 +381,6 @@ static int dasd_state_ready_to_basic(struct dasd_device *device) | |||
| 374 | { | 381 | { |
| 375 | int rc; | 382 | int rc; |
| 376 | 383 | ||
| 377 | if (device->discipline->ready_to_basic) { | ||
| 378 | rc = device->discipline->ready_to_basic(device); | ||
| 379 | if (rc) | ||
| 380 | return rc; | ||
| 381 | } | ||
| 382 | device->state = DASD_STATE_BASIC; | 384 | device->state = DASD_STATE_BASIC; |
| 383 | if (device->block) { | 385 | if (device->block) { |
| 384 | struct dasd_block *block = device->block; | 386 | struct dasd_block *block = device->block; |
| @@ -579,6 +581,7 @@ void dasd_kick_device(struct dasd_device *device) | |||
| 579 | /* queue call to dasd_kick_device to the kernel event daemon. */ | 581 | /* queue call to dasd_kick_device to the kernel event daemon. */ |
| 580 | schedule_work(&device->kick_work); | 582 | schedule_work(&device->kick_work); |
| 581 | } | 583 | } |
| 584 | EXPORT_SYMBOL(dasd_kick_device); | ||
| 582 | 585 | ||
| 583 | /* | 586 | /* |
| 584 | * dasd_reload_device will schedule a call do do_reload_device to the kernel | 587 | * dasd_reload_device will schedule a call do do_reload_device to the kernel |
| @@ -639,6 +642,7 @@ void dasd_set_target_state(struct dasd_device *device, int target) | |||
| 639 | mutex_unlock(&device->state_mutex); | 642 | mutex_unlock(&device->state_mutex); |
| 640 | dasd_put_device(device); | 643 | dasd_put_device(device); |
| 641 | } | 644 | } |
| 645 | EXPORT_SYMBOL(dasd_set_target_state); | ||
| 642 | 646 | ||
| 643 | /* | 647 | /* |
| 644 | * Enable devices with device numbers in [from..to]. | 648 | * Enable devices with device numbers in [from..to]. |
| @@ -661,6 +665,7 @@ void dasd_enable_device(struct dasd_device *device) | |||
| 661 | if (device->discipline->kick_validate) | 665 | if (device->discipline->kick_validate) |
| 662 | device->discipline->kick_validate(device); | 666 | device->discipline->kick_validate(device); |
| 663 | } | 667 | } |
| 668 | EXPORT_SYMBOL(dasd_enable_device); | ||
| 664 | 669 | ||
| 665 | /* | 670 | /* |
| 666 | * SECTION: device operation (interrupt handler, start i/o, term i/o ...) | 671 | * SECTION: device operation (interrupt handler, start i/o, term i/o ...) |
| @@ -972,37 +977,37 @@ static void dasd_stats_seq_print(struct seq_file *m, | |||
| 972 | seq_printf(m, "total_sectors %u\n", data->dasd_io_sects); | 977 | seq_printf(m, "total_sectors %u\n", data->dasd_io_sects); |
| 973 | seq_printf(m, "total_pav %u\n", data->dasd_io_alias); | 978 | seq_printf(m, "total_pav %u\n", data->dasd_io_alias); |
| 974 | seq_printf(m, "total_hpf %u\n", data->dasd_io_tpm); | 979 | seq_printf(m, "total_hpf %u\n", data->dasd_io_tpm); |
| 975 | seq_printf(m, "histogram_sectors "); | 980 | seq_puts(m, "histogram_sectors "); |
| 976 | dasd_stats_array(m, data->dasd_io_secs); | 981 | dasd_stats_array(m, data->dasd_io_secs); |
| 977 | seq_printf(m, "histogram_io_times "); | 982 | seq_puts(m, "histogram_io_times "); |
| 978 | dasd_stats_array(m, data->dasd_io_times); | 983 | dasd_stats_array(m, data->dasd_io_times); |
| 979 | seq_printf(m, "histogram_io_times_weighted "); | 984 | seq_puts(m, "histogram_io_times_weighted "); |
| 980 | dasd_stats_array(m, data->dasd_io_timps); | 985 | dasd_stats_array(m, data->dasd_io_timps); |
| 981 | seq_printf(m, "histogram_time_build_to_ssch "); | 986 | seq_puts(m, "histogram_time_build_to_ssch "); |
| 982 | dasd_stats_array(m, data->dasd_io_time1); | 987 | dasd_stats_array(m, data->dasd_io_time1); |
| 983 | seq_printf(m, "histogram_time_ssch_to_irq "); | 988 | seq_puts(m, "histogram_time_ssch_to_irq "); |
| 984 | dasd_stats_array(m, data->dasd_io_time2); | 989 | dasd_stats_array(m, data->dasd_io_time2); |
| 985 | seq_printf(m, "histogram_time_ssch_to_irq_weighted "); | 990 | seq_puts(m, "histogram_time_ssch_to_irq_weighted "); |
| 986 | dasd_stats_array(m, data->dasd_io_time2ps); | 991 | dasd_stats_array(m, data->dasd_io_time2ps); |
| 987 | seq_printf(m, "histogram_time_irq_to_end "); | 992 | seq_puts(m, "histogram_time_irq_to_end "); |
| 988 | dasd_stats_array(m, data->dasd_io_time3); | 993 | dasd_stats_array(m, data->dasd_io_time3); |
| 989 | seq_printf(m, "histogram_ccw_queue_length "); | 994 | seq_puts(m, "histogram_ccw_queue_length "); |
| 990 | dasd_stats_array(m, data->dasd_io_nr_req); | 995 | dasd_stats_array(m, data->dasd_io_nr_req); |
| 991 | seq_printf(m, "total_read_requests %u\n", data->dasd_read_reqs); | 996 | seq_printf(m, "total_read_requests %u\n", data->dasd_read_reqs); |
| 992 | seq_printf(m, "total_read_sectors %u\n", data->dasd_read_sects); | 997 | seq_printf(m, "total_read_sectors %u\n", data->dasd_read_sects); |
| 993 | seq_printf(m, "total_read_pav %u\n", data->dasd_read_alias); | 998 | seq_printf(m, "total_read_pav %u\n", data->dasd_read_alias); |
| 994 | seq_printf(m, "total_read_hpf %u\n", data->dasd_read_tpm); | 999 | seq_printf(m, "total_read_hpf %u\n", data->dasd_read_tpm); |
| 995 | seq_printf(m, "histogram_read_sectors "); | 1000 | seq_puts(m, "histogram_read_sectors "); |
| 996 | dasd_stats_array(m, data->dasd_read_secs); | 1001 | dasd_stats_array(m, data->dasd_read_secs); |
| 997 | seq_printf(m, "histogram_read_times "); | 1002 | seq_puts(m, "histogram_read_times "); |
| 998 | dasd_stats_array(m, data->dasd_read_times); | 1003 | dasd_stats_array(m, data->dasd_read_times); |
| 999 | seq_printf(m, "histogram_read_time_build_to_ssch "); | 1004 | seq_puts(m, "histogram_read_time_build_to_ssch "); |
| 1000 | dasd_stats_array(m, data->dasd_read_time1); | 1005 | dasd_stats_array(m, data->dasd_read_time1); |
| 1001 | seq_printf(m, "histogram_read_time_ssch_to_irq "); | 1006 | seq_puts(m, "histogram_read_time_ssch_to_irq "); |
| 1002 | dasd_stats_array(m, data->dasd_read_time2); | 1007 | dasd_stats_array(m, data->dasd_read_time2); |
| 1003 | seq_printf(m, "histogram_read_time_irq_to_end "); | 1008 | seq_puts(m, "histogram_read_time_irq_to_end "); |
| 1004 | dasd_stats_array(m, data->dasd_read_time3); | 1009 | dasd_stats_array(m, data->dasd_read_time3); |
| 1005 | seq_printf(m, "histogram_read_ccw_queue_length "); | 1010 | seq_puts(m, "histogram_read_ccw_queue_length "); |
| 1006 | dasd_stats_array(m, data->dasd_read_nr_req); | 1011 | dasd_stats_array(m, data->dasd_read_nr_req); |
| 1007 | } | 1012 | } |
| 1008 | 1013 | ||
| @@ -1016,7 +1021,7 @@ static int dasd_stats_show(struct seq_file *m, void *v) | |||
| 1016 | data = profile->data; | 1021 | data = profile->data; |
| 1017 | if (!data) { | 1022 | if (!data) { |
| 1018 | spin_unlock_bh(&profile->lock); | 1023 | spin_unlock_bh(&profile->lock); |
| 1019 | seq_printf(m, "disabled\n"); | 1024 | seq_puts(m, "disabled\n"); |
| 1020 | return 0; | 1025 | return 0; |
| 1021 | } | 1026 | } |
| 1022 | dasd_stats_seq_print(m, data); | 1027 | dasd_stats_seq_print(m, data); |
| @@ -1069,7 +1074,7 @@ static ssize_t dasd_stats_global_write(struct file *file, | |||
| 1069 | static int dasd_stats_global_show(struct seq_file *m, void *v) | 1074 | static int dasd_stats_global_show(struct seq_file *m, void *v) |
| 1070 | { | 1075 | { |
| 1071 | if (!dasd_global_profile_level) { | 1076 | if (!dasd_global_profile_level) { |
| 1072 | seq_printf(m, "disabled\n"); | 1077 | seq_puts(m, "disabled\n"); |
| 1073 | return 0; | 1078 | return 0; |
| 1074 | } | 1079 | } |
| 1075 | dasd_stats_seq_print(m, &dasd_global_profile_data); | 1080 | dasd_stats_seq_print(m, &dasd_global_profile_data); |
| @@ -1111,23 +1116,17 @@ static void dasd_profile_init(struct dasd_profile *profile, | |||
| 1111 | static void dasd_profile_exit(struct dasd_profile *profile) | 1116 | static void dasd_profile_exit(struct dasd_profile *profile) |
| 1112 | { | 1117 | { |
| 1113 | dasd_profile_off(profile); | 1118 | dasd_profile_off(profile); |
| 1114 | if (profile->dentry) { | 1119 | debugfs_remove(profile->dentry); |
| 1115 | debugfs_remove(profile->dentry); | 1120 | profile->dentry = NULL; |
| 1116 | profile->dentry = NULL; | ||
| 1117 | } | ||
| 1118 | } | 1121 | } |
| 1119 | 1122 | ||
| 1120 | static void dasd_statistics_removeroot(void) | 1123 | static void dasd_statistics_removeroot(void) |
| 1121 | { | 1124 | { |
| 1122 | dasd_global_profile_level = DASD_PROFILE_OFF; | 1125 | dasd_global_profile_level = DASD_PROFILE_OFF; |
| 1123 | if (dasd_global_profile_dentry) { | 1126 | debugfs_remove(dasd_global_profile_dentry); |
| 1124 | debugfs_remove(dasd_global_profile_dentry); | 1127 | dasd_global_profile_dentry = NULL; |
| 1125 | dasd_global_profile_dentry = NULL; | 1128 | debugfs_remove(dasd_debugfs_global_entry); |
| 1126 | } | 1129 | debugfs_remove(dasd_debugfs_root_entry); |
| 1127 | if (dasd_debugfs_global_entry) | ||
| 1128 | debugfs_remove(dasd_debugfs_global_entry); | ||
| 1129 | if (dasd_debugfs_root_entry) | ||
| 1130 | debugfs_remove(dasd_debugfs_root_entry); | ||
| 1131 | } | 1130 | } |
| 1132 | 1131 | ||
| 1133 | static void dasd_statistics_createroot(void) | 1132 | static void dasd_statistics_createroot(void) |
| @@ -1178,7 +1177,7 @@ static void dasd_statistics_removeroot(void) | |||
| 1178 | 1177 | ||
| 1179 | int dasd_stats_generic_show(struct seq_file *m, void *v) | 1178 | int dasd_stats_generic_show(struct seq_file *m, void *v) |
| 1180 | { | 1179 | { |
| 1181 | seq_printf(m, "Statistics are not activated in this kernel\n"); | 1180 | seq_puts(m, "Statistics are not activated in this kernel\n"); |
| 1182 | return 0; | 1181 | return 0; |
| 1183 | } | 1182 | } |
| 1184 | 1183 | ||
| @@ -1243,6 +1242,7 @@ struct dasd_ccw_req *dasd_kmalloc_request(int magic, int cplength, | |||
| 1243 | dasd_get_device(device); | 1242 | dasd_get_device(device); |
| 1244 | return cqr; | 1243 | return cqr; |
| 1245 | } | 1244 | } |
| 1245 | EXPORT_SYMBOL(dasd_kmalloc_request); | ||
| 1246 | 1246 | ||
| 1247 | struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength, | 1247 | struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength, |
| 1248 | int datasize, | 1248 | int datasize, |
| @@ -1282,6 +1282,7 @@ struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength, | |||
| 1282 | dasd_get_device(device); | 1282 | dasd_get_device(device); |
| 1283 | return cqr; | 1283 | return cqr; |
| 1284 | } | 1284 | } |
| 1285 | EXPORT_SYMBOL(dasd_smalloc_request); | ||
| 1285 | 1286 | ||
| 1286 | /* | 1287 | /* |
| 1287 | * Free memory of a channel program. This function needs to free all the | 1288 | * Free memory of a channel program. This function needs to free all the |
| @@ -1304,6 +1305,7 @@ void dasd_kfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device) | |||
| 1304 | kfree(cqr); | 1305 | kfree(cqr); |
| 1305 | dasd_put_device(device); | 1306 | dasd_put_device(device); |
| 1306 | } | 1307 | } |
| 1308 | EXPORT_SYMBOL(dasd_kfree_request); | ||
| 1307 | 1309 | ||
| 1308 | void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device) | 1310 | void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device) |
| 1309 | { | 1311 | { |
| @@ -1314,6 +1316,7 @@ void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device) | |||
| 1314 | spin_unlock_irqrestore(&device->mem_lock, flags); | 1316 | spin_unlock_irqrestore(&device->mem_lock, flags); |
| 1315 | dasd_put_device(device); | 1317 | dasd_put_device(device); |
| 1316 | } | 1318 | } |
| 1319 | EXPORT_SYMBOL(dasd_sfree_request); | ||
| 1317 | 1320 | ||
| 1318 | /* | 1321 | /* |
| 1319 | * Check discipline magic in cqr. | 1322 | * Check discipline magic in cqr. |
| @@ -1391,6 +1394,7 @@ int dasd_term_IO(struct dasd_ccw_req *cqr) | |||
| 1391 | dasd_schedule_device_bh(device); | 1394 | dasd_schedule_device_bh(device); |
| 1392 | return rc; | 1395 | return rc; |
| 1393 | } | 1396 | } |
| 1397 | EXPORT_SYMBOL(dasd_term_IO); | ||
| 1394 | 1398 | ||
| 1395 | /* | 1399 | /* |
| 1396 | * Start the i/o. This start_IO can fail if the channel is really busy. | 1400 | * Start the i/o. This start_IO can fail if the channel is really busy. |
| @@ -1509,6 +1513,7 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) | |||
| 1509 | cqr->intrc = rc; | 1513 | cqr->intrc = rc; |
| 1510 | return rc; | 1514 | return rc; |
| 1511 | } | 1515 | } |
| 1516 | EXPORT_SYMBOL(dasd_start_IO); | ||
| 1512 | 1517 | ||
| 1513 | /* | 1518 | /* |
| 1514 | * Timeout function for dasd devices. This is used for different purposes | 1519 | * Timeout function for dasd devices. This is used for different purposes |
| @@ -1541,6 +1546,7 @@ void dasd_device_set_timer(struct dasd_device *device, int expires) | |||
| 1541 | else | 1546 | else |
| 1542 | mod_timer(&device->timer, jiffies + expires); | 1547 | mod_timer(&device->timer, jiffies + expires); |
| 1543 | } | 1548 | } |
| 1549 | EXPORT_SYMBOL(dasd_device_set_timer); | ||
| 1544 | 1550 | ||
| 1545 | /* | 1551 | /* |
| 1546 | * Clear timeout for a device. | 1552 | * Clear timeout for a device. |
| @@ -1549,6 +1555,7 @@ void dasd_device_clear_timer(struct dasd_device *device) | |||
| 1549 | { | 1555 | { |
| 1550 | del_timer(&device->timer); | 1556 | del_timer(&device->timer); |
| 1551 | } | 1557 | } |
| 1558 | EXPORT_SYMBOL(dasd_device_clear_timer); | ||
| 1552 | 1559 | ||
| 1553 | static void dasd_handle_killed_request(struct ccw_device *cdev, | 1560 | static void dasd_handle_killed_request(struct ccw_device *cdev, |
| 1554 | unsigned long intparm) | 1561 | unsigned long intparm) |
| @@ -1601,6 +1608,7 @@ void dasd_generic_handle_state_change(struct dasd_device *device) | |||
| 1601 | if (device->block) | 1608 | if (device->block) |
| 1602 | dasd_schedule_block_bh(device->block); | 1609 | dasd_schedule_block_bh(device->block); |
| 1603 | } | 1610 | } |
| 1611 | EXPORT_SYMBOL_GPL(dasd_generic_handle_state_change); | ||
| 1604 | 1612 | ||
| 1605 | /* | 1613 | /* |
| 1606 | * Interrupt handler for "normal" ssch-io based dasd devices. | 1614 | * Interrupt handler for "normal" ssch-io based dasd devices. |
| @@ -1667,8 +1675,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
| 1667 | if (cqr->status == DASD_CQR_CLEAR_PENDING && | 1675 | if (cqr->status == DASD_CQR_CLEAR_PENDING && |
| 1668 | scsw_fctl(&irb->scsw) & SCSW_FCTL_CLEAR_FUNC) { | 1676 | scsw_fctl(&irb->scsw) & SCSW_FCTL_CLEAR_FUNC) { |
| 1669 | cqr->status = DASD_CQR_CLEARED; | 1677 | cqr->status = DASD_CQR_CLEARED; |
| 1678 | if (cqr->callback_data == DASD_SLEEPON_START_TAG) | ||
| 1679 | cqr->callback_data = DASD_SLEEPON_END_TAG; | ||
| 1670 | dasd_device_clear_timer(device); | 1680 | dasd_device_clear_timer(device); |
| 1671 | wake_up(&dasd_flush_wq); | 1681 | wake_up(&dasd_flush_wq); |
| 1682 | wake_up(&generic_waitq); | ||
| 1672 | dasd_schedule_device_bh(device); | 1683 | dasd_schedule_device_bh(device); |
| 1673 | return; | 1684 | return; |
| 1674 | } | 1685 | } |
| @@ -1722,6 +1733,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
| 1722 | dasd_device_clear_timer(device); | 1733 | dasd_device_clear_timer(device); |
| 1723 | dasd_schedule_device_bh(device); | 1734 | dasd_schedule_device_bh(device); |
| 1724 | } | 1735 | } |
| 1736 | EXPORT_SYMBOL(dasd_int_handler); | ||
| 1725 | 1737 | ||
| 1726 | enum uc_todo dasd_generic_uc_handler(struct ccw_device *cdev, struct irb *irb) | 1738 | enum uc_todo dasd_generic_uc_handler(struct ccw_device *cdev, struct irb *irb) |
| 1727 | { | 1739 | { |
| @@ -1995,6 +2007,7 @@ finished: | |||
| 1995 | __dasd_device_process_final_queue(device, &flush_queue); | 2007 | __dasd_device_process_final_queue(device, &flush_queue); |
| 1996 | return rc; | 2008 | return rc; |
| 1997 | } | 2009 | } |
| 2010 | EXPORT_SYMBOL_GPL(dasd_flush_device_queue); | ||
| 1998 | 2011 | ||
| 1999 | /* | 2012 | /* |
| 2000 | * Acquire the device lock and process queues for the device. | 2013 | * Acquire the device lock and process queues for the device. |
| @@ -2034,6 +2047,7 @@ void dasd_schedule_device_bh(struct dasd_device *device) | |||
| 2034 | dasd_get_device(device); | 2047 | dasd_get_device(device); |
| 2035 | tasklet_hi_schedule(&device->tasklet); | 2048 | tasklet_hi_schedule(&device->tasklet); |
| 2036 | } | 2049 | } |
| 2050 | EXPORT_SYMBOL(dasd_schedule_device_bh); | ||
| 2037 | 2051 | ||
| 2038 | void dasd_device_set_stop_bits(struct dasd_device *device, int bits) | 2052 | void dasd_device_set_stop_bits(struct dasd_device *device, int bits) |
| 2039 | { | 2053 | { |
| @@ -2066,6 +2080,7 @@ void dasd_add_request_head(struct dasd_ccw_req *cqr) | |||
| 2066 | dasd_schedule_device_bh(device); | 2080 | dasd_schedule_device_bh(device); |
| 2067 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | 2081 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); |
| 2068 | } | 2082 | } |
| 2083 | EXPORT_SYMBOL(dasd_add_request_head); | ||
| 2069 | 2084 | ||
| 2070 | /* | 2085 | /* |
| 2071 | * Queue a request to the tail of the device ccw_queue. | 2086 | * Queue a request to the tail of the device ccw_queue. |
| @@ -2084,6 +2099,7 @@ void dasd_add_request_tail(struct dasd_ccw_req *cqr) | |||
| 2084 | dasd_schedule_device_bh(device); | 2099 | dasd_schedule_device_bh(device); |
| 2085 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | 2100 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); |
| 2086 | } | 2101 | } |
| 2102 | EXPORT_SYMBOL(dasd_add_request_tail); | ||
| 2087 | 2103 | ||
| 2088 | /* | 2104 | /* |
| 2089 | * Wakeup helper for the 'sleep_on' functions. | 2105 | * Wakeup helper for the 'sleep_on' functions. |
| @@ -2291,13 +2307,27 @@ retry: | |||
| 2291 | 2307 | ||
| 2292 | rc = 0; | 2308 | rc = 0; |
| 2293 | list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) { | 2309 | list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) { |
| 2294 | if (__dasd_sleep_on_erp(cqr)) | 2310 | /* |
| 2295 | rc = 1; | 2311 | * for alias devices simplify error recovery and |
| 2312 | * return to upper layer | ||
| 2313 | */ | ||
| 2314 | if (cqr->startdev != cqr->basedev && | ||
| 2315 | (cqr->status == DASD_CQR_TERMINATED || | ||
| 2316 | cqr->status == DASD_CQR_NEED_ERP)) | ||
| 2317 | return -EAGAIN; | ||
| 2318 | else { | ||
| 2319 | /* normal recovery for basedev IO */ | ||
| 2320 | if (__dasd_sleep_on_erp(cqr)) { | ||
| 2321 | if (!cqr->status == DASD_CQR_TERMINATED && | ||
| 2322 | !cqr->status == DASD_CQR_NEED_ERP) | ||
| 2323 | break; | ||
| 2324 | rc = 1; | ||
| 2325 | } | ||
| 2326 | } | ||
| 2296 | } | 2327 | } |
| 2297 | if (rc) | 2328 | if (rc) |
| 2298 | goto retry; | 2329 | goto retry; |
| 2299 | 2330 | ||
| 2300 | |||
| 2301 | return 0; | 2331 | return 0; |
| 2302 | } | 2332 | } |
| 2303 | 2333 | ||
| @@ -2309,6 +2339,7 @@ int dasd_sleep_on(struct dasd_ccw_req *cqr) | |||
| 2309 | { | 2339 | { |
| 2310 | return _dasd_sleep_on(cqr, 0); | 2340 | return _dasd_sleep_on(cqr, 0); |
| 2311 | } | 2341 | } |
| 2342 | EXPORT_SYMBOL(dasd_sleep_on); | ||
| 2312 | 2343 | ||
| 2313 | /* | 2344 | /* |
| 2314 | * Start requests from a ccw_queue and wait for their completion. | 2345 | * Start requests from a ccw_queue and wait for their completion. |
| @@ -2327,6 +2358,7 @@ int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr) | |||
| 2327 | { | 2358 | { |
| 2328 | return _dasd_sleep_on(cqr, 1); | 2359 | return _dasd_sleep_on(cqr, 1); |
| 2329 | } | 2360 | } |
| 2361 | EXPORT_SYMBOL(dasd_sleep_on_interruptible); | ||
| 2330 | 2362 | ||
| 2331 | /* | 2363 | /* |
| 2332 | * Whoa nelly now it gets really hairy. For some functions (e.g. steal lock | 2364 | * Whoa nelly now it gets really hairy. For some functions (e.g. steal lock |
| @@ -2401,6 +2433,7 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) | |||
| 2401 | 2433 | ||
| 2402 | return rc; | 2434 | return rc; |
| 2403 | } | 2435 | } |
| 2436 | EXPORT_SYMBOL(dasd_sleep_on_immediatly); | ||
| 2404 | 2437 | ||
| 2405 | /* | 2438 | /* |
| 2406 | * Cancels a request that was started with dasd_sleep_on_req. | 2439 | * Cancels a request that was started with dasd_sleep_on_req. |
| @@ -2423,6 +2456,8 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr) | |||
| 2423 | case DASD_CQR_QUEUED: | 2456 | case DASD_CQR_QUEUED: |
| 2424 | /* request was not started - just set to cleared */ | 2457 | /* request was not started - just set to cleared */ |
| 2425 | cqr->status = DASD_CQR_CLEARED; | 2458 | cqr->status = DASD_CQR_CLEARED; |
| 2459 | if (cqr->callback_data == DASD_SLEEPON_START_TAG) | ||
| 2460 | cqr->callback_data = DASD_SLEEPON_END_TAG; | ||
| 2426 | break; | 2461 | break; |
| 2427 | case DASD_CQR_IN_IO: | 2462 | case DASD_CQR_IN_IO: |
| 2428 | /* request in IO - terminate IO and release again */ | 2463 | /* request in IO - terminate IO and release again */ |
| @@ -2442,6 +2477,7 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr) | |||
| 2442 | dasd_schedule_device_bh(device); | 2477 | dasd_schedule_device_bh(device); |
| 2443 | return rc; | 2478 | return rc; |
| 2444 | } | 2479 | } |
| 2480 | EXPORT_SYMBOL(dasd_cancel_req); | ||
| 2445 | 2481 | ||
| 2446 | /* | 2482 | /* |
| 2447 | * SECTION: Operations of the dasd_block layer. | 2483 | * SECTION: Operations of the dasd_block layer. |
| @@ -2475,6 +2511,7 @@ void dasd_block_set_timer(struct dasd_block *block, int expires) | |||
| 2475 | else | 2511 | else |
| 2476 | mod_timer(&block->timer, jiffies + expires); | 2512 | mod_timer(&block->timer, jiffies + expires); |
| 2477 | } | 2513 | } |
| 2514 | EXPORT_SYMBOL(dasd_block_set_timer); | ||
| 2478 | 2515 | ||
| 2479 | /* | 2516 | /* |
| 2480 | * Clear timeout for a dasd_block. | 2517 | * Clear timeout for a dasd_block. |
| @@ -2483,6 +2520,7 @@ void dasd_block_clear_timer(struct dasd_block *block) | |||
| 2483 | { | 2520 | { |
| 2484 | del_timer(&block->timer); | 2521 | del_timer(&block->timer); |
| 2485 | } | 2522 | } |
| 2523 | EXPORT_SYMBOL(dasd_block_clear_timer); | ||
| 2486 | 2524 | ||
| 2487 | /* | 2525 | /* |
| 2488 | * Process finished error recovery ccw. | 2526 | * Process finished error recovery ccw. |
| @@ -2864,6 +2902,7 @@ void dasd_schedule_block_bh(struct dasd_block *block) | |||
| 2864 | dasd_get_device(block->base); | 2902 | dasd_get_device(block->base); |
| 2865 | tasklet_hi_schedule(&block->tasklet); | 2903 | tasklet_hi_schedule(&block->tasklet); |
| 2866 | } | 2904 | } |
| 2905 | EXPORT_SYMBOL(dasd_schedule_block_bh); | ||
| 2867 | 2906 | ||
| 2868 | 2907 | ||
| 2869 | /* | 2908 | /* |
| @@ -3202,8 +3241,8 @@ static void dasd_generic_auto_online(void *data, async_cookie_t cookie) | |||
| 3202 | 3241 | ||
| 3203 | ret = ccw_device_set_online(cdev); | 3242 | ret = ccw_device_set_online(cdev); |
| 3204 | if (ret) | 3243 | if (ret) |
| 3205 | pr_warning("%s: Setting the DASD online failed with rc=%d\n", | 3244 | pr_warn("%s: Setting the DASD online failed with rc=%d\n", |
| 3206 | dev_name(&cdev->dev), ret); | 3245 | dev_name(&cdev->dev), ret); |
| 3207 | } | 3246 | } |
| 3208 | 3247 | ||
| 3209 | /* | 3248 | /* |
| @@ -3234,6 +3273,7 @@ int dasd_generic_probe(struct ccw_device *cdev, | |||
| 3234 | async_schedule(dasd_generic_auto_online, cdev); | 3273 | async_schedule(dasd_generic_auto_online, cdev); |
| 3235 | return 0; | 3274 | return 0; |
| 3236 | } | 3275 | } |
| 3276 | EXPORT_SYMBOL_GPL(dasd_generic_probe); | ||
| 3237 | 3277 | ||
| 3238 | /* | 3278 | /* |
| 3239 | * This will one day be called from a global not_oper handler. | 3279 | * This will one day be called from a global not_oper handler. |
| @@ -3276,6 +3316,7 @@ void dasd_generic_remove(struct ccw_device *cdev) | |||
| 3276 | 3316 | ||
| 3277 | dasd_remove_sysfs_files(cdev); | 3317 | dasd_remove_sysfs_files(cdev); |
| 3278 | } | 3318 | } |
| 3319 | EXPORT_SYMBOL_GPL(dasd_generic_remove); | ||
| 3279 | 3320 | ||
| 3280 | /* | 3321 | /* |
| 3281 | * Activate a device. This is called from dasd_{eckd,fba}_probe() when either | 3322 | * Activate a device. This is called from dasd_{eckd,fba}_probe() when either |
| @@ -3298,9 +3339,8 @@ int dasd_generic_set_online(struct ccw_device *cdev, | |||
| 3298 | discipline = base_discipline; | 3339 | discipline = base_discipline; |
| 3299 | if (device->features & DASD_FEATURE_USEDIAG) { | 3340 | if (device->features & DASD_FEATURE_USEDIAG) { |
| 3300 | if (!dasd_diag_discipline_pointer) { | 3341 | if (!dasd_diag_discipline_pointer) { |
| 3301 | pr_warning("%s Setting the DASD online failed because " | 3342 | pr_warn("%s Setting the DASD online failed because of missing DIAG discipline\n", |
| 3302 | "of missing DIAG discipline\n", | 3343 | dev_name(&cdev->dev)); |
| 3303 | dev_name(&cdev->dev)); | ||
| 3304 | dasd_delete_device(device); | 3344 | dasd_delete_device(device); |
| 3305 | return -ENODEV; | 3345 | return -ENODEV; |
| 3306 | } | 3346 | } |
| @@ -3321,9 +3361,8 @@ int dasd_generic_set_online(struct ccw_device *cdev, | |||
| 3321 | /* check_device will allocate block device if necessary */ | 3361 | /* check_device will allocate block device if necessary */ |
| 3322 | rc = discipline->check_device(device); | 3362 | rc = discipline->check_device(device); |
| 3323 | if (rc) { | 3363 | if (rc) { |
| 3324 | pr_warning("%s Setting the DASD online with discipline %s " | 3364 | pr_warn("%s Setting the DASD online with discipline %s failed with rc=%i\n", |
| 3325 | "failed with rc=%i\n", | 3365 | dev_name(&cdev->dev), discipline->name, rc); |
| 3326 | dev_name(&cdev->dev), discipline->name, rc); | ||
| 3327 | module_put(discipline->owner); | 3366 | module_put(discipline->owner); |
| 3328 | module_put(base_discipline->owner); | 3367 | module_put(base_discipline->owner); |
| 3329 | dasd_delete_device(device); | 3368 | dasd_delete_device(device); |
| @@ -3332,8 +3371,8 @@ int dasd_generic_set_online(struct ccw_device *cdev, | |||
| 3332 | 3371 | ||
| 3333 | dasd_set_target_state(device, DASD_STATE_ONLINE); | 3372 | dasd_set_target_state(device, DASD_STATE_ONLINE); |
| 3334 | if (device->state <= DASD_STATE_KNOWN) { | 3373 | if (device->state <= DASD_STATE_KNOWN) { |
| 3335 | pr_warning("%s Setting the DASD online failed because of a " | 3374 | pr_warn("%s Setting the DASD online failed because of a missing discipline\n", |
| 3336 | "missing discipline\n", dev_name(&cdev->dev)); | 3375 | dev_name(&cdev->dev)); |
| 3337 | rc = -ENODEV; | 3376 | rc = -ENODEV; |
| 3338 | dasd_set_target_state(device, DASD_STATE_NEW); | 3377 | dasd_set_target_state(device, DASD_STATE_NEW); |
| 3339 | if (device->block) | 3378 | if (device->block) |
| @@ -3348,6 +3387,7 @@ int dasd_generic_set_online(struct ccw_device *cdev, | |||
| 3348 | dasd_put_device(device); | 3387 | dasd_put_device(device); |
| 3349 | return rc; | 3388 | return rc; |
| 3350 | } | 3389 | } |
| 3390 | EXPORT_SYMBOL_GPL(dasd_generic_set_online); | ||
| 3351 | 3391 | ||
| 3352 | int dasd_generic_set_offline(struct ccw_device *cdev) | 3392 | int dasd_generic_set_offline(struct ccw_device *cdev) |
| 3353 | { | 3393 | { |
| @@ -3371,13 +3411,11 @@ int dasd_generic_set_offline(struct ccw_device *cdev) | |||
| 3371 | open_count = atomic_read(&device->block->open_count); | 3411 | open_count = atomic_read(&device->block->open_count); |
| 3372 | if (open_count > max_count) { | 3412 | if (open_count > max_count) { |
| 3373 | if (open_count > 0) | 3413 | if (open_count > 0) |
| 3374 | pr_warning("%s: The DASD cannot be set offline " | 3414 | pr_warn("%s: The DASD cannot be set offline with open count %i\n", |
| 3375 | "with open count %i\n", | 3415 | dev_name(&cdev->dev), open_count); |
| 3376 | dev_name(&cdev->dev), open_count); | ||
| 3377 | else | 3416 | else |
| 3378 | pr_warning("%s: The DASD cannot be set offline " | 3417 | pr_warn("%s: The DASD cannot be set offline while it is in use\n", |
| 3379 | "while it is in use\n", | 3418 | dev_name(&cdev->dev)); |
| 3380 | dev_name(&cdev->dev)); | ||
| 3381 | clear_bit(DASD_FLAG_OFFLINE, &device->flags); | 3419 | clear_bit(DASD_FLAG_OFFLINE, &device->flags); |
| 3382 | dasd_put_device(device); | 3420 | dasd_put_device(device); |
| 3383 | return -EBUSY; | 3421 | return -EBUSY; |
| @@ -3451,6 +3489,7 @@ interrupted: | |||
| 3451 | dasd_put_device(device); | 3489 | dasd_put_device(device); |
| 3452 | return rc; | 3490 | return rc; |
| 3453 | } | 3491 | } |
| 3492 | EXPORT_SYMBOL_GPL(dasd_generic_set_offline); | ||
| 3454 | 3493 | ||
| 3455 | int dasd_generic_last_path_gone(struct dasd_device *device) | 3494 | int dasd_generic_last_path_gone(struct dasd_device *device) |
| 3456 | { | 3495 | { |
| @@ -3492,6 +3531,10 @@ int dasd_generic_path_operational(struct dasd_device *device) | |||
| 3492 | dasd_schedule_device_bh(device); | 3531 | dasd_schedule_device_bh(device); |
| 3493 | if (device->block) | 3532 | if (device->block) |
| 3494 | dasd_schedule_block_bh(device->block); | 3533 | dasd_schedule_block_bh(device->block); |
| 3534 | |||
| 3535 | if (!device->stopped) | ||
| 3536 | wake_up(&generic_waitq); | ||
| 3537 | |||
| 3495 | return 1; | 3538 | return 1; |
| 3496 | } | 3539 | } |
| 3497 | EXPORT_SYMBOL_GPL(dasd_generic_path_operational); | 3540 | EXPORT_SYMBOL_GPL(dasd_generic_path_operational); |
| @@ -3523,6 +3566,7 @@ int dasd_generic_notify(struct ccw_device *cdev, int event) | |||
| 3523 | dasd_put_device(device); | 3566 | dasd_put_device(device); |
| 3524 | return ret; | 3567 | return ret; |
| 3525 | } | 3568 | } |
| 3569 | EXPORT_SYMBOL_GPL(dasd_generic_notify); | ||
| 3526 | 3570 | ||
| 3527 | void dasd_generic_path_event(struct ccw_device *cdev, int *path_event) | 3571 | void dasd_generic_path_event(struct ccw_device *cdev, int *path_event) |
| 3528 | { | 3572 | { |
| @@ -3872,39 +3916,3 @@ failed: | |||
| 3872 | 3916 | ||
| 3873 | module_init(dasd_init); | 3917 | module_init(dasd_init); |
| 3874 | module_exit(dasd_exit); | 3918 | module_exit(dasd_exit); |
| 3875 | |||
| 3876 | EXPORT_SYMBOL(dasd_debug_area); | ||
| 3877 | EXPORT_SYMBOL(dasd_diag_discipline_pointer); | ||
| 3878 | |||
| 3879 | EXPORT_SYMBOL(dasd_add_request_head); | ||
| 3880 | EXPORT_SYMBOL(dasd_add_request_tail); | ||
| 3881 | EXPORT_SYMBOL(dasd_cancel_req); | ||
| 3882 | EXPORT_SYMBOL(dasd_device_clear_timer); | ||
| 3883 | EXPORT_SYMBOL(dasd_block_clear_timer); | ||
| 3884 | EXPORT_SYMBOL(dasd_enable_device); | ||
| 3885 | EXPORT_SYMBOL(dasd_int_handler); | ||
| 3886 | EXPORT_SYMBOL(dasd_kfree_request); | ||
| 3887 | EXPORT_SYMBOL(dasd_kick_device); | ||
| 3888 | EXPORT_SYMBOL(dasd_kmalloc_request); | ||
| 3889 | EXPORT_SYMBOL(dasd_schedule_device_bh); | ||
| 3890 | EXPORT_SYMBOL(dasd_schedule_block_bh); | ||
| 3891 | EXPORT_SYMBOL(dasd_set_target_state); | ||
| 3892 | EXPORT_SYMBOL(dasd_device_set_timer); | ||
| 3893 | EXPORT_SYMBOL(dasd_block_set_timer); | ||
| 3894 | EXPORT_SYMBOL(dasd_sfree_request); | ||
| 3895 | EXPORT_SYMBOL(dasd_sleep_on); | ||
| 3896 | EXPORT_SYMBOL(dasd_sleep_on_immediatly); | ||
| 3897 | EXPORT_SYMBOL(dasd_sleep_on_interruptible); | ||
| 3898 | EXPORT_SYMBOL(dasd_smalloc_request); | ||
| 3899 | EXPORT_SYMBOL(dasd_start_IO); | ||
| 3900 | EXPORT_SYMBOL(dasd_term_IO); | ||
| 3901 | |||
| 3902 | EXPORT_SYMBOL_GPL(dasd_generic_probe); | ||
| 3903 | EXPORT_SYMBOL_GPL(dasd_generic_remove); | ||
| 3904 | EXPORT_SYMBOL_GPL(dasd_generic_notify); | ||
| 3905 | EXPORT_SYMBOL_GPL(dasd_generic_set_online); | ||
| 3906 | EXPORT_SYMBOL_GPL(dasd_generic_set_offline); | ||
| 3907 | EXPORT_SYMBOL_GPL(dasd_generic_handle_state_change); | ||
| 3908 | EXPORT_SYMBOL_GPL(dasd_flush_device_queue); | ||
| 3909 | EXPORT_SYMBOL_GPL(dasd_alloc_block); | ||
| 3910 | EXPORT_SYMBOL_GPL(dasd_free_block); | ||
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 2e8e0755070b..51dea7baf02c 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
| @@ -2039,7 +2039,7 @@ static int dasd_eckd_online_to_ready(struct dasd_device *device) | |||
| 2039 | return 0; | 2039 | return 0; |
| 2040 | }; | 2040 | }; |
| 2041 | 2041 | ||
| 2042 | static int dasd_eckd_ready_to_basic(struct dasd_device *device) | 2042 | static int dasd_eckd_basic_to_known(struct dasd_device *device) |
| 2043 | { | 2043 | { |
| 2044 | return dasd_alias_remove_device(device); | 2044 | return dasd_alias_remove_device(device); |
| 2045 | }; | 2045 | }; |
| @@ -2061,11 +2061,12 @@ dasd_eckd_fill_geometry(struct dasd_block *block, struct hd_geometry *geo) | |||
| 2061 | 2061 | ||
| 2062 | static struct dasd_ccw_req * | 2062 | static struct dasd_ccw_req * |
| 2063 | dasd_eckd_build_format(struct dasd_device *base, | 2063 | dasd_eckd_build_format(struct dasd_device *base, |
| 2064 | struct format_data_t *fdata) | 2064 | struct format_data_t *fdata, |
| 2065 | int enable_pav) | ||
| 2065 | { | 2066 | { |
| 2066 | struct dasd_eckd_private *base_priv; | 2067 | struct dasd_eckd_private *base_priv; |
| 2067 | struct dasd_eckd_private *start_priv; | 2068 | struct dasd_eckd_private *start_priv; |
| 2068 | struct dasd_device *startdev; | 2069 | struct dasd_device *startdev = NULL; |
| 2069 | struct dasd_ccw_req *fcp; | 2070 | struct dasd_ccw_req *fcp; |
| 2070 | struct eckd_count *ect; | 2071 | struct eckd_count *ect; |
| 2071 | struct ch_t address; | 2072 | struct ch_t address; |
| @@ -2079,7 +2080,9 @@ dasd_eckd_build_format(struct dasd_device *base, | |||
| 2079 | int nr_tracks; | 2080 | int nr_tracks; |
| 2080 | int use_prefix; | 2081 | int use_prefix; |
| 2081 | 2082 | ||
| 2082 | startdev = dasd_alias_get_start_dev(base); | 2083 | if (enable_pav) |
| 2084 | startdev = dasd_alias_get_start_dev(base); | ||
| 2085 | |||
| 2083 | if (!startdev) | 2086 | if (!startdev) |
| 2084 | startdev = base; | 2087 | startdev = base; |
| 2085 | 2088 | ||
| @@ -2309,6 +2312,7 @@ dasd_eckd_build_format(struct dasd_device *base, | |||
| 2309 | 2312 | ||
| 2310 | fcp->startdev = startdev; | 2313 | fcp->startdev = startdev; |
| 2311 | fcp->memdev = startdev; | 2314 | fcp->memdev = startdev; |
| 2315 | fcp->basedev = base; | ||
| 2312 | fcp->retries = 256; | 2316 | fcp->retries = 256; |
| 2313 | fcp->expires = startdev->default_expires * HZ; | 2317 | fcp->expires = startdev->default_expires * HZ; |
| 2314 | fcp->buildclk = get_tod_clock(); | 2318 | fcp->buildclk = get_tod_clock(); |
| @@ -2319,7 +2323,8 @@ dasd_eckd_build_format(struct dasd_device *base, | |||
| 2319 | 2323 | ||
| 2320 | static int | 2324 | static int |
| 2321 | dasd_eckd_format_device(struct dasd_device *base, | 2325 | dasd_eckd_format_device(struct dasd_device *base, |
| 2322 | struct format_data_t *fdata) | 2326 | struct format_data_t *fdata, |
| 2327 | int enable_pav) | ||
| 2323 | { | 2328 | { |
| 2324 | struct dasd_ccw_req *cqr, *n; | 2329 | struct dasd_ccw_req *cqr, *n; |
| 2325 | struct dasd_block *block; | 2330 | struct dasd_block *block; |
| @@ -2327,7 +2332,7 @@ dasd_eckd_format_device(struct dasd_device *base, | |||
| 2327 | struct list_head format_queue; | 2332 | struct list_head format_queue; |
| 2328 | struct dasd_device *device; | 2333 | struct dasd_device *device; |
| 2329 | int old_stop, format_step; | 2334 | int old_stop, format_step; |
| 2330 | int step, rc = 0; | 2335 | int step, rc = 0, sleep_rc; |
| 2331 | 2336 | ||
| 2332 | block = base->block; | 2337 | block = base->block; |
| 2333 | private = (struct dasd_eckd_private *) base->private; | 2338 | private = (struct dasd_eckd_private *) base->private; |
| @@ -2361,11 +2366,11 @@ dasd_eckd_format_device(struct dasd_device *base, | |||
| 2361 | } | 2366 | } |
| 2362 | 2367 | ||
| 2363 | INIT_LIST_HEAD(&format_queue); | 2368 | INIT_LIST_HEAD(&format_queue); |
| 2364 | old_stop = fdata->stop_unit; | ||
| 2365 | 2369 | ||
| 2370 | old_stop = fdata->stop_unit; | ||
| 2366 | while (fdata->start_unit <= 1) { | 2371 | while (fdata->start_unit <= 1) { |
| 2367 | fdata->stop_unit = fdata->start_unit; | 2372 | fdata->stop_unit = fdata->start_unit; |
| 2368 | cqr = dasd_eckd_build_format(base, fdata); | 2373 | cqr = dasd_eckd_build_format(base, fdata, enable_pav); |
| 2369 | list_add(&cqr->blocklist, &format_queue); | 2374 | list_add(&cqr->blocklist, &format_queue); |
| 2370 | 2375 | ||
| 2371 | fdata->stop_unit = old_stop; | 2376 | fdata->stop_unit = old_stop; |
| @@ -2383,7 +2388,7 @@ retry: | |||
| 2383 | if (step > format_step) | 2388 | if (step > format_step) |
| 2384 | fdata->stop_unit = fdata->start_unit + format_step - 1; | 2389 | fdata->stop_unit = fdata->start_unit + format_step - 1; |
| 2385 | 2390 | ||
| 2386 | cqr = dasd_eckd_build_format(base, fdata); | 2391 | cqr = dasd_eckd_build_format(base, fdata, enable_pav); |
| 2387 | if (IS_ERR(cqr)) { | 2392 | if (IS_ERR(cqr)) { |
| 2388 | if (PTR_ERR(cqr) == -ENOMEM) { | 2393 | if (PTR_ERR(cqr) == -ENOMEM) { |
| 2389 | /* | 2394 | /* |
| @@ -2403,7 +2408,7 @@ retry: | |||
| 2403 | } | 2408 | } |
| 2404 | 2409 | ||
| 2405 | sleep: | 2410 | sleep: |
| 2406 | dasd_sleep_on_queue(&format_queue); | 2411 | sleep_rc = dasd_sleep_on_queue(&format_queue); |
| 2407 | 2412 | ||
| 2408 | list_for_each_entry_safe(cqr, n, &format_queue, blocklist) { | 2413 | list_for_each_entry_safe(cqr, n, &format_queue, blocklist) { |
| 2409 | device = cqr->startdev; | 2414 | device = cqr->startdev; |
| @@ -2415,6 +2420,9 @@ sleep: | |||
| 2415 | private->count--; | 2420 | private->count--; |
| 2416 | } | 2421 | } |
| 2417 | 2422 | ||
| 2423 | if (sleep_rc) | ||
| 2424 | return sleep_rc; | ||
| 2425 | |||
| 2418 | /* | 2426 | /* |
| 2419 | * in case of ENOMEM we need to retry after | 2427 | * in case of ENOMEM we need to retry after |
| 2420 | * first requests are finished | 2428 | * first requests are finished |
| @@ -4511,7 +4519,7 @@ static struct dasd_discipline dasd_eckd_discipline = { | |||
| 4511 | .verify_path = dasd_eckd_verify_path, | 4519 | .verify_path = dasd_eckd_verify_path, |
| 4512 | .basic_to_ready = dasd_eckd_basic_to_ready, | 4520 | .basic_to_ready = dasd_eckd_basic_to_ready, |
| 4513 | .online_to_ready = dasd_eckd_online_to_ready, | 4521 | .online_to_ready = dasd_eckd_online_to_ready, |
| 4514 | .ready_to_basic = dasd_eckd_ready_to_basic, | 4522 | .basic_to_known = dasd_eckd_basic_to_known, |
| 4515 | .fill_geometry = dasd_eckd_fill_geometry, | 4523 | .fill_geometry = dasd_eckd_fill_geometry, |
| 4516 | .start_IO = dasd_start_IO, | 4524 | .start_IO = dasd_start_IO, |
| 4517 | .term_IO = dasd_term_IO, | 4525 | .term_IO = dasd_term_IO, |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 690001af0d09..c20170166909 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
| @@ -175,6 +175,7 @@ struct dasd_ccw_req { | |||
| 175 | struct dasd_block *block; /* the originating block device */ | 175 | struct dasd_block *block; /* the originating block device */ |
| 176 | struct dasd_device *memdev; /* the device used to allocate this */ | 176 | struct dasd_device *memdev; /* the device used to allocate this */ |
| 177 | struct dasd_device *startdev; /* device the request is started on */ | 177 | struct dasd_device *startdev; /* device the request is started on */ |
| 178 | struct dasd_device *basedev; /* base device if no block->base */ | ||
| 178 | void *cpaddr; /* address of ccw or tcw */ | 179 | void *cpaddr; /* address of ccw or tcw */ |
| 179 | unsigned char cpmode; /* 0 = cmd mode, 1 = itcw */ | 180 | unsigned char cpmode; /* 0 = cmd mode, 1 = itcw */ |
| 180 | char status; /* status of this request */ | 181 | char status; /* status of this request */ |
| @@ -304,7 +305,7 @@ struct dasd_discipline { | |||
| 304 | */ | 305 | */ |
| 305 | int (*basic_to_ready) (struct dasd_device *); | 306 | int (*basic_to_ready) (struct dasd_device *); |
| 306 | int (*online_to_ready) (struct dasd_device *); | 307 | int (*online_to_ready) (struct dasd_device *); |
| 307 | int (*ready_to_basic) (struct dasd_device *); | 308 | int (*basic_to_known)(struct dasd_device *); |
| 308 | 309 | ||
| 309 | /* (struct dasd_device *); | 310 | /* (struct dasd_device *); |
| 310 | * Device operation functions. build_cp creates a ccw chain for | 311 | * Device operation functions. build_cp creates a ccw chain for |
| @@ -321,7 +322,7 @@ struct dasd_discipline { | |||
| 321 | int (*term_IO) (struct dasd_ccw_req *); | 322 | int (*term_IO) (struct dasd_ccw_req *); |
| 322 | void (*handle_terminated_request) (struct dasd_ccw_req *); | 323 | void (*handle_terminated_request) (struct dasd_ccw_req *); |
| 323 | int (*format_device) (struct dasd_device *, | 324 | int (*format_device) (struct dasd_device *, |
| 324 | struct format_data_t *); | 325 | struct format_data_t *, int enable_pav); |
| 325 | int (*free_cp) (struct dasd_ccw_req *, struct request *); | 326 | int (*free_cp) (struct dasd_ccw_req *, struct request *); |
| 326 | 327 | ||
| 327 | /* | 328 | /* |
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 25a0f2f8b0b9..02837d0ad942 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c | |||
| @@ -203,7 +203,9 @@ static int | |||
| 203 | dasd_format(struct dasd_block *block, struct format_data_t *fdata) | 203 | dasd_format(struct dasd_block *block, struct format_data_t *fdata) |
| 204 | { | 204 | { |
| 205 | struct dasd_device *base; | 205 | struct dasd_device *base; |
| 206 | int rc; | 206 | int enable_pav = 1; |
| 207 | int rc, retries; | ||
| 208 | int start, stop; | ||
| 207 | 209 | ||
| 208 | base = block->base; | 210 | base = block->base; |
| 209 | if (base->discipline->format_device == NULL) | 211 | if (base->discipline->format_device == NULL) |
| @@ -231,11 +233,30 @@ dasd_format(struct dasd_block *block, struct format_data_t *fdata) | |||
| 231 | bdput(bdev); | 233 | bdput(bdev); |
| 232 | } | 234 | } |
| 233 | 235 | ||
| 234 | rc = base->discipline->format_device(base, fdata); | 236 | retries = 255; |
| 235 | if (rc) | 237 | /* backup start- and endtrack for retries */ |
| 236 | return rc; | 238 | start = fdata->start_unit; |
| 237 | 239 | stop = fdata->stop_unit; | |
| 238 | return 0; | 240 | do { |
| 241 | rc = base->discipline->format_device(base, fdata, enable_pav); | ||
| 242 | if (rc) { | ||
| 243 | if (rc == -EAGAIN) { | ||
| 244 | retries--; | ||
| 245 | /* disable PAV in case of errors */ | ||
| 246 | enable_pav = 0; | ||
| 247 | fdata->start_unit = start; | ||
| 248 | fdata->stop_unit = stop; | ||
| 249 | } else | ||
| 250 | return rc; | ||
| 251 | } else | ||
| 252 | /* success */ | ||
| 253 | break; | ||
| 254 | } while (retries); | ||
| 255 | |||
| 256 | if (!retries) | ||
| 257 | return -EIO; | ||
| 258 | else | ||
| 259 | return 0; | ||
| 239 | } | 260 | } |
| 240 | 261 | ||
| 241 | /* | 262 | /* |
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 5af7f0bd6125..a6d47e5eee9e 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c | |||
| @@ -288,12 +288,16 @@ static void raw3215_timeout(unsigned long __data) | |||
| 288 | unsigned long flags; | 288 | unsigned long flags; |
| 289 | 289 | ||
| 290 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); | 290 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); |
| 291 | if (raw->flags & RAW3215_TIMER_RUNS) { | 291 | raw->flags &= ~RAW3215_TIMER_RUNS; |
| 292 | del_timer(&raw->timer); | 292 | if (!(raw->port.flags & ASYNC_SUSPENDED)) { |
| 293 | raw->flags &= ~RAW3215_TIMER_RUNS; | 293 | raw3215_mk_write_req(raw); |
| 294 | if (!(raw->port.flags & ASYNC_SUSPENDED)) { | 294 | raw3215_start_io(raw); |
| 295 | raw3215_mk_write_req(raw); | 295 | if ((raw->queued_read || raw->queued_write) && |
| 296 | raw3215_start_io(raw); | 296 | !(raw->flags & RAW3215_WORKING) && |
| 297 | !(raw->flags & RAW3215_TIMER_RUNS)) { | ||
| 298 | raw->timer.expires = RAW3215_TIMEOUT + jiffies; | ||
| 299 | add_timer(&raw->timer); | ||
| 300 | raw->flags |= RAW3215_TIMER_RUNS; | ||
| 297 | } | 301 | } |
| 298 | } | 302 | } |
| 299 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); | 303 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
| @@ -317,17 +321,15 @@ static inline void raw3215_try_io(struct raw3215_info *raw) | |||
| 317 | (raw->flags & RAW3215_FLUSHING)) { | 321 | (raw->flags & RAW3215_FLUSHING)) { |
| 318 | /* execute write requests bigger than minimum size */ | 322 | /* execute write requests bigger than minimum size */ |
| 319 | raw3215_start_io(raw); | 323 | raw3215_start_io(raw); |
| 320 | if (raw->flags & RAW3215_TIMER_RUNS) { | ||
| 321 | del_timer(&raw->timer); | ||
| 322 | raw->flags &= ~RAW3215_TIMER_RUNS; | ||
| 323 | } | ||
| 324 | } else if (!(raw->flags & RAW3215_TIMER_RUNS)) { | ||
| 325 | /* delay small writes */ | ||
| 326 | raw->timer.expires = RAW3215_TIMEOUT + jiffies; | ||
| 327 | add_timer(&raw->timer); | ||
| 328 | raw->flags |= RAW3215_TIMER_RUNS; | ||
| 329 | } | 324 | } |
| 330 | } | 325 | } |
| 326 | if ((raw->queued_read || raw->queued_write) && | ||
| 327 | !(raw->flags & RAW3215_WORKING) && | ||
| 328 | !(raw->flags & RAW3215_TIMER_RUNS)) { | ||
| 329 | raw->timer.expires = RAW3215_TIMEOUT + jiffies; | ||
| 330 | add_timer(&raw->timer); | ||
| 331 | raw->flags |= RAW3215_TIMER_RUNS; | ||
| 332 | } | ||
| 331 | } | 333 | } |
| 332 | 334 | ||
| 333 | /* | 335 | /* |
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index f5f4a91fab44..f76bff68d1de 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | #include "qdio.h" | 17 | #include "qdio.h" |
| 18 | #include "qdio_debug.h" | 18 | #include "qdio_debug.h" |
| 19 | 19 | ||
| 20 | #define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer)) | ||
| 21 | |||
| 20 | static struct kmem_cache *qdio_q_cache; | 22 | static struct kmem_cache *qdio_q_cache; |
| 21 | static struct kmem_cache *qdio_aob_cache; | 23 | static struct kmem_cache *qdio_aob_cache; |
| 22 | 24 | ||
| @@ -32,6 +34,57 @@ void qdio_release_aob(struct qaob *aob) | |||
| 32 | } | 34 | } |
| 33 | EXPORT_SYMBOL_GPL(qdio_release_aob); | 35 | EXPORT_SYMBOL_GPL(qdio_release_aob); |
| 34 | 36 | ||
| 37 | /** | ||
| 38 | * qdio_free_buffers() - free qdio buffers | ||
| 39 | * @buf: array of pointers to qdio buffers | ||
| 40 | * @count: number of qdio buffers to free | ||
| 41 | */ | ||
| 42 | void qdio_free_buffers(struct qdio_buffer **buf, unsigned int count) | ||
| 43 | { | ||
| 44 | int pos; | ||
| 45 | |||
| 46 | for (pos = 0; pos < count; pos += QBUFF_PER_PAGE) | ||
| 47 | free_page((unsigned long) buf[pos]); | ||
| 48 | } | ||
| 49 | EXPORT_SYMBOL_GPL(qdio_free_buffers); | ||
| 50 | |||
| 51 | /** | ||
| 52 | * qdio_alloc_buffers() - allocate qdio buffers | ||
| 53 | * @buf: array of pointers to qdio buffers | ||
| 54 | * @count: number of qdio buffers to allocate | ||
| 55 | */ | ||
| 56 | int qdio_alloc_buffers(struct qdio_buffer **buf, unsigned int count) | ||
| 57 | { | ||
| 58 | int pos; | ||
| 59 | |||
| 60 | for (pos = 0; pos < count; pos += QBUFF_PER_PAGE) { | ||
| 61 | buf[pos] = (void *) get_zeroed_page(GFP_KERNEL); | ||
| 62 | if (!buf[pos]) { | ||
| 63 | qdio_free_buffers(buf, count); | ||
| 64 | return -ENOMEM; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | for (pos = 0; pos < count; pos++) | ||
| 68 | if (pos % QBUFF_PER_PAGE) | ||
| 69 | buf[pos] = buf[pos - 1] + 1; | ||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | EXPORT_SYMBOL_GPL(qdio_alloc_buffers); | ||
| 73 | |||
| 74 | /** | ||
| 75 | * qdio_reset_buffers() - reset qdio buffers | ||
| 76 | * @buf: array of pointers to qdio buffers | ||
| 77 | * @count: number of qdio buffers that will be zeroed | ||
| 78 | */ | ||
| 79 | void qdio_reset_buffers(struct qdio_buffer **buf, unsigned int count) | ||
| 80 | { | ||
| 81 | int pos; | ||
| 82 | |||
| 83 | for (pos = 0; pos < count; pos++) | ||
| 84 | memset(buf[pos], 0, sizeof(struct qdio_buffer)); | ||
| 85 | } | ||
| 86 | EXPORT_SYMBOL_GPL(qdio_reset_buffers); | ||
| 87 | |||
| 35 | /* | 88 | /* |
| 36 | * qebsm is only available under 64bit but the adapter sets the feature | 89 | * qebsm is only available under 64bit but the adapter sets the feature |
| 37 | * flag anyway, so we manually override it. | 90 | * flag anyway, so we manually override it. |
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index bbafbd0e017a..97ef37b51068 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h | |||
| @@ -439,10 +439,10 @@ struct qeth_qdio_buffer { | |||
| 439 | }; | 439 | }; |
| 440 | 440 | ||
| 441 | struct qeth_qdio_q { | 441 | struct qeth_qdio_q { |
| 442 | struct qdio_buffer qdio_bufs[QDIO_MAX_BUFFERS_PER_Q]; | 442 | struct qdio_buffer *qdio_bufs[QDIO_MAX_BUFFERS_PER_Q]; |
| 443 | struct qeth_qdio_buffer bufs[QDIO_MAX_BUFFERS_PER_Q]; | 443 | struct qeth_qdio_buffer bufs[QDIO_MAX_BUFFERS_PER_Q]; |
| 444 | int next_buf_to_init; | 444 | int next_buf_to_init; |
| 445 | } __attribute__ ((aligned(256))); | 445 | }; |
| 446 | 446 | ||
| 447 | struct qeth_qdio_out_buffer { | 447 | struct qeth_qdio_out_buffer { |
| 448 | struct qdio_buffer *buffer; | 448 | struct qdio_buffer *buffer; |
| @@ -465,7 +465,7 @@ enum qeth_out_q_states { | |||
| 465 | }; | 465 | }; |
| 466 | 466 | ||
| 467 | struct qeth_qdio_out_q { | 467 | struct qeth_qdio_out_q { |
| 468 | struct qdio_buffer qdio_bufs[QDIO_MAX_BUFFERS_PER_Q]; | 468 | struct qdio_buffer *qdio_bufs[QDIO_MAX_BUFFERS_PER_Q]; |
| 469 | struct qeth_qdio_out_buffer *bufs[QDIO_MAX_BUFFERS_PER_Q]; | 469 | struct qeth_qdio_out_buffer *bufs[QDIO_MAX_BUFFERS_PER_Q]; |
| 470 | struct qdio_outbuf_state *bufstates; /* convenience pointer */ | 470 | struct qdio_outbuf_state *bufstates; /* convenience pointer */ |
| 471 | int queue_no; | 471 | int queue_no; |
| @@ -483,7 +483,7 @@ struct qeth_qdio_out_q { | |||
| 483 | atomic_t used_buffers; | 483 | atomic_t used_buffers; |
| 484 | /* indicates whether PCI flag must be set (or if one is outstanding) */ | 484 | /* indicates whether PCI flag must be set (or if one is outstanding) */ |
| 485 | atomic_t set_pci_flags_count; | 485 | atomic_t set_pci_flags_count; |
| 486 | } __attribute__ ((aligned(256))); | 486 | }; |
| 487 | 487 | ||
| 488 | struct qeth_qdio_info { | 488 | struct qeth_qdio_info { |
| 489 | atomic_t state; | 489 | atomic_t state; |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 71bfacfc097e..c0d6ba8655c7 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
| @@ -292,14 +292,43 @@ int qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt) | |||
| 292 | } | 292 | } |
| 293 | EXPORT_SYMBOL_GPL(qeth_realloc_buffer_pool); | 293 | EXPORT_SYMBOL_GPL(qeth_realloc_buffer_pool); |
| 294 | 294 | ||
| 295 | static void qeth_free_qdio_queue(struct qeth_qdio_q *q) | ||
| 296 | { | ||
| 297 | if (!q) | ||
| 298 | return; | ||
| 299 | |||
| 300 | qdio_free_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q); | ||
| 301 | kfree(q); | ||
| 302 | } | ||
| 303 | |||
| 304 | static struct qeth_qdio_q *qeth_alloc_qdio_queue(void) | ||
| 305 | { | ||
| 306 | struct qeth_qdio_q *q = kzalloc(sizeof(*q), GFP_KERNEL); | ||
| 307 | int i; | ||
| 308 | |||
| 309 | if (!q) | ||
| 310 | return NULL; | ||
| 311 | |||
| 312 | if (qdio_alloc_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q)) { | ||
| 313 | kfree(q); | ||
| 314 | return NULL; | ||
| 315 | } | ||
| 316 | |||
| 317 | for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; ++i) | ||
| 318 | q->bufs[i].buffer = q->qdio_bufs[i]; | ||
| 319 | |||
| 320 | QETH_DBF_HEX(SETUP, 2, &q, sizeof(void *)); | ||
| 321 | return q; | ||
| 322 | } | ||
| 323 | |||
| 295 | static inline int qeth_cq_init(struct qeth_card *card) | 324 | static inline int qeth_cq_init(struct qeth_card *card) |
| 296 | { | 325 | { |
| 297 | int rc; | 326 | int rc; |
| 298 | 327 | ||
| 299 | if (card->options.cq == QETH_CQ_ENABLED) { | 328 | if (card->options.cq == QETH_CQ_ENABLED) { |
| 300 | QETH_DBF_TEXT(SETUP, 2, "cqinit"); | 329 | QETH_DBF_TEXT(SETUP, 2, "cqinit"); |
| 301 | memset(card->qdio.c_q->qdio_bufs, 0, | 330 | qdio_reset_buffers(card->qdio.c_q->qdio_bufs, |
| 302 | QDIO_MAX_BUFFERS_PER_Q * sizeof(struct qdio_buffer)); | 331 | QDIO_MAX_BUFFERS_PER_Q); |
| 303 | card->qdio.c_q->next_buf_to_init = 127; | 332 | card->qdio.c_q->next_buf_to_init = 127; |
| 304 | rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, | 333 | rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, |
| 305 | card->qdio.no_in_queues - 1, 0, | 334 | card->qdio.no_in_queues - 1, 0, |
| @@ -323,21 +352,12 @@ static inline int qeth_alloc_cq(struct qeth_card *card) | |||
| 323 | struct qdio_outbuf_state *outbuf_states; | 352 | struct qdio_outbuf_state *outbuf_states; |
| 324 | 353 | ||
| 325 | QETH_DBF_TEXT(SETUP, 2, "cqon"); | 354 | QETH_DBF_TEXT(SETUP, 2, "cqon"); |
| 326 | card->qdio.c_q = kzalloc(sizeof(struct qeth_qdio_q), | 355 | card->qdio.c_q = qeth_alloc_qdio_queue(); |
| 327 | GFP_KERNEL); | ||
| 328 | if (!card->qdio.c_q) { | 356 | if (!card->qdio.c_q) { |
| 329 | rc = -1; | 357 | rc = -1; |
| 330 | goto kmsg_out; | 358 | goto kmsg_out; |
| 331 | } | 359 | } |
| 332 | QETH_DBF_HEX(SETUP, 2, &card->qdio.c_q, sizeof(void *)); | ||
| 333 | |||
| 334 | for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; ++i) { | ||
| 335 | card->qdio.c_q->bufs[i].buffer = | ||
| 336 | &card->qdio.c_q->qdio_bufs[i]; | ||
| 337 | } | ||
| 338 | |||
| 339 | card->qdio.no_in_queues = 2; | 360 | card->qdio.no_in_queues = 2; |
| 340 | |||
| 341 | card->qdio.out_bufstates = | 361 | card->qdio.out_bufstates = |
| 342 | kzalloc(card->qdio.no_out_queues * | 362 | kzalloc(card->qdio.no_out_queues * |
| 343 | QDIO_MAX_BUFFERS_PER_Q * | 363 | QDIO_MAX_BUFFERS_PER_Q * |
| @@ -361,7 +381,7 @@ static inline int qeth_alloc_cq(struct qeth_card *card) | |||
| 361 | out: | 381 | out: |
| 362 | return rc; | 382 | return rc; |
| 363 | free_cq_out: | 383 | free_cq_out: |
| 364 | kfree(card->qdio.c_q); | 384 | qeth_free_qdio_queue(card->qdio.c_q); |
| 365 | card->qdio.c_q = NULL; | 385 | card->qdio.c_q = NULL; |
| 366 | kmsg_out: | 386 | kmsg_out: |
| 367 | dev_err(&card->gdev->dev, "Failed to create completion queue\n"); | 387 | dev_err(&card->gdev->dev, "Failed to create completion queue\n"); |
| @@ -372,7 +392,7 @@ static inline void qeth_free_cq(struct qeth_card *card) | |||
| 372 | { | 392 | { |
| 373 | if (card->qdio.c_q) { | 393 | if (card->qdio.c_q) { |
| 374 | --card->qdio.no_in_queues; | 394 | --card->qdio.no_in_queues; |
| 375 | kfree(card->qdio.c_q); | 395 | qeth_free_qdio_queue(card->qdio.c_q); |
| 376 | card->qdio.c_q = NULL; | 396 | card->qdio.c_q = NULL; |
| 377 | } | 397 | } |
| 378 | kfree(card->qdio.out_bufstates); | 398 | kfree(card->qdio.out_bufstates); |
| @@ -1282,35 +1302,6 @@ static void qeth_free_buffer_pool(struct qeth_card *card) | |||
| 1282 | } | 1302 | } |
| 1283 | } | 1303 | } |
| 1284 | 1304 | ||
| 1285 | static void qeth_free_qdio_buffers(struct qeth_card *card) | ||
| 1286 | { | ||
| 1287 | int i, j; | ||
| 1288 | |||
| 1289 | if (atomic_xchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED) == | ||
| 1290 | QETH_QDIO_UNINITIALIZED) | ||
| 1291 | return; | ||
| 1292 | |||
| 1293 | qeth_free_cq(card); | ||
| 1294 | cancel_delayed_work_sync(&card->buffer_reclaim_work); | ||
| 1295 | for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { | ||
| 1296 | if (card->qdio.in_q->bufs[j].rx_skb) | ||
| 1297 | dev_kfree_skb_any(card->qdio.in_q->bufs[j].rx_skb); | ||
| 1298 | } | ||
| 1299 | kfree(card->qdio.in_q); | ||
| 1300 | card->qdio.in_q = NULL; | ||
| 1301 | /* inbound buffer pool */ | ||
| 1302 | qeth_free_buffer_pool(card); | ||
| 1303 | /* free outbound qdio_qs */ | ||
| 1304 | if (card->qdio.out_qs) { | ||
| 1305 | for (i = 0; i < card->qdio.no_out_queues; ++i) { | ||
| 1306 | qeth_clear_outq_buffers(card->qdio.out_qs[i], 1); | ||
| 1307 | kfree(card->qdio.out_qs[i]); | ||
| 1308 | } | ||
| 1309 | kfree(card->qdio.out_qs); | ||
| 1310 | card->qdio.out_qs = NULL; | ||
| 1311 | } | ||
| 1312 | } | ||
| 1313 | |||
| 1314 | static void qeth_clean_channel(struct qeth_channel *channel) | 1305 | static void qeth_clean_channel(struct qeth_channel *channel) |
| 1315 | { | 1306 | { |
| 1316 | int cnt; | 1307 | int cnt; |
| @@ -2392,7 +2383,7 @@ static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *q, int bidx) | |||
| 2392 | rc = -ENOMEM; | 2383 | rc = -ENOMEM; |
| 2393 | goto out; | 2384 | goto out; |
| 2394 | } | 2385 | } |
| 2395 | newbuf->buffer = &q->qdio_bufs[bidx]; | 2386 | newbuf->buffer = q->qdio_bufs[bidx]; |
| 2396 | skb_queue_head_init(&newbuf->skb_list); | 2387 | skb_queue_head_init(&newbuf->skb_list); |
| 2397 | lockdep_set_class(&newbuf->skb_list.lock, &qdio_out_skb_queue_key); | 2388 | lockdep_set_class(&newbuf->skb_list.lock, &qdio_out_skb_queue_key); |
| 2398 | newbuf->q = q; | 2389 | newbuf->q = q; |
| @@ -2411,6 +2402,28 @@ out: | |||
| 2411 | return rc; | 2402 | return rc; |
| 2412 | } | 2403 | } |
| 2413 | 2404 | ||
| 2405 | static void qeth_free_qdio_out_buf(struct qeth_qdio_out_q *q) | ||
| 2406 | { | ||
| 2407 | if (!q) | ||
| 2408 | return; | ||
| 2409 | |||
| 2410 | qdio_free_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q); | ||
| 2411 | kfree(q); | ||
| 2412 | } | ||
| 2413 | |||
| 2414 | static struct qeth_qdio_out_q *qeth_alloc_qdio_out_buf(void) | ||
| 2415 | { | ||
| 2416 | struct qeth_qdio_out_q *q = kzalloc(sizeof(*q), GFP_KERNEL); | ||
| 2417 | |||
| 2418 | if (!q) | ||
| 2419 | return NULL; | ||
| 2420 | |||
| 2421 | if (qdio_alloc_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q)) { | ||
| 2422 | kfree(q); | ||
| 2423 | return NULL; | ||
| 2424 | } | ||
| 2425 | return q; | ||
| 2426 | } | ||
| 2414 | 2427 | ||
| 2415 | static int qeth_alloc_qdio_buffers(struct qeth_card *card) | 2428 | static int qeth_alloc_qdio_buffers(struct qeth_card *card) |
| 2416 | { | 2429 | { |
| @@ -2422,19 +2435,11 @@ static int qeth_alloc_qdio_buffers(struct qeth_card *card) | |||
| 2422 | QETH_QDIO_ALLOCATED) != QETH_QDIO_UNINITIALIZED) | 2435 | QETH_QDIO_ALLOCATED) != QETH_QDIO_UNINITIALIZED) |
| 2423 | return 0; | 2436 | return 0; |
| 2424 | 2437 | ||
| 2425 | card->qdio.in_q = kzalloc(sizeof(struct qeth_qdio_q), | 2438 | QETH_DBF_TEXT(SETUP, 2, "inq"); |
| 2426 | GFP_KERNEL); | 2439 | card->qdio.in_q = qeth_alloc_qdio_queue(); |
| 2427 | if (!card->qdio.in_q) | 2440 | if (!card->qdio.in_q) |
| 2428 | goto out_nomem; | 2441 | goto out_nomem; |
| 2429 | QETH_DBF_TEXT(SETUP, 2, "inq"); | 2442 | |
| 2430 | QETH_DBF_HEX(SETUP, 2, &card->qdio.in_q, sizeof(void *)); | ||
| 2431 | memset(card->qdio.in_q, 0, sizeof(struct qeth_qdio_q)); | ||
| 2432 | /* give inbound qeth_qdio_buffers their qdio_buffers */ | ||
| 2433 | for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; ++i) { | ||
| 2434 | card->qdio.in_q->bufs[i].buffer = | ||
| 2435 | &card->qdio.in_q->qdio_bufs[i]; | ||
| 2436 | card->qdio.in_q->bufs[i].rx_skb = NULL; | ||
| 2437 | } | ||
| 2438 | /* inbound buffer pool */ | 2443 | /* inbound buffer pool */ |
| 2439 | if (qeth_alloc_buffer_pool(card)) | 2444 | if (qeth_alloc_buffer_pool(card)) |
| 2440 | goto out_freeinq; | 2445 | goto out_freeinq; |
| @@ -2446,8 +2451,7 @@ static int qeth_alloc_qdio_buffers(struct qeth_card *card) | |||
| 2446 | if (!card->qdio.out_qs) | 2451 | if (!card->qdio.out_qs) |
| 2447 | goto out_freepool; | 2452 | goto out_freepool; |
| 2448 | for (i = 0; i < card->qdio.no_out_queues; ++i) { | 2453 | for (i = 0; i < card->qdio.no_out_queues; ++i) { |
| 2449 | card->qdio.out_qs[i] = kzalloc(sizeof(struct qeth_qdio_out_q), | 2454 | card->qdio.out_qs[i] = qeth_alloc_qdio_out_buf(); |
| 2450 | GFP_KERNEL); | ||
| 2451 | if (!card->qdio.out_qs[i]) | 2455 | if (!card->qdio.out_qs[i]) |
| 2452 | goto out_freeoutq; | 2456 | goto out_freeoutq; |
| 2453 | QETH_DBF_TEXT_(SETUP, 2, "outq %i", i); | 2457 | QETH_DBF_TEXT_(SETUP, 2, "outq %i", i); |
| @@ -2476,7 +2480,7 @@ out_freeoutqbufs: | |||
| 2476 | } | 2480 | } |
| 2477 | out_freeoutq: | 2481 | out_freeoutq: |
| 2478 | while (i > 0) { | 2482 | while (i > 0) { |
| 2479 | kfree(card->qdio.out_qs[--i]); | 2483 | qeth_free_qdio_out_buf(card->qdio.out_qs[--i]); |
| 2480 | qeth_clear_outq_buffers(card->qdio.out_qs[i], 1); | 2484 | qeth_clear_outq_buffers(card->qdio.out_qs[i], 1); |
| 2481 | } | 2485 | } |
| 2482 | kfree(card->qdio.out_qs); | 2486 | kfree(card->qdio.out_qs); |
| @@ -2484,13 +2488,42 @@ out_freeoutq: | |||
| 2484 | out_freepool: | 2488 | out_freepool: |
| 2485 | qeth_free_buffer_pool(card); | 2489 | qeth_free_buffer_pool(card); |
| 2486 | out_freeinq: | 2490 | out_freeinq: |
| 2487 | kfree(card->qdio.in_q); | 2491 | qeth_free_qdio_queue(card->qdio.in_q); |
| 2488 | card->qdio.in_q = NULL; | 2492 | card->qdio.in_q = NULL; |
| 2489 | out_nomem: | 2493 | out_nomem: |
| 2490 | atomic_set(&card->qdio.state, QETH_QDIO_UNINITIALIZED); | 2494 | atomic_set(&card->qdio.state, QETH_QDIO_UNINITIALIZED); |
| 2491 | return -ENOMEM; | 2495 | return -ENOMEM; |
| 2492 | } | 2496 | } |
| 2493 | 2497 | ||
| 2498 | static void qeth_free_qdio_buffers(struct qeth_card *card) | ||
| 2499 | { | ||
| 2500 | int i, j; | ||
| 2501 | |||
| 2502 | if (atomic_xchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED) == | ||
| 2503 | QETH_QDIO_UNINITIALIZED) | ||
| 2504 | return; | ||
| 2505 | |||
| 2506 | qeth_free_cq(card); | ||
| 2507 | cancel_delayed_work_sync(&card->buffer_reclaim_work); | ||
| 2508 | for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { | ||
| 2509 | if (card->qdio.in_q->bufs[j].rx_skb) | ||
| 2510 | dev_kfree_skb_any(card->qdio.in_q->bufs[j].rx_skb); | ||
| 2511 | } | ||
| 2512 | qeth_free_qdio_queue(card->qdio.in_q); | ||
| 2513 | card->qdio.in_q = NULL; | ||
| 2514 | /* inbound buffer pool */ | ||
| 2515 | qeth_free_buffer_pool(card); | ||
| 2516 | /* free outbound qdio_qs */ | ||
| 2517 | if (card->qdio.out_qs) { | ||
| 2518 | for (i = 0; i < card->qdio.no_out_queues; ++i) { | ||
| 2519 | qeth_clear_outq_buffers(card->qdio.out_qs[i], 1); | ||
| 2520 | qeth_free_qdio_out_buf(card->qdio.out_qs[i]); | ||
| 2521 | } | ||
| 2522 | kfree(card->qdio.out_qs); | ||
| 2523 | card->qdio.out_qs = NULL; | ||
| 2524 | } | ||
| 2525 | } | ||
| 2526 | |||
| 2494 | static void qeth_create_qib_param_field(struct qeth_card *card, | 2527 | static void qeth_create_qib_param_field(struct qeth_card *card, |
| 2495 | char *param_field) | 2528 | char *param_field) |
| 2496 | { | 2529 | { |
| @@ -2788,8 +2821,8 @@ int qeth_init_qdio_queues(struct qeth_card *card) | |||
| 2788 | QETH_DBF_TEXT(SETUP, 2, "initqdqs"); | 2821 | QETH_DBF_TEXT(SETUP, 2, "initqdqs"); |
| 2789 | 2822 | ||
| 2790 | /* inbound queue */ | 2823 | /* inbound queue */ |
| 2791 | memset(card->qdio.in_q->qdio_bufs, 0, | 2824 | qdio_reset_buffers(card->qdio.in_q->qdio_bufs, |
| 2792 | QDIO_MAX_BUFFERS_PER_Q * sizeof(struct qdio_buffer)); | 2825 | QDIO_MAX_BUFFERS_PER_Q); |
| 2793 | qeth_initialize_working_pool_list(card); | 2826 | qeth_initialize_working_pool_list(card); |
| 2794 | /*give only as many buffers to hardware as we have buffer pool entries*/ | 2827 | /*give only as many buffers to hardware as we have buffer pool entries*/ |
| 2795 | for (i = 0; i < card->qdio.in_buf_pool.buf_count - 1; ++i) | 2828 | for (i = 0; i < card->qdio.in_buf_pool.buf_count - 1; ++i) |
| @@ -2811,8 +2844,8 @@ int qeth_init_qdio_queues(struct qeth_card *card) | |||
| 2811 | 2844 | ||
| 2812 | /* outbound queue */ | 2845 | /* outbound queue */ |
| 2813 | for (i = 0; i < card->qdio.no_out_queues; ++i) { | 2846 | for (i = 0; i < card->qdio.no_out_queues; ++i) { |
| 2814 | memset(card->qdio.out_qs[i]->qdio_bufs, 0, | 2847 | qdio_reset_buffers(card->qdio.out_qs[i]->qdio_bufs, |
| 2815 | QDIO_MAX_BUFFERS_PER_Q * sizeof(struct qdio_buffer)); | 2848 | QDIO_MAX_BUFFERS_PER_Q); |
| 2816 | for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { | 2849 | for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { |
| 2817 | qeth_clear_output_buffer(card->qdio.out_qs[i], | 2850 | qeth_clear_output_buffer(card->qdio.out_qs[i], |
| 2818 | card->qdio.out_qs[i]->bufs[j], | 2851 | card->qdio.out_qs[i]->bufs[j], |
| @@ -3569,7 +3602,7 @@ static void qeth_qdio_cq_handler(struct qeth_card *card, | |||
| 3569 | 3602 | ||
| 3570 | for (i = first_element; i < first_element + count; ++i) { | 3603 | for (i = first_element; i < first_element + count; ++i) { |
| 3571 | int bidx = i % QDIO_MAX_BUFFERS_PER_Q; | 3604 | int bidx = i % QDIO_MAX_BUFFERS_PER_Q; |
| 3572 | struct qdio_buffer *buffer = &cq->qdio_bufs[bidx]; | 3605 | struct qdio_buffer *buffer = cq->qdio_bufs[bidx]; |
| 3573 | int e; | 3606 | int e; |
| 3574 | 3607 | ||
| 3575 | e = 0; | 3608 | e = 0; |
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 06025cdaa4ad..495e1cb3afa6 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c | |||
| @@ -14,27 +14,10 @@ | |||
| 14 | #include "zfcp_ext.h" | 14 | #include "zfcp_ext.h" |
| 15 | #include "zfcp_qdio.h" | 15 | #include "zfcp_qdio.h" |
| 16 | 16 | ||
| 17 | #define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer)) | ||
| 18 | |||
| 19 | static bool enable_multibuffer = 1; | 17 | static bool enable_multibuffer = 1; |
| 20 | module_param_named(datarouter, enable_multibuffer, bool, 0400); | 18 | module_param_named(datarouter, enable_multibuffer, bool, 0400); |
| 21 | MODULE_PARM_DESC(datarouter, "Enable hardware data router support (default on)"); | 19 | MODULE_PARM_DESC(datarouter, "Enable hardware data router support (default on)"); |
| 22 | 20 | ||
| 23 | static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal) | ||
| 24 | { | ||
| 25 | int pos; | ||
| 26 | |||
| 27 | for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE) { | ||
| 28 | sbal[pos] = (struct qdio_buffer *) get_zeroed_page(GFP_KERNEL); | ||
| 29 | if (!sbal[pos]) | ||
| 30 | return -ENOMEM; | ||
| 31 | } | ||
| 32 | for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos++) | ||
| 33 | if (pos % QBUFF_PER_PAGE) | ||
| 34 | sbal[pos] = sbal[pos - 1] + 1; | ||
| 35 | return 0; | ||
| 36 | } | ||
| 37 | |||
| 38 | static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id, | 21 | static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id, |
| 39 | unsigned int qdio_err) | 22 | unsigned int qdio_err) |
| 40 | { | 23 | { |
| @@ -326,15 +309,30 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id, | |||
| 326 | static int zfcp_qdio_allocate(struct zfcp_qdio *qdio) | 309 | static int zfcp_qdio_allocate(struct zfcp_qdio *qdio) |
| 327 | { | 310 | { |
| 328 | struct qdio_initialize init_data; | 311 | struct qdio_initialize init_data; |
| 312 | int ret; | ||
| 329 | 313 | ||
| 330 | if (zfcp_qdio_buffers_enqueue(qdio->req_q) || | 314 | ret = qdio_alloc_buffers(qdio->req_q, QDIO_MAX_BUFFERS_PER_Q); |
| 331 | zfcp_qdio_buffers_enqueue(qdio->res_q)) | 315 | if (ret) |
| 332 | return -ENOMEM; | 316 | return -ENOMEM; |
| 333 | 317 | ||
| 318 | ret = qdio_alloc_buffers(qdio->res_q, QDIO_MAX_BUFFERS_PER_Q); | ||
| 319 | if (ret) | ||
| 320 | goto free_req_q; | ||
| 321 | |||
| 334 | zfcp_qdio_setup_init_data(&init_data, qdio); | 322 | zfcp_qdio_setup_init_data(&init_data, qdio); |
| 335 | init_waitqueue_head(&qdio->req_q_wq); | 323 | init_waitqueue_head(&qdio->req_q_wq); |
| 336 | 324 | ||
| 337 | return qdio_allocate(&init_data); | 325 | ret = qdio_allocate(&init_data); |
| 326 | if (ret) | ||
| 327 | goto free_res_q; | ||
| 328 | |||
| 329 | return 0; | ||
| 330 | |||
| 331 | free_res_q: | ||
| 332 | qdio_free_buffers(qdio->res_q, QDIO_MAX_BUFFERS_PER_Q); | ||
| 333 | free_req_q: | ||
| 334 | qdio_free_buffers(qdio->req_q, QDIO_MAX_BUFFERS_PER_Q); | ||
| 335 | return ret; | ||
| 338 | } | 336 | } |
| 339 | 337 | ||
| 340 | /** | 338 | /** |
| @@ -448,19 +446,14 @@ failed_establish: | |||
| 448 | 446 | ||
| 449 | void zfcp_qdio_destroy(struct zfcp_qdio *qdio) | 447 | void zfcp_qdio_destroy(struct zfcp_qdio *qdio) |
| 450 | { | 448 | { |
| 451 | int p; | ||
| 452 | |||
| 453 | if (!qdio) | 449 | if (!qdio) |
| 454 | return; | 450 | return; |
| 455 | 451 | ||
| 456 | if (qdio->adapter->ccw_device) | 452 | if (qdio->adapter->ccw_device) |
| 457 | qdio_free(qdio->adapter->ccw_device); | 453 | qdio_free(qdio->adapter->ccw_device); |
| 458 | 454 | ||
| 459 | for (p = 0; p < QDIO_MAX_BUFFERS_PER_Q; p += QBUFF_PER_PAGE) { | 455 | qdio_free_buffers(qdio->req_q, QDIO_MAX_BUFFERS_PER_Q); |
| 460 | free_page((unsigned long) qdio->req_q[p]); | 456 | qdio_free_buffers(qdio->res_q, QDIO_MAX_BUFFERS_PER_Q); |
| 461 | free_page((unsigned long) qdio->res_q[p]); | ||
| 462 | } | ||
| 463 | |||
| 464 | kfree(qdio); | 457 | kfree(qdio); |
| 465 | } | 458 | } |
| 466 | 459 | ||
| @@ -475,7 +468,7 @@ int zfcp_qdio_setup(struct zfcp_adapter *adapter) | |||
| 475 | qdio->adapter = adapter; | 468 | qdio->adapter = adapter; |
| 476 | 469 | ||
| 477 | if (zfcp_qdio_allocate(qdio)) { | 470 | if (zfcp_qdio_allocate(qdio)) { |
| 478 | zfcp_qdio_destroy(qdio); | 471 | kfree(qdio); |
| 479 | return -ENOMEM; | 472 | return -ENOMEM; |
| 480 | } | 473 | } |
| 481 | 474 | ||
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 76dd54122f76..f57312fced80 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
| @@ -1293,7 +1293,7 @@ config DIAG288_WATCHDOG | |||
| 1293 | both. | 1293 | both. |
| 1294 | 1294 | ||
| 1295 | To compile this driver as a module, choose M here. The module | 1295 | To compile this driver as a module, choose M here. The module |
| 1296 | will be called vmwatchdog. | 1296 | will be called diag288_wdt. |
| 1297 | 1297 | ||
| 1298 | # SUPERH (sh + sh64) Architecture | 1298 | # SUPERH (sh + sh64) Architecture |
| 1299 | 1299 | ||
