📄 pcibr_dvr.c
字号:
* 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, dev_desc, 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, (xtalk_intr_setfunc_t)pcibr_setwidint, (void *)bridge); /* * now we can start handling error interrupts; * enable all of them. * NOTE: some PCI ints may already be enabled. */ b_int_enable = bridge->b_int_enable | BRIDGE_ISR_ERRORS; bridge->b_int_enable = b_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; pciio_provider_register(pcibr_vhdl, &pcibr_provider); pciio_provider_startup(pcibr_vhdl); pci_io_fb = 0x00000004; /* I/O FreeBlock Base */ pci_io_fl = 0xFFFFFFFF; /* I/O FreeBlock Last */ pci_lo_fb = 0x00000010; /* Low Memory FreeBlock Base */ pci_lo_fl = 0x001FFFFF; /* Low Memory FreeBlock Last */ pci_hi_fb = 0x00200000; /* High Memory FreeBlock Base */ pci_hi_fl = 0x3FFFFFFF; /* High Memory FreeBlock Last */ PCI_ADDR_SPACE_LIMITS_STORE(); /* 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. */ pcibr_soft->bs_noslot_conn = noslot_conn; pcibr_soft->bs_noslot_info = pcibr_info;#if PCI_FBBE fast_back_to_back_enable = 1;#endif#if PCI_FBBE if (fast_back_to_back_enable) { /* * All devices on the bus are capable of fast back to back, so * we need to set the fast back to back bit in all devices on * the bus that are capable of doing such accesses. */ }#endif#ifdef LATER /* If the bridge has been reset then there is no need to reset * the individual PCI slots. */ for (slot = 0; slot < 8; ++slot) /* Reset all the slots */ (void)pcibr_slot_reset(pcibr_vhdl, slot);#endif for (slot = 0; slot < 8; ++slot) /* Find out what is out there */ (void)pcibr_slot_info_init(pcibr_vhdl,slot); for (slot = 0; slot < 8; ++slot) /* Set up the address space for this slot in the pci land */ (void)pcibr_slot_addr_space_init(pcibr_vhdl,slot); for (slot = 0; slot < 8; ++slot) /* Setup the device register */ (void)pcibr_slot_device_init(pcibr_vhdl, slot); for (slot = 0; slot < 8; ++slot) /* Setup host/guest relations */ (void)pcibr_slot_guest_info_init(pcibr_vhdl,slot); for (slot = 0; slot < 8; ++slot) /* Initial RRB management */ (void)pcibr_slot_initial_rrb_alloc(pcibr_vhdl,slot); /* driver attach routines should be called out from generic linux code */ for (slot = 0; slot < 8; ++slot) /* Call the device attach */ (void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0); /* * Each Pbrick PCI bus only has slots 1 and 2. Similarly for * widget 0xe on Ibricks. Allocate RRB's accordingly. */ if (pcibr_soft->bs_moduleid > 0) { switch (MODULE_GET_BTCHAR(pcibr_soft->bs_moduleid)) { case 'p': /* Pbrick */ do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); break; case 'i': /* Ibrick */ /* port 0xe on the Ibrick only has slots 1 and 2 */ if (pcibr_soft->bs_xid == 0xe) { do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); } else { /* allocate one RRB for the serial port */ do_pcibr_rrb_autoalloc(pcibr_soft, 0, 1); } break; } /* switch */ }#ifdef LATER if (strstr(nicinfo, XTALK_PCI_PART_NUM)) { do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8);#if PCIBR_RRB_DEBUG printf("\n\nFound XTALK_PCI (030-1275) at %v\n", xconn_vhdl); printf("pcibr_attach: %v Shoebox RRB MANAGEMENT: %d+%d free\n", pcibr_vhdl, pcibr_soft->bs_rrb_avail[0], pcibr_soft->bs_rrb_avail[1]); for (slot = 0; slot < 8; ++slot) printf("\t%d+%d+%d", 0xFFF & pcibr_soft->bs_rrb_valid[slot], 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], pcibr_soft->bs_rrb_res[slot]); printf("\n");#endif }#else FIXME("pcibr_attach: Call do_pcibr_rrb_autoalloc nicinfo\n");#endif if (aa) async_attach_add_info(noslot_conn, aa); pciio_device_attach(noslot_conn, 0); /* * Tear down pointer to async attach info -- async threads for * bridge's descendants may be running but the bridge's work is done. */ if (aa) async_attach_del_info(xconn_vhdl); return 0;}/* * pcibr_detach: * Detach the bridge device from the hwgraph after cleaning out all the * underlying vertices. */intpcibr_detach(devfs_handle_t xconn){ pciio_slot_t slot; devfs_handle_t pcibr_vhdl; pcibr_soft_t pcibr_soft; bridge_t *bridge; /* Get the bridge vertex from its xtalk connection point */ if (hwgraph_traverse(xconn, EDGE_LBL_PCI, &pcibr_vhdl) != GRAPH_SUCCESS) return(1); pcibr_soft = pcibr_soft_get(pcibr_vhdl); bridge = pcibr_soft->bs_base; /* Disable the interrupts from the bridge */ bridge->b_int_enable = 0; /* Detach all the PCI devices talking to this bridge */ for(slot = 0; slot < 8; slot++) {#ifdef DEBUG printk("pcibr_device_detach called for %p/%d\n", pcibr_vhdl,slot);#endif pcibr_slot_detach(pcibr_vhdl, slot, 0); } /* Unregister the no-slot connection point */ pciio_device_info_unregister(pcibr_vhdl, &(pcibr_soft->bs_noslot_info->f_c)); spin_lock_destroy(&pcibr_soft->bs_lock); kfree(pcibr_soft->bs_name); /* Error handler gets unregistered when the widget info is * cleaned */ /* Free the soft ATE maps */ if (pcibr_soft->bs_int_ate_map) rmfreemap(pcibr_soft->bs_int_ate_map); if (pcibr_soft->bs_ext_ate_map) rmfreemap(pcibr_soft->bs_ext_ate_map); /* Disconnect the error interrupt and free the xtalk resources * associated with it. */ xtalk_intr_disconnect(pcibr_soft->bsi_err_intr); xtalk_intr_free(pcibr_soft->bsi_err_intr); /* Clear the software state maintained by the bridge driver for this * bridge. */ DEL(pcibr_soft); /* Remove the Bridge revision labelled info */ (void)hwgraph_info_remove_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, NULL); /* Remove the character device associated with this bridge */ (void)hwgraph_edge_remove(pcibr_vhdl, EDGE_LBL_CONTROLLER, NULL); /* Remove the PCI bridge vertex */ (void)hwgraph_edge_remove(xconn, EDGE_LBL_PCI, NULL); return(0);}intpcibr_asic_rev(devfs_handle_t pconn_vhdl){ devfs_handle_t pcibr_vhdl; arbitrary_info_t ainfo; if (GRAPH_SUCCESS != hwgraph_traverse(pconn_vhdl, EDGE_LBL_MASTER, &pcibr_vhdl)) return -1; if (GRAPH_SUCCESS != hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &ainfo)) return -1; return (int) ainfo;}intpcibr_write_gather_flush(devfs_handle_t pconn_vhdl){ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); pciio_slot_t slot; slot = pciio_info_slot_get(pciio_info); pcibr_device_write_gather_flush(pcibr_soft, slot); return 0;}/* ===================================================================== * PIO MANAGEMENT */static iopaddr_tpcibr_addr_pci_to_xio(devfs_handle_t pconn_vhdl, pciio_slot_t slot, pciio_space_t space, iopaddr_t pci_addr, size_t req_size, unsigned flags){ pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); pciio_info_t pciio_info = &pcibr_info->f_c; pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); bridge_t *bridge = pcibr_soft->bs_base; unsigned bar; /* which BASE reg on device is decoding */ iopaddr_t xio_addr = XIO_NOWHERE; pciio_space_t wspace; /* which space device is decoding */ iopaddr_t wbase; /* base of device decode on PCI */ size_t wsize; /* size of device decode on PCI */ int try; /* DevIO(x) window scanning order control */ int win; /* which DevIO(x) window is being used */ pciio_space_t mspace; /* target space for devio(x) register */ iopaddr_t mbase; /* base of devio(x) mapped area on PCI */ size_t msize; /* size of devio(x) mapped area on PCI */ size_t mmask; /* addr bits stored in Device(x) */ unsigned long s; s = pcibr_lock(pcibr_soft); if (pcibr_soft->bs_slot[slot].has_host) { slot = pcibr_soft->bs_slot[slot].host_slot; pcibr_info = pcibr_soft->bs_slot[slot].bss_infos[0]; } if (space == PCIIO_SPACE_NONE) goto done; if (space == PCIIO_SPACE_CFG) { /* * Usually, the first mapping * established to a PCI device * is to its config space. * * In any case, we definitely * do NOT need to worry about * PCI BASE registers, and * MUST NOT attempt to point * the DevIO(x) window at * this access ... */ if (((flags & PCIIO_BYTE_STREAM) == 0) && ((pci_addr + req_size) <= BRIDGE_TYPE0_CFG_FUNC_OFF)) xio_addr = pci_addr + BRIDGE_TYPE0_CFG_DEV(slot); goto done; } if (space == PCIIO_SPACE_ROM) { /* PIO to the Expansion Rom. * Driver is responsible for * enabling and disabling * decodes properly. */ wbase = pcibr_info->f_rbase; wsize = pcibr_info->f_rsize; /* * While the driver should know better * than to attempt to map more space * than the device is decoding, he might * do it; better to bail out here. */ if ((pci_addr + req_size) > wsize) goto done; pci_addr += wbase; space = PCIIO_SPACE_MEM; } /* * reduce window mappings to raw * space mappings (maybe allocating * windows), and try for DevIO(x) * usage (setting it if it is available). */ bar = space - PCIIO_SPACE_WIN0; if (bar < 6) { wspace = pcibr_info->f_window[bar].w_space; if (wspace == PCIIO_SPACE_NONE) goto done; /* get PCI base and size */ wbase = pcibr_info->f_window[bar].w_base; wsize = pcibr_info->f_window[bar].w_size; /* * While the driver should know better * than to attempt to map more space * than the device is decoding, he might * do it; better to bail out here. */ if ((pci_addr + req_size) > wsize) goto done; /* shift from window relative to * decoded space relative. */ pci_addr += wbase; space = wspace; } else bar = -1; /* Scan all the DevIO(x) windows twice looking for one * that can satisfy our request. The first time through, * only look at assigned windows; the second time, also * look at PCIIO_SPACE_NON
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -