📄 pcibr_dvr.c
字号:
cnodeid = 0; vertex_to_name(pcibr_vhdl, vname, sizeof(vname)); printk(KERN_WARNING "Invalid hwgraph node path specified:\n" " DEVICE_ADMIN: %s %s=%s\n", vname, ADMIN_LBL_DMATRANS_NODE, node_val); } }#endif /* PIC_LATER */ nasid = COMPACT_TO_NASID_NODEID(cnodeid); paddr = NODE_OFFSET(nasid) + 0; /* currently, we just assume that if we ask * for a DMA mapping to "zero" the XIO * host will transmute this into a request * for the lowest hunk of memory. */ xbase = xtalk_dmatrans_addr(xconn_vhdl, 0, paddr, _PAGESZ, 0); if (xbase != XIO_NOWHERE) { if (XIO_PACKED(xbase)) { xport = XIO_PORT(xbase); xbase = XIO_ADDR(xbase); } else xport = pcibr_soft->bs_mxid; offset = xbase & ((1ull << BRIDGE_DIRMAP_OFF_ADDRSHFT) - 1ull); xbase >>= BRIDGE_DIRMAP_OFF_ADDRSHFT; dirmap = xport << BRIDGE_DIRMAP_W_ID_SHFT; if (xbase) dirmap |= BRIDGE_DIRMAP_OFF & xbase; else if (offset >= (512 << 20)) dirmap |= BRIDGE_DIRMAP_ADD512; bridge->b_dir_map = dirmap; } /* * Set bridge's idea of page size according to the system's * idea of "IO page size". TBD: The idea of IO page size * should really go away. */ /* * ensure that we write and read without any interruption. * The read following the write is required for the Bridge war */ spl_level = splhi();#if IOPGSIZE == 4096 if (IS_PIC_SOFT(pcibr_soft)) { bridge->p_wid_control_64 &= ~BRIDGE_CTRL_PAGE_SIZE; } else { bridge->b_wid_control &= ~BRIDGE_CTRL_PAGE_SIZE; }#elif IOPGSIZE == 16384 if (IS_PIC_SOFT(pcibr_soft)) { bridge->p_wid_control_64 |= BRIDGE_CTRL_PAGE_SIZE; } else { bridge->b_wid_control |= BRIDGE_CTRL_PAGE_SIZE; }#else <<<Unable to deal with IOPGSIZE >>>;#endif bridge->b_wid_control; /* inval addr bug war */ splx(spl_level); /* Initialize internal mapping entries */ for (entry = 0; entry < pcibr_soft->bs_int_ate_size; entry++) { bridge->b_int_ate_ram[entry].wr = 0; } /* * Determine if there's external mapping SSRAM on this * bridge. Set up Bridge control register appropriately, * inititlize SSRAM, and set software up to manage RAM * entries as an allocatable resource. * * Currently, we just use the rm* routines to manage ATE * allocation. We should probably replace this with a * Best Fit allocator. * * For now, if we have external SSRAM, avoid using * the internal ssram: we can't turn PREFETCH on * when we use the internal SSRAM; and besides, * this also guarantees that no allocation will * straddle the internal/external line, so we * can increment ATE write addresses rather than * recomparing against BRIDGE_INTERNAL_ATES every * time. */ if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) num_entries = 0; else num_entries = pcibr_init_ext_ate_ram(bridge); /* we always have 128 ATEs (512 for Xbridge) inside the chip * even if disabled for debugging. */ pcibr_soft->bs_int_ate_map = rmallocmap(pcibr_soft->bs_int_ate_size); pcibr_ate_free(pcibr_soft, 0, pcibr_soft->bs_int_ate_size); if (num_entries > pcibr_soft->bs_int_ate_size) {#if PCIBR_ATE_NOTBOTH /* for debug -- forces us to use external ates */ printk("pcibr_attach: disabling internal ATEs.\n"); pcibr_ate_alloc(pcibr_soft, pcibr_soft->bs_int_ate_size);#endif pcibr_soft->bs_ext_ate_map = rmallocmap(num_entries); pcibr_ate_free(pcibr_soft, pcibr_soft->bs_int_ate_size, num_entries - pcibr_soft->bs_int_ate_size); } PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, pcibr_vhdl, "pcibr_attach2: %d ATEs, %d internal & %d external\n", num_entries ? num_entries : pcibr_soft->bs_int_ate_size, pcibr_soft->bs_int_ate_size, num_entries ? num_entries-pcibr_soft->bs_int_ate_size : 0)); } { bridgereg_t dirmap; iopaddr_t xbase; /* * now figure the *real* xtalk base address * that dirmap sends us to. */ dirmap = bridge->b_dir_map; if (dirmap & BRIDGE_DIRMAP_OFF) xbase = (iopaddr_t)(dirmap & BRIDGE_DIRMAP_OFF) << BRIDGE_DIRMAP_OFF_ADDRSHFT; else if (dirmap & BRIDGE_DIRMAP_ADD512) xbase = 512 << 20; else xbase = 0; pcibr_soft->bs_dir_xbase = xbase; /* it is entirely possible that we may, at this * point, have our dirmap pointing somewhere * other than our "master" port. */ pcibr_soft->bs_dir_xport = (dirmap & BRIDGE_DIRMAP_W_ID) >> BRIDGE_DIRMAP_W_ID_SHFT; } /* pcibr sources an error interrupt; * figure out where to send it. * * If any interrupts are enabled in bridge, * then the prom set us up and our interrupt * has already been reconnected in mlreset * above. * * Need to set the D_INTR_ISERR flag * in the dev_desc used for allocating the * error interrupt, so our interrupt will * be properly routed and prioritized. * * If our crosstalk provider wants to * fix widget error interrupts to specific * destinations, D_INTR_ISERR is how it * knows to do this. */ xtalk_intr = xtalk_intr_alloc(xconn_vhdl, (device_desc_t)0, pcibr_vhdl); ASSERT(xtalk_intr != NULL); pcibr_soft->bsi_err_intr = xtalk_intr; /* * On IP35 with XBridge, we do some extra checks in pcibr_setwidint * in order to work around some addressing limitations. In order * for that fire wall to work properly, we need to make sure we * start from a known clean state. */ pcibr_clearwidint(bridge); xtalk_intr_connect(xtalk_intr, (intr_func_t) pcibr_error_intr_handler, (intr_arg_t) pcibr_soft, (xtalk_intr_setfunc_t)pcibr_setwidint, (void *)bridge);#ifdef BUS_INT_WAR_NOT_YET request_irq(CPU_VECTOR_TO_IRQ(((hub_intr_t)xtalk_intr)->i_cpuid, ((hub_intr_t)xtalk_intr)->i_bit), (intr_func_t)pcibr_error_intr_handler, 0, "PCIBR error", (intr_arg_t) pcibr_soft);#endif PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_vhdl, "pcibr_setwidint: b_wid_int_upper=0x%x, b_wid_int_lower=0x%x\n", bridge->b_wid_int_upper, bridge->b_wid_int_lower)); /* * now we can start handling error interrupts; * enable all of them. * NOTE: some PCI ints may already be enabled. */ /* We read the INT_ENABLE register as a 64bit picreg_t for PIC and a * 32bit bridgereg_t for BRIDGE, but always process the result as a * 64bit value so the code can be "common" for both PIC and BRIDGE... */ if (IS_PIC_SOFT(pcibr_soft)) { int_enable_64 = bridge->p_int_enable_64 | BRIDGE_ISR_ERRORS; int_enable = (uint64_t)int_enable_64; } else { int_enable_32 = bridge->b_int_enable | (BRIDGE_ISR_ERRORS & 0xffffffff); int_enable = ((uint64_t)int_enable_32 & 0xffffffff); }#ifdef BUS_INT_WAR_NOT_YET { extern void sn_add_polled_interrupt(int irq, int interval); sn_add_polled_interrupt(CPU_VECTOR_TO_IRQ(((hub_intr_t)xtalk_intr)->i_cpuid, ((hub_intr_t)xtalk_intr)->i_bit), 20000); }#endif#if BRIDGE_ERROR_INTR_WAR if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_A) { /* * We commonly get master timeouts when talking to ql. * We also see RESP_XTALK_ERROR and LLP_TX_RETRY interrupts. * Insure that these are all disabled for now. */ int_enable &= ~(BRIDGE_IMR_PCI_MST_TIMEOUT | BRIDGE_ISR_RESP_XTLK_ERR | BRIDGE_ISR_LLP_TX_RETRY); } if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_C) { int_enable &= ~BRIDGE_ISR_BAD_XRESP_PKT; }#endif /* BRIDGE_ERROR_INTR_WAR */#ifdef QL_SCSI_CTRL_WAR /* for IP30 only */ /* Really a QL rev A issue, but all newer hearts have newer QLs. * Forces all IO6/MSCSI to be new. */ if (heart_rev() == HEART_REV_A) int_enable &= ~BRIDGE_IMR_PCI_MST_TIMEOUT;#endif#ifdef BRIDGE1_TIMEOUT_WAR if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_A) { /* * Turn off these interrupts. They can't be trusted in bridge 1 */ int_enable &= ~(BRIDGE_IMR_XREAD_REQ_TIMEOUT | BRIDGE_IMR_UNEXP_RESP); }#endif#ifdef BRIDGE_B_DATACORR_WAR /* WAR panic for Rev B silent data corruption. * PIOERR turned off here because there is a problem * with not re-arming it in pcibr_error_intr_handler. * We don't get LLP error interrupts if we don't * re-arm PIOERR interrupts! Just disable them here */ if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_B) { int_enable |= BRIDGE_IMR_LLP_REC_CBERR; int_enable &= ~BRIDGE_ISR_PCIBUS_PIOERR; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, "Turning on LLP_REC_CBERR for Rev B Bridge.\n")); }#endif /* PIC BRINGUP WAR (PV# 856864 & 856865): allow the tnums that are * locked out to be freed up sooner (by timing out) so that the * read tnums are never completely used up. */ if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV856864, pcibr_soft)) { int_enable &= ~PIC_ISR_PCIX_REQ_TOUT; int_enable &= ~BRIDGE_ISR_XREAD_REQ_TIMEOUT; bridge->b_wid_req_timeout = 0x750; } /* * PIC BRINGUP WAR (PV# 856866, 859504, 861476, 861478): Don't use * RRB0, RRB8, RRB1, and RRB9. Assign them to DEVICE[2|3]--VCHAN3 * so they are not used */ if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV856866, pcibr_soft)) { bridge->b_even_resp |= 0x000f000f; bridge->b_odd_resp |= 0x000f000f; } if (IS_PIC_SOFT(pcibr_soft)) { bridge->p_int_enable_64 = (picreg_t)int_enable; } else { bridge->b_int_enable = (bridgereg_t)int_enable; } bridge->b_int_mode = 0; /* do not send "clear interrupt" packets */ bridge->b_wid_tflush; /* wait until Bridge PIO complete */ /* * Depending on the rev of bridge, disable certain features. * Easiest way seems to be to force the PCIBR_NOwhatever * flag to be on for all DMA calls, which overrides any * PCIBR_whatever flag or even the setting of whatever * from the PCIIO_DMA_class flags (or even from the other * PCIBR flags, since NO overrides YES). */ pcibr_soft->bs_dma_flags = 0; /* PREFETCH: * Always completely disabled for REV.A; * at "pcibr_prefetch_enable_rev", anyone * asking for PCIIO_PREFETCH gets it. * Between these two points, you have to ask * for PCIBR_PREFETCH, which promises that * your driver knows about known Bridge WARs. */ if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_B) pcibr_soft->bs_dma_flags |= PCIBR_NOPREFETCH; else if (pcibr_soft->bs_rev_num < (BRIDGE_WIDGET_PART_NUM << 4 | pcibr_prefetch_enable_rev)) pcibr_soft->bs_dma_flags |= PCIIO_NOPREFETCH; /* WRITE_GATHER: * Disabled up to but not including the * rev number in pcibr_wg_enable_rev. There * is no "WAR range" as with prefetch. */ if (pcibr_soft->bs_rev_num < (BRIDGE_WIDGET_PART_NUM << 4 | pcibr_wg_enable_rev)) pcibr_soft->bs_dma_flags |= PCIBR_NOWRITE_GATHER; /* PIC only supports 64-bit direct mapping in PCI-X mode. Since * all PCI-X devices that initiate memory transactions must be * capable of generating 64-bit addressed, we force 64-bit DMAs. */ if (IS_PCIX(pcibr_soft)) { pcibr_soft->bs_dma_flags |= PCIIO_DMA_A64; } { pciio_win_map_t win_map_p; iopaddr_t prom_base_addr = pcibr_soft->bs_xid << 24; int prom_base_size = 0x1000000; iopaddr_t prom_base_limit = prom_base_addr + prom_base_size; /* Allocate resource maps based on bus page size; for I/O and memory * space, free all pages except those in the base area and in the * range set by the PROM. * * PROM creates BAR addresses in this format: 0x0ws00000 where w is * the widget number and s is the device register offset for the slot. */ win_map_p = &pcibr_soft->bs_io_win_map; pciio_device_win_map_new(win_map_p, PCIBR_BUS_IO_MAX + 1, PCIBR_BUS_IO_PAGE); pciio_device_win_populate(win_map_p, PCIBR_BUS_IO_BASE, prom_base_addr - PCIBR_BUS_IO_BASE); pciio_device_win_populate(win_map_p, prom_base_limit, (PCIBR_BUS_IO_MAX + 1) - prom_base_limit); win_map_p = &pcibr_soft->bs_swin_map; pciio_device_win_map_new(win_map_p, PCIBR_BUS_SWIN_MAX + 1, PCIBR_BUS_SWIN_PAGE); pciio_device_win_populate(win_map_p, PCIBR_BUS_SWIN_BASE, (PCIBR_BUS_SWIN_MAX + 1) - PCIBR_BUS_SWIN_PAGE); win_map_p = &pcibr_soft->bs_mem_win_map; pciio_device_win_map_new(win_map_p, PCIBR_BUS_MEM_MAX + 1, PCIBR_BUS_MEM_PAGE); pciio_device_win_populate(win_map_p, PCIBR_BUS_MEM_BASE, prom_base_addr - PCIBR_BUS_MEM_BASE); pciio_device_win_populate(win_map_p, prom_base_limit, (PCIBR_BUS_MEM_MAX + 1) - prom_base_limit); } /* build "no-slot" connection point */ pcibr_info = pcibr_device_info_new (pcibr_soft, PCIIO_SLOT_NONE, PCIIO_FUNC_NONE, PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); noslot_conn = pciio_device_info_register (pcibr_vhdl, &pcibr_info->f_c); /* Remember the no slot connection point info for tearing it * down during detach. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -