diff options
Diffstat (limited to 'arch/sparc64/kernel/pci_psycho.c')
-rw-r--r-- | arch/sparc64/kernel/pci_psycho.c | 161 |
1 files changed, 20 insertions, 141 deletions
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 1cb63346f093..bf7b32b36705 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <asm/irq.h> | 18 | #include <asm/irq.h> |
19 | #include <asm/starfire.h> | 19 | #include <asm/starfire.h> |
20 | #include <asm/prom.h> | 20 | #include <asm/prom.h> |
21 | #include <asm/of_device.h> | ||
21 | 22 | ||
22 | #include "pci_impl.h" | 23 | #include "pci_impl.h" |
23 | #include "iommu_common.h" | 24 | #include "iommu_common.h" |
@@ -208,110 +209,6 @@ static struct pci_ops psycho_ops = { | |||
208 | .write = psycho_write_pci_cfg, | 209 | .write = psycho_write_pci_cfg, |
209 | }; | 210 | }; |
210 | 211 | ||
211 | /* PSYCHO interrupt mapping support. */ | ||
212 | #define PSYCHO_IMAP_A_SLOT0 0x0c00UL | ||
213 | #define PSYCHO_IMAP_B_SLOT0 0x0c20UL | ||
214 | static unsigned long psycho_pcislot_imap_offset(unsigned long ino) | ||
215 | { | ||
216 | unsigned int bus = (ino & 0x10) >> 4; | ||
217 | unsigned int slot = (ino & 0x0c) >> 2; | ||
218 | |||
219 | if (bus == 0) | ||
220 | return PSYCHO_IMAP_A_SLOT0 + (slot * 8); | ||
221 | else | ||
222 | return PSYCHO_IMAP_B_SLOT0 + (slot * 8); | ||
223 | } | ||
224 | |||
225 | #define PSYCHO_IMAP_SCSI 0x1000UL | ||
226 | #define PSYCHO_IMAP_ETH 0x1008UL | ||
227 | #define PSYCHO_IMAP_BPP 0x1010UL | ||
228 | #define PSYCHO_IMAP_AU_REC 0x1018UL | ||
229 | #define PSYCHO_IMAP_AU_PLAY 0x1020UL | ||
230 | #define PSYCHO_IMAP_PFAIL 0x1028UL | ||
231 | #define PSYCHO_IMAP_KMS 0x1030UL | ||
232 | #define PSYCHO_IMAP_FLPY 0x1038UL | ||
233 | #define PSYCHO_IMAP_SHW 0x1040UL | ||
234 | #define PSYCHO_IMAP_KBD 0x1048UL | ||
235 | #define PSYCHO_IMAP_MS 0x1050UL | ||
236 | #define PSYCHO_IMAP_SER 0x1058UL | ||
237 | #define PSYCHO_IMAP_TIM0 0x1060UL | ||
238 | #define PSYCHO_IMAP_TIM1 0x1068UL | ||
239 | #define PSYCHO_IMAP_UE 0x1070UL | ||
240 | #define PSYCHO_IMAP_CE 0x1078UL | ||
241 | #define PSYCHO_IMAP_A_ERR 0x1080UL | ||
242 | #define PSYCHO_IMAP_B_ERR 0x1088UL | ||
243 | #define PSYCHO_IMAP_PMGMT 0x1090UL | ||
244 | #define PSYCHO_IMAP_GFX 0x1098UL | ||
245 | #define PSYCHO_IMAP_EUPA 0x10a0UL | ||
246 | |||
247 | static unsigned long __onboard_imap_off[] = { | ||
248 | /*0x20*/ PSYCHO_IMAP_SCSI, | ||
249 | /*0x21*/ PSYCHO_IMAP_ETH, | ||
250 | /*0x22*/ PSYCHO_IMAP_BPP, | ||
251 | /*0x23*/ PSYCHO_IMAP_AU_REC, | ||
252 | /*0x24*/ PSYCHO_IMAP_AU_PLAY, | ||
253 | /*0x25*/ PSYCHO_IMAP_PFAIL, | ||
254 | /*0x26*/ PSYCHO_IMAP_KMS, | ||
255 | /*0x27*/ PSYCHO_IMAP_FLPY, | ||
256 | /*0x28*/ PSYCHO_IMAP_SHW, | ||
257 | /*0x29*/ PSYCHO_IMAP_KBD, | ||
258 | /*0x2a*/ PSYCHO_IMAP_MS, | ||
259 | /*0x2b*/ PSYCHO_IMAP_SER, | ||
260 | /*0x2c*/ PSYCHO_IMAP_TIM0, | ||
261 | /*0x2d*/ PSYCHO_IMAP_TIM1, | ||
262 | /*0x2e*/ PSYCHO_IMAP_UE, | ||
263 | /*0x2f*/ PSYCHO_IMAP_CE, | ||
264 | /*0x30*/ PSYCHO_IMAP_A_ERR, | ||
265 | /*0x31*/ PSYCHO_IMAP_B_ERR, | ||
266 | /*0x32*/ PSYCHO_IMAP_PMGMT | ||
267 | }; | ||
268 | #define PSYCHO_ONBOARD_IRQ_BASE 0x20 | ||
269 | #define PSYCHO_ONBOARD_IRQ_LAST 0x32 | ||
270 | #define psycho_onboard_imap_offset(__ino) \ | ||
271 | __onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE] | ||
272 | |||
273 | #define PSYCHO_ICLR_A_SLOT0 0x1400UL | ||
274 | #define PSYCHO_ICLR_SCSI 0x1800UL | ||
275 | |||
276 | #define psycho_iclr_offset(ino) \ | ||
277 | ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ | ||
278 | (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) | ||
279 | |||
280 | static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, | ||
281 | struct pci_dev *pdev, | ||
282 | unsigned int ino) | ||
283 | { | ||
284 | unsigned long imap, iclr; | ||
285 | unsigned long imap_off, iclr_off; | ||
286 | int inofixup = 0; | ||
287 | |||
288 | ino &= PCI_IRQ_INO; | ||
289 | if (ino < PSYCHO_ONBOARD_IRQ_BASE) { | ||
290 | /* PCI slot */ | ||
291 | imap_off = psycho_pcislot_imap_offset(ino); | ||
292 | } else { | ||
293 | /* Onboard device */ | ||
294 | if (ino > PSYCHO_ONBOARD_IRQ_LAST) { | ||
295 | prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino); | ||
296 | prom_halt(); | ||
297 | } | ||
298 | imap_off = psycho_onboard_imap_offset(ino); | ||
299 | } | ||
300 | |||
301 | /* Now build the IRQ bucket. */ | ||
302 | imap = pbm->controller_regs + imap_off; | ||
303 | imap += 4; | ||
304 | |||
305 | iclr_off = psycho_iclr_offset(ino); | ||
306 | iclr = pbm->controller_regs + iclr_off; | ||
307 | iclr += 4; | ||
308 | |||
309 | if ((ino & 0x20) == 0) | ||
310 | inofixup = ino & 0x03; | ||
311 | |||
312 | return build_irq(inofixup, iclr, imap); | ||
313 | } | ||
314 | |||
315 | /* PSYCHO error handling support. */ | 212 | /* PSYCHO error handling support. */ |
316 | enum psycho_error_type { | 213 | enum psycho_error_type { |
317 | UE_ERR, CE_ERR, PCI_ERR | 214 | UE_ERR, CE_ERR, PCI_ERR |
@@ -944,51 +841,34 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id, struct pt_regs *reg | |||
944 | #define PSYCHO_ECCCTRL_EE 0x8000000000000000UL /* Enable ECC Checking */ | 841 | #define PSYCHO_ECCCTRL_EE 0x8000000000000000UL /* Enable ECC Checking */ |
945 | #define PSYCHO_ECCCTRL_UE 0x4000000000000000UL /* Enable UE Interrupts */ | 842 | #define PSYCHO_ECCCTRL_UE 0x4000000000000000UL /* Enable UE Interrupts */ |
946 | #define PSYCHO_ECCCTRL_CE 0x2000000000000000UL /* Enable CE INterrupts */ | 843 | #define PSYCHO_ECCCTRL_CE 0x2000000000000000UL /* Enable CE INterrupts */ |
947 | #define PSYCHO_UE_INO 0x2e | ||
948 | #define PSYCHO_CE_INO 0x2f | ||
949 | #define PSYCHO_PCIERR_A_INO 0x30 | ||
950 | #define PSYCHO_PCIERR_B_INO 0x31 | ||
951 | static void psycho_register_error_handlers(struct pci_controller_info *p) | 844 | static void psycho_register_error_handlers(struct pci_controller_info *p) |
952 | { | 845 | { |
953 | struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */ | 846 | struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */ |
847 | struct of_device *op = of_find_device_by_node(pbm->prom_node); | ||
954 | unsigned long base = p->pbm_A.controller_regs; | 848 | unsigned long base = p->pbm_A.controller_regs; |
955 | unsigned int irq, portid = pbm->portid; | ||
956 | u64 tmp; | 849 | u64 tmp; |
957 | 850 | ||
958 | /* Build IRQs and register handlers. */ | 851 | if (!op) |
959 | irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_UE_INO); | 852 | return; |
960 | if (request_irq(irq, psycho_ue_intr, | ||
961 | SA_SHIRQ, "PSYCHO UE", p) < 0) { | ||
962 | prom_printf("PSYCHO%d: Cannot register UE interrupt.\n", | ||
963 | p->index); | ||
964 | prom_halt(); | ||
965 | } | ||
966 | 853 | ||
967 | irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_CE_INO); | 854 | /* Psycho interrupt property order is: |
968 | if (request_irq(irq, psycho_ce_intr, | 855 | * 0: PCIERR PBM B INO |
969 | SA_SHIRQ, "PSYCHO CE", p) < 0) { | 856 | * 1: UE ERR |
970 | prom_printf("PSYCHO%d: Cannot register CE interrupt.\n", | 857 | * 2: CE ERR |
971 | p->index); | 858 | * 3: POWER FAIL |
972 | prom_halt(); | 859 | * 4: SPARE HARDWARE |
973 | } | 860 | * 5: PCIERR PBM A INO |
861 | */ | ||
974 | 862 | ||
975 | pbm = &p->pbm_A; | 863 | if (op->num_irqs < 6) |
976 | irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_PCIERR_A_INO); | 864 | return; |
977 | if (request_irq(irq, psycho_pcierr_intr, | ||
978 | SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_A) < 0) { | ||
979 | prom_printf("PSYCHO%d(PBMA): Cannot register PciERR interrupt.\n", | ||
980 | p->index); | ||
981 | prom_halt(); | ||
982 | } | ||
983 | 865 | ||
984 | pbm = &p->pbm_B; | 866 | request_irq(op->irqs[1], psycho_ue_intr, SA_SHIRQ, "PSYCHO UE", p); |
985 | irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_PCIERR_B_INO); | 867 | request_irq(op->irqs[2], psycho_ce_intr, SA_SHIRQ, "PSYCHO CE", p); |
986 | if (request_irq(irq, psycho_pcierr_intr, | 868 | request_irq(op->irqs[5], psycho_pcierr_intr, SA_SHIRQ, |
987 | SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_B) < 0) { | 869 | "PSYCHO PCIERR-A", &p->pbm_A); |
988 | prom_printf("PSYCHO%d(PBMB): Cannot register PciERR interrupt.\n", | 870 | request_irq(op->irqs[0], psycho_pcierr_intr, SA_SHIRQ, |
989 | p->index); | 871 | "PSYCHO PCIERR-B", &p->pbm_B); |
990 | prom_halt(); | ||
991 | } | ||
992 | 872 | ||
993 | /* Enable UE and CE interrupts for controller. */ | 873 | /* Enable UE and CE interrupts for controller. */ |
994 | psycho_write(base + PSYCHO_ECC_CTRL, | 874 | psycho_write(base + PSYCHO_ECC_CTRL, |
@@ -1406,7 +1286,6 @@ void psycho_init(struct device_node *dp, char *model_name) | |||
1406 | p->index = pci_num_controllers++; | 1286 | p->index = pci_num_controllers++; |
1407 | p->pbms_same_domain = 0; | 1287 | p->pbms_same_domain = 0; |
1408 | p->scan_bus = psycho_scan_bus; | 1288 | p->scan_bus = psycho_scan_bus; |
1409 | p->irq_build = psycho_irq_build; | ||
1410 | p->base_address_update = psycho_base_address_update; | 1289 | p->base_address_update = psycho_base_address_update; |
1411 | p->resource_adjust = psycho_resource_adjust; | 1290 | p->resource_adjust = psycho_resource_adjust; |
1412 | p->pci_ops = &psycho_ops; | 1291 | p->pci_ops = &psycho_ops; |