LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* ppc4xx_dma
From: Ronnie Hedlund @ 2007-12-20 22:41 UTC (permalink / raw)
  To: linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 1371 bytes --]

Hi, 

DMA code (for the EBC) is broken for ppc4xx as it is (for all CPUs) in the linux kernel.
This (or some of it) should be implemented in the ppc kernel (since the same broken code has been provided for many years).

This works, and is thread safe. It can use more than one channel in parallel, without causing the "one in a million"-type of errors that WILL happen using the current code.


The old post regarding this matter.
http://ozlabs.org/pipermail/linuxppc-embedded/2005-December/021225.html

It is true that this code does handle the dma-memory in a new way, memory for the sg list is allocated dynamically, which takes a little more CPU time at allocation, but it can still operate on any DMA transfer size (as opposed to the hard coded value (<600Kb) used in current code). Reallocation can be prevented by keeping an allocation for many concurrent transfers.


Hope to help someone, but I'm somewhat shocked that the DMA code in the current 2.6 kernel is in the same state as it was many years ago in the 2.4 kernel, even though patches exists...
Seems everyone that uses the DMA->PLB3 (EBC) needs to patch the kernel code them selves (I'm probably the only one using it/has the hardware to run it, since not much has happened).

[Maybe patches like this are implemented already, then this post was not necessary]

Which you a nice DMA.
/Ronnie Hedlund
 


[-- Attachment #2: ppc4xx_dma.h --]
[-- Type: text/plain, Size: 19535 bytes --]

/*
 * include/asm-ppc/ppc4xx_dma.h
 *
 * IBM PPC4xx DMA engine library
 *
 * Copyright 2000-2004 MontaVista Software Inc.
 *
 * Cleaned up a bit more, Matt Porter <mporter@kernel.crashing.org>
 *
 * Original code by Armin Kuster <akuster@mvista.com>
 * and Pete Popov <ppopov@mvista.com>
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 *
 * You should have received a copy of the  GNU General Public License along
 * with this program; if not, write  to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifdef __KERNEL__
#ifndef __ASMPPC_PPC4xx_DMA_H
#define __ASMPPC_PPC4xx_DMA_H

#include <linux/types.h>
#include <asm/mmu.h>
#include <asm/ibm4xx.h>

#undef DEBUG_4xxDMA

#define MAX_PPC4xx_DMA_CHANNELS		4

/*
 * Function return status codes
 * These values are used to indicate whether or not the function
 * call was successful, or a bad/invalid parameter was passed.
 */
#define DMA_STATUS_GOOD			0
#define DMA_STATUS_BAD_CHANNEL		1
#define DMA_STATUS_BAD_HANDLE		2
#define DMA_STATUS_BAD_MODE		3
#define DMA_STATUS_NULL_POINTER		4
#define DMA_STATUS_OUT_OF_MEMORY	5
#define DMA_STATUS_SGL_LIST_EMPTY	6
#define DMA_STATUS_GENERAL_ERROR	7
#define DMA_STATUS_CHANNEL_NOTFREE	8

#define DMA_CHANNEL_BUSY		0x80000000

/*
 * These indicate status as returned from the DMA Status Register.
 */
#define DMA_STATUS_NO_ERROR	0
#define DMA_STATUS_CS		1	/* Count Status        */
#define DMA_STATUS_TS		2	/* Transfer Status     */
#define DMA_STATUS_DMA_ERROR	3	/* DMA Error Occurred  */
#define DMA_STATUS_DMA_BUSY	4	/* The channel is busy */


/*
 * DMA Channel Control Registers
 */

#if defined(CONFIG_44x) && !defined(CONFIG_440EP)
#define	PPC4xx_DMA_64BIT
#define DMA_CR_OFFSET 1
#else
#define DMA_CR_OFFSET 0
#endif

#define DMA_CE_ENABLE        (1<<31)	/* DMA Channel Enable */
#define SET_DMA_CE_ENABLE(x) (((x)&0x1)<<31)
#define GET_DMA_CE_ENABLE(x) (((x)&DMA_CE_ENABLE)>>31)

#define DMA_CIE_ENABLE        (1<<30)	/* DMA Channel Interrupt Enable */
#define SET_DMA_CIE_ENABLE(x) (((x)&0x1)<<30)
#define GET_DMA_CIE_ENABLE(x) (((x)&DMA_CIE_ENABLE)>>30)

#define DMA_TD                (1<<29)
#define SET_DMA_TD(x)         (((x)&0x1)<<29)
#define GET_DMA_TD(x)         (((x)&DMA_TD)>>29)

#define DMA_PL                (1<<28)	/* Peripheral Location */
#define SET_DMA_PL(x)         (((x)&0x1)<<28)
#define GET_DMA_PL(x)         (((x)&DMA_PL)>>28)

#define EXTERNAL_PERIPHERAL    0
#define INTERNAL_PERIPHERAL    1

#define SET_DMA_PW(x)     (((x)&0x3)<<(26-DMA_CR_OFFSET))	/* Peripheral Width */
#define DMA_PW_MASK       SET_DMA_PW(3)
#define   PW_8                 0
#define   PW_16                1
#define   PW_32                2
#define   PW_64                3
/* FIXME: Add PW_128 support for 440GP DMA block */
#define GET_DMA_PW(x)     (((x)&DMA_PW_MASK)>>(26-DMA_CR_OFFSET))

#define DMA_DAI           (1<<(25-DMA_CR_OFFSET))	/* Destination Address Increment */
#define SET_DMA_DAI(x)    (((x)&0x1)<<(25-DMA_CR_OFFSET))

#define DMA_SAI           (1<<(24-DMA_CR_OFFSET))	/* Source Address Increment */
#define SET_DMA_SAI(x)    (((x)&0x1)<<(24-DMA_CR_OFFSET))

#define DMA_BEN           (1<<(23-DMA_CR_OFFSET))	/* Buffer Enable */
#define SET_DMA_BEN(x)    (((x)&0x1)<<(23-DMA_CR_OFFSET))

#define SET_DMA_TM(x)     (((x)&0x3)<<(21-DMA_CR_OFFSET))	/* Transfer Mode */
#define DMA_TM_MASK       SET_DMA_TM(3)
#define   TM_PERIPHERAL        0	/* Peripheral */
#define   TM_RESERVED          1	/* Reserved */
#define   TM_S_MM              2	/* Memory to Memory */
#define   TM_D_MM              3	/* Device Paced Memory to Memory */
#define GET_DMA_TM(x)     (((x)&DMA_TM_MASK)>>(21-DMA_CR_OFFSET))

#define SET_DMA_PSC(x)    (((x)&0x3)<<(19-DMA_CR_OFFSET))	/* Peripheral Setup Cycles */
#define DMA_PSC_MASK      SET_DMA_PSC(3)
#define GET_DMA_PSC(x)    (((x)&DMA_PSC_MASK)>>(19-DMA_CR_OFFSET))

#define SET_DMA_PWC(x)    (((x)&0x3F)<<(13-DMA_CR_OFFSET))	/* Peripheral Wait Cycles */
#define DMA_PWC_MASK      SET_DMA_PWC(0x3F)
#define GET_DMA_PWC(x)    (((x)&DMA_PWC_MASK)>>(13-DMA_CR_OFFSET))

#define SET_DMA_PHC(x)    (((x)&0x7)<<(10-DMA_CR_OFFSET))	/* Peripheral Hold Cycles */
#define DMA_PHC_MASK      SET_DMA_PHC(0x7)
#define GET_DMA_PHC(x)    (((x)&DMA_PHC_MASK)>>(10-DMA_CR_OFFSET))

#define DMA_ETD_OUTPUT     (1<<(9-DMA_CR_OFFSET))	/* EOT pin is a TC output */
#define SET_DMA_ETD(x)     (((x)&0x1)<<(9-DMA_CR_OFFSET))

#define DMA_TCE_ENABLE     (1<<(8-DMA_CR_OFFSET))
#define SET_DMA_TCE(x)     (((x)&0x1)<<(8-DMA_CR_OFFSET))

#define DMA_DEC            (1<<(2))	/* Address Decrement */
#define SET_DMA_DEC(x)     (((x)&0x1)<<2)
#define GET_DMA_DEC(x)     (((x)&DMA_DEC)>>2)


/*
 * Transfer Modes
 * These modes are defined in a way that makes it possible to
 * simply "or" in the value in the control register.
 */

#define DMA_MODE_MM		(SET_DMA_TM(TM_S_MM))	/* memory to memory */

				/* Device-paced memory to memory, */
				/* device is at source address    */
#define DMA_MODE_MM_DEVATSRC	(DMA_TD | SET_DMA_TM(TM_D_MM))

				/* Device-paced memory to memory,      */
				/* device is at destination address    */
#define DMA_MODE_MM_DEVATDST	(SET_DMA_TM(TM_D_MM))

/* 405gp/440gp */
#define SET_DMA_PREFETCH(x)   (((x)&0x3)<<(4-DMA_CR_OFFSET))	/* Memory Read Prefetch */
#define DMA_PREFETCH_MASK      SET_DMA_PREFETCH(3)
#define   PREFETCH_1           0	/* Prefetch 1 Double Word */
#define   PREFETCH_2           1
#define   PREFETCH_4           2
#define GET_DMA_PREFETCH(x) (((x)&DMA_PREFETCH_MASK)>>(4-DMA_CR_OFFSET))

#define DMA_PCE            (1<<(3-DMA_CR_OFFSET))	/* Parity Check Enable */
#define SET_DMA_PCE(x)     (((x)&0x1)<<(3-DMA_CR_OFFSET))
#define GET_DMA_PCE(x)     (((x)&DMA_PCE)>>(3-DMA_CR_OFFSET))

/* stb3x */

#define DMA_ECE_ENABLE (1<<5)
#define SET_DMA_ECE(x) (((x)&0x1)<<5)
#define GET_DMA_ECE(x) (((x)&DMA_ECE_ENABLE)>>5)

#define DMA_TCD_DISABLE	(1<<4)
#define SET_DMA_TCD(x) (((x)&0x1)<<4)
#define GET_DMA_TCD(x) (((x)&DMA_TCD_DISABLE)>>4)

typedef uint32_t sgl_handle_t;

#ifdef CONFIG_PPC4xx_EDMA

#ifdef CONFIG_VDR
#define SGL_LIST_SIZE (8*4096)
#else
#define SGL_LIST_SIZE 4096
#endif
#define DMA_PPC4xx_SIZE SGL_LIST_SIZE

#define SET_DMA_PRIORITY(x)   (((x)&0x3)<<(6-DMA_CR_OFFSET))	/* DMA Channel Priority */
#define DMA_PRIORITY_MASK SET_DMA_PRIORITY(3)
#define PRIORITY_LOW           0
#define PRIORITY_MID_LOW       1
#define PRIORITY_MID_HIGH      2
#define PRIORITY_HIGH          3
#define GET_DMA_PRIORITY(x) (((x)&DMA_PRIORITY_MASK)>>(6-DMA_CR_OFFSET))

/*
 * DMA Polarity Configuration Register
 */
#define DMAReq_ActiveLow(chan) (1<<(31-(chan*3)))
#define DMAAck_ActiveLow(chan) (1<<(30-(chan*3)))
#define EOT_ActiveLow(chan)    (1<<(29-(chan*3)))	/* End of Transfer */

/*
 * DMA Sleep Mode Register
 */
#define SLEEP_MODE_ENABLE (1<<21)

/*
 * DMA Status Register
 */
#define DMA_CS0           (1<<31)	/* Terminal Count has been reached */
#define DMA_CS1           (1<<30)
#define DMA_CS2           (1<<29)
#define DMA_CS3           (1<<28)

#define DMA_TS0           (1<<27)	/* End of Transfer has been requested */
#define DMA_TS1           (1<<26)
#define DMA_TS2           (1<<25)
#define DMA_TS3           (1<<24)

#define DMA_CH0_ERR       (1<<23)	/* DMA Chanel 0 Error */
#define DMA_CH1_ERR       (1<<22)
#define DMA_CH2_ERR       (1<<21)
#define DMA_CH3_ERR       (1<<20)

#define DMA_IN_DMA_REQ0   (1<<19)	/* Internal DMA Request is pending */
#define DMA_IN_DMA_REQ1   (1<<18)
#define DMA_IN_DMA_REQ2   (1<<17)
#define DMA_IN_DMA_REQ3   (1<<16)

#define DMA_EXT_DMA_REQ0  (1<<15)	/* External DMA Request is pending */
#define DMA_EXT_DMA_REQ1  (1<<14)
#define DMA_EXT_DMA_REQ2  (1<<13)
#define DMA_EXT_DMA_REQ3  (1<<12)

#define DMA_CH0_BUSY      (1<<11)	/* DMA Channel 0 Busy */
#define DMA_CH1_BUSY      (1<<10)
#define DMA_CH2_BUSY       (1<<9)
#define DMA_CH3_BUSY       (1<<8)

#define DMA_SG0            (1<<7)	/* DMA Channel 0 Scatter/Gather in progress */
#define DMA_SG1            (1<<6)
#define DMA_SG2            (1<<5)
#define DMA_SG3            (1<<4)

/* DMA Channel Count Register */
#define DMA_CTC_BTEN     (1<<23)    /* Burst Enable/Disable bit */
#define DMA_CTC_BSIZ_MSK (3<<21)    /* Mask of the Burst size bits */
#define DMA_CTC_BSIZ_2   (0)
#define DMA_CTC_BSIZ_4   (1<<21)
#define DMA_CTC_BSIZ_8   (2<<21)
#define DMA_CTC_BSIZ_16  (3<<21)

/*
 * DMA SG Command Register
 */
#define SSG_ENABLE(chan)   	(1<<(31-chan))	/* Start Scatter Gather */
#define SSG_MASK_ENABLE(chan)	(1<<(15-chan))	/* Enable writing to SSG0 bit */

/*
 * DMA Scatter/Gather Descriptor Bit fields
 */
#define SG_LINK            (1<<31)	/* Link */
#define SG_TCI_ENABLE      (1<<29)	/* Enable Terminal Count Interrupt */
#define SG_ETI_ENABLE      (1<<28)	/* Enable End of Transfer Interrupt */
#define SG_ERI_ENABLE      (1<<27)	/* Enable Error Interrupt */
#define SG_COUNT_MASK       0xFFFF	/* Count Field */

#define SET_DMA_CONTROL \
 		(SET_DMA_CIE_ENABLE(p_init->int_enable) | /* interrupt enable         */ \
 		SET_DMA_BEN(p_init->buffer_enable)     | /* buffer enable            */\
		SET_DMA_ETD(p_init->etd_output)        | /* end of transfer pin      */ \
	       	SET_DMA_TCE(p_init->tce_enable)        | /* terminal count enable    */ \
                SET_DMA_PL(p_init->pl)                 | /* peripheral location      */ \
                SET_DMA_DAI(p_init->dai)               | /* dest addr increment      */ \
                SET_DMA_SAI(p_init->sai)               | /* src addr increment       */ \
                SET_DMA_PRIORITY(p_init->cp)           |  /* channel priority        */ \
                SET_DMA_PW(p_init->pwidth)             |  /* peripheral/bus width    */ \
                SET_DMA_PSC(p_init->psc)               |  /* peripheral setup cycles */ \
                SET_DMA_PWC(p_init->pwc)               |  /* peripheral wait cycles  */ \
                SET_DMA_PHC(p_init->phc)               |  /* peripheral hold cycles  */ \
                SET_DMA_PREFETCH(p_init->pf)              /* read prefetch           */)

#define GET_DMA_POLARITY(chan) (DMAReq_ActiveLow(chan) | DMAAck_ActiveLow(chan) | EOT_ActiveLow(chan))

#elif defined(CONFIG_STB03xxx)		/* stb03xxx */

#define DMA_PPC4xx_SIZE	4096

/*
 * DMA Status Register
 */

#define SET_DMA_PRIORITY(x)   (((x)&0x00800001))	/* DMA Channel Priority */
#define DMA_PRIORITY_MASK	0x00800001
#define   PRIORITY_LOW         	0x00000000
#define   PRIORITY_MID_LOW     	0x00000001
#define   PRIORITY_MID_HIGH    	0x00800000
#define   PRIORITY_HIGH        	0x00800001
#define GET_DMA_PRIORITY(x) (((((x)&DMA_PRIORITY_MASK) &0x00800000) >> 22 ) | (((x)&DMA_PRIORITY_MASK) &0x00000001))

#define DMA_CS0           (1<<31)	/* Terminal Count has been reached */
#define DMA_CS1           (1<<30)
#define DMA_CS2           (1<<29)
#define DMA_CS3           (1<<28)

#define DMA_TS0           (1<<27)	/* End of Transfer has been requested */
#define DMA_TS1           (1<<26)
#define DMA_TS2           (1<<25)
#define DMA_TS3           (1<<24)

#define DMA_CH0_ERR       (1<<23)	/* DMA Chanel 0 Error */
#define DMA_CH1_ERR       (1<<22)
#define DMA_CH2_ERR       (1<<21)
#define DMA_CH3_ERR       (1<<20)

#define DMA_CT0		  (1<<19)	/* Chained transfere */

#define DMA_IN_DMA_REQ0   (1<<18)	/* Internal DMA Request is pending */
#define DMA_IN_DMA_REQ1   (1<<17)
#define DMA_IN_DMA_REQ2   (1<<16)
#define DMA_IN_DMA_REQ3   (1<<15)

#define DMA_EXT_DMA_REQ0  (1<<14)	/* External DMA Request is pending */
#define DMA_EXT_DMA_REQ1  (1<<13)
#define DMA_EXT_DMA_REQ2  (1<<12)
#define DMA_EXT_DMA_REQ3  (1<<11)

#define DMA_CH0_BUSY      (1<<10)	/* DMA Channel 0 Busy */
#define DMA_CH1_BUSY      (1<<9)
#define DMA_CH2_BUSY       (1<<8)
#define DMA_CH3_BUSY       (1<<7)

#define DMA_CT1            (1<<6)	/* Chained transfere */
#define DMA_CT2            (1<<5)
#define DMA_CT3            (1<<4)

#define DMA_CH_ENABLE (1<<7)
#define SET_DMA_CH(x) (((x)&0x1)<<7)
#define GET_DMA_CH(x) (((x)&DMA_CH_ENABLE)>>7)

/* STBx25xxx dma unique */
/* enable device port on a dma channel
 * example ext 0 on dma 1
 */

#define	SSP0_RECV	15
#define	SSP0_XMIT	14
#define EXT_DMA_0	12
#define	SC1_XMIT	11
#define SC1_RECV	10
#define EXT_DMA_2	9
#define	EXT_DMA_3	8
#define SERIAL2_XMIT	7
#define SERIAL2_RECV	6
#define SC0_XMIT 	5
#define	SC0_RECV	4
#define	SERIAL1_XMIT	3
#define SERIAL1_RECV	2
#define	SERIAL0_XMIT	1
#define SERIAL0_RECV	0

#define DMA_CHAN_0	1
#define DMA_CHAN_1	2
#define DMA_CHAN_2	3
#define DMA_CHAN_3	4

/* end STBx25xx */

/*
 * Bit 30 must be one for Redwoods, otherwise transfers may receive errors.
 */
#define DMA_CR_MB0 0x2

#define SET_DMA_CONTROL \
       		(SET_DMA_CIE_ENABLE(p_init->int_enable) |  /* interrupt enable         */ \
		SET_DMA_ETD(p_init->etd_output)        |  /* end of transfer pin      */ \
		SET_DMA_TCE(p_init->tce_enable)        |  /* terminal count enable    */ \
		SET_DMA_PL(p_init->pl)                 |  /* peripheral location      */ \
		SET_DMA_DAI(p_init->dai)               |  /* dest addr increment      */ \
		SET_DMA_SAI(p_init->sai)               |  /* src addr increment       */ \
		SET_DMA_PRIORITY(p_init->cp)           |  /* channel priority        */  \
		SET_DMA_PW(p_init->pwidth)             |  /* peripheral/bus width    */ \
		SET_DMA_PSC(p_init->psc)               |  /* peripheral setup cycles */ \
		SET_DMA_PWC(p_init->pwc)               |  /* peripheral wait cycles  */ \
		SET_DMA_PHC(p_init->phc)               |  /* peripheral hold cycles  */ \
		SET_DMA_TCD(p_init->tcd_disable)	  |  /* TC chain mode disable   */ \
		SET_DMA_ECE(p_init->ece_enable)	  |  /* ECE chanin mode enable  */ \
		SET_DMA_CH(p_init->ch_enable)	|    /* Chain enable 	        */ \
		DMA_CR_MB0				/* must be one */)

#define GET_DMA_POLARITY(chan) chan

#endif

typedef struct {
	unsigned short in_use;	/* set when channel is being used, clr when
				 * available.
				 */
	/*
	 * Valid polarity settings:
	 *   DMAReq_ActiveLow(n)
	 *   DMAAck_ActiveLow(n)
	 *   EOT_ActiveLow(n)
	 *
	 *   n is 0 to max dma chans
	 */
	unsigned int polarity;

	char buffer_enable;	/* Boolean: buffer enable            */
	char tce_enable;	/* Boolean: terminal count enable    */
	char etd_output;	/* Boolean: eot pin is a tc output   */
	char pce;		/* Boolean: parity check enable      */

	/*
	 * Peripheral location:
	 * INTERNAL_PERIPHERAL (UART0 on the 405GP)
	 * EXTERNAL_PERIPHERAL
	 */
	char pl;		/* internal/external peripheral      */

	/*
	 * Valid pwidth settings:
	 *   PW_8
	 *   PW_16
	 *   PW_32
	 *   PW_64
	 */
	unsigned int pwidth;

	char dai;		/* Boolean: dst address increment   */
	char sai;		/* Boolean: src address increment   */

	/*
	 * Valid psc settings: 0-3
	 */
	unsigned int psc;	/* Peripheral Setup Cycles         */

	/*
	 * Valid pwc settings:
	 * 0-63
	 */
	unsigned int pwc;	/* Peripheral Wait Cycles          */

	/*
	 * Valid phc settings:
	 * 0-7
	 */
	unsigned int phc;	/* Peripheral Hold Cycles          */

	/*
	 * Valid cp (channel priority) settings:
	 *   PRIORITY_LOW
	 *   PRIORITY_MID_LOW
	 *   PRIORITY_MID_HIGH
	 *   PRIORITY_HIGH
	 */
	unsigned int cp;	/* channel priority                */

	/*
	 * Valid pf (memory read prefetch) settings:
	 *
	 *   PREFETCH_1
	 *   PREFETCH_2
	 *   PREFETCH_4
	 */
	unsigned int pf;	/* memory read prefetch            */

	/*
	 * Boolean: channel interrupt enable
	 * NOTE: for sgl transfers, only the last descriptor will be setup to
	 * interrupt.
	 */
	char int_enable;

	char shift;		/* easy access to byte_count shift, based on */
	/* the width of the channel                  */

	uint32_t control;	/* channel control word                      */

	/* These variabled are used ONLY in single dma transfers              */
	unsigned int mode;	/* transfer mode                     */
	phys_addr_t addr;
	char ce;		/* channel enable */
#ifdef CONFIG_STB03xxx
	char ch_enable;
	char tcd_disable;
	char ece_enable;
	char td;		/* transfer direction */
#endif

	char int_on_final_sg;/* for scatter/gather - only interrupt on last sg */
} ppc_dma_ch_t;

/*
 * PPC44x DMA implementations have a slightly different
 * descriptor layout.  Probably moved about due to the
 * change to 64-bit addresses and link pointer. I don't
 * know why they didn't just leave control_count after
 * the dst_addr.
 */
#ifdef PPC4xx_DMA_64BIT
typedef struct {
	uint32_t control;
	uint32_t control_count;
	phys_addr_t src_addr;
	phys_addr_t dst_addr;
	phys_addr_t next;
} ppc_sgl_t;
#else
typedef struct {
	uint32_t control;
	uint32_t src_addr;
	uint32_t dst_addr;
	uint32_t control_count;
	uint32_t next;
} ppc_sgl_t;
#endif

typedef struct {
	unsigned int dmanr;
	uint32_t control;	/* channel ctrl word; loaded from each descrptr */
	uint32_t sgl_control;	/* LK, TCI, ETI, and ERI bits in sgl descriptor */
	dma_addr_t dma_addr;	/* dma (physical) address of this list          */
	ppc_sgl_t *phead;
	dma_addr_t phead_dma;
	ppc_sgl_t *ptail;
	dma_addr_t ptail_dma;
} sgl_list_info_t;

typedef struct {
	phys_addr_t *src_addr;
	phys_addr_t *dst_addr;
	phys_addr_t dma_src_addr;
	phys_addr_t dma_dst_addr;
} pci_alloc_desc_t;

extern ppc_dma_ch_t dma_channels[];

/*
 * The DMA API are in ppc4xx_dma.c and ppc4xx_sgdma.c
 */
extern int ppc4xx_init_dma_channel(unsigned int, ppc_dma_ch_t *);
extern int ppc4xx_get_channel_config(unsigned int, ppc_dma_ch_t *);
extern int ppc4xx_set_channel_priority(unsigned int, unsigned int);
extern unsigned int ppc4xx_get_peripheral_width(unsigned int);
extern void ppc4xx_set_sg_addr(int, phys_addr_t);
extern int ppc4xx_add_dma_sgl(sgl_handle_t, phys_addr_t, phys_addr_t, unsigned int);
extern void ppc4xx_enable_dma_sgl(sgl_handle_t);
extern void ppc4xx_disable_dma_sgl(sgl_handle_t);
extern void ppc4xx_disable_dma_sgl_nr(unsigned int dmanr);
extern int ppc4xx_get_dma_sgl_residue(sgl_handle_t, phys_addr_t *, phys_addr_t *);
extern int ppc4xx_delete_dma_sgl_element(sgl_handle_t, phys_addr_t *, phys_addr_t *);
extern int ppc4xx_alloc_dma_handle(sgl_handle_t *, unsigned int, unsigned int);
extern void ppc4xx_free_dma_handle(sgl_handle_t);
extern int ppc4xx_get_dma_status(void);
extern int ppc4xx_enable_burst(unsigned int);
extern int ppc4xx_disable_burst(unsigned int);
extern int ppc4xx_set_burst_size(unsigned int, unsigned int);
extern void ppc4xx_set_src_addr(int dmanr, phys_addr_t src_addr);
extern void ppc4xx_set_dst_addr(int dmanr, phys_addr_t dst_addr);
extern void ppc4xx_enable_dma(unsigned int dmanr);
extern void ppc4xx_disable_dma(unsigned int dmanr);
extern void ppc4xx_set_dma_count(unsigned int dmanr, unsigned int count);
extern int ppc4xx_get_dma_residue(unsigned int dmanr);
extern void ppc4xx_set_dma_addr2(unsigned int dmanr, phys_addr_t src_dma_addr,
				 phys_addr_t dst_dma_addr);
extern int ppc4xx_enable_dma_interrupt(unsigned int dmanr);
extern int ppc4xx_disable_dma_interrupt(unsigned int dmanr);
extern int ppc4xx_clr_dma_status(unsigned int dmanr);
extern int ppc4xx_map_dma_port(unsigned int dmanr, unsigned int ocp_dma,short dma_chan);
extern int ppc4xx_disable_dma_port(unsigned int dmanr, unsigned int ocp_dma,short dma_chan);
extern int ppc4xx_set_dma_mode(unsigned int dmanr, unsigned int mode);

/* These are in kernel/dma.c: */

/* reserve a DMA channel */
extern int request_dma(unsigned int dmanr, const char *device_id);
/* release it again */
extern void free_dma(unsigned int dmanr);
#endif
#endif				/* __KERNEL__ */

[-- Attachment #3: ppc4xx_dma.c --]
[-- Type: text/plain, Size: 18928 bytes --]

/*
 * IBM PPC4xx DMA engine core library
 *
 * Copyright 2000-2004 MontaVista Software Inc.
 *
 * Cleaned up and converted to new DCR access
 * Matt Porter <mporter@kernel.crashing.org>
 *
 * Original code by Armin Kuster <akuster@mvista.com>
 * and Pete Popov <ppopov@mvista.com>
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 *
 * You should have received a copy of the  GNU General Public License along
 * with this program; if not, write  to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/init.h>
#include <linux/module.h>

#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/ppc4xx_dma.h>

ppc_dma_ch_t dma_channels[MAX_PPC4xx_DMA_CHANNELS];

int
ppc4xx_get_dma_status(void)
{
	return (mfdcr(DCRN_DMASR));
}

void
ppc4xx_set_src_addr(int dmanr, phys_addr_t src_addr)
{
	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk("set_src_addr: bad channel: %d\n", dmanr);
		return;
	}

#ifdef PPC4xx_DMA_64BIT
	mtdcr(DCRN_DMASAH0 + dmanr*2, (u32)(src_addr >> 32));
#else
	mtdcr(DCRN_DMASA0 + dmanr*2, (u32)src_addr);
#endif
}

void
ppc4xx_set_dst_addr(int dmanr, phys_addr_t dst_addr)
{
	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk("set_dst_addr: bad channel: %d\n", dmanr);
		return;
	}

#ifdef PPC4xx_DMA_64BIT
	mtdcr(DCRN_DMADAH0 + dmanr*2, (u32)(dst_addr >> 32));
#else
	mtdcr(DCRN_DMADA0 + dmanr*2, (u32)dst_addr);
#endif
}

void
ppc4xx_enable_dma(unsigned int dmanr)
{
	unsigned int control;
	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
	unsigned int status_bits[] = { DMA_CS0 | DMA_TS0 | DMA_CH0_ERR,
				       DMA_CS1 | DMA_TS1 | DMA_CH1_ERR,
				       DMA_CS2 | DMA_TS2 | DMA_CH2_ERR,
				       DMA_CS3 | DMA_TS3 | DMA_CH3_ERR};

	if (p_dma_ch->in_use) {
		printk("enable_dma: channel %d in use\n", dmanr);
		return;
	}

	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk("enable_dma: bad channel: %d\n", dmanr);
		return;
	}

	if (p_dma_ch->mode == DMA_MODE_READ) {
		/* peripheral to memory */
		ppc4xx_set_src_addr(dmanr, 0);
		ppc4xx_set_dst_addr(dmanr, p_dma_ch->addr);
	} else if (p_dma_ch->mode == DMA_MODE_WRITE) {
		/* memory to peripheral */
		ppc4xx_set_src_addr(dmanr, p_dma_ch->addr);
		ppc4xx_set_dst_addr(dmanr, 0);
	}

	/* for other xfer modes, the addresses are already set */
	control = mfdcr(DCRN_DMACR0 + (dmanr * 0x8));

	control &= ~(DMA_TM_MASK | DMA_TD);	/* clear all mode bits */
	if (p_dma_ch->mode == DMA_MODE_MM) {
		/* software initiated memory to memory */
		control |= DMA_ETD_OUTPUT | DMA_TCE_ENABLE;
	}

	mtdcr(DCRN_DMACR0 + (dmanr * 0x8), control);

	/*
	 * Clear the CS, TS, RI bits for the channel from DMASR.  This
	 * has been observed to happen correctly only after the mode and
	 * ETD/DCE bits in DMACRx are set above.  Must do this before
	 * enabling the channel.
	 */

	mtdcr(DCRN_DMASR, status_bits[dmanr]);

	/*
	 * For device-paced transfers, Terminal Count Enable apparently
	 * must be on, and this must be turned on after the mode, etc.
	 * bits are cleared above (at least on Redwood-6).
	 */

	if ((p_dma_ch->mode == DMA_MODE_MM_DEVATDST) ||
	    (p_dma_ch->mode == DMA_MODE_MM_DEVATSRC))
		control |= DMA_TCE_ENABLE;

	/*
	 * Now enable the channel.
	 */

	control |= (p_dma_ch->mode | DMA_CE_ENABLE);

	mtdcr(DCRN_DMACR0 + (dmanr * 0x8), control);

	p_dma_ch->in_use = 1;
}

void
ppc4xx_disable_dma(unsigned int dmanr)
{
	unsigned int control;
	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];

	if (!p_dma_ch->in_use) {
	  //		printk("disable_dma: channel %d not in use\n", dmanr);
		return;
	}

	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk("disable_dma: bad channel: %d\n", dmanr);
		return;
	}

	control = mfdcr(DCRN_DMACR0 + (dmanr * 0x8));
	control &= ~DMA_CE_ENABLE;
	mtdcr(DCRN_DMACR0 + (dmanr * 0x8), control);

	p_dma_ch->in_use = 0;
}

/*
 * Sets the dma mode for single DMA transfers only.
 * For scatter/gather transfers, the mode is passed to the
 * alloc_dma_handle() function as one of the parameters.
 *
 * The mode is simply saved and used later.  This allows
 * the driver to call set_dma_mode() and set_dma_addr() in
 * any order.
 *
 * Valid mode values are:
 *
 * DMA_MODE_READ          peripheral to memory
 * DMA_MODE_WRITE         memory to peripheral
 * DMA_MODE_MM            memory to memory
 * DMA_MODE_MM_DEVATSRC   device-paced memory to memory, device at src
 * DMA_MODE_MM_DEVATDST   device-paced memory to memory, device at dst
 */
int
ppc4xx_set_dma_mode(unsigned int dmanr, unsigned int mode)
{
	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];

	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk("set_dma_mode: bad channel 0x%x\n", dmanr);
		return DMA_STATUS_BAD_CHANNEL;
	}

	p_dma_ch->mode = mode;

	return DMA_STATUS_GOOD;
}

/*
 * Sets the DMA Count register. Note that 'count' is in bytes.
 * However, the DMA Count register counts the number of "transfers",
 * where each transfer is equal to the bus width.  Thus, count
 * MUST be a multiple of the bus width.
 */
void
ppc4xx_set_dma_count(unsigned int dmanr, unsigned int count)
{
	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];

#ifdef DEBUG_4xxDMA
	{
		int error = 0;
		switch (p_dma_ch->pwidth) {
		case PW_8:
			break;
		case PW_16:
			if (count & 0x1)
				error = 1;
			break;
		case PW_32:
			if (count & 0x3)
				error = 1;
			break;
		case PW_64:
			if (count & 0x7)
				error = 1;
			break;
		default:
			printk("set_dma_count: invalid bus width: 0x%x\n",
			       p_dma_ch->pwidth);
			return;
		}
		if (error)
			printk
			    ("Warning: set_dma_count count 0x%x bus width %d\n",
			     count, p_dma_ch->pwidth);
	}
#endif

	count = count >> p_dma_ch->shift;

	mtdcr(DCRN_DMACT0 + (dmanr * 0x8), count);
}

/*
 *   Returns the number of bytes left to be transfered.
 *   After a DMA transfer, this should return zero.
 *   Reading this while a DMA transfer is still in progress will return
 *   unpredictable results.
 */
int
ppc4xx_get_dma_residue(unsigned int dmanr)
{
	unsigned int count;
	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];

	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk("ppc4xx_get_dma_residue: bad channel 0x%x\n", dmanr);
		return DMA_STATUS_BAD_CHANNEL;
	}

	count = mfdcr(DCRN_DMACT0 + (dmanr * 0x8));

	return (count << p_dma_ch->shift);
}

/*
 * Sets the DMA address for a memory to peripheral or peripheral
 * to memory transfer.  The address is just saved in the channel
 * structure for now and used later in enable_dma().
 */
void
ppc4xx_set_dma_addr(unsigned int dmanr, phys_addr_t addr)
{
	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];

	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk("ppc4xx_set_dma_addr: bad channel: %d\n", dmanr);
		return;
	}

#ifdef DEBUG_4xxDMA
	{
		int error = 0;
		switch (p_dma_ch->pwidth) {
		case PW_8:
			break;
		case PW_16:
			if ((unsigned) addr & 0x1)
				error = 1;
			break;
		case PW_32:
			if ((unsigned) addr & 0x3)
				error = 1;
			break;
		case PW_64:
			if ((unsigned) addr & 0x7)
				error = 1;
			break;
		default:
			printk("ppc4xx_set_dma_addr: invalid bus width: 0x%x\n",
			       p_dma_ch->pwidth);
			return;
		}
		if (error)
			printk("Warning: ppc4xx_set_dma_addr addr 0x%x bus width %d\n",
			       addr, p_dma_ch->pwidth);
	}
#endif

	/* save dma address and program it later after we know the xfer mode */
	p_dma_ch->addr = addr;
}

/*
 * Sets both DMA addresses for a memory to memory transfer.
 * For memory to peripheral or peripheral to memory transfers
 * the function set_dma_addr() should be used instead.
 */
void
ppc4xx_set_dma_addr2(unsigned int dmanr, phys_addr_t src_dma_addr,
		     phys_addr_t dst_dma_addr)
{
	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk("ppc4xx_set_dma_addr2: bad channel: %d\n", dmanr);
		return;
	}

#ifdef DEBUG_4xxDMA
	{
		ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
		int error = 0;
		switch (p_dma_ch->pwidth) {
			case PW_8:
				break;
			case PW_16:
				if (((unsigned) src_dma_addr & 0x1) ||
						((unsigned) dst_dma_addr & 0x1)
				   )
					error = 1;
				break;
			case PW_32:
				if (((unsigned) src_dma_addr & 0x3) ||
						((unsigned) dst_dma_addr & 0x3)
				   )
					error = 1;
				break;
			case PW_64:
				if (((unsigned) src_dma_addr & 0x7) ||
						((unsigned) dst_dma_addr & 0x7)
				   )
					error = 1;
				break;
			default:
				printk("ppc4xx_set_dma_addr2: invalid bus width: 0x%x\n",
						p_dma_ch->pwidth);
				return;
		}
		if (error)
			printk
				("Warning: ppc4xx_set_dma_addr2 src 0x%x dst 0x%x bus width %d\n",
				 src_dma_addr, dst_dma_addr, p_dma_ch->pwidth);
	}
#endif

	ppc4xx_set_src_addr(dmanr, src_dma_addr);
	ppc4xx_set_dst_addr(dmanr, dst_dma_addr);
}

/*
 * Enables the channel interrupt.
 *
 * If performing a scatter/gatter transfer, this function
 * MUST be called before calling alloc_dma_handle() and building
 * the sgl list.  Otherwise, interrupts will not be enabled, if
 * they were previously disabled.
 */
int
ppc4xx_enable_dma_interrupt(unsigned int dmanr)
{
	unsigned int control;
	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];

	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk("ppc4xx_enable_dma_interrupt: bad channel: %d\n", dmanr);
		return DMA_STATUS_BAD_CHANNEL;
	}

	p_dma_ch->int_enable = 1;

	control = mfdcr(DCRN_DMACR0 + (dmanr * 0x8));
	control |= DMA_CIE_ENABLE;	/* Channel Interrupt Enable */
	mtdcr(DCRN_DMACR0 + (dmanr * 0x8), control);

	return DMA_STATUS_GOOD;
}

/*
 * Disables the channel interrupt.
 *
 * If performing a scatter/gatter transfer, this function
 * MUST be called before calling alloc_dma_handle() and building
 * the sgl list.  Otherwise, interrupts will not be disabled, if
 * they were previously enabled.
 */
int
ppc4xx_disable_dma_interrupt(unsigned int dmanr)
{
	unsigned int control;
	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];

	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk("ppc4xx_disable_dma_interrupt: bad channel: %d\n", dmanr);
		return DMA_STATUS_BAD_CHANNEL;
	}

	p_dma_ch->int_enable = 0;

	control = mfdcr(DCRN_DMACR0 + (dmanr * 0x8));
	control &= ~DMA_CIE_ENABLE;	/* Channel Interrupt Enable */
	mtdcr(DCRN_DMACR0 + (dmanr * 0x8), control);

	return DMA_STATUS_GOOD;
}

/*
 * Configures a DMA channel, including the peripheral bus width, if a
 * peripheral is attached to the channel, the polarity of the DMAReq and
 * DMAAck signals, etc.  This information should really be setup by the boot
 * code, since most likely the configuration won't change dynamically.
 * If the kernel has to call this function, it's recommended that it's
 * called from platform specific init code.  The driver should not need to
 * call this function.
 */
int
ppc4xx_init_dma_channel(unsigned int dmanr, ppc_dma_ch_t * p_init)
{
	unsigned int status_bits[] = { DMA_CS0 | DMA_TS0 | DMA_CH0_ERR,
				       DMA_CS1 | DMA_TS1 | DMA_CH1_ERR,
				       DMA_CS2 | DMA_TS2 | DMA_CH2_ERR,
				       DMA_CS3 | DMA_TS3 | DMA_CH3_ERR};

	unsigned int polarity;
	uint32_t control = 0;
	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];

	DMA_MODE_READ = (unsigned long) DMA_TD;	/* Peripheral to Memory */
	DMA_MODE_WRITE = 0;	/* Memory to Peripheral */

	if (!p_init) {
		printk("ppc4xx_init_dma_channel: NULL p_init\n");
		return DMA_STATUS_NULL_POINTER;
	}

	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk("ppc4xx_init_dma_channel: bad channel %d\n", dmanr);
		return DMA_STATUS_BAD_CHANNEL;
	}

#if DCRN_POL > 0
	polarity = mfdcr(DCRN_POL);
#else
	polarity = 0;
#endif

	/* Setup the control register based on the values passed to
	 * us in p_init.  Then, over-write the control register with this
	 * new value.
	 */
	control |= SET_DMA_CONTROL;

	/* clear all polarity signals and then "or" in new signal levels */
	polarity &= ~GET_DMA_POLARITY(dmanr);
	polarity |= p_init->polarity;
#if DCRN_POL > 0
	mtdcr(DCRN_POL, polarity);
#endif
	mtdcr(DCRN_DMACR0 + (dmanr * 0x8), control);

	/* save these values in our dma channel structure */
	memcpy(p_dma_ch, p_init, sizeof (ppc_dma_ch_t));

	/*
	 * The peripheral width values written in the control register are:
	 *   PW_8                 0
	 *   PW_16                1
	 *   PW_32                2
	 *   PW_64                3
	 *
	 *   Since the DMA count register takes the number of "transfers",
	 *   we need to divide the count sent to us in certain
	 *   functions by the appropriate number.  It so happens that our
	 *   right shift value is equal to the peripheral width value.
	 */
	p_dma_ch->shift = p_init->pwidth;

	/*
	 * Save the control word for easy access.
	 */
	p_dma_ch->control = control;

	/*
	 * clear status register for the channel
	 * only TS, CS and RI needs to be cleared.
	 */
	mtdcr(DCRN_DMASR, status_bits[dmanr]);
	
	return DMA_STATUS_GOOD;
}

/*
 * This function returns the channel configuration.
 */
int
ppc4xx_get_channel_config(unsigned int dmanr, ppc_dma_ch_t * p_dma_ch)
{
	unsigned int polarity;
	unsigned int control;

	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk("ppc4xx_get_channel_config: bad channel %d\n", dmanr);
		return DMA_STATUS_BAD_CHANNEL;
	}

	memcpy(p_dma_ch, &dma_channels[dmanr], sizeof (ppc_dma_ch_t));

#if DCRN_POL > 0
	polarity = mfdcr(DCRN_POL);
#else
	polarity = 0;
#endif

	p_dma_ch->polarity = polarity & GET_DMA_POLARITY(dmanr);
	control = mfdcr(DCRN_DMACR0 + (dmanr * 0x8));

	p_dma_ch->cp = GET_DMA_PRIORITY(control);
	p_dma_ch->pwidth = GET_DMA_PW(control);
	p_dma_ch->psc = GET_DMA_PSC(control);
	p_dma_ch->pwc = GET_DMA_PWC(control);
	p_dma_ch->phc = GET_DMA_PHC(control);
	p_dma_ch->ce = GET_DMA_CE_ENABLE(control);
	p_dma_ch->int_enable = GET_DMA_CIE_ENABLE(control);
	p_dma_ch->shift = GET_DMA_PW(control);

#ifdef CONFIG_PPC4xx_EDMA
	p_dma_ch->pf = GET_DMA_PREFETCH(control);
#else
	p_dma_ch->ch_enable = GET_DMA_CH(control);
	p_dma_ch->ece_enable = GET_DMA_ECE(control);
	p_dma_ch->tcd_disable = GET_DMA_TCD(control);
#endif
	return DMA_STATUS_GOOD;
}

/*
 * Sets the priority for the DMA channel dmanr.
 * Since this is setup by the hardware init function, this function
 * can be used to dynamically change the priority of a channel.
 *
 * Acceptable priorities:
 *
 * PRIORITY_LOW
 * PRIORITY_MID_LOW
 * PRIORITY_MID_HIGH
 * PRIORITY_HIGH
 *
 */
int
ppc4xx_set_channel_priority(unsigned int dmanr, unsigned int priority)
{
	unsigned int control;

	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk("ppc4xx_set_channel_priority: bad channel %d\n", dmanr);
		return DMA_STATUS_BAD_CHANNEL;
	}

	if ((priority != PRIORITY_LOW) &&
	    (priority != PRIORITY_MID_LOW) &&
	    (priority != PRIORITY_MID_HIGH) && (priority != PRIORITY_HIGH)) {
		printk("ppc4xx_set_channel_priority: bad priority: 0x%x\n", priority);
	}

	control = mfdcr(DCRN_DMACR0 + (dmanr * 0x8));
	control |= SET_DMA_PRIORITY(priority);
	mtdcr(DCRN_DMACR0 + (dmanr * 0x8), control);

	return DMA_STATUS_GOOD;
}

/*
 * Returns the width of the peripheral attached to this channel. This assumes
 * that someone who knows the hardware configuration, boot code or some other
 * init code, already set the width.
 *
 * The return value is one of:
 *   PW_8
 *   PW_16
 *   PW_32
 *   PW_64
 *
 *   The function returns 0 on error.
 */
unsigned int
ppc4xx_get_peripheral_width(unsigned int dmanr)
{
	unsigned int control;

	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk("ppc4xx_get_peripheral_width: bad channel %d\n", dmanr);
		return DMA_STATUS_BAD_CHANNEL;
	}

	control = mfdcr(DCRN_DMACR0 + (dmanr * 0x8));

	return (GET_DMA_PW(control));
}

/*
 * Clears the channel status bits
 */
int
ppc4xx_clr_dma_status(unsigned int dmanr)
{
	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk(KERN_ERR "ppc4xx_clr_dma_status: bad channel: %d\n", dmanr);
		return DMA_STATUS_BAD_CHANNEL;
	}
	mtdcr(DCRN_DMASR, ((u32)DMA_CH0_ERR | (u32)DMA_CS0 | (u32)DMA_TS0) >> dmanr);
	return DMA_STATUS_GOOD;
}

#ifdef CONFIG_PPC4xx_EDMA
/*
 * Enables the burst on the channel (BTEN bit in the control/count register)
 * Note:
 * For scatter/gather dma, this function MUST be called before the
 * ppc4xx_alloc_dma_handle() func as the chan count register is copied into the
 * sgl list and used as each sgl element is added.
 */
int
ppc4xx_enable_burst(unsigned int dmanr)
{
	unsigned int ctc;
	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk(KERN_ERR "ppc4xx_enable_burst: bad channel: %d\n", dmanr);
		return DMA_STATUS_BAD_CHANNEL;
	}
        ctc = mfdcr(DCRN_DMACT0 + (dmanr * 0x8)) | DMA_CTC_BTEN;
	mtdcr(DCRN_DMACT0 + (dmanr * 0x8), ctc);
	return DMA_STATUS_GOOD;
}
/*
 * Disables the burst on the channel (BTEN bit in the control/count register)
 * Note:
 * For scatter/gather dma, this function MUST be called before the
 * ppc4xx_alloc_dma_handle() func as the chan count register is copied into the
 * sgl list and used as each sgl element is added.
 */
int
ppc4xx_disable_burst(unsigned int dmanr)
{
	unsigned int ctc;
	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk(KERN_ERR "ppc4xx_disable_burst: bad channel: %d\n", dmanr);
		return DMA_STATUS_BAD_CHANNEL;
	}
	ctc = mfdcr(DCRN_DMACT0 + (dmanr * 0x8)) &~ DMA_CTC_BTEN;
	mtdcr(DCRN_DMACT0 + (dmanr * 0x8), ctc);
	return DMA_STATUS_GOOD;
}
/*
 * Sets the burst size (number of peripheral widths) for the channel
 * (BSIZ bits in the control/count register))
 * must be one of:
 *    DMA_CTC_BSIZ_2
 *    DMA_CTC_BSIZ_4
 *    DMA_CTC_BSIZ_8
 *    DMA_CTC_BSIZ_16
 * Note:
 * For scatter/gather dma, this function MUST be called before the
 * ppc4xx_alloc_dma_handle() func as the chan count register is copied into the
 * sgl list and used as each sgl element is added.
 */
int
ppc4xx_set_burst_size(unsigned int dmanr, unsigned int bsize)
{
	unsigned int ctc;
	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk(KERN_ERR "ppc4xx_set_burst_size: bad channel: %d\n", dmanr);
		return DMA_STATUS_BAD_CHANNEL;
	}
	ctc = mfdcr(DCRN_DMACT0 + (dmanr * 0x8)) &~ DMA_CTC_BSIZ_MSK;
	ctc |= (bsize & DMA_CTC_BSIZ_MSK);
	mtdcr(DCRN_DMACT0 + (dmanr * 0x8), ctc);
	return DMA_STATUS_GOOD;
}

EXPORT_SYMBOL(ppc4xx_enable_burst);
EXPORT_SYMBOL(ppc4xx_disable_burst);
EXPORT_SYMBOL(ppc4xx_set_burst_size);
#endif /* CONFIG_PPC4xx_EDMA */

EXPORT_SYMBOL(ppc4xx_init_dma_channel);
EXPORT_SYMBOL(ppc4xx_get_channel_config);
EXPORT_SYMBOL(ppc4xx_set_channel_priority);
EXPORT_SYMBOL(ppc4xx_get_peripheral_width);
EXPORT_SYMBOL(dma_channels);
EXPORT_SYMBOL(ppc4xx_set_src_addr);
EXPORT_SYMBOL(ppc4xx_set_dst_addr);
EXPORT_SYMBOL(ppc4xx_set_dma_addr);
EXPORT_SYMBOL(ppc4xx_set_dma_addr2);
EXPORT_SYMBOL(ppc4xx_enable_dma);
EXPORT_SYMBOL(ppc4xx_disable_dma);
EXPORT_SYMBOL(ppc4xx_set_dma_mode);
EXPORT_SYMBOL(ppc4xx_set_dma_count);
EXPORT_SYMBOL(ppc4xx_get_dma_residue);
EXPORT_SYMBOL(ppc4xx_enable_dma_interrupt);
EXPORT_SYMBOL(ppc4xx_disable_dma_interrupt);
EXPORT_SYMBOL(ppc4xx_get_dma_status);
EXPORT_SYMBOL(ppc4xx_clr_dma_status);


[-- Attachment #4: ppc4xx_sgdma.c --]
[-- Type: text/plain, Size: 17134 bytes --]

/*
 * IBM PPC4xx DMA engine scatter/gather library
 *
 * Copyright 2002-2003 MontaVista Software Inc.
 *
 * Cleaned up and converted to new DCR access
 * Matt Porter <mporter@kernel.crashing.org>
 *
 * Original code by Armin Kuster <akuster@mvista.com>
 * and Pete Popov <ppopov@mvista.com>
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 *
 * You should have received a copy of the  GNU General Public License along
 * with this program; if not, write  to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>

#include <asm/system.h>
#include <asm/io.h>
#include <asm/ppc4xx_dma.h>
#ifdef CONFIG_VDR
#include <asm/cacheflush.h>
#endif

void
ppc4xx_set_sg_addr(int dmanr, phys_addr_t sg_addr)
{
	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk("ppc4xx_set_sg_addr: bad channel: %d\n", dmanr);
		return;
	}

#ifdef PPC4xx_DMA_64BIT
	mtdcr(DCRN_ASGH0 + (dmanr * 0x8), (u32)(sg_addr >> 32));
#endif
	mtdcr(DCRN_ASG0 + (dmanr * 0x8), (u32)sg_addr);
}

/*
 *   Add a new sgl descriptor to the end of a scatter/gather list
 *   which was created by alloc_dma_handle().
 *
 *   For a memory to memory transfer, both dma addresses must be
 *   valid. For a peripheral to memory transfer, one of the addresses
 *   must be set to NULL, depending on the direction of the transfer:
 *   memory to peripheral: set dst_addr to NULL,
 *   peripheral to memory: set src_addr to NULL.
 */
int
ppc4xx_add_dma_sgl(sgl_handle_t handle, phys_addr_t src_addr, phys_addr_t dst_addr,
		   unsigned int count)
{
	sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
	ppc_dma_ch_t *p_dma_ch;

	if (!handle) {
		printk("ppc4xx_add_dma_sgl: null handle\n");
		return DMA_STATUS_BAD_HANDLE;
	}

	if (psgl->dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk("ppc4xx_add_dma_sgl: bad channel: %d\n", psgl->dmanr);
		return DMA_STATUS_BAD_CHANNEL;
	}

	p_dma_ch = &dma_channels[psgl->dmanr];

#ifdef DEBUG_4xxDMA
	{
		int error = 0;
		unsigned int aligned =
		    (unsigned) src_addr | (unsigned) dst_addr | count;
		switch (p_dma_ch->pwidth) {
		case PW_8:
			break;
		case PW_16:
			if (aligned & 0x1)
				error = 1;
			break;
		case PW_32:
			if (aligned & 0x3)
				error = 1;
			break;
		case PW_64:
			if (aligned & 0x7)
				error = 1;
			break;
		default:
			printk("ppc4xx_add_dma_sgl: invalid bus width: 0x%x\n",
			       p_dma_ch->pwidth);
			return DMA_STATUS_GENERAL_ERROR;
		}
		if (error)
			printk
			    ("Alignment warning: ppc4xx_add_dma_sgl src 0x%x dst 0x%x count 0x%x bus width var %d\n",
			     src_addr, dst_addr, count, p_dma_ch->pwidth);

	}
#endif

#ifdef CONFIG_VDR
	/* dynamic alloc each list element */
	{
		ppc_sgl_t *sgl_el = kmalloc(sizeof(ppc_sgl_t), GFP_KERNEL|GFP_DMA);
		if (!sgl_el)
			return DMA_STATUS_OUT_OF_MEMORY;

		if (!psgl->phead) { /* list was empty */
			psgl->phead = sgl_el;
		} else { /* not empty, tail exists */
			psgl->ptail->next = (uint32_t)virt_to_phys(sgl_el);
			dma_cache_wback((unsigned long)psgl->ptail, sizeof(ppc_sgl_t));
		}
		psgl->ptail = sgl_el;
	}

	psgl->ptail->control = psgl->control;
	psgl->ptail->src_addr = (uint32_t)src_addr;
	psgl->ptail->dst_addr = (uint32_t)dst_addr;
	psgl->ptail->control_count = (count >> p_dma_ch->shift) |
	    psgl->sgl_control;
	psgl->ptail->next = (uint32_t)virt_to_phys(NULL);
	dma_cache_wback((unsigned long)psgl->ptail, sizeof(ppc_sgl_t)); /* handled later, skip this one? */
#else
	if ((unsigned) (psgl->ptail + 1) >= ((unsigned) psgl + SGL_LIST_SIZE)) {
		printk("sgl handle out of memory \n");
		return DMA_STATUS_OUT_OF_MEMORY;
	}

	if (!psgl->ptail) {
		psgl->phead = (ppc_sgl_t *)
		    ((unsigned) psgl + sizeof (sgl_list_info_t));
		psgl->phead_dma = psgl->dma_addr + sizeof(sgl_list_info_t);
		psgl->ptail = psgl->phead;
		psgl->ptail_dma = psgl->phead_dma;
	} else {
		if(p_dma_ch->int_on_final_sg) {
			/* mask out all dma interrupts, except error, on tail
			before adding new tail. */
			psgl->ptail->control_count &=
				~(SG_TCI_ENABLE | SG_ETI_ENABLE);

			/* PATRIK: Added */
			/* Require Terminal Count interrupt on last */
			psgl->ptail->control_count |= SG_TCI_ENABLE; 
		}
		psgl->ptail->next = psgl->ptail_dma + sizeof(ppc_sgl_t);
		psgl->ptail++;
		psgl->ptail_dma += sizeof(ppc_sgl_t);
	}

	psgl->ptail->control = psgl->control;
	psgl->ptail->src_addr = src_addr;
	psgl->ptail->dst_addr = dst_addr;
	psgl->ptail->control_count = (count >> p_dma_ch->shift) |
	    psgl->sgl_control;
	psgl->ptail->next = (uint32_t) NULL;
#endif

	return DMA_STATUS_GOOD;
}

/*
 * Enable (start) the DMA described by the sgl handle.
 */
void
ppc4xx_enable_dma_sgl(sgl_handle_t handle)
{
	sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
	ppc_dma_ch_t *p_dma_ch;
	uint32_t sg_command;

	if (!handle) {
		printk("ppc4xx_enable_dma_sgl: null handle\n");
		return;
	} else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
		printk("ppc4xx_enable_dma_sgl: bad channel in handle %d\n",
		       psgl->dmanr);
		return;
	} else if (!psgl->phead) {
		printk("ppc4xx_enable_dma_sgl: sg list empty\n");
		return;
	}

	p_dma_ch = &dma_channels[psgl->dmanr];
	psgl->ptail->control_count &= ~SG_LINK;	/* make this the last dscrptr */
	if (p_dma_ch->int_enable)
	{
		/* Require Terminal Count interrupt on last */
		psgl->ptail->control_count |= SG_TCI_ENABLE; 
	}

#ifdef CONFIG_VDR
	/* No more changes to tail object allowed */
	//dma_cache_wback((unsigned long)psgl->ptail, sizeof(ppc_sgl_t));
	dma_cache_wback_inv((unsigned long)psgl->ptail, sizeof(ppc_sgl_t));
	
	ppc4xx_set_sg_addr(psgl->dmanr, virt_to_phys(psgl->phead));
#else
	ppc4xx_set_sg_addr(psgl->dmanr, psgl->phead_dma);
#endif

	sg_command = SSG_ENABLE(psgl->dmanr) | SSG_MASK_ENABLE(psgl->dmanr);
	mtdcr(DCRN_ASGC, sg_command);	/* start transfer */
}

/*
 * Halt an active scatter/gather DMA operation (from handle).
 */
void
ppc4xx_disable_dma_sgl(sgl_handle_t handle)
{
	uint32_t sg_command;

	if (!handle) {
		printk("ppc4xx_disable_dma_sgl: null handle\n");
		return;
	} else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
		printk("ppc4xx_disable_dma_sgl: bad channel in handle %d\n",
		       psgl->dmanr);
		return;
	}
	
	sg_command = SSG_MASK_ENABLE(psgl->dmanr);
	mtdcr(DCRN_ASGC, sg_command);	/* stop transfer */
}

/*
 * Halt an active scatter/gather DMA operation (from dmanr).
 */
void
ppc4xx_disable_dma_sgl_nr(unsigned int dmanr)
{
	uint32_t sg_command;

	if (dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
		printk("ppc4xx_disable_dma_sgl_nr: bad channel %d\n", dmanr);
		return;
	}

	sg_command = SSG_MASK_ENABLE(dmanr);
	mtdcr(DCRN_ASGC, sg_command);	/* stop transfer */
}

/*
 *  Returns number of bytes left to be transferred from the entire sgl list.
 *  *src_addr and *dst_addr get set to the source/destination address of
 *  the sgl descriptor where the DMA stopped.
 *
 *  An sgl transfer must NOT be active when this function is called.
 *  Note: Make sure ppc4xx_disable_dma_sgl is called before returning from
 *  interrupt handler (TSn, CSn will not disable the sgl)!
 */
int
ppc4xx_get_dma_sgl_residue(sgl_handle_t handle, phys_addr_t * src_addr,
			   phys_addr_t * dst_addr)
{
	sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
	ppc_dma_ch_t *p_dma_ch;
	ppc_sgl_t *pnext, *sgl_addr;
	uint32_t count_left;

	if (!handle) {
		printk("ppc4xx_get_dma_sgl_residue: null handle\n");
		return DMA_STATUS_BAD_HANDLE;
	} else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
		printk("ppc4xx_get_dma_sgl_residue: bad channel in handle %d\n",
		       psgl->dmanr);
		return DMA_STATUS_BAD_CHANNEL;
	}

	sgl_addr = (ppc_sgl_t *) __va(mfdcr(DCRN_ASG0 + (psgl->dmanr * 0x8)));
	count_left = mfdcr(DCRN_DMACT0 + (psgl->dmanr * 0x8)) & SG_COUNT_MASK;


#ifdef CONFIG_VDR
	if (!sgl_addr) {
		/* Last in list */
		return count_left;
	}

	pnext = sgl_addr; /* sgl_addr is next to be loaded */

	/*
	 * Why this interface? Better return nothing or sgl_addr instead...?
	 */
	*src_addr = pnext->src_addr;
	*dst_addr = pnext->dst_addr;

	/*
	 * Now search the remaining descriptors and add their count.
	 * We already have the remaining count from this descriptor in
	 * count_left.
	 */
	while (pnext) {
		count_left += pnext->control_count & SG_COUNT_MASK;
		pnext = phys_to_virt(pnext->next);
	}

	/* success */
	p_dma_ch = &dma_channels[psgl->dmanr];
	return (count_left << p_dma_ch->shift);	/* count in bytes */
#else
	if (!sgl_addr) {
		printk("ppc4xx_get_dma_sgl_residue: sgl addr register is null\n");
		goto error;
	}
	pnext = psgl->phead;
	while (pnext &&
	       ((unsigned) pnext < ((unsigned) psgl + SGL_LIST_SIZE) &&
		(pnext != sgl_addr))
	    ) {
		pnext++;
	}

	if (pnext == sgl_addr) {	/* found the sgl descriptor */

		*src_addr = pnext->src_addr;
		*dst_addr = pnext->dst_addr;

		/*
		 * Now search the remaining descriptors and add their count.
		 * We already have the remaining count from this descriptor in
		 * count_left.
		 */
		pnext++;

		while ((pnext != psgl->ptail) &&
		       ((unsigned) pnext < ((unsigned) psgl + SGL_LIST_SIZE))
		    ) {
			count_left += pnext->control_count & SG_COUNT_MASK;
		}

		if (pnext != psgl->ptail) {	/* should never happen */
			printk
			    ("ppc4xx_get_dma_sgl_residue error (1) psgl->ptail 0x%x handle 0x%x\n",
			     (unsigned int) psgl->ptail, (unsigned int) handle);
			goto error;
		}

		/* success */
		p_dma_ch = &dma_channels[psgl->dmanr];
		return (count_left << p_dma_ch->shift);	/* count in bytes */

	} else {
		/* this shouldn't happen */
		printk
		    ("get_dma_sgl_residue, unable to match current address 0x%x, handle 0x%x\n",
		     (unsigned int) sgl_addr, (unsigned int) handle);

	}

      error:
	*src_addr = (phys_addr_t) NULL;
	*dst_addr = (phys_addr_t) NULL;
	return 0;
#endif
}

/*
 * Returns the address(es) of the buffer(s) contained in the head element of
 * the scatter/gather list.  The element is removed from the scatter/gather
 * list and the next element becomes the head.
 *
 * This function should only be called when the DMA is not active.
 */
int
ppc4xx_delete_dma_sgl_element(sgl_handle_t handle, phys_addr_t * src_dma_addr,
			      phys_addr_t * dst_dma_addr)
{
	sgl_list_info_t *psgl = (sgl_list_info_t *) handle;

	if (!handle) {
		printk("ppc4xx_delete_sgl_element: null handle\n");
		return DMA_STATUS_BAD_HANDLE;
	} else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
		printk("ppc4xx_delete_sgl_element: bad channel in handle %d\n",
		       psgl->dmanr);
		return DMA_STATUS_BAD_CHANNEL;
	}

	if (!psgl->phead) {
		/* printk("ppc4xx_delete_sgl_element: sgl list empty\n"); - not an error */
		*src_dma_addr = (phys_addr_t) NULL;
		*dst_dma_addr = (phys_addr_t) NULL;
		return DMA_STATUS_SGL_LIST_EMPTY;
	}

	*src_dma_addr = (phys_addr_t) psgl->phead->src_addr;
	*dst_dma_addr = (phys_addr_t) psgl->phead->dst_addr;

	if (psgl->phead == psgl->ptail) {
		/* last descriptor on the list */
#ifdef CONFIG_VDR
		kfree(psgl->phead);
#endif		
		psgl->phead = NULL;
		psgl->ptail = NULL;
	} else {
#ifdef CONFIG_VDR
		ppc_sgl_t *next = phys_to_virt(psgl->phead->next);
		kfree(psgl->phead);
		psgl->phead = next;
#else
		psgl->phead++;
		psgl->phead_dma += sizeof(ppc_sgl_t);
#endif
	}

	return DMA_STATUS_GOOD;
}


/*
 *   Create a scatter/gather list handle.  This is simply a structure which
 *   describes a scatter/gather list.
 *
 *   A handle is returned in "handle" which the driver should save in order to
 *   be able to access this list later.  A chunk of memory will be allocated
 *   to be used by the API for internal management purposes, including managing
 *   the sg list and allocating memory for the sgl descriptors.  One page should
 *   be more than enough for that purpose.  Perhaps it's a bit wasteful to use
 *   a whole page for a single sg list, but most likely there will be only one
 *   sg list per channel.
 *
 *   Interrupt notes:
 *   Each sgl descriptor has a copy of the DMA control word which the DMA engine
 *   loads in the control register.  The control word has a "global" interrupt
 *   enable bit for that channel. Interrupts are further qualified by a few bits
 *   in the sgl descriptor count register.  In order to setup an sgl, we have to
 *   know ahead of time whether or not interrupts will be enabled at the completion
 *   of the transfers.  Thus, enable_dma_interrupt()/disable_dma_interrupt() MUST
 *   be called before calling alloc_dma_handle().  If the interrupt mode will never
 *   change after powerup, then enable_dma_interrupt()/disable_dma_interrupt()
 *   do not have to be called -- interrupts will be enabled or disabled based
 *   on how the channel was configured after powerup by the hw_init_dma_channel()
 *   function.  Each sgl descriptor will be setup to interrupt if an error occurs;
 *   however, only the last descriptor will be setup to interrupt. Thus, an
 *   interrupt will occur (if interrupts are enabled) only after the complete
 *   sgl transfer is done.
 *   End of Transfer Interrupt needs to be enabled in all descriptors, since it
 *   is impossible to know which one will be the last...
 */
int
ppc4xx_alloc_dma_handle(sgl_handle_t * phandle, unsigned int mode, unsigned int dmanr)
{
	sgl_list_info_t *psgl=NULL;
#ifdef CONFIG_VDR
	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
#else
	dma_addr_t dma_addr;
	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
	uint32_t ctc_settings;
	void *ret;
#endif

	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
		printk("ppc4xx_alloc_dma_handle: invalid channel 0x%x\n", dmanr);
		return DMA_STATUS_BAD_CHANNEL;
	}

	if (!phandle) {
		printk("ppc4xx_alloc_dma_handle: null handle\n");
		return DMA_STATUS_BAD_HANDLE;
	}

#ifdef CONFIG_VDR
	/* Get memory for the listinfo struct */
	psgl = kmalloc(sizeof(sgl_list_info_t), GFP_KERNEL);
	if (psgl == NULL) {
		*phandle = (sgl_handle_t) NULL;
		return DMA_STATUS_OUT_OF_MEMORY;
	}
	memset(psgl, 0, sizeof(sgl_list_info_t));
	
	/* dma_addr is unused now */
	psgl->dmanr = dmanr;
#else
	/* Get a page of memory, which is zeroed out by consistent_alloc() */
	ret = dma_alloc_coherent(NULL, DMA_PPC4xx_SIZE, &dma_addr, GFP_KERNEL);
	if (ret != NULL) {
		memset(ret, 0, DMA_PPC4xx_SIZE);
		psgl = (sgl_list_info_t *) ret;
	}

	if (psgl == NULL) {
		*phandle = (sgl_handle_t) NULL;
		return DMA_STATUS_OUT_OF_MEMORY;
	}

	psgl->dma_addr = dma_addr;
	psgl->dmanr = dmanr;
#endif
	/*
	 * Modify and save the control word. These words will be
	 * written to each sgl descriptor.  The DMA engine then
	 * loads this control word into the control register
	 * every time it reads a new descriptor.
	 */
	psgl->control = p_dma_ch->control;
	/* Clear all mode bits */
	psgl->control &= ~(DMA_TM_MASK | DMA_TD);
	/* Save control word and mode */
	psgl->control |= (mode | DMA_CE_ENABLE);
	 /* PPC Errata? DMA else ignore count on first in list */
	psgl->control |= SET_DMA_TCE(1);
	
	/* In MM mode, we must set ETD/TCE */
	if (mode == DMA_MODE_MM)
		psgl->control |= DMA_ETD_OUTPUT | DMA_TCE_ENABLE;

	if (p_dma_ch->int_enable) {
		/* Enable channel interrupt */
		psgl->control |= DMA_CIE_ENABLE;
	} else {
		psgl->control &= ~DMA_CIE_ENABLE;
	}

	/* Enable SGL control access */
	psgl->sgl_control = SG_ERI_ENABLE | SG_LINK;

#ifndef CONFIG_VDR
	/* keep control count register settings */
	ctc_settings = mfdcr(DCRN_DMACT0 + (dmanr * 0x8))
		& (DMA_CTC_BSIZ_MSK | DMA_CTC_BTEN); /*burst mode settings*/
	psgl->sgl_control |= ctc_settings;
#endif

	if (p_dma_ch->int_enable) {
		if (p_dma_ch->tce_enable)
			psgl->sgl_control |= SG_TCI_ENABLE;
		else
			psgl->sgl_control |= SG_ETI_ENABLE;
	}

	*phandle = (sgl_handle_t) psgl;
	return DMA_STATUS_GOOD;
}

/*
 * Destroy a scatter/gather list handle that was created by alloc_dma_handle().
 * The list must be empty (contain no elements).
 */
void
ppc4xx_free_dma_handle(sgl_handle_t handle)
{
	sgl_list_info_t *psgl = (sgl_list_info_t *) handle;

#ifdef CONFIG_VDR
	if (!handle) {
		printk("ppc4xx_free_dma_handle: got NULL\n");
		return;
	} else if (psgl->phead) { /* free list here, why do it externaly? */
		phys_addr_t dummy;
		while (ppc4xx_delete_dma_sgl_element(handle, &dummy, &dummy) == DMA_STATUS_GOOD)
			/* NOOP */;
		/* printk("ppc4xx_free_dma_handle: list not empty\n"); */
	}

	kfree((void *) psgl);
#else
	if (!handle) {
		printk("ppc4xx_free_dma_handle: got NULL\n");
		return;
	} else if (psgl->phead) {
		printk("ppc4xx_free_dma_handle: list not empty\n");
		return;
	} else if (!psgl->dma_addr) {	/* should never happen */
		printk("ppc4xx_free_dma_handle: no dma address\n");
		return;
	}

	dma_free_coherent(NULL, DMA_PPC4xx_SIZE, (void *) psgl, 0);
#endif
}

EXPORT_SYMBOL(ppc4xx_alloc_dma_handle);
EXPORT_SYMBOL(ppc4xx_free_dma_handle);
EXPORT_SYMBOL(ppc4xx_add_dma_sgl);
EXPORT_SYMBOL(ppc4xx_delete_dma_sgl_element);
EXPORT_SYMBOL(ppc4xx_enable_dma_sgl);
EXPORT_SYMBOL(ppc4xx_disable_dma_sgl);
EXPORT_SYMBOL(ppc4xx_disable_dma_sgl_nr);
EXPORT_SYMBOL(ppc4xx_get_dma_sgl_residue);

^ permalink raw reply

* Re: [PATCH 0/5] Version 17, series to add device tree naming to i2c
From: Jon Smirl @ 2007-12-20 23:59 UTC (permalink / raw)
  To: i2c, linuxppc-dev, linux-kernel
In-Reply-To: <20071220044136.20091.70984.stgit@terra.home>

Are there any other objections to this patch? If not, can it be
targeted for 2.6.25?

On 12/19/07, Jon Smirl <jonsmirl@gmail.com> wrote:
> Since copying i2c-mpc.c to maintain support for the ppc architecture seems to be an issue; instead rework i2c-mpc.c to use CONFIG_PPC_MERGE #ifdefs to support both the ppc and powerpc architecture. When ppc is deleted in six months these #ifdefs will need to be removed.
>
> Another rework of the i2c for powerpc device tree patch. This version implements standard alias naming only on the powerpc platform and only for the device tree names. The old naming mechanism of i2c_client.name,driver_name is left in place and not changed for non-powerpc platforms. This patch is fully capable of dynamically loading the i2c modules. You can modprobe in the i2c-mpc driver and the i2c modules described in the device tree will be automatically loaded. Modules also work if compiled in.
>
> The follow on patch to module-init-tools is also needed since the i2c subsystem has never implemented dynamic loading.
>
> The following series implements standard linux module aliasing for i2c modules on arch=powerpc. It then converts the mpc i2c driver from being a platform driver to an open firmware one. I2C device names are picked up from the device tree. Module aliasing is used to translate from device tree names into to linux kernel names. Several i2c drivers are updated to use the new aliasing.
>
> --
> Jon Smirl
> jonsmirl@gmail.com
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>


-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply

* Re: [PATCH 3/4] sbc8560: Add device tree source for Wind River SBC8560 board
From: David Gibson @ 2007-12-20 23:57 UTC (permalink / raw)
  To: Paul Gortmaker; +Cc: linuxppc-dev
In-Reply-To: <6be237dcf5b58d604afa6cea3079ec7de02a8de9.1198107769.git.paul.gortmaker@windriver.com>

On Thu, Dec 20, 2007 at 09:54:31AM -0500, Paul Gortmaker wrote:
> This adds the device tree source for the Wind River SBC8560 board.  The
> biggest difference between this and the MPC8560ADS reference platform
> is the use of an external 16550 compatible UART instead of the CPM2.
> 
> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
> ---
>  arch/powerpc/boot/dts/sbc8560.dts |  202 +++++++++++++++++++++++++++++++++++++
>  1 files changed, 202 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/powerpc/boot/dts/sbc8560.dts b/arch/powerpc/boot/dts/sbc8560.dts
> new file mode 100644
> index 0000000..85fc488
> --- /dev/null
> +++ b/arch/powerpc/boot/dts/sbc8560.dts
> @@ -0,0 +1,202 @@
> +/*
> + * SBC8560 Device Tree Source
> + *
> + * Copyright 2007 Wind River Systems Inc.
> + *
> + * Paul Gortmaker (see MAINTAINERS for contact information)
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + */
> +
> +
> +/ {
> +	model = "SBC8560";
> +	compatible = "SBC8560";
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +
> +	cpus {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		PowerPC,8560@0 {
> +			device_type = "cpu";
> +			reg = <0>;
> +			d-cache-line-size = <20>;	// 32 bytes
> +			i-cache-line-size = <20>;	// 32 bytes
> +			d-cache-size = <8000>;		// L1, 32K
> +			i-cache-size = <8000>;		// L1, 32K
> +			timebase-frequency = <0>;	// From uboot
> +			bus-frequency = <0>;
> +			clock-frequency = <0>;
> +			32-bit;

Drop the "32-bit".  It was created in analogy with the "64-bit"
property, but nothing ever actually specified it.

> +		};
> +	};
> +
> +	memory {
> +		device_type = "memory";
> +		reg = <00000000 20000000>;
> +	};
> +
> +	soc8560@ff700000 {

I believe we're trying to call these "soc@address" now rather than
"socXXXX@address".

> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		#interrupt-cells = <2>;
> +		device_type = "soc";
> +		ranges = <0 ff700000 00100000>;
> +		reg = <ff700000 00100000>;
> +		bus-frequency = <0>;

This should be "clock-frequency" not "bus-frequency" although I don't
know if you can fix this within your code, or if it's a pre-existing
brokenness.

[snip]
> +		i2c@3000 {
> +			device_type = "i2c";

Drop this device_type.

> +			compatible = "fsl-i2c";
> +			reg = <3000 100>;
> +			interrupts = <2b 2>;
> +			interrupt-parent = <&mpic>;
> +			dfsrr;
> +		};
> +
> +		mdio@24520 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			device_type = "mdio";
> +			compatible = "gianfar";

And this one, and change the compatible.  The gianfar driver has
recently been updated to change this.

[snip]
> +		ethernet@24000 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			device_type = "network";
> +			model = "TSEC";
> +			compatible = "gianfar";

Likewise here.

> +			reg = <24000 1000>;
> +			local-mac-address = [ 00 00 00 00 00 00 ];
> +			interrupts = <1d 2 1e 2 22 2>;
> +			interrupt-parent = <&mpic>;
> +			phy-handle = <&phy0>;
> +		};

[snip]
> +		mpic: pic@40000 {
> +			clock-frequency = <0>;

The mpic has a clock-frequency??

> +			interrupt-controller;
> +			#address-cells = <0>;

Should have #size-cells = <0> too.

> +			#interrupt-cells = <2>;
> +			reg = <40000 40000>;
> +			built-in;
> +			compatible = "chrp,open-pic";
> +			device_type = "open-pic";
> +			big-endian;
> +		};
> +
> +		global-utilities@e0000 {
> +			compatible = "fsl,mpc8560-guts";
> +			reg = <e0000 1000>;
> +			fsl,has-rstcr;
> +		};
> +	};
> +
> +	duart@fc700000 {
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		#interrupt-cells = <2>;

This is neither an interrupt-controller nor an interrupt-nexus, so it
shouldn't have #interrupt-cells.

> +		device_type = "soc";		// console checks for this!

!?  If console checks this (whatever that means), then console is
doing crap...

This is clearly *not* a SoC, and should have a proper compatible, not
this crap device type.  Come to that, is this really an independent
device or does it belong within the soc or on the localbus or
something?

> +		ranges = <0 fc700000 00200000>;
> +		reg = <fc700000 00200000>;

Ranges and reg should not overlap like this, except in very unusal
cases.  I'm really not sure what this duart node is support to
represent, in any case.

> +		serial@000000 {

No leading zeroes on the unit address part of the name

> +			device_type = "serial";
> +			compatible = "ns16550";
> +			reg = <000000 100>;
> +			clock-frequency = <1C2000>;
> +			interrupts = <9 2>;
> +			interrupt-parent = <&mpic>;
> +		};
> +
> +		serial@100000 {
> +			device_type = "serial";
> +			compatible = "ns16550";
> +			reg = <100000 100>;
> +			clock-frequency = <1C2000>;
> +			interrupts = <a 2>;
> +			interrupt-parent = <&mpic>;
> +		};
> +	};
> +
> +	rtc@fc900000 {

Again, it looks very much like the duart and rtc belong off some
external bus controller, not directly on the CPU bus (which is what
the top-level of the device tree represents).

> +		#address-cells = <1>;
> +		#size-cells = <1>;

This has no child nodes, so no need for #address-cells and #size-cells.

> +		device_type = "rtc";

Drop device_type, we're trying to avoid them.

> +		compatible = "m48t59";
> +		reg = <fc900000 2000>;
> +	};
> +};

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

^ permalink raw reply

* Re: [PATCH 0/4] arch/powerpc support for SBC8560 board
From: Kumar Gala @ 2007-12-20 23:56 UTC (permalink / raw)
  To: Paul Gortmaker; +Cc: linuxppc-dev
In-Reply-To: <11981624722785-git-send-email-paul.gortmaker@windriver.com>

> 3) Add device tree source for Wind River SBC8560 board
>
> This is probably the most interesting part of the group, given that  
> the
> board doesn't use the CPM2 to provide the serial console.  I've made a
> duart dts entry that is kind of similar to what is done for the tsi108
> on the mpc7448/hpc-ii board, and made sure that the serial had their
> parent marked as "soc" (found out the hard way that UARTs were ignored
> as possible consoles unless they were soc or tsi108 children...)
>
> b/arch/powerpc/boot/dts/sbc8560.dts |  203 ++++++++++++++++++++++++++ 
> +++++++++-

we need to figure out to fix this so we don't need the parent marked  
as 'soc'.

Out of interest how exactly are the duart's wired on the 8560.  Are  
they off localbus?


> I'd quickly spun together a u-boot 1.2.0 for testing this -- since  
> that was
> the quickest route to getting a powerpc capable version.  I'll see  
> what
> can be done for getting a u-boot 1.3.1 patchset out so the local-mac- 
> address
> vs address thing in the dtb isn't an issue.
\x7f
Probably should add a boot wrapper to work with old non-device tree  
aware u-boots.

- k

^ permalink raw reply

* Re: patch pci-fix-bus-resource-assignment-on-32-bits-with-64b-resources.patch added to gregkh-2.6 tree
From: Benjamin Herrenschmidt @ 2007-12-20 23:56 UTC (permalink / raw)
  To: gregkh; +Cc: greg, linux-kernel, linuxppc-dev
In-Reply-To: <11981938363358@kroah.org>


> The current pci_assign_unassigned_resources() code doesn't work properly
> on 32 bits platforms with 64 bits resources. The main reason is the use
> of unsigned long in various places instead of resource_size_t.
> 
> This fixes it, along with some tricks to avoid casting to 64 bits on
> platforms that don't need it in every printk around.

Can you still edit the changelog ? If yes, please remove that sentence
since the latest version (which you put in your tree) doesn't actually
have those tricks anymore as per discussion on the list...

Sorry about that.

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH 3/4] sbc8560: Add device tree source for Wind River SBC8560 board
From: Kumar Gala @ 2007-12-20 23:54 UTC (permalink / raw)
  To: Paul Gortmaker; +Cc: linuxppc-dev
In-Reply-To: <11981624742139-git-send-email-paul.gortmaker@windriver.com>


On Dec 20, 2007, at 8:54 AM, Paul Gortmaker wrote:

> This adds the device tree source for the Wind River SBC8560 board.   
> The
> biggest difference between this and the MPC8560ADS reference platform
> is the use of an external 16550 compatible UART instead of the CPM2.
>
> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
> ---
> arch/powerpc/boot/dts/sbc8560.dts |  202 ++++++++++++++++++++++++++++ 
> +++++++++
> 1 files changed, 202 insertions(+), 0 deletions(-)
>
> diff --git a/arch/powerpc/boot/dts/sbc8560.dts b/arch/powerpc/boot/ 
> dts/sbc8560.dts
> new file mode 100644
> index 0000000..85fc488
> --- /dev/null
> +++ b/arch/powerpc/boot/dts/sbc8560.dts
> @@ -0,0 +1,202 @@
> +/*
> + * SBC8560 Device Tree Source
> + *
> + * Copyright 2007 Wind River Systems Inc.
> + *
> + * Paul Gortmaker (see MAINTAINERS for contact information)
> + *
> + * This program is free software; you can redistribute  it and/or  
> modify it
> + * under  the terms of  the GNU General  Public License as  
> published by the
> + * Free Software Foundation;  either version 2 of the  License, or  
> (at your
> + * option) any later version.
> + */
> +

can you look at converting this to a dts-v1 format.

>
> +
> +/ {
> +	model = "SBC8560";
> +	compatible = "SBC8560";
> +	#address-cells = <1>;
> +	#size-cells = <1>;

add aliases.

>
> +
> +	cpus {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		PowerPC,8560@0 {
> +			device_type = "cpu";
> +			reg = <0>;
> +			d-cache-line-size = <20>;	// 32 bytes
> +			i-cache-line-size = <20>;	// 32 bytes
> +			d-cache-size = <8000>;		// L1, 32K
> +			i-cache-size = <8000>;		// L1, 32K
> +			timebase-frequency = <0>;	// From uboot
> +			bus-frequency = <0>;
> +			clock-frequency = <0>;
> +			32-bit;
> +		};
> +	};
> +
> +	memory {
> +		device_type = "memory";
> +		reg = <00000000 20000000>;
> +	};
> +
> +	soc8560@ff700000 {
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		#interrupt-cells = <2>;
> +		device_type = "soc";
> +		ranges = <0 ff700000 00100000>;
> +		reg = <ff700000 00100000>;
> +		bus-frequency = <0>;
> +
> +		memory-controller@2000 {
> +			compatible = "fsl,8560-memory-controller";
> +			reg = <2000 1000>;
> +			interrupt-parent = <&mpic>;
> +			interrupts = <12 2>;
> +		};
> +
> +		l2-cache-controller@20000 {
> +			compatible = "fsl,8560-l2-cache-controller";
> +			reg = <20000 1000>;
> +			cache-line-size = <20>;	// 32 bytes
> +			cache-size = <40000>;	// L2, 256K
> +			interrupt-parent = <&mpic>;
> +			interrupts = <10 2>;
> +		};
> +
> +		i2c@3000 {
> +			device_type = "i2c";
> +			compatible = "fsl-i2c";
> +			reg = <3000 100>;
> +			interrupts = <2b 2>;
> +			interrupt-parent = <&mpic>;
> +			dfsrr;
> +		};

See updates for i2c controllers in the for-2.6.25 branch.

>
> +
> +		mdio@24520 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			device_type = "mdio";
> +			compatible = "gianfar";

seem updates to mdio in for-2.6.25 branch.

>
> +			reg = <24520 20>;
> +			phy0: ethernet-phy@19 {
> +				interrupt-parent = <&mpic>;
> +				interrupts = <6 1>;
> +				reg = <19>;
> +				device_type = "ethernet-phy";
> +			};
> +			phy1: ethernet-phy@1a {
> +				interrupt-parent = <&mpic>;
> +				interrupts = <7 1>;
> +				reg = <1a>;
> +				device_type = "ethernet-phy";
> +			};
> +		};
> +
> +		ethernet@24000 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			device_type = "network";
> +			model = "TSEC";
> +			compatible = "gianfar";
> +			reg = <24000 1000>;
> +			local-mac-address = [ 00 00 00 00 00 00 ];
> +			interrupts = <1d 2 1e 2 22 2>;
> +			interrupt-parent = <&mpic>;
> +			phy-handle = <&phy0>;

see updates to enet nodes.

>
> +		};
> +
> +		ethernet@25000 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			device_type = "network";
> +			model = "TSEC";
> +			compatible = "gianfar";
> +			reg = <25000 1000>;
> +			local-mac-address = [ 00 00 00 00 00 00 ];
> +			interrupts = <23 2 24 2 28 2>;
> +			interrupt-parent = <&mpic>;
> +			phy-handle = <&phy1>;
> +		};
> +

- k

^ permalink raw reply

* Re: [PATCH v2 3/4] [POWERPC][SPI] use brg-frequency for SPI in QE
From: Anton Vorontsov @ 2007-12-20 23:40 UTC (permalink / raw)
  To: Anton Vorontsov; +Cc: linuxppc-dev
In-Reply-To: <20071220203322.GC19553@localhost.localdomain>

On Thu, Dec 20, 2007 at 11:33:22PM +0300, Anton Vorontsov wrote:
> In case of QE we can use brg-frequency (which is qeclk/2).
> Thus no need to divide sysclk in the spi_mpc83xx.
> 
> This patch also adds code to use get_brgfreq() on QE chips.

> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> ---
[...]
> @@ -91,6 +91,11 @@ u32 get_brgfreq(void)
>  
>  	/* Legacy device binding -- will go away when no users are left. */
>  	node = of_find_node_by_type(NULL, "cpm");
> +	if (!node)
> +		node = of_find_compatible_node(NULL, NULL, "fsl,qe");
> +	if (!node)
> +		node = of_find_node_by_type(NULL, "qe");
> +
>  	if (node) {
>  		prop = of_get_property(node, "brg-frequency", &size);

I beg your pardon, truly. I just tested this on MPC8323E-RDB. No,
older u-boots doesn't have brg-frequency. So, I must add
of_get_property() for bus-frequency in case of failing
brg-frequency. :-/

I also found few glitches in `fsl_spi_init and users: stop using
device_type = "spi"' patch, regarding of_node_put(). Heh,
of_find_compatible_node() _puts_ `from' argument by itself, which
is not obvious at all.

I'll attach updated patches, with David's Acked-by on SPI driver
part. Other patches seem to be fine though.

Thanks,

p.s. dropping spi-devel list, because only powerpc stuff
affected.

-- 
Anton Vorontsov
email: cbou@mail.ru
backup email: ya-cbou@yandex.ru
irc://irc.freenode.net/bd2

^ permalink raw reply

* Re: [PATCH 0/4] arch/powerpc support for SBC8560 board
From: Kumar Gala @ 2007-12-20 23:49 UTC (permalink / raw)
  To: Paul Gortmaker; +Cc: linuxppc-dev
In-Reply-To: <11981624722785-git-send-email-paul.gortmaker@windriver.com>

Can we get ride of sbc85xx in arch/ppc with these patches?

- k

^ permalink raw reply

* Re: [PATCH 1/4] sbc8560: add basic support for Wind River SBC8560 as powerpc
From: Kumar Gala @ 2007-12-20 23:49 UTC (permalink / raw)
  To: Paul Gortmaker; +Cc: linuxppc-dev
In-Reply-To: <11981624732110-git-send-email-paul.gortmaker@windriver.com>


On Dec 20, 2007, at 8:54 AM, Paul Gortmaker wrote:

> This adds the basic support for the Wind River SBC8560 board,  
> implemented
> as powerpc.  It closely follows the implementation of the MPC8560ADS.
>
> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
> ---
> arch/powerpc/platforms/85xx/Kconfig   |   11 +-
> arch/powerpc/platforms/85xx/Makefile  |    1 +
> arch/powerpc/platforms/85xx/sbc8560.c |  302 ++++++++++++++++++++++++ 
> +++++++++
> 3 files changed, 312 insertions(+), 2 deletions(-)
>
> diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/ 
> platforms/85xx/Kconfig
> index 7748a3a..0eb497b 100644
> --- a/arch/powerpc/platforms/85xx/Kconfig
> +++ b/arch/powerpc/platforms/85xx/Kconfig
> @@ -38,6 +38,13 @@ config MPC85xx_DS
> 	help
> 	  This option enables support for the MPC85xx DS (MPC8544 DS) board
>
> +config SBC8560
> +	bool "Wind River SBC8560"
> +	select DEFAULT_UIMAGE
> +	select PPC_CPM_NEW_BINDING
> +	help
> +	  This option enables support for the Wind River SBC8560 board
> +
> endchoice
>
> config MPC8540
> @@ -49,7 +56,7 @@ config MPC8540
> config MPC8560
> 	bool
> 	select CPM2
> -	default y if MPC8560_ADS
> +	default y if MPC8560_ADS || SBC8560
>
> config MPC85xx
> 	bool
> @@ -59,4 +66,4 @@ config MPC85xx
> 	select FSL_PCI if PCI
> 	select SERIAL_8250_SHARE_IRQ if SERIAL_8250
> 	default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS \
> -		|| MPC85xx_MDS || MPC85xx_DS
> +		|| MPC85xx_MDS || MPC85xx_DS || SBC8560
> diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/ 
> platforms/85xx/Makefile
> index 5eca920..c3f4d01 100644
> --- a/arch/powerpc/platforms/85xx/Makefile
> +++ b/arch/powerpc/platforms/85xx/Makefile
> @@ -6,3 +6,4 @@ obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o
> obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o
> obj-$(CONFIG_MPC85xx_DS)  += mpc85xx_ds.o
> obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o
> +obj-$(CONFIG_SBC8560) += sbc8560.o
> diff --git a/arch/powerpc/platforms/85xx/sbc8560.c b/arch/powerpc/ 
> platforms/85xx/sbc8560.c
> new file mode 100644
> index 0000000..6aef38b
> --- /dev/null
> +++ b/arch/powerpc/platforms/85xx/sbc8560.c
> @@ -0,0 +1,302 @@
> +/*
> + * Wind River SBC8560 setup and early boot code.
> + *
> + * Copyright 2007 Wind River Systems Inc.
> + *
> + * By Paul Gortmaker (see MAINTAINERS for contact information)
> + *
> + * Based largely on the MPC8560ADS support - Copyright 2005  
> Freescale Inc.
> + *
> + * This program is free software; you can redistribute  it and/or  
> modify it
> + * under  the terms of  the GNU General  Public License as  
> published by the
> + * Free Software Foundation;  either version 2 of the  License, or  
> (at your
> + * option) any later version.
> + */
> +
> +#include <linux/stddef.h>
> +#include <linux/kernel.h>
> +#include <linux/pci.h>
> +#include <linux/kdev_t.h>
> +#include <linux/delay.h>
> +#include <linux/seq_file.h>
> +#include <linux/of_platform.h>
> +
> +#include <asm/system.h>
> +#include <asm/time.h>
> +#include <asm/machdep.h>
> +#include <asm/pci-bridge.h>
> +#include <asm/mpic.h>
> +#include <mm/mmu_decl.h>
> +#include <asm/udbg.h>
> +
> +#include <sysdev/fsl_soc.h>
> +#include <sysdev/fsl_pci.h>
> +
> +#ifdef CONFIG_CPM2
> +#include <asm/cpm2.h>
> +#include <sysdev/cpm2_pic.h>
> +#endif
> +
> +#ifdef CONFIG_PCI
> +static int sbc8560_exclude_device(struct pci_controller *hose,
> +				   u_char bus, u_char devfn)
> +{
> +	if (bus == 0 && PCI_SLOT(devfn) == 0)
> +		return PCIBIOS_DEVICE_NOT_FOUND;
> +	else
> +		return PCIBIOS_SUCCESSFUL;
> +}

do you really need to exclude the PHB itself?  I've fixed this for FSL  
PHBs so I don't believe you need this anymore.

>
> +#endif /* CONFIG_PCI */
> +

- k

^ permalink raw reply

* patch pci-fix-warning-in-setup-res.c-on-32-bit-platforms-with-64-bit-resources.patch added to gregkh-2.6 tree
From: gregkh @ 2007-12-20 23:37 UTC (permalink / raw)
  To: benh, greg, gregkh, linux-kernel, linuxppc-dev
In-Reply-To: <20071210063217.292B5DDE27@ozlabs.org>


This is a note to let you know that I've just added the patch titled

     Subject: PCI: Fix warning in setup-res.c on 32-bit platforms with 64-bit resources

to my gregkh-2.6 tree.  Its filename is

     pci-fix-warning-in-setup-res.c-on-32-bit-platforms-with-64-bit-resources.patch

This tree can be found at 
    http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/


>From benh@ozlabs.org Sun Dec  9 22:32:23 2007
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date: Mon, 10 Dec 2007 17:32:16 +1100
Subject: PCI: Fix warning in setup-res.c on 32-bit platforms with 64-bit resources
To: Greg Kroah-Hartman <greg@kroah.com>
Cc: linux-pci@atrey.karlin.mff.cuni.cz, <linuxppc-dev@ozlabs.org>, <linux-kernel@vger.kernel.org>
Message-ID: <20071210063217.292B5DDE27@ozlabs.org>


This adds appropriate casts to avoid a warning and print the correct
values in pr_debug.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
 drivers/pci/setup-res.c |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -51,10 +51,12 @@ pci_update_resource(struct pci_dev *dev,
 
 	pcibios_resource_to_bus(dev, &region, res);
 
-	pr_debug("  got res [%llx:%llx] bus [%lx:%lx] flags %lx for "
+	pr_debug("  got res [%llx:%llx] bus [%llx:%llx] flags %lx for "
 		 "BAR %d of %s\n", (unsigned long long)res->start,
 		 (unsigned long long)res->end,
-		 region.start, region.end, res->flags, resno, pci_name(dev));
+		 (unsigned long long)region.start,
+		 (unsigned long long)region.end,
+		 (unsigned long)res->flags, resno, pci_name(dev));
 
 	new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
 	if (res->flags & IORESOURCE_IO)


Patches currently in gregkh-2.6 which might be from benh@kernel.crashing.org are

bad/battery-class-driver.patch
driver/adb-convert-from-class_device-to-device.patch
driver/kobject-convert-hvc_console-to-use-kref-not-kobject.patch
driver/kobject-convert-hvcs-to-use-kref-not-kobject.patch
driver/kobject-convert-icom-to-use-kref-not-kobject.patch
pci/pci-fix-bus-resource-assignment-on-32-bits-with-64b-resources.patch
pci/pci-fix-warning-in-setup-res.c-on-32-bit-platforms-with-64-bit-resources.patch
usb/usb-remove-ohci-useless-masking-unmasking-of-wdh-interrupt.patch

^ permalink raw reply

* patch pci-fix-bus-resource-assignment-on-32-bits-with-64b-resources.patch added to gregkh-2.6 tree
From: gregkh @ 2007-12-20 23:37 UTC (permalink / raw)
  To: benh, greg, gregkh, linux-kernel, linuxppc-dev
In-Reply-To: <20071210063216.89DBBDDE1E@ozlabs.org>


This is a note to let you know that I've just added the patch titled

     Subject: PCI: Fix bus resource assignment on 32 bits with 64b resources

to my gregkh-2.6 tree.  Its filename is

     pci-fix-bus-resource-assignment-on-32-bits-with-64b-resources.patch

This tree can be found at 
    http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/


>From benh@ozlabs.org Sun Dec  9 22:32:23 2007
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date: Mon, 10 Dec 2007 17:32:15 +1100
Subject: PCI: Fix bus resource assignment on 32 bits with 64b resources
To: Greg Kroah-Hartman <greg@kroah.com>
Cc: linux-pci@atrey.karlin.mff.cuni.cz, <linuxppc-dev@ozlabs.org>, <linux-kernel@vger.kernel.org>
Message-ID: <20071210063216.89DBBDDE1E@ozlabs.org>


The current pci_assign_unassigned_resources() code doesn't work properly
on 32 bits platforms with 64 bits resources. The main reason is the use
of unsigned long in various places instead of resource_size_t.

This fixes it, along with some tricks to avoid casting to 64 bits on
platforms that don't need it in every printk around.

This is a pre-requisite for making powerpc use the generic code instead of
its own half-useful implementation.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
 drivers/pci/setup-bus.c |   64 ++++++++++++++++++++++++++++++------------------
 include/linux/pci.h     |    4 +--
 2 files changed, 42 insertions(+), 26 deletions(-)

--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -89,8 +89,9 @@ void pci_setup_cardbus(struct pci_bus *b
 		 * The IO resource is allocated a range twice as large as it
 		 * would normally need.  This allows us to set both IO regs.
 		 */
-		printk("  IO window: %08lx-%08lx\n",
-			region.start, region.end);
+		printk(KERN_INFO "  IO window: 0x%08lx-0x%08lx\n",
+		       (unsigned long)region.start,
+		       (unsigned long)region.end);
 		pci_write_config_dword(bridge, PCI_CB_IO_BASE_0,
 					region.start);
 		pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0,
@@ -99,8 +100,9 @@ void pci_setup_cardbus(struct pci_bus *b
 
 	pcibios_resource_to_bus(bridge, &region, bus->resource[1]);
 	if (bus->resource[1]->flags & IORESOURCE_IO) {
-		printk("  IO window: %08lx-%08lx\n",
-			region.start, region.end);
+		printk(KERN_INFO "  IO window: 0x%08lx-0x%08lx\n",
+		       (unsigned long)region.start,
+		       (unsigned long)region.end);
 		pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
 					region.start);
 		pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1,
@@ -109,8 +111,9 @@ void pci_setup_cardbus(struct pci_bus *b
 
 	pcibios_resource_to_bus(bridge, &region, bus->resource[2]);
 	if (bus->resource[2]->flags & IORESOURCE_MEM) {
-		printk("  PREFETCH window: %08lx-%08lx\n",
-			region.start, region.end);
+		printk(KERN_INFO "  PREFETCH window: 0x%08lx-0x%08lx\n",
+		       (unsigned long)region.start,
+		       (unsigned long)region.end);
 		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
 					region.start);
 		pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0,
@@ -119,8 +122,9 @@ void pci_setup_cardbus(struct pci_bus *b
 
 	pcibios_resource_to_bus(bridge, &region, bus->resource[3]);
 	if (bus->resource[3]->flags & IORESOURCE_MEM) {
-		printk("  MEM window: %08lx-%08lx\n",
-			region.start, region.end);
+		printk(KERN_INFO "  MEM window: 0x%08lx-0x%08lx\n",
+		       (unsigned long)region.start,
+		       (unsigned long)region.end);
 		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
 					region.start);
 		pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1,
@@ -145,7 +149,7 @@ pci_setup_bridge(struct pci_bus *bus)
 {
 	struct pci_dev *bridge = bus->self;
 	struct pci_bus_region region;
-	u32 l, io_upper16;
+	u32 l, bu, lu, io_upper16;
 
 	DBG(KERN_INFO "PCI: Bridge: %s\n", pci_name(bridge));
 
@@ -159,7 +163,8 @@ pci_setup_bridge(struct pci_bus *bus)
 		/* Set up upper 16 bits of I/O base/limit. */
 		io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
 		DBG(KERN_INFO "  IO window: %04lx-%04lx\n",
-				region.start, region.end);
+		    (unsigned long)region.start,
+		    (unsigned long)region.end);
 	}
 	else {
 		/* Clear upper 16 bits of I/O base/limit. */
@@ -180,8 +185,9 @@ pci_setup_bridge(struct pci_bus *bus)
 	if (bus->resource[1]->flags & IORESOURCE_MEM) {
 		l = (region.start >> 16) & 0xfff0;
 		l |= region.end & 0xfff00000;
-		DBG(KERN_INFO "  MEM window: %08lx-%08lx\n",
-				region.start, region.end);
+		DBG(KERN_INFO "  MEM window: 0x%08lx-0x%08lx\n",
+		    (unsigned long)region.start,
+		    (unsigned long)region.end);
 	}
 	else {
 		l = 0x0000fff0;
@@ -195,12 +201,18 @@ pci_setup_bridge(struct pci_bus *bus)
 	pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
 
 	/* Set up PREF base/limit. */
+	bu = lu = 0;
 	pcibios_resource_to_bus(bridge, &region, bus->resource[2]);
 	if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
 		l = (region.start >> 16) & 0xfff0;
 		l |= region.end & 0xfff00000;
-		DBG(KERN_INFO "  PREFETCH window: %08lx-%08lx\n",
-				region.start, region.end);
+#ifdef CONFIG_RESOURCES_64BIT
+		bu = region.start >> 32;
+		lu = region.end >> 32;
+#endif
+		DBG(KERN_INFO "  PREFETCH window: 0x%016llx-0x%016llx\n",
+		    (unsigned long long)region.start,
+		    (unsigned long long)region.end);
 	}
 	else {
 		l = 0x0000fff0;
@@ -208,8 +220,9 @@ pci_setup_bridge(struct pci_bus *bus)
 	}
 	pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
 
-	/* Clear out the upper 32 bits of PREF base. */
-	pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
+	/* Set the upper 32 bits of PREF base & limit. */
+	pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
+	pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
 
 	pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
 }
@@ -323,8 +336,8 @@ static void pbus_size_io(struct pci_bus 
 static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
 {
 	struct pci_dev *dev;
-	unsigned long min_align, align, size;
-	unsigned long aligns[12];	/* Alignments from 1Mb to 2Gb */
+	resource_size_t min_align, align, size;
+	resource_size_t aligns[12];	/* Alignments from 1Mb to 2Gb */
 	int order, max_order;
 	struct resource *b_res = find_free_bus_resource(bus, type);
 
@@ -340,7 +353,7 @@ static int pbus_size_mem(struct pci_bus 
 		
 		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
 			struct resource *r = &dev->resource[i];
-			unsigned long r_size;
+			resource_size_t r_size;
 
 			if (r->parent || (r->flags & mask) != type)
 				continue;
@@ -350,10 +363,10 @@ static int pbus_size_mem(struct pci_bus 
 			order = __ffs(align) - 20;
 			if (order > 11) {
 				printk(KERN_WARNING "PCI: region %s/%d "
-				       "too large: %llx-%llx\n",
+				       "too large: 0x%016llx-0x%016llx\n",
 					pci_name(dev), i,
-					(unsigned long long)r->start,
-					(unsigned long long)r->end);
+				       (unsigned long long)r->start,
+				       (unsigned long long)r->end);
 				r->flags = 0;
 				continue;
 			}
@@ -372,8 +385,11 @@ static int pbus_size_mem(struct pci_bus 
 	align = 0;
 	min_align = 0;
 	for (order = 0; order <= max_order; order++) {
-		unsigned long align1 = 1UL << (order + 20);
-
+#ifdef CONFIG_RESOURCES_64BIT
+		resource_size_t align1 = 1ULL << (order + 20);
+#else
+		resource_size_t align1 = 1U << (order + 20);
+#endif
 		if (!align)
 			min_align = align1;
 		else if (ALIGN(align + min_align, min_align) < align1)
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -309,8 +309,8 @@ struct pci_raw_ops {
 extern struct pci_raw_ops *raw_pci_ops;
 
 struct pci_bus_region {
-	unsigned long start;
-	unsigned long end;
+	resource_size_t start;
+	resource_size_t end;
 };
 
 struct pci_dynids {


Patches currently in gregkh-2.6 which might be from benh@kernel.crashing.org are

bad/battery-class-driver.patch
driver/adb-convert-from-class_device-to-device.patch
driver/kobject-convert-hvc_console-to-use-kref-not-kobject.patch
driver/kobject-convert-hvcs-to-use-kref-not-kobject.patch
driver/kobject-convert-icom-to-use-kref-not-kobject.patch
pci/pci-fix-bus-resource-assignment-on-32-bits-with-64b-resources.patch
pci/pci-fix-warning-in-setup-res.c-on-32-bit-platforms-with-64-bit-resources.patch
usb/usb-remove-ohci-useless-masking-unmasking-of-wdh-interrupt.patch

^ permalink raw reply

* Re: More patches added to for-2.6.25 and master branches of powerpc.git
From: Michael Neuling @ 2007-12-20 23:22 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <18282.19253.485799.233476@cargo.ozlabs.ibm.com>

Paulus,

Can you take the crash shutdown hook patches as well?

http://patchwork.ozlabs.org/linuxppc/patch?person=414&id=15546
http://patchwork.ozlabs.org/linuxppc/patch?person=414&id=15547

Mikey


In message <18282.19253.485799.233476@cargo.ozlabs.ibm.com> you wrote:
> Andre Detsch (1):
>       [POWERPC] cell: safer of_has_vicinity routine
> 
> Balbir Singh (1):
>       [POWERPC] Fake NUMA emulation for PowerPC
> 
> Benjamin Herrenschmidt (20):
>       [POWERPC] pci32: Remove bogus alignment message
>       [POWERPC] pci32: Use generic pci_assign_unassign_resources
>       [POWERPC] pci32: Remove PowerMac P2P bridge IO hack
>       [POWERPC] pci32: Add flags modifying the PCI code behaviour
>       [POWERPC] pci32: Remove obsolete PowerMac bus number hack
>       [POWERPC] pci32: Add platform option to enable /proc PCI domains
>       [POWERPC] Merge pcibios_resource_to_bus/bus_to_resource
>       [POWERPC] Merge PCI resource fixups
>       [POWERPC] Merge PCI resource allocation & assignment
>       [POWERPC] fix iSeries PCI resource management
>       [POWERPC] Updates/fixes to 32 bits pcibios_enable_device()
>       [POWERPC] Merge 32 and 64 bits pcibios_enable_device
>       [POWERPC] Fixup powermac enable device hook
>       [POWERPC] Clear pci_probe_only on 64 bits PowerMac
>       [POWERPC] Various fixes to pcibios_enable_device()
>       [POWERPC] Enable self-view of the HT host bridge on PowerMac G5
>       [POWERPC] Improve resource setup of PowerMac G5 HT bridge
>       [POWERPC] Fixup skipping of PowerMac PCI<->PCI bridge "closed" resource
s
>       [POWERPC] Disable PCI IO/Mem on a device when resources can't be alloca
ted
>       [POWERPC] Fix PCI IRQ fallback code to not map IRQ 0
> 
> Bob Nelson (1):
>       [POWERPC] OProfile: fix cbe pm signal routing problem
> 
> Cyrill Gorcunov (1):
>       [POWERPC] CHRP: Fix possible NULL pointer dereference
> 
> David Gibson (2):
>       [POWERPC] Merge dtc upstream source
>       [POWERPC] Use embedded dtc in kernel builds
> 
> Grant Likely (1):
>       [POWERPC] Add machine initcall macros
> 
> Ishizaki Kou (3):
>       [POWERPC] cell: add missing '\n'
>       [POWERPC] Cleanup calling mmio_nvram_init
>       [POWERPC] celleb: Split machine definition
> 
> Jeremy Kerr (6):
>       [POWERPC] cell: export force_sig_info()
>       [POWERPC] cell: handle kernel SLB setup in spu_base.c
>       [POWERPC] cell: use spu_load_slb for SLB setup
>       [POWERPC] cell: add spu_64k_pages_available() check
>       [POWERPC] cell: handle SPE kernel mappings that cross segment boundarie
s
>       [POWERPC] cell: catch errors from sysfs_create_group()
> 
> Jochen Friedrich (2):
>       [POWERPC] Add support for PORTA and PORTB odr registers
>       [POWERPC] Move CPM command handling into the cpm drivers
> 
> Johannes Berg (3):
>       [POWERPC] adb: Replace sleep notifier with platform driver suspend/resu
me hooks
>       [POWERPC] via-pmu: Kill sleep notifiers completely
>       [POWERPC] powermac: Use generic suspend code
> 
> Jon Loeliger (3):
>       [POWERPC] 8xxx: Convert #include of asm/of_{platform, device}.h into li
nux/of_{platform, device}.h.
>       [POWERPC] 86xx: Add aliases node to 8641hpcn DTS file.
>       [POWERPC] cell: Convert #include of asm/of_{platform, device}.h into li
nux/of_{platform, device}.h.
> 
> Julia Lawall (3):
>       [POWERPC] arch/ppc: Remove an unnecessary pci_dev_put
>       [POWERPC] arch/powerpc: Add missing of_node_put
>       [POWERPC] cell/cbe_regs.c: Add missing of_node_put
> 
> Kevin Corry (1):
>       [POWERPC] perfmon2: make pm_interval register read/write
> 
> Kumar Gala (5):
>       [POWERPC] Add SPRN for Embedded registers specified in PowerISA 2.04
>       [POWERPC] Emulate isel (Integer Select) instruction
>       [POWERPC] FSL: I2C device tree cleanups
>       [POWERPC] FSL: enet device tree cleanups
>       [POWERPC] FSL: Added aliases node to device trees
> 
> Li Yang (5):
>       [POWERPC] add e300c4 entry to cputable
>       [POWERPC] ipic: add new interrupts introduced by new chip
>       [POWERPC] 83xx: Add platform support for MPC837x MDS board
>       [POWERPC] 83xx: Add MPC837x MDS default kernel configuration
>       [POWERPC] ipic: ack only for edge interrupts
> 
> Li Zefan (1):
>       [POWERPC] Don't cast a struct pointer to list_head pointer
> 
> Lucas Woods (2):
>       [POWERPC] arch/powerpc: Remove duplicate includes
>       [POWERPC] arch/ppc: Remove duplicate includes
> 
> Michael Ellerman (1):
>       [POWERPC] Implement pci_set_dma_mask() in terms of the dma_ops
> 
> Milton Miller (6):
>       [POWERPC] Push down or eliminate smp_processor_id calls in xics code
>       [POWERPC] init_decrementer_clockevent can be static __init
>       [POWERPC] Use __get_cpu_var in time.c
>       [POWERPC] Timer interrupt: use a struct for two per_cpu varables
>       [POWERPC] Depend on ->initialized in calc_steal_time
>       [POWERPC] Optimize account_system_vtime
> 
> Olof Johansson (3):
>       [POWERPC] MPIC: Minor optimization of ipi handler
>       [POWERPC] pasemi: Implement MSI support
>       [POWERPC] holly.c: Remove unnecessary include of linux/ide.h
> 
> Paul Mackerras (5):
>       [POWERPC] Convert media-bay.c to use the kthread API
>       [POWERPC] Convert adb.c to use kthread API and not spin on ADB requests
>       [POWERPC] Convert therm_pm72.c to use the kthread API
>       [POWERPC] Convert therm_windtunnel.c to use the kthread API
>       [POWERPC] Fix sleep on powerbook 3400
> 
> Scott Wood (5):
>       [POWERPC] 8xx: Convert mpc866ads to the new device binding.
>       [POWERPC] 83xx: mpc834x_mds: Fix whitespace and call of_platform_bus_pr
obe().
>       [POWERPC] 83xx: mpc8313erdb: Fix whitespace.
>       [POWERPC] wrapper: Rename offset in offset_devp()
>       [POWERPC] wrapper: Treat NULL as root node in devp_offset; add devp_off
set_find()
> 
> Stephen Rothwell (2):
>       [POWERPC] iSeries: Fix unregistering HV event handlers
>       [POWERPC] Stop the TOC overflowing for large builds
> 
> Timur Tabi (4):
>       [POWERPC] 86xx: fix guts_set_dmacr() and add guts_set_pmuxcr_dma() to i
mmap_86xx.h
>       [POWERPC] QE: change qe_setbrg() to take an enum qe_clock instead of an
 integer
>       [POWERPC] qe: add function qe_clock_source()
>       [POWERPC] ucc_geth: use rx-clock-name and tx-clock-name device tree pro
perties
> 
> joe@perches.com (4):
>       [POWERPC] arch/powerpc/: Spelling fixes
>       [POWERPC] include/asm-powerpc/: Spelling fixes
>       [POWERPC] arch/ppc/: Spelling fixes
>       [POWERPC] include/asm-ppc/: Spelling fixes
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
> 

^ permalink raw reply

* Re: [PATCH 1/4] sbc8560: add basic support for Wind River SBC8560 as powerpc
From: Stephen Rothwell @ 2007-12-20 23:14 UTC (permalink / raw)
  To: Paul Gortmaker; +Cc: linuxppc-dev
In-Reply-To: <11981624732110-git-send-email-paul.gortmaker@windriver.com>

[-- Attachment #1: Type: text/plain, Size: 1354 bytes --]

Hi Paul,

Just a couple of comments.

On Thu, 20 Dec 2007 09:54:29 -0500 Paul Gortmaker <paul.gortmaker@windriver.com> wrote:
>
> +++ b/arch/powerpc/platforms/85xx/sbc8560.c
> +static void cpm2_cascade(unsigned int irq, struct irq_desc *desc)
> +{
> +	int cascade_irq;
> +
> +	while ((cascade_irq = cpm2_get_irq()) >= 0) {
> +		generic_handle_irq(cascade_irq);
> +	}

The braces are unnecessary.

> +static void __init sbc8560_pic_init(void)
> +{
> +	struct mpic *mpic;
> +	struct resource r;
> +	struct device_node *np = NULL;
> +#ifdef CONFIG_CPM2
> +	int irq;
> +#endif
> +
> +	np = of_find_node_by_type(np, "open-pic");
> +
> +	if (np == NULL) {

We often say "if (!np)" and leave out the blank line above.

> +	if(of_address_to_resource(np, 0, &r)) {
          ^
Put a space here.

> +#ifdef CONFIG_CPM2
> +	/* Setup CPM2 PIC */
> +	np = of_find_compatible_node(NULL, NULL, "fsl,cpm2-pic");
> +	if (np == NULL) {
> +		printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n");
> +		return;
> +	}
> +	irq = irq_of_parse_and_map(np, 0);
> +
> +	cpm2_pic_init(np);

Need an of_node_pit(np) - cpm2_pic_init() does its own of_node_get.

> +static struct cpm_pin sbc8560_pins[] = {

const?

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [PATCH] ASoC drivers for the Freescale MPC8610 SoC
From: Jon Smirl @ 2007-12-20 23:13 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, alsa-devel, Timur Tabi
In-Reply-To: <476AF061.1030605@freescale.com>

On 12/20/07, Scott Wood <scottwood@freescale.com> wrote:
> Timur Tabi wrote:
> > Jon Smirl wrote:
> >
> >> mpc5200 does it like this:
> >> of_platform_bus_probe(NULL, NULL, NULL);
> >
> > I think that tells the OF base code to probe everything in the device tree,
> > which is probably overkill.  I think fsl_soc.c covers most of the device tree,
> > but the SSI is not defined in fsl_soc.c.
>
> Not quite; it tells it to use a built-in list of bus matches.  Most of
> which are device_type-based, FWIW.

Here's the default. Using NULL would work.

static struct of_device_id of_default_bus_ids[] = {
        { .type = "soc", },
        { .compatible = "soc", },
        { .type = "spider", },
        { .type = "axon", },
        { .type = "plb5", },
        { .type = "plb4", },
        { .type = "opb", },
        { .type = "ebc", },
        {},
};


>
> -Scott
>


-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply

* Re: [spi-devel-general] [PATCH v2 3/4] [POWERPC][SPI] use brg-frequency for SPI in QE
From: David Brownell @ 2007-12-20 23:04 UTC (permalink / raw)
  To: spi-devel-general; +Cc: linuxppc-dev
In-Reply-To: <20071220203322.GC19553@localhost.localdomain>

On Thursday 20 December 2007, Anton Vorontsov wrote:
> In case of QE we can use brg-frequency (which is qeclk/2).
> Thus no need to divide sysclk in the spi_mpc83xx.
> 
> This patch also adds code to use get_brgfreq() on QE chips.
> 
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> ---
>  arch/powerpc/sysdev/fsl_soc.c |   37 ++++++++++++++++++++++++-------------
>  drivers/spi/spi_mpc83xx.c     |    6 +-----
>  2 files changed, 25 insertions(+), 18 deletions(-)

For the SPI parts:

Acked-by: David Brownell <dbrownell@users.sourceforge.net>

Though it all looks a bit confusing to me, and I wonder
if the OF docs would make it less so.

^ permalink raw reply

* Re: [PATCH] ASoC drivers for the Freescale MPC8610 SoC
From: Scott Wood @ 2007-12-20 22:44 UTC (permalink / raw)
  To: Timur Tabi; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <476AEF47.8040802@freescale.com>

Timur Tabi wrote:
> Jon Smirl wrote:
> 
>> mpc5200 does it like this:
>> of_platform_bus_probe(NULL, NULL, NULL);
> 
> I think that tells the OF base code to probe everything in the device tree, 
> which is probably overkill.  I think fsl_soc.c covers most of the device tree, 
> but the SSI is not defined in fsl_soc.c.

Not quite; it tells it to use a built-in list of bus matches.  Most of 
which are device_type-based, FWIW.

-Scott

^ permalink raw reply

* Re: [PATCH] ASoC drivers for the Freescale MPC8610 SoC
From: Scott Wood @ 2007-12-20 22:43 UTC (permalink / raw)
  To: Timur Tabi; +Cc: Olof Johansson, linuxppc-dev, alsa-devel
In-Reply-To: <476AEEB3.2010403@freescale.com>

Timur Tabi wrote:
> Olof Johansson wrote:
> 
>>> I was just following the example from another board file.  However, the 'soc' 
>>> node in the device tree does not have a compatible property, so I don't how to 
>>> change this.
>> Then add an appropriate compatible entry to it, please.
> 
> None of the SOC nodes in any DTS have a "compatible" entry.

Not quite true; ep88xc, mpc8272ads, and pq2fads have them.

-Scott

^ permalink raw reply

* Re: [PATCH] ASoC drivers for the Freescale MPC8610 SoC
From: Timur Tabi @ 2007-12-20 22:40 UTC (permalink / raw)
  To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <9e4733910712201438u2165aa77t8eab91bccb4c5bda@mail.gmail.com>

Jon Smirl wrote:

> mpc5200 does it like this:
> of_platform_bus_probe(NULL, NULL, NULL);

I think that tells the OF base code to probe everything in the device tree, 
which is probably overkill.  I think fsl_soc.c covers most of the device tree, 
but the SSI is not defined in fsl_soc.c.

-- 
Timur Tabi
Linux kernel developer at Freescale

^ permalink raw reply

* Re: [PATCH] ASoC drivers for the Freescale MPC8610 SoC
From: Jon Smirl @ 2007-12-20 22:38 UTC (permalink / raw)
  To: Timur Tabi; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <476AED87.3090703@freescale.com>

On 12/20/07, Timur Tabi <timur@freescale.com> wrote:
> Jon Smirl wrote:
>
> > How is of_platform_bus_probe() supposed to be called? mpc5200/virtex
> > call it with three NULLs. Is it necessary to name all of the buses in
> > a of_device_id? If it's not necessary to list the buses the
> > of_platform_bus_probe() call could be moved to common code.
>
> I added the above code because it is the only way I could get my SSI nodes to be
> probed.  If there's a better way to do it, I'm all ears.  I just copied that
> code from the mpc836x_mds.c platform file.

mpc5200 does it like this:
of_platform_bus_probe(NULL, NULL, NULL);

No need for the ids.


>
> > Are these buses?
> >         { .compatible = "ibm,plb4", },
> >         { .compatible = "ibm,opb", },
> >         { .compatible = "ibm,ebc", },
>
> I have no idea.
>
> > Could of_platform_bus_probe() be simplified? No one uses the first and
> > third parameters.
>
> Maybe, but that's not a discussion for this thread!
>
> --
> Timur Tabi
> Linux kernel developer at Freescale
>


-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply

* Re: [PATCH] ASoC drivers for the Freescale MPC8610 SoC
From: Timur Tabi @ 2007-12-20 22:37 UTC (permalink / raw)
  To: Olof Johansson; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <20071220223943.GA24138@lixom.net>

Olof Johansson wrote:

>> I was just following the example from another board file.  However, the 'soc' 
>> node in the device tree does not have a compatible property, so I don't how to 
>> change this.
> 
> Then add an appropriate compatible entry to it, please.

None of the SOC nodes in any DTS have a "compatible" entry.  I understand the 
issue, but you're asking me to fix a larger problem, one that is beyond the 
scope of this patch.  You're saying that *all* SOC needs are incorrectly defined 
and need to be probed differently.

-- 
Timur Tabi
Linux kernel developer at Freescale

^ permalink raw reply

* Re: [PATCH] ASoC drivers for the Freescale MPC8610 SoC
From: Olof Johansson @ 2007-12-20 22:39 UTC (permalink / raw)
  To: Timur Tabi; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <476A7B23.2040905@freescale.com>

On Thu, Dec 20, 2007 at 08:24:35AM -0600, Timur Tabi wrote:
> Olof Johansson wrote:
> 
> >> +static struct of_device_id mpc8610_ids[] = {
> >> +	{ .type = "soc", },
> >> +	{}
> > 
> > Please scan based on compatible instead of device_type.
> 
> I was just following the example from another board file.  However, the 'soc' 
> node in the device tree does not have a compatible property, so I don't how to 
> change this.

Then add an appropriate compatible entry to it, please.

> > Do you ever anticipate having other dma users on the system, such as
> > memcpy offload? You'll probably need allocation support for channels
> > when that day comes (I ended up writing a simple library for dma channel
> > management for that very reason on my platform).
> 
> Yes, I plan on updating this driver to work with the standard Freescale "Elo" 
> device driver, but that will have to wait until that code is in the kernel and 
> stabilized.  The SSI is limited in which DMA channels it can use, anyway.

Ok.


-Olof

^ permalink raw reply

* Re: [PATCH] ASoC drivers for the Freescale MPC8610 SoC
From: Timur Tabi @ 2007-12-20 22:32 UTC (permalink / raw)
  To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <9e4733910712201429q5845e786yb2ecb3ce9c8b7871@mail.gmail.com>

Jon Smirl wrote:

> How is of_platform_bus_probe() supposed to be called? mpc5200/virtex
> call it with three NULLs. Is it necessary to name all of the buses in
> a of_device_id? If it's not necessary to list the buses the
> of_platform_bus_probe() call could be moved to common code.

I added the above code because it is the only way I could get my SSI nodes to be 
probed.  If there's a better way to do it, I'm all ears.  I just copied that 
code from the mpc836x_mds.c platform file.

> Are these buses?
>         { .compatible = "ibm,plb4", },
>         { .compatible = "ibm,opb", },
>         { .compatible = "ibm,ebc", },

I have no idea.

> Could of_platform_bus_probe() be simplified? No one uses the first and
> third parameters.

Maybe, but that's not a discussion for this thread!

-- 
Timur Tabi
Linux kernel developer at Freescale

^ permalink raw reply

* Re: [PATCH] ASoC drivers for the Freescale MPC8610 SoC
From: Jon Smirl @ 2007-12-20 22:29 UTC (permalink / raw)
  To: Timur Tabi; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <11981089894052-git-send-email-timur@freescale.com>

On 12/19/07, Timur Tabi <timur@freescale.com> wrote:

> +static struct of_device_id mpc8610_ids[] = {
> +       { .type = "soc", },
> +       {}
> +};
> +
> +static int __init mpc8610_declare_of_platform_devices(void)
> +{
> +       if (!machine_is(mpc86xx_hpcd))
> +               return 0;
> +
> +       /* Without this call, the SSI device driver won't get probed. */
> +       of_platform_bus_probe(NULL, mpc8610_ids, NULL);
> +
> +       return 0;
> +}
> +device_initcall(mpc8610_declare_of_platform_devices);

How is of_platform_bus_probe() supposed to be called? mpc5200/virtex
call it with three NULLs. Is it necessary to name all of the buses in
a of_device_id? If it's not necessary to list the buses the
of_platform_bus_probe() call could be moved to common code.

Are these buses?
        { .compatible = "ibm,plb4", },
        { .compatible = "ibm,opb", },
        { .compatible = "ibm,ebc", },

Could of_platform_bus_probe() be simplified? No one uses the first and
third parameters.

-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply

* Re: Oops: Kernel access of bad area
From: Nathan Lynch @ 2007-12-20 21:47 UTC (permalink / raw)
  To: Christian Kujau; +Cc: linuxppc-dev
In-Reply-To: <alpine.DEB.0.99999.0712192301220.6696@sheep.housecafe.de>

Christian Kujau wrote:
> Hi,
> 
> I started some x11 application (here: firefox) through an ssh connection 
> on a remote host and it crashed somehow. OK, no biggie, killed the 
> application and be done with it. However, I noticed that the load of the 
> machine is now constantly at 7. It's an iBook G4, has nothing to do, 
> disks, cpu, netwokr is idle and load is usually < 1. Now it's not
> slow to work or anyhow sluggish, but only the load is at 7 after the 
> application crashed. When I looked into dmesg I saw:
> 
> [84983.750977] Unable to handle kernel paging request for data at address 0x4815d000
> [84983.751046] Faulting instruction address: 0xc0012090
> [84983.751157] Oops: Kernel access of bad area, sig: 11 [#1]
> [84983.751178] PREEMPT PowerMac
> [84983.751214] Modules linked in: nls_iso8859_15 nls_cp850 vfat fat isofs nls_base zlib_inflate radeon drm snd_powermac snd_pcm snd_timer snd soundcore snd_page_alloc fuse firewire_ohci firewire_core crc_itu_t ide_cd cdrom ssb bcm43xx rng_core ieee80211softmac uninorth_agp ieee80211 ieee80211_crypt agpgart
> [84983.751750] NIP: c0012090 LR: c00165fc CTR: 00000080
> [84983.751786] REGS: cea65b30 TRAP: 0300   Not tainted  (2.6.24-rc5)
> [84983.751805] MSR: 00009032 <EE,ME,IR,DR>  CR: 24822282  XER: 00000000
> [84983.751946] DAR: 4815d000, DSISR: 40000000
> [84983.751965] TASK = ee372670[9138] 'firefox-bin' THREAD: cea64000
> [84983.751984] GPR00: e62b3a00 cea65be0 ee372670 4815d000 00000080 1bc0c181 4815d000 ffffffff
> [84983.752148] GPR08: 00010008 e62b3a00 00000000 c045f000 24822288 1002ea3c cea67690 ce954000
> [84983.752315] GPR16: c0420000 c03f6400 cea65cac cea65ca8 c0440000 ce974480 c07d7180 ceba2280
> [84983.752468] GPR24: e62b3a00 e62b3a50 4815d000 00000574 ceba2280 4815d000 1bc0c181 c07d7180
> [84983.752665] NIP [c0012090] __flush_dcache_icache+0x14/0x40
> [84983.752716] LR [c00165fc] update_mmu_cache+0x11c/0x120

Better to include the full stack trace in such reports, but here it
is:

 NIP [c0012090] __flush_dcache_icache+0x14/0x40
 LR [c00165fc] update_mmu_cache+0x11c/0x120
 Call Trace:
 [cea65be0] [ce8c1000] 0xce8c1000 (unreliable)
 [cea65c00] [c0075868] handle_mm_fault+0x39c/0x7f8
 [cea65c50] [c0075dec] get_user_pages+0x128/0x398
 [cea65ca0] [c00c5e18] elf_core_dump+0xb64/0xc28
 [cea65d40] [c0091e64] do_coredump+0x754/0x788
 [cea65e50] [c003cb20] get_signal_to_deliver+0x2dc/0x3fc
 [cea65e80] [c000a678] do_signal+0x48/0x28c
 [cea65f40] [c0012cb4] do_user_signal+0x74/0xc4
 --- Exception: c00 at 0xfd36ea4
     LR = 0x10012018
 Instruction dump:
 4d820020 7c8903a6 7c001bac 38630020 4200fff8 7c0004ac 4e800020 60000000
 54630026 38800080 7c8903a6 7c661b78 <7c00186c> 38630020 4200fff8 7c0004ac

So it looks like the kernel oopsed while firefox was dumping core,
yuck.

> This is the first time that this happened on this iBook, and it was not 
> reproducible so far (well, it happened just a few minutes ago). Is this 
> something to worry about? Or should I file this under "well, shit 
> happens"?

It's a real bug.  Hopefully someone on the list can help...

^ permalink raw reply

* [RESEND DTC PATCH 2/2] Add support for binary includes.
From: Scott Wood @ 2007-12-20 19:52 UTC (permalink / raw)
  To: jdl; +Cc: linuxppc-dev, u-boot-users

A property's data can be populated with a file's contents
as follows:

node {
	prop = /bin-include/ "path/to/data";
};

Search paths are not yet implemented; non-absolute lookups are relative to
the directory from which dtc was invoked.

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
Apologies if you get this twice, but AFAICT the original got eaten by our
mail server.

 dtc-lexer.l  |    6 ++++++
 dtc-parser.y |   26 ++++++++++++++++++++++++++
 dtc.h        |    1 +
 3 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/dtc-lexer.l b/dtc-lexer.l
index c811b22..1f3e6d6 100644
--- a/dtc-lexer.l
+++ b/dtc-lexer.l
@@ -190,6 +190,12 @@ static int dts_version; /* = 0 */
 			return DT_PROPNODENAME;
 		}
 
+"/bin-include/"	{
+			yylloc.filenum = srcpos_filenum;
+			yylloc.first_line = yylineno;
+			DPRINT("Binary Include\n");
+			return DT_BININCLUDE;
+		}
 
 <*>[[:space:]]+	/* eat whitespace */
 
diff --git a/dtc-parser.y b/dtc-parser.y
index 4a0181d..c7ed715 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -21,6 +21,8 @@
 %locations
 
 %{
+#include <sys/stat.h>
+
 #include "dtc.h"
 #include "srcpos.h"
 
@@ -58,6 +60,7 @@ extern struct boot_info *the_boot_info;
 %token <data> DT_STRING
 %token <labelref> DT_LABEL
 %token <labelref> DT_REF
+%token DT_BININCLUDE
 
 %type <data> propdata
 %type <data> propdataprefix
@@ -196,6 +199,29 @@ propdata:
 		{
 			$$ = data_add_marker($1, REF_PATH, $2);
 		}
+	| propdataprefix DT_BININCLUDE DT_STRING
+		{
+			struct stat st;
+			FILE *f;
+			int fd;
+			
+			f = fopen($3.val, "rb");
+			if (!f) {
+				yyerrorf("Cannot open file \"%s\": %s",
+				         $3.val, strerror(errno));
+				YYERROR;
+			}
+
+			fd = fileno(f);
+			if (fstat(fd, &st) < 0) {
+				yyerrorf("Cannot stat file \"%s\": %s",
+				         $3.val, strerror(errno));
+				YYERROR;
+			}
+
+			$$ = data_merge($1, data_copy_file(f, st.st_size));
+			fclose(f);
+		}
 	| propdata DT_LABEL
 		{
 			$$ = data_add_marker($1, LABEL, $2);
diff --git a/dtc.h b/dtc.h
index 9b89689..87b5bb1 100644
--- a/dtc.h
+++ b/dtc.h
@@ -138,6 +138,7 @@ struct data data_grow_for(struct data d, int xlen);
 struct data data_copy_mem(const char *mem, int len);
 struct data data_copy_escape_string(const char *s, int len);
 struct data data_copy_file(FILE *f, size_t len);
+struct data data_bin_include(const char *filename);
 
 struct data data_append_data(struct data d, const void *p, int len);
 struct data data_insert_at_marker(struct data d, struct marker *m,
-- 
1.5.3

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox