📄 pcibr.c
字号:
LOCAL iopaddr_t pcibr_addr_pci_to_xio(devfs_handle_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned);pcibr_piomap_t pcibr_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned);void pcibr_piomap_free(pcibr_piomap_t);caddr_t pcibr_piomap_addr(pcibr_piomap_t, iopaddr_t, size_t);void pcibr_piomap_done(pcibr_piomap_t);caddr_t pcibr_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned);iopaddr_t pcibr_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t);void pcibr_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t);LOCAL iopaddr_t pcibr_flags_to_d64(unsigned, pcibr_soft_t);LOCAL bridge_ate_t pcibr_flags_to_ate(unsigned);pcibr_dmamap_t pcibr_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned);void pcibr_dmamap_free(pcibr_dmamap_t);LOCAL bridge_ate_p pcibr_ate_addr(pcibr_soft_t, int);LOCAL iopaddr_t pcibr_addr_xio_to_pci(pcibr_soft_t, iopaddr_t, size_t);iopaddr_t pcibr_dmamap_addr(pcibr_dmamap_t, paddr_t, size_t);alenlist_t pcibr_dmamap_list(pcibr_dmamap_t, alenlist_t, unsigned);void pcibr_dmamap_done(pcibr_dmamap_t);cnodeid_t pcibr_get_dmatrans_node(devfs_handle_t);iopaddr_t pcibr_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned);alenlist_t pcibr_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned);void pcibr_dmamap_drain(pcibr_dmamap_t);void pcibr_dmaaddr_drain(devfs_handle_t, paddr_t, size_t);void pcibr_dmalist_drain(devfs_handle_t, alenlist_t);iopaddr_t pcibr_dmamap_pciaddr_get(pcibr_dmamap_t);static unsigned pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines);pcibr_intr_t pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t);void pcibr_intr_free(pcibr_intr_t);LOCAL void pcibr_setpciint(xtalk_intr_t);int pcibr_intr_connect(pcibr_intr_t, intr_func_t, intr_arg_t, void *);void pcibr_intr_disconnect(pcibr_intr_t);devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t);void pcibr_xintr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t);void pcibr_intr_func(intr_arg_t);LOCAL void print_bridge_errcmd(uint32_t, char *);void pcibr_error_dump(pcibr_soft_t);uint32_t pcibr_errintr_group(uint32_t);LOCAL void pcibr_pioerr_check(pcibr_soft_t);LOCAL void pcibr_error_intr_handler(intr_arg_t);LOCAL int pcibr_addr_toslot(pcibr_soft_t, iopaddr_t, pciio_space_t *, iopaddr_t *, pciio_function_t *);LOCAL void pcibr_error_cleanup(pcibr_soft_t, int);void pcibr_device_disable(pcibr_soft_t, int);LOCAL int pcibr_pioerror(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *);int pcibr_dmard_error(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *);int pcibr_dmawr_error(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *);LOCAL int pcibr_error_handler(error_handler_arg_t, int, ioerror_mode_t, ioerror_t *);int pcibr_error_devenable(devfs_handle_t, int);void pcibr_provider_startup(devfs_handle_t);void pcibr_provider_shutdown(devfs_handle_t);int pcibr_reset(devfs_handle_t);pciio_endian_t pcibr_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t);int pcibr_priority_bits_set(pcibr_soft_t, pciio_slot_t, pciio_priority_t);pciio_priority_t pcibr_priority_set(devfs_handle_t, pciio_priority_t);int pcibr_device_flags_set(devfs_handle_t, pcibr_device_flags_t);LOCAL cfg_p pcibr_config_addr(devfs_handle_t, unsigned);uint64_t pcibr_config_get(devfs_handle_t, unsigned, unsigned);LOCAL uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned);void pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t);LOCAL void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t);LOCAL pcibr_hints_t pcibr_hints_get(devfs_handle_t, int);void pcibr_hints_fix_rrbs(devfs_handle_t);void pcibr_hints_dualslot(devfs_handle_t, pciio_slot_t, pciio_slot_t);void pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *);void pcibr_set_rrb_callback(devfs_handle_t, rrb_alloc_funct_t);void pcibr_hints_handsoff(devfs_handle_t);void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, ulong);LOCAL int pcibr_slot_info_init(devfs_handle_t,pciio_slot_t);LOCAL int pcibr_slot_info_free(devfs_handle_t,pciio_slot_t);#ifdef LATERLOCAL int pcibr_slot_info_return(pcibr_soft_t, pciio_slot_t, pcibr_slot_info_resp_t);LOCAL void pcibr_slot_func_info_return(pcibr_info_h, int, pcibr_slot_func_info_resp_t);#endif /* LATER */LOCAL int pcibr_slot_addr_space_init(devfs_handle_t,pciio_slot_t);LOCAL int pcibr_slot_device_init(devfs_handle_t, pciio_slot_t);LOCAL int pcibr_slot_guest_info_init(devfs_handle_t,pciio_slot_t);LOCAL int pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t);LOCAL int pcibr_slot_call_device_attach(devfs_handle_t, pciio_slot_t, int);LOCAL int pcibr_slot_call_device_detach(devfs_handle_t, pciio_slot_t, int);LOCAL int pcibr_slot_detach(devfs_handle_t, pciio_slot_t, int);LOCAL int pcibr_is_slot_sys_critical(devfs_handle_t, pciio_slot_t);#ifdef LATERLOCAL int pcibr_slot_query(devfs_handle_t, pcibr_slot_info_req_t);#endif/* ===================================================================== * RRB management */#define LSBIT(word) ((word) &~ ((word)-1))#define PCIBR_RRB_SLOT_VIRTUAL 8LOCAL voiddo_pcibr_rrb_clear(bridge_t *bridge, int rrb){ bridgereg_t status; /* bridge_lock must be held; * this RRB must be disabled. */ /* wait until RRB has no outstanduing XIO packets. */ while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { ; /* XXX- beats on bridge. bad idea? */ } /* if the RRB has data, drain it. */ if (status & BRIDGE_RRB_VALID(rrb)) { bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); /* wait until RRB is no longer valid. */ while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { ; /* XXX- beats on bridge. bad idea? */ } }}LOCAL voiddo_pcibr_rrb_flush(bridge_t *bridge, int rrbn){ reg_p rrbp = &bridge->b_rrb_map[rrbn & 1].reg; bridgereg_t rrbv; int shft = 4 * (rrbn >> 1); unsigned ebit = BRIDGE_RRB_EN << shft; rrbv = *rrbp; if (rrbv & ebit) *rrbp = rrbv & ~ebit; do_pcibr_rrb_clear(bridge, rrbn); if (rrbv & ebit) *rrbp = rrbv;}/* * pcibr_rrb_count_valid: count how many RRBs are * marked valid for the specified PCI slot on this * bridge. * * NOTE: The "slot" parameter for all pcibr_rrb * management routines must include the "virtual" * bit; when manageing both the normal and the * virtual channel, separate calls to these * routines must be made. To denote the virtual * channel, add PCIBR_RRB_SLOT_VIRTUAL to the slot * number. * * IMPL NOTE: The obvious algorithm is to iterate * through the RRB fields, incrementing a count if * the RRB is valid and matches the slot. However, * it is much simpler to use an algorithm derived * from the "partitioned add" idea. First, XOR in a * pattern such that the fields that match this * slot come up "all ones" and all other fields * have zeros in the mismatching bits. Then AND * together the bits in the field, so we end up * with one bit turned on for each field that * matched. Now we need to count these bits. This * can be done either with a series of shift/add * instructions or by using "tmp % 15"; I expect * that the cascaded shift/add will be faster. */LOCAL intdo_pcibr_rrb_count_valid(bridge_t *bridge, pciio_slot_t slot){ bridgereg_t tmp; tmp = bridge->b_rrb_map[slot & 1].reg; tmp ^= 0x11111111 * (7 - slot / 2); tmp &= (0xCCCCCCCC & tmp) >> 2; tmp &= (0x22222222 & tmp) >> 1; tmp += tmp >> 4; tmp += tmp >> 8; tmp += tmp >> 16; return tmp & 15;}/* * do_pcibr_rrb_count_avail: count how many RRBs are * available to be allocated for the specified slot. * * IMPL NOTE: similar to the above, except we are * just counting how many fields have the valid bit * turned off. */LOCAL intdo_pcibr_rrb_count_avail(bridge_t *bridge, pciio_slot_t slot){ bridgereg_t tmp; tmp = bridge->b_rrb_map[slot & 1].reg; tmp = (0x88888888 & ~tmp) >> 3; tmp += tmp >> 4; tmp += tmp >> 8; tmp += tmp >> 16; return tmp & 15;}/* * do_pcibr_rrb_alloc: allocate some additional RRBs * for the specified slot. Returns -1 if there were * insufficient free RRBs to satisfy the request, * or 0 if the request was fulfilled. * * Note that if a request can be partially filled, * it will be, even if we return failure. * * IMPL NOTE: again we avoid iterating across all * the RRBs; instead, we form up a word containing * one bit for each free RRB, then peel the bits * off from the low end. */LOCAL intdo_pcibr_rrb_alloc(bridge_t *bridge, pciio_slot_t slot, int more){ int rv = 0; bridgereg_t reg, tmp, bit; reg = bridge->b_rrb_map[slot & 1].reg; tmp = (0x88888888 & ~reg) >> 3; while (more-- > 0) { bit = LSBIT(tmp); if (!bit) { rv = -1; break; } tmp &= ~bit; reg = ((reg & ~(bit * 15)) | (bit * (8 + slot / 2))); } bridge->b_rrb_map[slot & 1].reg = reg; return rv;}/* * do_pcibr_rrb_free: release some of the RRBs that * have been allocated for the specified * slot. Returns zero for success, or negative if * it was unable to free that many RRBs. * * IMPL NOTE: We form up a bit for each RRB * allocated to the slot, aligned with the VALID * bitfield this time; then we peel bits off one at * a time, releasing the corresponding RRB. */LOCAL intdo_pcibr_rrb_free(bridge_t *bridge, pciio_slot_t slot, int less){ int rv = 0; bridgereg_t reg, tmp, clr, bit; int i; clr = 0; reg = bridge->b_rrb_map[slot & 1].reg; /* This needs to be done otherwise the rrb's on the virtual channel * for this slot won't be freed !! */ tmp = reg & 0xbbbbbbbb; tmp ^= (0x11111111 * (7 - slot / 2)); tmp &= (0x33333333 & tmp) << 2; tmp &= (0x44444444 & tmp) << 1; while (less-- > 0) { bit = LSBIT(tmp); if (!bit) { rv = -1; break; } tmp &= ~bit; reg &= ~bit; clr |= bit; } bridge->b_rrb_map[slot & 1].reg = reg; for (i = 0; i < 8; i++) if (clr & (8 << (4 * i))) do_pcibr_rrb_clear(bridge, (2 * i) + (slot & 1)); return rv;}LOCAL voiddo_pcibr_rrb_autoalloc(pcibr_soft_t pcibr_soft, int slot, int more_rrbs){ bridge_t *bridge = pcibr_soft->bs_base; int got; for (got = 0; got < more_rrbs; ++got) { if (pcibr_soft->bs_rrb_res[slot & 7] > 0) pcibr_soft->bs_rrb_res[slot & 7]--; else if (pcibr_soft->bs_rrb_avail[slot & 1] > 0) pcibr_soft->bs_rrb_avail[slot & 1]--; else break; if (do_pcibr_rrb_alloc(bridge, slot, 1) < 0) break;#if PCIBR_RRB_DEBUG printk( "do_pcibr_rrb_autoalloc: add one to slot %d%s\n", slot & 7, slot & 8 ? "v" : "");#endif pcibr_soft->bs_rrb_valid[slot]++; }#if PCIBR_RRB_DEBUG printk("%s: %d+%d free RRBs. Allocation list:\n", pcibr_soft->bs_name, pcibr_soft->bs_rrb_avail[0], pcibr_soft->bs_rrb_avail[1]); for (slot = 0; slot < 8; ++slot) printk("\t%d+%d+%d", 0xFFF & pcibr_soft->bs_rrb_valid[slot], 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], pcibr_soft->bs_rrb_res[slot]); printk("\n");#endif}/* * Device driver interface to flush the write buffers for a specified * device hanging off the bridge. */intpcibr_wrb_flush(devfs_handle_t pconn_vhdl){ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); bridge_t *bridge = pcibr_soft->bs_base; volatile bridgereg_t *wrb_flush; wrb_flush = &(bridge->b_wr_req_buf[pciio_slot].reg); while (*wrb_flush); return(0);}/* * Device driver interface to request RRBs for a specified device * hanging off a Bridge. The driver requests the total number of * RRBs it would like for the normal channel (vchan0) and for the * "virtual channel" (vchan1). The actual number allocated to each * channel is returned. * * If we cannot allocate at least one RRB to a channel that needs * at least one, return -1 (failure). Otherwise, satisfy the request * as best we can and return 0. */intpcibr_rrb_alloc(devfs_handle_t pconn_vhdl, int *count_vchan0, int *count_vchan1){ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); bridge_t *bridge = pcibr_soft->bs_base; int desired_vchan0; int desired_vchan1; int orig_vchan0; int orig_vchan1; int delta_vchan0; int delta_vchan1; int final_vchan0; int final_vchan1; int avail_rrbs; unsigned long s; int error; /* * TBD: temper request with admin info about RRB allocation, * and according to demand from other devices on this Bridge. * * One way of doing this would be to allocate two RRBs * for each device on the bus, before any drivers start * asking for extras. This has the weakness that one * driver might not give back an "extra" RRB until after * another driver has already failed to get one that * it wanted. */ s = pcibr_lock(pcibr_soft); /* How many RRBs do we own? */ orig_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot]; orig_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL]; /* How many RRBs do we want? */ desired_vchan0 = count_vchan0 ? *count_vchan0 : orig_vchan0; desired_vchan1 = count_vchan1 ? *count_vchan1 : orig_vchan1; /* How many RRBs are free? */ avail_rrbs = pcibr_soft->bs_rrb_avail[pciio_slot & 1] + pcibr_soft->bs_rrb_res[pciio_slot]; /* Figure desired deltas */ delta_vchan0 = desired_vchan0 - orig_vchan0; delta_vchan1 = desired_vchan1 - orig_vchan1; /* Trim back deltas to something
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -