* Re: a problem of kernel-module version mismatch.
From: Arnd Bergmann @ 2006-06-08 15:25 UTC (permalink / raw)
To: Ming Liu; +Cc: linuxppc-embedded
In-Reply-To: <BAY110-F11CA5067CA16CB9E95E997B28B0@phx.gbl>
On Thursday 08 June 2006 15:52, Ming Liu wrote:
> >The easiest way is usually to put the driver in your source tree
> >and compile everything together. That also makes it easier to
> >distribute the complete source tree to your users.
>=20
> Sorry that I am a novice in Linux. I don't know how can I put the driver =
in=20
> my source tree and compile everything together. It looks like that there =
is=20
> no option in the menuconfig to choose a specially customed peripheral. So=
I=20
> think I only can include the customed peripheral as a module. Could you=20
> please say in a detail on how to do that?=20
The most simple way would be to put it into linux/drivers/misc and add it
to the Makefile in there.
> > > insmod: unresolved symbol XIo_In32
> > > insmod: unresolved symbol XIO_Out32
> >
> >that looks like part of your module is missing. Try to find where thses
> >functions are defined in there and why that isn't compiled.
>=20
> It's very strange because I have checked the source. In the header file o=
f=20
> xio.h, there are the following sentences,
>=20
> /************************** Function Prototypes=20
> ******************************/
>=20
> /* The following functions allow the software to be transportable across
> =A0* processors which may use memory mapped I/O or I/O which is mapped in=
to a
> =A0* seperate address space such as X86. =A0The functions are better suit=
ed for
> =A0* debugging and are therefore the default implementation. Macros can=20
> instead
> =A0* be used if USE_IO_MACROS is defined.
> =A0*/
> #ifndef USE_IO_MACROS
The comment tells you that you either need to implement these functions
youself or #define USE_IO_MACROS in the code before this.
> /* Functions */
> Xuint8 XIo_In8(XIo_Address InAddress);
> Xuint16 XIo_In16(XIo_Address InAddress);
> Xuint32 XIo_In32(XIo_Address InAddress);
>=20
> void XIo_Out8(XIo_Address OutAddress, Xuint8 Value);
> void XIo_Out16(XIo_Address OutAddress, Xuint16 Value);
> void XIo_Out32(XIo_Address OutAddress, Xuint32 Value);
>=20
> #else
>=20
> /* The following macros allow optimized I/O operations for memory mapped=
=20
> I/O
> =A0* Note that the SYNCHRONIZE_IO may be moved by the compiler during
> =A0* optimization.
> =A0*/
>=20
> #define XIo_In8(InputPtr) =A0(*(volatile Xuint8 =A0*)(InputPtr));=20
> SYNCHRONIZE_IO;
> #define XIo_In16(InputPtr) (*(volatile Xuint16 *)(InputPtr));=20
> SYNCHRONIZE_IO;
> #define XIo_In32(InputPtr) (*(volatile Xuint32 *)(InputPtr));=20
> SYNCHRONIZE_IO;
>=20
> #define XIo_Out8(OutputPtr, Value) =A0\
> =A0 =A0 { (*(volatile Xuint8 =A0*)(OutputPtr) =3D Value); SYNCHRONIZE_IO;=
}
> #define XIo_Out16(OutputPtr, Value) \
> =A0 =A0 { (*(volatile Xuint16 *)(OutputPtr) =3D Value); SYNCHRONIZE_IO; }
> #define XIo_Out32(OutputPtr, Value) \
> =A0 =A0 { (*(volatile Xuint32 *)(OutputPtr) =3D Value); SYNCHRONIZE_IO; }
>=20
> #endif
These macros are probably broken on powerpc.
>=20
> I think these are the defination of XIo_In32 and XIo_Out32. Also, during=
=20
> the compilation, there is no error to complain that "XIo_In32 or XIo_Out3=
2=20
> undeclared".=20
>=20
I would suggest you remove that part of the header file completely, and
replace it with:
#define XIo_In32(p) in_le32(x)
#define XIO_Out32(p,v) out_le32(p, v)
Arnd <><
^ permalink raw reply
* A Couple of 2.6/Xilinx Questions
From: rakirtley @ 2006-06-08 14:45 UTC (permalink / raw)
To: linuxppc-embedded
All,
I've been attempting to get a 2.6 version running on the Xilinx ML403 and only really need the ethernet and compact flash devices at this point. I've tried versions from mvista, kernel.org, etc; all only have the serial8250 device enabled. Obviously adding devices is a lot of work and it appears that you all have already made great progress enabling ethernet.
Are any of the advanced versions upon which you all work generally available? If so could you please provide a location? Apologies in advance for polluting your emailboxes and thanks in advance for any help/pointers that you can provide. I'll be more than happy to share any mods that I make (if any)
Rance Kirtley
Applied Systems Intelligence
Roswell, GA USA
^ permalink raw reply
* Re: a problem of kernel-module version mismatch.
From: Ming Liu @ 2006-06-08 13:52 UTC (permalink / raw)
To: arnd.bergmann; +Cc: linuxppc-embedded
In-Reply-To: <200606081536.15145.arnd.bergmann@de.ibm.com>
Thanks for your telling first.
>The easiest way is usually to put the driver in your source tree
>and compile everything together. That also makes it easier to
>distribute the complete source tree to your users.
Sorry that I am a novice in Linux. I don't know how can I put the driver in
my source tree and compile everything together. It looks like that there is
no option in the menuconfig to choose a specially customed peripheral. So I
think I only can include the customed peripheral as a module. Could you
please say in a detail on how to do that?
> > insmod: unresolved symbol XIo_In32
> > insmod: unresolved symbol XIO_Out32
>
>that looks like part of your module is missing. Try to find where thses
>functions are defined in there and why that isn't compiled.
It's very strange because I have checked the source. In the header file of
xio.h, there are the following sentences,
/************************** Function Prototypes
******************************/
/* The following functions allow the software to be transportable across
* processors which may use memory mapped I/O or I/O which is mapped into a
* seperate address space such as X86. The functions are better suited for
* debugging and are therefore the default implementation. Macros can
instead
* be used if USE_IO_MACROS is defined.
*/
#ifndef USE_IO_MACROS
/* Functions */
Xuint8 XIo_In8(XIo_Address InAddress);
Xuint16 XIo_In16(XIo_Address InAddress);
Xuint32 XIo_In32(XIo_Address InAddress);
void XIo_Out8(XIo_Address OutAddress, Xuint8 Value);
void XIo_Out16(XIo_Address OutAddress, Xuint16 Value);
void XIo_Out32(XIo_Address OutAddress, Xuint32 Value);
#else
/* The following macros allow optimized I/O operations for memory mapped
I/O
* Note that the SYNCHRONIZE_IO may be moved by the compiler during
* optimization.
*/
#define XIo_In8(InputPtr) (*(volatile Xuint8 *)(InputPtr));
SYNCHRONIZE_IO;
#define XIo_In16(InputPtr) (*(volatile Xuint16 *)(InputPtr));
SYNCHRONIZE_IO;
#define XIo_In32(InputPtr) (*(volatile Xuint32 *)(InputPtr));
SYNCHRONIZE_IO;
#define XIo_Out8(OutputPtr, Value) \
{ (*(volatile Xuint8 *)(OutputPtr) = Value); SYNCHRONIZE_IO; }
#define XIo_Out16(OutputPtr, Value) \
{ (*(volatile Xuint16 *)(OutputPtr) = Value); SYNCHRONIZE_IO; }
#define XIo_Out32(OutputPtr, Value) \
{ (*(volatile Xuint32 *)(OutputPtr) = Value); SYNCHRONIZE_IO; }
#endif
I think these are the defination of XIo_In32 and XIo_Out32. Also, during
the compilation, there is no error to complain that "XIo_In32 or XIo_Out32
undeclared".
More suggestions are appreciated. Thanks.
BR
Ming
_________________________________________________________________
免费下载 MSN Explorer: http://explorer.msn.com/lccn/
^ permalink raw reply
* Re: [PATCH 6/10] Add 8641 Register space and IRQ definitions.
From: Jon Loeliger @ 2006-06-08 13:39 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <EDB92A0C-28BA-4E18-98ED-F37C1EEDF8C2@kernel.crashing.org>
On Wed, 2006-06-07 at 23:57, Kumar Gala wrote:
> > +/* Offset from CCSRBAR */
> > +#define MPC86xx_DMA_OFFSET (0x21000)
> > +#define MPC86xx_DMA_SIZE (0x01000)
> > +#define MPC86xx_DMA0_OFFSET (0x21100)
> > +#define MPC86xx_DMA0_SIZE (0x00080)
> > +#define MPC86xx_DMA1_OFFSET (0x21180)
> > +#define MPC86xx_DMA1_SIZE (0x00080)
> > +#define MPC86xx_DMA2_OFFSET (0x21200)
> > +#define MPC86xx_DMA2_SIZE (0x00080)
> > +#define MPC86xx_DMA3_OFFSET (0x21280)
> > +#define MPC86xx_DMA3_SIZE (0x00080)
> > +
> > +#define MPC86xx_GUTS_OFFSET (0xe0000)
> > +#define MPC86xx_GUTS_SIZE (0x01000)
> > +
> > +#define MPC86xx_OPENPIC_OFFSET (0x40000)
> > +#define MPC86xx_OPENPIC_SIZE (0x40000)
> > +#define MPC86xx_PEX1_OFFSET (0x08000)
> > +#define MPC86xx_PEX1_SIZE (0x01000)
> > +#define MPC86xx_PEX2_OFFSET (0x09000)
> > +#define MPC86xx_PEX2_SIZE (0x01000)
> > +#define MPC86xx_PERFMON_OFFSET (0xe1000)
> > +#define MPC86xx_PERFMON_SIZE (0x01000)
> > +#define MPC86xx_UART0_OFFSET (0x04500)
> > +#define MPC86xx_UART0_SIZE (0x00100)
> > +#define MPC86xx_UART1_OFFSET (0x04600)
> > +#define MPC86xx_UART1_SIZE (0x00100)
> > +#define MPC86xx_MCM_OFFSET (0x00000)
> > +#define MPC86xx_MCM_SIZE (0x02000)
> > +
> > +#define MPC86xx_CCSRBAR_SIZE (1024*1024)
>
> Let's kill any OFFSET & SIZEs that aren't actually needed in code. I
> would hope most of these are going from the flat dev tree.
OK. I'll trim this set down.
> > +enum ppc_sys_devices {
> > + MPC86xx_TSEC1,
> > + MPC86xx_TSEC2,
> > + MPC86xx_TSEC3,
> > + MPC86xx_TSEC4,
> > + MPC86xx_DUART,
> > + MPC86xx_MDIO,
> > + MPC86xx_IIC1,
> > + MPC86xx_IIC2,
> > + NUM_PPC_SYS_DEVS,
> > +};
>
> please kill, I can't imagine any code actually using this.
Yep. Again, leftover tidbits. I'll fix it.
> > +#define PVR_8641 0x80040000
>
> Does anything code use this define, if not let's kill it. I think we
> are trying to reduce such things.
I'll check and remove as possible!
Thanks,
jdl
^ permalink raw reply
* Re: [PATCH 7/10] Add use of mpc86xx.h include files in legacy header files.
From: Jon Loeliger @ 2006-06-08 13:36 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <542A1CA4-6A5A-41DA-98D2-C61D5376B761@kernel.crashing.org>
On Wed, 2006-06-07 at 23:49, Kumar Gala wrote:
> On Jun 7, 2006, at 5:42 PM, Jon Loeliger wrote:
>
> >
> > Signed-off-by: Xianghua Xiao <x.xiao@freescale.com>
> > Signed-off-by: Jon Loeliger <jdl@freescale.com>
> >
> > ---
> >
> > include/asm-ppc/io.h | 2 ++
> > include/asm-ppc/ppc_sys.h | 2 ++
> > include/asm-ppc/serial.h | 2 ++
> > 3 files changed, 6 insertions(+), 0 deletions(-)
>
> Are the io.h & serial.h really needed for ARCH=powerpc? What does
> serial.h get from asm/mpc86xx.h? I can see the possibility of io.h
> needing some stuff from asm/mpc86xx.h
I'll check and do a round of include scrubbing.
There was some silliness going on there earlier,
but it could have been cleaned up along the way too.
> > index 40f197a..4eaf80d 100644
> > --- a/include/asm-ppc/ppc_sys.h
> > +++ b/include/asm-ppc/ppc_sys.h
> > @@ -27,6 +27,8 @@ #elif defined(CONFIG_83xx)
> > #include <asm/mpc83xx.h>
> > #elif defined(CONFIG_85xx)
> > #include <asm/mpc85xx.h>
> > +#elif defined(CONFIG_PPC_86xx)
> > +#include <asm/mpc86xx.h>
>
> this should go since I can't imagine your using ppc_sys.
Right. Leftover cleaning tidbits. It's gone.
Thanks,
jdl
^ permalink raw reply
* Re: [PATCH 1/10] Add the mpc8641 hpcn Kconfig and Makefiles.
From: Jon Loeliger @ 2006-06-08 13:35 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <0EC9507F-27EE-46E4-A92A-E4150A2FA312@kernel.crashing.org>
On Wed, 2006-06-07 at 23:44, Kumar Gala wrote:
> On Jun 7, 2006, at 5:34 PM, Jon Loeliger wrote:
> > config PPC_I8259
> > bool
> > + default y if PPC_86xx
> > default n
>
> This dependancy seems too generic, shouldn't it be based on some
> board (its not like 86xx actually has an i8259 in it).
> > +# Makefile for the PowerPC 86xx linux kernel.
> > +#
> > +
> > +obj-$(CONFIG_PPC_86xx) += mpc86xx_hpcn.o misc.o
>
> Seems like mpc86xx_hpcn.o is board specific code and should move down
> one line.
> > +
> > +config I8259_LEVEL_TRIGGER
> > + bool
> > + depends on MPC8641
> > + default y
>
> again, seems like it should depend on a board & not MPC8641
OK, I'll fix all of those.
> > diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> > index d6d4494..fbeae82 100644
> > --- a/drivers/i2c/busses/Kconfig
> > +++ b/drivers/i2c/busses/Kconfig
> > @@ -252,12 +252,12 @@ config I2C_POWERMAC
> >
> should probably separate this out into its own patch for the I2C
> maintainer.
Ah, OK. Who is that then?
Thanks,
jdl
^ permalink raw reply
* Re: a problem of kernel-module version mismatch.
From: Arnd Bergmann @ 2006-06-08 13:36 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <BAY110-F1B771BD82DFE542552C0BB28B0@phx.gbl>
On Thursday 08 June 2006 15:27, Ming Liu wrote:
> My embedded linux kernel version is 2.4.26. My compiler is
> "powerpc-405-linux-gnu-gcc 3.4.1". I don't know how the version mismatch
> happened. Shall I change another cross-compiler version? I will appreciate
> a lot if someone could tell me how to solve it. Thanks a lot.
The easiest way is usually to put the driver in your source tree
and compile everything together. That also makes it easier to
distribute the complete source tree to your users.
> insmod: unresolved symbol XIo_In32
> insmod: unresolved symbol XIO_Out32
that looks like part of your module is missing. Try to find where thses
functions are defined in there and why that isn't compiled.
Arnd <><
^ permalink raw reply
* a problem of kernel-module version mismatch.
From: Ming Liu @ 2006-06-08 13:27 UTC (permalink / raw)
To: Linuxppc-embedded
Hello everyone,
Now I am trying to cross-compile the driver for a customed FIFO peripheral
in my design. My embedded platform is Xilinx ML403 development board
(Virtex4) and the host linux is suse 64-bit. I use the cross-compiler to
compile the driver source files provided by Xilinx EDK. But the problem
happens:
# insmod FIFO.o
insmod: kernel-module version mismatch
FIFO.o was compiled for kernel version
while this kernel is version 2.4.26
If I use "-f" option, it shows:
insmod: kernel-module version mismatch
FIFO.o was compiled for kernel version
while this kernel is version 2.4.26
insmod: unresolved symbol XIo_In32
insmod: unresolved symbol XIO_Out32
My embedded linux kernel version is 2.4.26. My compiler is
"powerpc-405-linux-gnu-gcc 3.4.1". I don't know how the version mismatch
happened. Shall I change another cross-compiler version? I will appreciate
a lot if someone could tell me how to solve it. Thanks a lot.
Regards
Ming
_________________________________________________________________
与联机的朋友进行交流,请使用 MSN Messenger: http://messenger.msn.com/cn
^ permalink raw reply
* (no subject)
From: huseyin_yeter1977 @ 2006-06-08 8:57 UTC (permalink / raw)
To: Linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 9 bytes --]
thank you
[-- Attachment #2: Type: text/html, Size: 47 bytes --]
^ permalink raw reply
* RE: does Gianfar Ethernet Controller Version 1.1 support MARVELL 88E1111?
From: Liu Dave-r63238 @ 2006-06-08 8:41 UTC (permalink / raw)
To: '郭 剑非', Linuxppc-embedded
> Hi all,
> I'm debugging my board with MPC 8540 and marvell 88e1111
> designed on it.
> I'm sure the hardware connection is correct, and the phy's ID
> could be read
> through terminal port. But anyway, phy can not work. I wonder
Are you sure the hardware is no problem?
Can you successfully tftp files with the port in u-boot?
What is the phy interface mode you used?
> if it is the
> driver's problem? Since the Gianfar Ethernet Controller Version 1.1
> surpport 88e1011s, but some 88e1111's registers are different from
> 88e1011s'. Actually I'm a new guy to Linux. Has anybody ever
> used 88e1111
> phy in Linux envirenmemt? Please
Basically, the 88e1111 is same 88e1011s.
> give me some points. Thank you!
> I have read the Gianfar ethernet controller driver, but it's
> difficult for
> me to find out the sofware flow.
>
Change the board-specific things, for example
PHY address, PHY interrupt.
Please reference /arch/ppc/platforms/85xx/mpc8540_ads.c
-Dave
^ permalink raw reply
* does Gianfar Ethernet Controller Version 1.1 support MARVELL 88E1111?
From: 郭 剑非 @ 2006-06-08 7:43 UTC (permalink / raw)
To: Linuxppc-embedded
Hi all,
I'm debugging my board with MPC 8540 and marvell 88e1111 designed on it.
I'm sure the hardware connection is correct, and the phy's ID could be read
through terminal port. But anyway, phy can not work. I wonder if it is the
driver's problem? Since the Gianfar Ethernet Controller Version 1.1
surpport 88e1011s, but some 88e1111's registers are different from
88e1011s'. Actually I'm a new guy to Linux. Has anybody ever used 88e1111
phy in Linux envirenmemt? Please
give me some points. Thank you!
I have read the Gianfar ethernet controller driver, but it's difficult for
me to find out the sofware flow.
^ permalink raw reply
* Re: [PATCH 2/3] powerpc: Add early debugging / xmon support for Cell
From: Michael Ellerman @ 2006-06-08 5:22 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev
In-Reply-To: <20060502095406.C25DA67B3B@ozlabs.org>
[-- Attachment #1: Type: text/plain, Size: 1031 bytes --]
On Tue, 2006-05-02 at 19:54 +1000, Michael Ellerman wrote:
> This patch adds udbg routines for cell, and hooks them up for use as an early
> debugging console or for xmon.
>
> With this patch xmon seems to work. On one occasion after sitting in xmon
> for a while I lost hard disk interrupts and had to power off, not sure what
> the story was there.
>
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
This patch is no good, it allows you to inadvertently call rtas before
it's ready which causes the kernel to die. I think we can structure
things so that a) rtas is callable earlier, and b) rtas_call fails
gracefully when rtas isn't setup yet.
The BML guys now use these rtas calls too, so I'll do a version under
kernel/ so they can use it too.
New patch RSN.
cheers
--
Michael Ellerman
IBM OzLabs
wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)
We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 191 bytes --]
^ permalink raw reply
* Re: Making Two ethernet interfaces up in Linux
From: Shantanu Nalage @ 2006-06-08 5:16 UTC (permalink / raw)
To: Antonio Di Bacco, linuxppc-embedded
In-Reply-To: <200606032255.05997.antonio.dibacco@aruba.it>
[-- Attachment #1: Type: text/plain, Size: 1377 bytes --]
Thanks for the reply.
The driver which we are using for the ethernet is provided by Xilinx.
In the Linux kernel source, it is located in net/xilinx_enet
directory. We are attaching the adapter file for the driver provided
by Xilinx for the ethernet.
When we gave a first try, it showed two ethernet interfaces eth0 and
eth1 as an output of ifconfig command but only eth0 works, when eth1
is disabled. When both interfaces are up, neither interface works.
While even when eth0 is disabled, eth1 interface doesn't work.
With regards,
Shantanu.
On 6/4/06, Antonio Di Bacco <antonio.dibacco@aruba.it> wrote:
> > We are trying to port Linux on Xilinx Board XUPV2Pro which is
> > similar in most aspects to the Xilinx ML300 board. Linux is up and
> > running for the original board i.e. having only one ethrnet interface.
> > Now since we wanted to have the board working as router, we designed a
> > daughter board with two ethernet phy interfaces. The MACs required for
> > that are instantiated in Xilinx ....
>
> You have already the driver for the first MAC, then you should start from that
> modifying the init procedure for example and all the others. Your driver
> should initialize both the MACs and also create two devices calling
> init_etherdev tow times. If you post your driver I can suggest what to
> change. It is not so difficult.
>
> Bye,
> Antonio.
>
>
[-- Attachment #2: adapter.c --]
[-- Type: text/plain, Size: 58370 bytes --]
/*
* adapter.c
*
* Xilinx Ethernet Adapter component to interface XEmac component to Linux
*
* Author: MontaVista Software, Inc.
* source@mvista.com
*
* 2002 (c) MontaVista, Software, Inc. This file is licensed under the terms
* of the GNU General Public License version 2.1. This program is licensed
* "as is" without any warranty of any kind, whether express or implied.
*/
/*
* This driver is a bit unusual in that it is composed of two logical
* parts where one part is the OS independent code and the other part is
* the OS dependent code. Xilinx provides their drivers split in this
* fashion. This file represents the Linux OS dependent part known as
* the Linux adapter. The other files in this directory are the OS
* independent files as provided by Xilinx with no changes made to them.
* The names exported by those files begin with XEmac_. All functions
* in this file that are called by Linux have names that begin with
* xenet_. The functions in this file that have Handler in their name
* are registered as callbacks with the underlying Xilinx OS independent
* layer. Any other functions are static helper functions.
*/
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/mii.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/atomic.h>
#include <linux/ethtool.h>
#include <xbasic_types.h>
#include "xemac.h"
#include "xemac_i.h"
#include "xipif_v1_23_b.h"
#undef XEM_DFT_SEND_DESC
#define XEM_DFT_SEND_DESC 64
#undef XEM_DFT_RECV_DESC
#define XEM_DFT_RECV_DESC 256
#define DRIVER_NAME "Xilinx Eth MAC driver"
#define DRIVER_VERSION "1.0"
MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
MODULE_DESCRIPTION(DRIVER_NAME);
MODULE_LICENSE("GPL");
#define TX_TIMEOUT (60*HZ) /* Transmission timeout is 60 seconds. */
/* On the OPB, the 10/100 EMAC requires data to be aligned to 4 bytes.
* On the PLB, the 10/100 EMAC requires data to be aligned to 8 bytes.
* For simplicity, we always align to 8 bytes.
*/
#define ALIGNMENT 32
/* BUFFER_ALIGN(adr) calculates the number of bytes to the next alignment. */
#define BUFFER_ALIGN(adr) ((ALIGNMENT - ((u32) adr)) % ALIGNMENT)
/* physical to virtual pointer conversion */
#define P_TO_V(InstancePtr, p) \
((p) ? \
((InstancePtr)->VirtPtr + ((u32)(p) - (u32)(InstancePtr)->PhyPtr)) : \
0)
int bh_entry = 0;
/*
* Our private per device data. When a net_device is allocated we will
* ask for enough extra space for this.
*/
struct net_local {
struct list_head rcv;
XBufDescriptor * rcvBdPtr;
int rcvBds;
struct list_head xmit;
XBufDescriptor * xmitBdPtr;
int xmitBds;
struct net_device_stats stats; /* Statistics for this device */
struct net_device *next_dev; /* The next device in dev_list */
struct net_device *dev; /* this device */
struct timer_list phy_timer; /* PHY monitoring timer */
u32 index; /* Which interface is this */
XInterruptHandler Isr; /* Pointer to the XEmac ISR routine */
u8 mii_addr; /* The MII address of the PHY */
/*
* The underlying OS independent code needs space as well. A
* pointer to the following XEmac structure will be passed to
* any XEmac_ function that requires it. However, we treat the
* data as an opaque object in this file (meaning that we never
* reference any of the fields inside of the structure).
*/
XEmac Emac;
void *desc_space;
dma_addr_t desc_space_handle;
int desc_space_size;
u8 *ddrVirtPtr;
u32 ddrOffset;
u32 ddrSize;
struct sk_buff* deferred_skb;
atomic_t availSendBds;
};
/* List of devices we're handling and a lock to give us atomic access. */
static struct net_device *dev_list = NULL;
static spinlock_t dev_lock = SPIN_LOCK_UNLOCKED;
/* for exclusion of all program flows (processes, ISRs and BHs) possible to share data with current one */
static spinlock_t reset_lock = SPIN_LOCK_UNLOCKED;
/* Helper function to determine if a given XEmac error warrants a reset. */
extern inline int
status_requires_reset(XStatus s)
{
return (s == XST_DMA_ERROR || s == XST_FIFO_ERROR ||
s == XST_RESET_ERROR || s == XST_DMA_SG_NO_LIST ||
s == XST_DMA_SG_LIST_EMPTY);
}
/* BH statics */
LIST_HEAD(receivedQueue);
static spinlock_t rcvSpin = SPIN_LOCK_UNLOCKED;
LIST_HEAD(sentQueue);
static spinlock_t xmitSpin = SPIN_LOCK_UNLOCKED;
/* SAATODO: This function will be moved into the Xilinx code. */
/*****************************************************************************/
/**
*
* Lookup the device configuration based on the emac instance. The table
* EmacConfigTable contains the configuration info for each device in the system.
*
* @param Instance is the index of the emac being looked up.
*
* @return
*
* A pointer to the configuration table entry corresponding to the given
* device ID, or NULL if no match is found.
*
* @note
*
* None.
*
******************************************************************************/
XEmac_Config *
XEmac_GetConfig(int Instance)
{
if (Instance < 0 || Instance >= XPAR_XEMAC_NUM_INSTANCES) {
return NULL;
}
return &XEmac_ConfigTable[Instance];
}
/*
* The following are notes regarding the critical sections in this
* driver and how they are protected.
*
* dev_list
* There is a spinlock protecting the device list. It isn't really
* necessary yet because the list is only manipulated at init and
* cleanup, but it's there because it is basically free and if we start
* doing hot add and removal of ethernet devices when the FPGA is
* reprogrammed while the system is up, we'll need to protect the list.
*
* XEmac_Start, XEmac_Stop and XEmac_SetOptions are not thread safe.
* These functions are called from xenet_open(), xenet_close(), reset(),
* and xenet_set_multicast_list(). xenet_open() and xenet_close()
* should be safe because when they do start and stop, they don't have
* interrupts or timers enabled. The other side is that they won't be
* called while a timer or interrupt is being handled.
*
* XEmac_PhyRead and XEmac_PhyWrite are not thread safe.
* These functions are called from get_phy_status(), xenet_ioctl() and
* probe(). probe() is only called from xenet_init() so it is not an
* issue (nothing is really up and running yet). get_phy_status() is
* called from both poll_mii() (a timer bottom half) and xenet_open().
* These shouldn't interfere with each other because xenet_open() is
* what starts the poll_mii() timer. xenet_open() and xenet_ioctl()
* should be safe as well because they will be sequential. That leaves
* the interaction between poll_mii() and xenet_ioctl(). While the
* timer bottom half is executing, a new ioctl won't come in so that is
* taken care of. That leaves the one case of the poll_mii timer
* popping while handling an ioctl. To take care of that case, the
* timer is deleted when the ioctl comes in and then added back in after
* the ioctl is finished.
*/
typedef enum DUPLEX { UNKNOWN_DUPLEX, HALF_DUPLEX, FULL_DUPLEX } DUPLEX;
static void
reset(struct net_device *dev, DUPLEX duplex)
{
struct net_local *lp = (struct net_local *) dev->priv;
u32 Options;
u8 IfgPart1;
u8 IfgPart2;
u8 SendThreshold;
u32 SendWaitBound;
u8 RecvThreshold;
u32 RecvWaitBound;
int dma_works;
/* Shouldn't really be necessary, but shouldn't hurt. */
netif_stop_queue(dev);
/*
* XEmac_Reset puts the device back to the default state. We need
* to save all the settings we don't already know, reset, restore
* the settings, and then restart the emac.
*/
XEmac_GetInterframeGap(&lp->Emac, &IfgPart1, &IfgPart2);
Options = XEmac_GetOptions(&lp->Emac);
switch (duplex) {
case HALF_DUPLEX:
Options &= ~XEM_FDUPLEX_OPTION;
break;
case FULL_DUPLEX:
Options |= XEM_FDUPLEX_OPTION;
break;
case UNKNOWN_DUPLEX:
break;
}
if (XEmac_mIsSgDma(&lp->Emac)) {
/*
* The following four functions will return an error if we are
* not doing scatter-gather DMA. We just checked that so we
* can safely ignore the return values. We cast them to void
* to make that explicit.
*/
dma_works = 1;
(void) XEmac_GetPktThreshold(&lp->Emac, XEM_SEND,
&SendThreshold);
(void) XEmac_GetPktWaitBound(&lp->Emac, XEM_SEND,
&SendWaitBound);
(void) XEmac_GetPktThreshold(&lp->Emac, XEM_RECV,
&RecvThreshold);
(void) XEmac_GetPktWaitBound(&lp->Emac, XEM_RECV,
&RecvWaitBound);
} else
dma_works = 0;
XEmac_Reset(&lp->Emac);
/*
* The following three functions will return an error if the
* EMAC is already started. We just stopped it by calling
* XEmac_Reset() so we can safely ignore the return values.
* We cast them to void to make that explicit.
*/
(void) XEmac_SetMacAddress(&lp->Emac, dev->dev_addr);
(void) XEmac_SetInterframeGap(&lp->Emac, IfgPart1, IfgPart2);
(void) XEmac_SetOptions(&lp->Emac, Options);
if (XEmac_mIsSgDma(&lp->Emac)) {
/*
* The following four functions will return an error if
* we are not doing scatter-gather DMA or if the EMAC is
* already started. We just checked that we are indeed
* doing scatter-gather and we just stopped the EMAC so
* we can safely ignore the return values. We cast them
* to void to make that explicit.
*/
(void) XEmac_SetPktThreshold(&lp->Emac, XEM_SEND,
SendThreshold);
(void) XEmac_SetPktWaitBound(&lp->Emac, XEM_SEND,
SendWaitBound);
(void) XEmac_SetPktThreshold(&lp->Emac, XEM_RECV,
RecvThreshold);
(void) XEmac_SetPktWaitBound(&lp->Emac, XEM_RECV,
RecvWaitBound);
}
/*
* XEmac_Start returns an error when: it is already started, the send
* and receive handlers are not set, or a scatter-gather DMA list is
* missing. None of these can happen at this point, so we cast the
* return to void to make that explicit.
*/
if (dma_works) {
int avail_plus = 0;
while (!(XDmaChannel_IsSgListEmpty(&(lp->Emac.SendChannel)))) { /* list isn't empty, has to be cleared */
XStatus ret;
XBufDescriptor* BdPtr;
if ((ret = XDmaChannel_GetDescriptor (&(lp->Emac.SendChannel), &BdPtr)) != XST_SUCCESS) {
printk (KERN_ERR "SgDma ring structure ERROR %d\n", ret);
break;
}
avail_plus++;
XBufDescriptor_Unlock(BdPtr);
pci_unmap_single(NULL,
(u32) XBufDescriptor_GetSrcAddress(BdPtr),
XBufDescriptor_GetLength(BdPtr), PCI_DMA_TODEVICE);
lp->stats.tx_errors++;
}
atomic_add(avail_plus,&lp->availSendBds);
} else {
if (lp->deferred_skb) {
dev_kfree_skb(lp->deferred_skb);
lp->deferred_skb = NULL;
lp->stats.tx_errors++;
}
}
dev->trans_start = 0xffffffff - TX_TIMEOUT - TX_TIMEOUT; /* to exclude tx timeout */
(void) XEmac_Start(&lp->Emac);
/* We're all ready to go. Start the queue in case it was stopped. */
if (!bh_entry)
netif_wake_queue(dev);
}
static int
get_phy_status(struct net_device *dev, DUPLEX * duplex, int *linkup)
{
struct net_local *lp = (struct net_local *) dev->priv;
u16 reg;
XStatus xs;
xs = XEmac_PhyRead(&lp->Emac, lp->mii_addr, MII_BMCR, ®);
if (xs != XST_SUCCESS) {
printk(KERN_ERR
"%s: Could not read PHY control register; error %d\n",
dev->name, xs);
return -1;
}
if (!(reg & BMCR_ANENABLE)) {
/*
* Auto-negotiation is disabled so the full duplex bit in
* the control register tells us if the PHY is running
* half or full duplex.
*/
*duplex = (reg & BMCR_FULLDPLX) ? FULL_DUPLEX : HALF_DUPLEX;
} else {
/*
* Auto-negotiation is enabled. Figure out what was
* negotiated by looking for the best mode in the union
* of what we and our partner advertise.
*/
u16 advertise, partner, negotiated;
xs = XEmac_PhyRead(&lp->Emac, lp->mii_addr,
MII_ADVERTISE, &advertise);
if (xs != XST_SUCCESS) {
printk(KERN_ERR
"%s: Could not read PHY advertisement; error %d\n",
dev->name, xs);
return -1;
}
xs = XEmac_PhyRead(&lp->Emac, lp->mii_addr, MII_LPA, &partner);
if (xs != XST_SUCCESS) {
printk(KERN_ERR
"%s: Could not read PHY LPA; error %d\n",
dev->name, xs);
return -1;
}
negotiated = advertise & partner & ADVERTISE_ALL;
if (negotiated & ADVERTISE_100FULL)
*duplex = FULL_DUPLEX;
else if (negotiated & ADVERTISE_100HALF)
*duplex = HALF_DUPLEX;
else if (negotiated & ADVERTISE_10FULL)
*duplex = FULL_DUPLEX;
else
*duplex = HALF_DUPLEX;
}
xs = XEmac_PhyRead(&lp->Emac, lp->mii_addr, MII_BMSR, ®);
if (xs != XST_SUCCESS) {
printk(KERN_ERR
"%s: Could not read PHY status register; error %d\n",
dev->name, xs);
return -1;
}
*linkup = (reg & BMSR_LSTATUS) != 0;
return 0;
}
/*
* This routine is used for two purposes. The first is to keep the
* EMAC's duplex setting in sync with the PHY's. The second is to keep
* the system apprised of the state of the link. Note that this driver
* does not configure the PHY. Either the PHY should be configured for
* auto-negotiation or it should be handled by something like mii-tool.
*/
static void
poll_mii(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
struct net_local *lp = (struct net_local *) dev->priv;
u32 Options;
DUPLEX phy_duplex, mac_duplex;
int phy_carrier, netif_carrier;
unsigned long flags;
/* First, find out what's going on with the PHY. */
if (get_phy_status(dev, &phy_duplex, &phy_carrier)) {
printk(KERN_ERR "%s: Terminating link monitoring.\n",
dev->name);
return;
}
/* Second, figure out if we have the EMAC in half or full duplex. */
Options = XEmac_GetOptions(&lp->Emac);
mac_duplex = (Options & XEM_FDUPLEX_OPTION) ? FULL_DUPLEX : HALF_DUPLEX;
/* Now see if there is a mismatch. */
if (mac_duplex != phy_duplex) {
/*
* Make sure that no interrupts come in that could cause
* reentrancy problems in reset.
*/
spin_lock_irqsave(reset_lock, flags);
reset(dev, phy_duplex); /* the function sets Emac options to match the PHY */
spin_unlock_irqrestore(reset_lock, flags);
if (mac_duplex == FULL_DUPLEX)
printk(KERN_INFO "%s: Duplex has been changed: now %s\n",
dev->name, "HALF_DUPLEX");
else
printk(KERN_INFO "%s: Duplex has been changed: now %s\n",
dev->name, "FULL_DUPLEX");
}
netif_carrier = netif_carrier_ok(dev) != 0;
if (phy_carrier != netif_carrier) {
if (phy_carrier) {
printk(KERN_INFO "%s: Link carrier restored.\n",
dev->name);
netif_carrier_on(dev);
} else {
printk(KERN_INFO "%s: Link carrier lost.\n", dev->name);
netif_carrier_off(dev);
}
}
/* Set up the timer so we'll get called again in 2 seconds. */
lp->phy_timer.expires = jiffies + 2 * HZ;
add_timer(&lp->phy_timer);
}
/*
* This routine is registered with the OS as the function to call when
* the EMAC interrupts. It in turn, calls the Xilinx OS independent
* interrupt function. There are different interrupt functions for FIFO
* and scatter-gather so we just set a pointer (Isr) into our private
* data so we don't have to figure it out here. The Xilinx OS
* independent interrupt function will in turn call any callbacks that
* we have registered for various conditions.
*/
static void
xenet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
struct net_local *lp = (struct net_local *) dev->priv;
/* Call it. */
(*(lp->Isr)) (&lp->Emac);
}
static int
xenet_open(struct net_device *dev)
{
struct net_local *lp = (struct net_local *) dev->priv;
u32 Options;
DUPLEX phy_duplex, mac_duplex;
int phy_carrier;
/*
* Just to be safe, stop the device first. If the device is already
* stopped, an error will be returned. In this case, we don't really
* care, so cast it to void to make it explicit.
*/
(void) XEmac_Stop(&lp->Emac);
/* Set the MAC address each time opened. */
if (XEmac_SetMacAddress(&lp->Emac, dev->dev_addr) != XST_SUCCESS) {
printk(KERN_ERR "%s: Could not set MAC address.\n", dev->name);
return -EIO;
}
/*
* If the device is not configured for polled mode, connect to the
* interrupt controller and enable interrupts. Currently, there
* isn't any code to set polled mode, so this check is probably
* superfluous.
*/
Options = XEmac_GetOptions(&lp->Emac);
if ((Options & XEM_POLLED_OPTION) == 0) {
int retval;
/* Grab the IRQ */
retval =
request_irq(dev->irq, &xenet_interrupt, 0, dev->name, dev);
if (retval) {
printk(KERN_ERR
"%s: Could not allocate interrupt %d.\n",
dev->name, dev->irq);
return retval;
}
}
/* Set the EMAC's duplex setting based upon what the PHY says. */
if (!get_phy_status(dev, &phy_duplex, &phy_carrier)) {
/* We successfully got the PHY status. */
mac_duplex = ((Options & XEM_FDUPLEX_OPTION)
? FULL_DUPLEX : HALF_DUPLEX);
if (mac_duplex != phy_duplex) {
switch (phy_duplex) {
case HALF_DUPLEX:
Options &= ~XEM_FDUPLEX_OPTION;
break;
case FULL_DUPLEX:
Options |= XEM_FDUPLEX_OPTION;
break;
case UNKNOWN_DUPLEX:
break;
}
/*
* The following function will return an error
* if the EMAC is already started. We know it
* isn't started so we can safely ignore the
* return value. We cast it to void to make
* that explicit.
*/
}
}
Options |= XEM_FLOW_CONTROL_OPTION;
(void) XEmac_SetOptions(&lp->Emac, Options);
INIT_LIST_HEAD(&(lp->rcv));
lp->rcvBds = 0;
INIT_LIST_HEAD(&(lp->xmit));
lp->xmitBds = 0;
if (XEmac_Start(&lp->Emac) != XST_SUCCESS) {
printk(KERN_ERR "%s: Could not start device.\n", dev->name);
free_irq(dev->irq, dev);
return -EBUSY;
}
/* We're ready to go. */
MOD_INC_USE_COUNT;
netif_start_queue(dev);
/* Set up the PHY monitoring timer. */
lp->phy_timer.expires = jiffies + 2 * HZ;
lp->phy_timer.data = (unsigned long) dev;
lp->phy_timer.function = &poll_mii;
add_timer(&lp->phy_timer);
return 0;
}
static int
xenet_close(struct net_device *dev)
{
struct net_local *lp = (struct net_local *) dev->priv;
unsigned long flags;
/* Shut down the PHY monitoring timer. */
del_timer_sync(&lp->phy_timer);
netif_stop_queue(dev);
/*
* If not in polled mode, free the interrupt. Currently, there
* isn't any code to set polled mode, so this check is probably
* superfluous.
*/
if ((XEmac_GetOptions(&lp->Emac) & XEM_POLLED_OPTION) == 0)
free_irq(dev->irq, dev);
spin_lock_irqsave(rcvSpin, flags);
list_del(&(lp->rcv));
spin_unlock_irqrestore(rcvSpin, flags);
spin_lock_irqsave(xmitSpin, flags);
list_del(&(lp->xmit));
spin_unlock_irqrestore(xmitSpin, flags);
if (XEmac_Stop(&lp->Emac) != XST_SUCCESS) {
printk(KERN_ERR "%s: Could not stop device.\n", dev->name);
return -EBUSY;
}
MOD_DEC_USE_COUNT;
return 0;
}
static struct net_device_stats *
xenet_get_stats(struct net_device *dev)
{
struct net_local *lp = (struct net_local *) dev->priv;
return &lp->stats;
}
static int
xenet_FifoSend(struct sk_buff *orig_skb, struct net_device *dev)
{
struct net_local *lp = (struct net_local *) dev->priv;
struct sk_buff *new_skb;
unsigned int len, align;
unsigned long flags;
len = orig_skb->len;
/* PR FIXME: what follows can be removed if the asserts in the Xilinx
* independent drivers change. There is really no need to align the
* buffers in FIFO mode. The story is different for simple DMA.
*/
/*
* The packet FIFO requires the buffers to be 32/64 bit aligned.
* The sk_buff data is not 32/64 bit aligned, so we have to do this
* copy. As you probably well know, this is not optimal.
*/
if (!(new_skb = alloc_skb(len + ALIGNMENT, GFP_ATOMIC))) {
/* We couldn't get another skb. */
dev_kfree_skb(orig_skb);
lp->stats.tx_dropped++;
printk(KERN_ERR "%s: Could not allocate transmit buffer.\n",
dev->name);
netif_wake_queue(dev);
return -EBUSY;
}
/*
* A new skb should have the data word aligned, but this code is
* here just in case that isn't true... Calculate how many
* bytes we should reserve to get the data to start on a word
* boundary. */
align = BUFFER_ALIGN(new_skb->data);
if (align)
skb_reserve(new_skb, align);
/* Copy the data from the original skb to the new one. */
skb_put(new_skb, len);
memcpy(new_skb->data, orig_skb->data, len);
/* Get rid of the original skb. */
dev_kfree_skb(orig_skb);
spin_lock_irqsave(reset_lock, flags);
if (XEmac_FifoSend(&lp->Emac, (u8 *) new_skb->data, len) != XST_SUCCESS) {
netif_stop_queue(dev);
lp->deferred_skb = new_skb;
spin_unlock_irqrestore(reset_lock, flags);
return 0;
}
spin_unlock_irqrestore(reset_lock, flags);
lp->stats.tx_bytes += len;
dev_kfree_skb(new_skb);
dev->trans_start = jiffies;
return 0;
}
/* The callback function for completed frames sent in FIFO mode. */
static void
FifoSendHandler(void *CallbackRef)
{
struct net_device *dev = (struct net_device *) CallbackRef;
struct net_local *lp = (struct net_local *) dev->priv;
if (lp->deferred_skb) {
if (XEmac_FifoSend(&lp->Emac, (u8 *) lp->deferred_skb->data, lp->deferred_skb->len) != XST_SUCCESS) {
return;
} else {
dev_kfree_skb(lp->deferred_skb);
lp->deferred_skb = NULL;
netif_wake_queue(dev);
}
}
lp->stats.tx_packets++;
}
/* The send function for frames sent in DMA mode. */
static int
xenet_SgSend(struct sk_buff *skb, struct net_device *dev)
{
struct net_local *lp = (struct net_local *) dev->priv;
unsigned int len;
XBufDescriptor bd;
int result;
u32 physAddr;
u8 *virtAddr;
unsigned long flags;
len = skb->len;
virtAddr = lp->ddrVirtPtr + lp->ddrOffset;
if (skb->ip_summed == CHECKSUM_NONE)
/*cacheable_*/memcpy(virtAddr, skb->data, len);
else
skb_copy_and_csum_dev(skb, virtAddr);
dev_kfree_skb(skb);
physAddr = (u32) pci_map_single(NULL, virtAddr, len, PCI_DMA_TODEVICE);
/*
* lock the buffer descriptor to prevent lower layers from reusing
* it before the adapter has a chance to deallocate the buffer
* attached to it. The adapter will unlock it in the callback function
* that handles confirmation of transmits
*/
XBufDescriptor_Initialize(&bd);
XBufDescriptor_Lock(&bd);
XBufDescriptor_SetSrcAddress(&bd, physAddr);
XBufDescriptor_SetLength(&bd, len);
XBufDescriptor_SetLast(&bd);
lp->ddrOffset += len + BUFFER_ALIGN(len);
if (lp->ddrOffset + XEM_MAX_FRAME_SIZE > lp->ddrSize)
lp->ddrOffset = 0;
spin_lock_irqsave(reset_lock, flags);
result = XEmac_SgSend(&lp->Emac, &bd, XEM_SGDMA_NODELAY);
if (result != XST_SUCCESS) {
lp->stats.tx_dropped++;
printk(KERN_ERR "%s: ERROR, could not send transmit buffer (%d).\n",
dev->name, result);
/* we should never get here in the first place, but
* for some reason the kernel doesn't like -EBUSY here,
* so just return 0 and let the stack handle dropped packets.
*/
/* return -EBUSY; */
spin_unlock_irqrestore(reset_lock, flags);
return 0;
}
if (atomic_dec_and_test(&lp->availSendBds)) {
netif_stop_queue(dev);
}
dev->trans_start = jiffies;
spin_unlock_irqrestore(reset_lock, flags);
return 0;
}
/* The callback function for completed frames sent in DMA mode. */
static void SgSendHandlerBH (unsigned long p);
static void SgRecvHandlerBH (unsigned long p);
DECLARE_TASKLET (SgSendBH, SgSendHandlerBH, 0);
DECLARE_TASKLET (SgRecvBH, SgRecvHandlerBH, 0);
static void
SgSendHandlerBH (unsigned long p)
{
struct net_device *dev;
struct net_local *lp;
XBufDescriptor * BdPtr;
u32 NumBds;
u32 len;
XBufDescriptor *curbd;
unsigned long flags;
while (1) {
spin_lock_irqsave(xmitSpin,flags);
if (list_empty(&sentQueue)) {
spin_unlock_irqrestore(xmitSpin,flags);
break;
}
lp = list_entry(sentQueue.next, struct net_local, xmit);
list_del_init(&(lp->xmit));
NumBds = lp->xmitBds;
BdPtr = lp->xmitBdPtr;
dev = lp->dev;
atomic_add(NumBds, &lp->availSendBds);
while(NumBds != 0) {
NumBds--;
len = XBufDescriptor_GetLength(BdPtr);
pci_unmap_single(NULL,
(u32) XBufDescriptor_GetSrcAddress(BdPtr),
len, PCI_DMA_TODEVICE);
lp->stats.tx_bytes += len;
lp->stats.tx_packets++;
curbd = BdPtr;
BdPtr = P_TO_V(&lp->Emac.SendChannel,
XBufDescriptor_GetNextPtr(BdPtr));
XBufDescriptor_Unlock(curbd);
}
spin_unlock_irqrestore(xmitSpin,flags);
netif_wake_queue(dev);
}
}
static void
SgSendHandler(void *CallBackRef, XBufDescriptor * BdPtr, u32 NumBds)
{
struct net_device *dev = (struct net_device *) CallBackRef;
struct net_local *lp = (struct net_local *) dev->priv;
struct list_head* cur_lp = NULL;
spin_lock(xmitSpin);
list_for_each (cur_lp, &sentQueue) {
if (cur_lp == &(lp->xmit)) {
lp->xmitBds += NumBds;
break;
}
}
if (cur_lp != &(lp->xmit)) {
lp->xmitBds = NumBds;
lp->xmitBdPtr = BdPtr;
list_add_tail(&lp->xmit,&sentQueue);
bh_entry++;
tasklet_schedule (&SgSendBH);
}
spin_unlock(xmitSpin);
}
static void
SgRecvHandlerBH (unsigned long p)
{
struct net_device *dev;
struct net_local *lp;
XBufDescriptor* BdPtr;
int NumBds;
struct sk_buff *skb, *new_skb;
u32 len, new_skb_vaddr;
dma_addr_t skb_vaddr;
u32 align;
XStatus result;
XBufDescriptor *curbd;
unsigned long flags;
while (1) {
spin_lock_irqsave(rcvSpin,flags);
if (list_empty(&receivedQueue)) {
spin_unlock_irqrestore(rcvSpin,flags);
break;
}
lp = list_entry(receivedQueue.next, struct net_local, rcv);
list_del_init(&(lp->rcv));
NumBds = lp->rcvBds;
BdPtr = lp->rcvBdPtr;
dev = lp->dev;
spin_unlock_irqrestore(rcvSpin,flags);
while (NumBds != 0) {
NumBds--;
/* get ptr to skb */
skb = (struct sk_buff *) XBufDescriptor_GetId(BdPtr);
len = XBufDescriptor_GetLength(BdPtr);
/* we have all the information we need - move on */
curbd = BdPtr;
BdPtr = P_TO_V(&lp->Emac.RecvChannel,
XBufDescriptor_GetNextPtr(curbd));
skb_vaddr = (dma_addr_t)XBufDescriptor_GetDestAddress(curbd);
pci_unmap_single(NULL, skb_vaddr, len, PCI_DMA_FROMDEVICE);
/* replace skb with a new one */
new_skb = alloc_skb(XEM_MAX_FRAME_SIZE + ALIGNMENT, GFP_ATOMIC);
if (new_skb == 0) {
printk("SgRecvHandler: no mem for new_skb\n");
return;
}
/* make sure we're long-word aligned */
align = BUFFER_ALIGN(new_skb->data);
if (align) {
skb_reserve(new_skb, align);
}
new_skb_vaddr = (u32) pci_map_single(NULL, new_skb->data,
XEM_MAX_FRAME_SIZE,
PCI_DMA_FROMDEVICE);
XBufDescriptor_SetDestAddress(curbd, new_skb_vaddr);
XBufDescriptor_SetLength(curbd, XEM_MAX_FRAME_SIZE);
XBufDescriptor_SetId(curbd, new_skb);
XBufDescriptor_Unlock(curbd);
/* give the descriptor back to the driver */
result = XEmac_SgRecv(&lp->Emac, curbd);
if (result != XST_SUCCESS) {
printk("SgRecvHandler: SgRecv unsuccessful\n");
return;
}
/* back to the original skb */
skb->len = len;
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_NONE;
lp->stats.rx_packets++;
lp->stats.rx_bytes += len;
netif_rx(skb); /* Send the packet upstream. */
}
}
}
static void
SgRecvHandler(void *CallBackRef, XBufDescriptor * BdPtr, u32 NumBds)
{
struct net_device *dev = (struct net_device *) CallBackRef;
struct net_local *lp = (struct net_local *) dev->priv;
struct list_head* cur_lp = NULL;
spin_lock(rcvSpin);
list_for_each (cur_lp, &receivedQueue) {
if (cur_lp == &(lp->rcv)) {
lp->rcvBds += NumBds;
break;
}
}
if (cur_lp != &(lp->rcv)) {
lp->rcvBds = NumBds;
lp->rcvBdPtr = BdPtr;
list_add_tail(&lp->rcv, &receivedQueue);
tasklet_schedule (&SgRecvBH);
}
spin_unlock(rcvSpin);
}
static void
xenet_tx_timeout(struct net_device *dev)
{
struct net_local *lp = (struct net_local *) dev->priv;
unsigned long flags;
printk("%s: Exceeded transmit timeout of %lu ms.\n",
dev->name, TX_TIMEOUT * 1000UL / HZ);
lp->stats.tx_errors++;
spin_lock_irqsave(reset_lock, flags);
reset(dev, UNKNOWN_DUPLEX);
spin_unlock_irqrestore(reset_lock, flags);
}
/* The callback function for frames received when in FIFO mode. */
static void
FifoRecvHandler(void *CallbackRef)
{
struct net_device *dev = (struct net_device *) CallbackRef;
struct net_local *lp = (struct net_local *) dev->priv;
struct sk_buff *skb;
unsigned int align;
u32 len;
XStatus Result;
/*
* The OS independent Xilinx EMAC code does not provide a
* function to get the length of an incoming packet and a
* separate call to actually get the packet data. It does this
* because they didn't add any code to keep the hardware's
* receive length and data FIFOs in sync. Instead, they require
* that you send a maximal length buffer so that they can read
* the length and data FIFOs in a single chunk of code so that
* they can't get out of sync. So, we need to allocate an skb
* that can hold a maximal sized packet. The OS independent
* code needs to see the data 32/64-bit aligned, so we tack on an
* extra four just in case we need to do an skb_reserve to get
* it that way.
*/
len = XEM_MAX_FRAME_SIZE;
if (!(skb = alloc_skb(len + ALIGNMENT, GFP_ATOMIC))) {
/* Couldn't get memory. */
lp->stats.rx_dropped++;
printk(KERN_ERR "%s: Could not allocate receive buffer.\n",
dev->name);
return;
}
/*
* A new skb should have the data word aligned, but this code is
* here just in case that isn't true... Calculate how many
* bytes we should reserve to get the data to start on a word
* boundary. */
align = BUFFER_ALIGN(skb->data);
if (align)
skb_reserve(skb, align);
Result = XEmac_FifoRecv(&lp->Emac, (u8 *) skb->data, &len);
if (Result != XST_SUCCESS) {
int need_reset = status_requires_reset(Result);
lp->stats.rx_errors++;
dev_kfree_skb(skb);
printk(KERN_ERR "%s: Could not receive buffer, error=%d%s.\n",
dev->name, Result,
need_reset ? ", resetting device." : "");
if (need_reset) {
spin_lock(reset_lock);
reset(dev, UNKNOWN_DUPLEX);
spin_unlock(reset_lock);
}
return;
}
skb_put(skb, len); /* Tell the skb how much data we got. */
skb->dev = dev; /* Fill out required meta-data. */
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_NONE;
lp->stats.rx_packets++;
lp->stats.rx_bytes += len;
netif_rx(skb); /* Send the packet upstream. */
}
/* The callback function for errors. */
static void
ErrorHandler(void *CallbackRef, XStatus Code)
{
struct net_device *dev = (struct net_device *) CallbackRef;
int need_reset = status_requires_reset(Code);
unsigned long flags;
/* ignore some errors */
if (Code == XST_DMA_ERROR)
return;
printk(KERN_ERR "%s: device error %d%s\n",
dev->name, Code,need_reset ? ", resetting device." : "");
if (need_reset) {
spin_lock_irqsave(reset_lock, flags);
reset(dev, UNKNOWN_DUPLEX);
spin_unlock_irqrestore(reset_lock, flags);
}
}
static int
descriptor_init(struct net_device *dev)
{
struct net_local *lp = (struct net_local *) dev->priv;
int i, recvsize, sendsize;
int dftsize;
u32 *recvpoolptr, *sendpoolptr;
void *recvpoolphy, *sendpoolphy;
/* calc size of descriptor space pool; alloc from non-cached memory */
dftsize = (XEM_DFT_RECV_DESC + XEM_DFT_SEND_DESC) *
sizeof (XBufDescriptor);
lp->desc_space = consistent_alloc(GFP_ATOMIC, dftsize,
&lp->desc_space_handle);
if (lp->desc_space == 0) {
return -1;
}
lp->desc_space_size = dftsize;
lp->ddrSize = XEM_DFT_SEND_DESC * (XEM_MAX_FRAME_SIZE + ALIGNMENT);
lp->ddrOffset = 0;
lp->ddrVirtPtr = kmalloc(lp->ddrSize, GFP_ATOMIC);
if (lp->ddrVirtPtr == 0)
return -1;
atomic_set(&lp->availSendBds, XEM_DFT_SEND_DESC);
/* calc size of send and recv descriptor space */
recvsize = XEM_DFT_RECV_DESC * sizeof (XBufDescriptor);
sendsize = XEM_DFT_SEND_DESC * sizeof (XBufDescriptor);
recvpoolptr = lp->desc_space;
sendpoolptr = (void *) ((u32) lp->desc_space + recvsize);
recvpoolphy = (void *) lp->desc_space_handle;
sendpoolphy = (void *) ((u32) lp->desc_space_handle + recvsize);
/* add ptr to descriptor space to the driver */
XEmac_SetSgRecvSpace(&lp->Emac, recvpoolptr, recvsize, recvpoolphy);
XEmac_SetSgSendSpace(&lp->Emac, sendpoolptr, sendsize, sendpoolphy);
/* allocate skb's and give them to the dma engine */
for (i = 0; i < XEM_DFT_RECV_DESC; i++) {
struct sk_buff *skb;
XBufDescriptor bd;
int result;
u32 skb_vaddr, align;
skb = alloc_skb(XEM_MAX_FRAME_SIZE + ALIGNMENT, GFP_ATOMIC);
if (skb == 0) {
return -1;
}
align = BUFFER_ALIGN(skb->data);
if (align)
skb_reserve(skb, align);
skb_vaddr = (u32) pci_map_single(NULL, skb->data,
XEM_MAX_FRAME_SIZE,
PCI_DMA_FROMDEVICE);
/*
* initialize descriptors and set buffer address
* buffer length gets max frame size
*/
XBufDescriptor_Initialize(&bd);
XBufDescriptor_Lock(&bd);
XBufDescriptor_SetDestAddress(&bd, skb_vaddr);
XBufDescriptor_SetLength(&bd, XEM_MAX_FRAME_SIZE);
XBufDescriptor_SetId(&bd, skb);
/*
* descriptor with attached buffer to the driver and
* let it make it ready for frame reception
*/
result = XEmac_SgRecv(&lp->Emac, &bd);
if (result != XST_SUCCESS) {
return -1;
}
}
return 0;
}
void
free_descriptor_skb (struct net_device *dev)
{
struct net_local *lp = (struct net_local *) dev->priv;
int i;
XBufDescriptor* BdPtr;
struct sk_buff* skb;
BdPtr = (XBufDescriptor*)lp->Emac.RecvChannel.VirtPtr;
for (i=0; i<XEM_DFT_RECV_DESC; i++) {
skb = (struct sk_buff*)XBufDescriptor_GetId(BdPtr);
pci_unmap_single(NULL, virt_to_bus(skb->data), XBufDescriptor_GetLength(BdPtr), PCI_DMA_FROMDEVICE);
dev_kfree_skb(skb);
BdPtr = P_TO_V(&lp->Emac.RecvChannel,XBufDescriptor_GetNextPtr(BdPtr));
}
}
static void
xenet_set_multicast_list(struct net_device *dev)
{
struct net_local *lp = (struct net_local *) dev->priv;
u32 Options;
int ret = 0;
unsigned long flags;
/*
* XEmac_Start, XEmac_Stop and XEmac_SetOptions are supposed to
* be protected by a semaphore. We do have one area in which
* this is a problem.
*
* xenet_set_multicast_list() is called while the link is up and
* interrupts are enabled, so at any point in time we could get
* an error that causes our reset() to be called. reset() calls
* the aforementioned functions, and we need to call them from
* here as well.
*
* The solution is to make sure that we don't get interrupts or
* timers popping while we are in this function.
*/
spin_lock_irqsave(reset_lock, flags);
if ((ret = XEmac_Stop(&lp->Emac)) == XST_SUCCESS) {
Options = XEmac_GetOptions(&lp->Emac);
/* Clear out the bits we may set. */
Options &= ~(XEM_PROMISC_OPTION | XEM_MULTICAST_OPTION);
if (dev->flags & IFF_PROMISC)
Options |= XEM_PROMISC_OPTION;
#if 0
else {
/*
* SAATODO: Xilinx is going to add multicast support to their
* VxWorks adapter and OS independent layer. After that is
* done, this skeleton code should be fleshed out. Note that
* IFF_MULTICAST is being masked out from dev->flags in probe,
* so that will need to be removed to actually do multidrop.
*/
if ((dev->flags & IFF_ALLMULTI)
|| dev->mc_count > MAX_MULTICAST ? ? ?) {
xemac_get_all_multicast ? ? ? ();
Options |= XEM_MULTICAST_OPTION;
} else if (dev->mc_count != 0) {
struct dev_mc_list *mc;
XEmac_MulticastClear(&lp->Emac);
for (mc = dev->mc_list; mc; mc = mc->next)
XEmac_MulticastAdd(&lp->Emac, mc->dmi_addr);
Options |= XEM_MULTICAST_OPTION;
}
}
#endif
/*
* The following function will return an error if the EMAC is already
* started. We know it isn't started so we can safely ignore the
* return value. We cast it to void to make that explicit.
*/
(void) XEmac_SetOptions(&lp->Emac, Options);
/*
* XEmac_Start returns an error when: it is already started, the send
* and receive handlers are not set, or a scatter-gather DMA list is
* missing. None of these can happen at this point, so we cast the
* return to void to make that explicit.
*/
(void) XEmac_Start(&lp->Emac);
}
/* All done, get those interrupts and timers going again. */
spin_unlock_irqrestore(reset_lock, flags);
}
static int
xenet_ethtool_get_settings (struct net_device *dev, struct ethtool_cmd* ecmd)
{
int ret;
struct net_local *lp = (struct net_local *) dev->priv;
u32 mac_options;
u8 threshold;
u16 mii_cmd;
u16 mii_status;
u16 mii_advControl;
XStatus xs;
memset (ecmd, 0, sizeof(struct ethtool_cmd));
mac_options = XEmac_GetOptions (&(lp->Emac));
xs = XEmac_PhyRead(&lp->Emac, lp->mii_addr, MII_BMCR, &mii_cmd);
if (xs != XST_SUCCESS) {
printk(KERN_ERR
"%s: Could not read mii command register; error %d\n",
dev->name, xs);
return -1;
}
xs = XEmac_PhyRead(&lp->Emac, lp->mii_addr, MII_BMSR, &mii_status);
if (xs != XST_SUCCESS) {
printk(KERN_ERR
"%s: Could not read mii status register; error %d\n",
dev->name, xs);
return -1;
}
xs = XEmac_PhyRead(&lp->Emac, lp->mii_addr, MII_ADVERTISE, &mii_advControl);
if (xs != XST_SUCCESS) {
printk(KERN_ERR
"%s: Could not read mii advertisement control register; error %d\n",
dev->name, xs);
return -1;
}
if (mac_options & XEM_FDUPLEX_OPTION)
ecmd->duplex = DUPLEX_FULL;
else
ecmd->duplex = DUPLEX_HALF;
if (mii_status & BMSR_100FULL)
ecmd->supported |= SUPPORTED_100baseT_Full;
if (mii_status & BMSR_100HALF)
ecmd->supported |= SUPPORTED_100baseT_Half;
if (mii_status & BMSR_10FULL)
ecmd->supported |= SUPPORTED_10baseT_Full;
if (mii_status & BMSR_10HALF)
ecmd->supported |= SUPPORTED_10baseT_Half;
if (XEmac_mHasMii(&(lp->Emac)))
ecmd->supported |= SUPPORTED_MII;
else
ecmd->supported &= (~SUPPORTED_MII);
if (mii_status & BMSR_ANEGCAPABLE)
ecmd->supported |= SUPPORTED_Autoneg;
if (mii_status & BMSR_ANEGCOMPLETE) {
ecmd->autoneg = AUTONEG_ENABLE;
ecmd->advertising |= ADVERTISED_Autoneg;
if ((mii_advControl & ADVERTISE_100FULL) || (mii_advControl & ADVERTISE_100HALF))
ecmd->speed = SPEED_100;
else
ecmd->speed = SPEED_10;
} else {
ecmd->autoneg = AUTONEG_DISABLE;
if (mii_cmd & BMCR_SPEED100)
ecmd->speed = SPEED_100;
else
ecmd->speed = SPEED_10;
}
if (mii_advControl & ADVERTISE_10FULL)
ecmd->advertising |= ADVERTISED_10baseT_Full;
if (mii_advControl & ADVERTISE_10HALF)
ecmd->advertising |= ADVERTISED_10baseT_Half;
if (mii_advControl & ADVERTISE_100FULL)
ecmd->advertising |= ADVERTISED_100baseT_Full;
if (mii_advControl & ADVERTISE_100HALF)
ecmd->advertising |= ADVERTISED_100baseT_Half;
ecmd->advertising |= ADVERTISED_MII;
ecmd->port = PORT_MII;
ecmd->phy_address = lp->Emac.PhysAddress;
ecmd->transceiver = XCVR_INTERNAL;
if (XEmac_mIsSgDma(&lp->Emac)) {
if ((ret = XEmac_GetPktThreshold(&lp->Emac, XEM_SEND, &threshold)) == XST_SUCCESS) {
ecmd->maxtxpkt = threshold;
} else
return -EIO;
if ((ret = XEmac_GetPktThreshold(&lp->Emac, XEM_RECV, &threshold)) == XST_SUCCESS) {
ecmd->maxrxpkt = threshold;
} else
return -EIO;
}
return 0;
}
static int
xenet_ethtool_get_coalesce (struct net_device *dev, struct ethtool_coalesce* ec)
{
int ret;
struct net_local *lp = (struct net_local *) dev->priv;
u8 threshold;
memset (ec, 0, sizeof(struct ethtool_coalesce));
if ((ret = XEmac_GetPktThreshold(&lp->Emac, XEM_RECV, &threshold)) != XST_SUCCESS) {
printk(KERN_INFO "XEmac_GetPktThreshold error %d\n", ret);
return -EIO;
}
ec->rx_max_coalesced_frames = threshold;
if ((ret = XEmac_GetPktWaitBound (&lp->Emac, XEM_RECV, &(ec->rx_coalesce_usecs))) != XST_SUCCESS) {
printk (KERN_INFO "XEmac_GetPktWaitBound error %d\n", ret);
return -EIO;
}
if ((ret = XEmac_GetPktThreshold(&lp->Emac, XEM_SEND, &threshold)) != XST_SUCCESS) {
printk (KERN_INFO "XEmac_GetPktThreshold send error %d\n", ret);
return -EIO;
}
ec->tx_max_coalesced_frames = threshold;
if ((ret = XEmac_GetPktWaitBound (&lp->Emac, XEM_SEND, &(ec->tx_coalesce_usecs))) != XST_SUCCESS) {
printk (KERN_INFO "XEmac_GetPktWaitBound send error %d\n", ret);
return -EIO;
}
return 0;
}
static int
xenet_ethtool_set_coalesce (struct net_device *dev, struct ethtool_coalesce* ec)
{
int ret;
struct net_local *lp = (struct net_local *) dev->priv;
unsigned long flags;
spin_lock_irqsave(reset_lock, flags);
if ((ret = XEmac_Stop(&lp->Emac)) != XST_SUCCESS)
return -EIO;
if ((ret = XEmac_SetPktThreshold(&lp->Emac, XEM_RECV, ec->rx_max_coalesced_frames)) != XST_SUCCESS) {
printk (KERN_INFO "XEmac_SetPktThreshold error %d\n", ret);
return -EIO;
}
if ((ret = XEmac_SetPktWaitBound (&lp->Emac, XEM_RECV, ec->rx_coalesce_usecs)) != XST_SUCCESS) {
printk (KERN_INFO "XEmac_SetPktWaitBound error %d\n", ret);
return -EIO;
}
if ((ret = XEmac_SetPktThreshold(&lp->Emac, XEM_SEND, ec->tx_max_coalesced_frames)) != XST_SUCCESS) {
printk (KERN_INFO "XEmac_SetPktThreshold send error %d\n", ret);
return -EIO;
}
if ((ret = XEmac_SetPktWaitBound (&lp->Emac, XEM_SEND, ec->tx_coalesce_usecs)) != XST_SUCCESS) {
printk (KERN_INFO "XEmac_SetPktWaitBound send error %d\n", ret);
return -EIO;
}
if ((ret = XEmac_Start(&lp->Emac)) != XST_SUCCESS)
return -EIO;
spin_unlock_irqrestore(reset_lock, flags);
return 0;
}
static int
xenet_ethtool_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo* ed)
{
memset (ed, 0, sizeof(struct ethtool_drvinfo));
strcpy (ed->driver, DRIVER_NAME);
strcpy (ed->version, DRIVER_VERSION);
return 0;
}
static int
xenet_ethtool_get_ringparam (struct net_device *dev, struct ethtool_ringparam* erp)
{
memset (erp, 0, sizeof(struct ethtool_ringparam));
erp->rx_max_pending = XEM_DFT_RECV_DESC;
erp->tx_max_pending = XEM_DFT_SEND_DESC;
erp->rx_pending = XEM_DFT_RECV_DESC;
erp->tx_pending = XEM_DFT_SEND_DESC;
return 0;
}
#define EMAG_REGS_N 32
struct mac_regsDump {
struct ethtool_regs hd;
u16 data[EMAG_REGS_N];
};
static void
xenet_ethtool_get_regs (struct net_device *dev, struct ethtool_regs* regs, void* ret)
{
struct net_local *lp = (struct net_local *) dev->priv;
struct mac_regsDump* dump = (struct mac_regsDump*)regs;
int i;
XStatus r;
dump->hd.version = 0;
dump->hd.len = EMAG_REGS_N * sizeof(dump->data);
for (i=0; i<EMAG_REGS_N; i++) {
if ((r = XEmac_PhyRead (&(lp->Emac), lp->mii_addr, i, &(dump->data[i]))) != XST_SUCCESS) {
printk (KERN_INFO "PhyRead ERROR %d\n", r);
*(int*)ret = -EIO;
return;
}
}
*(int*)ret = 0;
}
static int
xenet_do_ethtool_ioctl (struct net_device *dev, struct ifreq *rq)
{
struct net_local *lp = (struct net_local *) dev->priv;
struct ethtool_cmd ecmd;
struct ethtool_coalesce eco;
struct ethtool_drvinfo edrv;
struct ethtool_ringparam erp;
struct ethtool_pauseparam epp;
struct mac_regsDump regs;
int ret = -EOPNOTSUPP;
XStatus result;
u32 Options;
u16 mii_reg_sset;
u16 mii_reg_spause;
u16 mii_reg_autoneg;
u32 flags;
if (copy_from_user(&ecmd, rq->ifr_data, sizeof (ecmd.cmd)))
return -EFAULT;
switch (ecmd.cmd) {
case ETHTOOL_GSET:
ret = xenet_ethtool_get_settings(dev, &ecmd);
if (ret >= 0) {
if (copy_to_user(rq->ifr_data, &ecmd, sizeof (ecmd)))
ret = -EFAULT;
}
break;
case ETHTOOL_SSET:
if (copy_from_user(&ecmd, rq->ifr_data, sizeof (struct ethtool_cmd)))
return -EFAULT;
mii_reg_sset = 0;
if (ecmd.speed == SPEED_100)
mii_reg_sset |= BMCR_SPEED100;
if (ecmd.duplex == DUPLEX_FULL)
mii_reg_sset |= BMCR_FULLDPLX;
if (ecmd.autoneg == AUTONEG_ENABLE) {
mii_reg_sset |= (BMCR_ANENABLE | BMCR_ANRESTART);
spin_lock_irqsave(reset_lock, flags);
result = XEmac_PhyWrite(&lp->Emac, lp->mii_addr,
MII_BMCR, mii_reg_sset);
if (result != XST_SUCCESS) {
spin_unlock_irqrestore(reset_lock, flags);
ret = -EIO;
break;
}
result = XEmac_PhyRead(&lp->Emac, lp->mii_addr, MII_ADVERTISE, &mii_reg_sset);
if (result != XST_SUCCESS) {
spin_unlock_irqrestore(reset_lock, flags);
ret = -EIO;
break;
}
if (ecmd.speed == SPEED_100) {
if (ecmd.duplex == DUPLEX_FULL) {
mii_reg_sset |= (ADVERTISE_10FULL | ADVERTISE_100FULL |
ADVERTISE_10HALF | ADVERTISE_100HALF);
} else {
mii_reg_sset |= (ADVERTISE_10HALF | ADVERTISE_100HALF);
mii_reg_sset &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL);
}
} else {
if (ecmd.duplex == DUPLEX_FULL) {
mii_reg_sset |= (ADVERTISE_10FULL | ADVERTISE_10HALF);
mii_reg_sset &= ~(ADVERTISE_100FULL| ADVERTISE_100HALF);
} else {
mii_reg_sset |= (ADVERTISE_10HALF);
mii_reg_sset &= ~(ADVERTISE_100FULL| ADVERTISE_100HALF | ADVERTISE_10FULL);
}
}
result = XEmac_PhyWrite(&lp->Emac, lp->mii_addr, MII_ADVERTISE, mii_reg_sset);
spin_unlock_irqrestore(reset_lock, flags);
if (result != XST_SUCCESS) {
ret = -EIO;
break;
}
} else {
mii_reg_sset &= ~(BMCR_ANENABLE | BMCR_ANRESTART);
if (ecmd.duplex == DUPLEX_FULL) {
mii_reg_sset |= BMCR_FULLDPLX;
} else {
mii_reg_sset &= ~BMCR_FULLDPLX;
}
if (ecmd.speed == SPEED_100) {
mii_reg_sset |= BMCR_SPEED100;
} else {
mii_reg_sset &= ~BMCR_SPEED100;
}
spin_lock_irqsave(reset_lock, flags);
result = XEmac_PhyWrite(&lp->Emac, lp->mii_addr,
MII_BMCR, mii_reg_sset);
spin_unlock_irqrestore(reset_lock, flags);
if (result != XST_SUCCESS) {
ret = -EIO;
break;
}
}
ret = 0;
break;
case ETHTOOL_GPAUSEPARAM:
ret = xenet_ethtool_get_settings(dev, &ecmd);
if (ret < 0) {
break;
}
epp.cmd = ecmd.cmd;
epp.autoneg = ecmd.autoneg;
Options = XEmac_GetOptions(&lp->Emac);
if (Options & XEM_INSERT_PAD_OPTION) {
epp.rx_pause = 1;
epp.tx_pause = 1;
} else {
epp.rx_pause = 0;
epp.tx_pause = 0;
}
if (copy_to_user(rq->ifr_data, &epp, sizeof(struct ethtool_pauseparam)))
ret = -EFAULT;
else
ret = 0;
break;
case ETHTOOL_SPAUSEPARAM:
if (copy_from_user(&epp, rq->ifr_data, sizeof (struct ethtool_pauseparam)))
return -EFAULT;
ret = xenet_ethtool_get_settings(dev, &ecmd);
if (ret < 0) {
break;
}
epp.cmd = ecmd.cmd;
mii_reg_spause = 0;
if (epp.autoneg == AUTONEG_ENABLE) {
mii_reg_spause |= (BMCR_ANENABLE | BMCR_ANRESTART);
} else {
if (ecmd.speed == SPEED_100)
mii_reg_spause |= BMCR_SPEED100;
if (ecmd.duplex == DUPLEX_FULL)
mii_reg_spause |= BMCR_FULLDPLX;
}
spin_lock_irqsave(reset_lock, flags);
result = XEmac_PhyWrite(&lp->Emac, lp->mii_addr,
MII_BMCR, mii_reg_spause);
spin_unlock_irqrestore(reset_lock, flags);
if (result != XST_SUCCESS) {
ret = -EIO;
break;
}
if (epp.rx_pause != epp.tx_pause) {
ret = 0;
break;
} else {
spin_lock_irqsave(reset_lock, flags);
(void)XEmac_Stop(&(lp->Emac));
Options = XEmac_GetOptions(&lp->Emac);
if (epp.rx_pause)
Options |= XEM_INSERT_PAD_OPTION;
else
Options &= ~XEM_INSERT_PAD_OPTION;
(void)XEmac_SetOptions(&lp->Emac,Options);
(void)XEmac_Start(&(lp->Emac));
spin_unlock_irqrestore(reset_lock, flags);
}
ret = 0;
break;
case ETHTOOL_GCOALESCE:
eco.cmd = ecmd.cmd;
ret = xenet_ethtool_get_coalesce(dev, &eco);
if (ret >= 0) {
if (copy_to_user(rq->ifr_data, &eco, sizeof (struct ethtool_coalesce)))
ret = -EFAULT;
}
break;
case ETHTOOL_SCOALESCE:
if (copy_from_user(&eco, rq->ifr_data, sizeof (struct ethtool_coalesce)))
return -EFAULT;
ret = xenet_ethtool_set_coalesce(dev, &eco);
break;
case ETHTOOL_GDRVINFO:
edrv.cmd = edrv.cmd;
ret = xenet_ethtool_get_drvinfo(dev, &edrv);
if (ret >= 0) {
if (copy_to_user(rq->ifr_data, &edrv, sizeof (struct ethtool_drvinfo)))
ret = -EFAULT;
}
break;
case ETHTOOL_GREGS:
regs.hd.cmd = edrv.cmd;
xenet_ethtool_get_regs (dev, &(regs.hd), &ret);
if (ret >= 0) {
if (copy_to_user(rq->ifr_data, ®s, sizeof (struct mac_regsDump)))
ret = -EFAULT;
}
break;
case ETHTOOL_GRINGPARAM:
erp.cmd = edrv.cmd;
ret = xenet_ethtool_get_ringparam (dev, &(erp));
if (ret >= 0) {
if (copy_to_user(rq->ifr_data, &erp, sizeof (struct ethtool_ringparam)))
ret = -EFAULT;
}
break;
case ETHTOOL_NWAY_RST:
epp.cmd = ecmd.cmd;
mii_reg_autoneg = 0;
mii_reg_autoneg |= (BMCR_ANENABLE | BMCR_ANRESTART);
spin_lock_irqsave(reset_lock, flags);
result = XEmac_PhyWrite(&lp->Emac, lp->mii_addr,
MII_BMCR, mii_reg_autoneg);
spin_unlock_irqrestore(reset_lock, flags);
if (result != XST_SUCCESS) {
ret = -EIO;
break;
}
ret = 0;
break;
default:
break;
}
return ret;
}
static int
xenet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct net_local *lp = (struct net_local *) dev->priv;
/* mii_ioctl_data has 4 u16 fields: phy_id, reg_num, val_in & val_out */
struct mii_ioctl_data *data = (struct mii_ioctl_data *) &rq->ifr_data;
struct {
__u8 threshold;
__u32 direction;
} thr_arg;
struct {
__u32 waitbound;
__u32 direction;
} wbnd_arg ;
XStatus ret;
unsigned long flags;
XStatus Result;
switch (cmd) {
case SIOCETHTOOL:
return xenet_do_ethtool_ioctl(dev, rq);
case SIOCGMIIPHY: /* Get address of MII PHY in use. */
case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */
data->phy_id = lp->mii_addr;
/* Fall Through */
case SIOCGMIIREG: /* Read MII PHY register. */
case SIOCDEVPRIVATE + 1: /* for binary compat, remove in 2.5 */
if (data->phy_id > 31 || data->reg_num > 31)
return -ENXIO;
/* Stop the PHY timer to prevent reentrancy. */
del_timer_sync(&lp->phy_timer);
spin_lock_irqsave(reset_lock, flags);
Result = XEmac_PhyRead(&lp->Emac, data->phy_id,
data->reg_num, &data->val_out);
/* Start the PHY timer up again. */
spin_unlock_irqrestore(reset_lock, flags);
lp->phy_timer.expires = jiffies + 2 * HZ;
add_timer(&lp->phy_timer);
if (Result != XST_SUCCESS) {
printk(KERN_ERR
"%s: Could not read from PHY, error=%d.\n",
dev->name, Result);
return (Result == XST_EMAC_MII_BUSY) ? -EBUSY : -EIO;
}
return 0;
case SIOCSMIIREG: /* Write MII PHY register. */
case SIOCDEVPRIVATE + 2: /* for binary compat, remove in 2.5 */
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (data->phy_id > 31 || data->reg_num > 31)
return -ENXIO;
/* Stop the PHY timer to prevent reentrancy. */
del_timer_sync(&lp->phy_timer);
spin_lock_irqsave(reset_lock, flags);
Result = XEmac_PhyWrite(&lp->Emac, data->phy_id,
data->reg_num, data->val_in);
spin_unlock_irqrestore(reset_lock, flags);
/* Start the PHY timer up again. */
lp->phy_timer.expires = jiffies + 2 * HZ;
add_timer(&lp->phy_timer);
if (Result != XST_SUCCESS) {
printk(KERN_ERR
"%s: Could not write to PHY, error=%d.\n",
dev->name, Result);
return (Result == XST_EMAC_MII_BUSY) ? -EBUSY : -EIO;
}
return 0;
case SIOCDEVPRIVATE + 3: /* set THRESHOLD */
if (copy_from_user(&thr_arg, rq->ifr_data, sizeof(thr_arg))) {
return -EFAULT;
}
spin_lock_irqsave(reset_lock, flags);
if ((ret = XEmac_Stop(&lp->Emac)) != XST_SUCCESS) {
return -EIO;
}
if ((ret = XEmac_SetPktThreshold(&lp->Emac, thr_arg.direction, thr_arg.threshold)) != XST_SUCCESS) {
return -EIO;
}
if ((ret = XEmac_Start(&lp->Emac)) != XST_SUCCESS) {
return -EIO;
}
spin_unlock_irqrestore(reset_lock, flags);
return 0;
case SIOCDEVPRIVATE + 4: /* set WAITBOUND */
if (copy_from_user(&wbnd_arg, rq->ifr_data, sizeof(wbnd_arg))) {
return -EFAULT;
}
spin_lock_irqsave(reset_lock, flags);
if ((ret = XEmac_Stop(&lp->Emac)) != XST_SUCCESS) {
return -EIO;
}
if ((ret = XEmac_SetPktWaitBound(&lp->Emac, wbnd_arg.direction, wbnd_arg.waitbound)) != XST_SUCCESS) {
return -EIO;
}
if ((ret = XEmac_Start(&lp->Emac)) != XST_SUCCESS) {
return -EIO;
}
spin_unlock_irqrestore(reset_lock, flags);
return 0;
case SIOCDEVPRIVATE + 5: /* get THRESHOLD */
if (copy_from_user(&thr_arg, rq->ifr_data, sizeof(thr_arg))) {
return -EFAULT;
}
if ((ret = XEmac_GetPktThreshold(&lp->Emac, thr_arg.direction, &(thr_arg.threshold))) != XST_SUCCESS) {
return -EIO;
}
if (copy_to_user(rq->ifr_data, &thr_arg, sizeof(thr_arg))) {
return -EFAULT;
}
return 0;
case SIOCDEVPRIVATE + 6: /* get WAITBOUND */
if (copy_from_user(&wbnd_arg, rq->ifr_data, sizeof(wbnd_arg))) {
return -EFAULT;
}
if ((ret = XEmac_GetPktWaitBound(&lp->Emac, wbnd_arg.direction, &(wbnd_arg.waitbound))) != XST_SUCCESS) {
return -EIO;
}
if (copy_to_user(rq->ifr_data, &wbnd_arg, sizeof(wbnd_arg))) {
return -EFAULT;
}
return 0;
default:
return -EOPNOTSUPP;
}
}
static void
remove_head_dev(void)
{
struct net_local *lp;
struct net_device *dev;
XEmac_Config *cfg;
/* Pull the head off of dev_list. */
spin_lock(&dev_lock);
dev = dev_list;
lp = (struct net_local *) dev->priv;
dev_list = lp->next_dev;
spin_unlock(&dev_lock);
/* Put the physical address back */
cfg = XEmac_GetConfig(lp->index);
iounmap((void *) cfg->BaseAddress);
cfg->BaseAddress = cfg->PhysAddress;
/* Free up the memory. */
if (lp->desc_space)
{
free_descriptor_skb(dev);
consistent_free(lp->desc_space);
}
if (lp->ddrVirtPtr) {
kfree (lp->ddrVirtPtr);
}
unregister_netdev(dev);
kfree(dev);
}
static int __init
probe(int index)
{
static const unsigned long remap_size
= XPAR_EMAC_0_HIGHADDR - XPAR_EMAC_0_BASEADDR + 1;
struct net_device *dev;
struct net_local *lp;
XEmac_Config *cfg;
unsigned int irq;
u32 maddr;
switch (index) {
#if defined(XPAR_INTC_0_EMAC_0_VEC_ID)
case 0:
irq = 31 - XPAR_INTC_0_EMAC_0_VEC_ID;
break;
#if defined(XPAR_INTC_0_EMAC_1_VEC_ID)
case 1:
irq = 31 - XPAR_INTC_0_EMAC_1_VEC_ID;
break;
#if defined(XPAR_INTC_0_EMAC_2_VEC_ID)
case 2:
irq = 31 - XPAR_INTC_0_EMAC_2_VEC_ID;
break;
#if defined(XPAR_INTC_0_EMAC_3_VEC_ID)
#error Edit this file to add more devices.
#endif /* 3 */
#endif /* 2 */
#endif /* 1 */
#endif /* 0 */
default:
return -ENODEV;
}
/* Find the config for our device. */
cfg = XEmac_GetConfig(index);
if (!cfg)
return -ENODEV;
dev = init_etherdev(0, sizeof (struct net_local));
if (!dev) {
printk(KERN_ERR "Could not allocate Xilinx enet device %d.\n",
index);
return -ENOMEM;
}
SET_MODULE_OWNER(dev);
ether_setup(dev);
dev->irq = irq;
/* Initialize our private data. */
lp = (struct net_local *) dev->priv;
memset(lp, 0, sizeof (struct net_local));
lp->index = index;
lp->dev = dev;
/* Make it the head of dev_list. */
spin_lock(&dev_lock);
lp->next_dev = dev_list;
dev_list = dev;
spin_unlock(&dev_lock);
/* Change the addresses to be virtual */
cfg->PhysAddress = cfg->BaseAddress;
cfg->BaseAddress = (u32) ioremap(cfg->PhysAddress, remap_size);
if (XEmac_Initialize(&lp->Emac, cfg->DeviceId) != XST_SUCCESS) {
printk(KERN_ERR "%s: Could not initialize device.\n",
dev->name);
remove_head_dev();
return -ENODEV;
}
memcpy(dev->dev_addr, ((bd_t *) __res)->bi_enetaddr, 6);
if (XEmac_SetMacAddress(&lp->Emac, dev->dev_addr) != XST_SUCCESS) {
/* should not fail right after an initialize */
printk(KERN_ERR "%s: Could not set MAC address.\n", dev->name);
remove_head_dev();
return -EIO;
}
if (XEmac_mIsSgDma(&lp->Emac)) {
int result;
printk(KERN_ERR "%s: using sgDMA mode.\n", dev->name);
XEmac_SetSgRecvHandler(&lp->Emac, dev, SgRecvHandler);
XEmac_SetSgSendHandler(&lp->Emac, dev, SgSendHandler);
dev->hard_start_xmit = xenet_SgSend;
lp->Isr = XEmac_IntrHandlerDma;
result = descriptor_init(dev);
if (result) {
remove_head_dev();
return -EIO;
}
/* set the packet threshold and waitbound*/
XEmac_SetPktThreshold(&lp->Emac, XEM_SEND, 31);
XEmac_SetPktThreshold(&lp->Emac, XEM_RECV, 31);
(void) XEmac_SetPktWaitBound(&lp->Emac, XEM_SEND, 5);
(void) XEmac_SetPktWaitBound(&lp->Emac, XEM_RECV, 5);
/* disable SGEND interrupt */
XEmac_SetOptions(&lp->Emac, XEmac_GetOptions(&lp->Emac) |
XEM_NO_SGEND_INT_OPTION);
} else {
printk(KERN_ERR "%s: using fifo mode.\n", dev->name);
XEmac_SetFifoRecvHandler(&lp->Emac, dev, FifoRecvHandler);
XEmac_SetFifoSendHandler(&lp->Emac, dev, FifoSendHandler);
dev->hard_start_xmit = xenet_FifoSend;
lp->Isr = XEmac_IntrHandlerFifo;
}
XEmac_SetErrorHandler(&lp->Emac, dev, ErrorHandler);
/* Scan to find the PHY. */
lp->mii_addr = 0xFF;
for (maddr = 0; maddr < 31; maddr++) {
XStatus Result;
u16 reg;
Result = XEmac_PhyRead(&lp->Emac, maddr, MII_BMCR, ®);
/*
* XEmac_PhyRead is currently returning XST_SUCCESS even
* when reading from non-existent addresses. Work
* around this by doing a primitive validation on the
* control word we get back.
*/
if (Result == XST_SUCCESS && (reg & BMCR_RESV) == 0) {
lp->mii_addr = maddr;
break;
}
}
if (lp->mii_addr == 0xFF) {
lp->mii_addr = 0;
printk(KERN_WARNING
"%s: No PHY detected. Assuming a PHY at address %d.\n",
dev->name, lp->mii_addr);
}
dev->open = xenet_open;
dev->stop = xenet_close;
dev->get_stats = xenet_get_stats;
dev->flags &= ~IFF_MULTICAST;
dev->set_multicast_list = xenet_set_multicast_list;
dev->do_ioctl = xenet_ioctl;
dev->tx_timeout = xenet_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HW_CSUM;
printk(KERN_INFO
"%s: Xilinx EMAC #%d at 0x%08X mapped to 0x%08X, irq=%d\n",
dev->name, index, cfg->PhysAddress, cfg->BaseAddress, dev->irq);
/* print h/w id */
{
u32 id = XIo_In32(cfg->BaseAddress + XIIF_V123B_RESETR_OFFSET);
printk("%s: id %d.%d%c; block id %d, type %d\n",
dev->name, (id >> 28) & 0xf, (id >> 21) & 0x7f,
((id >> 16) & 0x1f) + 'a',
(id >> 16) & 0xff, (id >> 0) & 0xff);
}
return 0;
}
static int __init
xenet_init(void)
{
int index = 0;
while (probe(index++) == 0) ;
/* If we found at least one, report success. */
return (index > 1) ? 0 : -ENODEV;
}
static void __exit
xenet_cleanup(void)
{
while (dev_list)
remove_head_dev();
}
EXPORT_NO_SYMBOLS;
module_init(xenet_init);
module_exit(xenet_cleanup);
^ permalink raw reply
* Re: [PATCH 6/10] Add 8641 Register space and IRQ definitions.
From: Kumar Gala @ 2006-06-08 4:57 UTC (permalink / raw)
To: Jon Loeliger; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <1149720021.23938.198.camel@cashmere.sps.mot.com>
On Jun 7, 2006, at 5:40 PM, Jon Loeliger wrote:
>
> Signed-off-by: Jon Loeliger <jdl@freescale.com>
> Signed-off-by: Jeff Brown <Jeff.Brown@freescale.com>
> Signed-off-by: Xianghua Xiao <x.xiao@freescale.com>
>
> ---
>
> include/asm-powerpc/immap_86xx.h | 199 +++++++++++++++++++++++++++
> +++++++++++
> include/asm-powerpc/irq.h | 88 +++++++++++++++++
> include/asm-powerpc/mpc86xx.h | 95 ++++++++++++++++++
> include/asm-powerpc/reg.h | 1
> 4 files changed, 383 insertions(+), 0 deletions(-)
>
>
> diff --git a/include/asm-powerpc/immap_86xx.h b/include/asm-powerpc/
> immap_86xx.h
> new file mode 100644
> index 0000000..d905b66
> --- /dev/null
> +++ b/include/asm-powerpc/immap_86xx.h
> @@ -0,0 +1,199 @@
> +/*
> + * MPC86xx Internal Memory Map
> + *
> + * Author: Jeff Brown
> + *
> + * Copyright 2004 Freescale Semiconductor, 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.
> + *
> + */
> +
> +#ifndef __ASM_POWERPC_IMMAP_86XX_H__
> +#define __ASM_POWERPC_IMMAP_86XX_H__
> +#ifdef __KERNEL__
> +
> +/* Eventually this should define all the IO block registers in
> 86xx */
> +
> +/* PCI Registers */
> +typedef struct ccsr_pci {
> + uint cfg_addr; /* 0x.000 - PCI Configuration Address Register */
> + uint cfg_data; /* 0x.004 - PCI Configuration Data Register */
> + uint int_ack; /* 0x.008 - PCI Interrupt Acknowledge Register */
> + char res1[3060];
> + uint potar0; /* 0x.c00 - PCI Outbound Transaction Address
> Register 0 */
> + uint potear0; /* 0x.c04 - PCI Outbound Translation Extended
> Address Register 0 */
> + uint powbar0; /* 0x.c08 - PCI Outbound Window Base Address
> Register 0 */
> + char res2[4];
> + uint powar0; /* 0x.c10 - PCI Outbound Window Attributes Register
> 0 */
> + char res3[12];
> + uint potar1; /* 0x.c20 - PCI Outbound Transaction Address
> Register 1 */
> + uint potear1; /* 0x.c24 - PCI Outbound Translation Extended
> Address Register 1 */
> + uint powbar1; /* 0x.c28 - PCI Outbound Window Base Address
> Register 1 */
> + char res4[4];
> + uint powar1; /* 0x.c30 - PCI Outbound Window Attributes Register
> 1 */
> + char res5[12];
> + uint potar2; /* 0x.c40 - PCI Outbound Transaction Address
> Register 2 */
> + uint potear2; /* 0x.c44 - PCI Outbound Translation Extended
> Address Register 2 */
> + uint powbar2; /* 0x.c48 - PCI Outbound Window Base Address
> Register 2 */
> + char res6[4];
> + uint powar2; /* 0x.c50 - PCI Outbound Window Attributes Register
> 2 */
> + char res7[12];
> + uint potar3; /* 0x.c60 - PCI Outbound Transaction Address
> Register 3 */
> + uint potear3; /* 0x.c64 - PCI Outbound Translation Extended
> Address Register 3 */
> + uint powbar3; /* 0x.c68 - PCI Outbound Window Base Address
> Register 3 */
> + char res8[4];
> + uint powar3; /* 0x.c70 - PCI Outbound Window Attributes Register
> 3 */
> + char res9[12];
> + uint potar4; /* 0x.c80 - PCI Outbound Transaction Address
> Register 4 */
> + uint potear4; /* 0x.c84 - PCI Outbound Translation Extended
> Address Register 4 */
> + uint powbar4; /* 0x.c88 - PCI Outbound Window Base Address
> Register 4 */
> + char res10[4];
> + uint powar4; /* 0x.c90 - PCI Outbound Window Attributes Register
> 4 */
> + char res11[268];
> + uint pitar3; /* 0x.da0 - PCI Inbound Translation Address
> Register 3 */
> + char res12[4];
> + uint piwbar3; /* 0x.da8 - PCI Inbound Window Base Address
> Register 3 */
> + uint piwbear3; /* 0x.dac - PCI Inbound Window Base Extended
> Address Register 3 */
> + uint piwar3; /* 0x.db0 - PCI Inbound Window Attributes Register
> 3 */
> + char res13[12];
> + uint pitar2; /* 0x.dc0 - PCI Inbound Translation Address
> Register 2 */
> + char res14[4];
> + uint piwbar2; /* 0x.dc8 - PCI Inbound Window Base Address
> Register 2 */
> + uint piwbear2; /* 0x.dcc - PCI Inbound Window Base Extended
> Address Register 2 */
> + uint piwar2; /* 0x.dd0 - PCI Inbound Window Attributes Register
> 2 */
> + char res15[12];
> + uint pitar1; /* 0x.de0 - PCI Inbound Translation Address
> Register 1 */
> + char res16[4];
> + uint piwbar1; /* 0x.de8 - PCI Inbound Window Base Address
> Register 1 */
> + char res17[4];
> + uint piwar1; /* 0x.df0 - PCI Inbound Window Attributes Register
> 1 */
> + char res18[12];
> + uint err_dr; /* 0x.e00 - PCI Error Detect Register */
> + uint err_cap_dr; /* 0x.e04 - PCI Error Capture Disable Register */
> + uint err_en; /* 0x.e08 - PCI Error Enable Register */
> + uint err_attrib; /* 0x.e0c - PCI Error Attributes Capture
> Register */
> + uint err_addr; /* 0x.e10 - PCI Error Address Capture Register */
> + uint err_ext_addr; /* 0x.e14 - PCI Error Extended Address Capture
> Register */
> + uint err_dl; /* 0x.e18 - PCI Error Data Low Capture Register */
> + uint err_dh; /* 0x.e1c - PCI Error Data High Capture Register */
> + uint gas_timr; /* 0x.e20 - PCI Gasket Timer Register */
> + uint pci_timr; /* 0x.e24 - PCI Timer Register */
> + char res19[472];
> +} ccsr_pci_t;
> +
> +/* PCI Express Registers */
> +typedef struct ccsr_pex {
> + uint pex_config_addr; /* 0x.000 - PCI Express
> Configuration Address Register */
> + uint pex_config_data; /* 0x.004 - PCI Express
> Configuration Data Register */
> + char res1[4];
> + uint pex_otb_cpl_tor; /* 0x.00c - PCI Express Outbound
> completion timeout register */
> + uint pex_conf_tor; /* 0x.010 - PCI Express
> configuration timeout register */
> + char res2[12];
> + uint pex_pme_mes_dr; /* 0x.020 - PCI Express PME and
> message detect register */
> + uint pex_pme_mes_disr; /* 0x.024 - PCI Express PME and
> message disable register */
> + uint pex_pme_mes_ier; /* 0x.028 - PCI Express PME and
> message interrupt enable register */
> + uint pex_pmcr; /* 0x.02c - PCI Express power
> management command register */
> + char res3[3024];
> + uint pexotar0; /* 0x.c00 - PCI Express outbound
> translation address register 0 */
> + uint pexotear0; /* 0x.c04 - PCI Express outbound
> translation extended address register 0*/
> + char res4[8];
> + uint pexowar0; /* 0x.c10 - PCI Express outbound
> window attributes register 0*/
> + char res5[12];
> + uint pexotar1; /* 0x.c20 - PCI Express outbound
> translation address register 1 */
> + uint pexotear1; /* 0x.c24 - PCI Express outbound
> translation extended address register 1*/
> + uint pexowbar1; /* 0x.c28 - PCI Express outbound
> window base address register 1*/
> + char res6[4];
> + uint pexowar1; /* 0x.c30 - PCI Express outbound
> window attributes register 1*/
> + char res7[12];
> + uint pexotar2; /* 0x.c40 - PCI Express outbound
> translation address register 2 */
> + uint pexotear2; /* 0x.c44 - PCI Express outbound
> translation extended address register 2*/
> + uint pexowbar2; /* 0x.c48 - PCI Express outbound
> window base address register 2*/
> + char res8[4];
> + uint pexowar2; /* 0x.c50 - PCI Express outbound
> window attributes register 2*/
> + char res9[12];
> + uint pexotar3; /* 0x.c60 - PCI Express outbound
> translation address register 3 */
> + uint pexotear3; /* 0x.c64 - PCI Express outbound
> translation extended address register 3*/
> + uint pexowbar3; /* 0x.c68 - PCI Express outbound
> window base address register 3*/
> + char res10[4];
> + uint pexowar3; /* 0x.c70 - PCI Express outbound
> window attributes register 3*/
> + char res11[12];
> + uint pexotar4; /* 0x.c80 - PCI Express outbound
> translation address register 4 */
> + uint pexotear4; /* 0x.c84 - PCI Express outbound
> translation extended address register 4*/
> + uint pexowbar4; /* 0x.c88 - PCI Express outbound
> window base address register 4*/
> + char res12[4];
> + uint pexowar4; /* 0x.c90 - PCI Express outbound
> window attributes register 4*/
> + char res13[12];
> + char res14[256];
> + uint pexitar3; /* 0x.da0 - PCI Express inbound
> translation address register 3 */
> + char res15[4];
> + uint pexiwbar3; /* 0x.da8 - PCI Express inbound
> window base address register 3 */
> + uint pexiwbear3; /* 0x.dac - PCI Express inbound
> window base extended address register 3 */
> + uint pexiwar3; /* 0x.db0 - PCI Express inbound
> window attributes register 3 */
> + char res16[12];
> + uint pexitar2; /* 0x.dc0 - PCI Express inbound
> translation address register 2 */
> + char res17[4];
> + uint pexiwbar2; /* 0x.dc8 - PCI Express inbound
> window base address register 2 */
> + uint pexiwbear2; /* 0x.dcc - PCI Express inbound
> window base extended address register 2 */
> + uint pexiwar2; /* 0x.dd0 - PCI Express inbound
> window attributes register 2 */
> + char res18[12];
> + uint pexitar1; /* 0x.de0 - PCI Express inbound
> translation address register 2 */
> + char res19[4];
> + uint pexiwbar1; /* 0x.de8 - PCI Express inbound
> window base address register 2 */
> + uint pexiwbear1; /* 0x.dec - PCI Express inbound
> window base extended address register 2 */
> + uint pexiwar1; /* 0x.df0 - PCI Express inbound
> window attributes register 2 */
> + char res20[12];
> + uint pex_err_dr; /* 0x.e00 - PCI Express error
> detect register */
> + char res21[4];
> + uint pex_err_en; /* 0x.e08 - PCI Express error
> interrupt enable register */
> + char res22[4];
> + uint pex_err_disr; /* 0x.e10 - PCI Express error
> disable register */
> + char res23[12];
> + uint pex_err_cap_stat; /* 0x.e20 - PCI Express error
> capture status register */
> + char res24[4];
> + uint pex_err_cap_r0; /* 0x.e28 - PCI Express error
> capture register 0 */
> + uint pex_err_cap_r1; /* 0x.e2c - PCI Express error
> capture register 0 */
> + uint pex_err_cap_r2; /* 0x.e30 - PCI Express error
> capture register 0 */
> + uint pex_err_cap_r3; /* 0x.e34 - PCI Express error
> capture register 0 */
> +} ccsr_pex_t;
> +
> +/* Global Utility Registers */
> +typedef struct ccsr_guts {
> + uint porpllsr; /* 0x.0000 - POR PLL Ratio Status Register */
> + uint porbmsr; /* 0x.0004 - POR Boot Mode Status Register */
> + uint porimpscr; /* 0x.0008 - POR I/O Impedance Status and Control
> Register */
> + uint pordevsr; /* 0x.000c - POR I/O Device Status Register */
> + uint pordbgmsr; /* 0x.0010 - POR Debug Mode Status Register */
> + char res1[12];
> + uint gpporcr; /* 0x.0020 - General-Purpose POR Configuration
> Register */
> + char res2[12];
> + uint gpiocr; /* 0x.0030 - GPIO Control Register */
> + char res3[12];
> + uint gpoutdr; /* 0x.0040 - General-Purpose Output Data Register */
> + char res4[12];
> + uint gpindr; /* 0x.0050 - General-Purpose Input Data Register */
> + char res5[12];
> + uint pmuxcr; /* 0x.0060 - Alternate Function Signal Multiplex
> Control */
> + char res6[12];
> + uint devdisr; /* 0x.0070 - Device Disable Control */
> + char res7[12];
> + uint powmgtcsr; /* 0x.0080 - Power Management Status and Control
> Register */
> + char res8[12];
> + uint mcpsumr; /* 0x.0090 - Machine Check Summary Register */
> + char res9[12];
> + uint pvr; /* 0x.00a0 - Processor Version Register */
> + uint svr; /* 0x.00a4 - System Version Register */
> + char res10[3416];
> + uint clkocr; /* 0x.0e00 - Clock Out Select Register */
> + char res11[12];
> + uint ddrdllcr; /* 0x.0e10 - DDR DLL Control Register */
> + char res12[12];
> + uint lbcdllcr; /* 0x.0e20 - LBC DLL Control Register */
> + char res13[61916];
> +} ccsr_guts_t;
> +
> +#endif /* __ASM_POWERPC_IMMAP_86XX_H__ */
> +#endif /* __KERNEL__ */
> diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h
> index 7bc6d73..997d2e8 100644
> --- a/include/asm-powerpc/irq.h
> +++ b/include/asm-powerpc/irq.h
> @@ -348,6 +348,94 @@ #define SIU_INT_PC2 ((uint)0x3d+CPM_IRQ
> #define SIU_INT_PC1 ((uint)0x3e+CPM_IRQ_OFFSET)
> #define SIU_INT_PC0 ((uint)0x3f+CPM_IRQ_OFFSET)
>
> +#elif defined(CONFIG_PPC_86xx)
> +#include <asm/mpc86xx.h>
> +
> +#define NR_EPIC_INTS 48
> +#ifndef NR_8259_INTS
> +#define NR_8259_INTS 16 /*ULI 1575 can route 12 interrupts */
> +#endif
> +#define NUM_8259_INTERRUPTS NR_8259_INTS
> +
> +#ifndef I8259_OFFSET
> +#define I8259_OFFSET 0
> +#endif
> +
> +#define NR_IRQS 256
> +
> +/* Internal IRQs on MPC86xx OpenPIC */
> +
> +#ifndef MPC86xx_OPENPIC_IRQ_OFFSET
> +#define MPC86xx_OPENPIC_IRQ_OFFSET NR_8259_INTS
> +#endif
> +
> +/* The 48 internal sources */
> +#define MPC86xx_IRQ_NULL ( 0 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_MCM ( 1 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_DDR ( 2 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_LBC ( 3 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_DMA0 ( 4 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_DMA1 ( 5 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_DMA2 ( 6 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_DMA3 ( 7 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_PEX1 ( 8 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_PEX2 ( 9 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +
> +/* no 10,11 */
> +#define MPC86xx_IRQ_UART2 (12 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_TSEC1_TX (13 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_TSEC1_RX (14 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_TSEC3_TX (15 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_TSEC3_RX (16 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_TSEC3_ERROR (17 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_TSEC1_ERROR (18 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_TSEC2_TX (19 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_TSEC2_RX (20 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_TSEC4_TX (21 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_TSEC4_RX (22 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_TSEC4_ERROR (23 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_TSEC2_ERROR (24 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +/* no 25 */
> +#define MPC86xx_IRQ_UART1 (26 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_IIC (27 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_PERFMON (28 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +/* no 29,30,31 */
> +#define MPC86xx_IRQ_SRIO_ERROR (32 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_SRIO_OUT_BELL (33 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_SRIO_IN_BELL (34 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +/* no 35,36 */
> +#define MPC86xx_IRQ_SRIO_OUT_MSG1 (37 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_SRIO_IN_MSG1 (38 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_SRIO_OUT_MSG2 (39 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_SRIO_IN_MSG2 (40 + MPC86xx_OPENPIC_IRQ_OFFSET)
> +
> +/* The 12 external interrupt lines */
> +#define MPC86xx_IRQ_EXT_BASE 48
> +#define MPC86xx_IRQ_EXT0 (0 + MPC86xx_IRQ_EXT_BASE \
> + + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_EXT1 (1 + MPC86xx_IRQ_EXT_BASE \
> + + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_EXT2 (2 + MPC86xx_IRQ_EXT_BASE \
> + + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_EXT3 (3 + MPC86xx_IRQ_EXT_BASE \
> + + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_EXT4 (4 + MPC86xx_IRQ_EXT_BASE \
> + + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_EXT5 (5 + MPC86xx_IRQ_EXT_BASE \
> + + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_EXT6 (6 + MPC86xx_IRQ_EXT_BASE \
> + + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_EXT7 (7 + MPC86xx_IRQ_EXT_BASE \
> + + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_EXT8 (8 + MPC86xx_IRQ_EXT_BASE \
> + + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_EXT9 (9 + MPC86xx_IRQ_EXT_BASE \
> + + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_EXT10 (10 + MPC86xx_IRQ_EXT_BASE \
> + + MPC86xx_OPENPIC_IRQ_OFFSET)
> +#define MPC86xx_IRQ_EXT11 (11 + MPC86xx_IRQ_EXT_BASE \
> + + MPC86xx_OPENPIC_IRQ_OFFSET)
> +
> #else /* CONFIG_40x + CONFIG_8xx */
> /*
> * this is the # irq's for all ppc arch's (pmac/chrp/prep)
> diff --git a/include/asm-powerpc/mpc86xx.h b/include/asm-powerpc/
> mpc86xx.h
> new file mode 100644
> index 0000000..03942a2
> --- /dev/null
> +++ b/include/asm-powerpc/mpc86xx.h
> @@ -0,0 +1,95 @@
> +/*
> + * MPC86xx definitions
> + *
> + * Author: Jeff Brown
> + *
> + * Copyright 2004 Freescale Semiconductor, 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.
> + */
> +
> +#ifdef __KERNEL__
> +#ifndef __ASM_POWERPC_MPC86xx_H__
> +#define __ASM_POWERPC_MPC86xx_H__
> +
> +#include <linux/config.h>
> +#include <asm/mmu.h>
> +
> +#ifdef CONFIG_PPC_86xx
> +
> +#ifdef CONFIG_MPC8641_HPCN
> +#include <platforms/86xx/mpc8641_hpcn.h>
> +#endif
> +
> +#define _IO_BASE isa_io_base
> +#define _ISA_MEM_BASE isa_mem_base
> +#ifdef CONFIG_PCI
> +#define PCI_DRAM_OFFSET pci_dram_offset
> +#else
> +#define PCI_DRAM_OFFSET 0
> +#endif
> +
> +#define CPU0_BOOT_RELEASE 0x01000000
> +#define CPU1_BOOT_RELEASE 0x02000000
> +#define CPU_ALL_RELEASED (CPU0_BOOT_RELEASE | CPU1_BOOT_RELEASE)
> +#define MCM_PORT_CONFIG_OFFSET 0x1010
> +
> +/* Offset from CCSRBAR */
> +#define MPC86xx_DMA_OFFSET (0x21000)
> +#define MPC86xx_DMA_SIZE (0x01000)
> +#define MPC86xx_DMA0_OFFSET (0x21100)
> +#define MPC86xx_DMA0_SIZE (0x00080)
> +#define MPC86xx_DMA1_OFFSET (0x21180)
> +#define MPC86xx_DMA1_SIZE (0x00080)
> +#define MPC86xx_DMA2_OFFSET (0x21200)
> +#define MPC86xx_DMA2_SIZE (0x00080)
> +#define MPC86xx_DMA3_OFFSET (0x21280)
> +#define MPC86xx_DMA3_SIZE (0x00080)
> +
> +#define MPC86xx_GUTS_OFFSET (0xe0000)
> +#define MPC86xx_GUTS_SIZE (0x01000)
> +
> +#define MPC86xx_OPENPIC_OFFSET (0x40000)
> +#define MPC86xx_OPENPIC_SIZE (0x40000)
> +#define MPC86xx_PEX1_OFFSET (0x08000)
> +#define MPC86xx_PEX1_SIZE (0x01000)
> +#define MPC86xx_PEX2_OFFSET (0x09000)
> +#define MPC86xx_PEX2_SIZE (0x01000)
> +#define MPC86xx_PERFMON_OFFSET (0xe1000)
> +#define MPC86xx_PERFMON_SIZE (0x01000)
> +#define MPC86xx_UART0_OFFSET (0x04500)
> +#define MPC86xx_UART0_SIZE (0x00100)
> +#define MPC86xx_UART1_OFFSET (0x04600)
> +#define MPC86xx_UART1_SIZE (0x00100)
> +#define MPC86xx_MCM_OFFSET (0x00000)
> +#define MPC86xx_MCM_SIZE (0x02000)
> +
> +#define MPC86xx_CCSRBAR_SIZE (1024*1024)
Let's kill any OFFSET & SIZEs that aren't actually needed in code. I
would hope most of these are going from the flat dev tree.
> +
> +/* Let modules/drivers get at CCSRBAR */
> +extern phys_addr_t get_ccsrbar(void);
> +
> +#ifdef MODULE
> +#define CCSRBAR get_ccsrbar()
> +#else
> +#define CCSRBAR BOARD_CCSRBAR
> +#endif
> +
> +enum ppc_sys_devices {
> + MPC86xx_TSEC1,
> + MPC86xx_TSEC2,
> + MPC86xx_TSEC3,
> + MPC86xx_TSEC4,
> + MPC86xx_DUART,
> + MPC86xx_MDIO,
> + MPC86xx_IIC1,
> + MPC86xx_IIC2,
> + NUM_PPC_SYS_DEVS,
> +};
please kill, I can't imagine any code actually using this.
> +
> +#endif /* CONFIG_PPC_86xx */
> +#endif /* __ASM_POWERPC_MPC86xx_H__ */
> +#endif /* __KERNEL__ */
> diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
> index 0257189..1b1548f 100644
> --- a/include/asm-powerpc/reg.h
> +++ b/include/asm-powerpc/reg.h
> @@ -543,6 +543,7 @@ #define PVR_7410 0x800C0000
> #define PVR_7450 0x80000000
> #define PVR_8540 0x80200000
> #define PVR_8560 0x80200000
> +#define PVR_8641 0x80040000
Does anything code use this define, if not let's kill it. I think we
are trying to reduce such things.
> /*
> * For the 8xx processors, all of them report the same PVR family for
> * the PowerPC core. The various versions of these processors must be
>
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
^ permalink raw reply
* Re: [PATCH 7/10] Add use of mpc86xx.h include files in legacy header files.
From: Kumar Gala @ 2006-06-08 4:49 UTC (permalink / raw)
To: Jon Loeliger; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <1149720157.23938.202.camel@cashmere.sps.mot.com>
On Jun 7, 2006, at 5:42 PM, Jon Loeliger wrote:
>
> Signed-off-by: Xianghua Xiao <x.xiao@freescale.com>
> Signed-off-by: Jon Loeliger <jdl@freescale.com>
>
> ---
>
> include/asm-ppc/io.h | 2 ++
> include/asm-ppc/ppc_sys.h | 2 ++
> include/asm-ppc/serial.h | 2 ++
> 3 files changed, 6 insertions(+), 0 deletions(-)
Are the io.h & serial.h really needed for ARCH=powerpc? What does
serial.h get from asm/mpc86xx.h? I can see the possibility of io.h
needing some stuff from asm/mpc86xx.h
- k
>
> diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h
> index b919d8f..0802be9 100644
> --- a/include/asm-ppc/io.h
> +++ b/include/asm-ppc/io.h
> @@ -37,6 +37,8 @@ #elif defined(CONFIG_83xx)
> #include <asm/mpc83xx.h>
> #elif defined(CONFIG_85xx)
> #include <asm/mpc85xx.h>
> +#elif defined(CONFIG_PPC_86xx)
> +#include <asm/mpc86xx.h>
> #elif defined(CONFIG_APUS)
> #define _IO_BASE 0
> #define _ISA_MEM_BASE 0
> diff --git a/include/asm-ppc/ppc_sys.h b/include/asm-ppc/ppc_sys.h
> index 40f197a..4eaf80d 100644
> --- a/include/asm-ppc/ppc_sys.h
> +++ b/include/asm-ppc/ppc_sys.h
> @@ -27,6 +27,8 @@ #elif defined(CONFIG_83xx)
> #include <asm/mpc83xx.h>
> #elif defined(CONFIG_85xx)
> #include <asm/mpc85xx.h>
> +#elif defined(CONFIG_PPC_86xx)
> +#include <asm/mpc86xx.h>
this should go since I can't imagine your using ppc_sys.
> #elif defined(CONFIG_8xx)
> #include <asm/mpc8xx.h>
> #elif defined(CONFIG_PPC_MPC52xx)
> diff --git a/include/asm-ppc/serial.h b/include/asm-ppc/serial.h
> index b74af54..e819250 100644
> --- a/include/asm-ppc/serial.h
> +++ b/include/asm-ppc/serial.h
> @@ -36,6 +36,8 @@ #elif defined(CONFIG_83xx)
> #include <asm/mpc83xx.h>
> #elif defined(CONFIG_85xx)
> #include <asm/mpc85xx.h>
> +#elif defined(CONFIG_PPC_86xx)
> +#include <asm/mpc86xx.h>
> #elif defined(CONFIG_RADSTONE_PPC7D)
> #include <platforms/radstone_ppc7d.h>
> #else
>
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
^ permalink raw reply
* Re: [PATCH 1/10] Add the mpc8641 hpcn Kconfig and Makefiles.
From: Kumar Gala @ 2006-06-08 4:44 UTC (permalink / raw)
To: Jon Loeliger; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <1149719645.23938.184.camel@cashmere.sps.mot.com>
On Jun 7, 2006, at 5:34 PM, Jon Loeliger wrote:
>
> Signed-off-by: Xianghua Xiao <x.xiao@freescale.com>
> Signed-off-by: Jon Loeliger <jdl@freescale.com>
>
> ---
>
> arch/powerpc/Kconfig | 15 ++++++++++-
> arch/powerpc/platforms/Makefile | 1 +
> arch/powerpc/platforms/86xx/Makefile | 7 +++++
> arch/powerpc/platforms/86xx/Kconfig | 46 +++++++++++++++++++++++
> +++++++++++
> drivers/i2c/busses/Kconfig | 4 +--
> 5 files changed, 69 insertions(+), 4 deletions(-)
>
>
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 75ba0ec..e708401 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -141,6 +141,15 @@ config PPC_85xx
> select FSL_SOC
> select 85xx
>
> +config PPC_86xx
> + bool "Freescale 86xx"
> + select 6xx
> + select FSL_SOC
> + select PPC_FPU
> + select ALTIVEC
> + help
> + The Freescale E600 SoCs have 74xx cores.
> +
> config 40x
> bool "AMCC 40x"
>
> @@ -549,6 +558,7 @@ source arch/powerpc/platforms/embedded6x
> source arch/powerpc/platforms/4xx/Kconfig
> source arch/powerpc/platforms/83xx/Kconfig
> source arch/powerpc/platforms/85xx/Kconfig
> +source arch/powerpc/platforms/86xx/Kconfig
> source arch/powerpc/platforms/8xx/Kconfig
> source arch/powerpc/platforms/cell/Kconfig
>
> @@ -780,6 +790,7 @@ config GENERIC_ISA_DMA
>
> config PPC_I8259
> bool
> + default y if PPC_86xx
> default n
This dependancy seems too generic, shouldn't it be based on some
board (its not like 86xx actually has an i8259 in it).
>
> config PPC_INDIRECT_PCI
> @@ -802,8 +813,8 @@ config MCA
> bool
>
> config PCI
> - bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx ||
> PPC_MPC52xx || (EMBEDDED && PPC_ISERIES)
> - default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx && !
> PPC_85xx
> + bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx ||
> PPC_86xx || PPC_MPC52xx || (EMBEDDED && PPC_ISERIES)
> + default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx && !
> PPC_85xx && !PPC_86xx
> default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS
> default PCI_QSPAN if !4xx && !CPM2 && 8xx
> help
> diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/
> platforms/Makefile
> index c4f6b0d..2928636 100644
> --- a/arch/powerpc/platforms/Makefile
> +++ b/arch/powerpc/platforms/Makefile
> @@ -9,6 +9,7 @@ obj-$(CONFIG_PPC_CHRP) += chrp/
> obj-$(CONFIG_4xx) += 4xx/
> obj-$(CONFIG_PPC_83xx) += 83xx/
> obj-$(CONFIG_PPC_85xx) += 85xx/
> +obj-$(CONFIG_PPC_86xx) += 86xx/
> obj-$(CONFIG_PPC_PSERIES) += pseries/
> obj-$(CONFIG_PPC_ISERIES) += iseries/
> obj-$(CONFIG_PPC_MAPLE) += maple/
> diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/
> platforms/86xx/Makefile
> new file mode 100644
> index 0000000..8a237a1
> --- /dev/null
> +++ b/arch/powerpc/platforms/86xx/Makefile
> @@ -0,0 +1,7 @@
> +#
> +# Makefile for the PowerPC 86xx linux kernel.
> +#
> +
> +obj-$(CONFIG_PPC_86xx) += mpc86xx_hpcn.o misc.o
Seems like mpc86xx_hpcn.o is board specific code and should move down
one line.
> +obj-$(CONFIG_MPC8641_HPCN) += mpc8641_hpcn.o
> +obj-$(CONFIG_PCI) += pci.o pex.o
> diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/
> platforms/86xx/Kconfig
> new file mode 100644
> index 0000000..b8924e7
> --- /dev/null
> +++ b/arch/powerpc/platforms/86xx/Kconfig
> @@ -0,0 +1,46 @@
> +menu "Platform Support"
> + depends on PPC_86xx
> +
> +choice
> + prompt "Machine Type"
> + default MPC8641_HPCN
> +
> +config MPC8641_HPCN
> + bool "Freescale MPC8641 HPCN"
> + help
> + This option enables support for the MPC8641 HPCN board.
> +
> +endchoice
> +
> +
> +config MPC8641
> + bool
> + select PPC_INDIRECT_PCI
> + select PPC_UDBG_16550
> + default y if MPC8641_HPCN
> +
> +config MPIC
> + bool
> + default y
> +
> +config PPC_INDIRECT_PCI_BE
> + bool
> + depends on PPC_86xx
> + default y
> +
> +config PEX
> + bool "PCI Express support"
> + depends on PCI && PPC_86xx
> + default y
> +
> +config I8259_LEVEL_TRIGGER
> + bool
> + depends on MPC8641
> + default y
again, seems like it should depend on a board & not MPC8641
> +
> +config PPC_STD_MMU
> + bool
> + depends on PPC_86xx
> + default y
> +
> +endmenu
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index d6d4494..fbeae82 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -252,12 +252,12 @@ config I2C_POWERMAC
> will be called i2c-powermac.
>
> config I2C_MPC
> - tristate "MPC107/824x/85xx/52xx"
> + tristate "MPC107/824x/85xx/52xx/86xx"
> depends on I2C && PPC32
> help
> If you say yes to this option, support will be included for the
> built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
> - MPC85xx family processors. The driver may also work on 52xx
> + MPC85xx/MPC8641 family processors. The driver may also work on
> 52xx
> family processors, though interrupts are known not to work.
>
> This driver can also be built as a module. If so, the module
should probably separate this out into its own patch for the I2C
maintainer.
- k
^ permalink raw reply
* [PATCH] powerpc: oprofile support for POWER6
From: Michael Neuling @ 2006-06-08 4:42 UTC (permalink / raw)
To: paulus; +Cc: linuxppc-dev
POWER6 moves some of the MMCRA bits and also requires some bits to be
cleared each PMU interrupt.
Signed-off-by: Michael Neuling <mikey@neuling.org>
Acked-by: Anton Blanchard <anton@samba.org>
---
Paul: for your post 2.6.17 queue. Updated with comments from Segher.
arch/powerpc/kernel/cputable.c | 13 ++++++++++-
arch/powerpc/oprofile/op_model_power4.c | 37 ++++++++++++--------------------
include/asm-powerpc/cputable.h | 11 ++++++---
include/asm-powerpc/reg.h | 4 +++
4 files changed, 39 insertions(+), 26 deletions(-)
Index: linux-2.6-powerpc/arch/powerpc/kernel/cputable.c
===================================================================
--- linux-2.6-powerpc.orig/arch/powerpc/kernel/cputable.c
+++ linux-2.6-powerpc/arch/powerpc/kernel/cputable.c
@@ -236,6 +236,11 @@ struct cpu_spec cpu_specs[] = {
.num_pmcs = 6,
.oprofile_cpu_type = "ppc64/power5",
.oprofile_type = PPC_OPROFILE_POWER4,
+ /* SIHV / SIPR bits are implemented on POWER4+ (GQ)
+ * and above but only works on POWER5 and above
+ */
+ .oprofile_mmcra_sihv = MMCRA_SIHV,
+ .oprofile_mmcra_sipr = MMCRA_SIPR,
.platform = "power5",
},
{ /* Power5 GS */
@@ -249,6 +254,8 @@ struct cpu_spec cpu_specs[] = {
.num_pmcs = 6,
.oprofile_cpu_type = "ppc64/power5+",
.oprofile_type = PPC_OPROFILE_POWER4,
+ .oprofile_mmcra_sihv = MMCRA_SIHV,
+ .oprofile_mmcra_sipr = MMCRA_SIPR,
.platform = "power5+",
},
{ /* Power6 */
@@ -259,9 +266,13 @@ struct cpu_spec cpu_specs[] = {
.cpu_user_features = COMMON_USER_POWER6,
.icache_bsize = 128,
.dcache_bsize = 128,
- .num_pmcs = 6,
+ .num_pmcs = 8,
.oprofile_cpu_type = "ppc64/power6",
.oprofile_type = PPC_OPROFILE_POWER4,
+ .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV,
+ .oprofile_mmcra_sipr = POWER6_MMCRA_SIPR,
+ .oprofile_mmcra_clear = POWER6_MMCRA_THRM |
+ POWER6_MMCRA_OTHER,
.platform = "power6",
},
{ /* Cell Broadband Engine */
Index: linux-2.6-powerpc/arch/powerpc/oprofile/op_model_power4.c
===================================================================
--- linux-2.6-powerpc.orig/arch/powerpc/oprofile/op_model_power4.c
+++ linux-2.6-powerpc/arch/powerpc/oprofile/op_model_power4.c
@@ -24,10 +24,6 @@
static unsigned long reset_value[OP_MAX_COUNTER];
static int oprofile_running;
-static int mmcra_has_sihv;
-/* Unfortunately these bits vary between CPUs */
-static unsigned long mmcra_sihv = MMCRA_SIHV;
-static unsigned long mmcra_sipr = MMCRA_SIPR;
/* mmcr values are set in power4_reg_setup, used in power4_cpu_setup */
static u32 mmcr0_val;
@@ -41,16 +37,6 @@ static void power4_reg_setup(struct op_c
int i;
/*
- * SIHV / SIPR bits are only implemented on POWER4+ (GQ) and above.
- * However we disable it on all POWER4 until we verify it works
- * (I was seeing some strange behaviour last time I tried).
- *
- * It has been verified to work on POWER5 so we enable it there.
- */
- if (cpu_has_feature(CPU_FTR_MMCRA_SIHV))
- mmcra_has_sihv = 1;
-
- /*
* The performance counter event settings are given in the mmcr0,
* mmcr1 and mmcra values passed from the user in the
* op_system_config structure (sys variable).
@@ -202,18 +188,19 @@ static unsigned long get_pc(struct pt_re
unsigned long mmcra;
/* Cant do much about it */
- if (!mmcra_has_sihv)
+ if (!cur_cpu_spec->oprofile_mmcra_sihv)
return pc;
mmcra = mfspr(SPRN_MMCRA);
/* Were we in the hypervisor? */
- if (firmware_has_feature(FW_FEATURE_LPAR) && (mmcra & mmcra_sihv))
+ if (firmware_has_feature(FW_FEATURE_LPAR) &&
+ (mmcra & cur_cpu_spec->oprofile_mmcra_sihv))
/* function descriptor madness */
return *((unsigned long *)hypervisor_bucket);
/* We were in userspace, nothing to do */
- if (mmcra & mmcra_sipr)
+ if (mmcra & cur_cpu_spec->oprofile_mmcra_sipr)
return pc;
#ifdef CONFIG_PPC_RTAS
@@ -235,15 +222,14 @@ static unsigned long get_pc(struct pt_re
return pc;
}
-static int get_kernel(unsigned long pc)
+static int get_kernel(unsigned long pc, unsigned long mmcra)
{
int is_kernel;
- if (!mmcra_has_sihv) {
+ if (!cur_cpu_spec->oprofile_mmcra_sihv) {
is_kernel = is_kernel_addr(pc);
} else {
- unsigned long mmcra = mfspr(SPRN_MMCRA);
- is_kernel = ((mmcra & mmcra_sipr) == 0);
+ is_kernel = ((mmcra & cur_cpu_spec->oprofile_mmcra_sipr) == 0);
}
return is_kernel;
@@ -257,9 +243,12 @@ static void power4_handle_interrupt(stru
int val;
int i;
unsigned int mmcr0;
+ unsigned long mmcra;
+
+ mmcra = mfspr(SPRN_MMCRA);
pc = get_pc(regs);
- is_kernel = get_kernel(pc);
+ is_kernel = get_kernel(pc, mmcra);
/* set the PMM bit (see comment below) */
mtmsrd(mfmsr() | MSR_PMM);
@@ -287,6 +276,10 @@ static void power4_handle_interrupt(stru
*/
mmcr0 &= ~MMCR0_PMAO;
+ /* Clear the appropriate bits in the MMCRA */
+ mmcra &= ~cur_cpu_spec->oprofile_mmcra_clear;
+ mtspr(SPRN_MMCRA, mmcra);
+
/*
* now clear the freeze bit, counting will not start until we
* rfid from this exception, because only at that point will
Index: linux-2.6-powerpc/include/asm-powerpc/cputable.h
===================================================================
--- linux-2.6-powerpc.orig/include/asm-powerpc/cputable.h
+++ linux-2.6-powerpc/include/asm-powerpc/cputable.h
@@ -69,6 +69,13 @@ struct cpu_spec {
/* Processor specific oprofile operations */
enum powerpc_oprofile_type oprofile_type;
+ /* Bit locations inside the mmcra change */
+ unsigned long oprofile_mmcra_sihv;
+ unsigned long oprofile_mmcra_sipr;
+
+ /* Bits to clear during an oprofile exception */
+ unsigned long oprofile_mmcra_clear;
+
/* Name of processor class, for the ELF AT_PLATFORM entry */
char *platform;
};
@@ -117,7 +124,6 @@ extern void do_cpu_ftr_fixups(unsigned l
#define CPU_FTR_SMT ASM_CONST(0x0000010000000000)
#define CPU_FTR_COHERENT_ICACHE ASM_CONST(0x0000020000000000)
#define CPU_FTR_LOCKLESS_TLBIE ASM_CONST(0x0000040000000000)
-#define CPU_FTR_MMCRA_SIHV ASM_CONST(0x0000080000000000)
#define CPU_FTR_CI_LARGE_PAGE ASM_CONST(0x0000100000000000)
#define CPU_FTR_PAUSE_ZERO ASM_CONST(0x0000200000000000)
#define CPU_FTR_PURR ASM_CONST(0x0000400000000000)
@@ -134,7 +140,6 @@ extern void do_cpu_ftr_fixups(unsigned l
#define CPU_FTR_SMT ASM_CONST(0x0)
#define CPU_FTR_COHERENT_ICACHE ASM_CONST(0x0)
#define CPU_FTR_LOCKLESS_TLBIE ASM_CONST(0x0)
-#define CPU_FTR_MMCRA_SIHV ASM_CONST(0x0)
#define CPU_FTR_CI_LARGE_PAGE ASM_CONST(0x0)
#define CPU_FTR_PURR ASM_CONST(0x0)
#endif
@@ -320,7 +325,7 @@ extern void do_cpu_ftr_fixups(unsigned l
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
CPU_FTR_MMCRA | CPU_FTR_SMT | \
CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
- CPU_FTR_MMCRA_SIHV | CPU_FTR_PURR)
+ CPU_FTR_PURR)
#define CPU_FTRS_POWER6 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
CPU_FTR_MMCRA | CPU_FTR_SMT | \
Index: linux-2.6-powerpc/include/asm-powerpc/reg.h
===================================================================
--- linux-2.6-powerpc.orig/include/asm-powerpc/reg.h
+++ linux-2.6-powerpc/include/asm-powerpc/reg.h
@@ -443,6 +443,10 @@
#define MMCRA_SIHV 0x10000000UL /* state of MSR HV when SIAR set */
#define MMCRA_SIPR 0x08000000UL /* state of MSR PR when SIAR set */
#define MMCRA_SAMPLE_ENABLE 0x00000001UL /* enable sampling */
+#define POWER6_MMCRA_SIHV 0x0000040000000000ULL
+#define POWER6_MMCRA_SIPR 0x0000020000000000ULL
+#define POWER6_MMCRA_THRM 0x00000020UL
+#define POWER6_MMCRA_OTHER 0x0000000EUL
#define SPRN_PMC1 787
#define SPRN_PMC2 788
#define SPRN_PMC3 789
^ permalink raw reply
* Re: [PATCH] powerpc: oprofile support for POWER6
From: Michael Neuling @ 2006-06-08 4:29 UTC (permalink / raw)
To: Segher Boessenkool; +Cc: linuxppc-dev, paulus
In-Reply-To: <4AE0F2C6-99B7-40AF-AB28-71D51C1141A5@kernel.crashing.org>
> > /*
> > - * SIHV / SIPR bits are only implemented on POWER4+ (GQ) and above.
> > - * However we disable it on all POWER4 until we verify it works
> > - * (I was seeing some strange behaviour last time I tried).
> > - *
> > - * It has been verified to work on POWER5 so we enable it there.
> > - */
>
> The patched code doesn't handle GQ at all. Is this on purpose? Add a
> similar comment to the CPU feature tables perhaps?
Yeah, those bits are bust on POWER4+. We didn't touch them previously
and we still don't with this patch.
You're right, we should keep that comment. I'll update and retransmit.
Mikey
^ permalink raw reply
* Re: [PATCH] convert powermac ide blink to new led infrastructure
From: Benjamin Herrenschmidt @ 2006-06-08 0:28 UTC (permalink / raw)
To: Johannes Berg; +Cc: linuxppc-dev list
In-Reply-To: <1149635136.32002.49.camel@johannes>
On Wed, 2006-06-07 at 01:05 +0200, Johannes Berg wrote:
> Ben, all, do you have any further objections to this patch? Otherwise,
> I'd like to see it queued for 2.6.18 through whoever should do that.
No objection, but a question: how do you bind the led to the hard disk
by default ? some userland stuff ? can't be automatic at boot by
default ?
Ben.
> ---
>
> This patch removes the old pmac ide led blink code and adds generic LED
> subsystem support for the LED.
>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
>
> --- wireless-dev.orig/drivers/ide/Kconfig 2006-05-26 15:42:45.292052079 +0200
> +++ wireless-dev/drivers/ide/Kconfig 2006-06-07 00:50:11.021517067 +0200
> @@ -773,13 +773,6 @@ config BLK_DEV_IDEDMA_PMAC
> to transfer data to and from memory. Saying Y is safe and improves
> performance.
>
> -config BLK_DEV_IDE_PMAC_BLINK
> - bool "Blink laptop LED on drive activity"
> - depends on BLK_DEV_IDE_PMAC && ADB_PMU
> - help
> - This option enables the use of the sleep LED as a hard drive
> - activity LED.
> -
> config BLK_DEV_IDE_SWARM
> tristate "IDE for Sibyte evaluation boards"
> depends on SIBYTE_SB1xxx_SOC
> --- wireless-dev.orig/drivers/ide/ppc/pmac.c 2006-05-26 15:42:45.322052079 +0200
> +++ wireless-dev/drivers/ide/ppc/pmac.c 2006-06-07 00:50:11.231517067 +0200
> @@ -421,107 +421,6 @@ static void pmac_ide_kauai_selectproc(id
> #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
>
> /*
> - * Below is the code for blinking the laptop LED along with hard
> - * disk activity.
> - */
> -
> -#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK
> -
> -/* Set to 50ms minimum led-on time (also used to limit frequency
> - * of requests sent to the PMU
> - */
> -#define PMU_HD_BLINK_TIME (HZ/50)
> -
> -static struct adb_request pmu_blink_on, pmu_blink_off;
> -static spinlock_t pmu_blink_lock;
> -static unsigned long pmu_blink_stoptime;
> -static int pmu_blink_ledstate;
> -static struct timer_list pmu_blink_timer;
> -static int pmu_ide_blink_enabled;
> -
> -
> -static void
> -pmu_hd_blink_timeout(unsigned long data)
> -{
> - unsigned long flags;
> -
> - spin_lock_irqsave(&pmu_blink_lock, flags);
> -
> - /* We may have been triggered again in a racy way, check
> - * that we really want to switch it off
> - */
> - if (time_after(pmu_blink_stoptime, jiffies))
> - goto done;
> -
> - /* Previous req. not complete, try 100ms more */
> - if (pmu_blink_off.complete == 0)
> - mod_timer(&pmu_blink_timer, jiffies + PMU_HD_BLINK_TIME);
> - else if (pmu_blink_ledstate) {
> - pmu_request(&pmu_blink_off, NULL, 4, 0xee, 4, 0, 0);
> - pmu_blink_ledstate = 0;
> - }
> -done:
> - spin_unlock_irqrestore(&pmu_blink_lock, flags);
> -}
> -
> -static void
> -pmu_hd_kick_blink(void *data, int rw)
> -{
> - unsigned long flags;
> -
> - pmu_blink_stoptime = jiffies + PMU_HD_BLINK_TIME;
> - wmb();
> - mod_timer(&pmu_blink_timer, pmu_blink_stoptime);
> - /* Fast path when LED is already ON */
> - if (pmu_blink_ledstate == 1)
> - return;
> - spin_lock_irqsave(&pmu_blink_lock, flags);
> - if (pmu_blink_on.complete && !pmu_blink_ledstate) {
> - pmu_request(&pmu_blink_on, NULL, 4, 0xee, 4, 0, 1);
> - pmu_blink_ledstate = 1;
> - }
> - spin_unlock_irqrestore(&pmu_blink_lock, flags);
> -}
> -
> -static int
> -pmu_hd_blink_init(void)
> -{
> - struct device_node *dt;
> - const char *model;
> -
> - /* Currently, I only enable this feature on KeyLargo based laptops,
> - * older laptops may support it (at least heathrow/paddington) but
> - * I don't feel like loading those venerable old machines with so
> - * much additional interrupt & PMU activity...
> - */
> - if (pmu_get_model() != PMU_KEYLARGO_BASED)
> - return 0;
> -
> - dt = of_find_node_by_path("/");
> - if (dt == NULL)
> - return 0;
> - model = (const char *)get_property(dt, "model", NULL);
> - if (model == NULL)
> - return 0;
> - if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 &&
> - strncmp(model, "iBook", strlen("iBook")) != 0) {
> - of_node_put(dt);
> - return 0;
> - }
> - of_node_put(dt);
> -
> - pmu_blink_on.complete = 1;
> - pmu_blink_off.complete = 1;
> - spin_lock_init(&pmu_blink_lock);
> - init_timer(&pmu_blink_timer);
> - pmu_blink_timer.function = pmu_hd_blink_timeout;
> -
> - return 1;
> -}
> -
> -#endif /* CONFIG_BLK_DEV_IDE_PMAC_BLINK */
> -
> -/*
> * N.B. this can't be an initfunc, because the media-bay task can
> * call ide_[un]register at any time.
> */
> @@ -1190,23 +1089,6 @@ pmac_ide_do_suspend(ide_hwif_t *hwif)
> pmif->timings[0] = 0;
> pmif->timings[1] = 0;
>
> -#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK
> - /* Note: This code will be called for every hwif, thus we'll
> - * try several time to stop the LED blinker timer, but that
> - * should be harmless
> - */
> - if (pmu_ide_blink_enabled) {
> - unsigned long flags;
> -
> - /* Make sure we don't hit the PMU blink */
> - spin_lock_irqsave(&pmu_blink_lock, flags);
> - if (pmu_blink_ledstate)
> - del_timer(&pmu_blink_timer);
> - pmu_blink_ledstate = 0;
> - spin_unlock_irqrestore(&pmu_blink_lock, flags);
> - }
> -#endif /* CONFIG_BLK_DEV_IDE_PMAC_BLINK */
> -
> disable_irq(pmif->irq);
>
> /* The media bay will handle itself just fine */
> @@ -1374,13 +1256,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *p
> hwif->selectproc = pmac_ide_selectproc;
> hwif->speedproc = pmac_ide_tune_chipset;
>
> -#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK
> - pmu_ide_blink_enabled = pmu_hd_blink_init();
> -
> - if (pmu_ide_blink_enabled)
> - hwif->led_act = pmu_hd_kick_blink;
> -#endif
> -
> printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s, irq %d\n",
> hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
> pmif->mediabay ? " (mediabay)" : "", hwif->irq);
> --- wireless-dev.orig/drivers/macintosh/Kconfig 2006-05-26 15:42:45.382052079 +0200
> +++ wireless-dev/drivers/macintosh/Kconfig 2006-06-07 00:50:11.341517067 +0200
> @@ -78,6 +78,17 @@ config ADB_PMU
> this device; you should do so if your machine is one of those
> mentioned above.
>
> +config ADB_PMU_LED
> + bool "Support for the Power/iBook front LED"
> + depends on ADB_PMU
> + select LEDS_CLASS
> + help
> + Support the front LED on Power/iBooks as a generic LED that can
> + be triggered by any of the supported triggers. To get the
> + behaviour of the old CONFIG_BLK_DEV_IDE_PMAC_BLINK, select this
> + and the ide-disk LED trigger and configure appropriately through
> + sysfs.
> +
> config PMAC_SMU
> bool "Support for SMU based PowerMacs"
> depends on PPC_PMAC64
> --- wireless-dev.orig/drivers/macintosh/Makefile 2006-05-26 15:42:45.442052079 +0200
> +++ wireless-dev/drivers/macintosh/Makefile 2006-06-07 00:58:49.861517067 +0200
> @@ -12,6 +12,7 @@ obj-$(CONFIG_INPUT_ADBHID) += adbhid.o
> obj-$(CONFIG_ANSLCD) += ans-lcd.o
>
> obj-$(CONFIG_ADB_PMU) += via-pmu.o
> +obj-$(CONFIG_ADB_PMU_LED) += via-pmu-led.o
> obj-$(CONFIG_ADB_CUDA) += via-cuda.o
> obj-$(CONFIG_PMAC_APM_EMU) += apm_emu.o
> obj-$(CONFIG_PMAC_SMU) += smu.o
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ wireless-dev/drivers/macintosh/via-pmu-led.c 2006-06-07 01:01:15.521517067 +0200
> @@ -0,0 +1,141 @@
> +/*
> + * via-pmu LED class device
> + *
> + * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
> + * NON INFRINGEMENT. See the GNU General Public License for more
> + * details.
> + *
> + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +#include <linux/types.h>
> +#include <linux/kernel.h>
> +#include <linux/device.h>
> +#include <linux/leds.h>
> +#include <linux/adb.h>
> +#include <linux/pmu.h>
> +#include <asm/prom.h>
> +
> +static spinlock_t pmu_blink_lock;
> +static struct adb_request pmu_blink_req;
> +/* -1: no change, 0: request off, 1: request on */
> +static int requested_change;
> +static int sleeping;
> +
> +static void pmu_req_done(struct adb_request * req)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&pmu_blink_lock, flags);
> + /* if someone requested a change in the meantime
> + * (we only see the last one which is fine)
> + * then apply it now */
> + if (requested_change != -1 && !sleeping)
> + pmu_request(&pmu_blink_req, NULL, 4, 0xee, 4, 0, requested_change);
> + /* reset requested change */
> + requested_change = -1;
> + spin_unlock_irqrestore(&pmu_blink_lock, flags);
> +}
> +
> +static void pmu_led_set(struct led_classdev *led_cdev,
> + enum led_brightness brightness)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&pmu_blink_lock, flags);
> + switch (brightness) {
> + case LED_OFF:
> + requested_change = 0;
> + break;
> + case LED_FULL:
> + requested_change = 1;
> + break;
> + default:
> + goto out;
> + break;
> + }
> + /* if request isn't done, then don't do anything */
> + if (pmu_blink_req.complete && !sleeping)
> + pmu_request(&pmu_blink_req, NULL, 4, 0xee, 4, 0, requested_change);
> + out:
> + spin_unlock_irqrestore(&pmu_blink_lock, flags);
> +}
> +
> +static struct led_classdev pmu_led = {
> + .name = "pmu-front-led",
> + .brightness_set = pmu_led_set,
> +};
> +
> +#ifdef CONFIG_PM
> +static int pmu_led_sleep_call(struct pmu_sleep_notifier *self, int when)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&pmu_blink_lock, flags);
> +
> + switch (when) {
> + case PBOOK_SLEEP_REQUEST:
> + sleeping = 1;
> + break;
> + case PBOOK_WAKE:
> + sleeping = 0;
> + break;
> + default:
> + /* do nothing */
> + break;
> + }
> + spin_unlock_irqrestore(&pmu_blink_lock, flags);
> +
> + return PBOOK_SLEEP_OK;
> +}
> +
> +static struct pmu_sleep_notifier via_pmu_led_sleep_notif = {
> + .notifier_call = pmu_led_sleep_call,
> +};
> +#endif
> +
> +static int __init via_pmu_led_init(void)
> +{
> + struct device_node *dt;
> + const char *model;
> +
> + /* only do this on keylargo based models */
> + if (pmu_get_model() != PMU_KEYLARGO_BASED)
> + return -ENODEV;
> +
> + dt = of_find_node_by_path("/");
> + if (dt == NULL)
> + return -ENODEV;
> + model = (const char *)get_property(dt, "model", NULL);
> + if (model == NULL)
> + return -ENODEV;
> + if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 &&
> + strncmp(model, "iBook", strlen("iBook")) != 0) {
> + of_node_put(dt);
> + /* silently ignore */
> + return 0;
> + }
> + of_node_put(dt);
> +
> + spin_lock_init(&pmu_blink_lock);
> + /* no outstanding req */
> + pmu_blink_req.complete = 1;
> + pmu_blink_req.done = pmu_req_done;
> +#ifdef CONFIG_PM
> + pmu_register_sleep_notifier(&via_pmu_led_sleep_notif);
> +#endif
> + return led_classdev_register(NULL, &pmu_led);
> +}
> +
> +late_initcall(via_pmu_led_init);
>
^ permalink raw reply
* Re: [PATCH] powerpc: Fix cell blade detection
From: Benjamin Herrenschmidt @ 2006-06-08 0:26 UTC (permalink / raw)
To: Segher Boessenkool; +Cc: linuxppc-dev list, Paul Mackerras
In-Reply-To: <3EB64128-691F-4DB9-922E-C60CE739168F@kernel.crashing.org>
On Thu, 2006-06-08 at 01:09 +0200, Segher Boessenkool wrote:
> > +#ifdef CONFIG_PPC64
> > + /* We must make sure we don't detect the IBM Cell
> > + * blades as pSeries due to some firmware issues,
> > + * so we do it here.
> > + */
>
> Is this #ifdef needed? Do we really care about 22 bytes of rodata?
For 32 bits platforms, yes :)
Ben.
^ permalink raw reply
* Re: [PATCH] powerpc: Fix cell blade detection
From: Segher Boessenkool @ 2006-06-07 23:09 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list, Paul Mackerras
In-Reply-To: <1149645858.27572.93.camel@localhost.localdomain>
> +#ifdef CONFIG_PPC64
> + /* We must make sure we don't detect the IBM Cell
> + * blades as pSeries due to some firmware issues,
> + * so we do it here.
> + */
Is this #ifdef needed? Do we really care about 22 bytes of rodata?
Segher
^ permalink raw reply
* Re: [PATCH] powerpc: Fix call to ibm,client-architecture-support
From: Segher Boessenkool @ 2006-06-07 23:07 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list, Paul Mackerras
In-Reply-To: <1149645693.27572.90.camel@localhost.localdomain>
> The code in prom_init.c calling the firmware
> ibm,client-architecture-support on pSeries has a bug where it fails to
> properly pass the instance handle of the firmware object when
> trying to
> call a method. Result ranges from the call doing nothing to the
> firmware
> crashing. (Found by Segher, thanks !)
Dry debugging is one of the most fun things in the world, second
only to reverse engineering. Am I pathetic or what?
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Segher Boessenkool <segher@kernel.crashing.org>
> Index: linux-work/arch/powerpc/kernel/prom_init.c
> ===================================================================
> --- linux-work.orig/arch/powerpc/kernel/prom_init.c 2006-05-30
> 13:00:51.000000000 +1000
> +++ linux-work/arch/powerpc/kernel/prom_init.c 2006-06-06
> 11:59:20.000000000 +1000
> @@ -822,6 +822,7 @@ static void __init prom_send_capabilitie
> /* try calling the ibm,client-architecture-support method */
> if (call_prom_ret("call-method", 3, 2, &ret,
> ADDR("ibm,client-architecture-support"),
> + root,
> ADDR(ibm_architecture_vec)) == 0) {
> /* the call exists... */
> if (ret)
^ permalink raw reply
* Re: [PATCH 3/3] RTAS MSI
From: Nathan Lynch @ 2006-06-07 22:58 UTC (permalink / raw)
To: Jake Moilanen; +Cc: linuxppc-dev, paulus
In-Reply-To: <20060607162540.f53bc270.moilanen@austin.ibm.com>
Hi Jake, some comments below:
Jake Moilanen wrote:
> Index: 2.6/drivers/pci/msi-rtas.c
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ 2.6/drivers/pci/msi-rtas.c 2006-06-07 15:59:59.000000000 -0500
> @@ -0,0 +1,162 @@
> +/*
> + * Jake Moilanen <moilanen@austin.ibm.com>
> + * Copyright (C) 2006 IBM
> + *
> + * 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; version 2 of the
> + * License.
> + *
> + */
> +
> +#include <linux/pci.h>
> +#include <linux/irq.h>
> +#include <asm/rtas.h>
> +#include <asm/hw_irq.h>
> +
> +int rtas_enable_msi(struct pci_dev* pdev)
> +{
> + static int seq_num = 1;
> + int i;
> + int rc;
> + int query_token = rtas_token("ibm,query-interrupt-source-number");
> + int devfn;
> + int busno;
> + u32 *reg;
> + int reglen;
> + int ret[3];
> + int dummy;
> + unsigned int virq;
> + unsigned int addr;
> + unsigned long buid = -1;
> + unsigned long wait_time;
> + struct device_node * dn;
> +
> + BUG_ON(!pdev);
> +
> + dn = pci_device_to_OF_node(pdev);
> +
> + if (!of_find_property(dn, "ibm,req#msi", &dummy))
> + return -ENOENT;
> +
> + reg = (u32 *) get_property(dn, "reg", ®len);
> + if (reg == NULL || reglen < 20)
> + return -ENXIO;
> +
> + devfn = (reg[0] >> 8) & 0xff;
> + busno = (reg[0] >> 16) & 0xff;
> +
> + buid = get_phb_buid(dn->parent);
> + addr = (busno << 16) | (devfn << 8);
> +
> + while (1) {
> + rc = rtas_call(rtas_token("ibm,change-msi"), 6, 3, ret, addr,
> + buid >> 32, buid & 0xffffffff,
> + 0, 0, seq_num);
> +
> + if (!rc)
> + break;
> + else if (rc == RTAS_BUSY)
> + udelay(1);
> + else if (rtas_is_extended_busy(rc)) {
> + wait_time = rtas_extended_busy_delay_time(rc);
> + udelay(wait_time * 1000);
> + } else {
> + printk(KERN_WARNING "error[%d]: getting the number of "
> + "MSI interrupts for %s\n", rc, dn->name);
> + return -EIO;
> + }
> +
> + seq_num = ret[1];
> + }
Please see John Rose's patch from a few days ago for handling RTAS
delays with msleep instead of udelay. As written, this loop could tie
up the cpu for an arbitrary amount of time, and it is this kind of
situation John's patch is intended to address.
> +
> + /* Return if there's no MSI interrupts */
> + if (!ret[0])
> + return -ENOENT;
> +
> + dn->n_intrs = ret[0];
> +
> + dn->intrs = kmalloc(dn->n_intrs * sizeof(*(dn->intrs)), GFP_KERNEL);
> + if (!dn->intrs) {
> + printk(KERN_WARNING "rtas_enable_msi: can't allocate space\n");
> + return -ENOMEM;
> + }
> +
> + for (i = 0; i < dn->n_intrs; i++) {
> + rc = rtas_call(query_token, 4, 3, ret, addr,
> + buid >> 32, buid & 0xffffffff, i);
> +
> + if (!rc) {
> + virq = virt_irq_create_mapping(ret[0]);
> +
> + dn->intrs[i].line = irq_offset_up(virq);
> + dn->intrs[i].sense = ret[1];
> + } else {
> + printk(KERN_WARNING "error[%d]: query-interrupt-source-number for %s\n",
> + rc, dn->name);
> + }
> + }
> +
> + /* Just give the first vector out for now */
> + pdev->irq = dn->intrs[0].line;
> +
> + return 0;
> +}
> +
> +void rtas_disable_msi(struct pci_dev* pdev)
> +{
> + static int seq_num = 1;
> + struct device_node * dn;
> + int rc;
> + int devfn;
> + int busno;
> + u32 *reg;
> + int reglen;
> + int ret[3];
> + int dummy;
> + unsigned int addr;
> + unsigned long buid = -1;
> + unsigned long wait_time;
> +
> + BUG_ON(!pdev);
> +
> + dn = pci_device_to_OF_node(pdev);
> +
> + if (!of_find_property(dn, "ibm,req#msi", &dummy))
> + return;
> +
> + reg = (u32 *) get_property(dn, "reg", ®len);
> + if (reg == NULL || reglen < 20)
> + return;
> +
> + devfn = (reg[0] >> 8) & 0xff;
> + busno = (reg[0] >> 16) & 0xff;
> +
> + buid = get_phb_buid(dn->parent);
> + addr = (busno << 16) | (devfn << 8);
> +
> + while (1) {
> + rc = rtas_call(rtas_token("ibm,change-msi"), 6, 3, ret, addr,
> + buid >> 32, buid & 0xffffffff,
> + 2, 0, seq_num);
> +
> + if (!rc)
> + break;
> + else if (rc == RTAS_BUSY)
> + udelay(1);
> + else if (rtas_is_extended_busy(rc)) {
> + wait_time = rtas_extended_busy_delay_time(rc);
> + udelay(wait_time * 1000);
> + } else {
> + printk(KERN_WARNING "error[%d]: setting the number of "
> + "MSI interrupts for %s\n", rc, dn->name);
> + return;
> + }
> +
> + seq_num = ret[1];
> + }
Same as above applies here.
> +
> + dn->n_intrs = 0;
> +
> + kfree(dn->intrs);
> +}
> Index: 2.6/drivers/pci/Kconfig
> ===================================================================
> --- 2.6.orig/drivers/pci/Kconfig 2006-06-07 15:29:55.000000000 -0500
> +++ 2.6/drivers/pci/Kconfig 2006-06-07 15:59:28.000000000 -0500
> @@ -4,7 +4,7 @@
> config PCI_MSI
> bool "Message Signaled Interrupts (MSI and MSI-X)"
> depends on PCI
> - depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64
> + depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 || PPC_PSERIES
> help
> This allows device drivers to enable MSI (Message Signaled
> Interrupts). Message Signaled Interrupts enable a device to
> Index: 2.6/arch/powerpc/platforms/pseries/setup.c
> ===================================================================
> --- 2.6.orig/arch/powerpc/platforms/pseries/setup.c 2006-06-07 15:29:55.000000000 -0500
> +++ 2.6/arch/powerpc/platforms/pseries/setup.c 2006-06-07 15:59:28.000000000 -0500
> @@ -78,6 +78,8 @@
> #endif
>
> extern void find_udbg_vterm(void);
> +extern int rtas_enable_msi(struct pci_dev* pdev);
> +extern void rtas_disable_msi(struct pci_dev * pdev);
These belong in a header.
^ permalink raw reply
* Re: [PATCH] powerpc: oprofile support for POWER6
From: Segher Boessenkool @ 2006-06-07 22:59 UTC (permalink / raw)
To: Michael Neuling; +Cc: linuxppc-dev, paulus
In-Reply-To: <20060607012359.D59C467B37@ozlabs.org>
> /*
> - * SIHV / SIPR bits are only implemented on POWER4+ (GQ) and above.
> - * However we disable it on all POWER4 until we verify it works
> - * (I was seeing some strange behaviour last time I tried).
> - *
> - * It has been verified to work on POWER5 so we enable it there.
> - */
The patched code doesn't handle GQ at all. Is this on purpose? Add a
similar comment to the CPU feature tables perhaps?
Segher
^ permalink raw reply
* Re: Collecting hypervisor call stats
From: Segher Boessenkool @ 2006-06-07 22:57 UTC (permalink / raw)
To: Mike Kravetz; +Cc: Bryan Rosenburg, Christopher Yeoh, linuxppc-dev, Chris Yeoh
In-Reply-To: <20060606164646.GA3161@w-mikek2.ibm.com>
> Can you explain the need for barrier(s) before and after the call
> to the
> real routine? It usually takes me a couple days of thought to
> figure out
> exactly where these are needed. :)
The barriers make the timing ever so slightly more deterministic (not
more
"accurate" though), because it has a "sync" insn in it. The sc insn
to do
the actual hypervisor call is a synchronisation point itself of
course, as
probably some things around it are as well. So just blast-em away,
they do
slow down things, and you don't really care about a few cycles more
or less
reported, hypervisor calls are not that fast.
Segher
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox