📄 pciba.c
字号:
/* $Id: pciba.c,v 1.1.1.1 2004/02/04 12:55:33 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/config.h>#include <linux/slab.h>#include <linux/module.h>#include <asm/sn/sgi.h>#include <asm/sn/addrs.h>#include <asm/sn/arch.h>#include <asm/sn/iograph.h>#include <asm/sn/invent.h>#include <asm/sn/hcl.h>#include <asm/sn/labelcl.h>#include <asm/sn/xtalk/xwidget.h>#include <asm/sn/pci/bridge.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/prio.h>#include <asm/sn/ioerror_handling.h>#include <asm/sn/xtalk/xbow.h>#include <asm/sn/ioc3.h>#include <asm/sn/eeprom.h>#include <asm/sn/sn1/bedrock.h>#include <asm/sn/sn_private.h>#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)#include <asm/sn/sn1/hubio.h>#include <asm/sn/sn1/hubio_next.h>#endif#define copyin(_a, _b, _c) copy_from_user(_b, _a, _c)#ifndef DEBUG_PCIBA#define DEBUG_PCIBA 0#endif/* v_mapphys does not percolate page offset back. */#define PCIBA_ALIGN_CHECK 1#include <asm/sn/pci/pciba.h>/* grab an unused space code for "User DMA" space */#ifndef PCIBA_SPACE_UDMA#define PCIBA_SPACE_UDMA (14)#endif#if DEBUG_REFCTextern int hwgraph_vertex_refct(vertex_hdl_t);#endifextern int pci_user_dma_max_pages;#define NEW(ptr) (ptr = kmem_zalloc(sizeof (*(ptr)), KM_SLEEP))#define DEL(ptr) (kfree(ptr))/* Oops -- no standard "pci address" type! */typedef uint64_t pciaddr_t;/* ================================================================ * driver types */typedef struct pciba_slot_s *pciba_slot_t;typedef struct pciba_comm_s *pciba_comm_t;typedef struct pciba_soft_s *pciba_soft_t;typedef struct pciba_map_s *pciba_map_t, **pciba_map_h;typedef struct pciba_dma_s *pciba_dma_t, **pciba_dma_h;typedef struct pciba_bus_s *pciba_bus_t;#define TRACKED_SPACES 16struct pciba_comm_s { devfs_handle_t conn; pciba_bus_t bus; int refct; pciba_soft_t soft[TRACKED_SPACES][2]; struct semaphore lock; pciba_dma_t dmap;};/* pciba_soft: device_info() for all openables */struct pciba_soft_s { pciba_comm_t comm; devfs_handle_t vhdl; int refct; pciio_space_t space; size_t size; pciio_space_t iomem; pciaddr_t base; unsigned flags;};#define pciba_soft_get(v) (pciba_soft_t)hwgraph_fastinfo_get(v)#define pciba_soft_set(v,i) hwgraph_fastinfo_set(v,(arbitrary_info_t)(i))#define pciba_soft_lock(soft) down(&soft->comm->lock)#define pciba_soft_unlock(soft) up(&soft->comm->lock)/* pciba_map: data describing a mapping. * (ie. a user mmap request) */struct pciba_map_s { pciba_map_t next;#ifdef LATER uthread_t *uthread;#endif __psunsigned_t handle; uvaddr_t uvaddr; size_t size; pciio_piomap_t map; pciio_space_t space; pciaddr_t base; unsigned flags;};/* pciba_dma: data describing a DMA mapping. */struct pciba_dma_s { pciba_dma_t next; iopaddr_t paddr; /* starting phys addr */ caddr_t kaddr; /* starting kern addr */ pciio_dmamap_t map; /* mapping resources (ugh!) */ pciaddr_t daddr; /* starting pci addr */ size_t pages; /* size of block in pages */ size_t bytes; /* size of block in bytes */ __psunsigned_t handle; /* mapping handle */};/* pciba_bus: common bus info for all openables * descended from the same master vertex. */struct pciba_bus_s { struct semaphore lock; pciba_map_t maps; /* stack of mappings */ int refct;};#define pciba_bus_lock(bus) down(&bus->lock)#define pciba_bus_unlock(bus) up(&bus->lock)typedef union ioctl_arg_buffer_u { char data[IOCPARM_MASK + 1]; uint8_t uc; uint16_t us; uint32_t ui; uint64_t ud; caddr_t ca;#if ULI struct uliargs uli; struct uliargs32 uli32;#endif} ioctl_arg_buffer_t;/* ================================================================ * driver variables */char *pciba_mversion = "mload version 7.0";int pciba_devflag = 0x1 | 0x200 | 0x400;/* this counts the reasons why we can not * currently unload this driver. */atomic_t pciba_prevent_unload = ATOMIC_INIT(0);#if DEBUG_PCIBAstatic struct reg_values space_v[] ={ {PCIIO_SPACE_NONE, "none"}, {PCIIO_SPACE_ROM, "ROM"}, {PCIIO_SPACE_IO, "I/O"}, {PCIIO_SPACE_MEM, "MEM"}, {PCIIO_SPACE_MEM32, "MEM(32)"}, {PCIIO_SPACE_MEM64, "MEM(64)"}, {PCIIO_SPACE_CFG, "CFG"}, {PCIIO_SPACE_WIN(0), "WIN(0)"}, {PCIIO_SPACE_WIN(1), "WIN(1)"}, {PCIIO_SPACE_WIN(2), "WIN(2)"}, {PCIIO_SPACE_WIN(3), "WIN(3)"}, {PCIIO_SPACE_WIN(4), "WIN(4)"}, {PCIIO_SPACE_WIN(5), "WIN(5)"}, {PCIBA_SPACE_UDMA, "UDMA"}, {PCIIO_SPACE_BAD, "BAD"}, {0}};static struct reg_desc space_desc[] ={ {0xFF, 0, "space", 0, space_v}, {0}};#endifchar pciba_edge_lbl_base[] = "base";char pciba_edge_lbl_cfg[] = "config";char pciba_edge_lbl_dma[] = "dma";char pciba_edge_lbl_intr[] = "intr";char pciba_edge_lbl_io[] = "io";char pciba_edge_lbl_mem[] = "mem";char pciba_edge_lbl_rom[] = "rom";char *pciba_edge_lbl_win[6] ={"0", "1", "2", "3", "4", "5"};#define PCIBA_EDGE_LBL_BASE pciba_edge_lbl_base#define PCIBA_EDGE_LBL_CFG pciba_edge_lbl_cfg#define PCIBA_EDGE_LBL_DMA pciba_edge_lbl_dma#define PCIBA_EDGE_LBL_INTR pciba_edge_lbl_intr#define PCIBA_EDGE_LBL_IO pciba_edge_lbl_io#define PCIBA_EDGE_LBL_MEM pciba_edge_lbl_mem#define PCIBA_EDGE_LBL_ROM pciba_edge_lbl_rom#define PCIBA_EDGE_LBL_WIN(n) pciba_edge_lbl_win[n]#define PCIBA_EDGE_LBL_FLIP pciba_edge_lbl_flipstatic char pciba_info_lbl_bus[] = "pciba_bus";#define PCIBA_INFO_LBL_BUS pciba_info_lbl_busstruct file_operations pciba_fops = { owner: THIS_MODULE, llseek: NULL, read: NULL, write: NULL, readdir: NULL, poll: NULL, ioctl: NULL, mmap: NULL, open: NULL, flush: NULL, release: NULL, fsync: NULL, fasync: NULL, lock: NULL, readv: NULL, writev: NULL}; /* ================================================================ * function table of contents */void pciba_init(void);int pciba_attach(devfs_handle_t);static void pciba_sub_attach(pciba_comm_t, pciio_space_t, pciio_space_t, pciaddr_t, devfs_handle_t, devfs_handle_t, char *);static pciba_bus_t pciba_find_bus(devfs_handle_t, int);#ifdef LATERstatic void pciba_map_push(pciba_bus_t, pciba_map_t);static pciba_map_t pciba_map_pop_hdl(pciba_bus_t, __psunsigned_t);static void pciba_sub_detach(devfs_handle_t, char *);static pciio_iter_f pciba_unload_me;#endifint pciba_unload(void);int pciba_unreg(void);int pciba_detach(devfs_handle_t);int pciba_open(dev_t *, int, int, struct cred *);int pciba_close(dev_t);int pciba_read(dev_t, cred_t *);int pciba_write(dev_t, cred_t *);int pciba_ioctl(dev_t, int, void *, int, cred_t *, int *);int pciba_map(dev_t, vhandl_t *, off_t, size_t, uint32_t);int pciba_unmap(dev_t, vhandl_t *);#if ULIvoid pciba_clearuli(struct uli *);static intr_func_f pciba_intr;#endif /* Undef as it gets implemented *//* ================================================================ * driver load, register, and setup */voidpciba_init(void){ /* * What do we need to do here? */#if DEBUG_PCIBA printk("pciba_init()\n");#endif}#ifdef LATER#if HWG_PERF_CHECK && IP30 && !DEBUGvoidpciba_timeout(void *arg1, void *arg2){ struct semaphore *semap = (sema_t *) arg1; unsigned long *cvalp = (unsigned long *) arg2; if (cvalp) cvalp[0] = RAW_COUNT(); if (semap) up(semap);}volatile unsigned long cNval[1];struct semaphore tsema;voidpciba_timeout_test(void){ unsigned long c0val, cval; toid_t tid; extern void hwg_hprint(unsigned long, char *); sema_init(&tsema, 0); cNval[0] = 0; c0val = RAW_COUNT(); tid = timeout((void (*)()) pciba_timeout, (void *) 0, 1, (void *) cNval); DELAY(1000000); cval = cNval[0]; if (cval == 0) { untimeout(tid); PRINT_ALERT("pciba: one-tick timeout did not happen in a second\n"); return; } cval = cval - c0val; hwg_hprint(cval, "timeout(1)"); cNval[0] = 0; c0val = RAW_COUNT(); tid = timeout((void (*)()) pciba_timeout, (void *) &tsema, 2, (void *) cNval); /* FIXME : this probably needs to be down_interruptible() */ if (down(&tsema) < 0) { /* wait for the pciba_timeout */ untimeout(tid); PRINT_WARNING("pciba: timeout(2) time check aborted\n"); return; } cval = cNval[0]; if (cval == 0) { untimeout(tid); PRINT_WARNING("pciba: timeout(2) time not logged\n"); return; } cval = cval - c0val; hwg_hprint(cval, "timeout(2)"); cNval[0] = 0; c0val = RAW_COUNT(); tid = timeout((void (*)()) pciba_timeout, (void *) &tsema, HZ, (void *) cNval); /* FIXME : this probably needs to be down_interruptible() */ if (down(&tsema) < 0) { /* wait for the pciba_timeout */ untimeout(tid); PRINT_WARNING("pciba: timeout(HZ) time check aborted\n"); return; } cval = cNval[0]; if (cval == 0) { untimeout(tid); PRINT_WARNING("pciba: timeout(HZ) time not logged\n"); return; } cval = cval - c0val; hwg_hprint(cval, "timeout(HZ)"); printk("verifying untimeout() cancells ...\n"); cNval[0] = 0; tid = timeout((void (*)()) pciba_timeout, (void *) 0, 2, (void *) cNval); untimeout(tid); DELAY(1000000); cval = cNval[0]; if (cval != 0) { PRINT_ALERT("pciba: unable to cancel two-tick timeout\n"); cval -= c0val; hwg_hprint(cval, "CANCELLED timeout(2)"); }}#endifintpciba_reg(void){#if DEBUG_PCIBA printk("pciba_reg()\n");#endif pciio_driver_register(-1, -1, "pciba_", 0);#if HWG_PERF_CHECK && IP30 && !DEBUG printk("%s %d\n", __FUNCTION__, __LINE__);pciba_timeout_test();#endif#if DEBUG_REFCT { char *cname = "pciba"; char *dname = "ptv"; char *cpath0 = "node/xtalk/15"; char *uname0 = "0"; char *cpath1 = "node/xtalk/13"; char *uname1 = "1"; devfs_handle_t conn; devfs_handle_t conv; devfs_handle_t vhdl; int ret; printk("pciba refct tests:\n");#define SHOWREF(vhdl,func) printk("ref=%d\t%s\t(%d) %v\n", hwgraph_vertex_refct(vhdl), #func, vhdl, vhdl); if (GRAPH_SUCCESS != (ret = hwgraph_path_add(hwgraph_root, cname, &conv))) printk("\tunable to create conv (ret=%d)\n", ret); else { SHOWREF(conv, hwgraph_path_add); if (GRAPH_SUCCESS != (ret = hwgraph_traverse(hwgraph_root, cpath0, &conn))) printk("\tunable to find %s (ret=%d)\n", cpath0, ret); else { SHOWREF(conn, hwgraph_traverse); if (GRAPH_SUCCESS != (ret = hwgraph_char_device_add(conn, dname, "pciba_", &vhdl))) printk("unable to create %v/%s (ret=%d)\n", conn, dname, ret); else { SHOWREF(vhdl, hwgraph_char_device_add); hwgraph_chmod(vhdl, 0666); SHOWREF(vhdl, hwgraph_chmod);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -