xref: /kernel/linux/linux-6.6/drivers/s390/cio/isc.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Functions for registration of I/O interruption subclasses on s390.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright IBM Corp. 2008
662306a36Sopenharmony_ci * Authors: Sebastian Ott <sebott@linux.vnet.ibm.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/spinlock.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <asm/isc.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic unsigned int isc_refs[MAX_ISC + 1];
1462306a36Sopenharmony_cistatic DEFINE_SPINLOCK(isc_ref_lock);
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/**
1862306a36Sopenharmony_ci * isc_register - register an I/O interruption subclass.
1962306a36Sopenharmony_ci * @isc: I/O interruption subclass to register
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * The number of users for @isc is increased. If this is the first user to
2262306a36Sopenharmony_ci * register @isc, the corresponding I/O interruption subclass mask is enabled.
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * Context:
2562306a36Sopenharmony_ci *   This function must not be called in interrupt context.
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_civoid isc_register(unsigned int isc)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	if (isc > MAX_ISC) {
3062306a36Sopenharmony_ci		WARN_ON(1);
3162306a36Sopenharmony_ci		return;
3262306a36Sopenharmony_ci	}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	spin_lock(&isc_ref_lock);
3562306a36Sopenharmony_ci	if (isc_refs[isc] == 0)
3662306a36Sopenharmony_ci		ctl_set_bit(6, 31 - isc);
3762306a36Sopenharmony_ci	isc_refs[isc]++;
3862306a36Sopenharmony_ci	spin_unlock(&isc_ref_lock);
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(isc_register);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/**
4362306a36Sopenharmony_ci * isc_unregister - unregister an I/O interruption subclass.
4462306a36Sopenharmony_ci * @isc: I/O interruption subclass to unregister
4562306a36Sopenharmony_ci *
4662306a36Sopenharmony_ci * The number of users for @isc is decreased. If this is the last user to
4762306a36Sopenharmony_ci * unregister @isc, the corresponding I/O interruption subclass mask is
4862306a36Sopenharmony_ci * disabled.
4962306a36Sopenharmony_ci * Note: This function must not be called if isc_register() hasn't been called
5062306a36Sopenharmony_ci * before by the driver for @isc.
5162306a36Sopenharmony_ci *
5262306a36Sopenharmony_ci * Context:
5362306a36Sopenharmony_ci *   This function must not be called in interrupt context.
5462306a36Sopenharmony_ci */
5562306a36Sopenharmony_civoid isc_unregister(unsigned int isc)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	spin_lock(&isc_ref_lock);
5862306a36Sopenharmony_ci	/* check for misuse */
5962306a36Sopenharmony_ci	if (isc > MAX_ISC || isc_refs[isc] == 0) {
6062306a36Sopenharmony_ci		WARN_ON(1);
6162306a36Sopenharmony_ci		goto out_unlock;
6262306a36Sopenharmony_ci	}
6362306a36Sopenharmony_ci	if (isc_refs[isc] == 1)
6462306a36Sopenharmony_ci		ctl_clear_bit(6, 31 - isc);
6562306a36Sopenharmony_ci	isc_refs[isc]--;
6662306a36Sopenharmony_ciout_unlock:
6762306a36Sopenharmony_ci	spin_unlock(&isc_ref_lock);
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(isc_unregister);
70