📄 pcibr_dvr.c
字号:
/* * pcibr_attach: called every time the crosstalk * infrastructure is asked to initialize a widget * that matches the part number we handed to the * registration routine above. *//*ARGSUSED */intpcibr_attach(devfs_handle_t xconn_vhdl){ /* REFERENCED */ graph_error_t rc; devfs_handle_t pcibr_vhdl; devfs_handle_t ctlr_vhdl; bridge_t *bridge = NULL; bridgereg_t id; int rev; pcibr_soft_t pcibr_soft; pcibr_info_t pcibr_info; xwidget_info_t info; xtalk_intr_t xtalk_intr; device_desc_t dev_desc = (device_desc_t)0; int slot; int ibit; devfs_handle_t noslot_conn; char devnm[MAXDEVNAME], *s; pcibr_hints_t pcibr_hints; bridgereg_t b_int_enable; unsigned rrb_fixed = 0; iopaddr_t pci_io_fb, pci_io_fl; iopaddr_t pci_lo_fb, pci_lo_fl; iopaddr_t pci_hi_fb, pci_hi_fl; int spl_level;#ifdef LATER char *nicinfo = (char *)0;#endif#if PCI_FBBE int fast_back_to_back_enable;#endif l1sc_t *scp; nasid_t nasid; async_attach_t aa = NULL; aa = async_attach_get_info(xconn_vhdl);#if DEBUG && ATTACH_DEBUG printk("pcibr_attach: xconn_vhdl= %p\n", xconn_vhdl); { int pos; char dname[256]; pos = devfs_generate_path(xconn_vhdl, dname, 256); printk("%s : path= %s \n", __FUNCTION__, &dname[pos]); }#endif /* Setup the PRB for the bridge in CONVEYOR BELT * mode. PRBs are setup in default FIRE-AND-FORGET * mode during the initialization. */ hub_device_flags_set(xconn_vhdl, HUB_PIO_CONVEYOR); bridge = (bridge_t *) xtalk_piotrans_addr(xconn_vhdl, NULL, 0, sizeof(bridge_t), 0); /* * Create the vertex for the PCI bus, which we * will also use to hold the pcibr_soft and * which will be the "master" vertex for all the * pciio connection points we will hang off it. * This needs to happen before we call nic_bridge_vertex_info * as we are some of the *_vmc functions need access to the edges. * * Opening this vertex will provide access to * the Bridge registers themselves. */ rc = hwgraph_path_add(xconn_vhdl, EDGE_LBL_PCI, &pcibr_vhdl); ASSERT(rc == GRAPH_SUCCESS); ctlr_vhdl = NULL; ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, 0, DEVFS_FL_AUTO_DEVNUM, 0, 0, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, &pcibr_fops, NULL); ASSERT(ctlr_vhdl != NULL); /* * decode the nic, and hang its stuff off our * connection point where other drivers can get * at it. */#ifdef LATER nicinfo = BRIDGE_VERTEX_MFG_INFO(xconn_vhdl, (nic_data_t) & bridge->b_nic);#endif /* * Get the hint structure; if some NIC callback * marked this vertex as "hands-off" then we * just return here, before doing anything else. */ pcibr_hints = pcibr_hints_get(xconn_vhdl, 0); if (pcibr_hints && pcibr_hints->ph_hands_off) return -1; /* generic operations disabled */ id = bridge->b_wid_id; rev = XWIDGET_PART_REV_NUM(id); hwgraph_info_add_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, (arbitrary_info_t) rev); /* * allocate soft state structure, fill in some * fields, and hook it up to our vertex. */ NEW(pcibr_soft); BZERO(pcibr_soft, sizeof *pcibr_soft); pcibr_soft_set(pcibr_vhdl, pcibr_soft); pcibr_soft->bs_conn = xconn_vhdl; pcibr_soft->bs_vhdl = pcibr_vhdl; pcibr_soft->bs_base = bridge; pcibr_soft->bs_rev_num = rev; pcibr_soft->bs_intr_bits = pcibr_intr_bits; if (is_xbridge(bridge)) { pcibr_soft->bs_int_ate_size = XBRIDGE_INTERNAL_ATES; pcibr_soft->bs_xbridge = 1; } else { pcibr_soft->bs_int_ate_size = BRIDGE_INTERNAL_ATES; pcibr_soft->bs_xbridge = 0; } nasid = NASID_GET(bridge); scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; pcibr_soft->bs_l1sc = scp; pcibr_soft->bs_moduleid = iobrick_module_get(scp); pcibr_soft->bsi_err_intr = 0; /* Bridges up through REV C * are unable to set the direct * byteswappers to BYTE_STREAM. */ if (pcibr_soft->bs_rev_num <= BRIDGE_PART_REV_C) { pcibr_soft->bs_pio_end_io = PCIIO_WORD_VALUES; pcibr_soft->bs_pio_end_mem = PCIIO_WORD_VALUES; }#if PCIBR_SOFT_LIST { pcibr_list_p self; NEW(self); self->bl_soft = pcibr_soft; self->bl_vhdl = pcibr_vhdl; self->bl_next = pcibr_list; self->bl_next = swap_ptr((void **) &pcibr_list, (void *)self); }#endif /* * get the name of this bridge vertex and keep the info. Use this * only where it is really needed now: like error interrupts. */ s = dev_to_name(pcibr_vhdl, devnm, MAXDEVNAME); pcibr_soft->bs_name = kmalloc(strlen(s) + 1, GFP_KERNEL); strcpy(pcibr_soft->bs_name, s);#if SHOW_REVS || DEBUG#if !DEBUG if (kdebug)#endif printk("%sBridge ASIC: rev %s (code=0x%x) at %s\n", is_xbridge(bridge) ? "X" : "", (rev == BRIDGE_PART_REV_A) ? "A" : (rev == BRIDGE_PART_REV_B) ? "B" : (rev == BRIDGE_PART_REV_C) ? "C" : (rev == BRIDGE_PART_REV_D) ? "D" : (rev == XBRIDGE_PART_REV_A) ? "A" : (rev == XBRIDGE_PART_REV_B) ? "B" : "unknown", rev, pcibr_soft->bs_name);#endif info = xwidget_info_get(xconn_vhdl); pcibr_soft->bs_xid = xwidget_info_id_get(info); pcibr_soft->bs_master = xwidget_info_master_get(info); pcibr_soft->bs_mxid = xwidget_info_masterid_get(info); /* * Init bridge lock. */ spin_lock_init(&pcibr_soft->bs_lock); /* * If we have one, process the hints structure. */ if (pcibr_hints) { rrb_fixed = pcibr_hints->ph_rrb_fixed; pcibr_soft->bs_rrb_fixed = rrb_fixed; if (pcibr_hints->ph_intr_bits) pcibr_soft->bs_intr_bits = pcibr_hints->ph_intr_bits; for (slot = 0; slot < 8; ++slot) { int hslot = pcibr_hints->ph_host_slot[slot] - 1; if (hslot < 0) { pcibr_soft->bs_slot[slot].host_slot = slot; } else { pcibr_soft->bs_slot[slot].has_host = 1; pcibr_soft->bs_slot[slot].host_slot = hslot; } } } /* * set up initial values for state fields */ for (slot = 0; slot < 8; ++slot) { pcibr_soft->bs_slot[slot].bss_devio.bssd_space = PCIIO_SPACE_NONE; pcibr_soft->bs_slot[slot].bss_d64_base = PCIBR_D64_BASE_UNSET; pcibr_soft->bs_slot[slot].bss_d32_base = PCIBR_D32_BASE_UNSET; pcibr_soft->bs_slot[slot].bss_ext_ates_active = ATOMIC_INIT(0); } for (ibit = 0; ibit < 8; ++ibit) { pcibr_soft->bs_intr[ibit].bsi_xtalk_intr = 0; pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_soft = pcibr_soft; pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_list = NULL; pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_stat = &(bridge->b_int_status); pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_hdlrcnt = 0; pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_shared = 0; pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_connected = 0; } /* * Initialize various Bridge registers. */ /* * On pre-Rev.D bridges, set the PCI_RETRY_CNT * to zero to avoid dropping stores. (#475347) */ if (rev < BRIDGE_PART_REV_D) bridge->b_bus_timeout &= ~BRIDGE_BUS_PCI_RETRY_MASK; /* * Clear all pending interrupts. */ bridge->b_int_rst_stat = (BRIDGE_IRR_ALL_CLR); /* * Until otherwise set up, * assume all interrupts are * from slot 7. */ bridge->b_int_device = (uint32_t) 0xffffffff; { bridgereg_t dirmap; paddr_t paddr; iopaddr_t xbase; xwidgetnum_t xport; iopaddr_t offset; int num_entries = 0; int entry; cnodeid_t cnodeid; nasid_t nasid; /* Set the Bridge's 32-bit PCI to XTalk * Direct Map register to the most useful * value we can determine. Note that we * must use a single xid for all of: * direct-mapped 32-bit DMA accesses * direct-mapped 64-bit DMA accesses * DMA accesses through the PMU * interrupts * This is the only way to guarantee that * completion interrupts will reach a CPU * after all DMA data has reached memory. * (Of course, there may be a few special * drivers/controlers that explicitly manage * this ordering problem.) */ cnodeid = 0; /* default node id */ 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 bridge->b_wid_control &= ~BRIDGE_CTRL_PAGE_SIZE;#elif IOPGSIZE == 16384 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(bridge)) 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 PCIBR_ATE_DEBUG printk("pcibr_attach: %d INTERNAL ATEs\n", pcibr_soft->bs_int_ate_size);#endif 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);#if PCIBR_ATE_DEBUG printk("pcibr_attach: %d EXTERNAL ATEs\n", num_entries - pcibr_soft->bs_int_ate_size);#endif } } { 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -