Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/s390/linux

Pull s390 fixes from Martin Schwidefsky:
 "A couple of bug fixes, the most hairy on is the flush_tlb_kernel_range
  fix.  Another case of "how could this ever have worked?"."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
  s390/kdump: Do not add standby memory for kdump
  drivers/i2c: remove !S390 dependency, add missing GENERIC_HARDIRQS dependencies
  s390/scm: process availability
  s390/scm_blk: suspend writes
  s390/scm_drv: extend notify callback
  s390/scm_blk: fix request number accounting
  s390/mm: fix flush_tlb_kernel_range()
  s390/mm: fix vmemmap size calculation
  s390: critical section cleanup vs. machine checks
  • Loading branch information
torvalds committed Mar 18, 2013
2 parents 1c6ba37 + 52319b4 commit 991657a
Show file tree
Hide file tree
Showing 14 changed files with 136 additions and 23 deletions.
6 changes: 5 additions & 1 deletion arch/s390/include/asm/eadm.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ struct arsb {
u32 reserved[4];
} __packed;

#define EQC_WR_PROHIBIT 22

struct msb {
u8 fmt:4;
u8 oc:4;
Expand Down Expand Up @@ -96,11 +98,13 @@ struct scm_device {
#define OP_STATE_TEMP_ERR 2
#define OP_STATE_PERM_ERR 3

enum scm_event {SCM_CHANGE, SCM_AVAIL};

struct scm_driver {
struct device_driver drv;
int (*probe) (struct scm_device *scmdev);
int (*remove) (struct scm_device *scmdev);
void (*notify) (struct scm_device *scmdev);
void (*notify) (struct scm_device *scmdev, enum scm_event event);
void (*handler) (struct scm_device *scmdev, void *data, int error);
};

Expand Down
2 changes: 0 additions & 2 deletions arch/s390/include/asm/tlbflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,6 @@ static inline void __tlb_flush_idte(unsigned long asce)

static inline void __tlb_flush_mm(struct mm_struct * mm)
{
if (unlikely(cpumask_empty(mm_cpumask(mm))))
return;
/*
* If the machine has IDTE we prefer to do a per mm flush
* on all cpus instead of doing a local flush if the mm
Expand Down
3 changes: 2 additions & 1 deletion arch/s390/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,8 @@ ENTRY(mcck_int_handler)
UPDATE_VTIME %r14,%r15,__LC_MCCK_ENTER_TIMER
mcck_skip:
SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+32,__LC_PANIC_STACK,PAGE_SHIFT
mvc __PT_R0(64,%r11),__LC_GPREGS_SAVE_AREA
stm %r0,%r7,__PT_R0(%r11)
mvc __PT_R8(32,%r11),__LC_GPREGS_SAVE_AREA+32
stm %r8,%r9,__PT_PSW(%r11)
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
l %r1,BASED(.Ldo_machine_check)
Expand Down
5 changes: 3 additions & 2 deletions arch/s390/kernel/entry64.S
Original file line number Diff line number Diff line change
Expand Up @@ -678,8 +678,9 @@ ENTRY(mcck_int_handler)
UPDATE_VTIME %r14,__LC_MCCK_ENTER_TIMER
LAST_BREAK %r14
mcck_skip:
lghi %r14,__LC_GPREGS_SAVE_AREA
mvc __PT_R0(128,%r11),0(%r14)
lghi %r14,__LC_GPREGS_SAVE_AREA+64
stmg %r0,%r7,__PT_R0(%r11)
mvc __PT_R8(64,%r11),0(%r14)
stmg %r8,%r9,__PT_PSW(%r11)
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
lgr %r2,%r11 # pass pointer to pt_regs
Expand Down
2 changes: 2 additions & 0 deletions arch/s390/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,8 @@ static void __init setup_memory_end(void)

/* Split remaining virtual space between 1:1 mapping & vmemmap array */
tmp = VMALLOC_START / (PAGE_SIZE + sizeof(struct page));
/* vmemmap contains a multiple of PAGES_PER_SECTION struct pages */
tmp = SECTION_ALIGN_UP(tmp);
tmp = VMALLOC_START - tmp * sizeof(struct page);
tmp &= ~((vmax >> 11) - 1); /* align to page table level */
tmp = min(tmp, 1UL << MAX_PHYSMEM_BITS);
Expand Down
2 changes: 1 addition & 1 deletion drivers/i2c/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

menuconfig I2C
tristate "I2C support"
depends on !S390
select RT_MUTEXES
---help---
I2C (pronounce: I-squared-C) is a slow serial bus protocol used in
Expand Down Expand Up @@ -76,6 +75,7 @@ config I2C_HELPER_AUTO

config I2C_SMBUS
tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO
depends on GENERIC_HARDIRQS
help
Say Y here if you want support for SMBus extensions to the I2C
specification. At the moment, the only supported extension is
Expand Down
6 changes: 4 additions & 2 deletions drivers/i2c/busses/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ config I2C_I801

config I2C_ISCH
tristate "Intel SCH SMBus 1.0"
depends on PCI
depends on PCI && GENERIC_HARDIRQS
select LPC_SCH
help
Say Y here if you want to use SMBus controller on the Intel SCH
Expand Down Expand Up @@ -543,6 +543,7 @@ config I2C_NUC900

config I2C_OCORES
tristate "OpenCores I2C Controller"
depends on GENERIC_HARDIRQS
help
If you say yes to this option, support will be included for the
OpenCores I2C controller. For details see
Expand Down Expand Up @@ -777,7 +778,7 @@ config I2C_DIOLAN_U2C

config I2C_PARPORT
tristate "Parallel port adapter"
depends on PARPORT
depends on PARPORT && GENERIC_HARDIRQS
select I2C_ALGOBIT
select I2C_SMBUS
help
Expand All @@ -802,6 +803,7 @@ config I2C_PARPORT

config I2C_PARPORT_LIGHT
tristate "Parallel port adapter (light)"
depends on GENERIC_HARDIRQS
select I2C_ALGOBIT
select I2C_SMBUS
help
Expand Down
69 changes: 62 additions & 7 deletions drivers/s390/block/scm_blk.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ static const struct block_device_operations scm_blk_devops = {
.release = scm_release,
};

static bool scm_permit_request(struct scm_blk_dev *bdev, struct request *req)
{
return rq_data_dir(req) != WRITE || bdev->state != SCM_WR_PROHIBIT;
}

static void scm_request_prepare(struct scm_request *scmrq)
{
struct scm_blk_dev *bdev = scmrq->bdev;
Expand Down Expand Up @@ -195,14 +200,18 @@ void scm_request_requeue(struct scm_request *scmrq)

scm_release_cluster(scmrq);
blk_requeue_request(bdev->rq, scmrq->request);
atomic_dec(&bdev->queued_reqs);
scm_request_done(scmrq);
scm_ensure_queue_restart(bdev);
}

void scm_request_finish(struct scm_request *scmrq)
{
struct scm_blk_dev *bdev = scmrq->bdev;

scm_release_cluster(scmrq);
blk_end_request_all(scmrq->request, scmrq->error);
atomic_dec(&bdev->queued_reqs);
scm_request_done(scmrq);
}

Expand All @@ -218,6 +227,10 @@ static void scm_blk_request(struct request_queue *rq)
if (req->cmd_type != REQ_TYPE_FS)
continue;

if (!scm_permit_request(bdev, req)) {
scm_ensure_queue_restart(bdev);
return;
}
scmrq = scm_request_fetch();
if (!scmrq) {
SCM_LOG(5, "no request");
Expand All @@ -231,11 +244,13 @@ static void scm_blk_request(struct request_queue *rq)
return;
}
if (scm_need_cluster_request(scmrq)) {
atomic_inc(&bdev->queued_reqs);
blk_start_request(req);
scm_initiate_cluster_request(scmrq);
return;
}
scm_request_prepare(scmrq);
atomic_inc(&bdev->queued_reqs);
blk_start_request(req);

ret = scm_start_aob(scmrq->aob);
Expand All @@ -244,7 +259,6 @@ static void scm_blk_request(struct request_queue *rq)
scm_request_requeue(scmrq);
return;
}
atomic_inc(&bdev->queued_reqs);
}
}

Expand Down Expand Up @@ -280,6 +294,38 @@ void scm_blk_irq(struct scm_device *scmdev, void *data, int error)
tasklet_hi_schedule(&bdev->tasklet);
}

static void scm_blk_handle_error(struct scm_request *scmrq)
{
struct scm_blk_dev *bdev = scmrq->bdev;
unsigned long flags;

if (scmrq->error != -EIO)
goto restart;

/* For -EIO the response block is valid. */
switch (scmrq->aob->response.eqc) {
case EQC_WR_PROHIBIT:
spin_lock_irqsave(&bdev->lock, flags);
if (bdev->state != SCM_WR_PROHIBIT)
pr_info("%lu: Write access to the SCM increment is suspended\n",
(unsigned long) bdev->scmdev->address);
bdev->state = SCM_WR_PROHIBIT;
spin_unlock_irqrestore(&bdev->lock, flags);
goto requeue;
default:
break;
}

restart:
if (!scm_start_aob(scmrq->aob))
return;

requeue:
spin_lock_irqsave(&bdev->rq_lock, flags);
scm_request_requeue(scmrq);
spin_unlock_irqrestore(&bdev->rq_lock, flags);
}

static void scm_blk_tasklet(struct scm_blk_dev *bdev)
{
struct scm_request *scmrq;
Expand All @@ -293,11 +339,8 @@ static void scm_blk_tasklet(struct scm_blk_dev *bdev)
spin_unlock_irqrestore(&bdev->lock, flags);

if (scmrq->error && scmrq->retries-- > 0) {
if (scm_start_aob(scmrq->aob)) {
spin_lock_irqsave(&bdev->rq_lock, flags);
scm_request_requeue(scmrq);
spin_unlock_irqrestore(&bdev->rq_lock, flags);
}
scm_blk_handle_error(scmrq);

/* Request restarted or requeued, handle next. */
spin_lock_irqsave(&bdev->lock, flags);
continue;
Expand All @@ -310,7 +353,6 @@ static void scm_blk_tasklet(struct scm_blk_dev *bdev)
}

scm_request_finish(scmrq);
atomic_dec(&bdev->queued_reqs);
spin_lock_irqsave(&bdev->lock, flags);
}
spin_unlock_irqrestore(&bdev->lock, flags);
Expand All @@ -332,6 +374,7 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev)
}

bdev->scmdev = scmdev;
bdev->state = SCM_OPER;
spin_lock_init(&bdev->rq_lock);
spin_lock_init(&bdev->lock);
INIT_LIST_HEAD(&bdev->finished_requests);
Expand Down Expand Up @@ -396,6 +439,18 @@ void scm_blk_dev_cleanup(struct scm_blk_dev *bdev)
put_disk(bdev->gendisk);
}

void scm_blk_set_available(struct scm_blk_dev *bdev)
{
unsigned long flags;

spin_lock_irqsave(&bdev->lock, flags);
if (bdev->state == SCM_WR_PROHIBIT)
pr_info("%lu: Write access to the SCM increment is restored\n",
(unsigned long) bdev->scmdev->address);
bdev->state = SCM_OPER;
spin_unlock_irqrestore(&bdev->lock, flags);
}

static int __init scm_blk_init(void)
{
int ret = -EINVAL;
Expand Down
2 changes: 2 additions & 0 deletions drivers/s390/block/scm_blk.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct scm_blk_dev {
spinlock_t rq_lock; /* guard the request queue */
spinlock_t lock; /* guard the rest of the blockdev */
atomic_t queued_reqs;
enum {SCM_OPER, SCM_WR_PROHIBIT} state;
struct list_head finished_requests;
#ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE
struct list_head cluster_list;
Expand Down Expand Up @@ -48,6 +49,7 @@ struct scm_request {

int scm_blk_dev_setup(struct scm_blk_dev *, struct scm_device *);
void scm_blk_dev_cleanup(struct scm_blk_dev *);
void scm_blk_set_available(struct scm_blk_dev *);
void scm_blk_irq(struct scm_device *, void *, int);

void scm_request_finish(struct scm_request *);
Expand Down
23 changes: 17 additions & 6 deletions drivers/s390/block/scm_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,23 @@
#include <asm/eadm.h>
#include "scm_blk.h"

static void notify(struct scm_device *scmdev)
static void scm_notify(struct scm_device *scmdev, enum scm_event event)
{
pr_info("%lu: The capabilities of the SCM increment changed\n",
(unsigned long) scmdev->address);
SCM_LOG(2, "State changed");
SCM_LOG_STATE(2, scmdev);
struct scm_blk_dev *bdev = dev_get_drvdata(&scmdev->dev);

switch (event) {
case SCM_CHANGE:
pr_info("%lu: The capabilities of the SCM increment changed\n",
(unsigned long) scmdev->address);
SCM_LOG(2, "State changed");
SCM_LOG_STATE(2, scmdev);
break;
case SCM_AVAIL:
SCM_LOG(2, "Increment available");
SCM_LOG_STATE(2, scmdev);
scm_blk_set_available(bdev);
break;
}
}

static int scm_probe(struct scm_device *scmdev)
Expand Down Expand Up @@ -64,7 +75,7 @@ static struct scm_driver scm_drv = {
.name = "scm_block",
.owner = THIS_MODULE,
},
.notify = notify,
.notify = scm_notify,
.probe = scm_probe,
.remove = scm_remove,
.handler = scm_blk_irq,
Expand Down
2 changes: 2 additions & 0 deletions drivers/s390/char/sclp_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,8 @@ static int __init sclp_detect_standby_memory(void)
struct read_storage_sccb *sccb;
int i, id, assigned, rc;

if (OLDMEM_BASE) /* No standby memory in kdump mode */
return 0;
if (!early_read_info_sccb_valid)
return 0;
if ((sclp_facilities & 0xe00000000000ULL) != 0xe00000000000ULL)
Expand Down
17 changes: 17 additions & 0 deletions drivers/s390/cio/chsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,20 @@ static void chsc_process_sei_scm_change(struct chsc_sei_nt0_area *sei_area)
" failed (rc=%d).\n", ret);
}

static void chsc_process_sei_scm_avail(struct chsc_sei_nt0_area *sei_area)
{
int ret;

CIO_CRW_EVENT(4, "chsc: scm available information\n");
if (sei_area->rs != 7)
return;

ret = scm_process_availability_information();
if (ret)
CIO_CRW_EVENT(0, "chsc: process availability information"
" failed (rc=%d).\n", ret);
}

static void chsc_process_sei_nt2(struct chsc_sei_nt2_area *sei_area)
{
switch (sei_area->cc) {
Expand Down Expand Up @@ -468,6 +482,9 @@ static void chsc_process_sei_nt0(struct chsc_sei_nt0_area *sei_area)
case 12: /* scm change notification */
chsc_process_sei_scm_change(sei_area);
break;
case 14: /* scm available notification */
chsc_process_sei_scm_avail(sei_area);
break;
default: /* other stuff */
CIO_CRW_EVENT(2, "chsc: sei nt0 unhandled cc=%d\n",
sei_area->cc);
Expand Down
2 changes: 2 additions & 0 deletions drivers/s390/cio/chsc.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,10 @@ int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token);

#ifdef CONFIG_SCM_BUS
int scm_update_information(void);
int scm_process_availability_information(void);
#else /* CONFIG_SCM_BUS */
static inline int scm_update_information(void) { return 0; }
static inline int scm_process_availability_information(void) { return 0; }
#endif /* CONFIG_SCM_BUS */


Expand Down
Loading

0 comments on commit 991657a

Please sign in to comment.