📄 pciio.c
字号:
if (GRAPH_SUCCESS != hwgraph_path_add(connectpt, name, &pconn)) return pconn; pciio_info->c_vertex = pconn; pciio_info_set(pconn, pciio_info);#ifdef DEBUG_PCIIO { int pos; char dname[256]; pos = devfs_generate_path(pconn, dname, 256); printk("%s : pconn path= %s \n", __FUNCTION__, &dname[pos]); }#endif /* DEBUG_PCIIO */ /* * create link to our pci provider */ device_master_set(pconn, pciio_info->c_master);#if USRPCI /* * Call into usrpci provider to let it initialize for * the given slot. */ if (pciio_info->c_slot != PCIIO_SLOT_NONE) usrpci_device_register(pconn, pciio_info->c_master, pciio_info->c_slot);#endif return pconn;}voidpciio_device_info_unregister(devfs_handle_t connectpt, pciio_info_t pciio_info){ char name[32]; devfs_handle_t pconn; if (!pciio_info) return; pciio_slot_func_to_name(name, pciio_info->c_slot, pciio_info->c_func); hwgraph_edge_remove(connectpt,name,&pconn); pciio_info_set(pconn,0); /* Remove the link to our pci provider */ hwgraph_edge_remove(pconn, EDGE_LBL_MASTER, NULL); hwgraph_vertex_unref(pconn); hwgraph_vertex_destroy(pconn); }/* Add the pci card inventory information to the hwgraph */static voidpciio_device_inventory_add(devfs_handle_t pconn_vhdl){ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); ASSERT(pciio_info); ASSERT(pciio_info->c_vertex == pconn_vhdl); /* Donot add inventory for non-existent devices */ if ((pciio_info->c_vendor == PCIIO_VENDOR_ID_NONE) || (pciio_info->c_device == PCIIO_DEVICE_ID_NONE)) return; device_inventory_add(pconn_vhdl,INV_IOBD,INV_PCIADAP, pciio_info->c_vendor,pciio_info->c_device, pciio_info->c_slot);}/*ARGSUSED */intpciio_device_attach(devfs_handle_t pconn, int drv_flags){ pciio_info_t pciio_info; pciio_vendor_id_t vendor_id; pciio_device_id_t device_id; pciio_device_inventory_add(pconn); pciio_info = pciio_info_get(pconn); vendor_id = pciio_info->c_vendor; device_id = pciio_info->c_device; /* we don't start attaching things until * all the driver init routines (including * pciio_init) have been called; so we * can assume here that we have a registry. */ ASSERT(pciio_registry != NULL); return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn, drv_flags));}intpciio_device_detach(devfs_handle_t pconn, int drv_flags){ pciio_info_t pciio_info; pciio_vendor_id_t vendor_id; pciio_device_id_t device_id; pciio_info = pciio_info_get(pconn); vendor_id = pciio_info->c_vendor; device_id = pciio_info->c_device; /* we don't start attaching things until * all the driver init routines (including * pciio_init) have been called; so we * can assume here that we have a registry. */ ASSERT(pciio_registry != NULL); return(cdl_del_connpt(pciio_registry, vendor_id, device_id, pconn, drv_flags));}/* SN2 *//* * Allocate (if necessary) and initialize a PCI window mapping structure. */pciio_win_map_tpciio_device_win_map_new(pciio_win_map_t win_map, size_t region_size, size_t page_size){ ASSERT((page_size & (page_size - 1)) == 0); ASSERT((region_size & (page_size - 1)) == 0); if (win_map == NULL) NEW(win_map); /* * The map array tracks the free ``pages'' in the region. The worst * case scenario is when every other page in the region is free -- * e.i. maximum fragmentation. This leads to (max pages + 1) / 2 + 1 * map entries. The first "+1" handles the divide by 2 rounding; the * second handles the need for an end marker sentinel. */ win_map->wm_map = rmallocmap((region_size / page_size + 1) / 2 + 1); win_map->wm_page_size = page_size; ASSERT(win_map->wm_map != NULL); return win_map;}/* * Free resources associated with a PCI window mapping structure. */extern voidpciio_device_win_map_free(pciio_win_map_t win_map){ rmfreemap(win_map->wm_map); bzero(win_map, sizeof *win_map);}/* * Populate window map with specified free range. */voidpciio_device_win_populate(pciio_win_map_t win_map, iopaddr_t ioaddr, size_t size){ ASSERT((size & (win_map->wm_page_size - 1)) == 0); ASSERT((ioaddr & (win_map->wm_page_size - 1)) == 0); rmfree(win_map->wm_map, size / win_map->wm_page_size, (unsigned long)ioaddr / win_map->wm_page_size); }/* * Allocate space from the specified PCI window mapping resource. On * success record information about the allocation in the supplied window * allocation cookie (if non-NULL) and return the address of the allocated * window. On failure return NULL. * * The "size" parameter is usually from a PCI device's Base Address Register * (BAR) decoder. As such, the allocation must be aligned to be a multiple of * that. The "align" parameter acts as a ``minimum alignment'' allocation * constraint. The alignment contraint reflects system or device addressing * restrictions such as the inability to share higher level ``windows'' * between devices, etc. The returned PCI address allocation will be a * multiple of the alignment constraint both in alignment and size. Thus, the * returned PCI address block is aligned to the maximum of the requested size * and alignment. */iopaddr_tpciio_device_win_alloc(pciio_win_map_t win_map, pciio_win_alloc_t win_alloc, size_t start, size_t size, size_t align){ unsigned long base;#ifdef PIC_LATER ASSERT((size & (size - 1)) == 0); ASSERT((align & (align - 1)) == 0); /* * Convert size and alignment to pages. If size is greated than the * requested alignment, we bump the alignment up to size; otherwise * convert the size into a multiple of the alignment request. */ size = (size + win_map->wm_page_size - 1) / win_map->wm_page_size; align = align / win_map->wm_page_size; if (size > align) align = size; else size = (size + align - 1) & ~(align - 1); /* XXXX */ base = rmalloc_align(win_map->wm_map, size, align, VM_NOSLEEP); if (base == RMALLOC_FAIL) return((iopaddr_t)NULL);#else int index_page, index_page_align; int align_pages, size_pages; int alloc_pages, free_pages; int addr_align; /* Convert PCI bus alignment from bytes to pages */ align_pages = align / win_map->wm_page_size; /* Convert PCI request from bytes to pages */ size_pages = (size / win_map->wm_page_size) + ((size % win_map->wm_page_size) ? 1 : 0); /* Align address with the larger of the size or the requested slot align */ if (size_pages > align_pages) align_pages = size_pages; /* * Avoid wasting space by aligning - 1; this will prevent crossing * another alignment boundary. */ alloc_pages = size_pages + (align_pages - 1); /* Allocate PCI bus space in pages */ index_page = (int) rmalloc(win_map->wm_map, (size_t) alloc_pages); /* Error if no PCI bus address space available */ if (!index_page) return 0; /* PCI bus address index starts at 0 */ index_page--; /* Align the page offset as requested */ index_page_align = (index_page + (align_pages - 1)) - ((index_page + (align_pages - 1)) % align_pages); free_pages = (align_pages - 1) - (index_page_align - index_page); /* Free unused PCI bus pages adjusting the index to start at 1 */ rmfree(win_map->wm_map, free_pages, (index_page_align + 1) + size_pages); /* Return aligned PCI bus space in bytes */ addr_align = (index_page_align * win_map->wm_page_size); base = index_page; size = alloc_pages - free_pages;#endif /* PIC_LATER */ /* * If a window allocation cookie has been supplied, use it to keep * track of all the allocated space assigned to this window. */ if (win_alloc) { win_alloc->wa_map = win_map; win_alloc->wa_base = base; win_alloc->wa_pages = size; } return base * win_map->wm_page_size;}/* * Free the specified window allocation back into the PCI window mapping * resource. As noted above, we keep page addresses offset by 1 ... */voidpciio_device_win_free(pciio_win_alloc_t win_alloc){ if (win_alloc->wa_pages) rmfree(win_alloc->wa_map->wm_map, win_alloc->wa_pages, win_alloc->wa_base);}/* * pciio_error_register: * arrange for a function to be called with * a specified first parameter plus other * information when an error is encountered * and traced to the pci slot corresponding * to the connection point pconn. * * may also be called with a null function * pointer to "unregister" the error handler. * * NOTE: subsequent calls silently overwrite * previous data for this vertex. We assume that * cooperating drivers, well, cooperate ... */voidpciio_error_register(devfs_handle_t pconn, error_handler_f *efunc, error_handler_arg_t einfo){ pciio_info_t pciio_info; pciio_info = pciio_info_get(pconn); ASSERT(pciio_info != NULL); pciio_info->c_efunc = efunc; pciio_info->c_einfo = einfo;}/* * Check if any device has been found in this slot, and return * true or false * vhdl is the vertex for the slot */intpciio_slot_inuse(devfs_handle_t pconn_vhdl){ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); ASSERT(pciio_info); ASSERT(pciio_info->c_vertex == pconn_vhdl); if (pciio_info->c_vendor) { /* * Non-zero value for vendor indicate * a board being found in this slot. */ return 1; } return 0;}intpciio_dma_enabled(devfs_handle_t pconn_vhdl){ return DEV_FUNC(pconn_vhdl, dma_enabled)(pconn_vhdl);}intpciio_info_type1_get(pciio_info_t pci_info){ return(0);}/* * These are complementary Linux interfaces that takes in a pci_dev * as the * first arguement instead of devfs_handle_t. */iopaddr_t snia_pciio_dmatrans_addr(struct pci_dev *, device_desc_t, paddr_t, size_t, unsigned);pciio_dmamap_t snia_pciio_dmamap_alloc(struct pci_dev *, device_desc_t, size_t, unsigned);void snia_pciio_dmamap_free(pciio_dmamap_t);iopaddr_t snia_pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t);void snia_pciio_dmamap_done(pciio_dmamap_t);pciio_endian_t snia_pciio_endian_set(struct pci_dev *pci_dev, pciio_endian_t device_end, pciio_endian_t desired_end);#include <linux/module.h>EXPORT_SYMBOL(snia_pciio_dmatrans_addr);EXPORT_SYMBOL(snia_pciio_dmamap_alloc);EXPORT_SYMBOL(snia_pciio_dmamap_free);EXPORT_SYMBOL(snia_pciio_dmamap_addr);EXPORT_SYMBOL(snia_pciio_dmamap_done);EXPORT_SYMBOL(snia_pciio_endian_set);intsnia_pcibr_rrb_alloc(struct pci_dev *pci_dev, int *count_vchan0, int *count_vchan1){ devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); return pcibr_rrb_alloc(dev, count_vchan0, count_vchan1);}EXPORT_SYMBOL(snia_pcibr_rrb_alloc);pciio_endian_tsnia_pciio_endian_set(struct pci_dev *pci_dev, pciio_endian_t device_end, pciio_endian_t desired_end){ devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); return DEV_FUNC(dev, endian_set) (dev, device_end, desired_end);}iopaddr_tsnia_pciio_dmatrans_addr(struct pci_dev *pci_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 */ devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); /* * If the device is not a PIC, we always want the PCIIO_BYTE_STREAM to be * set. Otherwise, it must not be set. This applies to SN1 and SN2. */ return DEV_FUNC(dev, dmatrans_addr) (dev, dev_desc, paddr, byte_count, (IS_PIC_DEVICE(pci_dev)) ? (flags & ~PCIIO_BYTE_STREAM) : flags | PCIIO_BYTE_STREAM);}pciio_dmamap_tsnia_pciio_dmamap_alloc(struct pci_dev *pci_dev, /* set up mappings for this device */ device_desc_t dev_desc, /* device descriptor */ size_t byte_count_max, /* max size of a mapping */ unsigned flags){ /* defined in dma.h */ devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); /* * If the device is not a PIC, we always want the PCIIO_BYTE_STREAM to be * set. Otherwise, it must not be set. This applies to SN1 and SN2. */ return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc) (dev, dev_desc, byte_count_max, (IS_PIC_DEVICE(pci_dev)) ? (flags & ~PCIIO_BYTE_STREAM) : flags | PCIIO_BYTE_STREAM);}voidsnia_pciio_dmamap_free(pciio_dmamap_t pciio_dmamap){ DMAMAP_FUNC(pciio_dmamap, dmamap_free) (CAST_DMAMAP(pciio_dmamap));}iopaddr_tsnia_pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ paddr_t paddr, /* map for this address */ size_t byte_count){ /* map this many bytes */ return DMAMAP_FUNC(pciio_dmamap, dmamap_addr) (CAST_DMAMAP(pciio_dmamap), paddr, byte_count);}voidsnia_pciio_dmamap_done(pciio_dmamap_t pciio_dmamap){ DMAMAP_FUNC(pciio_dmamap, dmamap_done) (CAST_DMAMAP(pciio_dmamap));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -