Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/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
This commit is contained in:
commit
991657a39d
|
@ -34,6 +34,8 @@ struct arsb {
|
||||||
u32 reserved[4];
|
u32 reserved[4];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
#define EQC_WR_PROHIBIT 22
|
||||||
|
|
||||||
struct msb {
|
struct msb {
|
||||||
u8 fmt:4;
|
u8 fmt:4;
|
||||||
u8 oc:4;
|
u8 oc:4;
|
||||||
|
@ -96,11 +98,13 @@ struct scm_device {
|
||||||
#define OP_STATE_TEMP_ERR 2
|
#define OP_STATE_TEMP_ERR 2
|
||||||
#define OP_STATE_PERM_ERR 3
|
#define OP_STATE_PERM_ERR 3
|
||||||
|
|
||||||
|
enum scm_event {SCM_CHANGE, SCM_AVAIL};
|
||||||
|
|
||||||
struct scm_driver {
|
struct scm_driver {
|
||||||
struct device_driver drv;
|
struct device_driver drv;
|
||||||
int (*probe) (struct scm_device *scmdev);
|
int (*probe) (struct scm_device *scmdev);
|
||||||
int (*remove) (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);
|
void (*handler) (struct scm_device *scmdev, void *data, int error);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -74,8 +74,6 @@ static inline void __tlb_flush_idte(unsigned long asce)
|
||||||
|
|
||||||
static inline void __tlb_flush_mm(struct mm_struct * mm)
|
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
|
* 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
|
* on all cpus instead of doing a local flush if the mm
|
||||||
|
|
|
@ -636,7 +636,8 @@ ENTRY(mcck_int_handler)
|
||||||
UPDATE_VTIME %r14,%r15,__LC_MCCK_ENTER_TIMER
|
UPDATE_VTIME %r14,%r15,__LC_MCCK_ENTER_TIMER
|
||||||
mcck_skip:
|
mcck_skip:
|
||||||
SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+32,__LC_PANIC_STACK,PAGE_SHIFT
|
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)
|
stm %r8,%r9,__PT_PSW(%r11)
|
||||||
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
|
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
|
||||||
l %r1,BASED(.Ldo_machine_check)
|
l %r1,BASED(.Ldo_machine_check)
|
||||||
|
|
|
@ -678,8 +678,9 @@ ENTRY(mcck_int_handler)
|
||||||
UPDATE_VTIME %r14,__LC_MCCK_ENTER_TIMER
|
UPDATE_VTIME %r14,__LC_MCCK_ENTER_TIMER
|
||||||
LAST_BREAK %r14
|
LAST_BREAK %r14
|
||||||
mcck_skip:
|
mcck_skip:
|
||||||
lghi %r14,__LC_GPREGS_SAVE_AREA
|
lghi %r14,__LC_GPREGS_SAVE_AREA+64
|
||||||
mvc __PT_R0(128,%r11),0(%r14)
|
stmg %r0,%r7,__PT_R0(%r11)
|
||||||
|
mvc __PT_R8(64,%r11),0(%r14)
|
||||||
stmg %r8,%r9,__PT_PSW(%r11)
|
stmg %r8,%r9,__PT_PSW(%r11)
|
||||||
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
||||||
lgr %r2,%r11 # pass pointer to pt_regs
|
lgr %r2,%r11 # pass pointer to pt_regs
|
||||||
|
|
|
@ -571,6 +571,8 @@ static void __init setup_memory_end(void)
|
||||||
|
|
||||||
/* Split remaining virtual space between 1:1 mapping & vmemmap array */
|
/* Split remaining virtual space between 1:1 mapping & vmemmap array */
|
||||||
tmp = VMALLOC_START / (PAGE_SIZE + sizeof(struct page));
|
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 = VMALLOC_START - tmp * sizeof(struct page);
|
||||||
tmp &= ~((vmax >> 11) - 1); /* align to page table level */
|
tmp &= ~((vmax >> 11) - 1); /* align to page table level */
|
||||||
tmp = min(tmp, 1UL << MAX_PHYSMEM_BITS);
|
tmp = min(tmp, 1UL << MAX_PHYSMEM_BITS);
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
menuconfig I2C
|
menuconfig I2C
|
||||||
tristate "I2C support"
|
tristate "I2C support"
|
||||||
depends on !S390
|
|
||||||
select RT_MUTEXES
|
select RT_MUTEXES
|
||||||
---help---
|
---help---
|
||||||
I2C (pronounce: I-squared-C) is a slow serial bus protocol used in
|
I2C (pronounce: I-squared-C) is a slow serial bus protocol used in
|
||||||
|
@ -76,6 +75,7 @@ config I2C_HELPER_AUTO
|
||||||
|
|
||||||
config I2C_SMBUS
|
config I2C_SMBUS
|
||||||
tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO
|
tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO
|
||||||
|
depends on GENERIC_HARDIRQS
|
||||||
help
|
help
|
||||||
Say Y here if you want support for SMBus extensions to the I2C
|
Say Y here if you want support for SMBus extensions to the I2C
|
||||||
specification. At the moment, the only supported extension is
|
specification. At the moment, the only supported extension is
|
||||||
|
|
|
@ -114,7 +114,7 @@ config I2C_I801
|
||||||
|
|
||||||
config I2C_ISCH
|
config I2C_ISCH
|
||||||
tristate "Intel SCH SMBus 1.0"
|
tristate "Intel SCH SMBus 1.0"
|
||||||
depends on PCI
|
depends on PCI && GENERIC_HARDIRQS
|
||||||
select LPC_SCH
|
select LPC_SCH
|
||||||
help
|
help
|
||||||
Say Y here if you want to use SMBus controller on the Intel SCH
|
Say Y here if you want to use SMBus controller on the Intel SCH
|
||||||
|
@ -543,6 +543,7 @@ config I2C_NUC900
|
||||||
|
|
||||||
config I2C_OCORES
|
config I2C_OCORES
|
||||||
tristate "OpenCores I2C Controller"
|
tristate "OpenCores I2C Controller"
|
||||||
|
depends on GENERIC_HARDIRQS
|
||||||
help
|
help
|
||||||
If you say yes to this option, support will be included for the
|
If you say yes to this option, support will be included for the
|
||||||
OpenCores I2C controller. For details see
|
OpenCores I2C controller. For details see
|
||||||
|
@ -777,7 +778,7 @@ config I2C_DIOLAN_U2C
|
||||||
|
|
||||||
config I2C_PARPORT
|
config I2C_PARPORT
|
||||||
tristate "Parallel port adapter"
|
tristate "Parallel port adapter"
|
||||||
depends on PARPORT
|
depends on PARPORT && GENERIC_HARDIRQS
|
||||||
select I2C_ALGOBIT
|
select I2C_ALGOBIT
|
||||||
select I2C_SMBUS
|
select I2C_SMBUS
|
||||||
help
|
help
|
||||||
|
@ -802,6 +803,7 @@ config I2C_PARPORT
|
||||||
|
|
||||||
config I2C_PARPORT_LIGHT
|
config I2C_PARPORT_LIGHT
|
||||||
tristate "Parallel port adapter (light)"
|
tristate "Parallel port adapter (light)"
|
||||||
|
depends on GENERIC_HARDIRQS
|
||||||
select I2C_ALGOBIT
|
select I2C_ALGOBIT
|
||||||
select I2C_SMBUS
|
select I2C_SMBUS
|
||||||
help
|
help
|
||||||
|
|
|
@ -135,6 +135,11 @@ static const struct block_device_operations scm_blk_devops = {
|
||||||
.release = scm_release,
|
.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)
|
static void scm_request_prepare(struct scm_request *scmrq)
|
||||||
{
|
{
|
||||||
struct scm_blk_dev *bdev = scmrq->bdev;
|
struct scm_blk_dev *bdev = scmrq->bdev;
|
||||||
|
@ -195,14 +200,18 @@ void scm_request_requeue(struct scm_request *scmrq)
|
||||||
|
|
||||||
scm_release_cluster(scmrq);
|
scm_release_cluster(scmrq);
|
||||||
blk_requeue_request(bdev->rq, scmrq->request);
|
blk_requeue_request(bdev->rq, scmrq->request);
|
||||||
|
atomic_dec(&bdev->queued_reqs);
|
||||||
scm_request_done(scmrq);
|
scm_request_done(scmrq);
|
||||||
scm_ensure_queue_restart(bdev);
|
scm_ensure_queue_restart(bdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void scm_request_finish(struct scm_request *scmrq)
|
void scm_request_finish(struct scm_request *scmrq)
|
||||||
{
|
{
|
||||||
|
struct scm_blk_dev *bdev = scmrq->bdev;
|
||||||
|
|
||||||
scm_release_cluster(scmrq);
|
scm_release_cluster(scmrq);
|
||||||
blk_end_request_all(scmrq->request, scmrq->error);
|
blk_end_request_all(scmrq->request, scmrq->error);
|
||||||
|
atomic_dec(&bdev->queued_reqs);
|
||||||
scm_request_done(scmrq);
|
scm_request_done(scmrq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,6 +227,10 @@ static void scm_blk_request(struct request_queue *rq)
|
||||||
if (req->cmd_type != REQ_TYPE_FS)
|
if (req->cmd_type != REQ_TYPE_FS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!scm_permit_request(bdev, req)) {
|
||||||
|
scm_ensure_queue_restart(bdev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
scmrq = scm_request_fetch();
|
scmrq = scm_request_fetch();
|
||||||
if (!scmrq) {
|
if (!scmrq) {
|
||||||
SCM_LOG(5, "no request");
|
SCM_LOG(5, "no request");
|
||||||
|
@ -231,11 +244,13 @@ static void scm_blk_request(struct request_queue *rq)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (scm_need_cluster_request(scmrq)) {
|
if (scm_need_cluster_request(scmrq)) {
|
||||||
|
atomic_inc(&bdev->queued_reqs);
|
||||||
blk_start_request(req);
|
blk_start_request(req);
|
||||||
scm_initiate_cluster_request(scmrq);
|
scm_initiate_cluster_request(scmrq);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scm_request_prepare(scmrq);
|
scm_request_prepare(scmrq);
|
||||||
|
atomic_inc(&bdev->queued_reqs);
|
||||||
blk_start_request(req);
|
blk_start_request(req);
|
||||||
|
|
||||||
ret = scm_start_aob(scmrq->aob);
|
ret = scm_start_aob(scmrq->aob);
|
||||||
|
@ -244,7 +259,6 @@ static void scm_blk_request(struct request_queue *rq)
|
||||||
scm_request_requeue(scmrq);
|
scm_request_requeue(scmrq);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
atomic_inc(&bdev->queued_reqs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,6 +294,38 @@ void scm_blk_irq(struct scm_device *scmdev, void *data, int error)
|
||||||
tasklet_hi_schedule(&bdev->tasklet);
|
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)
|
static void scm_blk_tasklet(struct scm_blk_dev *bdev)
|
||||||
{
|
{
|
||||||
struct scm_request *scmrq;
|
struct scm_request *scmrq;
|
||||||
|
@ -293,11 +339,8 @@ static void scm_blk_tasklet(struct scm_blk_dev *bdev)
|
||||||
spin_unlock_irqrestore(&bdev->lock, flags);
|
spin_unlock_irqrestore(&bdev->lock, flags);
|
||||||
|
|
||||||
if (scmrq->error && scmrq->retries-- > 0) {
|
if (scmrq->error && scmrq->retries-- > 0) {
|
||||||
if (scm_start_aob(scmrq->aob)) {
|
scm_blk_handle_error(scmrq);
|
||||||
spin_lock_irqsave(&bdev->rq_lock, flags);
|
|
||||||
scm_request_requeue(scmrq);
|
|
||||||
spin_unlock_irqrestore(&bdev->rq_lock, flags);
|
|
||||||
}
|
|
||||||
/* Request restarted or requeued, handle next. */
|
/* Request restarted or requeued, handle next. */
|
||||||
spin_lock_irqsave(&bdev->lock, flags);
|
spin_lock_irqsave(&bdev->lock, flags);
|
||||||
continue;
|
continue;
|
||||||
|
@ -310,7 +353,6 @@ static void scm_blk_tasklet(struct scm_blk_dev *bdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
scm_request_finish(scmrq);
|
scm_request_finish(scmrq);
|
||||||
atomic_dec(&bdev->queued_reqs);
|
|
||||||
spin_lock_irqsave(&bdev->lock, flags);
|
spin_lock_irqsave(&bdev->lock, flags);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&bdev->lock, flags);
|
spin_unlock_irqrestore(&bdev->lock, flags);
|
||||||
|
@ -332,6 +374,7 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
bdev->scmdev = scmdev;
|
bdev->scmdev = scmdev;
|
||||||
|
bdev->state = SCM_OPER;
|
||||||
spin_lock_init(&bdev->rq_lock);
|
spin_lock_init(&bdev->rq_lock);
|
||||||
spin_lock_init(&bdev->lock);
|
spin_lock_init(&bdev->lock);
|
||||||
INIT_LIST_HEAD(&bdev->finished_requests);
|
INIT_LIST_HEAD(&bdev->finished_requests);
|
||||||
|
@ -396,6 +439,18 @@ void scm_blk_dev_cleanup(struct scm_blk_dev *bdev)
|
||||||
put_disk(bdev->gendisk);
|
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)
|
static int __init scm_blk_init(void)
|
||||||
{
|
{
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
|
@ -21,6 +21,7 @@ struct scm_blk_dev {
|
||||||
spinlock_t rq_lock; /* guard the request queue */
|
spinlock_t rq_lock; /* guard the request queue */
|
||||||
spinlock_t lock; /* guard the rest of the blockdev */
|
spinlock_t lock; /* guard the rest of the blockdev */
|
||||||
atomic_t queued_reqs;
|
atomic_t queued_reqs;
|
||||||
|
enum {SCM_OPER, SCM_WR_PROHIBIT} state;
|
||||||
struct list_head finished_requests;
|
struct list_head finished_requests;
|
||||||
#ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE
|
#ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE
|
||||||
struct list_head cluster_list;
|
struct list_head cluster_list;
|
||||||
|
@ -48,6 +49,7 @@ struct scm_request {
|
||||||
|
|
||||||
int scm_blk_dev_setup(struct scm_blk_dev *, struct scm_device *);
|
int scm_blk_dev_setup(struct scm_blk_dev *, struct scm_device *);
|
||||||
void scm_blk_dev_cleanup(struct scm_blk_dev *);
|
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_blk_irq(struct scm_device *, void *, int);
|
||||||
|
|
||||||
void scm_request_finish(struct scm_request *);
|
void scm_request_finish(struct scm_request *);
|
||||||
|
|
|
@ -13,12 +13,23 @@
|
||||||
#include <asm/eadm.h>
|
#include <asm/eadm.h>
|
||||||
#include "scm_blk.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",
|
struct scm_blk_dev *bdev = dev_get_drvdata(&scmdev->dev);
|
||||||
(unsigned long) scmdev->address);
|
|
||||||
SCM_LOG(2, "State changed");
|
switch (event) {
|
||||||
SCM_LOG_STATE(2, scmdev);
|
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)
|
static int scm_probe(struct scm_device *scmdev)
|
||||||
|
@ -64,7 +75,7 @@ static struct scm_driver scm_drv = {
|
||||||
.name = "scm_block",
|
.name = "scm_block",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
},
|
},
|
||||||
.notify = notify,
|
.notify = scm_notify,
|
||||||
.probe = scm_probe,
|
.probe = scm_probe,
|
||||||
.remove = scm_remove,
|
.remove = scm_remove,
|
||||||
.handler = scm_blk_irq,
|
.handler = scm_blk_irq,
|
||||||
|
|
|
@ -627,6 +627,8 @@ static int __init sclp_detect_standby_memory(void)
|
||||||
struct read_storage_sccb *sccb;
|
struct read_storage_sccb *sccb;
|
||||||
int i, id, assigned, rc;
|
int i, id, assigned, rc;
|
||||||
|
|
||||||
|
if (OLDMEM_BASE) /* No standby memory in kdump mode */
|
||||||
|
return 0;
|
||||||
if (!early_read_info_sccb_valid)
|
if (!early_read_info_sccb_valid)
|
||||||
return 0;
|
return 0;
|
||||||
if ((sclp_facilities & 0xe00000000000ULL) != 0xe00000000000ULL)
|
if ((sclp_facilities & 0xe00000000000ULL) != 0xe00000000000ULL)
|
||||||
|
|
|
@ -433,6 +433,20 @@ static void chsc_process_sei_scm_change(struct chsc_sei_nt0_area *sei_area)
|
||||||
" failed (rc=%d).\n", ret);
|
" 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)
|
static void chsc_process_sei_nt2(struct chsc_sei_nt2_area *sei_area)
|
||||||
{
|
{
|
||||||
switch (sei_area->cc) {
|
switch (sei_area->cc) {
|
||||||
|
@ -468,6 +482,9 @@ static void chsc_process_sei_nt0(struct chsc_sei_nt0_area *sei_area)
|
||||||
case 12: /* scm change notification */
|
case 12: /* scm change notification */
|
||||||
chsc_process_sei_scm_change(sei_area);
|
chsc_process_sei_scm_change(sei_area);
|
||||||
break;
|
break;
|
||||||
|
case 14: /* scm available notification */
|
||||||
|
chsc_process_sei_scm_avail(sei_area);
|
||||||
|
break;
|
||||||
default: /* other stuff */
|
default: /* other stuff */
|
||||||
CIO_CRW_EVENT(2, "chsc: sei nt0 unhandled cc=%d\n",
|
CIO_CRW_EVENT(2, "chsc: sei nt0 unhandled cc=%d\n",
|
||||||
sei_area->cc);
|
sei_area->cc);
|
||||||
|
|
|
@ -156,8 +156,10 @@ int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token);
|
||||||
|
|
||||||
#ifdef CONFIG_SCM_BUS
|
#ifdef CONFIG_SCM_BUS
|
||||||
int scm_update_information(void);
|
int scm_update_information(void);
|
||||||
|
int scm_process_availability_information(void);
|
||||||
#else /* CONFIG_SCM_BUS */
|
#else /* CONFIG_SCM_BUS */
|
||||||
static inline int scm_update_information(void) { return 0; }
|
static inline int scm_update_information(void) { return 0; }
|
||||||
|
static inline int scm_process_availability_information(void) { return 0; }
|
||||||
#endif /* CONFIG_SCM_BUS */
|
#endif /* CONFIG_SCM_BUS */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -211,7 +211,7 @@ static void scmdev_update(struct scm_device *scmdev, struct sale *sale)
|
||||||
goto out;
|
goto out;
|
||||||
scmdrv = to_scm_drv(scmdev->dev.driver);
|
scmdrv = to_scm_drv(scmdev->dev.driver);
|
||||||
if (changed && scmdrv->notify)
|
if (changed && scmdrv->notify)
|
||||||
scmdrv->notify(scmdev);
|
scmdrv->notify(scmdev, SCM_CHANGE);
|
||||||
out:
|
out:
|
||||||
device_unlock(&scmdev->dev);
|
device_unlock(&scmdev->dev);
|
||||||
if (changed)
|
if (changed)
|
||||||
|
@ -297,6 +297,22 @@ int scm_update_information(void)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int scm_dev_avail(struct device *dev, void *unused)
|
||||||
|
{
|
||||||
|
struct scm_driver *scmdrv = to_scm_drv(dev->driver);
|
||||||
|
struct scm_device *scmdev = to_scm_dev(dev);
|
||||||
|
|
||||||
|
if (dev->driver && scmdrv->notify)
|
||||||
|
scmdrv->notify(scmdev, SCM_AVAIL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int scm_process_availability_information(void)
|
||||||
|
{
|
||||||
|
return bus_for_each_dev(&scm_bus_type, NULL, NULL, scm_dev_avail);
|
||||||
|
}
|
||||||
|
|
||||||
static int __init scm_init(void)
|
static int __init scm_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
Loading…
Reference in New Issue