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 + -
显示快捷键?