📄 pcibr_dvr.c
字号:
if (flags & PCIBR_BARRIER) new |= BRIDGE_DEV_BARRIER; if (flags & PCIBR_NOBARRIER) new &= ~BRIDGE_DEV_BARRIER; if (flags & PCIBR_64BIT) new |= BRIDGE_DEV_DEV_SIZE; if (flags & PCIBR_NO64BIT) new &= ~BRIDGE_DEV_DEV_SIZE; /* * PIC BRINGUP WAR (PV# 855271): * Allow setting BRIDGE_DEV_VIRTUAL_EN on PIC iff we're a 64-bit * device. The bit is only intended for 64-bit devices and, on * PIC, can cause problems for 32-bit devices. */ if (IS_PIC_SOFT(pcibr_soft) && mask == BRIDGE_DEV_D64_BITS && PCIBR_WAR_ENABLED(PV855271, pcibr_soft)) { if (flags & PCIBR_VCHAN1) { new |= BRIDGE_DEV_VIRTUAL_EN; xmask |= BRIDGE_DEV_VIRTUAL_EN; } } chg = old ^ new; /* what are we changing, */ chg &= xmask; /* of the interesting bits */ if (chg) { badd32 = slotp->bss_d32_uctr ? (BRIDGE_DEV_D32_BITS & chg) : 0; if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) { badpmu = slotp->bss_pmu_uctr ? (XBRIDGE_DEV_PMU_BITS & chg) : 0; badd64 = slotp->bss_d64_uctr ? (XBRIDGE_DEV_D64_BITS & chg) : 0; } else { badpmu = slotp->bss_pmu_uctr ? (BRIDGE_DEV_PMU_BITS & chg) : 0; badd64 = slotp->bss_d64_uctr ? (BRIDGE_DEV_D64_BITS & chg) : 0; } bad = badpmu | badd32 | badd64; if (bad) { /* some conflicts can be resolved by * forcing the bit on. this may cause * some performance degredation in * the stream(s) that want the bit off, * but the alternative is not allowing * the new stream at all. */ if ( (fix = bad & (BRIDGE_DEV_PRECISE | BRIDGE_DEV_BARRIER)) ) { bad &= ~fix; /* don't change these bits if * they are already set in "old" */ chg &= ~(fix & old); } /* some conflicts can be resolved by * forcing the bit off. this may cause * some performance degredation in * the stream(s) that want the bit on, * but the alternative is not allowing * the new stream at all. */ if ( (fix = bad & (BRIDGE_DEV_WRGA_BITS | BRIDGE_DEV_PREF)) ) { bad &= ~fix; /* don't change these bits if * we wanted to turn them on. */ chg &= ~(fix & new); } /* conflicts in other bits mean * we can not establish this DMA * channel while the other(s) are * still present. */ if (bad) { pcibr_unlock(pcibr_soft, s);#ifdef PIC_LATER PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pcibr_soft->bs_vhdl, "pcibr_try_set_device: mod blocked by %x\n", bad, device_bits));#endif return bad; } } } if (mask == BRIDGE_DEV_PMU_BITS) slotp->bss_pmu_uctr++; if (mask == BRIDGE_DEV_D32_BITS) slotp->bss_d32_uctr++; if (mask == BRIDGE_DEV_D64_BITS) slotp->bss_d64_uctr++; /* the value we want to write is the * original value, with the bits for * our selected changes flipped, and * with any disabled features turned off. */ new = old ^ chg; /* only change what we want to change */ if (slotp->bss_device == new) { pcibr_unlock(pcibr_soft, s); return 0; } if ( IS_PIC_SOFT(pcibr_soft) ) { bridge->b_device[slot].reg = new; slotp->bss_device = new; bridge->b_wid_tflush; /* wait until Bridge PIO complete */ } pcibr_unlock(pcibr_soft, s);#ifdef PIC_LATER PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pcibr_soft->bs_vhdl, "pcibr_try_set_device: Device(%d): %x\n", slot, new, device_bits));#else printk("pcibr_try_set_device: Device(%d): %x\n", slot, new);#endif return 0;}voidpcibr_release_device(pcibr_soft_t pcibr_soft, pciio_slot_t slot, bridgereg_t mask){ pcibr_soft_slot_t slotp; unsigned long s; slotp = &pcibr_soft->bs_slot[slot]; s = pcibr_lock(pcibr_soft); if (mask == BRIDGE_DEV_PMU_BITS) slotp->bss_pmu_uctr--; if (mask == BRIDGE_DEV_D32_BITS) slotp->bss_d32_uctr--; if (mask == BRIDGE_DEV_D64_BITS) slotp->bss_d64_uctr--; pcibr_unlock(pcibr_soft, s);}/* ===================================================================== * Bridge (pcibr) "Device Driver" entry points */static intpcibr_mmap(struct file * file, struct vm_area_struct * vma){ vertex_hdl_t pcibr_vhdl; pcibr_soft_t pcibr_soft; bridge_t *bridge; unsigned long phys_addr; int error = 0;#ifdef CONFIG_HWGFS_FS pcibr_vhdl = (vertex_hdl_t) file->f_dentry->d_fsdata;#else pcibr_vhdl = (vertex_hdl_t) file->private_data;#endif pcibr_soft = pcibr_soft_get(pcibr_vhdl); bridge = pcibr_soft->bs_base; phys_addr = (unsigned long)bridge & ~0xc000000000000000; /* Mask out the Uncache bits */ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_flags |= VM_NONCACHED | VM_RESERVED | VM_IO; error = io_remap_page_range(vma->vm_start, phys_addr, vma->vm_end-vma->vm_start, vma->vm_page_prot); return(error);}/* * This is the file operation table for the pcibr driver. * As each of the functions are implemented, put the * appropriate function name below. */static int pcibr_mmap(struct file * file, struct vm_area_struct * vma);struct file_operations pcibr_fops = { .owner = THIS_MODULE, .mmap = pcibr_mmap,};/* This is special case code used by grio. There are plans to make * this a bit more general in the future, but till then this should * be sufficient. */pciio_slot_tpcibr_device_slot_get(vertex_hdl_t dev_vhdl){ char devname[MAXDEVNAME]; vertex_hdl_t tdev; pciio_info_t pciio_info; pciio_slot_t slot = PCIIO_SLOT_NONE; vertex_to_name(dev_vhdl, devname, MAXDEVNAME); /* run back along the canonical path * until we find a PCI connection point. */ tdev = hwgraph_connectpt_get(dev_vhdl); while (tdev != GRAPH_VERTEX_NONE) { pciio_info = pciio_info_chk(tdev); if (pciio_info) { slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); break; } hwgraph_vertex_unref(tdev); tdev = hwgraph_connectpt_get(tdev); } hwgraph_vertex_unref(tdev); return slot;}pcibr_info_tpcibr_info_get(vertex_hdl_t vhdl){ return (pcibr_info_t) pciio_info_get(vhdl);}pcibr_info_tpcibr_device_info_new( pcibr_soft_t pcibr_soft, pciio_slot_t slot, pciio_function_t rfunc, pciio_vendor_id_t vendor, pciio_device_id_t device){ pcibr_info_t pcibr_info; pciio_function_t func; int ibit; func = (rfunc == PCIIO_FUNC_NONE) ? 0 : rfunc; /* * Create a pciio_info_s for this device. pciio_device_info_new() * will set the c_slot (which is suppose to represent the external * slot (i.e the slot number silk screened on the back of the I/O * brick)). So for PIC we need to adjust this "internal slot" num * passed into us, into its external representation. See comment * for the PCIBR_DEVICE_TO_SLOT macro for more information. */ NEW(pcibr_info); pciio_device_info_new(&pcibr_info->f_c, pcibr_soft->bs_vhdl, PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), rfunc, vendor, device); pcibr_info->f_dev = slot; /* Set PCI bus number */ pcibr_info->f_bus = pcibr_widget_to_bus(pcibr_soft->bs_vhdl); if (slot != PCIIO_SLOT_NONE) { /* * Currently favored mapping from PCI * slot number and INTA/B/C/D to Bridge * PCI Interrupt Bit Number: * * SLOT A B C D * 0 0 4 0 4 * 1 1 5 1 5 * 2 2 6 2 6 * 3 3 7 3 7 * 4 4 0 4 0 * 5 5 1 5 1 * 6 6 2 6 2 * 7 7 3 7 3 * * XXX- allow pcibr_hints to override default * XXX- allow ADMIN to override pcibr_hints */ for (ibit = 0; ibit < 4; ++ibit) pcibr_info->f_ibit[ibit] = (slot + 4 * ibit) & 7; /* * Record the info in the sparse func info space. */ if (func < pcibr_soft->bs_slot[slot].bss_ninfo) pcibr_soft->bs_slot[slot].bss_infos[func] = pcibr_info; } return pcibr_info;}/* * pcibr_device_unregister * This frees up any hardware resources reserved for this PCI device * and removes any PCI infrastructural information setup for it. * This is usually used at the time of shutting down of the PCI card. */intpcibr_device_unregister(vertex_hdl_t pconn_vhdl){ pciio_info_t pciio_info; vertex_hdl_t pcibr_vhdl; pciio_slot_t slot; pcibr_soft_t pcibr_soft; bridge_t *bridge; int count_vchan0, count_vchan1; unsigned s; int error_call; int error = 0; pciio_info = pciio_info_get(pconn_vhdl); pcibr_vhdl = pciio_info_master_get(pciio_info); slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft = pcibr_soft_get(pcibr_vhdl); bridge = pcibr_soft->bs_base; /* Clear all the hardware xtalk resources for this device */ xtalk_widgetdev_shutdown(pcibr_soft->bs_conn, slot); /* Flush all the rrbs */ pcibr_rrb_flush(pconn_vhdl); /* * If the RRB configuration for this slot has changed, set it * back to the boot-time default */ if (pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0] >= 0) { s = pcibr_lock(pcibr_soft); /* PIC NOTE: If this is a BRIDGE, VCHAN2 & VCHAN3 will be zero so * no need to conditionalize this (ie. "if (IS_PIC_SOFT())" ). */ pcibr_soft->bs_rrb_res[slot] = pcibr_soft->bs_rrb_res[slot] + pcibr_soft->bs_rrb_valid[slot][VCHAN0] + pcibr_soft->bs_rrb_valid[slot][VCHAN1] + pcibr_soft->bs_rrb_valid[slot][VCHAN2] + pcibr_soft->bs_rrb_valid[slot][VCHAN3]; /* Free the rrbs allocated to this slot, both the normal & virtual */ do_pcibr_rrb_free_all(pcibr_soft, bridge, slot); count_vchan0 = pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0]; count_vchan1 = pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN1]; pcibr_unlock(pcibr_soft, s); pcibr_rrb_alloc(pconn_vhdl, &count_vchan0, &count_vchan1); } /* Flush the write buffers !! */ error_call = pcibr_wrb_flush(pconn_vhdl); if (error_call) error = error_call; /* Clear the information specific to the slot */ error_call = pcibr_slot_info_free(pcibr_vhdl, slot); if (error_call) error = error_call; return(error); }/* * pcibr_driver_reg_callback * CDL will call this function for each device found in the PCI * registry that matches the vendor/device IDs supported by * the driver being registered. The device's connection vertex * and the driver's attach function return status enable the * slot's device status to be set. */voidpcibr_driver_reg_callback(vertex_hdl_t pconn_vhdl, int key1, int key2, int error){ pciio_info_t pciio_info; pcibr_info_t pcibr_info; vertex_hdl_t pcibr_vhdl; pciio_slot_t slot; pcibr_soft_t pcibr_soft; /* Do not set slot status for vendor/device ID wildcard drivers */ if ((key1 == -1) || (key2 == -1)) return; pciio_info = pciio_info_get(pconn_vhdl); pcibr_info = pcibr_info_get(pconn_vhdl); pcibr_vhdl = pciio_info_master_get(pciio_info); slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -