linux/arch/s390/pci/pci_msi.c
<<
>>
Prefs
   1/*
   2 * Copyright IBM Corp. 2012
   3 *
   4 * Author(s):
   5 *   Jan Glauber <jang@linux.vnet.ibm.com>
   6 */
   7
   8#define COMPONENT "zPCI"
   9#define pr_fmt(fmt) COMPONENT ": " fmt
  10
  11#include <linux/kernel.h>
  12#include <linux/err.h>
  13#include <linux/rculist.h>
  14#include <linux/hash.h>
  15#include <linux/pci.h>
  16#include <linux/msi.h>
  17#include <asm/hw_irq.h>
  18
  19/* mapping of irq numbers to msi_desc */
  20static struct hlist_head *msi_hash;
  21static const unsigned int msi_hash_bits = 8;
  22#define MSI_HASH_BUCKETS (1U << msi_hash_bits)
  23#define msi_hashfn(nr)  hash_long(nr, msi_hash_bits)
  24
  25static DEFINE_SPINLOCK(msi_map_lock);
  26
  27struct msi_desc *__irq_get_msi_desc(unsigned int irq)
  28{
  29        struct msi_map *map;
  30
  31        hlist_for_each_entry_rcu(map,
  32                        &msi_hash[msi_hashfn(irq)], msi_chain)
  33                if (map->irq == irq)
  34                        return map->msi;
  35        return NULL;
  36}
  37
  38int zpci_msi_set_mask_bits(struct msi_desc *msi, u32 mask, u32 flag)
  39{
  40        if (msi->msi_attrib.is_msix) {
  41                int offset = msi->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
  42                        PCI_MSIX_ENTRY_VECTOR_CTRL;
  43                msi->masked = readl(msi->mask_base + offset);
  44                writel(flag, msi->mask_base + offset);
  45        } else {
  46                if (msi->msi_attrib.maskbit) {
  47                        int pos;
  48                        u32 mask_bits;
  49
  50                        pos = (long) msi->mask_base;
  51                        pci_read_config_dword(msi->dev, pos, &mask_bits);
  52                        mask_bits &= ~(mask);
  53                        mask_bits |= flag & mask;
  54                        pci_write_config_dword(msi->dev, pos, mask_bits);
  55                } else {
  56                        return 0;
  57                }
  58        }
  59
  60        msi->msi_attrib.maskbit = !!flag;
  61        return 1;
  62}
  63
  64int zpci_setup_msi_irq(struct zpci_dev *zdev, struct msi_desc *msi,
  65                        unsigned int nr, int offset)
  66{
  67        struct msi_map *map;
  68        struct msi_msg msg;
  69        int rc;
  70
  71        map = kmalloc(sizeof(*map), GFP_KERNEL);
  72        if (map == NULL)
  73                return -ENOMEM;
  74
  75        map->irq = nr;
  76        map->msi = msi;
  77        zdev->msi_map[nr & ZPCI_MSI_MASK] = map;
  78        INIT_HLIST_NODE(&map->msi_chain);
  79
  80        pr_debug("%s hashing irq: %u  to bucket nr: %llu\n",
  81                __func__, nr, msi_hashfn(nr));
  82        hlist_add_head_rcu(&map->msi_chain, &msi_hash[msi_hashfn(nr)]);
  83
  84        spin_lock(&msi_map_lock);
  85        rc = irq_set_msi_desc(nr, msi);
  86        if (rc) {
  87                spin_unlock(&msi_map_lock);
  88                hlist_del_rcu(&map->msi_chain);
  89                kfree(map);
  90                zdev->msi_map[nr & ZPCI_MSI_MASK] = NULL;
  91                return rc;
  92        }
  93        spin_unlock(&msi_map_lock);
  94
  95        msg.data = nr - offset;
  96        msg.address_lo = zdev->msi_addr & 0xffffffff;
  97        msg.address_hi = zdev->msi_addr >> 32;
  98        write_msi_msg(nr, &msg);
  99        return 0;
 100}
 101
 102void zpci_teardown_msi_irq(struct zpci_dev *zdev, struct msi_desc *msi)
 103{
 104        int irq = msi->irq & ZPCI_MSI_MASK;
 105        struct msi_map *map;
 106
 107        msi->msg.address_lo = 0;
 108        msi->msg.address_hi = 0;
 109        msi->msg.data = 0;
 110        msi->irq = 0;
 111        zpci_msi_set_mask_bits(msi, 1, 1);
 112
 113        spin_lock(&msi_map_lock);
 114        map = zdev->msi_map[irq];
 115        hlist_del_rcu(&map->msi_chain);
 116        kfree(map);
 117        zdev->msi_map[irq] = NULL;
 118        spin_unlock(&msi_map_lock);
 119}
 120
 121/*
 122 * The msi hash table has 256 entries which is good for 4..20
 123 * devices (a typical device allocates 10 + CPUs MSI's). Maybe make
 124 * the hash table size adjustable later.
 125 */
 126int __init zpci_msihash_init(void)
 127{
 128        unsigned int i;
 129
 130        msi_hash = kmalloc(MSI_HASH_BUCKETS * sizeof(*msi_hash), GFP_KERNEL);
 131        if (!msi_hash)
 132                return -ENOMEM;
 133
 134        for (i = 0; i < MSI_HASH_BUCKETS; i++)
 135                INIT_HLIST_HEAD(&msi_hash[i]);
 136        return 0;
 137}
 138
 139void __init zpci_msihash_exit(void)
 140{
 141        kfree(msi_hash);
 142}
 143