amd64/89550: [amd64] sym0: VTOBUS failed (6.0 Release)

Jan Mikkelsen janm at transactionware.com
Mon Sep 18 22:40:25 PDT 2006


The following reply was made to PR amd64/89550; it has been noted by GNATS.

From: "Jan Mikkelsen" <janm at transactionware.com>
To: <bug-followup at FreeBSD.org>,
	<awallac3 at uiuc.edu>
Cc:  
Subject: Re: amd64/89550: [amd64] sym0: VTOBUS failed (6.0 Release)
Date: Tue, 19 Sep 2006 15:39:32 +1000

 I've just been looking at this.
 
 The problem seems to be caused by the sym driver assuming that the =
 virtual
 address of the memory allocated by bus_dmamem_alloc will be aligned to =
 an
 address 2*PAGE_SIZE.  The physical address is aligned like that, but the
 virtual address isn't.  This also breaks the buddy algorithm.
 
 Here are the changes I have made to make it work on my system.  Summary:
 Allocate additional pages and adjust the virtual address if necessary to =
 get
 memory with the right alignment.
 
 Other changes (possibly incorrect):
 
 - Adjusted the contigmalloc call because the boundary argument didn't =
 make
 sense to me compared to the man page.
 
 - Adjusted the highaddr argument in the bus_dma_tag_create() call, =
 again,
 the usage didn't really match what I expected from the man page.
 
 Little testing;  I have used it to boot and dd over an old 4GB drive.  =
 With
 the original version it never made it past sym_pci_attach.
 
 
 *** FreeBSD/src/sys/dev/sym/sym_hipd.c	Tue Aug  8 00:43:31 2006
 --- /home/janm/sym_hipd.c	Tue Sep 19 15:27:55 2006
 ***************
 *** 439,445 ****
   #define free_pages(p)		free((p), M_DEVBUF)
   #else
   #define get_pages()		contigmalloc(MEMO_CLUSTER_SIZE, M_DEVBUF, \
 ! 				    0, 0, 1LL << 32, PAGE_SIZE, 1LL << 32)
   #define free_pages(p)		contigfree((p), MEMO_CLUSTER_SIZE, M_DEVBUF)
   #endif
  =20
 --- 439,446 ----
   #define free_pages(p)		free((p), M_DEVBUF)
   #else
   #define get_pages()		contigmalloc(MEMO_CLUSTER_SIZE, M_DEVBUF, \
 ! 				    0, 0, 1LL << 32, PAGE_SIZE, \
 ! 				    MEMO_CLUSTER_SIZE)
   #define free_pages(p)		contigfree((p), MEMO_CLUSTER_SIZE, M_DEVBUF)
   #endif
  =20
 ***************
 *** 453,458 ****
 --- 454,462 ----
   	struct m_vtob	*next;
   	bus_dmamap_t	dmamap;	/* Map for this chunk */
   	m_addr_t	vaddr;	/* Virtual address */
 + #if PAGE_SIZE < MEMO_CLUSTER_SIZE
 + 	m_addr_t	adjusted_vaddr;	/* Virtual address adjusted for
 buddy */
 + #endif
   	m_addr_t	baddr;	/* Bus physical address */
   } m_vtob_s;
   /* Hash this stuff a bit to speed up translations */
 ***************
 *** 674,685 ****
   	if (bus_dmamem_alloc(mp->dmat, &vaddr,
   			      BUS_DMA_NOWAIT, &vbp->dmamap))
   		goto out_err;
   	bus_dmamap_load(mp->dmat, vbp->dmamap, vaddr,
   			MEMO_CLUSTER_SIZE, getbaddrcb, &baddr, 0);
   	if (baddr) {
 ! 		int hc =3D VTOB_HASH_CODE(vaddr);
   		vbp->vaddr =3D (m_addr_t) vaddr;
   		vbp->baddr =3D (m_addr_t) baddr;
   		vbp->next =3D mp->vtob[hc];
   		mp->vtob[hc] =3D vbp;
   		++mp->nump;
 --- 678,711 ----
   	if (bus_dmamem_alloc(mp->dmat, &vaddr,
   			      BUS_DMA_NOWAIT, &vbp->dmamap))
   		goto out_err;
 + #if PAGE_SIZE < MEMO_CLUSTER_SIZE
 + 	bus_dmamap_load(mp->dmat, vbp->dmamap, vaddr,
 + 			MEMO_CLUSTER_SIZE * 2, getbaddrcb, &baddr, 0);
 + #else
   	bus_dmamap_load(mp->dmat, vbp->dmamap, vaddr,
   			MEMO_CLUSTER_SIZE, getbaddrcb, &baddr, 0);
 + #endif
   	if (baddr) {
 ! 		int hc;
 !=20
   		vbp->vaddr =3D (m_addr_t) vaddr;
   		vbp->baddr =3D (m_addr_t) baddr;
 + #if PAGE_SIZE < MEMO_CLUSTER_SIZE
 + 		/*
 + 		 * Adjusting vaddr is OK here because we do not error out.
 + 		 * If that changes, the bus_dmamem_free() call below would
 + 		 * need to be fixed.
 + 		 *
 + 		 * This code assumes that we will be at most one page away
 + 		 * from having things aligned the way we want.
 + 		 */
 +=20
 + 		if (((m_addr_t) vaddr & ~MEMO_CLUSTER_MASK) !=3D (m_addr_t)
 vaddr)
 + 			vaddr =3D (void*) ((m_addr_t) vaddr + PAGE_SIZE);
 +=20
 + 		vbp->adjusted_vaddr =3D (m_addr_t) vaddr;
 + #endif
 + 	       	hc =3D VTOB_HASH_CODE(vaddr);
   		vbp->next =3D mp->vtob[hc];
   		mp->vtob[hc] =3D vbp;
   		++mp->nump;
 ***************
 *** 733,744 ****
   	mp =3D __sym_calloc(&mp0, sizeof(*mp), "MPOOL");
   	if (mp) {
   		mp->dev_dmat =3D dev_dmat;
 ! 		if (!bus_dma_tag_create(dev_dmat, 1, MEMO_CLUSTER_SIZE,
   			       BUS_SPACE_MAXADDR_32BIT,
   			       BUS_SPACE_MAXADDR_32BIT,
   			       NULL, NULL, MEMO_CLUSTER_SIZE, 1,
   			       MEMO_CLUSTER_SIZE, 0,
   			       busdma_lock_mutex, &Giant, &mp->dmat)) {
   			mp->getp =3D ___dma_getp;
   #ifdef	MEMO_FREE_UNUSED
   			mp->freep =3D ___dma_freep;
 --- 759,779 ----
   	mp =3D __sym_calloc(&mp0, sizeof(*mp), "MPOOL");
   	if (mp) {
   		mp->dev_dmat =3D dev_dmat;
 ! #if PAGE_SIZE < MEMO_CLUSTER_SIZE
 ! 		if (!bus_dma_tag_create(dev_dmat, 1, MEMO_CLUSTER_SIZE * 2,
   			       BUS_SPACE_MAXADDR_32BIT,
 + 			       BUS_SPACE_MAXADDR,
 + 			       NULL, NULL, MEMO_CLUSTER_SIZE * 2, 1,
 + 			       MEMO_CLUSTER_SIZE * 2, 0,
 + 			       busdma_lock_mutex, &Giant, &mp->dmat)) {
 + #else
 + 		if (!bus_dma_tag_create(dev_dmat, 1, MEMO_CLUSTER_SIZE,
   			       BUS_SPACE_MAXADDR_32BIT,
 + 			       BUS_SPACE_MAXADDR,
   			       NULL, NULL, MEMO_CLUSTER_SIZE, 1,
   			       MEMO_CLUSTER_SIZE, 0,
   			       busdma_lock_mutex, &Giant, &mp->dmat)) {
 + #endif
   			mp->getp =3D ___dma_getp;
   #ifdef	MEMO_FREE_UNUSED
   			mp->freep =3D ___dma_freep;
 ***************
 *** 815,827 ****
   	mp =3D ___get_dma_pool(dev_dmat);
   	if (mp) {
   		vp =3D mp->vtob[hc];
   		while (vp && (m_addr_t) vp->vaddr !=3D a)
   			vp =3D vp->next;
   	}
   	/* Unlock */
   	if (!vp)
   		panic("sym: VTOBUS FAILED!\n");
 ! 	return vp ? vp->baddr + (((m_addr_t) m) - a) : 0;
   }
  =20
  =20
 --- 850,872 ----
   	mp =3D ___get_dma_pool(dev_dmat);
   	if (mp) {
   		vp =3D mp->vtob[hc];
 + #if (PAGE_SIZE < MEMO_CLUSTER_SIZE)
 + 		while (vp && (m_addr_t) vp->adjusted_vaddr !=3D a)
 + #else
   		while (vp && (m_addr_t) vp->vaddr !=3D a)
 + #endif
   			vp =3D vp->next;
   	}
 +=20
   	/* Unlock */
   	if (!vp)
   		panic("sym: VTOBUS FAILED!\n");
 ! #if (PAGE_SIZE < MEMO_CLUSTER_SIZE)
 ! 	return vp->baddr + (((m_addr_t) m) - a) +
 ! 		(vp->adjusted_vaddr - vp->vaddr);
 ! #else
 ! 	return vp->baddr + (((m_addr_t) m) - a);
 ! #endif
   }
  =20
  =20
 


More information about the freebsd-amd64 mailing list