d4b480a18b0ffde8d0d47f04dfe3a9400ec4b7d1
[pandora-kernel.git] / arch / s390 / pci / pci_msi.c
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 */
20 static struct hlist_head *msi_hash;
21 static 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
25 static DEFINE_SPINLOCK(msi_map_lock);
26
27 struct 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
38 int 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
64 int 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 = zdev->msi_map + (nr & ZPCI_MSI_VEC_MASK);
72         map->irq = nr;
73         map->msi = msi;
74         INIT_HLIST_NODE(&map->msi_chain);
75
76         pr_debug("%s hashing irq: %u  to bucket nr: %llu\n",
77                 __func__, nr, msi_hashfn(nr));
78         hlist_add_head_rcu(&map->msi_chain, &msi_hash[msi_hashfn(nr)]);
79
80         spin_lock(&msi_map_lock);
81         rc = irq_set_msi_desc(nr, msi);
82         if (rc) {
83                 spin_unlock(&msi_map_lock);
84                 hlist_del_rcu(&map->msi_chain);
85                 return rc;
86         }
87         spin_unlock(&msi_map_lock);
88
89         msg.data = nr - offset;
90         msg.address_lo = zdev->msi_addr & 0xffffffff;
91         msg.address_hi = zdev->msi_addr >> 32;
92         write_msi_msg(nr, &msg);
93         return 0;
94 }
95
96 void zpci_teardown_msi_irq(struct zpci_dev *zdev, struct msi_desc *msi)
97 {
98         int nr = msi->irq & ZPCI_MSI_VEC_MASK;
99         struct msi_map *map;
100
101         zpci_msi_set_mask_bits(msi, 1, 1);
102         msi->msg.address_lo = 0;
103         msi->msg.address_hi = 0;
104         msi->msg.data = 0;
105         msi->irq = 0;
106
107         spin_lock(&msi_map_lock);
108         map = zdev->msi_map + nr;
109         hlist_del_rcu(&map->msi_chain);
110         spin_unlock(&msi_map_lock);
111 }
112
113 /*
114  * The msi hash table has 256 entries which is good for 4..20
115  * devices (a typical device allocates 10 + CPUs MSI's). Maybe make
116  * the hash table size adjustable later.
117  */
118 int __init zpci_msihash_init(void)
119 {
120         unsigned int i;
121
122         msi_hash = kmalloc(MSI_HASH_BUCKETS * sizeof(*msi_hash), GFP_KERNEL);
123         if (!msi_hash)
124                 return -ENOMEM;
125
126         for (i = 0; i < MSI_HASH_BUCKETS; i++)
127                 INIT_HLIST_HEAD(&msi_hash[i]);
128         return 0;
129 }
130
131 void __init zpci_msihash_exit(void)
132 {
133         kfree(msi_hash);
134 }