/* * Copyright IBM Corp. 2012 * * Author(s): * Jan Glauber <jang@linux.vnet.ibm.com> */ #define COMPONENT "zPCI" #define pr_fmt(fmt) COMPONENT ": " fmt #include <linux/kernel.h> #include <linux/err.h> #include <linux/rculist.h> #include <linux/hash.h> #include <linux/pci.h> #include <linux/msi.h> #include <asm/hw_irq.h> /* mapping of irq numbers to msi_desc */ static struct hlist_head *msi_hash; static const unsigned int msi_hash_bits = 8; #define MSI_HASH_BUCKETS (1U << msi_hash_bits) #define msi_hashfn(nr) hash_long(nr, msi_hash_bits) static DEFINE_SPINLOCK(msi_map_lock); struct msi_desc *__irq_get_msi_desc(unsigned int irq) { struct msi_map *map; hlist_for_each_entry_rcu(map, &msi_hash[msi_hashfn(irq)], msi_chain) if (map->irq == irq) return map->msi; return NULL; } int zpci_msi_set_mask_bits(struct msi_desc *msi, u32 mask, u32 flag) { if (msi->msi_attrib.is_msix) { int offset = msi->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; msi->masked = readl(msi->mask_base + offset); writel(flag, msi->mask_base + offset); } else { if (msi->msi_attrib.maskbit) { int pos; u32 mask_bits; pos = (long) msi->mask_base; pci_read_config_dword(msi->dev, pos, &mask_bits); mask_bits &= ~(mask); mask_bits |= flag & mask; pci_write_config_dword(msi->dev, pos, mask_bits); } else { return 0; } } msi->msi_attrib.maskbit = !!flag; return 1; } int zpci_setup_msi_irq(struct zpci_dev *zdev, struct msi_desc *msi, unsigned int nr, int offset) { struct msi_map *map; struct msi_msg msg; int rc; map = kmalloc(sizeof(*map), GFP_KERNEL); if (map == NULL) return -ENOMEM; map->irq = nr; map->msi = msi; zdev->msi_map[nr & ZPCI_MSI_MASK] = map; INIT_HLIST_NODE(&map->msi_chain); pr_debug("%s hashing irq: %u to bucket nr: %llu\n", __func__, nr, msi_hashfn(nr)); hlist_add_head_rcu(&map->msi_chain, &msi_hash[msi_hashfn(nr)]); spin_lock(&msi_map_lock); rc = irq_set_msi_desc(nr, msi); if (rc) { spin_unlock(&msi_map_lock); hlist_del_rcu(&map->msi_chain); kfree(map); zdev->msi_map[nr & ZPCI_MSI_MASK] = NULL; return rc; } spin_unlock(&msi_map_lock); msg.data = nr - offset; msg.address_lo = zdev->msi_addr & 0xffffffff; msg.address_hi = zdev->msi_addr >> 32; write_msi_msg(nr, &msg); return 0; } void zpci_teardown_msi_irq(struct zpci_dev *zdev, struct msi_desc *msi) { int irq = msi->irq & ZPCI_MSI_MASK; struct msi_map *map; msi->msg.address_lo = 0; msi->msg.address_hi = 0; msi->msg.data = 0; msi->irq = 0; zpci_msi_set_mask_bits(msi, 1, 1); spin_lock(&msi_map_lock); map = zdev->msi_map[irq]; hlist_del_rcu(&map->msi_chain); kfree(map); zdev->msi_map[irq] = NULL; spin_unlock(&msi_map_lock); } /* * The msi hash table has 256 entries which is good for 4..20 * devices (a typical device allocates 10 + CPUs MSI's). Maybe make * the hash table size adjustable later. */ int __init zpci_msihash_init(void) { unsigned int i; msi_hash = kmalloc(MSI_HASH_BUCKETS * sizeof(*msi_hash), GFP_KERNEL); if (!msi_hash) return -ENOMEM; for (i = 0; i < MSI_HASH_BUCKETS; i++) INIT_HLIST_HEAD(&msi_hash[i]); return 0; } void __init zpci_msihash_exit(void) { kfree(msi_hash); }