<commit_before>/**
 * tpci200.c
 *
 * driver for the TEWS TPCI-200 device
 * Copyright (c) 2009 <NAME>, EIC2 SA
 * Copyright (c) 2010,2011 <NAME> <<EMAIL>>, CERN
 * Copyright (c) 2012 <NAME> <<EMAIL>>, Igalia
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; version 2 of the License.
 */

#include <linux/module.h>
#include "tpci200.h"

static u16 tpci200_status_timeout[] = {
	TPCI200_A_TIMEOUT,
	TPCI200_B_TIMEOUT,
	TPCI200_C_TIMEOUT,
	TPCI200_D_TIMEOUT,
};

static u16 tpci200_status_error[] = {
	TPCI200_A_ERROR,
	TPCI200_B_ERROR,
	TPCI200_C_ERROR,
	TPCI200_D_ERROR,
};

static struct tpci200_board *check_slot(struct ipack_device *dev)
{
	struct tpci200_board *tpci200;

	if (dev == NULL)
		return NULL;


	tpci200 = dev_get_drvdata(dev->bus->parent);

	if (tpci200 == NULL) {
		dev_info(&dev->dev, "carrier board not found\n");
		return NULL;
	}

	if (dev->slot >= TPCI200_NB_SLOT) {
		dev_info(&dev->dev,
			 "Slot [%d:%d] doesn't exist! Last tpci200 slot is %d.\n",
			 dev->bus_nr, dev->slot, TPCI200_NB_SLOT-1);
		return NULL;
	}

	return tpci200;
}

static void __tpci200_clear_mask(__le16 __iomem *addr, u16 mask)
{
	iowrite16(ioread16(addr) & (~mask), addr);
}

static void tpci200_clear_mask(struct tpci200_board *tpci200,
			       __le16 __iomem *addr, u16 mask)
{
	mutex_lock(&tpci200->mutex);
	__tpci200_clear_mask(addr, mask);
	mutex_unlock(&tpci200->mutex);
}

static void __tpci200_set_mask(__le16 __iomem *addr, u16 mask)
{
	iowrite16(ioread16(addr) | mask, addr);
}

static void tpci200_set_mask(struct tpci200_board *tpci200,
			     __le16 __iomem *addr, u16 mask)
{
	mutex_lock(&tpci200->mutex);
	__tpci200_set_mask(addr, mask);
	mutex_unlock(&tpci200->mutex);
}

static void tpci200_unregister(struct tpci200_board *tpci200)
{
	int i;

	free_irq(tpci200->info->pdev->irq, (void *) tpci200);

	pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs);
	pci_iounmap(tpci200->info->pdev, tpci200->info->ioidint_space);
	pci_iounmap(tpci200->info->pdev, tpci200->info->mem8_space);
	pci_iounmap(tpci200->info->pdev, tpci200->info->cfg_regs);

	pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
	pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
	pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR);
	pci_release_region(tpci200->info->pdev, TPCI200_CFG_MEM_BAR);

	pci_disable_device(tpci200->info->pdev);
	pci_dev_put(tpci200->info->pdev);

	for (i = 0; i < TPCI200_NB_SLOT; i++) {
		tpci200->slots[i].io_phys.address = NULL;
		tpci200->slots[i].io_phys.size = 0;
		tpci200->slots[i].id_phys.address = NULL;
		tpci200->slots[i].id_phys.size = 0;
		tpci200->slots[i].mem_phys.address = NULL;
		tpci200->slots[i].mem_phys.size = 0;
	}
}

static irqreturn_t tpci200_interrupt(int irq, void *dev_id)
{
	struct tpci200_board *tpci200 = (struct tpci200_board *) dev_id;
	int i;
	unsigned short status_reg;
	unsigned short unhandled_ints = 0;
	irqreturn_t ret = IRQ_NONE;
	struct slot_irq *slot_irq;

	/* Read status register */
	status_reg = readw(&tpci200->info->interface_regs->status);

	if (status_reg & TPCI200_SLOT_INT_MASK) {
		unhandled_ints = status_reg & TPCI200_SLOT_INT_MASK;
		/* callback to the IRQ handler for the corresponding slot */
		for (i = 0; i < TPCI200_NB_SLOT; i++) {
			slot_irq = tpci200->slots[i].irq;

			if ((slot_irq != NULL) &&
			    (status_reg & ((TPCI200_A_INT0 | TPCI200_A_INT1) << (2*i)))) {

				ret = slot_irq->handler(slot_irq->arg);

				/* Dummy reads */
				readw(slot_irq->holder->io_space.address +
				      0xC0);
				readw(slot_irq->holder->io_space.address +
				      0xC2);

				unhandled_ints &= ~(((TPCI200_A_INT0 | TPCI200_A_INT1) << (2*i)));
			}
		}
	}
	/* Interrupts not handled are disabled */
	if (unhandled_ints) {
		for (i = 0; i < TPCI200_NB_SLOT; i++) {
			slot_irq = tpci200->slots[i].irq;

			if (unhandled_ints & ((TPCI200_INT0_EN | TPCI200_INT1_EN) << (2*i))) {
				dev_info(&slot_irq->holder->dev,
					 "No registered ISR for slot [%d:%d]!. IRQ will be disabled.\n",
					 tpci200->number, i);
				__tpci200_clear_mask(
					&tpci200->info->interface_regs->control[i],
					TPCI200_INT0_EN | TPCI200_INT1_EN);
			}
		}
	}<commit_msg>Staging: ipack/bridges/tpci200: Clean up interrupt handler.<commit_after>/**
 * tpci200.c
 *
 * driver for the TEWS TPCI-200 device
 * Copyright (c) 2009 <NAME>, EIC2 SA
 * Copyright (c) 2010,2011 <NAME> <<EMAIL>>, CERN
 * Copyright (c) 2012 <NAME> <<EMAIL>>, Igalia
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; version 2 of the License.
 */

#include <linux/module.h>
#include "tpci200.h"

static u16 tpci200_status_timeout[] = {
	TPCI200_A_TIMEOUT,
	TPCI200_B_TIMEOUT,
	TPCI200_C_TIMEOUT,
	TPCI200_D_TIMEOUT,
};

static u16 tpci200_status_error[] = {
	TPCI200_A_ERROR,
	TPCI200_B_ERROR,
	TPCI200_C_ERROR,
	TPCI200_D_ERROR,
};

static struct tpci200_board *check_slot(struct ipack_device *dev)
{
	struct tpci200_board *tpci200;

	if (dev == NULL)
		return NULL;


	tpci200 = dev_get_drvdata(dev->bus->parent);

	if (tpci200 == NULL) {
		dev_info(&dev->dev, "carrier board not found\n");
		return NULL;
	}

	if (dev->slot >= TPCI200_NB_SLOT) {
		dev_info(&dev->dev,
			 "Slot [%d:%d] doesn't exist! Last tpci200 slot is %d.\n",
			 dev->bus_nr, dev->slot, TPCI200_NB_SLOT-1);
		return NULL;
	}

	return tpci200;
}

static void __tpci200_clear_mask(__le16 __iomem *addr, u16 mask)
{
	iowrite16(ioread16(addr) & (~mask), addr);
}

static void tpci200_clear_mask(struct tpci200_board *tpci200,
			       __le16 __iomem *addr, u16 mask)
{
	mutex_lock(&tpci200->mutex);
	__tpci200_clear_mask(addr, mask);
	mutex_unlock(&tpci200->mutex);
}

static void __tpci200_set_mask(__le16 __iomem *addr, u16 mask)
{
	iowrite16(ioread16(addr) | mask, addr);
}

static void tpci200_set_mask(struct tpci200_board *tpci200,
			     __le16 __iomem *addr, u16 mask)
{
	mutex_lock(&tpci200->mutex);
	__tpci200_set_mask(addr, mask);
	mutex_unlock(&tpci200->mutex);
}

static void tpci200_unregister(struct tpci200_board *tpci200)
{
	int i;

	free_irq(tpci200->info->pdev->irq, (void *) tpci200);

	pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs);
	pci_iounmap(tpci200->info->pdev, tpci200->info->ioidint_space);
	pci_iounmap(tpci200->info->pdev, tpci200->info->mem8_space);
	pci_iounmap(tpci200->info->pdev, tpci200->info->cfg_regs);

	pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
	pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
	pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR);
	pci_release_region(tpci200->info->pdev, TPCI200_CFG_MEM_BAR);

	pci_disable_device(tpci200->info->pdev);
	pci_dev_put(tpci200->info->pdev);

	for (i = 0; i < TPCI200_NB_SLOT; i++) {
		tpci200->slots[i].io_phys.address = NULL;
		tpci200->slots[i].io_phys.size = 0;
		tpci200->slots[i].id_phys.address = NULL;
		tpci200->slots[i].id_phys.size = 0;
		tpci200->slots[i].mem_phys.address = NULL;
		tpci200->slots[i].mem_phys.size = 0;
	}
}

static irqreturn_t tpci200_slot_irq(struct slot_irq *slot_irq)
{
	irqreturn_t ret = slot_irq->handler(slot_irq->arg);

	/* Dummy reads */
	readw(slot_irq->holder->io_space.address + 0xC0);
	readw(slot_irq->holder->io_space.address + 0xC2);

	return ret;
}

static irqreturn_t tpci200_interrupt(int irq, void *dev_id)
{
	struct tpci200_board *tpci200 = (struct tpci200_board *) dev_id;
	int i;
	unsigned short status_reg;
	irqreturn_t ret = IRQ_NONE;
	struct slot_irq *slot_irq;

	/* Read status register */
	status_reg = readw(&tpci200->info->interface_regs->status);

	if (status_reg & TPCI200_SLOT_INT_MASK) {
		/* callback to the IRQ handler for the corresponding slot */
		for (i = 0; i < TPCI200_NB_SLOT; i++) {
			if (!(status_reg & ((TPCI200_A_INT0 | TPCI200_A_INT1) << (2*i))))
				continue;
			slot_irq = tpci200->slots[i].irq;
			if (slot_irq) {
				ret = tpci200_slot_irq(slot_irq);
			} else {
				dev_info(&tpci200->info->pdev->dev,
					 "No registered ISR for slot [%d:%d]!. IRQ will be disabled.\n",
					 tpci200->number, i);
				__tpci200_clear_mask(
					&tpci200->info->interface_regs->control[i],
					TPCI200_INT0_EN | TPCI200_INT1_EN);
			}
		}
	}
{'fraction_non_alphanumeric': 0.14028390790886316, 'fraction_numerical': 0.07789574138136705, 'mean_word_length': 4.68406779661017, 'pattern_counts': {'":': 0, '<': 32, '<?xml version=': 0, '>': 151, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '917646', 'n_tokens_mistral': 4018, 'n_tokens_neox': 3396, 'n_words': 642}