/**
 * Map a memory region for a device using /dev/xsvc.
 *
 * \param dev   Device whose memory region is to be mapped.
 * \param map   Parameters of the mapping that is to be created.
 *
 * \return
 * Zero on success or an \c errno value on failure.
 */
static int
pci_device_solx_devfs_map_range(struct pci_device *dev,
				struct pci_device_mapping *map)
{
    const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0)
			? (PROT_READ | PROT_WRITE) : PROT_READ;
    int err = 0;

#ifdef __sparc
    char	map_dev[128];
    int		map_fd;

    if (MAPPING_DEV_PATH(dev))
	snprintf(map_dev, sizeof (map_dev), "%s%s", "/devices", MAPPING_DEV_PATH(dev));
    else
	strcpy (map_dev, "/dev/fb0");

    if ((map_fd = open(map_dev, O_RDWR | O_CLOEXEC)) < 0) {
	err = errno;
	(void) fprintf(stderr, "can not open %s: %s\n", map_dev,
			   strerror(errno));
	return err;
    }

    map->memory = mmap(NULL, map->size, prot, MAP_SHARED, map_fd, map->base);
#else
    /*
     * Still used xsvc to do the user space mapping
     */
    if (xsvc_fd < 0) {
	if ((xsvc_fd = open("/dev/xsvc", O_RDWR | O_CLOEXEC)) < 0) {
	    err = errno;
	    (void) fprintf(stderr, "can not open /dev/xsvc: %s\n",
			   strerror(errno));
	    return err;
	}
    }

    map->memory = mmap(NULL, map->size, prot, MAP_SHARED, xsvc_fd, map->base);
#endif

    if (map->memory == MAP_FAILED) {
	err = errno;

	(void) fprintf(stderr, "map rom region =%llx failed: %s\n",
		       map->base, strerror(errno));
    }

#ifdef __sparc
    close (map_fd);
#endif

    return err;
}
/*
 * Release all the resources
 * Solaris version
 */
static void
pci_system_solx_devfs_destroy( void )
{
    /*
     * The memory allocated for pci_sys & devices in create routines
     * will be freed in pci_system_cleanup.
     * Need to free system-specific allocations here.
     */
    nexus_t *nexus, *next;

    for (nexus = nexus_list ; nexus != NULL ; nexus = next) {
	next = nexus->next;
	close(nexus->fd);
	free(nexus->path);
	free(nexus->dev_path);
#ifdef __sparc
	{
	    struct pci_device *dev;
	    int i;

	    for (i = 0; i < nexus->num_devices; i++) {
		dev = nexus->devlist[i];
		if (MAPPING_DEV_PATH(dev))
		    di_devfs_path_free((char *) MAPPING_DEV_PATH(dev));
	    }
	}
	free(nexus->devlist);
#endif
	free(nexus);
    }
    nexus_list = NULL;

#ifdef __sparc
    if (di_phdl != DI_PROM_HANDLE_NIL)
	(void) di_prom_fini(di_phdl);
#else
    if (xsvc_fd >= 0) {
	close(xsvc_fd);
	xsvc_fd = -1;
    }
#endif
}
Ejemplo n.º 3
0
/*
 * Release resources per device
 */
static void
pci_system_solx_devfs_destroy_device( struct pci_device *dev )
{
   if (MAPPING_DEV_PATH(dev))
	di_devfs_path_free((char *) MAPPING_DEV_PATH(dev));
}
/*
 * Solaris version
 */
static int
pci_device_solx_devfs_probe( struct pci_device * dev )
{
    int err = 0;
    di_node_t rnode = DI_NODE_NIL;
    i_devnode_t args = { 0, 0, 0, DI_NODE_NIL };
    int *regbuf;
    pci_regspec_t *reg;
    int i;
    int len = 0;
    uint ent = 0;
    nexus_t *nexus;

#ifdef __sparc
    if ( (nexus = find_nexus_for_dev(dev)) == NULL )
#else
    if ( (nexus = find_nexus_for_bus(dev->domain, dev->bus)) == NULL )
#endif
	return ENODEV;

    /*
     * starting to find if it is MEM/MEM64/IO
     * using libdevinfo
     */
    if ((rnode = di_init(nexus->dev_path, DINFOCPYALL)) == DI_NODE_NIL) {
	err = errno;
	(void) fprintf(stderr, "di_init failed: %s\n", strerror(errno));
    } else {
	args.bus = dev->bus;
	args.dev = dev->dev;
	args.func = dev->func;
	(void) di_walk_node(rnode, DI_WALK_CLDFIRST,
		(void *)&args, find_target_node);
    }

    if (args.node != DI_NODE_NIL) {
#ifdef __sparc
	di_minor_t minor;
#endif

#ifdef __sparc
	if (minor = di_minor_next(args.node, DI_MINOR_NIL))
	    MAPPING_DEV_PATH(dev) = di_devfs_minor_path (minor);
	else
	    MAPPING_DEV_PATH(dev) = NULL;
#endif

	/*
	 * It will succeed for sure, because it was
	 * successfully called in find_target_node
	 */
	len = di_prop_lookup_ints(DDI_DEV_T_ANY, args.node,
				  "assigned-addresses",
				  &regbuf);

#ifdef __sparc
	if ((len <= 0) && di_phdl) {
	    len = di_prom_prop_lookup_ints(di_phdl, args.node,
				"assigned-addresses", &regbuf);
	}
#endif
    }

    if (len <= 0)
	goto cleanup;


    /*
     * how to find the size of rom???
     * if the device has expansion rom,
     * it must be listed in the last
     * cells because solaris find probe
     * the base address from offset 0x10
     * to 0x30h. So only check the last
     * item.
     */
    reg = (pci_regspec_t *)&regbuf[len - CELL_NUMS_1275];
    if (PCI_REG_REG_G(reg->pci_phys_hi) == PCI_CONF_ROM) {
	/*
	 * rom can only be 32 bits
	 */
	dev->rom_size = reg->pci_size_low;
	len = len - CELL_NUMS_1275;
    }
    else {
	/*
	 * size default to 64K and base address
	 * default to 0xC0000
	 */
	dev->rom_size = 0x10000;
    }

    /*
     * Solaris has its own BAR index.
     * Linux give two region slot for 64 bit address.
     */
    for (i = 0; i < len; i = i + CELL_NUMS_1275) {

	reg = (pci_regspec_t *)&regbuf[i];
	ent = reg->pci_phys_hi & 0xff;
	/*
	 * G35 broken in BAR0
	 */
	ent = (ent - PCI_CONF_BASE0) >> 2;
	if (ent >= 6) {
	    fprintf(stderr, "error ent = %d\n", ent);
	    break;
	}

	/*
	 * non relocatable resource is excluded
	 * such like 0xa0000, 0x3b0. If it is met,
	 * the loop is broken;
	 */
	if (!PCI_REG_REG_G(reg->pci_phys_hi))
	    break;

	if (reg->pci_phys_hi & PCI_PREFETCH_B) {
	    dev->regions[ent].is_prefetchable = 1;
	}


	/*
	 * We split the shift count 32 into two 16 to
	 * avoid the complaining of the compiler
	 */
	dev->regions[ent].base_addr = reg->pci_phys_low +
	    ((reg->pci_phys_mid << 16) << 16);
	dev->regions[ent].size = reg->pci_size_low +
	    ((reg->pci_size_hi << 16) << 16);

	switch (reg->pci_phys_hi & PCI_REG_ADDR_M) {
	    case PCI_ADDR_IO:
		dev->regions[ent].is_IO = 1;
		break;
	    case PCI_ADDR_MEM32:
		break;
	    case PCI_ADDR_MEM64:
		dev->regions[ent].is_64 = 1;
		/*
		 * Skip one slot for 64 bit address
		 */
		break;
	}
    }

  cleanup:
    if (rnode != DI_NODE_NIL) {
	di_fini(rnode);
    }
    return (err);
}