xref: /openbmc/linux/arch/powerpc/platforms/powernv/pci-cxl.c (revision f456834a6c1db36c290fdfe8ab53107adaf334e7)
1*f456834aSIan Munsie /*
2*f456834aSIan Munsie  * Copyright 2014-2016 IBM Corp.
3*f456834aSIan Munsie  *
4*f456834aSIan Munsie  * This program is free software; you can redistribute it and/or
5*f456834aSIan Munsie  * modify it under the terms of the GNU General Public License
6*f456834aSIan Munsie  * as published by the Free Software Foundation; either version
7*f456834aSIan Munsie  * 2 of the License, or (at your option) any later version.
8*f456834aSIan Munsie  */
9*f456834aSIan Munsie 
10*f456834aSIan Munsie #include <asm/pnv-pci.h>
11*f456834aSIan Munsie #include <asm/opal.h>
12*f456834aSIan Munsie 
13*f456834aSIan Munsie #include "pci.h"
14*f456834aSIan Munsie 
15*f456834aSIan Munsie struct device_node *pnv_pci_get_phb_node(struct pci_dev *dev)
16*f456834aSIan Munsie {
17*f456834aSIan Munsie 	struct pci_controller *hose = pci_bus_to_host(dev->bus);
18*f456834aSIan Munsie 
19*f456834aSIan Munsie 	return of_node_get(hose->dn);
20*f456834aSIan Munsie }
21*f456834aSIan Munsie EXPORT_SYMBOL(pnv_pci_get_phb_node);
22*f456834aSIan Munsie 
23*f456834aSIan Munsie int pnv_phb_to_cxl_mode(struct pci_dev *dev, uint64_t mode)
24*f456834aSIan Munsie {
25*f456834aSIan Munsie 	struct pci_controller *hose = pci_bus_to_host(dev->bus);
26*f456834aSIan Munsie 	struct pnv_phb *phb = hose->private_data;
27*f456834aSIan Munsie 	struct pnv_ioda_pe *pe;
28*f456834aSIan Munsie 	int rc;
29*f456834aSIan Munsie 
30*f456834aSIan Munsie 	pe = pnv_ioda_get_pe(dev);
31*f456834aSIan Munsie 	if (!pe)
32*f456834aSIan Munsie 		return -ENODEV;
33*f456834aSIan Munsie 
34*f456834aSIan Munsie 	pe_info(pe, "Switching PHB to CXL\n");
35*f456834aSIan Munsie 
36*f456834aSIan Munsie 	rc = opal_pci_set_phb_cxl_mode(phb->opal_id, mode, pe->pe_number);
37*f456834aSIan Munsie 	if (rc == OPAL_UNSUPPORTED)
38*f456834aSIan Munsie 		dev_err(&dev->dev, "Required cxl mode not supported by firmware - update skiboot\n");
39*f456834aSIan Munsie 	else if (rc)
40*f456834aSIan Munsie 		dev_err(&dev->dev, "opal_pci_set_phb_cxl_mode failed: %i\n", rc);
41*f456834aSIan Munsie 
42*f456834aSIan Munsie 	return rc;
43*f456834aSIan Munsie }
44*f456834aSIan Munsie EXPORT_SYMBOL(pnv_phb_to_cxl_mode);
45*f456834aSIan Munsie 
46*f456834aSIan Munsie /* Find PHB for cxl dev and allocate MSI hwirqs?
47*f456834aSIan Munsie  * Returns the absolute hardware IRQ number
48*f456834aSIan Munsie  */
49*f456834aSIan Munsie int pnv_cxl_alloc_hwirqs(struct pci_dev *dev, int num)
50*f456834aSIan Munsie {
51*f456834aSIan Munsie 	struct pci_controller *hose = pci_bus_to_host(dev->bus);
52*f456834aSIan Munsie 	struct pnv_phb *phb = hose->private_data;
53*f456834aSIan Munsie 	int hwirq = msi_bitmap_alloc_hwirqs(&phb->msi_bmp, num);
54*f456834aSIan Munsie 
55*f456834aSIan Munsie 	if (hwirq < 0) {
56*f456834aSIan Munsie 		dev_warn(&dev->dev, "Failed to find a free MSI\n");
57*f456834aSIan Munsie 		return -ENOSPC;
58*f456834aSIan Munsie 	}
59*f456834aSIan Munsie 
60*f456834aSIan Munsie 	return phb->msi_base + hwirq;
61*f456834aSIan Munsie }
62*f456834aSIan Munsie EXPORT_SYMBOL(pnv_cxl_alloc_hwirqs);
63*f456834aSIan Munsie 
64*f456834aSIan Munsie void pnv_cxl_release_hwirqs(struct pci_dev *dev, int hwirq, int num)
65*f456834aSIan Munsie {
66*f456834aSIan Munsie 	struct pci_controller *hose = pci_bus_to_host(dev->bus);
67*f456834aSIan Munsie 	struct pnv_phb *phb = hose->private_data;
68*f456834aSIan Munsie 
69*f456834aSIan Munsie 	msi_bitmap_free_hwirqs(&phb->msi_bmp, hwirq - phb->msi_base, num);
70*f456834aSIan Munsie }
71*f456834aSIan Munsie EXPORT_SYMBOL(pnv_cxl_release_hwirqs);
72*f456834aSIan Munsie 
73*f456834aSIan Munsie void pnv_cxl_release_hwirq_ranges(struct cxl_irq_ranges *irqs,
74*f456834aSIan Munsie 				  struct pci_dev *dev)
75*f456834aSIan Munsie {
76*f456834aSIan Munsie 	struct pci_controller *hose = pci_bus_to_host(dev->bus);
77*f456834aSIan Munsie 	struct pnv_phb *phb = hose->private_data;
78*f456834aSIan Munsie 	int i, hwirq;
79*f456834aSIan Munsie 
80*f456834aSIan Munsie 	for (i = 1; i < CXL_IRQ_RANGES; i++) {
81*f456834aSIan Munsie 		if (!irqs->range[i])
82*f456834aSIan Munsie 			continue;
83*f456834aSIan Munsie 		pr_devel("cxl release irq range 0x%x: offset: 0x%lx  limit: %ld\n",
84*f456834aSIan Munsie 			 i, irqs->offset[i],
85*f456834aSIan Munsie 			 irqs->range[i]);
86*f456834aSIan Munsie 		hwirq = irqs->offset[i] - phb->msi_base;
87*f456834aSIan Munsie 		msi_bitmap_free_hwirqs(&phb->msi_bmp, hwirq,
88*f456834aSIan Munsie 				       irqs->range[i]);
89*f456834aSIan Munsie 	}
90*f456834aSIan Munsie }
91*f456834aSIan Munsie EXPORT_SYMBOL(pnv_cxl_release_hwirq_ranges);
92*f456834aSIan Munsie 
93*f456834aSIan Munsie int pnv_cxl_alloc_hwirq_ranges(struct cxl_irq_ranges *irqs,
94*f456834aSIan Munsie 			       struct pci_dev *dev, int num)
95*f456834aSIan Munsie {
96*f456834aSIan Munsie 	struct pci_controller *hose = pci_bus_to_host(dev->bus);
97*f456834aSIan Munsie 	struct pnv_phb *phb = hose->private_data;
98*f456834aSIan Munsie 	int i, hwirq, try;
99*f456834aSIan Munsie 
100*f456834aSIan Munsie 	memset(irqs, 0, sizeof(struct cxl_irq_ranges));
101*f456834aSIan Munsie 
102*f456834aSIan Munsie 	/* 0 is reserved for the multiplexed PSL DSI interrupt */
103*f456834aSIan Munsie 	for (i = 1; i < CXL_IRQ_RANGES && num; i++) {
104*f456834aSIan Munsie 		try = num;
105*f456834aSIan Munsie 		while (try) {
106*f456834aSIan Munsie 			hwirq = msi_bitmap_alloc_hwirqs(&phb->msi_bmp, try);
107*f456834aSIan Munsie 			if (hwirq >= 0)
108*f456834aSIan Munsie 				break;
109*f456834aSIan Munsie 			try /= 2;
110*f456834aSIan Munsie 		}
111*f456834aSIan Munsie 		if (!try)
112*f456834aSIan Munsie 			goto fail;
113*f456834aSIan Munsie 
114*f456834aSIan Munsie 		irqs->offset[i] = phb->msi_base + hwirq;
115*f456834aSIan Munsie 		irqs->range[i] = try;
116*f456834aSIan Munsie 		pr_devel("cxl alloc irq range 0x%x: offset: 0x%lx  limit: %li\n",
117*f456834aSIan Munsie 			 i, irqs->offset[i], irqs->range[i]);
118*f456834aSIan Munsie 		num -= try;
119*f456834aSIan Munsie 	}
120*f456834aSIan Munsie 	if (num)
121*f456834aSIan Munsie 		goto fail;
122*f456834aSIan Munsie 
123*f456834aSIan Munsie 	return 0;
124*f456834aSIan Munsie fail:
125*f456834aSIan Munsie 	pnv_cxl_release_hwirq_ranges(irqs, dev);
126*f456834aSIan Munsie 	return -ENOSPC;
127*f456834aSIan Munsie }
128*f456834aSIan Munsie EXPORT_SYMBOL(pnv_cxl_alloc_hwirq_ranges);
129*f456834aSIan Munsie 
130*f456834aSIan Munsie int pnv_cxl_get_irq_count(struct pci_dev *dev)
131*f456834aSIan Munsie {
132*f456834aSIan Munsie 	struct pci_controller *hose = pci_bus_to_host(dev->bus);
133*f456834aSIan Munsie 	struct pnv_phb *phb = hose->private_data;
134*f456834aSIan Munsie 
135*f456834aSIan Munsie 	return phb->msi_bmp.irq_count;
136*f456834aSIan Munsie }
137*f456834aSIan Munsie EXPORT_SYMBOL(pnv_cxl_get_irq_count);
138*f456834aSIan Munsie 
139*f456834aSIan Munsie int pnv_cxl_ioda_msi_setup(struct pci_dev *dev, unsigned int hwirq,
140*f456834aSIan Munsie 			   unsigned int virq)
141*f456834aSIan Munsie {
142*f456834aSIan Munsie 	struct pci_controller *hose = pci_bus_to_host(dev->bus);
143*f456834aSIan Munsie 	struct pnv_phb *phb = hose->private_data;
144*f456834aSIan Munsie 	unsigned int xive_num = hwirq - phb->msi_base;
145*f456834aSIan Munsie 	struct pnv_ioda_pe *pe;
146*f456834aSIan Munsie 	int rc;
147*f456834aSIan Munsie 
148*f456834aSIan Munsie 	if (!(pe = pnv_ioda_get_pe(dev)))
149*f456834aSIan Munsie 		return -ENODEV;
150*f456834aSIan Munsie 
151*f456834aSIan Munsie 	/* Assign XIVE to PE */
152*f456834aSIan Munsie 	rc = opal_pci_set_xive_pe(phb->opal_id, pe->pe_number, xive_num);
153*f456834aSIan Munsie 	if (rc) {
154*f456834aSIan Munsie 		pe_warn(pe, "%s: OPAL error %d setting msi_base 0x%x "
155*f456834aSIan Munsie 			"hwirq 0x%x XIVE 0x%x PE\n",
156*f456834aSIan Munsie 			pci_name(dev), rc, phb->msi_base, hwirq, xive_num);
157*f456834aSIan Munsie 		return -EIO;
158*f456834aSIan Munsie 	}
159*f456834aSIan Munsie 	pnv_set_msi_irq_chip(phb, virq);
160*f456834aSIan Munsie 
161*f456834aSIan Munsie 	return 0;
162*f456834aSIan Munsie }
163*f456834aSIan Munsie EXPORT_SYMBOL(pnv_cxl_ioda_msi_setup);
164