Commit bc97ce95 authored by Olof Johansson's avatar Olof Johansson Committed by Paul Mackerras
Browse files

[PATCH] powerpc: kill union tce_entry



It's been long overdue to kill the union tce_entry in the pSeries/iSeries
TCE code, especially since I asked the Summit guys to do it on the code
they copied from us.

Also, while I was at it, I cleaned up some whitespace.

Built and booted on pSeries, built on iSeries.

Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent c7f0e8cb
Loading
Loading
Loading
Loading
+10 −11
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
 * Rewrite, cleanup:
 *
 * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation
 * Copyright (C) 2006 Olof Johansson <olof@lixom.net>
 *
 * Dynamic DMA mapping support, iSeries-specific parts.
 *
@@ -42,30 +43,28 @@ static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages,
		unsigned long uaddr, enum dma_data_direction direction)
{
	u64 rc;
	union tce_entry tce;
	u64 tce, rpn;

	index <<= TCE_PAGE_FACTOR;
	npages <<= TCE_PAGE_FACTOR;

	while (npages--) {
		tce.te_word = 0;
		tce.te_bits.tb_rpn = virt_to_abs(uaddr) >> TCE_SHIFT;
		rpn = virt_to_abs(uaddr) >> TCE_SHIFT;
		tce = (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT;

		if (tbl->it_type == TCE_VB) {
			/* Virtual Bus */
			tce.te_bits.tb_valid = 1;
			tce.te_bits.tb_allio = 1;
			tce |= TCE_VALID|TCE_ALLIO;
			if (direction != DMA_TO_DEVICE)
				tce.te_bits.tb_rdwr = 1;
				tce |= TCE_VB_WRITE;
		} else {
			/* PCI Bus */
			tce.te_bits.tb_rdwr = 1; /* Read allowed */
			tce |= TCE_PCI_READ; /* Read allowed */
			if (direction != DMA_TO_DEVICE)
				tce.te_bits.tb_pciwr = 1;
				tce |= TCE_PCI_WRITE;
		}

		rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index,
				tce.te_word);
		rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, tce);
		if (rc)
			panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n",
					rc);
@@ -123,7 +122,7 @@ void iommu_table_getparms_iSeries(unsigned long busno,

	/* itc_size is in pages worth of table, it_size is in # of entries */
	tbl->it_size = ((parms->itc_size * TCE_PAGE_SIZE) /
			sizeof(union tce_entry)) >> TCE_PAGE_FACTOR;
			TCE_ENTRY_SIZE) >> TCE_PAGE_FACTOR;
	tbl->it_busno = parms->itc_busno;
	tbl->it_offset = parms->itc_offset >> TCE_PAGE_FACTOR;
	tbl->it_index = parms->itc_index;
+52 −70
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
 * Rewrite, cleanup:
 *
 * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation
 * Copyright (C) 2006 Olof Johansson <olof@lixom.net>
 *
 * Dynamic DMA mapping support, pSeries-specific parts, both SMP and LPAR.
 *
@@ -53,48 +54,42 @@ static void tce_build_pSeries(struct iommu_table *tbl, long index,
			      long npages, unsigned long uaddr,
			      enum dma_data_direction direction)
{
	union tce_entry t;
	union tce_entry *tp;
	u64 proto_tce;
	u64 *tcep;
	u64 rpn;

	index <<= TCE_PAGE_FACTOR;
	npages <<= TCE_PAGE_FACTOR;

	t.te_word = 0;
	t.te_rdwr = 1; // Read allowed 
	proto_tce = TCE_PCI_READ; // Read allowed

	if (direction != DMA_TO_DEVICE)
		t.te_pciwr = 1;
		proto_tce |= TCE_PCI_WRITE;

	tp = ((union tce_entry *)tbl->it_base) + index;
	tcep = ((u64 *)tbl->it_base) + index;

	while (npages--) {
		/* can't move this out since we might cross LMB boundary */
		t.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
	
		tp->te_word = t.te_word;
		rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
		*tcep = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT;

		uaddr += TCE_PAGE_SIZE;
		tp++;
		tcep++;
	}
}


static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages)
{
	union tce_entry t;
	union tce_entry *tp;
	u64 *tcep;

	npages <<= TCE_PAGE_FACTOR;
	index <<= TCE_PAGE_FACTOR;

	t.te_word = 0;
	tp  = ((union tce_entry *)tbl->it_base) + index;
		
	while (npages--) {
		tp->te_word = t.te_word;
	tcep = ((u64 *)tbl->it_base) + index;

		tp++;
	}
	while (npages--)
		*(tcep++) = 0;
}


@@ -103,43 +98,44 @@ static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum,
				enum dma_data_direction direction)
{
	u64 rc;
	union tce_entry tce;
	u64 proto_tce, tce;
	u64 rpn;

	tcenum <<= TCE_PAGE_FACTOR;
	npages <<= TCE_PAGE_FACTOR;

	tce.te_word = 0;
	tce.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
	tce.te_rdwr = 1;
	rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
	proto_tce = TCE_PCI_READ;
	if (direction != DMA_TO_DEVICE)
		tce.te_pciwr = 1;
		proto_tce |= TCE_PCI_WRITE;

	while (npages--) {
		rc = plpar_tce_put((u64)tbl->it_index, 
				   (u64)tcenum << 12, 
				   tce.te_word );
		tce = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT;
		rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, tce);

		if (rc && printk_ratelimit()) {
			printk("tce_build_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc);
			printk("\tindex   = 0x%lx\n", (u64)tbl->it_index);
			printk("\ttcenum  = 0x%lx\n", (u64)tcenum);
			printk("\ttce val = 0x%lx\n", tce.te_word );
			printk("\ttce val = 0x%lx\n", tce );
			show_stack(current, (unsigned long *)__get_SP());
		}

		tcenum++;
		tce.te_rpn++;
		rpn++;
	}
}

static DEFINE_PER_CPU(void *, tce_page) = NULL;
static DEFINE_PER_CPU(u64 *, tce_page) = NULL;

static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
				     long npages, unsigned long uaddr,
				     enum dma_data_direction direction)
{
	u64 rc;
	union tce_entry tce, *tcep;
	u64 proto_tce;
	u64 *tcep;
	u64 rpn;
	long l, limit;

	if (TCE_PAGE_FACTOR == 0 && npages == 1)
@@ -152,7 +148,7 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
	 * from iommu_alloc{,_sg}()
	 */
	if (!tcep) {
		tcep = (void *)__get_free_page(GFP_ATOMIC);
		tcep = (u64 *)__get_free_page(GFP_ATOMIC);
		/* If allocation fails, fall back to the loop implementation */
		if (!tcep)
			return tce_build_pSeriesLP(tbl, tcenum, npages,
@@ -163,11 +159,10 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
	tcenum <<= TCE_PAGE_FACTOR;
	npages <<= TCE_PAGE_FACTOR;

	tce.te_word = 0;
	tce.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
	tce.te_rdwr = 1;
	rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
	proto_tce = TCE_PCI_READ;
	if (direction != DMA_TO_DEVICE)
		tce.te_pciwr = 1;
		proto_tce |= TCE_PCI_WRITE;

	/* We can map max one pageful of TCEs at a time */
	do {
@@ -175,11 +170,11 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
		 * Set up the page with TCE data, looping through and setting
		 * the values.
		 */
		limit = min_t(long, npages, 4096/sizeof(union tce_entry));
		limit = min_t(long, npages, 4096/TCE_ENTRY_SIZE);

		for (l = 0; l < limit; l++) {
			tcep[l] = tce;
			tce.te_rpn++;
			tcep[l] = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT;
			rpn++;
		}

		rc = plpar_tce_put_indirect((u64)tbl->it_index,
@@ -195,7 +190,7 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
		printk("tce_buildmulti_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc);
		printk("\tindex   = 0x%lx\n", (u64)tbl->it_index);
		printk("\tnpages  = 0x%lx\n", (u64)npages);
		printk("\ttce[0] val = 0x%lx\n", tcep[0].te_word);
		printk("\ttce[0] val = 0x%lx\n", tcep[0]);
		show_stack(current, (unsigned long *)__get_SP());
	}
}
@@ -203,23 +198,17 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages)
{
	u64 rc;
	union tce_entry tce;

	tcenum <<= TCE_PAGE_FACTOR;
	npages <<= TCE_PAGE_FACTOR;

	tce.te_word = 0;

	while (npages--) {
		rc = plpar_tce_put((u64)tbl->it_index,
				   (u64)tcenum << 12,
				   tce.te_word);
		rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, 0);

		if (rc && printk_ratelimit()) {
			printk("tce_free_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc);
			printk("\tindex   = 0x%lx\n", (u64)tbl->it_index);
			printk("\ttcenum  = 0x%lx\n", (u64)tcenum);
			printk("\ttce val = 0x%lx\n", tce.te_word );
			show_stack(current, (unsigned long *)__get_SP());
		}

@@ -231,24 +220,17 @@ static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages
static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages)
{
	u64 rc;
	union tce_entry tce;

	tcenum <<= TCE_PAGE_FACTOR;
	npages <<= TCE_PAGE_FACTOR;

	tce.te_word = 0;

	rc = plpar_tce_stuff((u64)tbl->it_index,
			   (u64)tcenum << 12,
			   tce.te_word,
			   npages);
	rc = plpar_tce_stuff((u64)tbl->it_index, (u64)tcenum << 12, 0, npages);

	if (rc && printk_ratelimit()) {
		printk("tce_freemulti_pSeriesLP: plpar_tce_stuff failed\n");
		printk("\trc      = %ld\n", rc);
		printk("\tindex   = 0x%lx\n", (u64)tbl->it_index);
		printk("\tnpages  = 0x%lx\n", (u64)npages);
		printk("\ttce val = 0x%lx\n", tce.te_word );
		show_stack(current, (unsigned long *)__get_SP());
	}
}
+9 −26
Original line number Diff line number Diff line
@@ -35,32 +35,15 @@
#define TCE_PAGE_SIZE	(1 << TCE_SHIFT)
#define TCE_PAGE_FACTOR	(PAGE_SHIFT - TCE_SHIFT)


/* tce_entry
 * Used by pSeries (SMP) and iSeries/pSeries LPAR, but there it's
 * abstracted so layout is irrelevant.
 */
union tce_entry {
   	unsigned long te_word;
	struct {
		unsigned int  tb_cacheBits :6;	/* Cache hash bits - not used */
		unsigned int  tb_rsvd      :6;
		unsigned long tb_rpn       :40;	/* Real page number */
		unsigned int  tb_valid     :1;	/* Tce is valid (vb only) */
		unsigned int  tb_allio     :1;	/* Tce is valid for all lps (vb only) */
		unsigned int  tb_lpindex   :8;	/* LpIndex for user of TCE (vb only) */
		unsigned int  tb_pciwr     :1;	/* Write allowed (pci only) */
		unsigned int  tb_rdwr      :1;	/* Read allowed  (pci), Write allowed (vb) */
	} te_bits;
#define te_cacheBits te_bits.tb_cacheBits
#define te_rpn       te_bits.tb_rpn
#define te_valid     te_bits.tb_valid
#define te_allio     te_bits.tb_allio
#define te_lpindex   te_bits.tb_lpindex
#define te_pciwr     te_bits.tb_pciwr
#define te_rdwr      te_bits.tb_rdwr
};

#define TCE_ENTRY_SIZE		8		/* each TCE is 64 bits */

#define TCE_RPN_MASK		0xfffffffffful  /* 40-bit RPN (4K pages) */
#define TCE_RPN_SHIFT		12
#define TCE_VALID		0x800		/* TCE valid */
#define TCE_ALLIO		0x400		/* TCE valid for all lpars */
#define TCE_PCI_WRITE		0x2		/* write from PCI allowed */
#define TCE_PCI_READ		0x1		/* read from PCI allowed */
#define TCE_VB_WRITE		0x1		/* write from VB allowed */

#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_TCE_H */