⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pic.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */#include <linux/interrupt.h>#include <asm/sn/sn_cpuid.h>#include <asm/sn/iograph.h>#include <asm/sn/hcl_util.h>#include <asm/sn/pci/pciio.h>#include <asm/sn/pci/pcibr.h>#include <asm/sn/pci/pcibr_private.h>#include <asm/sn/pci/pci_defs.h>#include <asm/sn/pci/pic.h>#include <asm/sn/sn_private.h>extern struct file_operations pcibr_fops;extern pcibr_list_p	pcibr_list;static int		pic_attach2(vertex_hdl_t, void *, vertex_hdl_t, 				int, pcibr_soft_t *);extern int		isIO9(nasid_t);extern char	       *dev_to_name(vertex_hdl_t dev, char *buf, uint buflen);extern int		pcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl);extern pcibr_hints_t	pcibr_hints_get(vertex_hdl_t, int);extern unsigned		pcibr_intr_bits(pciio_info_t info,				pciio_intr_line_t lines, int nslots);extern void		pcibr_setwidint(xtalk_intr_t);extern int		pcibr_error_handler_wrapper(error_handler_arg_t, int,				ioerror_mode_t, ioerror_t *);extern void		pcibr_error_intr_handler(intr_arg_t);extern void		pcibr_directmap_init(pcibr_soft_t);extern int		pcibr_slot_info_init(vertex_hdl_t,pciio_slot_t);extern int		pcibr_slot_addr_space_init(vertex_hdl_t,pciio_slot_t);extern int		pcibr_slot_device_init(vertex_hdl_t, pciio_slot_t);extern int		pcibr_slot_pcix_rbar_init(pcibr_soft_t, pciio_slot_t);extern int		pcibr_slot_guest_info_init(vertex_hdl_t,pciio_slot_t);extern int		pcibr_slot_call_device_attach(vertex_hdl_t,				pciio_slot_t, int);extern void		pcibr_rrb_alloc_init(pcibr_soft_t, int, int, int);extern int		pcibr_pcix_rbars_calc(pcibr_soft_t);extern pcibr_info_t	pcibr_device_info_new(pcibr_soft_t, pciio_slot_t,				pciio_function_t, pciio_vendor_id_t,				pciio_device_id_t);extern int		pcibr_initial_rrb(vertex_hdl_t, pciio_slot_t, 				pciio_slot_t);extern void		xwidget_error_register(vertex_hdl_t, error_handler_f *,				error_handler_arg_t);extern void		pcibr_clearwidint(pcibr_soft_t);/* * copy xwidget_info_t from conn_v to peer_conn_v */static intpic_bus1_widget_info_dup(vertex_hdl_t conn_v, vertex_hdl_t peer_conn_v,					cnodeid_t xbow_peer, char *peer_path){	xwidget_info_t widget_info, peer_widget_info;	vertex_hdl_t peer_hubv;	hubinfo_t peer_hub_info;	/* get the peer hub's widgetid */	peer_hubv = NODEPDA(xbow_peer)->node_vertex;	peer_hub_info = NULL;	hubinfo_get(peer_hubv, &peer_hub_info);	if (peer_hub_info == NULL)		return 0;	if (hwgraph_info_get_LBL(conn_v, INFO_LBL_XWIDGET,			(arbitrary_info_t *)&widget_info) == GRAPH_SUCCESS) {		peer_widget_info = kmalloc(sizeof (*(peer_widget_info)), GFP_KERNEL);		if ( !peer_widget_info ) {			return -ENOMEM;		}		memset(peer_widget_info, 0, sizeof (*(peer_widget_info)));		peer_widget_info->w_fingerprint = widget_info_fingerprint;    		peer_widget_info->w_vertex = peer_conn_v;    		peer_widget_info->w_id = widget_info->w_id;    		peer_widget_info->w_master = peer_hubv;    		peer_widget_info->w_masterid = peer_hub_info->h_widgetid;		/* structure copy */    		peer_widget_info->w_hwid = widget_info->w_hwid;    		peer_widget_info->w_efunc = 0;    		peer_widget_info->w_einfo = 0;		peer_widget_info->w_name = kmalloc(strlen(peer_path) + 1, GFP_KERNEL);		if (!peer_widget_info->w_name) {			kfree(peer_widget_info);			return -ENOMEM;		}		strcpy(peer_widget_info->w_name, peer_path);		if (hwgraph_info_add_LBL(peer_conn_v, INFO_LBL_XWIDGET,			(arbitrary_info_t)peer_widget_info) != GRAPH_SUCCESS) {			kfree(peer_widget_info->w_name);				kfree(peer_widget_info);				return 0;		}		xwidget_info_set(peer_conn_v, peer_widget_info);		return 1;	}	printk("pic_bus1_widget_info_dup: "			"cannot get INFO_LBL_XWIDGET from 0x%lx\n", (uint64_t)conn_v);	return 0;}/* * If this PIC is attached to two Cbricks ("dual-ported") then * attach each bus to opposite Cbricks. * * If successful, return a new vertex suitable for attaching the PIC bus. * If not successful, return zero and both buses will attach to the * vertex passed into pic_attach(). */static vertex_hdl_tpic_bus1_redist(nasid_t nasid, vertex_hdl_t conn_v){	cnodeid_t cnode = nasid_to_cnodeid(nasid);	cnodeid_t xbow_peer = -1;	char pathname[256], peer_path[256], tmpbuf[256];	char *p;	int rc;	vertex_hdl_t peer_conn_v, hubv;	int pos;	slabid_t slab;	if (NODEPDA(cnode)->xbow_peer >= 0) {			/* if dual-ported */		/* create a path for this widget on the peer Cbrick */		/* pcibr widget hw/module/001c11/slab/0/Pbrick/xtalk/12 */		/* sprintf(pathname, "%v", conn_v); */		xbow_peer = nasid_to_cnodeid(NODEPDA(cnode)->xbow_peer);		pos = hwgfs_generate_path(conn_v, tmpbuf, 256);		strcpy(pathname, &tmpbuf[pos]);		p = pathname + strlen("hw/module/001c01/slab/0/");		memset(tmpbuf, 0, 16);		format_module_id(tmpbuf, geo_module((NODEPDA(xbow_peer))->geoid), MODULE_FORMAT_BRIEF);		slab = geo_slab((NODEPDA(xbow_peer))->geoid);		sprintf(peer_path, "module/%s/slab/%d/%s", tmpbuf, (int)slab, p); 				/* Look for vertex for this widget on the peer Cbrick.		 * Expect GRAPH_NOT_FOUND.		 */		rc = hwgraph_traverse(hwgraph_root, peer_path, &peer_conn_v);		if (GRAPH_SUCCESS == rc)			printk("pic_attach: found unexpected vertex: 0x%lx\n",								(uint64_t)peer_conn_v);		else if (GRAPH_NOT_FOUND != rc) {			printk("pic_attach: hwgraph_traverse unexpectedly"					" returned 0x%x\n", rc);		} else {			/* try to add the widget vertex to the peer Cbrick */			rc = hwgraph_path_add(hwgraph_root, peer_path, &peer_conn_v);			if (GRAPH_SUCCESS != rc)			    printk("pic_attach: hwgraph_path_add"						" failed with 0x%x\n", rc);			else {			    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v,					"pic_bus1_redist: added vertex %v\n", peer_conn_v)); 			    /* Now hang appropiate stuff off of the new			     * vertex.	We bail out if we cannot add something.			     * In that case, we don't remove the newly added			     * vertex but that should be safe and we don't			     * really expect the additions to fail anyway.			     */			    if (!pic_bus1_widget_info_dup(conn_v, peer_conn_v, 							  xbow_peer, peer_path))					return 0;			    hubv = cnodeid_to_vertex(xbow_peer);			    ASSERT(hubv != GRAPH_VERTEX_NONE);			    device_master_set(peer_conn_v, hubv);			    xtalk_provider_register(hubv, &hub_provider);			    xtalk_provider_startup(hubv);			    return peer_conn_v;			}		}	}	return 0;}/* * PIC has two buses under a single widget.  pic_attach() calls pic_attach2() * to attach each of those buses. */intpic_attach(vertex_hdl_t conn_v){	int		rc;	void	*bridge0, *bridge1 = (void *)0;	vertex_hdl_t	pcibr_vhdl0, pcibr_vhdl1 = (vertex_hdl_t)0;	pcibr_soft_t	bus0_soft, bus1_soft = (pcibr_soft_t)0;	vertex_hdl_t  conn_v0, conn_v1, peer_conn_v;	int		bricktype;	int		iobrick_type_get_nasid(nasid_t nasid);	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, "pic_attach()\n"));	bridge0 = pcibr_bridge_ptr_get(conn_v, 0);	bridge1 = pcibr_bridge_ptr_get(conn_v, 1);	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v,		    "pic_attach: bridge0=0x%lx, bridge1=0x%lx\n", 		    bridge0, bridge1));	conn_v0 = conn_v1 = conn_v;	/* If dual-ported then split the two PIC buses across both Cbricks */	peer_conn_v = pic_bus1_redist(NASID_GET(bridge0), conn_v);	if (peer_conn_v)		conn_v1 = peer_conn_v;	/*	 * Create the vertex for the PCI buses, 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.	 */	bricktype = iobrick_type_get_nasid(NASID_GET(bridge0));	if ( bricktype == MODULE_CGBRICK ) {		rc = hwgraph_path_add(conn_v0, EDGE_LBL_AGP_0, &pcibr_vhdl0);		ASSERT(rc == GRAPH_SUCCESS);		rc = hwgraph_path_add(conn_v1, EDGE_LBL_AGP_1, &pcibr_vhdl1);		ASSERT(rc == GRAPH_SUCCESS);	} else {		rc = hwgraph_path_add(conn_v0, EDGE_LBL_PCIX_0, &pcibr_vhdl0);		ASSERT(rc == GRAPH_SUCCESS);		rc = hwgraph_path_add(conn_v1, EDGE_LBL_PCIX_1, &pcibr_vhdl1);		ASSERT(rc == GRAPH_SUCCESS);	}	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v,		    "pic_attach: pcibr_vhdl0=0x%lx, pcibr_vhdl1=0x%lx\n",		    pcibr_vhdl0, pcibr_vhdl1));	/* register pci provider array */	pciio_provider_register(pcibr_vhdl0, &pci_pic_provider);	pciio_provider_register(pcibr_vhdl1, &pci_pic_provider);	pciio_provider_startup(pcibr_vhdl0);	pciio_provider_startup(pcibr_vhdl1);	pic_attach2(conn_v0, bridge0, pcibr_vhdl0, 0, &bus0_soft);	pic_attach2(conn_v1, bridge1, pcibr_vhdl1, 1, &bus1_soft);	{	    /* If we're dual-ported finish duplicating the peer info structure.	     * The error handler and arg are done in pic_attach2().	     */	    xwidget_info_t info0, info1;		if (conn_v0 != conn_v1) {	/* dual ported */			info0 = xwidget_info_get(conn_v0);			info1 = xwidget_info_get(conn_v1);			if (info1->w_efunc == (error_handler_f *)NULL)				info1->w_efunc = info0->w_efunc;			if (info1->w_einfo == (error_handler_arg_t)0)				info1->w_einfo = bus1_soft;		}	}	/* save a pointer to the PIC's other bus's soft struct */        bus0_soft->bs_peers_soft = bus1_soft;        bus1_soft->bs_peers_soft = bus0_soft;	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v,		    "pic_attach: bus0_soft=0x%lx, bus1_soft=0x%lx\n",		    bus0_soft, bus1_soft));	return 0;}/* * PIC has two buses under a single widget.  pic_attach() calls pic_attach2() * to attach each of those buses. */static intpic_attach2(vertex_hdl_t xconn_vhdl, void *bridge,	      vertex_hdl_t pcibr_vhdl, int busnum, pcibr_soft_t *ret_softp){    vertex_hdl_t	    ctlr_vhdl;    pcibr_soft_t	    pcibr_soft;    pcibr_info_t	    pcibr_info;    xwidget_info_t	    info;    xtalk_intr_t	    xtalk_intr;    pcibr_list_p	    self;    int			    entry, slot, ibit, i;    vertex_hdl_t	    noslot_conn;    char		    devnm[MAXDEVNAME], *s;    pcibr_hints_t	    pcibr_hints;    picreg_t		    id;    picreg_t		    int_enable;    picreg_t		    pic_ctrl_reg;    int			    iobrick_type_get_nasid(nasid_t nasid);    int			    iomoduleid_get(nasid_t nasid);    int			    irq;    int			    cpu;    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl,		"pic_attach2: bridge=0x%lx, busnum=%d\n", bridge, busnum));    ctlr_vhdl = NULL;    ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, 0,		0, 0, 0,		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,		(struct file_operations *)&pcibr_fops, (void *)pcibr_vhdl);    ASSERT(ctlr_vhdl != NULL);    id = pcireg_bridge_id_get(bridge);    hwgraph_info_add_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV,                         (arbitrary_info_t)XWIDGET_PART_REV_NUM(id));    /*     * 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;    /* allocate soft structure to hang off the vertex.  Link the new soft     * structure to the pcibr_list linked list     */    pcibr_soft = kmalloc(sizeof (*(pcibr_soft)), GFP_KERNEL);    if ( !pcibr_soft )	return -ENOMEM;    self = kmalloc(sizeof (*(self)), GFP_KERNEL);    if ( !self ) {	kfree(pcibr_soft);	return -ENOMEM;    }    memset(pcibr_soft, 0, sizeof (*(pcibr_soft)));    memset(self, 0, sizeof (*(self)));    self->bl_soft = pcibr_soft;    self->bl_vhdl = pcibr_vhdl;    self->bl_next = pcibr_list;    pcibr_list = self;    if (ret_softp)        *ret_softp = pcibr_soft;    memset(pcibr_soft, 0, sizeof *pcibr_soft);    pcibr_soft_set(pcibr_vhdl, pcibr_soft);    s = dev_to_name(pcibr_vhdl, devnm, MAXDEVNAME);    pcibr_soft->bs_name = kmalloc(strlen(s) + 1, GFP_KERNEL);    if (!pcibr_soft->bs_name)	    return -ENOMEM;    strcpy(pcibr_soft->bs_name, s);    pcibr_soft->bs_conn = xconn_vhdl;    pcibr_soft->bs_vhdl = pcibr_vhdl;    pcibr_soft->bs_base = (void *)bridge;    pcibr_soft->bs_rev_num = XWIDGET_PART_REV_NUM(id);    pcibr_soft->bs_intr_bits = (pcibr_intr_bits_f *)pcibr_intr_bits;    pcibr_soft->bsi_err_intr = 0;    pcibr_soft->bs_min_slot = 0;    pcibr_soft->bs_max_slot = 3;    pcibr_soft->bs_busnum = busnum;    pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_PIC;    pcibr_soft->bs_int_ate_size = PIC_INTERNAL_ATES;    /* Make sure this is called after setting the bs_base and bs_bridge_type */    pcibr_soft->bs_bridge_mode = (pcireg_speed_get(pcibr_soft) << 1) |                                  pcireg_mode_get(pcibr_soft);    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);    strcpy(pcibr_soft->bs_asic_name, "PIC");    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl,                "pic_attach2: pcibr_soft=0x%lx, mode=0x%x\n",                pcibr_soft, pcibr_soft->bs_bridge_mode));    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl,                "pic_attach2: %s ASIC: rev %s (code=0x%x)\n",                pcibr_soft->bs_asic_name,                (IS_PIC_PART_REV_A(pcibr_soft->bs_rev_num)) ? "A" :                (IS_PIC_PART_REV_B(pcibr_soft->bs_rev_num)) ? "B" :                (IS_PIC_PART_REV_C(pcibr_soft->bs_rev_num)) ? "C" :                "unknown", pcibr_soft->bs_rev_num));    /* PV854845: Must clear write request buffer to avoid parity errors */    for (i=0; i < PIC_WR_REQ_BUFSIZE; i++) {        ((pic_t *)bridge)->p_wr_req_lower[i] = 0;        ((pic_t *)bridge)->p_wr_req_upper[i] = 0;        ((pic_t *)bridge)->p_wr_req_parity[i] = 0;    }    pcibr_soft->bs_nasid = NASID_GET(bridge);    pcibr_soft->bs_bricktype = iobrick_type_get_nasid(pcibr_soft->bs_nasid);    if (pcibr_soft->bs_bricktype < 0)        printk(KERN_WARNING "%s: bricktype was unknown by L1 (ret val = 0x%x)\n",                pcibr_soft->bs_name, pcibr_soft->bs_bricktype);

⌨️ 快捷键说明

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