📄 io.c
字号:
* address range. *//* ARGSUSED */extern iopaddr_thub_dmamap_addr( hub_dmamap_t dmamap, /* use these mapping resources */ paddr_t paddr, /* map for this address */ size_t byte_count) /* map this many bytes */{ devfs_handle_t vhdl; ASSERT(dmamap->hdma_flags & HUB_DMAMAP_IS_VALID); if (dmamap->hdma_flags & HUB_DMAMAP_USED) { /* If the map is FIXED, re-use is OK. */ if (!(dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) { vhdl = dmamap->hdma_xtalk_info.xd_dev;#if defined(SUPPORT_PRINTING_V_FORMAT) PRINT_WARNING("%v: hub_dmamap_addr re-uses dmamap.\n",vhdl);#else PRINT_WARNING("0x%x: hub_dmamap_addr re-uses dmamap.\n", vhdl);#endif } } else { dmamap->hdma_flags |= HUB_DMAMAP_USED; } /* There isn't actually any DMA mapping hardware on the hub. */ return(paddr);}/* * Establish a DMA mapping using the resources allocated in a previous dmamap_alloc. * Return an appropriate crosstalk address list that maps to the specified physical * address list. *//* ARGSUSED */alenlist_thub_dmamap_list(hub_dmamap_t hub_dmamap, /* use these mapping resources */ alenlist_t palenlist, /* map this area of memory */ unsigned flags){ devfs_handle_t vhdl; ASSERT(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_VALID); if (hub_dmamap->hdma_flags & HUB_DMAMAP_USED) { /* If the map is FIXED, re-use is OK. */ if (!(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) { vhdl = hub_dmamap->hdma_xtalk_info.xd_dev;#if defined(SUPPORT_PRINTING_V_FORMAT) PRINT_WARNING("%v: hub_dmamap_list re-uses dmamap\n",vhdl);#else PRINT_WARNING("0x%x: hub_dmamap_list re-uses dmamap\n", vhdl);#endif } } else { hub_dmamap->hdma_flags |= HUB_DMAMAP_USED; } /* There isn't actually any DMA mapping hardware on the hub. */ return(palenlist);}/* * Driver indicates that it has completed whatever DMA it may have started * after an earlier dmamap_addr or dmamap_list call. */voidhub_dmamap_done(hub_dmamap_t hub_dmamap) /* done with these mapping resources */{ devfs_handle_t vhdl; if (hub_dmamap->hdma_flags & HUB_DMAMAP_USED) { hub_dmamap->hdma_flags &= ~HUB_DMAMAP_USED; } else { /* If the map is FIXED, re-done is OK. */ if (!(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) { vhdl = hub_dmamap->hdma_xtalk_info.xd_dev;#if defined(SUPPORT_PRINTING_V_FORMAT) PRINT_WARNING("%v: hub_dmamap_done already done with dmamap\n",vhdl);#else PRINT_WARNING("0x%x: hub_dmamap_done already done with dmamap\n", vhdl);#endif } }}/* * Translate a single system physical address into a crosstalk address. *//* ARGSUSED */iopaddr_thub_dmatrans_addr( devfs_handle_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ paddr_t paddr, /* system physical address */ size_t byte_count, /* length */ unsigned flags) /* defined in dma.h */{ /* no translation needed */ return(paddr);}/* * Translate a list of IP27 addresses and lengths into a list of crosstalk * addresses and lengths. No actual hardware mapping takes place; the hub * has no DMA mapping registers -- crosstalk addresses map directly. *//* ARGSUSED */alenlist_thub_dmatrans_list( devfs_handle_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ alenlist_t palenlist, /* system address/length list */ unsigned flags) /* defined in dma.h */{ /* no translation needed */ return(palenlist);}/*ARGSUSED*/voidhub_dmamap_drain( hub_dmamap_t map){ /* XXX- flush caches, if cache coherency WAR is needed */}/*ARGSUSED*/voidhub_dmaaddr_drain( devfs_handle_t vhdl, paddr_t addr, size_t bytes){ /* XXX- flush caches, if cache coherency WAR is needed */}/*ARGSUSED*/voidhub_dmalist_drain( devfs_handle_t vhdl, alenlist_t list){ /* XXX- flush caches, if cache coherency WAR is needed */}/* INTERRUPT MANAGEMENT *//* ARGSUSED */static voidhub_intr_init(devfs_handle_t hubv){}/* * hub_device_desc_update * Update the passed in device descriptor with the actual the * target cpu number and interrupt priority level. * NOTE : These might be the same as the ones passed in thru * the descriptor. */static voidhub_device_desc_update(device_desc_t dev_desc, ilvl_t intr_swlevel, cpuid_t cpu){ char cpuname[40]; /* Store the interrupt priority level in the device descriptor */ device_desc_intr_swlevel_set(dev_desc, intr_swlevel); /* Convert the cpuid to the vertex handle in the hwgraph and * save it in the device descriptor. */ sprintf(cpuname,"/hw/cpunum/%ld",cpu); device_desc_intr_target_set(dev_desc, hwgraph_path_to_dev(cpuname));}int allocate_my_bit = INTRCONNECT_ANYBIT;/* * Allocate resources required for an interrupt as specified in dev_desc. * Returns a hub interrupt handle on success, or 0 on failure. */static hub_intr_tdo_hub_intr_alloc(devfs_handle_t dev, /* which crosstalk device */ device_desc_t dev_desc, /* device descriptor */ devfs_handle_t owner_dev, /* owner of this interrupt, if known */ int uncond_nothread) /* unconditionally non-threaded */{ cpuid_t cpu = (cpuid_t)0; /* cpu to receive interrupt */ int cpupicked = 0; int bit; /* interrupt vector */ /*REFERENCED*/ int intr_resflags = 0; hub_intr_t intr_hdl; cnodeid_t nodeid; /* node to receive interrupt */ /*REFERENCED*/ nasid_t nasid; /* nasid to receive interrupt */ struct xtalk_intr_s *xtalk_info; iopaddr_t xtalk_addr; /* xtalk addr on hub to set intr */ xwidget_info_t xwidget_info; /* standard crosstalk widget info handle */ char *intr_name = NULL; ilvl_t intr_swlevel; extern int default_intr_pri;#ifdef CONFIG_IA64_SGI_SN1 extern void synergy_intr_alloc(int, int);#endif /* * If caller didn't explicily specify a device descriptor, see if there's * a default descriptor associated with the device. */ if (!dev_desc) dev_desc = device_desc_default_get(dev); if (dev_desc) { intr_name = device_desc_intr_name_get(dev_desc); intr_swlevel = device_desc_intr_swlevel_get(dev_desc); if (dev_desc->flags & D_INTR_ISERR) { intr_resflags = II_ERRORINT; } else if (!uncond_nothread && !(dev_desc->flags & D_INTR_NOTHREAD)) { intr_resflags = II_THREADED; } else { /* Neither an error nor a thread. */ intr_resflags = 0; } } else { intr_swlevel = default_intr_pri; if (!uncond_nothread) intr_resflags = II_THREADED; } /* XXX - Need to determine if the interrupt should be threaded. */ /* If the cpu has not been picked already then choose a candidate * interrupt target and reserve the interrupt bit */#if defined(NEW_INTERRUPTS) if (!cpupicked) { cpu = intr_heuristic(dev,dev_desc,allocate_my_bit, intr_resflags,owner_dev, intr_name,&bit); }#endif /* At this point we SHOULD have a valid cpu */ if (cpu == CPU_NONE) {#if defined(SUPPORT_PRINTING_V_FORMAT) PRINT_WARNING("%v hub_intr_alloc could not allocate interrupt\n", owner_dev);#else PRINT_WARNING("0x%x hub_intr_alloc could not allocate interrupt\n", owner_dev);#endif return(0); } /* If the cpu has been picked already (due to the bridge data * corruption bug) then try to reserve an interrupt bit . */#if defined(NEW_INTERRUPTS) if (cpupicked) { bit = intr_reserve_level(cpu, allocate_my_bit, intr_resflags, owner_dev, intr_name); if (bit < 0) {#if defined(SUPPORT_PRINTING_V_FORMAT) PRINT_WARNING("Could not reserve an interrupt bit for cpu " " %d and dev %v\n", cpu,owner_dev);#else PRINT_WARNING("Could not reserve an interrupt bit for cpu " " %d and dev 0x%x\n", cpu, owner_dev);#endif return(0); } }#endif /* NEW_INTERRUPTS */ nodeid = cpuid_to_cnodeid(cpu); nasid = cpuid_to_nasid(cpu); xtalk_addr = HUBREG_AS_XTALKADDR(nasid, PIREG(PI_INT_PEND_MOD, cpuid_to_subnode(cpu))); /* * Allocate an interrupt handle, and fill it in. There are two * pieces to an interrupt handle: the piece needed by generic * xtalk code which is used by crosstalk device drivers, and * the piece needed by low-level IP27 hardware code. */ intr_hdl = kmem_alloc_node(sizeof(struct hub_intr_s), KM_NOSLEEP, nodeid); ASSERT_ALWAYS(intr_hdl); /* * Fill in xtalk information for generic xtalk interfaces that * operate on xtalk_intr_hdl's. */ xtalk_info = &intr_hdl->i_xtalk_info; xtalk_info->xi_dev = dev; xtalk_info->xi_vector = bit; xtalk_info->xi_addr = xtalk_addr; /* * Regardless of which CPU we ultimately interrupt, a given crosstalk * widget always handles interrupts (and PIO and DMA) through its * designated "master" crosstalk provider. */ xwidget_info = xwidget_info_get(dev); if (xwidget_info) xtalk_info->xi_target = xwidget_info_masterid_get(xwidget_info); /* Fill in low level hub information for hub_* interrupt interface */ intr_hdl->i_swlevel = intr_swlevel; intr_hdl->i_cpuid = cpu; intr_hdl->i_bit = bit; intr_hdl->i_flags = HUB_INTR_IS_ALLOCED; /* Store the actual interrupt priority level & interrupt target * cpu back in the device descriptor. */ hub_device_desc_update(dev_desc, intr_swlevel, cpu);#ifdef CONFIG_IA64_SGI_SN1 synergy_intr_alloc((int)bit, (int)cpu);#endif return(intr_hdl);}/* * Allocate resources required for an interrupt as specified in dev_desc. * Returns a hub interrupt handle on success, or 0 on failure. */hub_intr_thub_intr_alloc( devfs_handle_t dev, /* which crosstalk device */ device_desc_t dev_desc, /* device descriptor */ devfs_handle_t owner_dev) /* owner of this interrupt, if known */{ return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 0));}/* * Allocate resources required for an interrupt as specified in dev_desc. * Uncondtionally request non-threaded, regardless of what the device * descriptor might say. * Returns a hub interrupt handle on success, or 0 on failure. */hub_intr_thub_intr_alloc_nothd(devfs_handle_t dev, /* which crosstalk device */ device_desc_t dev_desc, /* device descriptor */ devfs_handle_t owner_dev) /* owner of this interrupt, if known */{ return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 1));}/* * Free resources consumed by intr_alloc. */voidhub_intr_free(hub_intr_t intr_hdl){ cpuid_t cpu = intr_hdl->i_cpuid; int bit = intr_hdl->i_bit; xtalk_intr_t xtalk_info; if (intr_hdl->i_flags & HUB_INTR_IS_CONNECTED) { /* Setting the following fields in the xtalk interrupt info * clears the interrupt target register in the xtalk user */ xtalk_info = &intr_hdl->i_xtalk_info; xtalk_info->xi_dev = NODEV; xtalk_info->xi_vector = 0; xtalk_info->xi_addr = 0; hub_intr_disconnect(intr_hdl); } if (intr_hdl->i_flags & HUB_INTR_IS_ALLOCED) kfree(intr_hdl);#if defined(NEW_INTERRUPTS) intr_unreserve_level(cpu, bit);#endif}/* * Associate resources allocated with a previous hub_intr_alloc call with the * described handler, arg, name, etc. *//*ARGSUSED*/inthub_intr_connect( hub_intr_t intr_hdl, /* xtalk intr resource handle */ intr_func_t intr_func, /* xtalk intr handler */ void *intr_arg, /* arg to intr handler */ xtalk_intr_setfunc_t setfunc, /* func to set intr hw */ void *setfunc_arg, /* arg to setfunc */ void *thread) /* intr thread to use */{ int rv; cpuid_t cpu = intr_hdl->i_cpuid; int bit = intr_hdl->i_bit;#ifdef CONFIG_IA64_SGI_SN1 extern int synergy_intr_connect(int, int);#endif ASSERT(intr_hdl->i_flags & HUB_INTR_IS_ALLOCED);#if defined(NEW_INTERRUPTS) rv = intr_connect_level(cpu, bit, intr_hdl->i_swlevel, intr_func, intr_arg, NULL); if (rv < 0) return(rv);#endif intr_hdl->i_xtalk_info.xi_setfunc = setfunc; intr_hdl->i_xtalk_info.xi_sfarg = setfunc_arg; if (setfunc) (*setfunc)((xtalk_intr_t)intr_hdl); intr_hdl->i_flags |= HUB_INTR_IS_CONNECTED;#ifdef CONFIG_IA64_SGI_SN1 return(synergy_intr_connect((int)bit, (int)cpu));#endif}/* * Disassociate handler with the specified interrupt. */voidhub_intr_disconnect(hub_intr_t intr_hdl){ /*REFERENCED*/ int rv; cpuid_t cpu = intr_hdl->i_cpuid; int bit = intr_hdl->i_bit; xtalk_intr_setfunc_t setfunc; setfunc = intr_hdl->i_xtalk_info.xi_setfunc;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -