Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 26 Aug 2013 10:55:17 -0400
From:      John Baldwin <jhb@freebsd.org>
To:        "Jean-Sebastien Pedron" <dumbbell@freebsd.org>
Cc:        svn-src-head@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org
Subject:   Re: svn commit: r254882 - head/sys/dev/pci
Message-ID:  <201308261055.17964.jhb@freebsd.org>
In-Reply-To: <201308251809.r7PI9CsE052978@svn.freebsd.org>
References:  <201308251809.r7PI9CsE052978@svn.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sunday, August 25, 2013 2:09:12 pm Jean-Sebastien Pedron wrote:
> Author: dumbbell
> Date: Sun Aug 25 18:09:11 2013
> New Revision: 254882
> URL: http://svnweb.freebsd.org/changeset/base/254882
> 
> Log:
>   vga_pci: Add API to map the Video BIOS
>   
>   Here are two new functions to map and unmap the Video BIOS:
>       void * vga_pci_map_bios(device_t dev, size_t *size);
>       void   vga_pci_unmap_bios(device_t dev, void *bios);
>   
>   The BIOS is either taken from the shadow copy made by the System BIOS at
>   boot time if the given device was used for the default display (i386,
>   amd64 and ia64 only), or from the PCI expansion ROM.
>   
>   Additionally, one can determine if a given device was the default
>   display at boot time using the following new function:
>       void   vga_pci_unmap_bios(device_t dev, void *bios);
> 
> Modified:
>   head/sys/dev/pci/pcivar.h
>   head/sys/dev/pci/vga_pci.c
> 
> Modified: head/sys/dev/pci/pcivar.h
> 
==============================================================================
> --- head/sys/dev/pci/pcivar.h	Sun Aug 25 17:26:05 2013	(r254881)
> +++ head/sys/dev/pci/pcivar.h	Sun Aug 25 18:09:11 2013	(r254882)
> @@ -517,4 +517,11 @@ extern uint32_t	pci_generation;
>  struct pci_map *pci_find_bar(device_t dev, int reg);
>  int	pci_bar_enabled(device_t dev, struct pci_map *pm);
>  
> +#define	VGA_PCI_BIOS_SHADOW_ADDR	0xC0000
> +#define	VGA_PCI_BIOS_SHADOW_SIZE	131072
> +
> +int	vga_pci_is_boot_display(device_t dev);
> +void *	vga_pci_map_bios(device_t dev, size_t *size);
> +void	vga_pci_unmap_bios(device_t dev, void *bios);
> +
>  #endif /* _PCIVAR_H_ */
> 
> Modified: head/sys/dev/pci/vga_pci.c
> 
==============================================================================
> --- head/sys/dev/pci/vga_pci.c	Sun Aug 25 17:26:05 2013	(r254881)
> +++ head/sys/dev/pci/vga_pci.c	Sun Aug 25 18:09:11 2013	(r254882)
> @@ -46,6 +46,11 @@ __FBSDID("$FreeBSD$");
>  #include <sys/sysctl.h>
>  #include <sys/systm.h>
>  
> +#if defined(__amd64__) || defined(__i386__) || defined(__ia64__)
> +#include <vm/vm.h>
> +#include <vm/pmap.h>
> +#endif
> +
>  #include <dev/pci/pcireg.h>
>  #include <dev/pci/pcivar.h>
>  
> @@ -67,6 +72,99 @@ TUNABLE_INT("hw.pci.default_vgapci_unit"
>  SYSCTL_INT(_hw_pci, OID_AUTO, default_vgapci_unit, CTLFLAG_RDTUN,
>      &vga_pci_default_unit, -1, "Default VGA-compatible display");
>  
> +int
> +vga_pci_is_boot_display(device_t dev)
> +{
> +
> +	/*
> +	 * Return true if the given device is the default display used
> +	 * at boot time.
> +	 */
> +
> +	return (
> +	    (pci_get_class(dev) == PCIC_DISPLAY ||
> +	     (pci_get_class(dev) == PCIC_OLD &&
> +	      pci_get_subclass(dev) == PCIS_OLD_VGA)) &&
> +	    device_get_unit(dev) == vga_pci_default_unit);
> +}
> +
> +void *
> +vga_pci_map_bios(device_t dev, size_t *size)
> +{
> +	int rid;
> +	struct resource *res;
> +
> +#if defined(__amd64__) || defined(__i386__) || defined(__ia64__)
> +	if (vga_pci_is_boot_display(dev)) {
> +		/*
> +		 * On x86, the System BIOS copy the default display
> +		 * device's Video BIOS at a fixed location in system
> +		 * memory (0xC0000, 128 kBytes long) at boot time.
> +		 *
> +		 * We use this copy for the default boot device, because
> +		 * the original ROM may not be valid after boot.
> +		 */
> +
> +		printf("%s: Mapping BIOS shadow\n", __func__);
> +		*size = VGA_PCI_BIOS_SHADOW_SIZE;
> +		return (pmap_mapbios(VGA_PCI_BIOS_SHADOW_ADDR, *size));
> +	}
> +#endif
> +
> +	printf("%s: Mapping PCI expansion ROM\n", __func__);
> +	rid = PCIR_BIOS;
> +	res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
> +	if (res == NULL) {
> +		return (NULL);
> +	}
> +
> +	*size = rman_get_size(res);
> +	return (rman_get_virtual(res));
> +}
> +
> +void
> +vga_pci_unmap_bios(device_t dev, void *bios)
> +{
> +	int rid;
> +	struct resource *res;
> +
> +	if (bios == NULL) {
> +		return;
> +	}
> +
> +#if defined(__amd64__) || defined(__i386__) || defined(__ia64__)
> +	if (vga_pci_is_boot_display(dev)) {
> +		/* We mapped the BIOS shadow copy located at 0xC0000. */
> +		printf("%s: Unmapping BIOS shadow\n", __func__);
> +		pmap_unmapdev((vm_offset_t)bios, VGA_PCI_BIOS_SHADOW_SIZE);
> +
> +		return;
> +	}
> +#endif
> +
> +	/*
> +	 * FIXME: We returned only the virtual address of the resource
> +	 * to the caller. Now, to get the resource struct back, we
> +	 * allocate it again: the struct exists once in memory in
> +	 * device softc. Therefore, we release twice now to release the
> +	 * reference we just obtained to get the structure back and the
> +	 * caller's reference.
> +	 */

This won't actually work (the PCI bus will panic when you do the duplicate 
alloc).  Why not put this in the softc of the vga_pci device?  In fact, it is 
already there.  You just need to bump the vr_refs on the vga_bios resource 
similar to what vga_pci_alloc_resource() does.

Also, returning a void * for this API seems rather hacky.  Have you considered
returning a struct resource * instead (and requiring the caller to use 
bus_space_* on it)?  That would be more consistent with new-bus.  I can help 
with getting the right bus_alloc_resource() incantation to alloc a struct 
resource * for the shadow copy if so.

-- 
John Baldwin



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201308261055.17964.jhb>