pcibr_dvr.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 2,108 行 · 第 1/5 页
C
2,108 行
* be sufficient. */pciio_slot_tpcibr_device_slot_get(vertex_hdl_t dev_vhdl){ char devname[MAXDEVNAME]; vertex_hdl_t tdev; pciio_info_t pciio_info; pciio_slot_t slot = PCIIO_SLOT_NONE; vertex_to_name(dev_vhdl, devname, MAXDEVNAME); /* run back along the canonical path * until we find a PCI connection point. */ tdev = hwgraph_connectpt_get(dev_vhdl); while (tdev != GRAPH_VERTEX_NONE) { pciio_info = pciio_info_chk(tdev); if (pciio_info) { slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); break; } hwgraph_vertex_unref(tdev); tdev = hwgraph_connectpt_get(tdev); } hwgraph_vertex_unref(tdev); return slot;}pcibr_info_tpcibr_info_get(vertex_hdl_t vhdl){ return (pcibr_info_t) pciio_info_get(vhdl);}pcibr_info_tpcibr_device_info_new( pcibr_soft_t pcibr_soft, pciio_slot_t slot, pciio_function_t rfunc, pciio_vendor_id_t vendor, pciio_device_id_t device){ pcibr_info_t pcibr_info; pciio_function_t func; int ibit; func = (rfunc == PCIIO_FUNC_NONE) ? 0 : rfunc; /* * Create a pciio_info_s for this device. pciio_device_info_new() * will set the c_slot (which is suppose to represent the external * slot (i.e the slot number silk screened on the back of the I/O * brick)). So for PIC we need to adjust this "internal slot" num * passed into us, into its external representation. See comment * for the PCIBR_DEVICE_TO_SLOT macro for more information. */ pcibr_info = kmalloc(sizeof (*(pcibr_info)), GFP_KERNEL); if ( !pcibr_info ) { return NULL; } memset(pcibr_info, 0, sizeof (*(pcibr_info))); pciio_device_info_new(&pcibr_info->f_c, pcibr_soft->bs_vhdl, PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), rfunc, vendor, device); pcibr_info->f_dev = slot; /* Set PCI bus number */ pcibr_info->f_bus = pcibr_widget_to_bus(pcibr_soft->bs_vhdl); if (slot != PCIIO_SLOT_NONE) { /* * Currently favored mapping from PCI * slot number and INTA/B/C/D to Bridge * PCI Interrupt Bit Number: * * SLOT A B C D * 0 0 4 0 4 * 1 1 5 1 5 * 2 2 6 2 6 * 3 3 7 3 7 * 4 4 0 4 0 * 5 5 1 5 1 * 6 6 2 6 2 * 7 7 3 7 3 * * XXX- allow pcibr_hints to override default * XXX- allow ADMIN to override pcibr_hints */ for (ibit = 0; ibit < 4; ++ibit) pcibr_info->f_ibit[ibit] = (slot + 4 * ibit) & 7; /* * Record the info in the sparse func info space. */ if (func < pcibr_soft->bs_slot[slot].bss_ninfo) pcibr_soft->bs_slot[slot].bss_infos[func] = pcibr_info; } return pcibr_info;}/* * pcibr_device_unregister * This frees up any hardware resources reserved for this PCI device * and removes any PCI infrastructural information setup for it. * This is usually used at the time of shutting down of the PCI card. */intpcibr_device_unregister(vertex_hdl_t pconn_vhdl){ pciio_info_t pciio_info; vertex_hdl_t pcibr_vhdl; pciio_slot_t slot; pcibr_soft_t pcibr_soft; int count_vchan0, count_vchan1; unsigned long s; int error_call; int error = 0; pciio_info = pciio_info_get(pconn_vhdl); pcibr_vhdl = pciio_info_master_get(pciio_info); slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft = pcibr_soft_get(pcibr_vhdl); /* Clear all the hardware xtalk resources for this device */ xtalk_widgetdev_shutdown(pcibr_soft->bs_conn, slot); /* Flush all the rrbs */ pcibr_rrb_flush(pconn_vhdl); /* * If the RRB configuration for this slot has changed, set it * back to the boot-time default */ if (pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0] >= 0) { s = pcibr_lock(pcibr_soft); pcibr_soft->bs_rrb_res[slot] = pcibr_soft->bs_rrb_res[slot] + pcibr_soft->bs_rrb_valid[slot][VCHAN0] + pcibr_soft->bs_rrb_valid[slot][VCHAN1] + pcibr_soft->bs_rrb_valid[slot][VCHAN2] + pcibr_soft->bs_rrb_valid[slot][VCHAN3]; /* Free the rrbs allocated to this slot, both the normal & virtual */ do_pcibr_rrb_free_all(pcibr_soft, slot); count_vchan0 = pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0]; count_vchan1 = pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN1]; pcibr_unlock(pcibr_soft, s); pcibr_rrb_alloc(pconn_vhdl, &count_vchan0, &count_vchan1); } /* Flush the write buffers !! */ error_call = pcibr_wrb_flush(pconn_vhdl); if (error_call) error = error_call; /* Clear the information specific to the slot */ error_call = pcibr_slot_info_free(pcibr_vhdl, slot); if (error_call) error = error_call; return error; }/* * pcibr_driver_reg_callback * CDL will call this function for each device found in the PCI * registry that matches the vendor/device IDs supported by * the driver being registered. The device's connection vertex * and the driver's attach function return status enable the * slot's device status to be set. */voidpcibr_driver_reg_callback(vertex_hdl_t pconn_vhdl, int key1, int key2, int error){ pciio_info_t pciio_info; pcibr_info_t pcibr_info; vertex_hdl_t pcibr_vhdl; pciio_slot_t slot; pcibr_soft_t pcibr_soft; /* Do not set slot status for vendor/device ID wildcard drivers */ if ((key1 == -1) || (key2 == -1)) return; pciio_info = pciio_info_get(pconn_vhdl); pcibr_info = pcibr_info_get(pconn_vhdl); pcibr_vhdl = pciio_info_master_get(pciio_info); slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft = pcibr_soft_get(pcibr_vhdl); pcibr_info->f_att_det_error = error;#ifdef CONFIG_HOTPLUG_PCI_SGI pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; if (error) { pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT; } else { pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT; }#endif /* CONFIG_HOTPLUG_PCI_SGI */}/* * pcibr_driver_unreg_callback * CDL will call this function for each device found in the PCI * registry that matches the vendor/device IDs supported by * the driver being unregistered. The device's connection vertex * and the driver's detach function return status enable the * slot's device status to be set. */voidpcibr_driver_unreg_callback(vertex_hdl_t pconn_vhdl, int key1, int key2, int error){ pciio_info_t pciio_info; pcibr_info_t pcibr_info; vertex_hdl_t pcibr_vhdl; pciio_slot_t slot; pcibr_soft_t pcibr_soft; /* Do not set slot status for vendor/device ID wildcard drivers */ if ((key1 == -1) || (key2 == -1)) return; pciio_info = pciio_info_get(pconn_vhdl); pcibr_info = pcibr_info_get(pconn_vhdl); pcibr_vhdl = pciio_info_master_get(pciio_info); slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft = pcibr_soft_get(pcibr_vhdl); pcibr_info->f_att_det_error = error;#ifdef CONFIG_HOTPLUG_PCI_SGI pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; if (error) { pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT; } else { pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT; }#endif /* CONFIG_HOTPLUG_PCI_SGI */}/* * pcibr_detach: * Detach the bridge device from the hwgraph after cleaning out all the * underlying vertices. */intpcibr_detach(vertex_hdl_t xconn){ pciio_slot_t slot; vertex_hdl_t pcibr_vhdl; pcibr_soft_t pcibr_soft; unsigned long s; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DETACH, xconn, "pcibr_detach\n")); /* 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); /* Disable the interrupts from the bridge */ s = pcibr_lock(pcibr_soft); pcireg_intr_enable_set(pcibr_soft, 0); pcibr_unlock(pcibr_soft, s); /* Detach all the PCI devices talking to this bridge */ for (slot = pcibr_soft->bs_min_slot; slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { pcibr_slot_detach(pcibr_vhdl, slot, 0, (char *)NULL, (int *)NULL); } /* Unregister the no-slot connection point */ pciio_device_info_unregister(pcibr_vhdl, &(pcibr_soft->bs_noslot_info->f_c)); kfree(pcibr_soft->bs_name); /* 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. */ kfree(pcibr_soft); /* Remove the Bridge revision labelled info */ (void)hwgraph_info_remove_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, NULL); return 0;}/* * 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. */voidpcibr_directmap_init(pcibr_soft_t pcibr_soft){ paddr_t paddr; iopaddr_t xbase; uint64_t diroff; cnodeid_t cnodeid = 0; /* We need api for diroff api */ nasid_t nasid; nasid = cnodeid_to_nasid(cnodeid); paddr = NODE_OFFSET(nasid) + 0; /* 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(pcibr_soft->bs_conn, 0, paddr, PAGE_SIZE, 0); diroff = xbase >> BRIDGE_DIRMAP_OFF_ADDRSHFT; pcireg_dirmap_diroff_set(pcibr_soft, diroff); pcireg_dirmap_wid_set(pcibr_soft, pcibr_soft->bs_mxid); pcibr_soft->bs_dir_xport = pcibr_soft->bs_mxid; if (xbase == (512 << 20)) { /* 512Meg */ pcireg_dirmap_add512_set(pcibr_soft); pcibr_soft->bs_dir_xbase = (512 << 20); } else { pcireg_dirmap_add512_clr(pcibr_soft); pcibr_soft->bs_dir_xbase = diroff << BRIDGE_DIRMAP_OFF_ADDRSHFT; }}intpcibr_asic_rev(vertex_hdl_t pconn_vhdl){ vertex_hdl_t pcibr_vhdl; int rc; arbitrary_info_t ainfo; if (GRAPH_SUCCESS != hwgraph_traverse(pconn_vhdl, EDGE_LBL_MASTER, &pcibr_vhdl)) return -1; rc = hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &ainfo); /* * Any hwgraph function that returns a vertex handle will implicity * increment that vertex's reference count. The caller must explicity * decrement the vertex's referece count after the last reference to * that vertex. * * Decrement reference count incremented by call to hwgraph_traverse(). * */ hwgraph_vertex_unref(pcibr_vhdl); if (rc != GRAPH_SUCCESS) return -1; return (int) ainfo;}/* ===================================================================== * PIO MANAGEMENT */static iopaddr_tpcibr_addr_pci_to_xio(vertex_hdl_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 = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); unsigned bar; /* which BASE reg on device is decoding */ iopaddr_t xio_addr = XIO_NOWHERE; iopaddr_t base = 0; iopaddr_t limit = 0; 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 maxtry, halftry; 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) */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?