| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | ** DINO manager |
|---|
| 3 | 4 | ** |
|---|
| .. | .. |
|---|
| 5 | 6 | ** (c) Copyright 1999 SuSE GmbH |
|---|
| 6 | 7 | ** (c) Copyright 1999,2000 Hewlett-Packard Company |
|---|
| 7 | 8 | ** (c) Copyright 2000 Grant Grundler |
|---|
| 8 | | -** (c) Copyright 2006 Helge Deller |
|---|
| 9 | +** (c) Copyright 2006-2019 Helge Deller |
|---|
| 9 | 10 | ** |
|---|
| 10 | | -** This program is free software; you can redistribute it and/or modify |
|---|
| 11 | | -** it under the terms of the GNU General Public License as published by |
|---|
| 12 | | -** the Free Software Foundation; either version 2 of the License, or |
|---|
| 13 | | -** (at your option) any later version. |
|---|
| 14 | 11 | ** |
|---|
| 15 | 12 | ** This module provides access to Dino PCI bus (config/IOport spaces) |
|---|
| 16 | 13 | ** and helps manage Dino IRQ lines. |
|---|
| .. | .. |
|---|
| 59 | 56 | #include <asm/hardware.h> |
|---|
| 60 | 57 | |
|---|
| 61 | 58 | #include "gsc.h" |
|---|
| 59 | +#include "iommu.h" |
|---|
| 62 | 60 | |
|---|
| 63 | 61 | #undef DINO_DEBUG |
|---|
| 64 | 62 | |
|---|
| .. | .. |
|---|
| 144 | 142 | { |
|---|
| 145 | 143 | struct pci_hba_data hba; /* 'C' inheritance - must be first */ |
|---|
| 146 | 144 | spinlock_t dinosaur_pen; |
|---|
| 147 | | - unsigned long txn_addr; /* EIR addr to generate interrupt */ |
|---|
| 148 | | - u32 txn_data; /* EIR data assign to each dino */ |
|---|
| 149 | 145 | u32 imr; /* IRQ's which are enabled */ |
|---|
| 146 | + struct gsc_irq gsc_irq; |
|---|
| 150 | 147 | int global_irq[DINO_LOCAL_IRQS]; /* map IMR bit to global irq */ |
|---|
| 151 | 148 | #ifdef DINO_DEBUG |
|---|
| 152 | 149 | unsigned int dino_irr0; /* save most recent IRQ line stat */ |
|---|
| 153 | 150 | #endif |
|---|
| 154 | 151 | }; |
|---|
| 155 | 152 | |
|---|
| 156 | | -/* Looks nice and keeps the compiler happy */ |
|---|
| 157 | | -#define DINO_DEV(d) ({ \ |
|---|
| 158 | | - void *__pdata = d; \ |
|---|
| 159 | | - BUG_ON(!__pdata); \ |
|---|
| 160 | | - (struct dino_device *)__pdata; }) |
|---|
| 161 | | - |
|---|
| 153 | +static inline struct dino_device *DINO_DEV(struct pci_hba_data *hba) |
|---|
| 154 | +{ |
|---|
| 155 | + return container_of(hba, struct dino_device, hba); |
|---|
| 156 | +} |
|---|
| 162 | 157 | |
|---|
| 163 | 158 | /* |
|---|
| 164 | 159 | * Dino Configuration Space Accessor Functions |
|---|
| .. | .. |
|---|
| 343 | 338 | if (tmp & DINO_MASK_IRQ(local_irq)) { |
|---|
| 344 | 339 | DBG(KERN_WARNING "%s(): IRQ asserted! (ILR 0x%x)\n", |
|---|
| 345 | 340 | __func__, tmp); |
|---|
| 346 | | - gsc_writel(dino_dev->txn_data, dino_dev->txn_addr); |
|---|
| 341 | + gsc_writel(dino_dev->gsc_irq.txn_data, dino_dev->gsc_irq.txn_addr); |
|---|
| 347 | 342 | } |
|---|
| 348 | 343 | } |
|---|
| 344 | + |
|---|
| 345 | +#ifdef CONFIG_SMP |
|---|
| 346 | +static int dino_set_affinity_irq(struct irq_data *d, const struct cpumask *dest, |
|---|
| 347 | + bool force) |
|---|
| 348 | +{ |
|---|
| 349 | + struct dino_device *dino_dev = irq_data_get_irq_chip_data(d); |
|---|
| 350 | + struct cpumask tmask; |
|---|
| 351 | + int cpu_irq; |
|---|
| 352 | + u32 eim; |
|---|
| 353 | + |
|---|
| 354 | + if (!cpumask_and(&tmask, dest, cpu_online_mask)) |
|---|
| 355 | + return -EINVAL; |
|---|
| 356 | + |
|---|
| 357 | + cpu_irq = cpu_check_affinity(d, &tmask); |
|---|
| 358 | + if (cpu_irq < 0) |
|---|
| 359 | + return cpu_irq; |
|---|
| 360 | + |
|---|
| 361 | + dino_dev->gsc_irq.txn_addr = txn_affinity_addr(d->irq, cpu_irq); |
|---|
| 362 | + eim = ((u32) dino_dev->gsc_irq.txn_addr) | dino_dev->gsc_irq.txn_data; |
|---|
| 363 | + __raw_writel(eim, dino_dev->hba.base_addr+DINO_IAR0); |
|---|
| 364 | + |
|---|
| 365 | + irq_data_update_effective_affinity(d, &tmask); |
|---|
| 366 | + |
|---|
| 367 | + return IRQ_SET_MASK_OK; |
|---|
| 368 | +} |
|---|
| 369 | +#endif |
|---|
| 349 | 370 | |
|---|
| 350 | 371 | static struct irq_chip dino_interrupt_type = { |
|---|
| 351 | 372 | .name = "GSC-PCI", |
|---|
| 352 | 373 | .irq_unmask = dino_unmask_irq, |
|---|
| 353 | 374 | .irq_mask = dino_mask_irq, |
|---|
| 375 | +#ifdef CONFIG_SMP |
|---|
| 376 | + .irq_set_affinity = dino_set_affinity_irq, |
|---|
| 377 | +#endif |
|---|
| 354 | 378 | }; |
|---|
| 355 | 379 | |
|---|
| 356 | 380 | |
|---|
| .. | .. |
|---|
| 382 | 406 | DBG(KERN_DEBUG "%s(%d, %p) mask 0x%x\n", |
|---|
| 383 | 407 | __func__, irq, intr_dev, mask); |
|---|
| 384 | 408 | generic_handle_irq(irq); |
|---|
| 385 | | - mask &= ~(1 << local_irq); |
|---|
| 409 | + mask &= ~DINO_MASK_IRQ(local_irq); |
|---|
| 386 | 410 | } while (mask); |
|---|
| 387 | 411 | |
|---|
| 388 | 412 | /* Support for level triggered IRQ lines. |
|---|
| .. | .. |
|---|
| 396 | 420 | if (mask) { |
|---|
| 397 | 421 | if (--ilr_loop > 0) |
|---|
| 398 | 422 | goto ilr_again; |
|---|
| 399 | | - printk(KERN_ERR "Dino 0x%px: stuck interrupt %d\n", |
|---|
| 423 | + pr_warn_ratelimited("Dino 0x%px: stuck interrupt %d\n", |
|---|
| 400 | 424 | dino_dev->hba.base_addr, mask); |
|---|
| 401 | | - return IRQ_NONE; |
|---|
| 402 | 425 | } |
|---|
| 403 | 426 | return IRQ_HANDLED; |
|---|
| 404 | 427 | } |
|---|
| .. | .. |
|---|
| 811 | 834 | { |
|---|
| 812 | 835 | int status; |
|---|
| 813 | 836 | u32 eim; |
|---|
| 814 | | - struct gsc_irq gsc_irq; |
|---|
| 815 | 837 | struct resource *res; |
|---|
| 816 | 838 | |
|---|
| 817 | 839 | pcibios_register_hba(&dino_dev->hba); |
|---|
| .. | .. |
|---|
| 826 | 848 | ** still only has 11 IRQ input lines - just map some of them |
|---|
| 827 | 849 | ** to a different processor. |
|---|
| 828 | 850 | */ |
|---|
| 829 | | - dev->irq = gsc_alloc_irq(&gsc_irq); |
|---|
| 830 | | - dino_dev->txn_addr = gsc_irq.txn_addr; |
|---|
| 831 | | - dino_dev->txn_data = gsc_irq.txn_data; |
|---|
| 832 | | - eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data; |
|---|
| 851 | + dev->irq = gsc_alloc_irq(&dino_dev->gsc_irq); |
|---|
| 852 | + eim = ((u32) dino_dev->gsc_irq.txn_addr) | dino_dev->gsc_irq.txn_data; |
|---|
| 833 | 853 | |
|---|
| 834 | 854 | /* |
|---|
| 835 | 855 | ** Dino needs a PA "IRQ" to get a processor's attention. |
|---|
| .. | .. |
|---|
| 892 | 912 | #define CUJO_RAVEN_BADPAGE 0x01003000UL |
|---|
| 893 | 913 | #define CUJO_FIREHAWK_BADPAGE 0x01607000UL |
|---|
| 894 | 914 | |
|---|
| 895 | | -static const char *dino_vers[] = { |
|---|
| 915 | +static const char dino_vers[][4] = { |
|---|
| 896 | 916 | "2.0", |
|---|
| 897 | 917 | "2.1", |
|---|
| 898 | 918 | "3.0", |
|---|
| 899 | 919 | "3.1" |
|---|
| 900 | 920 | }; |
|---|
| 901 | 921 | |
|---|
| 902 | | -static const char *cujo_vers[] = { |
|---|
| 922 | +static const char cujo_vers[][4] = { |
|---|
| 903 | 923 | "1.0", |
|---|
| 904 | 924 | "2.0" |
|---|
| 905 | 925 | }; |
|---|
| .. | .. |
|---|
| 979 | 999 | } |
|---|
| 980 | 1000 | |
|---|
| 981 | 1001 | dino_dev->hba.dev = dev; |
|---|
| 982 | | - dino_dev->hba.base_addr = ioremap_nocache(hpa, 4096); |
|---|
| 1002 | + dino_dev->hba.base_addr = ioremap(hpa, 4096); |
|---|
| 983 | 1003 | dino_dev->hba.lmmio_space_offset = PCI_F_EXTEND; |
|---|
| 984 | 1004 | spin_lock_init(&dino_dev->dinosaur_pen); |
|---|
| 985 | 1005 | dino_dev->hba.iommu = ccio_get_iommu(dev); |
|---|