#include "entry.h"
#include "cpumap.h"
#include "kstack.h"
+#include "pci_impl.h"
struct ino_bucket *ivector_table;
unsigned long ivector_table_pa;
}
static int sun4v_virt_set_affinity(struct irq_data *data,
- const struct cpumask *mask, bool force)
+ const struct cpumask *mask, bool force)
{
+ int msi;
+ unsigned int msiqid;
+ struct irq_desc *mdesc;
+ struct pci_pbm_info *pbm;
unsigned long dev_handle = irq_data_to_handle(data);
unsigned long dev_ino = irq_data_to_ino(data);
unsigned long cpuid;
"err(%d)\n",
dev_handle, dev_ino, cpuid, err);
+ pbm = (struct pci_pbm_info *)data->msi_desc;
+ if (!pbm)
+ return 0;
+
+ /* get the msiqid */
+ for (msiqid = 0; msiqid < pbm->msiq_num; msiqid++)
+ if (pbm->msiqid_irq_table[msiqid] == data->irq)
+ break;
+
+ if (msiqid >= pbm->msiq_num) {
+ pr_err("sun4v_virt_set_affinity can't set related affinities\n");
+ return 0;
+ }
+
+ /* set affinities of "related" msiq_irq's */
+ for (msi = 0; msi < pbm->msi_num; msi++)
+ if (pbm->msi_msiqid_table[msi] == msiqid) {
+ mdesc = irq_to_desc(pbm->msi_irq_table[msi]);
+ cpumask_copy(mdesc->irq_data.affinity, mask);
+ }
+
return 0;
}
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/irq.h>
+#include <linux/seq_file.h>
#include "pci_impl.h"
clear_bit(msi_num, pbm->msi_bitmap);
}
+static void set_related_affinity(struct pci_pbm_info *pbm, unsigned int msiqid,
+ unsigned int oirq, const struct cpumask *mask)
+{
+ unsigned int msi;
+
+ for (msi = 0; msi < pbm->msi_num; msi++)
+ if (pbm->msi_msiqid_table[msi] == msiqid) {
+ unsigned int irq;
+ struct irq_desc *desc;
+
+ irq = pbm->msi_irq_table[msi - pbm->msiq_first];
+ if (irq == oirq)
+ continue;
+
+ desc = irq_to_desc(irq);
+ cpumask_copy(desc->irq_data.affinity, mask);
+ }
+}
+
+static int irq_set_msi_affinity(struct irq_data *data,
+ const struct cpumask *dest, bool force)
+{
+ int ret;
+ unsigned int msiqid;
+ unsigned int msiq_irq;
+ struct irq_data *mdata;
+ struct irq_desc *mdesc;
+ struct irq_chip *mchip;
+
+ struct msi_desc *msi_desc = data->msi_desc;
+ struct pci_dev *pdev = msi_desc->dev;
+ struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
+
+ msiqid = pbm->msi_msiqid_table[msi_desc->msg.data - pbm->msiq_first];
+ msiq_irq = pbm->msiqid_irq_table[msiqid];
+
+ mdesc = irq_to_desc(msiq_irq);
+ mdata = irq_desc_get_irq_data(mdesc);
+ mchip = irq_desc_get_chip(mdesc);
+
+ ret = mchip->irq_set_affinity(mdata, dest, force);
+ if (ret != IRQ_SET_MASK_OK)
+ return ret;
+
+ cpumask_copy(mdata->affinity, dest);
+
+ set_related_affinity(pbm, msiqid, data->irq, dest);
+
+ return IRQ_SET_MASK_OK;
+}
+
+static void irq_print_msi_chip(struct irq_data *data, struct seq_file *p)
+{
+ unsigned int msiqid;
+ unsigned int msiq_irq;
+
+ struct msi_desc *msi_desc = data->msi_desc;
+ struct pci_dev *pdev = msi_desc->dev;
+ struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
+
+ msiqid = pbm->msi_msiqid_table[msi_desc->msg.data - pbm->msiq_first];
+ msiq_irq = pbm->msiqid_irq_table[msiqid];
+
+ seq_printf(p, "MSIQ:%d", msiq_irq);
+}
+
static struct irq_chip msi_irq = {
.name = "PCI-MSI",
.irq_mask = pci_msi_mask_irq,
.irq_unmask = pci_msi_unmask_irq,
.irq_enable = pci_msi_unmask_irq,
.irq_disable = pci_msi_mask_irq,
- /* XXX affinity XXX */
+ .irq_set_affinity = irq_set_msi_affinity,
+ .irq_print_chip = irq_print_msi_chip,
};
static int sparc64_setup_msi_irq(unsigned int *irq_p,
}
msg.data = msi;
+ pbm->msi_msiqid_table[msi - pbm->msi_first] = msiqid;
+
irq_set_msi_desc(*irq_p, entry);
pci_write_msi_msg(*irq_p, &msg);
size = pbm->msi_num * sizeof(unsigned int);
pbm->msi_irq_table = kzalloc(size, GFP_KERNEL);
- if (!pbm->msi_irq_table) {
- kfree(pbm->msiq_irq_cookies);
- pbm->msiq_irq_cookies = NULL;
- return -ENOMEM;
- }
+ if (!pbm->msi_irq_table)
+ goto no_irq_cookies;
+
+ pbm->msi_msiqid_table = kzalloc(size, GFP_KERNEL);
+ if (!pbm->msi_msiqid_table)
+ goto no_irq_table;
return 0;
+
+no_irq_table:
+ kfree(pbm->msi_irq_table);
+ pbm->msi_irq_table = NULL;
+
+no_irq_cookies:
+ kfree(pbm->msiq_irq_cookies);
+ pbm->msiq_irq_cookies = NULL;
+ return -ENOMEM;
}
static void msi_table_free(struct pci_pbm_info *pbm)
kfree(pbm->msi_irq_table);
pbm->msi_irq_table = NULL;
+
+ kfree(pbm->msi_msiqid_table);
+ pbm->msi_msiqid_table = NULL;
}
static int bringup_one_msi_queue(struct pci_pbm_info *pbm,
{
int irq = ops->msiq_build_irq(pbm, msiqid, devino);
int err, nid;
+ struct irq_data *mdata;
+ struct irq_desc *mdesc;
if (irq < 0)
return irq;
if (err)
return err;
+ mdesc = irq_to_desc(irq);
+ mdata = irq_desc_get_irq_data(mdesc);
+
+ /*
+ * Since these are not MSI interrupts, the msi_desc field is
+ * unused. Steal it. This is needed to reverse lookup associated
+ * MSI-x vectors.
+ */
+ mdata->msi_desc = (struct msi_desc *)pbm;
+
+ pbm->msiqid_irq_table[msiqid] = irq;
return 0;
}
const struct sparc64_msiq_ops *ops)
{
int i;
+ int size;
+
+ size = pbm->msiq_num * sizeof(unsigned int);
+ pbm->msiqid_irq_table = kzalloc(size, GFP_KERNEL);
+ if (!pbm->msiqid_irq_table)
+ return -ENOMEM;
for (i = 0; i < pbm->msiq_num; i++) {
unsigned long msiqid = i + pbm->msiq_first;