📄 xbow.c
字号:
/* $Id: xbow.c,v 1.1.1.1 2004/02/04 12:55:34 laputa Exp $ * * 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) 1992 - 1997, 2000 Silicon Graphics, Inc. * Copyright (C) 2000 by Colin Ngam */#include <linux/types.h>#include <linux/slab.h>#include <linux/sched.h>#include <asm/sn/sgi.h>#include <asm/sn/iograph.h>#include <asm/sn/invent.h>#include <asm/sn/hcl.h>#include <asm/sn/labelcl.h>#include <asm/sn/hack.h>#include <asm/sn/pci/bridge.h>#include <asm/sn/xtalk/xtalk_private.h>/* #define DEBUG 1 *//* #define XBOW_DEBUG 1 *//* * Files needed to get the device driver entry points */#include <asm/sn/xtalk/xbow.h>#include <asm/sn/xtalk/xtalk.h>#include <asm/sn/xtalk/xswitch.h>#include <asm/sn/xtalk/xwidget.h>#include <asm/sn/prio.h>#include <asm/sn/hcl_util.h>#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))#define DEL(ptr) (kfree(ptr))int xbow_devflag = D_MP;/* * This file supports the Xbow chip. Main functions: initializtion, * error handling, and GBR. *//* * each vertex corresponding to an xbow chip * has a "fastinfo" pointer pointing at one * of these things. */typedef struct xbow_soft_s *xbow_soft_t;struct xbow_soft_s { devfs_handle_t conn; /* our connection point */ devfs_handle_t vhdl; /* xbow's private vertex */ devfs_handle_t busv; /* the xswitch vertex */ xbow_t *base; /* PIO pointer to crossbow chip */ char *name; /* hwgraph name */ xbow_perf_t xbow_perfcnt[XBOW_PERF_COUNTERS]; xbow_perf_link_t xbow_perflink[MAX_XBOW_PORTS]; xbow_link_status_t xbow_link_status[MAX_XBOW_PORTS]; spinlock_t xbow_perf_lock; int link_monitor; widget_cfg_t *wpio[MAX_XBOW_PORTS]; /* cached PIO pointer */ /* Bandwidth allocation state. Bandwidth values are for the * destination port since contention happens there. * Implicit mapping from xbow ports (8..f) -> (0..7) array indices. */ spinlock_t xbow_bw_alloc_lock; /* bw allocation lock */ unsigned long long bw_hiwm[MAX_XBOW_PORTS]; /* hiwater mark values */ unsigned long long bw_cur_used[MAX_XBOW_PORTS]; /* bw used currently */};#define xbow_soft_set(v,i) hwgraph_fastinfo_set((v), (arbitrary_info_t)(i))#define xbow_soft_get(v) ((xbow_soft_t)hwgraph_fastinfo_get((v)))/* * Function Table of Contents */void xbow_mlreset(xbow_t *);void xbow_init(void);int xbow_attach(devfs_handle_t);int xbow_open(devfs_handle_t *, int, int, cred_t *);int xbow_close(devfs_handle_t, int, int, cred_t *);int xbow_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint);int xbow_unmap(devfs_handle_t, vhandl_t *);int xbow_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *);int xbow_widget_present(xbow_t *, int);static int xbow_link_alive(xbow_t *, int);devfs_handle_t xbow_widget_lookup(devfs_handle_t, int);#ifdef LATERstatic void xbow_setwidint(xtalk_intr_t);static void xbow_errintr_handler(intr_arg_t);static error_handler_f xbow_error_handler;#endifvoid xbow_intr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t);void xbow_update_perf_counters(devfs_handle_t);xbow_perf_link_t *xbow_get_perf_counters(devfs_handle_t);int xbow_enable_perf_counter(devfs_handle_t, int, int, int);xbow_link_status_t *xbow_get_llp_status(devfs_handle_t);void xbow_update_llp_status(devfs_handle_t);int xbow_disable_llp_monitor(devfs_handle_t);int xbow_enable_llp_monitor(devfs_handle_t);int xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t, unsigned long long, unsigned long long);xswitch_reset_link_f xbow_reset_link;void idbg_xbowregs(int64_t);xswitch_provider_t xbow_provider ={ xbow_reset_link,};/* * xbow_mlreset: called at mlreset time if the * platform specific code determines that there is * a crossbow in a critical path that must be * functional before the driver would normally get * the device properly set up. * * what do we need to do, that the boot prom can * not be counted on to have already done, that is * generic across all platforms using crossbows? *//*ARGSUSED */voidxbow_mlreset(xbow_t * xbow){}/* * xbow_init: called with the rest of the device * driver XXX_init routines. This platform *might* * have a Crossbow chip, or even several, but it * might have none. Register with the crosstalk * generic provider so when we encounter the chip * the right magic happens. */voidxbow_init(void){#if DEBUG && ATTACH_DEBUG printf("xbow_init\n");#endif xwidget_driver_register(XXBOW_WIDGET_PART_NUM, 0, /* XXBOW_WIDGET_MFGR_NUM, */ "xbow_", CDL_PRI_HI); /* attach before friends */ xwidget_driver_register(XBOW_WIDGET_PART_NUM, XBOW_WIDGET_MFGR_NUM, "xbow_", CDL_PRI_HI); /* attach before friends */}#ifdef XBRIDGE_REGS_SIM/* xbow_set_simulated_regs: sets xbow regs as needed * for powering through the boot */voidxbow_set_simulated_regs(xbow_t *xbow, int port){ /* * turn on link */ xbow->xb_link(port).link_status = (1<<31); /* * and give it a live widget too */ xbow->xb_link(port).link_aux_status = XB_AUX_STAT_PRESENT; /* * zero the link control reg */ xbow->xb_link(port).link_control = 0x0;}#endif /* XBRIDGE_REGS_SIM *//* * xbow_attach: the crosstalk provider has * determined that there is a crossbow widget * present, and has handed us the connection * point for that vertex. * * We not only add our own vertex, but add * some "xtalk switch" data to the switch * vertex (at the connect point's parent) if * it does not have any. *//*ARGSUSED */intxbow_attach(devfs_handle_t conn){ /*REFERENCED */ devfs_handle_t vhdl; devfs_handle_t busv; xbow_t *xbow; xbow_soft_t soft; int port; xswitch_info_t info;#ifdef LATER xtalk_intr_t intr_hdl; device_desc_t dev_desc;#endif char devnm[MAXDEVNAME], *s; xbowreg_t id; int rev; int i; int xbow_num; #if DEBUG && ATTACH_DEBUG#if defined(SUPPORT_PRINTING_V_FORMAT printk("%v: xbow_attach\n", conn);#else printk("0x%x: xbow_attach\n", conn);#endif#endif /* * Get a PIO pointer to the base of the crossbow * chip. */#ifdef XBRIDGE_REGS_SIM printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: allocating %ld bytes for xbow_s\n", sizeof(xbow_t)); xbow = (xbow_t *) kmalloc(sizeof(xbow_t), GFP_KERNEL); /* * turn on ports e and f like in a real live ibrick */ xbow_set_simulated_regs(xbow, 0xe); xbow_set_simulated_regs(xbow, 0xf);#else xbow = (xbow_t *) xtalk_piotrans_addr(conn, 0, 0, sizeof(xbow_t), 0);#endif /* XBRIDGE_REGS_SIM */ /* * Locate the "switch" vertex: it is the parent * of our connection point. */ busv = hwgraph_connectpt_get(conn);#if DEBUG && ATTACH_DEBUG printk("xbow_attach: Bus Vertex 0x%p, conn 0x%p, xbow register 0x%p wid= 0x%x\n", busv, conn, xbow, *(volatile u32 *)xbow);#endif ASSERT(busv != GRAPH_VERTEX_NONE); /* * Create our private vertex, and connect our * driver information to it. This makes it possible * for diagnostic drivers to open the crossbow * vertex for access to registers. */ /* * We need to teach xbow drivers to provide the right set of * file ops. */ vhdl = NULL; vhdl = hwgraph_register(conn, EDGE_LBL_XBOW, 0, DEVFS_FL_AUTO_DEVNUM, 0, 0, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, /* &hcl_fops */ (void *)&vhdl, NULL); if (!vhdl) { printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n", conn); } /* * Allocate the soft state structure and attach * it to the xbow's vertex */ NEW(soft); soft->conn = conn; soft->vhdl = vhdl; soft->busv = busv; soft->base = xbow; /* does the universe really need another macro? */ /* xbow_soft_set(vhdl, (arbitrary_info_t) soft); */ hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) soft);#define XBOW_NUM_SUFFIX_FORMAT "[xbow# %d]" /* Add xbow number as a suffix to the hwgraph name of the xbow. * This is helpful while looking at the error/warning messages. */ xbow_num = 0; /* * get the name of this xbow vertex and keep the info. * This is needed during errors and interrupts, but as * long as we have it, we can use it elsewhere. */ s = dev_to_name(vhdl, devnm, MAXDEVNAME); soft->name = kmalloc(strlen(s) + strlen(XBOW_NUM_SUFFIX_FORMAT) + 1, GFP_KERNEL); sprintf(soft->name,"%s"XBOW_NUM_SUFFIX_FORMAT, s,xbow_num);#ifdef XBRIDGE_REGS_SIM /* my o200/ibrick has id=0x2d002049, but XXBOW_WIDGET_PART_NUM is defined * as 0xd000, so I'm using that for the partnum bitfield. */ printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: need xb_wid_id value!!\n"); id = 0x2d000049;#else id = xbow->xb_wid_id;#endif /* XBRIDGE_REGS_SIM */ rev = XWIDGET_PART_REV_NUM(id); /* * Print the revision if DEBUG, or SHOW_REVS and kdebug, * or the xbow is downrev. * * If xbow is downrev, make it a WARNING that the * Crossbow is DOWNREV: these chips are not good * to have around, and the operator should be told. */#ifdef LATER#if !DEBUG if (#if SHOW_REVS (kdebug) ||#endif /* SHOW_REVS */ (rev < XBOW_REV_1_1))#endif /* !DEBUG */ printk("%sCrossbow ASIC: rev %s (code=%d) at %s%s", (rev < XBOW_REV_1_1) ? "DOWNREV " : "", (rev == XBOW_REV_1_0) ? "1.0" : (rev == XBOW_REV_1_1) ? "1.1" : (rev == XBOW_REV_1_2) ? "1.2" : (rev == XBOW_REV_1_3) ? "1.3" : (rev == XBOW_REV_2_0) ? "2.0" : (rev == XXBOW_PART_REV_1_0) ? "Xbridge 1.0" : (rev == XXBOW_PART_REV_2_0) ? "Xbridge 2.0" : "unknown", rev, soft->name, (rev < XBOW_REV_1_1) ? "" : "\n");#endif /* LATER */ mutex_spinlock_init(&soft->xbow_perf_lock); soft->xbow_perfcnt[0].xp_perf_reg = &xbow->xb_perf_ctr_a; soft->xbow_perfcnt[1].xp_perf_reg = &xbow->xb_perf_ctr_b; /* Initialization for GBR bw allocation */ mutex_spinlock_init(&soft->xbow_bw_alloc_lock);#define XBOW_8_BIT_PORT_BW_MAX (400 * 1000 * 1000) /* 400 MB/s */#define XBOW_16_BIT_PORT_BW_MAX (800 * 1000 * 1000) /* 800 MB/s */ /* Set bandwidth hiwatermark and current values */ for (i = 0; i < MAX_XBOW_PORTS; i++) { soft->bw_hiwm[i] = XBOW_16_BIT_PORT_BW_MAX; /* for now */ soft->bw_cur_used[i] = 0; } /* * attach the crossbow error interrupt. */#ifdef LATER dev_desc = device_desc_dup(vhdl); device_desc_flags_set(dev_desc, device_desc_flags_get(dev_desc) | D_INTR_ISERR); device_desc_intr_name_set(dev_desc, "Crossbow error"); intr_hdl = xtalk_intr_alloc(conn, dev_desc, vhdl); ASSERT(intr_hdl != NULL); xtalk_intr_connect(intr_hdl, (intr_func_t) xbow_errintr_handler, (intr_arg_t) soft, (xtalk_intr_setfunc_t) xbow_setwidint, (void *) xbow, (void *) 0); device_desc_free(dev_desc); xwidget_error_register(conn, xbow_error_handler, soft);#else FIXME("xbow_attach: Fixme: we bypassed attaching xbow error interrupt.\n");#endif /* LATER */ /* * Enable xbow error interrupts */ xbow->xb_wid_control = (XB_WID_CTRL_REG_ACC_IE | XB_WID_CTRL_XTALK_IE); /* * take a census of the widgets present, * leaving notes at the switch vertex. */ info = xswitch_info_new(busv); for (port = MAX_PORT_NUM - MAX_XBOW_PORTS; port < MAX_PORT_NUM; ++port) { if (!xbow_link_alive(xbow, port)) {#if DEBUG && XBOW_DEBUG printk(KERN_INFO "0x%p link %d is not alive\n", busv, port);#endif continue; } if (!xbow_widget_present(xbow, port)) {#if DEBUG && XBOW_DEBUG printk(KERN_INFO "0x%p link %d is alive but no widget is present\n", busv, port);#endif continue; }#if DEBUG && XBOW_DEBUG printk(KERN_INFO "0x%p link %d has a widget\n", busv, port);#endif xswitch_info_link_is_ok(info, port); /* * Turn some error interrupts on * and turn others off. The PROM has * some things turned on we don't * want to see (bandwidth allocation * errors for instance); so if it * is not listed here, it is not on. */ xbow->xb_link(port).link_control = ( (xbow->xb_link(port).link_control /* * Turn off these bits; they are non-fatal, * but we might want to save some statistics * on the frequency of these errors. * XXX FIXME XXX */ & ~XB_CTRL_RCV_CNT_OFLOW_IE & ~XB_CTRL_XMT_CNT_OFLOW_IE & ~XB_CTRL_BNDWDTH_ALLOC_IE & ~XB_CTRL_RCV_IE) /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -