8d5e98f8d6
Add local and system prefix to some functions to clarify they change control register contents on either the local CPU or the on all CPUs. This results in the following API: Two defines which load and save multiple control registers. The defines correlate with the following C prototypes: void __local_ctl_load(unsigned long *, unsigned int cr_low, unsigned int cr_high); void __local_ctl_store(unsigned long *, unsigned int cr_low, unsigned int cr_high); Two functions which locally set or clear one bit for a specified control register: void local_ctl_set_bit(unsigned int cr, unsigned int bit); void local_ctl_clear_bit(unsigned int cr, unsigned int bit); Two functions which set or clear one bit for a specified control register on all CPUs: void system_ctl_set_bit(unsigned int cr, unsigned int bit); void system_ctl_clear_bit(unsigend int cr, unsigned int bit); Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
70 lines
1.7 KiB
C
70 lines
1.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Functions for registration of I/O interruption subclasses on s390.
|
|
*
|
|
* Copyright IBM Corp. 2008
|
|
* Authors: Sebastian Ott <sebott@linux.vnet.ibm.com>
|
|
*/
|
|
|
|
#include <linux/spinlock.h>
|
|
#include <linux/module.h>
|
|
#include <asm/isc.h>
|
|
|
|
static unsigned int isc_refs[MAX_ISC + 1];
|
|
static DEFINE_SPINLOCK(isc_ref_lock);
|
|
|
|
|
|
/**
|
|
* isc_register - register an I/O interruption subclass.
|
|
* @isc: I/O interruption subclass to register
|
|
*
|
|
* The number of users for @isc is increased. If this is the first user to
|
|
* register @isc, the corresponding I/O interruption subclass mask is enabled.
|
|
*
|
|
* Context:
|
|
* This function must not be called in interrupt context.
|
|
*/
|
|
void isc_register(unsigned int isc)
|
|
{
|
|
if (isc > MAX_ISC) {
|
|
WARN_ON(1);
|
|
return;
|
|
}
|
|
|
|
spin_lock(&isc_ref_lock);
|
|
if (isc_refs[isc] == 0)
|
|
system_ctl_set_bit(6, 31 - isc);
|
|
isc_refs[isc]++;
|
|
spin_unlock(&isc_ref_lock);
|
|
}
|
|
EXPORT_SYMBOL_GPL(isc_register);
|
|
|
|
/**
|
|
* isc_unregister - unregister an I/O interruption subclass.
|
|
* @isc: I/O interruption subclass to unregister
|
|
*
|
|
* The number of users for @isc is decreased. If this is the last user to
|
|
* unregister @isc, the corresponding I/O interruption subclass mask is
|
|
* disabled.
|
|
* Note: This function must not be called if isc_register() hasn't been called
|
|
* before by the driver for @isc.
|
|
*
|
|
* Context:
|
|
* This function must not be called in interrupt context.
|
|
*/
|
|
void isc_unregister(unsigned int isc)
|
|
{
|
|
spin_lock(&isc_ref_lock);
|
|
/* check for misuse */
|
|
if (isc > MAX_ISC || isc_refs[isc] == 0) {
|
|
WARN_ON(1);
|
|
goto out_unlock;
|
|
}
|
|
if (isc_refs[isc] == 1)
|
|
system_ctl_clear_bit(6, 31 - isc);
|
|
isc_refs[isc]--;
|
|
out_unlock:
|
|
spin_unlock(&isc_ref_lock);
|
|
}
|
|
EXPORT_SYMBOL_GPL(isc_unregister);
|