pcibr_slot.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,843 行 · 第 1/4 页

C
1,843
字号
    int                 error = ENODEV;    pcibr_soft = pcibr_soft_get(pcibr_vhdl);    if (!pcibr_soft)	return -EINVAL;    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))	return -EINVAL;    if (pcibr_soft->bs_slot[slot].has_host) {        return -EPERM;    }        xconn_vhdl = pcibr_soft->bs_conn;    nfunc = pcibr_soft->bs_slot[slot].bss_ninfo;    pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;    for (func = 0; func < nfunc; ++func) {	pcibr_info = pcibr_infoh[func];		if (!pcibr_info)	    continue;	if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE)	    continue;	conn_vhdl = pcibr_info->f_vertex;	error_func = pciio_device_attach(conn_vhdl, drv_flags);	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEV_ATTACH, pcibr_vhdl,		    "pcibr_slot_call_device_attach: slot=%d, func=%d "		    "drv_flags=0x%x, pciio_device_attach returned %d\n",		    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, 		    drv_flags, error_func));        pcibr_info->f_att_det_error = error_func;	if (error_func)	    error_slot = error_func;        error = error_slot;    }				/* next func */#ifdef CONFIG_HOTPLUG_PCI_SGI    if (error) {	if ((error != ENODEV) && (error != EUNATCH) && (error != EPERM)) {	    pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;	    pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT;	}    } else {        pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;        pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT;    }#endif	/* CONFIG_HOTPLUG_PCI_SGI */    return error;}/* * pcibr_slot_call_device_detach *	This calls the associated driver detach routine for the PCI * 	card in this slot. */intpcibr_slot_call_device_detach(vertex_hdl_t pcibr_vhdl,			      pciio_slot_t slot,			      int          drv_flags){    pcibr_soft_t	pcibr_soft;    pcibr_info_h	pcibr_infoh;    pcibr_info_t	pcibr_info;    int			func;    vertex_hdl_t	conn_vhdl = GRAPH_VERTEX_NONE;    int			nfunc;    int                 error_func;    int                 error_slot = 0;    int                 error = ENODEV;    pcibr_soft = pcibr_soft_get(pcibr_vhdl);    if (!pcibr_soft)	return -EINVAL;    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))	return -EINVAL;    if (pcibr_soft->bs_slot[slot].has_host)        return -EPERM;    nfunc = pcibr_soft->bs_slot[slot].bss_ninfo;    pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;    for (func = 0; func < nfunc; ++func) {	pcibr_info = pcibr_infoh[func];		if (!pcibr_info)	    continue;	if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE)	    continue;	if (IS_PCIX(pcibr_soft) && pcibr_info->f_pcix_cap) {	    int max_out;	    pcibr_soft->bs_pcix_num_funcs--;	    max_out = pcibr_info->f_pcix_cap->pcix_type0_status.max_out_split;	    pcibr_soft->bs_pcix_split_tot -= max_splittrans_to_numbuf[max_out];	}	conn_vhdl = pcibr_info->f_vertex;	error_func = pciio_device_detach(conn_vhdl, drv_flags);	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEV_DETACH, pcibr_vhdl,		    "pcibr_slot_call_device_detach: slot=%d, func=%d "		    "drv_flags=0x%x, pciio_device_detach returned %d\n",		    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, 		    drv_flags, error_func));        pcibr_info->f_att_det_error = error_func;	if (error_func)	    error_slot = error_func;	error = error_slot;    }				/* next func */#ifdef CONFIG_HOTPLUG_PCI_SGI    if (error) {	if ((error != ENODEV) && (error != EUNATCH) && (error != EPERM)) {	    pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;            pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT;	}    } else {        if (conn_vhdl != GRAPH_VERTEX_NONE)             pcibr_device_unregister(conn_vhdl);        pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;        pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT;    }#endif	/* CONFIG_HOTPLUG_PCI_SGI */    return error;}/* * pcibr_slot_detach *	This is a place holder routine to keep track of all the *	slot-specific freeing that needs to be done. */intpcibr_slot_detach(vertex_hdl_t pcibr_vhdl,		  pciio_slot_t slot,		  int          drv_flags,		  char        *l1_msg,                  int         *sub_errorp){    pcibr_soft_t  pcibr_soft = pcibr_soft_get(pcibr_vhdl);    int		  error;        /* Call the device detach function */    error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags));    if (error) {        if (sub_errorp)            *sub_errorp = error;       	if (l1_msg)	    ;        return PCI_SLOT_DRV_DETACH_ERR;    }    /* Recalculate the RBARs for all the devices on the bus since we've     * just freed some up and some of the devices could use them.     */    if (IS_PCIX(pcibr_soft)) {	int tmp_slot;	pcibr_soft->bs_pcix_rbar_inuse = 0;	pcibr_soft->bs_pcix_rbar_avail = NUM_RBAR;	pcibr_soft->bs_pcix_rbar_percent_allowed = 					pcibr_pcix_rbars_calc(pcibr_soft);	for (tmp_slot = pcibr_soft->bs_min_slot;			tmp_slot < PCIBR_NUM_SLOTS(pcibr_soft); ++tmp_slot)            (void)pcibr_slot_pcix_rbar_init(pcibr_soft, tmp_slot);    }    return 0;}/* * pcibr_probe_slot_pic: read a config space word * while trapping any errors; return zero if * all went OK, or nonzero if there was an error. * The value read, if any, is passed back * through the valp parameter. */static intpcibr_probe_slot(pcibr_soft_t pcibr_soft,		 cfg_p cfg,		 unsigned *valp){    return pcibr_probe_work(pcibr_soft, (void *)cfg, 4, (void *)valp);}/* * Probe an offset within a piomap with errors disabled. * len must be 1, 2, 4, or 8.  	The probed address must be a multiple of * len. * * Returns:	0	if the offset was probed and put valid data in valp *		-1	if there was a usage error such as improper alignment *			or out of bounds offset/len combination.  In this *			case, the map was not probed *		1 	if the offset was probed but resulted in an error *			such as device not responding, bus error, etc. */intpcibr_piomap_probe(pcibr_piomap_t piomap, off_t offset, int len, void *valp){	if (offset + len > piomap->bp_mapsz) {		return -1;	}	return pcibr_probe_work(piomap->bp_soft,				piomap->bp_kvaddr + offset, len, valp);}static uint64_tpcibr_disable_mst_timeout(pcibr_soft_t pcibr_soft){    uint64_t		old_enable;    uint64_t		new_enable;    uint64_t		intr_bits;    intr_bits = PIC_ISR_PCI_MST_TIMEOUT		| PIC_ISR_PCIX_MTOUT | PIC_ISR_PCIX_SPLIT_EMSG;    old_enable = pcireg_intr_enable_get(pcibr_soft);    pcireg_intr_enable_bit_clr(pcibr_soft, intr_bits);    new_enable = pcireg_intr_enable_get(pcibr_soft);    if (old_enable == new_enable) {	return 0;		/* was already disabled */    } else {	return 1;    }}static intpcibr_enable_mst_timeout(pcibr_soft_t pcibr_soft){    uint64_t		old_enable;    uint64_t		new_enable;    uint64_t		intr_bits;        intr_bits = PIC_ISR_PCI_MST_TIMEOUT		| PIC_ISR_PCIX_MTOUT | PIC_ISR_PCIX_SPLIT_EMSG;    old_enable = pcireg_intr_enable_get(pcibr_soft);    pcireg_intr_enable_bit_set(pcibr_soft, intr_bits);    new_enable = pcireg_intr_enable_get(pcibr_soft);    if (old_enable == new_enable) {	return 0;		/* was alread enabled */    } else {	return 1;    }}/* * pcibr_probe_slot: read a config space word * while trapping any errors; return zero if * all went OK, or nonzero if there was an error. * The value read, if any, is passed back * through the valp parameter. */static intpcibr_probe_work(pcibr_soft_t pcibr_soft,		 void *addr,		 int len,		 void *valp){    int			rv, changed;    /*     * Sanity checks ...     */    if (len != 1 && len != 2 && len != 4 && len != 8) {	return -1;				/* invalid len */    }    if ((uint64_t)addr & (len-1)) {	return -1;				/* invalid alignment */    }    changed = pcibr_disable_mst_timeout(pcibr_soft);    rv = snia_badaddr_val((void *)addr, len, valp);    /* Clear the int_view register incase it was set */    pcireg_intr_reset_set(pcibr_soft, BRIDGE_IRR_MULTI_CLR);    if (changed) {	pcibr_enable_mst_timeout(pcibr_soft);    }    return (rv ? 1 : 0);	/* return 1 for snia_badaddr_val error, 0 if ok */}voidpcibr_device_info_free(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot){    pcibr_soft_t	pcibr_soft = pcibr_soft_get(pcibr_vhdl);    pcibr_info_t	pcibr_info;    pciio_function_t	func;    pcibr_soft_slot_t	slotp = &pcibr_soft->bs_slot[slot];    cfg_p               cfgw;    int			nfunc = slotp->bss_ninfo;    int                 bar;    int                 devio_index;    unsigned long	s;    unsigned            cmd_reg;    for (func = 0; func < nfunc; func++) {	pcibr_info = slotp->bss_infos[func];	if (!pcibr_info) 	    continue;        s = pcibr_lock(pcibr_soft);        /* Disable memory and I/O BARs */	cfgw = pcibr_func_config_addr(pcibr_soft, 0, slot, func, 0);	cmd_reg = do_pcibr_config_get(cfgw, PCI_CFG_COMMAND, 4);	cmd_reg &= (PCI_CMD_MEM_SPACE | PCI_CMD_IO_SPACE);	do_pcibr_config_set(cfgw, PCI_CFG_COMMAND, 4, cmd_reg);        for (bar = 0; bar < PCI_CFG_BASE_ADDRS; bar++) {            if (pcibr_info->f_window[bar].w_space == PCIIO_SPACE_NONE)                continue;            /* Free the PCI bus space */            pcibr_bus_addr_free(&pcibr_info->f_window[bar]);            /* Get index of the DevIO(x) register used to access this BAR */            devio_index = pcibr_info->f_window[bar].w_devio_index;             /* On last use, clear the DevIO(x) used to access this BAR */            if (! --pcibr_soft->bs_slot[devio_index].bss_devio.bssd_ref_cnt) {               pcibr_soft->bs_slot[devio_index].bss_devio.bssd_space =                                                       PCIIO_SPACE_NONE;                pcibr_soft->bs_slot[devio_index].bss_devio.bssd_base =                                                       PCIBR_D32_BASE_UNSET;               pcibr_soft->bs_slot[devio_index].bss_device = 0;            }        }        /* Free the Expansion ROM PCI bus space */	if(pcibr_info->f_rbase && pcibr_info->f_rsize) {            pcibr_bus_addr_free(&pcibr_info->f_rwindow);        }        pcibr_unlock(pcibr_soft, s);	slotp->bss_infos[func] = 0;	pciio_device_info_unregister(pcibr_vhdl, &pcibr_info->f_c);	pciio_device_info_free(&pcibr_info->f_c);	kfree(pcibr_info);    }    /* Reset the mapping usage counters */    slotp->bss_pmu_uctr = 0;    slotp->bss_d32_uctr = 0;    slotp->bss_d64_uctr = 0;    /* Clear the Direct translation info */    slotp->bss_d64_base = PCIBR_D64_BASE_UNSET;    slotp->bss_d64_flags = 0;    slotp->bss_d32_base = PCIBR_D32_BASE_UNSET;    slotp->bss_d32_flags = 0;}iopaddr_tpcibr_bus_addr_alloc(pcibr_soft_t pcibr_soft, pciio_win_info_t win_info_p,                     pciio_space_t space, int start, int size, int align){    pciio_win_map_t win_map_p;    struct resource *root_resource = NULL;    iopaddr_t iopaddr = 0;    switch (space) {        case PCIIO_SPACE_IO:            win_map_p = &pcibr_soft->bs_io_win_map;	    root_resource = &pcibr_soft->bs_io_win_root_resource;            break;        case PCIIO_SPACE_MEM:            win_map_p = &pcibr_soft->bs_swin_map;	    root_resource = &pcibr_soft->bs_swin_root_resource;            break;        case PCIIO_SPACE_MEM32:            win_map_p = &pcibr_soft->bs_mem_win_map;	    root_resource = &pcibr_soft->bs_mem_win_root_resource;            break;        default:            return 0;    }    iopaddr = pciio_device_win_alloc(root_resource,				  win_info_p				  ? &win_info_p->w_win_alloc				  : NULL,				  start, size, align);    return iopaddr;}voidpcibr_bus_addr_free(pciio_win_info_t win_info_p){	pciio_device_win_free(&win_info_p->w_win_alloc);}/* * given a vertex_hdl to the pcibr_vhdl, return the brick's bus number * associated with that vertex_hdl.  The true mapping happens from the * io_brick_tab[] array defined in ml/SN/iograph.c */intpcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl) {    pcibr_soft_t	pcibr_soft = pcibr_soft_get(pcibr_vhdl);    xwidgetnum_t	widget = pcibr_soft->bs_xid;    int			bricktype = pcibr_soft->bs_bricktype;    int			bus;        if ((bus = io_brick_map_widget(bricktype, widget)) <= 0) {	printk(KERN_WARNING "pcibr_widget_to_bus() bad bricktype %d\n", bricktype);	return 0;    }    /* For PIC there are 2 busses per widget and pcibr_soft->bs_busnum     * will be 0 or 1.  Add in the correct PIC bus offset.     */    bus += pcibr_soft->bs_busnum;    return bus;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?