1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <console/console.h>
4 #include <device/pci.h>
5 #include <device/pci_ops.h>
6 #include <intelblocks/gpio.h>
7 #include <intelblocks/irq.h>
8 #include <intelblocks/lpc_lib.h>
9 #include <soc/pci_devs.h>
10 #include <southbridge/intel/common/acpi_pirq_gen.h>
14 #define MIN_SHARED_IRQ 16
15 #define MAX_SHARED_IRQ 23
16 #define TOTAL_SHARED_IRQ (MAX_SHARED_IRQ - MIN_SHARED_IRQ + 1)
19 #define IDX2PIN(i) (enum pci_pin)((i) + PCI_INT_A)
20 #define PIN2IDX(p) (size_t)((p) - PCI_INT_A)
28 unsigned int usage_count
;
32 static unsigned int irq_share_count
[TOTAL_SHARED_IRQ
];
35 * Assign PCI IRQs & pins according to controller rules.
37 * This information is provided to the FSP in order for it to do the
38 * programming; this is required because the FSP is also responsible for
39 * enabling some PCI devices so they will show up on their respective PCI
40 * buses. The FSP & PCH BIOS Specification contain rules for how certain IPs
41 * require their interrupt pin and interrupt line to be programmed.
43 * IOAPIC IRQs are used for PCI devices & GPIOs. The GPIO IRQs are fixed in
44 * hardware (the IRQ field is RO), and often start at 24, which means
45 * conflicts with PCI devices (if using the default FSP configuration) are very
48 * These are the rules:
49 * 1) One entry per slot/function
50 * 2) Functions using PIRQs must use IOxAPIC IRQs 16-23
51 * 3) Single-function devices must use INTA
52 * 4) Each slot must have consistent INTx<->PIRQy mappings
53 * 5) Some functions have special interrupt pin requirements (FIXED_INT_ANY_PIRQ)
54 * 6) PCI Express RPs must be assigned in a special way (FIXED_INT_PIRQ)
55 * 7) Some functions require a unique IRQ number (mostly LPSS devices, DIRECT_IRQ)
56 * 8) PCI functions must avoid sharing an IRQ with a GPIO pad which routes its
57 * IRQ through IO-APIC.
60 static int find_free_unique_irq(void)
62 static unsigned int next_irq
= MAX_SHARED_IRQ
+ 1;
64 while (next_irq
< MAX_IRQS
&& gpio_routes_ioapic_irq(next_irq
))
67 if (next_irq
== MAX_IRQS
)
73 static enum pci_pin
find_free_pin(const struct pin_info pin_info
[PCI_INT_MAX
])
75 for (size_t pin_idx
= 0; pin_idx
< PCI_INT_MAX
; pin_idx
++) {
76 if (pin_info
[pin_idx
].pin_state
== FREE_PIN
)
77 return IDX2PIN(pin_idx
);
83 static enum pci_pin
find_shareable_pin(const struct pin_info pin_info
[PCI_INT_MAX
])
85 unsigned int least_shared
= 255;
88 for (size_t pin_idx
= 0; pin_idx
< PCI_INT_MAX
; pin_idx
++) {
89 if (pin_info
[pin_idx
].pin_state
== SHARED_IRQ_PIN
&&
90 pin_info
[pin_idx
].usage_count
< least_shared
) {
91 least_shared
= pin_info
[pin_idx
].usage_count
;
92 least_index
= pin_idx
;
99 return IDX2PIN(least_index
);
102 static enum pirq
find_global_least_used_pirq(void)
104 unsigned int least_shared
= 255;
105 int least_index
= -1;
107 for (size_t i
= 0; i
< TOTAL_SHARED_IRQ
; i
++) {
108 if (irq_share_count
[i
] < least_shared
) {
109 least_shared
= irq_share_count
[i
];
114 if (least_index
>= 0)
115 return (enum pirq
)least_index
+ PIRQ_A
;
121 static int pirq_to_irq(enum pirq pirq
)
123 return pirq_idx(pirq
) + MIN_SHARED_IRQ
;
126 static bool assign_pirq(struct pin_info pin_info
[PCI_INT_MAX
], enum pci_pin pin
, enum pirq pirq
)
128 if (pirq
< PIRQ_A
|| pirq
> PIRQ_H
) {
129 printk(BIOS_ERR
, "Invalid pirq constraint %u\n", pirq
);
133 const int irq
= pirq_to_irq(pirq
);
134 pin_info
[PIN2IDX(pin
)].irq
= irq
;
135 irq_share_count
[pirq_idx(pirq
)]++;
139 static bool assign_pin(enum pci_pin pin
, unsigned int fn
, enum pin_state state
,
140 struct pin_info
*pin_info
,
141 enum pci_pin fn_pin_map
[MAX_FNS
])
143 if (pin
< PCI_INT_A
|| pin
> PCI_INT_D
) {
144 printk(BIOS_ERR
, "Invalid pin constraint %u\n", pin
);
148 const size_t pin_idx
= PIN2IDX(pin
);
149 pin_info
[pin_idx
].pin_state
= state
;
150 pin_info
[pin_idx
].usage_count
++;
151 fn_pin_map
[fn
] = pin
;
156 static bool assign_fixed_pins(const struct slot_irq_constraints
*constraints
,
157 struct pin_info
*pin_info
, enum pci_pin fn_pin_map
[MAX_FNS
])
159 for (size_t i
= 0; i
< MAX_FNS
; i
++) {
160 const enum pci_pin fixed_int_pin
= constraints
->fns
[i
].fixed_int_pin
;
161 if (fixed_int_pin
== PCI_INT_NONE
)
164 if (!assign_pin(fixed_int_pin
, i
, SHARED_IRQ_PIN
, pin_info
, fn_pin_map
))
171 static bool assign_fixed_pirqs(const struct slot_irq_constraints
*constraints
,
172 struct pin_info
*pin_info
, enum pci_pin fn_pin_map
[MAX_FNS
])
174 for (size_t i
= 0; i
< MAX_FNS
; i
++) {
175 const enum pirq fixed_pirq
= constraints
->fns
[i
].fixed_pirq
;
176 if (fixed_pirq
== PIRQ_INVALID
)
179 /* A constraint with a fixed pirq is assumed to also have a
181 const enum pci_pin pin
= fn_pin_map
[i
];
182 if (pin
== PCI_INT_NONE
) {
183 printk(BIOS_ERR
, "Slot %u, pirq %u, no pin for function %zu\n",
184 constraints
->slot
, fixed_pirq
, i
);
188 if (!assign_pirq(pin_info
, pin
, fixed_pirq
))
195 static bool assign_direct_irqs(const struct slot_irq_constraints
*constraints
,
196 struct pin_info
*pin_info
, enum pci_pin fn_pin_map
[MAX_FNS
])
198 for (size_t i
= 0; i
< MAX_FNS
; i
++) {
199 if (constraints
->fns
[i
].irq_route
!= IRQ_DIRECT
)
202 enum pci_pin pin
= find_free_pin(pin_info
);
203 if (pin
== PCI_INT_NONE
)
206 if (!assign_pin(pin
, i
, UNIQUE_IRQ_PIN
, pin_info
, fn_pin_map
))
209 const int irq
= find_free_unique_irq();
210 if (irq
== INVALID_IRQ
) {
211 printk(BIOS_ERR
, "No free unique IRQs found\n");
215 const size_t pin_idx
= PIN2IDX(pin
);
216 pin_info
[pin_idx
].irq
= irq
;
222 static bool assign_shareable_pins(const struct slot_irq_constraints
*constraints
,
223 struct pin_info
*pin_info
, enum pci_pin fn_pin_map
[MAX_FNS
])
225 for (size_t i
= 0; i
< MAX_FNS
; i
++) {
226 if (constraints
->fns
[i
].irq_route
!= IRQ_PIRQ
)
229 if (fn_pin_map
[i
] == PCI_INT_NONE
) {
230 enum pci_pin pin
= find_free_pin(pin_info
);
231 if (pin
== PCI_INT_NONE
) {
232 pin
= find_shareable_pin(pin_info
);
234 if (pin
== PCI_INT_NONE
) {
235 printk(BIOS_ERR
, "No shareable pins found\n");
240 if (!assign_pin(pin
, i
, SHARED_IRQ_PIN
, pin_info
, fn_pin_map
))
248 static bool assign_pirqs(struct pin_info pin_info
[PCI_INT_MAX
])
250 for (size_t pin_idx
= 0; pin_idx
< PCI_INT_MAX
; pin_idx
++) {
251 if (pin_info
[pin_idx
].pin_state
!= SHARED_IRQ_PIN
|| pin_info
[pin_idx
].irq
!= 0)
254 enum pirq pirq
= find_global_least_used_pirq();
255 if (pirq
== PIRQ_INVALID
)
258 if (!assign_pirq(pin_info
, IDX2PIN(pin_idx
), pirq
))
265 static void add_entry(struct pci_irq_entry
**head
, pci_devfn_t devfn
, enum pci_pin pin
,
268 struct pci_irq_entry
*entry
= malloc(sizeof(*entry
));
269 struct pci_irq_entry
**tmp
= head
;
271 entry
->devfn
= devfn
;
282 static void add_slot_entries(struct pci_irq_entry
**head
, unsigned int slot
,
283 struct pin_info pin_info
[PCI_INT_MAX
],
284 const enum pci_pin fn_pin_map
[MAX_FNS
])
286 for (size_t fn
= 0; fn
< MAX_FNS
; fn
++) {
287 if (fn_pin_map
[fn
] == PCI_INT_NONE
)
290 const size_t pin_idx
= PIN2IDX(fn_pin_map
[fn
]);
291 add_entry(head
, PCI_DEVFN(slot
, fn
), fn_pin_map
[fn
], pin_info
[pin_idx
].irq
);
295 static bool assign_slot(struct pci_irq_entry
**head
,
296 const struct slot_irq_constraints
*constraints
)
298 struct pin_info pin_info
[PCI_INT_MAX
] = {0};
299 enum pci_pin fn_pin_map
[MAX_FNS
] = {0};
301 /* The order in which pins are assigned is important in that strict constraints must
302 * be resolved first. This means fixed_int_pin -> fixed_pirq -> direct route ->
303 * shared pins -> shared pirqs
305 if (!assign_fixed_pins(constraints
, pin_info
, fn_pin_map
))
308 if (!assign_fixed_pirqs(constraints
, pin_info
, fn_pin_map
))
311 if (!assign_direct_irqs(constraints
, pin_info
, fn_pin_map
))
314 if (!assign_shareable_pins(constraints
, pin_info
, fn_pin_map
))
317 if (!assign_pirqs(pin_info
))
320 add_slot_entries(head
, constraints
->slot
, pin_info
, fn_pin_map
);
324 static struct pci_irq_entry
*cached_entries
;
326 bool assign_pci_irqs(const struct slot_irq_constraints
*constraints
, size_t num_slots
)
328 for (size_t i
= 0; i
< num_slots
; i
++) {
329 if (!assign_slot(&cached_entries
, &constraints
[i
]))
333 const struct pci_irq_entry
*entry
= cached_entries
;
335 printk(BIOS_INFO
, "PCI %2X.%X, %s, using IRQ #%d\n",
336 PCI_SLOT(entry
->devfn
), PCI_FUNC(entry
->devfn
),
337 pin_to_str(entry
->pin
), entry
->irq
);
345 const struct pci_irq_entry
*get_cached_pci_irqs(void)
347 return cached_entries
;
350 static enum pirq
irq_to_pirq(unsigned int irq
)
352 if (irq
>= MIN_SHARED_IRQ
&& irq
<= MAX_SHARED_IRQ
)
353 return (enum pirq
)(irq
- MIN_SHARED_IRQ
+ PIRQ_A
);
356 * Unknown if devices that require unique IRQs will
357 * even work in legacy PIC mode, given they cannot map
358 * to a PIRQ, therefore skip adding an entry.
363 bool generate_pin_irq_map(void)
365 struct slot_pin_irq_map
*pin_irq_map
;
366 const uint8_t *legacy_pirq_routing
;
367 struct pic_pirq_map pirq_map
= {0};
368 size_t map_count
= 0;
375 pin_irq_map
= calloc(MAX_SLOTS
* PCI_INT_MAX
, sizeof(struct slot_pin_irq_map
));
377 pirq_map
.type
= PIRQ_GSI
;
378 legacy_pirq_routing
= lpc_get_pic_pirq_routing(&pirq_routes
);
379 for (i
= 0; i
< PIRQ_COUNT
&& i
< pirq_routes
; i
++)
380 pirq_map
.gsi
[i
] = legacy_pirq_routing
[i
];
382 const struct pci_irq_entry
*entry
= cached_entries
;
384 const unsigned int slot
= PCI_SLOT(entry
->devfn
);
386 if (is_slot_pin_assigned(pin_irq_map
, map_count
, slot
, entry
->pin
)) {
391 pin_irq_map
[map_count
].slot
= slot
;
392 pin_irq_map
[map_count
].pin
= entry
->pin
;
393 pin_irq_map
[map_count
].apic_gsi
= entry
->irq
;
394 pin_irq_map
[map_count
].pic_pirq
= irq_to_pirq(entry
->irq
);
399 intel_write_pci_PRT("\\_SB.PCI0", pin_irq_map
, map_count
, &pirq_map
);
405 bool __weak
is_pch_slot(unsigned int devfn
)
407 if (PCI_SLOT(devfn
) >= MIN_PCH_SLOT
)
412 bool irq_program_non_pch(void)
414 const struct pci_irq_entry
*entry
= cached_entries
;
420 if (is_pch_slot(entry
->devfn
)) {
426 pci_devfn_t dev
= PCI_DEV(0, PCI_SLOT(entry
->devfn
),
427 PCI_FUNC(entry
->devfn
));
428 pci_s_write_config8(dev
, PCI_INTERRUPT_LINE
, entry
->irq
);
429 pci_s_write_config8(dev
, PCI_INTERRUPT_PIN
, (uint8_t)entry
->pin
);
438 int get_pci_devfn_irq(unsigned int devfn
)
440 const struct pci_irq_entry
*entry
= cached_entries
;
443 if (entry
->devfn
== devfn
)