~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/platforms/pasemi/msi.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright 2007, Olof Johansson, PA Semi
  4  *
  5  * Based on arch/powerpc/sysdev/mpic_u3msi.c:
  6  *
  7  * Copyright 2006, Segher Boessenkool, IBM Corporation.
  8  * Copyright 2006-2007, Michael Ellerman, IBM Corporation.
  9  */
 10 
 11 #include <linux/irq.h>
 12 #include <linux/irqdomain.h>
 13 #include <linux/msi.h>
 14 #include <asm/mpic.h>
 15 #include <asm/hw_irq.h>
 16 #include <asm/ppc-pci.h>
 17 #include <asm/msi_bitmap.h>
 18 
 19 #include <sysdev/mpic.h>
 20 
 21 /* Allocate 16 interrupts per device, to give an alignment of 16,
 22  * since that's the size of the grouping w.r.t. affinity. If someone
 23  * needs more than 32 MSI's down the road we'll have to rethink this,
 24  * but it should be OK for now.
 25  */
 26 #define ALLOC_CHUNK 16
 27 
 28 #define PASEMI_MSI_ADDR 0xfc080000
 29 
 30 /* A bit ugly, can we get this from the pci_dev somehow? */
 31 static struct mpic *msi_mpic;
 32 
 33 
 34 static void mpic_pasemi_msi_mask_irq(struct irq_data *data)
 35 {
 36         pr_debug("mpic_pasemi_msi_mask_irq %d\n", data->irq);
 37         pci_msi_mask_irq(data);
 38         mpic_mask_irq(data);
 39 }
 40 
 41 static void mpic_pasemi_msi_unmask_irq(struct irq_data *data)
 42 {
 43         pr_debug("mpic_pasemi_msi_unmask_irq %d\n", data->irq);
 44         mpic_unmask_irq(data);
 45         pci_msi_unmask_irq(data);
 46 }
 47 
 48 static struct irq_chip mpic_pasemi_msi_chip = {
 49         .irq_shutdown           = mpic_pasemi_msi_mask_irq,
 50         .irq_mask               = mpic_pasemi_msi_mask_irq,
 51         .irq_unmask             = mpic_pasemi_msi_unmask_irq,
 52         .irq_eoi                = mpic_end_irq,
 53         .irq_set_type           = mpic_set_irq_type,
 54         .irq_set_affinity       = mpic_set_affinity,
 55         .name                   = "PASEMI-MSI",
 56 };
 57 
 58 static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev)
 59 {
 60         struct msi_desc *entry;
 61         irq_hw_number_t hwirq;
 62 
 63         pr_debug("pasemi_msi_teardown_msi_irqs, pdev %p\n", pdev);
 64 
 65         msi_for_each_desc(entry, &pdev->dev, MSI_DESC_ASSOCIATED) {
 66                 hwirq = virq_to_hw(entry->irq);
 67                 irq_set_msi_desc(entry->irq, NULL);
 68                 irq_dispose_mapping(entry->irq);
 69                 entry->irq = 0;
 70                 msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq, ALLOC_CHUNK);
 71         }
 72 }
 73 
 74 static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
 75 {
 76         unsigned int virq;
 77         struct msi_desc *entry;
 78         struct msi_msg msg;
 79         int hwirq;
 80 
 81         if (type == PCI_CAP_ID_MSIX)
 82                 pr_debug("pasemi_msi: MSI-X untested, trying anyway\n");
 83         pr_debug("pasemi_msi_setup_msi_irqs, pdev %p nvec %d type %d\n",
 84                  pdev, nvec, type);
 85 
 86         msg.address_hi = 0;
 87         msg.address_lo = PASEMI_MSI_ADDR;
 88 
 89         msi_for_each_desc(entry, &pdev->dev, MSI_DESC_NOTASSOCIATED) {
 90                 /* Allocate 16 interrupts for now, since that's the grouping for
 91                  * affinity. This can be changed later if it turns out 32 is too
 92                  * few MSIs for someone, but restrictions will apply to how the
 93                  * sources can be changed independently.
 94                  */
 95                 hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap,
 96                                                 ALLOC_CHUNK);
 97                 if (hwirq < 0) {
 98                         pr_debug("pasemi_msi: failed allocating hwirq\n");
 99                         return hwirq;
100                 }
101 
102                 virq = irq_create_mapping(msi_mpic->irqhost, hwirq);
103                 if (!virq) {
104                         pr_debug("pasemi_msi: failed mapping hwirq 0x%x\n",
105                                   hwirq);
106                         msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq,
107                                                ALLOC_CHUNK);
108                         return -ENOSPC;
109                 }
110 
111                 /* Vector on MSI is really an offset, the hardware adds
112                  * it to the value written at the magic address. So set
113                  * it to 0 to remain sane.
114                  */
115                 mpic_set_vector(virq, 0);
116 
117                 irq_set_msi_desc(virq, entry);
118                 irq_set_chip(virq, &mpic_pasemi_msi_chip);
119                 irq_set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
120 
121                 pr_debug("pasemi_msi: allocated virq 0x%x (hw 0x%x) " \
122                          "addr 0x%x\n", virq, hwirq, msg.address_lo);
123 
124                 /* Likewise, the device writes [0...511] into the target
125                  * register to generate MSI [512...1023]
126                  */
127                 msg.data = hwirq-0x200;
128                 pci_write_msi_msg(virq, &msg);
129         }
130 
131         return 0;
132 }
133 
134 int __init mpic_pasemi_msi_init(struct mpic *mpic)
135 {
136         int rc;
137         struct pci_controller *phb;
138         struct device_node *of_node;
139 
140         of_node = irq_domain_get_of_node(mpic->irqhost);
141         if (!of_node ||
142             !of_device_is_compatible(of_node,
143                                      "pasemi,pwrficient-openpic"))
144                 return -ENODEV;
145 
146         rc = mpic_msi_init_allocator(mpic);
147         if (rc) {
148                 pr_debug("pasemi_msi: Error allocating bitmap!\n");
149                 return rc;
150         }
151 
152         pr_debug("pasemi_msi: Registering PA Semi MPIC MSI callbacks\n");
153 
154         msi_mpic = mpic;
155         list_for_each_entry(phb, &hose_list, list_node) {
156                 WARN_ON(phb->controller_ops.setup_msi_irqs);
157                 phb->controller_ops.setup_msi_irqs = pasemi_msi_setup_msi_irqs;
158                 phb->controller_ops.teardown_msi_irqs = pasemi_msi_teardown_msi_irqs;
159         }
160 
161         return 0;
162 }
163 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php