📄 voyager_cat.c
字号:
asicp->asic_location = asic; sp_table = (voyager_sp_table_t *)(eprom_buf + sp_offset); asicp->asic_id = sp_table->asic_id; asic_table = (voyager_at_t *)(eprom_buf + sp_table->asic_data_offset); for(j=0; j<4; j++) asicp->jtag_id[j] = asic_table->jtag_id[j]; jtag_table = (voyager_jtt_t *)(eprom_buf + asic_table->jtag_offset); asicp->ireg_length = jtag_table->ireg_len; asicp->bit_location = (*modpp)->inst_bits; (*modpp)->inst_bits += asicp->ireg_length; if(asicp->ireg_length > (*modpp)->largest_reg) (*modpp)->largest_reg = asicp->ireg_length; if (asicp->ireg_length < (*modpp)->smallest_reg || (*modpp)->smallest_reg == 0) (*modpp)->smallest_reg = asicp->ireg_length; CDEBUG(("asic 0x%x, ireg_length=%d, bit_location=%d\n", asicp->asic_id, asicp->ireg_length, asicp->bit_location)); if(asicp->asic_id == VOYAGER_QUAD_QABC) { CDEBUG(("VOYAGER CAT: QABC ASIC found\n")); qabc_asic = asicp; } sp_offset += sizeof(voyager_sp_table_t); } CDEBUG(("Module inst_bits = %d, largest_reg = %d, smallest_reg=%d\n", (*modpp)->inst_bits, (*modpp)->largest_reg, (*modpp)->smallest_reg)); /* OK, now we have the QUAD ASICs set up, use them. * we need to: * * 1. Find the Memory area for the Quad CPIs. * 2. Find the Extended VIC processor * 3. Configure a second extended VIC processor (This * cannot be done for the 51xx. * */ outb(VOYAGER_CAT_RUN, CAT_CMD); cat_connect(*modpp, (*modpp)->asic); CDEBUG(("CAT CONNECTED!!\n")); cat_subread(*modpp, qabc_asic, 0, sizeof(qabc_data), qabc_data); qic_addr = qabc_data[5] << 8; qic_addr = (qic_addr | qabc_data[6]) << 8; qic_addr = (qic_addr | qabc_data[7]) << 8; printk("Module \"%s\": Quad Processor Card; CPI 0x%lx, SET=0x%x\n", cat_module_name(i), qic_addr, qabc_data[8]);#if 0 /* plumbing fails---FIXME */ if((qabc_data[8] & 0xf0) == 0) { /* FIXME: 32 way 8 CPU slot monster cannot be * plumbed this way---need to check for it */ printk("Plumbing second Extended Quad Processor\n"); /* second VIC line hardwired to Quad CPU 1 */ qabc_data[8] |= 0x20; cat_subwrite(*modpp, qabc_asic, 8, 1, &qabc_data[8]);#ifdef VOYAGER_CAT_DEBUG /* verify plumbing */ cat_subread(*modpp, qabc_asic, 8, 1, &qabc_data[8]); if((qabc_data[8] & 0xf0) == 0) { CDEBUG(("PLUMBING FAILED: 0x%x\n", qabc_data[8])); }#endif }#endif { struct resource *res = kzalloc(sizeof(struct resource),GFP_KERNEL); res->name = kmalloc(128, GFP_KERNEL); sprintf((char *)res->name, "Voyager %s Quad CPI", cat_module_name(i)); res->start = qic_addr; res->end = qic_addr + 0x3ff; request_resource(&iomem_resource, res); } qic_addr = (unsigned long)ioremap(qic_addr, 0x400); for(j = 0; j < 4; j++) { __u8 cpu; if(voyager_8slot) { /* 8 slot has a different mapping, * each slot has only one vic line, so * 1 cpu in each slot must be < 8 */ cpu = (i & 0x07) + j*8; } else { cpu = (i & 0x03) + j*4; } if( (qabc_data[8] & (1<<j))) { voyager_extended_vic_processors |= (1<<cpu); } if(qabc_data[8] & (1<<(j+4)) ) { /* Second SET register plumbed: Quad * card has two VIC connected CPUs. * Secondary cannot be booted as a VIC * CPU */ voyager_extended_vic_processors |= (1<<cpu); voyager_allowed_boot_processors &= (~(1<<cpu)); } voyager_quad_processors |= (1<<cpu); voyager_quad_cpi_addr[cpu] = (struct voyager_qic_cpi *) (qic_addr+(j<<8)); CDEBUG(("CPU%d: CPI address 0x%lx\n", cpu, (unsigned long)voyager_quad_cpi_addr[cpu])); } outb(VOYAGER_CAT_END, CAT_CMD); *asicpp = NULL; modpp = &((*modpp)->next); } *modpp = NULL; printk("CAT Bus Initialisation finished: extended procs 0x%x, quad procs 0x%x, allowed vic boot = 0x%x\n", voyager_extended_vic_processors, voyager_quad_processors, voyager_allowed_boot_processors); request_resource(&ioport_resource, &vic_res); if(voyager_quad_processors) request_resource(&ioport_resource, &qic_res); /* set up the front power switch */}intvoyager_cat_readb(__u8 module, __u8 asic, int reg){ return 0;}static intcat_disconnect(voyager_module_t *modp, voyager_asic_t *asicp) { __u8 val; int err = 0; if(!modp->scan_path_connected) return 0; if(asicp->asic_id != VOYAGER_CAT_ID) { CDEBUG(("cat_disconnect: ASIC is not CAT\n")); return 1; } err = cat_read(modp, asicp, VOYAGER_SCANPATH, &val); if(err) { CDEBUG(("cat_disconnect: failed to read SCANPATH\n")); return err; } val &= VOYAGER_DISCONNECT_ASIC; err = cat_write(modp, asicp, VOYAGER_SCANPATH, val); if(err) { CDEBUG(("cat_disconnect: failed to write SCANPATH\n")); return err; } outb(VOYAGER_CAT_END, CAT_CMD); outb(VOYAGER_CAT_RUN, CAT_CMD); modp->scan_path_connected = 0; return 0;}static intcat_connect(voyager_module_t *modp, voyager_asic_t *asicp) { __u8 val; int err = 0; if(modp->scan_path_connected) return 0; if(asicp->asic_id != VOYAGER_CAT_ID) { CDEBUG(("cat_connect: ASIC is not CAT\n")); return 1; } err = cat_read(modp, asicp, VOYAGER_SCANPATH, &val); if(err) { CDEBUG(("cat_connect: failed to read SCANPATH\n")); return err; } val |= VOYAGER_CONNECT_ASIC; err = cat_write(modp, asicp, VOYAGER_SCANPATH, val); if(err) { CDEBUG(("cat_connect: failed to write SCANPATH\n")); return err; } outb(VOYAGER_CAT_END, CAT_CMD); outb(VOYAGER_CAT_RUN, CAT_CMD); modp->scan_path_connected = 1; return 0;}voidvoyager_cat_power_off(void){ /* Power the machine off by writing to the PSI over the CAT * bus */ __u8 data; voyager_module_t psi = { 0 }; voyager_asic_t psi_asic = { 0 }; psi.asic = &psi_asic; psi.asic->asic_id = VOYAGER_CAT_ID; psi.asic->subaddr = VOYAGER_SUBADDR_HI; psi.module_addr = VOYAGER_PSI; psi.scan_path_connected = 0; outb(VOYAGER_CAT_END, CAT_CMD); /* Connect the PSI to the CAT Bus */ outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT); outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT); outb(VOYAGER_CAT_RUN, CAT_CMD); cat_disconnect(&psi, &psi_asic); /* Read the status */ cat_subread(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data); outb(VOYAGER_CAT_END, CAT_CMD); CDEBUG(("PSI STATUS 0x%x\n", data)); /* These two writes are power off prep and perform */ data = PSI_CLEAR; outb(VOYAGER_CAT_RUN, CAT_CMD); cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data); outb(VOYAGER_CAT_END, CAT_CMD); data = PSI_POWER_DOWN; outb(VOYAGER_CAT_RUN, CAT_CMD); cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data); outb(VOYAGER_CAT_END, CAT_CMD);}struct voyager_status voyager_status = { 0 };voidvoyager_cat_psi(__u8 cmd, __u16 reg, __u8 *data){ voyager_module_t psi = { 0 }; voyager_asic_t psi_asic = { 0 }; psi.asic = &psi_asic; psi.asic->asic_id = VOYAGER_CAT_ID; psi.asic->subaddr = VOYAGER_SUBADDR_HI; psi.module_addr = VOYAGER_PSI; psi.scan_path_connected = 0; outb(VOYAGER_CAT_END, CAT_CMD); /* Connect the PSI to the CAT Bus */ outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT); outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT); outb(VOYAGER_CAT_RUN, CAT_CMD); cat_disconnect(&psi, &psi_asic); switch(cmd) { case VOYAGER_PSI_READ: cat_read(&psi, &psi_asic, reg, data); break; case VOYAGER_PSI_WRITE: cat_write(&psi, &psi_asic, reg, *data); break; case VOYAGER_PSI_SUBREAD: cat_subread(&psi, &psi_asic, reg, 1, data); break; case VOYAGER_PSI_SUBWRITE: cat_subwrite(&psi, &psi_asic, reg, 1, data); break; default: printk(KERN_ERR "Voyager PSI, unrecognised command %d\n", cmd); break; } outb(VOYAGER_CAT_END, CAT_CMD);}voidvoyager_cat_do_common_interrupt(void){ /* This is caused either by a memory parity error or something * in the PSI */ __u8 data; voyager_module_t psi = { 0 }; voyager_asic_t psi_asic = { 0 }; struct voyager_psi psi_reg; int i; re_read: psi.asic = &psi_asic; psi.asic->asic_id = VOYAGER_CAT_ID; psi.asic->subaddr = VOYAGER_SUBADDR_HI; psi.module_addr = VOYAGER_PSI; psi.scan_path_connected = 0; outb(VOYAGER_CAT_END, CAT_CMD); /* Connect the PSI to the CAT Bus */ outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT); outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT); outb(VOYAGER_CAT_RUN, CAT_CMD); cat_disconnect(&psi, &psi_asic); /* Read the status. NOTE: Need to read *all* the PSI regs here * otherwise the cmn int will be reasserted */ for(i = 0; i < sizeof(psi_reg.regs); i++) { cat_read(&psi, &psi_asic, i, &((__u8 *)&psi_reg.regs)[i]); } outb(VOYAGER_CAT_END, CAT_CMD); if((psi_reg.regs.checkbit & 0x02) == 0) { psi_reg.regs.checkbit |= 0x02; cat_write(&psi, &psi_asic, 5, psi_reg.regs.checkbit); printk("VOYAGER RE-READ PSI\n"); goto re_read; } outb(VOYAGER_CAT_RUN, CAT_CMD); for(i = 0; i < sizeof(psi_reg.subregs); i++) { /* This looks strange, but the PSI doesn't do auto increment * correctly */ cat_subread(&psi, &psi_asic, VOYAGER_PSI_SUPPLY_REG + i, 1, &((__u8 *)&psi_reg.subregs)[i]); } outb(VOYAGER_CAT_END, CAT_CMD);#ifdef VOYAGER_CAT_DEBUG printk("VOYAGER PSI: "); for(i=0; i<sizeof(psi_reg.regs); i++) printk("%02x ", ((__u8 *)&psi_reg.regs)[i]); printk("\n "); for(i=0; i<sizeof(psi_reg.subregs); i++) printk("%02x ", ((__u8 *)&psi_reg.subregs)[i]); printk("\n");#endif if(psi_reg.regs.intstatus & PSI_MON) { /* switch off or power fail */ if(psi_reg.subregs.supply & PSI_SWITCH_OFF) { if(voyager_status.switch_off) { printk(KERN_ERR "Voyager front panel switch turned off again---Immediate power off!\n"); voyager_cat_power_off(); /* not reached */ } else { printk(KERN_ERR "Voyager front panel switch turned off\n"); voyager_status.switch_off = 1; voyager_status.request_from_kernel = 1; wake_up_process(voyager_thread); } /* Tell the hardware we're taking care of the * shutdown, otherwise it will power the box off * within 3 seconds of the switch being pressed and, * which is much more important to us, continue to * assert the common interrupt */ data = PSI_CLR_SWITCH_OFF; outb(VOYAGER_CAT_RUN, CAT_CMD); cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_SUPPLY_REG, 1, &data); outb(VOYAGER_CAT_END, CAT_CMD); } else { VDEBUG(("Voyager ac fail reg 0x%x\n", psi_reg.subregs.ACfail)); if((psi_reg.subregs.ACfail & AC_FAIL_STAT_CHANGE) == 0) { /* No further update */ return; }#if 0 /* Don't bother trying to find out who failed. * FIXME: This probably makes the code incorrect on * anything other than a 345x */ for(i=0; i< 5; i++) { if( psi_reg.subregs.ACfail &(1<<i)) { break; } } printk(KERN_NOTICE "AC FAIL IN SUPPLY %d\n", i);#endif /* DON'T do this: it shuts down the AC PSI outb(VOYAGER_CAT_RUN, CAT_CMD); data = PSI_MASK_MASK | i; cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_MASK, 1, &data); outb(VOYAGER_CAT_END, CAT_CMD); */ printk(KERN_ERR "Voyager AC power failure\n"); outb(VOYAGER_CAT_RUN, CAT_CMD); data = PSI_COLD_START; cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data); outb(VOYAGER_CAT_END, CAT_CMD); voyager_status.power_fail = 1; voyager_status.request_from_kernel = 1; wake_up_process(voyager_thread); } } else if(psi_reg.regs.intstatus & PSI_FAULT) { /* Major fault! */ printk(KERN_ERR "Voyager PSI Detected major fault, immediate power off!\n"); voyager_cat_power_off(); /* not reached */ } else if(psi_reg.regs.intstatus & (PSI_DC_FAIL | PSI_ALARM | PSI_CURRENT | PSI_DVM | PSI_PSCFAULT | PSI_STAT_CHG)) { /* other psi fault */ printk(KERN_WARNING "Voyager PSI status 0x%x\n", data); /* clear the PSI fault */ outb(VOYAGER_CAT_RUN, CAT_CMD); cat_write(&psi, &psi_asic, VOYAGER_PSI_STATUS_REG, 0); outb(VOYAGER_CAT_END, CAT_CMD); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -