Subject: Re: [PATCH] DMA 4GB boundary protection

From: [email-masked] (Olof Johansson)
Date: Thu, 22 Mar 2007 12:53:24 -0500

On Wed, Mar 21, 2007 at 04:05:48PM -0500, Jake Moilanen wrote:

> @@ -480,6 +495,21 @@ struct iommu_table *iommu_init_table(str
>  	ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size);
>  #endif
>  
> +	/*
> +	 * DMA cannot cross 4 GB boundary.  Mark first entry of each 4
> +	 * GB chunk as reserved.
> +	 */
> +	if (protect4gb) {
> +		start_addr = tbl->it_offset << IOMMU_PAGE_SHIFT;
> +		/* go up to next 4GB boundary */
> +		start_addr = (start_addr + 0x00000000ffffffffl) >> 32;
> +		end_addr = (tbl->it_offset + tbl->it_size) << IOMMU_PAGE_SHIFT;
> +		for (index = start_addr; index < end_addr; index += (1l << 32)) {
> +			/* Reserve 4GB entry */
> +			__set_bit((index >> IOMMU_PAGE_SHIFT) - tbl->it_offset,
> tbl->it_map);
> +		}
> +	}
> +

This is done a bit more complicated than it has to be. The >> 32 is a
red flag as well.

I would also like it to be the last page in the range, not the first
(since otherwise you'll reserve even if the window is less than 4GB.

Something like (untested):

	entries_per_4g = 0x100000000 >> IOMMU_PAGE_SHIFT;

	/* Mark the last bit before a 4GB boundary as used */
	start_index = tbl->it_offset | (entries_per_4g - 1);
	end_index = tbl->it_offset + tbl->it_size;

	for (index = start_index; index < end_index; index += entries_per_4g)
		__set_bit(index, tbl->it_map);

Is easier to follow.

-Olof