18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Functions for registration of I/O interruption subclasses on s390.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2008
68c2ecf20Sopenharmony_ci * Authors: Sebastian Ott <sebott@linux.vnet.ibm.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <asm/isc.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic unsigned int isc_refs[MAX_ISC + 1];
148c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(isc_ref_lock);
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/**
188c2ecf20Sopenharmony_ci * isc_register - register an I/O interruption subclass.
198c2ecf20Sopenharmony_ci * @isc: I/O interruption subclass to register
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * The number of users for @isc is increased. If this is the first user to
228c2ecf20Sopenharmony_ci * register @isc, the corresponding I/O interruption subclass mask is enabled.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * Context:
258c2ecf20Sopenharmony_ci *   This function must not be called in interrupt context.
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_civoid isc_register(unsigned int isc)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	if (isc > MAX_ISC) {
308c2ecf20Sopenharmony_ci		WARN_ON(1);
318c2ecf20Sopenharmony_ci		return;
328c2ecf20Sopenharmony_ci	}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	spin_lock(&isc_ref_lock);
358c2ecf20Sopenharmony_ci	if (isc_refs[isc] == 0)
368c2ecf20Sopenharmony_ci		ctl_set_bit(6, 31 - isc);
378c2ecf20Sopenharmony_ci	isc_refs[isc]++;
388c2ecf20Sopenharmony_ci	spin_unlock(&isc_ref_lock);
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(isc_register);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/**
438c2ecf20Sopenharmony_ci * isc_unregister - unregister an I/O interruption subclass.
448c2ecf20Sopenharmony_ci * @isc: I/O interruption subclass to unregister
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci * The number of users for @isc is decreased. If this is the last user to
478c2ecf20Sopenharmony_ci * unregister @isc, the corresponding I/O interruption subclass mask is
488c2ecf20Sopenharmony_ci * disabled.
498c2ecf20Sopenharmony_ci * Note: This function must not be called if isc_register() hasn't been called
508c2ecf20Sopenharmony_ci * before by the driver for @isc.
518c2ecf20Sopenharmony_ci *
528c2ecf20Sopenharmony_ci * Context:
538c2ecf20Sopenharmony_ci *   This function must not be called in interrupt context.
548c2ecf20Sopenharmony_ci */
558c2ecf20Sopenharmony_civoid isc_unregister(unsigned int isc)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	spin_lock(&isc_ref_lock);
588c2ecf20Sopenharmony_ci	/* check for misuse */
598c2ecf20Sopenharmony_ci	if (isc > MAX_ISC || isc_refs[isc] == 0) {
608c2ecf20Sopenharmony_ci		WARN_ON(1);
618c2ecf20Sopenharmony_ci		goto out_unlock;
628c2ecf20Sopenharmony_ci	}
638c2ecf20Sopenharmony_ci	if (isc_refs[isc] == 1)
648c2ecf20Sopenharmony_ci		ctl_clear_bit(6, 31 - isc);
658c2ecf20Sopenharmony_ci	isc_refs[isc]--;
668c2ecf20Sopenharmony_ciout_unlock:
678c2ecf20Sopenharmony_ci	spin_unlock(&isc_ref_lock);
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(isc_unregister);
70