* booting with NFS root
@ 2006-05-26 0:49 Roman Mashak
2006-05-26 0:49 ` Roman Mashak
2006-05-26 1:38 ` Yoichi Yuasa
0 siblings, 2 replies; 9+ messages in thread
From: Roman Mashak @ 2006-05-26 0:49 UTC (permalink / raw)
To: linux-mips
Hello!
I have evaluation board from PMC-sierra, their CPU is using E9000 core.
Kernel (2.4.26), root FS are provided by them. I set up NFS and TFTP servers
on my linux box, kernel loads into board but fails to boot woth the
following message (I skipped some lines of kernel):
=====================
PMC-Sierra TITAN 10/100/1000 Ethernet Driver
Device Id : 206014, Version : 0
eth0: port 0 with MAC address 30:30:3a:31:31:3a
Rx NAPI supported, Tx Coalescing ON
eth1: port 1 with MAC address 30:30:3a:31:31:3b
Rx NAPI supported, Tx Coalescing ON
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP, IGMP
IP: routing cache hash table of 1024 buckets, 8Kbytes
TCP: Hash tables configured (established 8192 bind 16384)
IP-Config: Entered.
ipconfig.c 1194
dev.c 1998
dev.c 2013
dev.c 750
irq.c 539
irq.c 571
irq.c 840
irq.c 879
handler->startup 80259d14
irq.c 892
irq.c 576
Assigned IRQ 6 to port 0
titan_ge.c 2256
titan_ge.c 2278
titan_ge.c 2316
titan_ge.c 2359
titan_ge.c 1614
titan_ge.c 1659
titan_ge.c 1698
titan_ge.c 1717
titan_ge.c 1837
titan_ge.c 2025
titan_ge.c 2118
titan_ge.c 2177
dev_addr= 1, reg_addr= 11
val= 4111
val= 1
titan_ge.c 2184
titan_ge.c 2397
dev_addr= 1, reg_addr= 11
val= 4112
val= 1
dev.c 788
dev.c 2034
dev.c 2043
dev.c 2059
IP-Config: eth0 UP (able=1, xid=57c63687)
dev.c 1998
dev.c 2013
dev.c 750
irq.c 539
irq.c 571
irq.c 840
irq.c 879
irq.c 892
irq.c 576
Assigned IRQ 6 to port 1
titan_ge.c 2256
titan_ge.c 2278
titan_ge.c 2316
titan_ge.c 2359
titan_ge.c 1659
titan_ge.c 1698
titan_ge.c 1717
titan_ge.c 1837
titan_ge.c 2025
titan_ge.c 2118
titan_ge.c 2177
dev_addr= 2, reg_addr= 11
val= 4111
val= 1
titan_ge.c 2184
titan_ge.c 2397
dev_addr= 2, reg_addr= 11
val= 4212
val= 1
eth1: Error opening interface
dev.c 788
dev.c 2034
dev.c 2043
dev.c 2059
IP-Config: Failed to open eth1
ipconfig.c 1199
IP-Config: Guessing netmask 255.255.255.0
IP-Config: Complete:
device=eth0, addr=192.168.11.42, mask=255.255.255.0,
gw=255.255.255.255,
host=192.168.11.42, domain=, nis-domain=(none),
bootserver=255.255.255.255, rootserver=192.168.11.43, rootpath=
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
Looking up port of RPC 100003/2 on 192.168.11.43
Looking up port of RPC 100005/1 on 192.168.11.43
VFS: Mounted root (nfs filesystem).
Freeing unused kernel memory: 104k freed
do_cpu invoked from kernel context! in traps.c::do_cpu, line 676:
$0 : 00000000 9004a000 2ab03fe0 2ab03fe0 2ab01560 00000000 00000ae0 00000ae0
$8 : 00000020 2ab01fe0 2ab01520 00001000 00000019 00000080 811d7b18 00000c62
$16: 2ab010c0 811d7c58 87f8cfe0 00000003 00000080 2ab01520 87f841a0 00000001
$24: 00000000 00000080 811d6000 811d7ba0 2aaa8000 8015f414
Hi : 00000000
Lo : 00000000
epc : 80256e14 Not tainted
Status: 9004a003
Cause : 1000002c
PrId : 000034c1
Process init (pid: 1, stackpage=811d6000)
Stack: 8015f8a8 8015f9a8 87f71180 8012b2fc 00000000 80135330 00002012
00000019 87f8cf60 2ab019e4 00000004 00002012 000590c0 2ab01000 10000000
811d7d88 87ff5740 00000000 811d7ef8 81164e80 00000000 00000002 87f841a0
8015ffd8 811d7c20 811d6000 811d7cbc 801975a4 00006012 0000000a 811d7c18
811d7c18 7f454c46 01020100 00000000 00000000 00020008 00000001 00401980
00000034 ...
Call Trace: [<8015f8a8>] [<8015f9a8>] [<8012b2fc>] [<80135330>]
[<8015ffd8>]
[<801975a4>] [<8015fbc0>] [<801493ac>] [<801007b8>] [<8014889c>]
[<801495bc>]
[<801495a8>] [<801007b8>] [<80108f80>] [<801007b8>] [<8014fcc4>]
[<801095c0>]
[<8025ad30>] [<801007b8>] [<8025ad30>] [<8014af50>] [<801007b8>]
[<80117888>]
[<801194a0>] [<80100884>] [<801007b8>] [<8010079c>] [<8025de14>]
[<80104320>]
[<80117aec>] [<8026b7a8>] [<801b2054>] [<80104310>]
Code: 30c8003c 01244821 24840040 <ac85ffc0> ac85ffc4 ac85ffc8 ac85ffcc
ac85ffd0 ac85ffd4
Kernel panic: Attempted to kill init!
=====================
I load kernel with the following parameters:
tftp://192.168.11.43/vmlinux ip=192.168.11.42 root=/dev/nfs
nfsroot=192.168.11.43:/export/linux/mips-fs-be
What may be the problem here?
Thanks in advance!
With best regards, Roman Mashak. E-mail: mrv@corecom.co.kr
^ permalink raw reply [flat|nested] 9+ messages in thread
* booting with NFS root
2006-05-26 0:49 Roman Mashak
@ 2006-05-26 0:49 ` Roman Mashak
2006-05-26 1:38 ` Yoichi Yuasa
1 sibling, 0 replies; 9+ messages in thread
From: Roman Mashak @ 2006-05-26 0:49 UTC (permalink / raw)
To: linux-mips
Hello!
I have evaluation board from PMC-sierra, their CPU is using E9000 core.
Kernel (2.4.26), root FS are provided by them. I set up NFS and TFTP servers
on my linux box, kernel loads into board but fails to boot woth the
following message (I skipped some lines of kernel):
=====================
PMC-Sierra TITAN 10/100/1000 Ethernet Driver
Device Id : 206014, Version : 0
eth0: port 0 with MAC address 30:30:3a:31:31:3a
Rx NAPI supported, Tx Coalescing ON
eth1: port 1 with MAC address 30:30:3a:31:31:3b
Rx NAPI supported, Tx Coalescing ON
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP, IGMP
IP: routing cache hash table of 1024 buckets, 8Kbytes
TCP: Hash tables configured (established 8192 bind 16384)
IP-Config: Entered.
ipconfig.c 1194
dev.c 1998
dev.c 2013
dev.c 750
irq.c 539
irq.c 571
irq.c 840
irq.c 879
handler->startup 80259d14
irq.c 892
irq.c 576
Assigned IRQ 6 to port 0
titan_ge.c 2256
titan_ge.c 2278
titan_ge.c 2316
titan_ge.c 2359
titan_ge.c 1614
titan_ge.c 1659
titan_ge.c 1698
titan_ge.c 1717
titan_ge.c 1837
titan_ge.c 2025
titan_ge.c 2118
titan_ge.c 2177
dev_addr= 1, reg_addr= 11
val= 4111
val= 1
titan_ge.c 2184
titan_ge.c 2397
dev_addr= 1, reg_addr= 11
val= 4112
val= 1
dev.c 788
dev.c 2034
dev.c 2043
dev.c 2059
IP-Config: eth0 UP (able=1, xid=57c63687)
dev.c 1998
dev.c 2013
dev.c 750
irq.c 539
irq.c 571
irq.c 840
irq.c 879
irq.c 892
irq.c 576
Assigned IRQ 6 to port 1
titan_ge.c 2256
titan_ge.c 2278
titan_ge.c 2316
titan_ge.c 2359
titan_ge.c 1659
titan_ge.c 1698
titan_ge.c 1717
titan_ge.c 1837
titan_ge.c 2025
titan_ge.c 2118
titan_ge.c 2177
dev_addr= 2, reg_addr= 11
val= 4111
val= 1
titan_ge.c 2184
titan_ge.c 2397
dev_addr= 2, reg_addr= 11
val= 4212
val= 1
eth1: Error opening interface
dev.c 788
dev.c 2034
dev.c 2043
dev.c 2059
IP-Config: Failed to open eth1
ipconfig.c 1199
IP-Config: Guessing netmask 255.255.255.0
IP-Config: Complete:
device=eth0, addr=192.168.11.42, mask=255.255.255.0,
gw=255.255.255.255,
host=192.168.11.42, domain=, nis-domain=(none),
bootserver=255.255.255.255, rootserver=192.168.11.43, rootpath=
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
Looking up port of RPC 100003/2 on 192.168.11.43
Looking up port of RPC 100005/1 on 192.168.11.43
VFS: Mounted root (nfs filesystem).
Freeing unused kernel memory: 104k freed
do_cpu invoked from kernel context! in traps.c::do_cpu, line 676:
$0 : 00000000 9004a000 2ab03fe0 2ab03fe0 2ab01560 00000000 00000ae0 00000ae0
$8 : 00000020 2ab01fe0 2ab01520 00001000 00000019 00000080 811d7b18 00000c62
$16: 2ab010c0 811d7c58 87f8cfe0 00000003 00000080 2ab01520 87f841a0 00000001
$24: 00000000 00000080 811d6000 811d7ba0 2aaa8000 8015f414
Hi : 00000000
Lo : 00000000
epc : 80256e14 Not tainted
Status: 9004a003
Cause : 1000002c
PrId : 000034c1
Process init (pid: 1, stackpage=811d6000)
Stack: 8015f8a8 8015f9a8 87f71180 8012b2fc 00000000 80135330 00002012
00000019 87f8cf60 2ab019e4 00000004 00002012 000590c0 2ab01000 10000000
811d7d88 87ff5740 00000000 811d7ef8 81164e80 00000000 00000002 87f841a0
8015ffd8 811d7c20 811d6000 811d7cbc 801975a4 00006012 0000000a 811d7c18
811d7c18 7f454c46 01020100 00000000 00000000 00020008 00000001 00401980
00000034 ...
Call Trace: [<8015f8a8>] [<8015f9a8>] [<8012b2fc>] [<80135330>]
[<8015ffd8>]
[<801975a4>] [<8015fbc0>] [<801493ac>] [<801007b8>] [<8014889c>]
[<801495bc>]
[<801495a8>] [<801007b8>] [<80108f80>] [<801007b8>] [<8014fcc4>]
[<801095c0>]
[<8025ad30>] [<801007b8>] [<8025ad30>] [<8014af50>] [<801007b8>]
[<80117888>]
[<801194a0>] [<80100884>] [<801007b8>] [<8010079c>] [<8025de14>]
[<80104320>]
[<80117aec>] [<8026b7a8>] [<801b2054>] [<80104310>]
Code: 30c8003c 01244821 24840040 <ac85ffc0> ac85ffc4 ac85ffc8 ac85ffcc
ac85ffd0 ac85ffd4
Kernel panic: Attempted to kill init!
=====================
I load kernel with the following parameters:
tftp://192.168.11.43/vmlinux ip=192.168.11.42 root=/dev/nfs
nfsroot=192.168.11.43:/export/linux/mips-fs-be
What may be the problem here?
Thanks in advance!
With best regards, Roman Mashak. E-mail: mrv@corecom.co.kr
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: booting with NFS root
2006-05-26 0:49 Roman Mashak
2006-05-26 0:49 ` Roman Mashak
@ 2006-05-26 1:38 ` Yoichi Yuasa
2006-05-26 2:40 ` Roman Mashak
1 sibling, 1 reply; 9+ messages in thread
From: Yoichi Yuasa @ 2006-05-26 1:38 UTC (permalink / raw)
To: Roman Mashak; +Cc: linux-mips
Hi,
On Fri, 26 May 2006 09:49:50 +0900
"Roman Mashak" <mrv@corecom.co.kr> wrote:
> Hello!
>
> I have evaluation board from PMC-sierra, their CPU is using E9000 core.
> Kernel (2.4.26), root FS are provided by them. I set up NFS and TFTP servers
> on my linux box, kernel loads into board but fails to boot woth the
> following message (I skipped some lines of kernel):
>
<snip>
> Freeing unused kernel memory: 104k freed
> do_cpu invoked from kernel context! in traps.c::do_cpu, line 676:
This error is coprocessor unusable exception.
> $0 : 00000000 9004a000 2ab03fe0 2ab03fe0 2ab01560 00000000 00000ae0 00000ae0
> $8 : 00000020 2ab01fe0 2ab01520 00001000 00000019 00000080 811d7b18 00000c62
> $16: 2ab010c0 811d7c58 87f8cfe0 00000003 00000080 2ab01520 87f841a0 00000001
> $24: 00000000 00000080 811d6000 811d7ba0 2aaa8000 8015f414
> Hi : 00000000
> Lo : 00000000
> epc : 80256e14 Not tainted
The exception program counter is 0x80256e14 .
You can check instructions(0x80256e14 and before) in your kernel object.
> Status: 9004a003
> Cause : 1000002c
> PrId : 000034c1
> Process init (pid: 1, stackpage=811d6000)
> Stack: 8015f8a8 8015f9a8 87f71180 8012b2fc 00000000 80135330 00002012
> 00000019 87f8cf60 2ab019e4 00000004 00002012 000590c0 2ab01000 10000000
> 811d7d88 87ff5740 00000000 811d7ef8 81164e80 00000000 00000002 87f841a0
> 8015ffd8 811d7c20 811d6000 811d7cbc 801975a4 00006012 0000000a 811d7c18
> 811d7c18 7f454c46 01020100 00000000 00000000 00020008 00000001 00401980
> 00000034 ...
> Call Trace: [<8015f8a8>] [<8015f9a8>] [<8012b2fc>] [<80135330>]
> [<8015ffd8>]
> [<801975a4>] [<8015fbc0>] [<801493ac>] [<801007b8>] [<8014889c>]
> [<801495bc>]
> [<801495a8>] [<801007b8>] [<80108f80>] [<801007b8>] [<8014fcc4>]
> [<801095c0>]
> [<8025ad30>] [<801007b8>] [<8025ad30>] [<8014af50>] [<801007b8>]
> [<80117888>]
> [<801194a0>] [<80100884>] [<801007b8>] [<8010079c>] [<8025de14>]
> [<80104320>]
> [<80117aec>] [<8026b7a8>] [<801b2054>] [<80104310>]
>
> Code: 30c8003c 01244821 24840040 <ac85ffc0> ac85ffc4 ac85ffc8 ac85ffcc
> ac85ffd0 ac85ffd4
> Kernel panic: Attempted to kill init!
> =====================
>
> I load kernel with the following parameters:
> tftp://192.168.11.43/vmlinux ip=192.168.11.42 root=/dev/nfs
> nfsroot=192.168.11.43:/export/linux/mips-fs-be
>
> What may be the problem here?
>
> Thanks in advance!
>
> With best regards, Roman Mashak. E-mail: mrv@corecom.co.kr
>
Yoichi
^ permalink raw reply [flat|nested] 9+ messages in thread
* RE: booting with NFS root
@ 2006-05-26 2:07 Kiran Thota
2006-05-26 3:05 ` Roman Mashak
2006-05-26 17:56 ` Braden Marr
0 siblings, 2 replies; 9+ messages in thread
From: Kiran Thota @ 2006-05-26 2:07 UTC (permalink / raw)
To: Roman Mashak, linux-mips
[-- Attachment #1: Type: text/plain, Size: 4635 bytes --]
Roman,
You have an older version of the linux kernel. I can send you latest snapshot.
There was a software bug. I don't know your source version to send patch but I am
attaching the source titan_ge.c
Regards,
Kiran
-----Original Message-----
From: linux-mips-bounce@linux-mips.org [mailto:linux-mips-bounce@linux-mips.org] On Behalf Of Roman Mashak
Sent: Thursday, May 25, 2006 5:50 PM
To: linux-mips@linux-mips.org
Subject: booting with NFS root
Hello!
I have evaluation board from PMC-sierra, their CPU is using E9000 core.
Kernel (2.4.26), root FS are provided by them. I set up NFS and TFTP servers on my linux box, kernel loads into board but fails to boot woth the following message (I skipped some lines of kernel):
=====================
PMC-Sierra TITAN 10/100/1000 Ethernet Driver Device Id : 206014, Version : 0
eth0: port 0 with MAC address 30:30:3a:31:31:3a Rx NAPI supported, Tx Coalescing ON
eth1: port 1 with MAC address 30:30:3a:31:31:3b Rx NAPI supported, Tx Coalescing ON
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP, IGMP
IP: routing cache hash table of 1024 buckets, 8Kbytes
TCP: Hash tables configured (established 8192 bind 16384)
IP-Config: Entered.
ipconfig.c 1194
dev.c 1998
dev.c 2013
dev.c 750
irq.c 539
irq.c 571
irq.c 840
irq.c 879
handler->startup 80259d14
irq.c 892
irq.c 576
Assigned IRQ 6 to port 0
titan_ge.c 2256
titan_ge.c 2278
titan_ge.c 2316
titan_ge.c 2359
titan_ge.c 1614
titan_ge.c 1659
titan_ge.c 1698
titan_ge.c 1717
titan_ge.c 1837
titan_ge.c 2025
titan_ge.c 2118
titan_ge.c 2177
dev_addr= 1, reg_addr= 11
val= 4111
val= 1
titan_ge.c 2184
titan_ge.c 2397
dev_addr= 1, reg_addr= 11
val= 4112
val= 1
dev.c 788
dev.c 2034
dev.c 2043
dev.c 2059
IP-Config: eth0 UP (able=1, xid=57c63687) dev.c 1998 dev.c 2013 dev.c 750 irq.c 539 irq.c 571 irq.c 840 irq.c 879 irq.c 892 irq.c 576 Assigned IRQ 6 to port 1 titan_ge.c 2256 titan_ge.c 2278 titan_ge.c 2316 titan_ge.c 2359 titan_ge.c 1659 titan_ge.c 1698 titan_ge.c 1717 titan_ge.c 1837 titan_ge.c 2025 titan_ge.c 2118 titan_ge.c 2177
dev_addr= 2, reg_addr= 11
val= 4111
val= 1
titan_ge.c 2184
titan_ge.c 2397
dev_addr= 2, reg_addr= 11
val= 4212
val= 1
eth1: Error opening interface
dev.c 788
dev.c 2034
dev.c 2043
dev.c 2059
IP-Config: Failed to open eth1
ipconfig.c 1199
IP-Config: Guessing netmask 255.255.255.0
IP-Config: Complete:
device=eth0, addr=192.168.11.42, mask=255.255.255.0, gw=255.255.255.255,
host=192.168.11.42, domain=, nis-domain=(none),
bootserver=255.255.255.255, rootserver=192.168.11.43, rootpath=
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
Looking up port of RPC 100003/2 on 192.168.11.43 Looking up port of RPC 100005/1 on 192.168.11.43
VFS: Mounted root (nfs filesystem).
Freeing unused kernel memory: 104k freed do_cpu invoked from kernel context! in traps.c::do_cpu, line 676:
$0 : 00000000 9004a000 2ab03fe0 2ab03fe0 2ab01560 00000000 00000ae0 00000ae0
$8 : 00000020 2ab01fe0 2ab01520 00001000 00000019 00000080 811d7b18 00000c62
$16: 2ab010c0 811d7c58 87f8cfe0 00000003 00000080 2ab01520 87f841a0 00000001
$24: 00000000 00000080 811d6000 811d7ba0 2aaa8000 8015f414
Hi : 00000000
Lo : 00000000
epc : 80256e14 Not tainted
Status: 9004a003
Cause : 1000002c
PrId : 000034c1
Process init (pid: 1, stackpage=811d6000)
Stack: 8015f8a8 8015f9a8 87f71180 8012b2fc 00000000 80135330 00002012
00000019 87f8cf60 2ab019e4 00000004 00002012 000590c0 2ab01000 10000000
811d7d88 87ff5740 00000000 811d7ef8 81164e80 00000000 00000002 87f841a0
8015ffd8 811d7c20 811d6000 811d7cbc 801975a4 00006012 0000000a 811d7c18
811d7c18 7f454c46 01020100 00000000 00000000 00020008 00000001 00401980
00000034 ...
Call Trace: [<8015f8a8>] [<8015f9a8>] [<8012b2fc>] [<80135330>]
[<8015ffd8>]
[<801975a4>] [<8015fbc0>] [<801493ac>] [<801007b8>] [<8014889c>] [<801495bc>] [<801495a8>] [<801007b8>] [<80108f80>] [<801007b8>] [<8014fcc4>] [<801095c0>] [<8025ad30>] [<801007b8>] [<8025ad30>] [<8014af50>] [<801007b8>] [<80117888>] [<801194a0>] [<80100884>] [<801007b8>] [<8010079c>] [<8025de14>] [<80104320>] [<80117aec>] [<8026b7a8>] [<801b2054>] [<80104310>]
Code: 30c8003c 01244821 24840040 <ac85ffc0> ac85ffc4 ac85ffc8 ac85ffcc ac85ffd0 ac85ffd4 Kernel panic: Attempted to kill init!
=====================
I load kernel with the following parameters:
tftp://192.168.11.43/vmlinux ip=192.168.11.42 root=/dev/nfs nfsroot=192.168.11.43:/export/linux/mips-fs-be
What may be the problem here?
Thanks in advance!
With best regards, Roman Mashak. E-mail: mrv@corecom.co.kr
[-- Attachment #2: titan_ge.c --]
[-- Type: application/octet-stream, Size: 99807 bytes --]
/*
* drivers/net/titan_ge.c - Driver for Titan ethernet ports
*
* Copyright (C) 2004 PMC-Sierra Inc.
* Author : Manish Lachwani (lachwani@pmc-sierra.com)
* Changes for RM9150: Raj Palani (palanira@pmc-sierra.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* The MAC unit of the Titan consists of the following:
*
* -> XDMA Engine to move data to from the memory to the MAC packet FIFO
* -> FIFO is where the incoming and outgoing data is placed
* -> TRTG is the unit that pulls the data from the FIFO for Tx and pushes
* the data into the FIFO for Rx
* -> TMAC is the outgoing MAC interface and RMAC is the incoming.
* -> AFX is the address filtering block
* -> GMII block to communicate with the PHY
*
* Rx will look like the following:
* GMII --> RMAC --> AFX --> TRTG --> Rx FIFO --> XDMA --> CPU memory
*
* Tx will look like the following:
* CPU memory --> XDMA --> Tx FIFO --> TRTG --> TMAC --> GMII
*
* The Titan driver has support for the following performance features:
* -> Rx side checksumming
* -> Jumbo Frames
* -> Interrupt Coalscing
* -> Rx NAPI
* -> SKB Recycling
* -> Transmit/Receive descriptors in SRAM
* -> Fast routing for IP forwarding
*
* Modified aggresively for IP forwarding. pktgen provides 750 kpps
* for Tx path and 64 byte packets. Using Smartbits, we get abt 408 Kpps
*
* SKB Recycling introduced : Pretty good IP forwarding improvement.
* Currently, we are getting 565 Kpps using Smartbits.
*
* Moved the Rx descriptors into the SRAM. Improved IP forwarding
* throughput to 765 Kpps
*
* Renice the priority of ksoftirqd to -19.
*
* Reduce the data touching in the IP forwarding path and set the
* Writeback Enable for the XDMA off. Improved performance for IP
* forwarding to 933 Kpps. On 1.2 Ghz board, packet forwarding has
* improved to 1.04 Mpps
*
* Turn on Direct Deposit for the receive side packets. Packets put
* directly into the L2 cache of the CPU. Prefetching changes also
* incorporated. Improves fastpath forwarding throughput to 1.059 Mpps
*
* Slow path forwarding is now about 415 Kpps. This includes the fix
* for the IP header alignment.
*
* Rx side NAPI support finally in. Gives about 500-512 Kpps forwarding.
* However, still needs work.
*
* Bug fix for NAPI. Was not properly incrementing the workload done for
* the receive. Now, we get about 565 Kpps on the slow path.
*
* Introduce the Tx and Rx thresholds for the descriptor recycling. Improves
* NAPI throughput to 578 Kpps.
*
* Made changes specific to the Uniprocessor kernel. No need to use LLSC on
* UP. Just disable and enable interrupts. Saves some CPU cycles and improves
* performance to 588 Kpps
*
* Disable rp_filter since it is broken and it gives us a couple of Kpps
* more. Performance for slow path improves to 591 Kpps
*
* Do we need Tx side interrupts at all? Increased the coalescing to a
* very large value, like 1000. Now, Tx interrupt comes after a very long
* time. This is good and gets the forwarding throughput to 600 Kpps
*
* At this point in time, Tx and Rx interrupts have been disabled completely
* and the poll routine handles everything. It clean the tx queue and also
* the Rx allocation. Performance now is 605 Kpps
*
* Make sure FASTROUTE and NAPI are not enabled at the same time.
*
* Changed the Tx Queue Size (Tx Ring Size) to 64. This improved the fast
* path routing from 1068 Kpps to about 1201 Kpps.
*
* If GCC 2.9.6 is used to compile the kernel, then it will align the IP
* header before presenting it to the network stack. Although, we avoid
* an extra copy in this case, we do not get any improvement in performance
*
* In Titan 1.2 chip, one of the fixes was to align the IP header. So, we
* dont need an extra copy for the incoming SKB if the board has a 1.2 chip
*
* Configure the port #3 to send the interrupts to the CPU.
*
* IO coherency flawed in case of SMP. The Data Wr coherency has to be turned
* off leading to two cache invalidates in the Rx side of the driver
*/
#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/fcntl.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ip.h>
#include <linux/init.h>
#include <linux/in.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/mii.h>
#include <linux/delay.h>
#include <linux/skbuff.h>
#ifdef CONFIG_NET_SKB_RECYCLING
#include <linux/prefetch.h>
#endif
/* For MII specifc registers, titan_mdio.h should be included */
#include <net/ip.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/types.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include "titan_ge.h"
#include "titan_mdio.h"
/* Static Function Declarations */
static int titan_ge_eth_open(struct net_device *);
static int titan_ge_eth_stop(struct net_device *);
static int titan_ge_change_mtu(struct net_device *, int);
static struct net_device_stats *titan_ge_get_stats(struct net_device *);
static int titan_ge_init_rx_desc_ring(titan_ge_port_info *, int, int,
unsigned long, unsigned long,
unsigned long);
static int titan_ge_init_tx_desc_ring(titan_ge_port_info *, int,
unsigned long, unsigned long);
static int titan_ge_open(struct net_device *);
static int titan_ge_start_xmit(struct sk_buff *, struct net_device *);
static int titan_ge_stop(struct net_device *);
static void titan_ge_int_handler(int, void *, struct pt_regs *);
static int titan_ge_set_mac_address(struct net_device *, void *);
static unsigned long titan_ge_tx_coal(unsigned long, int);
static unsigned long titan_ge_rx_coal(unsigned long, int);
static void titan_ge_port_reset(unsigned int);
static int titan_ge_free_tx_queue(titan_ge_port_info *);
static int titan_ge_rx_task(struct net_device *, titan_ge_port_info *);
static int titan_ge_port_start(struct net_device *, titan_ge_port_info *);
static int titan_ge_init(int);
static int titan_ge_return_tx_desc(titan_ge_port_info *, int);
#ifdef CONFIG_CPU_HAS_PREFETCH
#define Pref_Load 0
static inline void rm9000_prefetch(const void *addr)
{
__asm__ __volatile__(
" .set mips4 \n"
" pref %0, (%1) \n"
" .set mips0 \n"
:
: "i" (Pref_Load), "r" (addr));
}
#endif
#ifdef CONFIG_NET_SKB_RECYCLING
/*
* Not a part of the Linux tree as yet. Works well
* in the Uniprocessor mode
*/
#define RC_QUEUE_PER_DEV 300;
/*
* For the future, add the stats for the recycler
*/
struct titan_ge_rc_data {
struct sk_buff_head list ____cacheline_aligned;
struct sk_buff_head list_tmp[1] ____cacheline_aligned;
int qlen;
atomic_t cnt;
};
struct titan_ge_rc_data titan_ge_rc[1] ____cacheline_aligned;
static void titan_ge_recycle_init(void);
static void titan_ge_recycle_remove(void);
/*
* Initialize the recycler
*/
static void titan_ge_recycle_init(void)
{
int cpu, cpu1;
for (cpu=0; cpu < 1; cpu++) {
atomic_set(&titan_ge_rc[cpu].cnt, 0);
skb_queue_head_init(&titan_ge_rc[cpu].list);
for (cpu1=0; cpu1 < 1; cpu1++) {
skb_queue_head_init(&titan_ge_rc[cpu].list_tmp[cpu1]);
}
}
}
static void titan_ge_remove_tmp_queues(int cpu)
{
int cpu1;
for (cpu1=0; cpu1 < 1; cpu1++) {
struct sk_buff_head *list;
struct sk_buff *skb;
list = &titan_ge_rc[cpu].list_tmp[cpu1];
while ((skb=skb_dequeue(list))!=NULL) {
__kfree_skb_recycled(skb);
atomic_dec(&titan_ge_rc[cpu].cnt);
}
}
}
/*
* remove the recycler
*/
static void titan_ge_recycle_remove(void)
{
int cpu;
for(cpu=0; cpu < 1; cpu++) {
while(atomic_read(&titan_ge_rc[cpu].cnt)) {
struct sk_buff *skb;
struct sk_buff_head *list = &titan_ge_rc[cpu].list;
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(10);
titan_ge_remove_tmp_queues(cpu);
while ((skb=skb_dequeue(list))!=NULL) {
__kfree_skb_recycled(skb);
atomic_dec(&titan_ge_rc[cpu].cnt);
}
}
}
}
static inline int __skb_prepend_list(struct sk_buff_head *l1, struct sk_buff_head *l2)
{
struct sk_buff *t1, *t2;
int len = 0;
if(l2->qlen == 0)
return 0;
len = l2->qlen;
t1 = l1->next;
t2 = l2->prev;
l1->next = l2->next;
t2->next = t1;
l1->next->prev = (struct sk_buff *) l1;
t1->prev = t2;
l1->qlen += len;
l2->qlen = 0;
l2->next = l2->prev = (struct sk_buff *)l2;
return len;
}
static inline int skb_prepend_list(struct sk_buff_head *l1, struct sk_buff_head *l2)
{
int i;
unsigned long flags;
#ifdef CONFIG_SMP
spin_lock_irqsave(&l1->lock, flags);
#else
local_irq_save(flags);
#endif
spin_lock(&l2->lock);
i = __skb_prepend_list(l1, l2);
spin_unlock(&l2->lock);
#ifdef CONFIG_SMP
spin_unlock_irqrestore(&l1->lock, flags);
#else
local_irq_restore(flags);
#endif
return i;
}
/*
* Main recycling function
*/
static int titan_ge_recycle(struct sk_buff *skb)
{
struct sk_buff_head *list = &titan_ge_rc[smp_processor_id()].
list_tmp[skb->cpu];
if (skb_queue_len(list) <= titan_ge_rc[skb->cpu].qlen/4 ) {
if(skb->cpu == smp_processor_id()) {
struct sk_buff_head *list2;
list2 = &titan_ge_rc[smp_processor_id()].list;
__skb_queue_head(list2, skb);
return 1;
}
else {
__skb_queue_head(list, skb);
if(skb_queue_len(list) > 32 ){
struct sk_buff_head *list3;
list3 = &titan_ge_rc[skb->cpu].list_tmp[skb->cpu];
skb_prepend_list(list3, list);
}
return 1;
}
}
atomic_dec(&titan_ge_rc[skb->cpu].cnt);
return 0;
}
/*
* Reclaim the memory
*/
static void titan_ge_mem_reclaim(struct net_device *dev)
{
titan_ge_recycle_remove();
}
/*
* Main function to get the skb from the recycle pool
*/
static inline struct sk_buff *get_recycle(titan_ge_port_info *titan_ge_eth)
{
struct sk_buff_head *list = &titan_ge_rc[smp_processor_id()].list;
struct sk_buff *skb, *l;
l = (struct sk_buff *)list;
#ifdef CONFIG_CPU_HAS_PREFETCH
rm9000_prefetch(l->next->next);
#endif
skb = __skb_dequeue(list);
if(!skb) {
struct sk_buff_head *list2;
list2 = &titan_ge_rc[smp_processor_id()].list_tmp[smp_processor_id()];
while ( skb_queue_len(list2)) {
skb_prepend_list(list, list2);
}
skb = __skb_dequeue(list);
}
if(skb) {
u8 *data = skb->head;
unsigned int size = skb->truesize - sizeof(struct sk_buff);
l = (struct sk_buff *)list;
skb_headerinit(skb, data, size); /* clean state */
skb->data = skb->head;
skb->tail = skb->head;
skb->len = 0;
skb->end = data + size;
}
return skb;
}
#endif
/*
* Some configuration for the FIFO and the XDMA channel needs
* to be done only once for all the ports. This flag controls
* that
*/
unsigned long config_done = 0;
/*
* One time out of memory flag
*/
unsigned int oom_flag = 0;
#ifdef TITAN_RX_NAPI
static int titan_ge_poll(struct net_device *netdev, int *budget);
#endif
int titan_ge_receive_queue(struct net_device *, unsigned int);
/* MAC Address */
extern unsigned char titan_ge_mac_addr_base[6];
/*
* The Titan GE has two alignment requirements:
* -> skb->data to be cacheline aligned (32 byte)
* -> IP header alignment to 16 bytes
*
* The latter is not implemented. So, that results in an extra copy on
* the Rx. This is a big performance hog. For the former case, the
* dev_alloc_skb() has been replaced with titan_ge_alloc_skb(). The size
* requested is calculated:
*
* Ethernet Frame Size : 1518
* Ethernet Header : 14
* Future Titan change for IP header alignment : 2
*
* Hence, we allocate (1518 + 14 + 2+ 64) = 1580 bytes. For the future
* revisions of the chip that do support IP header alignment, we will use
* skb_reserve().
*/
#define ALIGNED_RX_SKB_ADDR(addr) \
((((unsigned long)(addr) + (64UL - 1UL)) \
& ~(64UL - 1UL)) - (unsigned long)(addr))
#define titan_ge_alloc_skb(__length, __gfp_flags) \
({ struct sk_buff *__skb; \
__skb = alloc_skb((__length) + 64, (__gfp_flags)); \
if(__skb) { \
int __offset = (int) ALIGNED_RX_SKB_ADDR(__skb->data); \
if(__offset) \
skb_reserve(__skb, __offset); \
} \
__skb; \
})
/*
* Reset the Marvel PHY
*/
static void titan_ge_reset_phy(void)
{
int err = 0;
unsigned int reg_data;
/* Reset the PHY for the above values to take effect */
err =
titan_ge_mdio_read(TITAN_GE_MARVEL_PHY_ID, MII_BMCR,
®_data);
if (err == TITAN_GE_MDIO_ERROR) {
printk(KERN_ERR
"Could not read PHY control register 0 \n");
return TITAN_GE_ERROR;
}
reg_data |= 0x8000;
err =
titan_ge_mdio_write(TITAN_GE_MARVEL_PHY_ID, MII_BMCR,
reg_data);
if (err == TITAN_GE_MDIO_ERROR) {
printk(KERN_ERR
"Could not write to PHY control register 0 \n");
return TITAN_GE_ERROR;
}
}
/*
* Wait for sometime to check if Auto-Neg has completed
*/
static int titan_ge_wait_autoneg(void)
{
int err = 0, i = 0;
unsigned long reg_data;
for (i = 0; i < PHY_ANEG_TIME_WAIT; i++) {
err =
titan_ge_mdio_read(TITAN_GE_MARVEL_PHY_ID, MII_BMSR,
®_data);
if (err == TITAN_GE_MDIO_ERROR) {
printk(KERN_ERR
"Could not read PHY status register 0x1 \n");
return TITAN_GE_MDIO_ERROR;
}
if (reg_data & 0x8)
return TITAN_GE_MDIO_GOOD;
msec_delay(100);
}
if (!(reg_data & 0x8)) {
printk(KERN_ERR
"Auto-Negotiation did not complete successfully \n");
return TITAN_GE_MDIO_ERROR;
}
return TITAN_GE_MDIO_GOOD;
}
/*
* Get the speed/duplex from the PHY and
* put it into the main Titan structure
*/
static int titan_ge_get_speed(titan_ge_port_info * titan_ge_eth)
{
int err = 0;
unsigned int reg_data = 0;
err =
titan_ge_mdio_read(TITAN_GE_MARVEL_PHY_ID,
TITAN_GE_MDIO_MII_EXTENDED, ®_data);
if (err == TITAN_GE_MDIO_ERROR) {
printk(KERN_ERR
"Could not read PHY status register 0x0f \n");
return TITAN_GE_MDIO_ERROR;
}
/* Check for 1000 Mbps first */
if (reg_data & 0x1010) {
titan_ge_eth->duplex = TITAN_GE_FULL_DUPLEX;
titan_ge_eth->speed = TITAN_GE_SPEED_1000;
return TITAN_GE_MDIO_GOOD;
}
if (reg_data & 0x0101) {
titan_ge_eth->duplex = TITAN_GE_HALF_DUPLEX;
titan_ge_eth->speed = TITAN_GE_SPEED_1000;
return TITAN_GE_MDIO_GOOD;
}
/* Check for 100 Mbps next */
err =
titan_ge_mdio_read(TITAN_GE_MARVEL_PHY_ID, MII_BMSR,
®_data);
if (err == TITAN_GE_MDIO_ERROR) {
printk(KERN_ERR
"Could not read PHY status register 0x01 \n");
return TITAN_GE_MDIO_ERROR;
}
if (reg_data & 0x4000) {
titan_ge_eth->duplex = TITAN_GE_FULL_DUPLEX;
titan_ge_eth->speed = TITAN_GE_SPEED_100;
return TITAN_GE_MDIO_GOOD;
}
if (reg_data & 0x2000) {
titan_ge_eth->duplex = TITAN_GE_HALF_DUPLEX;
titan_ge_eth->speed = TITAN_GE_SPEED_100;
return TITAN_GE_MDIO_GOOD;
}
/* Check for 10 Mbps */
if (reg_data & 0x1000) {
titan_ge_eth->duplex = TITAN_GE_FULL_DUPLEX;
titan_ge_eth->speed = TITAN_GE_SPEED_10;
return TITAN_GE_MDIO_GOOD;
}
if (reg_data & 0x0800) {
titan_ge_eth->duplex = TITAN_GE_HALF_DUPLEX;
titan_ge_eth->speed = TITAN_GE_SPEED_10;
return TITAN_GE_MDIO_GOOD;
}
return TITAN_GE_MDIO_ERROR;
}
/*
* Configures flow control
*/
static int titan_ge_fc_config(titan_ge_port_info * titan_ge_eth)
{
int err = 0;
unsigned int adv_reg_data, lp_reg_data;
err =
titan_ge_mdio_read(TITAN_GE_MARVEL_PHY_ID,
TITAN_PHY_AUTONEG_ADV, &adv_reg_data);
if (err == TITAN_GE_MDIO_ERROR) {
printk(KERN_ERR
"Could not read PHY control register 0x4 \n");
return TITAN_GE_MDIO_ERROR;
}
err =
titan_ge_mdio_read(TITAN_GE_MARVEL_PHY_ID,
TITAN_PHY_LP_ABILITY, &lp_reg_data);
if (err == TITAN_GE_MDIO_ERROR) {
printk(KERN_ERR
"Could not read PHY control register 0x4 \n");
return TITAN_GE_MDIO_ERROR;
}
/*
* Check if both the PAUSE bits are set to 1.
* If that is the case, then we have Symmetric
* Flow Control enabled at both the ends. For the
* Marvel PHY, the bits 8 and 7 in the TITAN_PHY_AUTONEG_ADV
* register need to be checked here. For the LP,
* the bits 11 and 10 of the TITAN_PHY_LP_ABILITY
* register need to be checked here
*/
if ((adv_reg_data & 0x0180) && (lp_reg_data & 0x0400)) {
printk("Symmetric Flow Control \n");
titan_ge_eth->fc = TITAN_GE_FC_FULL;
}
else
/* For the Transmit Pause Frames only */
if (!(adv_reg_data & 0x0080) && (adv_reg_data & 0x0100) &&
(lp_reg_data & 0x0800) && (lp_reg_data & 0x0400)) {
printk("Transmit FC \n");
titan_ge_eth->fc = TITAN_GE_FC_TX_PAUSE;
}
else
/* For the Receive Pause Frames only */
if ((adv_reg_data & 0x0180) && !(lp_reg_data & 0x0800) &&
(lp_reg_data & 0x0400)) {
printk("Rx Pause only \n");
titan_ge_eth->fc = TITAN_GE_FC_RX_PAUSE;
}
else {
printk("No FC \n");
/* No Flow Control */
titan_ge_eth->fc = TITAN_GE_FC_NONE;
}
return TITAN_GE_MDIO_GOOD;
}
/*
* Configure the GMII block of the Titan based
* on what the PHY tells us
*/
static void titan_ge_gmii_config(int port_num)
{
volatile unsigned int reg_data = 0, phy_reg;
int err;
err = titan_ge_mdio_read(port_num,
TITAN_GE_MDIO_PHY_STATUS, &phy_reg);
if (err == TITAN_GE_MDIO_ERROR) {
printk(KERN_ERR
"Could not read PHY control register 0x11 \n");
printk(KERN_ERR
"Setting speed to 1000 Mbps and Duplex to Full \n");
return TITAN_ERROR;
}
err = titan_ge_mdio_write(port_num,
TITAN_GE_MDIO_PHY_IE, 0);
if (phy_reg & 0x8000) {
if (phy_reg & 0x2000) {
/* Full Duplex and 1000 Mbps */
TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
(port_num << 12)), 0x201);
} else {
/* Half Duplex and 1000 Mbps */
TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
(port_num << 12)), 0x2201);
}
}
if (phy_reg & 0x4000) {
if (phy_reg & 0x2000) {
/* Full Duplex and 100 Mbps */
TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
(port_num << 12)), 0x100);
} else {
/* Half Duplex and 100 Mbps */
TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
(port_num << 12)), 0x2100);
}
}
reg_data = TITAN_GE_READ(TITAN_GE_GMII_CONFIG_GENERAL +
(port_num << 12));
reg_data |= 0x3;
TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_GENERAL +
(port_num << 12)), reg_data);
}
/*
* Configure the PHY. No support for TBI (10 Bit Interface) as yet.
* Hence, we need to make use of MDIO for communication with the
* external PHY. The PHY uses GMII
*/
static int titan_phy_setup(titan_ge_port_info * titan_ge_eth)
{
unsigned int reg_data;
int err = 0;
titan_ge_mdio_config *titan_ge_mdio =
kmalloc(sizeof(titan_ge_mdio_config), GFP_KERNEL);
titan_ge_mdio->clka = 0x301f; /* Clock */
titan_ge_mdio->mdio_spre = 0x0000; /* Generate 32-bit Preamble */
titan_ge_mdio->mdio_mode = 0x4000; /* Direct mode */
titan_ge_mdio_setup(titan_ge_mdio); /* Setup the SCMB and the MDIO */
/* Now read the PHY status register */
err = titan_ge_wait_autoneg();
if (err == TITAN_GE_MDIO_ERROR)
return TITAN_ERROR;
/* Now read the Model of the PHY */
err =
titan_ge_mdio_read(TITAN_GE_MARVEL_PHY_ID, MII_PHYSID2,
®_data);
if (err == TITAN_GE_MDIO_ERROR) {
printk(KERN_ERR
"Could not read PHY status register 0x3 \n");
return TITAN_ERROR;
}
printk("Marvel PHY Model Number : %x \n", reg_data);
/* Interrupt Enable Registers for the PHY */
err =
titan_ge_mdio_read(TITAN_GE_MARVEL_PHY_ID,
TITAN_GE_MDIO_PHY_IE, ®_data);
if (err == TITAN_GE_MDIO_ERROR) {
printk(KERN_ERR
"Could not read PHY control register 0x11 \n");
return TITAN_ERROR;
}
/*
* Description:
*
* Speed Change interrupt Enable
* Duplex Change interrupt Enable
* Link status change interrupt enable
*/
reg_data |= 0x34;
err =
titan_ge_mdio_write(TITAN_GE_MARVEL_PHY_ID, MII_BMCR,
reg_data);
if (err == TITAN_GE_MDIO_ERROR) {
printk(KERN_ERR
"Could not write to PHY control register 0x9 \n");
return TITAN_ERROR;
}
return TITAN_OK;
}
/*
* Enable the TMAC if it is not
*/
static void titan_ge_enable_tx(unsigned int port_num)
{
unsigned long reg_data;
reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 +
(port_num << 12));
if (!(reg_data & 0x8000)) {
printk("TMAC disabled for port %d!! \n", port_num);
reg_data |= 0x0001; /* Enable TMAC */
reg_data |= 0x4000; /* CRC Check Enable */
reg_data |= 0x2000; /* Padding enable */
reg_data |= 0x0800; /* CRC Add enable */
reg_data |= 0x0080; /* PAUSE frame */
TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 +
(port_num << 12)), reg_data);
}
}
/*
* Tx Timeout function
*/
static void titan_ge_tx_timeout(struct net_device *netdev)
{
titan_ge_port_info *titan_ge_eth = netdev->priv;
printk(KERN_INFO "%s: TX timeout ", netdev->name);
printk(KERN_INFO "Resetting card \n");
/* Do the reset outside of interrupt context */
schedule_task(&titan_ge_eth->tx_timeout_task);
}
/*
* Update the AFX tables for UC and MC for slice 0 only
*/
static void titan_ge_update_afx(titan_ge_port_info * titan_ge_eth)
{
unsigned int i;
volatile unsigned long reg_data = 0;
u8 p_addr[6];
int port = titan_ge_eth->port_num;
memcpy(p_addr, titan_ge_eth->port_mac_addr, 6);
/* Set the MAC address here for TMAC and RMAC */
TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port << 12)),
((p_addr[5] << 8) | p_addr[4]));
TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port << 12)),
((p_addr[3] << 8) | p_addr[2]));
TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port << 12)),
((p_addr[1] << 8) | p_addr[0]));
TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port << 12)),
((p_addr[5] << 8) | p_addr[4]));
TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port << 12)),
((p_addr[3] << 8) | p_addr[2]));
TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port << 12)),
((p_addr[1] << 8) | p_addr[0]));
#ifdef CONFIG_PMC_SEQUOIA
TITAN_GE_WRITE((0x1164 | (port << 12)), 0x1);
#else
TITAN_GE_WRITE((0x112c | (port << 12)), 0x1);
#endif
#ifdef CONFIG_PMC_SEQUOIA
/* Configure the sixteen address filters */
for (i = 0; i < 16; i++) {
/* Select each of the sixteen filters */
TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 +
(port << 12)), i);
/* Configure the match */
reg_data = 0x9; /* Forward Enable Bit */
TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 +
(port << 12)), reg_data);
/* Finally, AFX Exact Match Address Registers */
TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_LOW + (port << 12)),
((p_addr[1] << 8) | p_addr[0]));
TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_MID + (port << 12)),
((p_addr[3] << 8) | p_addr[2]));
TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_HIGH + (port << 12)),
((p_addr[5] << 8) | p_addr[4]));
/* VLAN id set to 0 */
TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_VID +
(port << 12)), 0);
}
#else //CONFIG_PMC_SEQUOIA
/* Configure the eight address filters */
for (i = 0; i < 8; i++) {
/* Select each of the eight filters */
TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 +
(port << 12)), i);
/* Configure the match */
reg_data = 0x9; /* Forward Enable Bit */
TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 +
(port << 12)), reg_data);
/* Finally, AFX Exact Match Address Registers */
TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_LOW + (port << 12)),
((p_addr[1] << 8) | p_addr[0]));
TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_MID + (port << 12)),
((p_addr[3] << 8) | p_addr[2]));
TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_HIGH + (port << 12)),
((p_addr[5] << 8) | p_addr[4]));
/* VLAN id set to 0 */
TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_VID +
(port << 12)), 0);
}
#endif //CONFIG_PMC_SEQUOIA
}
/*
* Actual Routine to reset the adapter when the timeout occurred
*/
static void titan_ge_tx_timeout_task(struct net_device *netdev)
{
titan_ge_port_info *titan_ge_eth = netdev->priv;
int port = titan_ge_eth->port_num;
printk("Titan GE: Transmit timed out. Resetting ... \n");
/* Dump debug info */
printk(KERN_ERR "TRTG cause : %x \n",
(unsigned long)TITAN_GE_READ(0x100c + (port << 12)));
#ifdef CONFIG_PMC_SEQUOIA
/* Fix this for the other ports */
printk(KERN_ERR "FIFO cause : %x \n",
(unsigned long)TITAN_GE_READ(0x282c));
printk(KERN_ERR "IE cause : %x \n",
(unsigned long)TITAN_GE_READ(0x0024));
printk(KERN_ERR "XDMA GDI ERROR : %x \n",
(unsigned long)TITAN_GE_READ(0x3008 + (port << 9)));
printk(KERN_ERR "CHANNEL ERROR: %x \n",
(unsigned long)TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT
+ (port << 9)));
#else //CONFIG_PMC_SEQUOIA
/* Fix this for the other ports */
printk(KERN_ERR "FIFO cause : %x \n",
(unsigned long)TITAN_GE_READ(0x482c));
printk(KERN_ERR "IE cause : %x \n",
(unsigned long)TITAN_GE_READ(0x0040));
printk(KERN_ERR "XDMA GDI ERROR : %x \n",
(unsigned long)TITAN_GE_READ(0x5008 + (port << 8)));
printk(KERN_ERR "CHANNEL ERROR: %x \n",
(unsigned long)TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT
+ (port << 8)));
#endif //CONFIG_PMC_SEQUOIA
netif_device_detach(netdev);
titan_ge_port_reset(titan_ge_eth->port_num);
titan_ge_port_start(netdev, titan_ge_eth);
netif_device_attach(netdev);
}
/*
* Change the MTU of the Ethernet Device
*/
static int titan_ge_change_mtu(struct net_device *netdev, int new_mtu)
{
titan_ge_port_info *titan_ge_eth;
unsigned int port_num;
unsigned long flags;
titan_ge_eth = netdev->priv;
port_num = titan_ge_eth->port_num;
spin_lock_irqsave(&titan_ge_eth->lock, flags);
if ((new_mtu > 9500) || (new_mtu < 64)) {
spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
return -EINVAL;
}
netdev->mtu = new_mtu;
/* Now we have to reopen the interface so that SKBs with the new
* size will be allocated */
if (netif_running(netdev)) {
if (titan_ge_eth_stop(netdev) != TITAN_OK) {
printk(KERN_ERR
"%s: Fatal error on stopping device\n",
netdev->name);
spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
return -1;
}
if (titan_ge_eth_open(netdev) != TITAN_OK) {
printk(KERN_ERR
"%s: Fatal error on opening device\n",
netdev->name);
spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
return -1;
}
}
spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
return 0;
}
/*
* Reset the XDMA unit due to errors
*/
static void titan_ge_xdma_reset(void)
{
unsigned long reg_data;
reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG);
reg_data |= 0x80000000;
TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data);
mdelay(2);
reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG);
reg_data &= ~(0x80000000);
TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data);
}
/*
* Titan Gbe Interrupt Handler. All the three ports
* send interrupt to one line only. Once an interrupt
* is triggered, figure out the port and then check
* the channel.
*/
static void titan_ge_int_handler(int irq, void *dev_id,
struct pt_regs *regs)
{
struct net_device *netdev = (struct net_device *) dev_id;
titan_ge_port_info *titan_ge_eth;
unsigned int port_num, reg_data;
unsigned long eth_int_cause_error = 0, is, temp;
unsigned long eth_int_cause1;
int err = 0;
unsigned int count;
#ifdef CONFIG_SMP
unsigned long eth_int_cause2;
#endif
titan_ge_eth = netdev->priv;
port_num = titan_ge_eth->port_num;
#ifdef CONFIG_PMC_SEQUOIA
/* Ack the CPU interrupt */
/* If we have separate interrupts for all the channels something
different has to be done
*/
#ifdef CONFIG_MIPS64
is = *(volatile u_int32_t *)(0xffffffff00000000
| RM9150_GCIC_INT3_STATUS);
temp = 0xffffffff00000000 | RM9150_GCIC_INT3_CLEAR;
*(volatile u_int32_t *)(temp) = is;
#else
is = *(volatile u_int32_t *)(RM9150_GCIC_INT3_STATUS);
*(volatile u_int32_t *)(RM9150_GCIC_INT3_CLEAR) = is;
#endif
eth_int_cause1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A);
if (eth_int_cause1 == 0) {
eth_int_cause_error = TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT
+ (port_num << 9));
if (eth_int_cause_error == 0)
return;
}
/* Handle Tx first. No need to ack interrupts */
if (eth_int_cause1 & 0x20002)
titan_ge_free_tx_queue(titan_ge_eth);
#ifdef TITAN_RX_NAPI
/* Handle the Rx next */
if (eth_int_cause1 & 0x10001) {
if (netif_rx_schedule_prep(netdev)) {
unsigned int ack;
ack = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
/* Disable Tx and Rx both */
if (port_num == 0)
ack &= ~(0x3);
if (port_num == 1)
ack &= ~(0x30000);
/* Interrupts have been disabled */
TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, ack);
__netif_rx_schedule(netdev);
}
}
#else
titan_ge_free_tx_queue(titan_ge_eth);
count = titan_ge_receive_queue(netdev, 0);
#endif
/* Handle error interrupts */
if (eth_int_cause_error &&
(eth_int_cause_error != 0x2)) {
/*
TITAN_GE_READ(TITAN_GE_GXIS);
*/
printk(KERN_ERR
"XDMA Channel Error : %x on port %d\n",
eth_int_cause_error, port_num);
printk(KERN_ERR
"XDMA GDI Hardware error : %x on port %d\n",
TITAN_GE_READ(0x3008 + (port_num << 9)), port_num);
printk(KERN_ERR
"XDMA currently has %d Rx descriptors \n",
TITAN_GE_READ(0x3048 + (port_num << 9)));
printk(KERN_ERR
"XDMA currently has prefetcted %d Rx descriptors \n",
TITAN_GE_READ(0x305c + (port_num << 9)));
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT +
(port_num << 9)), eth_int_cause_error);
}
/*
* PHY interrupt to inform abt the changes. Reading the
* PHY Status register will clear the interrupt
*/
if ((!(eth_int_cause1 & 0x30003)) &&
(eth_int_cause_error == 0)) {
err =
titan_ge_mdio_read(port_num,
TITAN_GE_MDIO_PHY_IS, ®_data);
if (reg_data & 0x0400) {
/* Link status change */
titan_ge_mdio_read(port_num,
TITAN_GE_MDIO_PHY_STATUS, ®_data);
if (!(reg_data & 0x0400)) {
/* Link is down */
netif_carrier_off(netdev);
netif_stop_queue(netdev);
} else {
/* Link is up */
netif_carrier_on(netdev);
netif_wake_queue(netdev);
/* Enable the queue */
titan_ge_enable_tx(port_num);
}
}
}
#else //CONFIG_PMC_SEQUOIA
/* Ack the CPU interrupt */
if (port_num == 1) {
#ifdef CONFIG_MIPS64
is = *(volatile u_int32_t *)(0xfffffffffb001b00);
*(volatile u_int32_t *)(0xfffffffffb001b0c) = is;
#else
is = *(volatile u_int32_t *)(0xfb001b00);
*(volatile u_int32_t *)(0xfb001b0c) = is;
#endif
#ifdef CONFIG_SMP
is = *(volatile u_int32_t *)(0xfb002b00);
*(volatile u_int32_t *)(0xfb002b0c) = is;
#endif
}
if (port_num == 0) {
#ifdef CONFIG_MIPS64
is = *(volatile u_int32_t *)(0xfffffffffb001b10);
*(volatile u_int32_t *)(0xfffffffffb001b1c) = is;
#else
is = *(volatile u_int32_t *)(0xfb001b10);
*(volatile u_int32_t *)(0xfb001b1c) = is;
#endif
#ifdef CONFIG_SMP
is = *(volatile u_int32_t *)(0xfb002b10);
*(volatile u_int32_t *)(0xfb002b1c) = is;
#endif
}
#ifdef TITAN_GE_12
if (port_num == 2) {
#ifdef CONFIG_MIPS64
is = *(volatile u_int32_t *)(0xfffffffffb001b40);
*(volatile u_int32_t *)(0xfffffffffb001b4c) = is;
#else
is = *(volatile u_int32_t *)(0xfb001b40);
*(volatile u_int32_t *)(0xfb001b4c) = is;
#endif
#ifdef CONFIG_SMP
is = *(volatile u_int32_t *)(0xfb002b40);
*(volatile u_int32_t *)(0xfb002b4c) = is;
#endif
}
#endif
eth_int_cause1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A);
#ifdef CONFIG_SMP
eth_int_cause2 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_B);
#endif
/* Spurious interrupt */
#ifdef CONFIG_SMP
if ( (eth_int_cause1 == 0) && (eth_int_cause2 == 0)) {
#else
if (eth_int_cause1 == 0) {
#endif
eth_int_cause_error = TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT +
(port_num << 8));
if (eth_int_cause_error == 0)
return;
}
/* Handle Tx first. No need to ack interrupts */
#ifdef CONFIG_SMP
if ( (eth_int_cause1 & 0x20202) ||
(eth_int_cause2 & 0x20202) )
#else
if (eth_int_cause1 & 0x20202)
#endif
titan_ge_free_tx_queue(titan_ge_eth);
#ifdef TITAN_RX_NAPI
/* Handle the Rx next */
#ifdef CONFIG_SMP
if ( (eth_int_cause1 & 0x10101) ||
(eth_int_cause2 & 0x10101)) {
#else
if (eth_int_cause1 & 0x10101) {
#endif
if (netif_rx_schedule_prep(netdev)) {
unsigned int ack;
ack = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
/* Disable Tx and Rx both */
if (port_num == 0)
ack &= ~(0x3);
if (port_num == 1)
ack &= ~(0x300);
if (port_num == 2)
ack &= ~(0x30000);
/* Interrupts have been disabled */
TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, ack);
__netif_rx_schedule(netdev);
}
}
#else
titan_ge_free_tx_queue(titan_ge_eth);
count = titan_ge_receive_queue(netdev, 0);
#endif
/* Handle error interrupts */
if (eth_int_cause_error &&
(eth_int_cause_error != 0x2)) {
printk(KERN_ERR
"XDMA Channel Error : %x on port %d\n",
eth_int_cause_error, port_num);
printk(KERN_ERR
"XDMA GDI Hardware error : %x on port %d\n",
TITAN_GE_READ(0x5008 + (port_num << 8)), port_num);
printk(KERN_ERR
"XDMA currently has %d Rx descriptors \n",
TITAN_GE_READ(0x5048 + (port_num << 8)));
printk(KERN_ERR
"XDMA currently has prefetcted %d Rx descriptors \n",
TITAN_GE_READ(0x505c + (port_num << 8)));
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT +
(port_num << 8)), eth_int_cause_error);
}
/*
* PHY interrupt to inform abt the changes. Reading the
* PHY Status register will clear the interrupt
*/
if ((!(eth_int_cause1 & 0x30303)) &&
(eth_int_cause_error == 0)) {
err =
titan_ge_mdio_read(port_num,
TITAN_GE_MDIO_PHY_IS, ®_data);
if (reg_data & 0x0400) {
/* Link status change */
titan_ge_mdio_read(port_num,
TITAN_GE_MDIO_PHY_STATUS, ®_data);
if (!(reg_data & 0x0400)) {
/* Link is down */
netif_carrier_off(netdev);
netif_stop_queue(netdev);
} else {
/* Link is up */
netif_carrier_on(netdev);
netif_wake_queue(netdev);
/* Enable the queue */
titan_ge_enable_tx(port_num);
}
}
}
#endif //CONFIG_PMC_SEQUOIA
}
/*
* Multicast and Promiscuous mode set. The
* set_multi entry point is called whenever the
* multicast address list or the network interface
* flags are updated.
*/
static void titan_ge_set_multi(struct net_device *netdev)
{
unsigned long reg_data;
struct dev_mc_list *mc_ptr;
unsigned int port_num;
titan_ge_port_info *titan_ge_eth;
titan_ge_eth = netdev->priv;
port_num = titan_ge_eth->port_num;
reg_data = TITAN_GE_READ(TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 +
(port_num << 12));
if (netdev->flags & IFF_PROMISC) {
reg_data |= 0x2;
}
else if (netdev->flags & IFF_ALLMULTI) {
reg_data |= 0x01;
reg_data |= 0x400; /* Use the 64-bit Multicast Hash bin */
}
else {
reg_data = 0x2;
}
TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 +
(port_num << 12)), reg_data);
if (reg_data & 0x01) {
TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_LOW +
(port_num << 12)), 0xffff);
TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDLOW +
(port_num << 12)), 0xffff);
TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDHI +
(port_num << 12)), 0xffff);
TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_HI +
(port_num << 12)), 0xffff);
}
}
/*
* Open the network device
*/
static int titan_ge_open(struct net_device *netdev)
{
int retval;
titan_ge_port_info *titan_ge_eth;
unsigned int port_num;
titan_ge_eth = netdev->priv;
port_num = titan_ge_eth->port_num;
#ifdef CONFIG_PMC_SEQUOIA
retval = request_irq(6, titan_ge_int_handler,
SA_SHIRQ | SA_SAMPLE_RANDOM , netdev->name, netdev);
if (retval != 0) {
printk(KERN_ERR "Cannot assign IRQ number to TITAN GE \n");
return -1;
} else {
netdev->irq = 6;
printk(KERN_INFO "Assigned IRQ %d to port %d\n",
netdev->irq, port_num);
}
#else //CONFIG_PMC_SEQUOIA
if (port_num == 2)
retval = request_irq(7, titan_ge_int_handler,
SA_SHIRQ | SA_SAMPLE_RANDOM , netdev->name, netdev);
else
retval = request_irq(TITAN_ETH_PORT_IRQ - port_num,
titan_ge_int_handler, SA_SHIRQ | SA_SAMPLE_RANDOM ,
netdev->name, netdev);
if (retval != 0) {
printk(KERN_ERR "Cannot assign IRQ number to TITAN GE \n");
return -1;
} else {
if (port_num == 2)
netdev->irq = 7;
else
netdev->irq = TITAN_ETH_PORT_IRQ - port_num;
printk(KERN_INFO "Assigned IRQ %d to port %d\n",
netdev->irq, port_num);
}
#endif //CONFIG_PMC_SEQUOIA
spin_lock_irq(&(titan_ge_eth->lock));
if (titan_ge_eth_open(netdev) != TITAN_OK) {
printk("%s: Error opening interface \n", netdev->name);
spin_unlock_irq(&(titan_ge_eth->lock));
free_irq(netdev->irq, netdev);
return -EBUSY;
}
SET_MODULE_OWNER(netdev);
spin_unlock_irq(&(titan_ge_eth->lock));
return 0;
}
/*
* Return the Rx buffer back to the Rx ring
*/
static int titan_ge_rx_return_buff(titan_ge_port_info * titan_ge_port,
struct sk_buff *skb)
{
int rx_used_desc;
volatile titan_ge_rx_desc *rx_desc;
rx_used_desc = titan_ge_port->rx_used_desc_q;
rx_desc = &(titan_ge_port->rx_desc_area[rx_used_desc]);
#ifdef TITAN_GE_JUMBO_FRAMES
rx_desc->buffer_addr =
pci_map_single(0, skb->data, TITAN_GE_JUMBO_BUFSIZE - 2,
PCI_DMA_FROMDEVICE);
#else
rx_desc->buffer_addr =
pci_map_single(0, skb->data, TITAN_GE_STD_BUFSIZE - 2,
PCI_DMA_FROMDEVICE);
#endif
titan_ge_port->rx_skb[rx_used_desc] = skb;
rx_desc->cmd_sts = TITAN_GE_RX_BUFFER_OWNED;
titan_ge_port->rx_used_desc_q =
(rx_used_desc + 1) % TITAN_GE_RX_QUEUE;
return TITAN_OK;
}
/*
* Allocate the SKBs for the Rx ring. Also used
* for refilling the queue
*/
static int titan_ge_rx_task(struct net_device *netdev,
titan_ge_port_info *titan_ge_eth)
{
struct sk_buff *skb;
int count = 0;
while (titan_ge_eth->rx_ring_skbs < titan_ge_eth->rx_ring_size) {
/* First try to get the skb from the recycler */
#ifdef CONFIG_NET_SKB_RECYCLING
skb = get_recycle(titan_ge_eth);
if (!skb) {
#endif
#ifdef TITAN_GE_JUMBO_FRAMES
skb = titan_ge_alloc_skb(TITAN_GE_JUMBO_BUFSIZE, GFP_ATOMIC);
#else
skb = titan_ge_alloc_skb(TITAN_GE_STD_BUFSIZE, GFP_ATOMIC);
#endif
if (!skb) {
/* OOM, set the flag */
printk("OOM \n");
oom_flag = 1;
break;
}
#ifdef CONFIG_NET_SKB_RECYCLING
skb->cpu = smp_processor_id();
atomic_inc(&titan_ge_rc[smp_processor_id()].cnt);
}
skb->skb_recycle = titan_ge_recycle;
#endif
count++;
skb->dev = netdev;
titan_ge_eth->rx_ring_skbs++;
if (titan_ge_rx_return_buff(titan_ge_eth, skb) !=
TITAN_OK) {
printk(KERN_ERR "%s: Error allocating RX Ring\n",
netdev->name);
break;
}
}
return count;
}
/*
* Actual init of the Tital GE port. There is one register for
* the channel configuration
*/
static void titan_port_init(struct net_device *netdev,
titan_ge_port_info * titan_ge_eth)
{
unsigned long reg_data;
int port_num;
#ifdef CONFIG_PMC_SEQUOIA
for (port_num = 0; port_num < 2; port_num++) {
titan_ge_port_reset(port_num);
/* First reset the TMAC */
reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 9));
reg_data |= 0x80000000;
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 9)), reg_data);
udelay(30);
reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 9));
reg_data &= ~(0xc0000000);
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 9)), reg_data);
/* Now reset the RMAC */
reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 9));
reg_data |= 0x0010000;
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 9)), reg_data);
udelay(30);
reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 9));
reg_data &= ~(0x00180000);
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 9)), reg_data);
}
#else //CONFIG_PMC_SEQUOIA
for (port_num = 0; port_num < 3; port_num++) {
titan_ge_port_reset(port_num);
/* First reset the TMAC */
reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 8));
reg_data |= 0x80000000;
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)), reg_data);
udelay(30);
reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 8));
reg_data &= ~(0xc0000000);
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)), reg_data);
/* Now reset the RMAC */
reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 8));
reg_data |= 0x00080000;
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)), reg_data);
udelay(30);
reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 8));
reg_data &= ~(0x000c0000);
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)), reg_data);
}
#endif
}
/*
* Start the port. All the hardware specific configuration
* for the XDMA, Tx FIFO, Rx FIFO, TMAC, RMAC, TRTG and AFX
* go here
*/
static int titan_ge_port_start(struct net_device *netdev,
titan_ge_port_info * titan_port)
{
volatile unsigned long reg_data, reg_data1, reg_data_1;
int count = 0;
int port_num = titan_port->port_num;
if (config_done == 0) {
#ifdef CONFIG_PMC_SEQUOIA
reg_data = TITAN_GE_READ(0x0008);
reg_data |= 0x100;
TITAN_GE_WRITE(0x0008, reg_data);
reg_data &= ~(0x100);
TITAN_GE_WRITE(0x0008, reg_data);
/* Turn on GMII/MII mode and turn off TBI mode */
reg_data = TITAN_GE_READ(TITAN_GE_CPIF2_GU0);
reg_data &= ~(0x0000000C);
TITAN_GE_WRITE(TITAN_GE_CPIF2_GU0, reg_data);
#else
reg_data = TITAN_GE_READ(0x0004);
reg_data |= 0x100;
TITAN_GE_WRITE(0x0004, reg_data);
reg_data &= ~(0x100);
TITAN_GE_WRITE(0x0004, reg_data);
/* Turn on GMII/MII mode and turn off TBI mode */
reg_data = TITAN_GE_READ(TITAN_GE_TSB_CTRL_1);
reg_data |= 0x00000700;
reg_data &= ~(0x00800000); /* Fencing */
#ifdef TITAN_RX_NAPI
TITAN_GE_WRITE(0x000c, 0x00001100);
#else
TITAN_GE_WRITE(0x000c, 0x00000100); /* No WCIMODE */
#endif
TITAN_GE_WRITE(TITAN_GE_TSB_CTRL_1, reg_data);
/* Set the CPU Resource Limit register */
TITAN_GE_WRITE(0x00f8, 0x8);
/* Be conservative when using the BIU buffers */
TITAN_GE_WRITE(0x0068, 0x4);
#endif // CONFIG_PMC_SEQUOIA
}
#ifdef TITAN_RX_NAPI
titan_port->tx_threshold = 0;
titan_port->rx_threshold = 0;
#endif
#ifdef CONFIG_PMC_SEQUOIA
/* We need to write the descriptors for Tx and Rx */
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_TX_DESC + (port_num << 9)),
(unsigned long) titan_port->tx_dma);
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_RX_DESC + (port_num << 9)),
(unsigned long) titan_port->rx_dma);
#else //CONFIG_PMC_SEQUOIA
/* We need to write the descriptors for Tx and Rx */
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_TX_DESC + (port_num << 8)),
(unsigned long) titan_port->tx_dma);
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_RX_DESC + (port_num << 8)),
(unsigned long) titan_port->rx_dma);
#endif //CONFIG_PMC_SEQUOIA
if (config_done == 0) {
/* Step 1: XDMA config */
reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG);
reg_data &= ~(0x80000000); /* clear reset */
reg_data |= 0x1 << 29; /* sparse tx descriptor spacing */
reg_data |= 0x1 << 28; /* sparse rx descriptor spacing */
#ifdef CONFIG_PMC_SEQUOIA
/* No support for coherency. Has to be cleared */
reg_data &= ~(0x1E00000);
#else //CONFIG_PMC_SEUQOIA
reg_data |= (0x1 << 23) | (0x1 << 24); /* Descriptor Rd and Wr Coherency */
reg_data |= (0x1 << 21) | (0x1 << 22); /* Data Rd and Wr Coherency */
#endif //CONFIG_PMC_SEQUOIA
TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data);
}
#ifdef CONFIG_PMC_SEQUOIA
/* IR register for the XDMA */
reg_data = TITAN_GE_READ(TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 9)
);
reg_data |= 0xF006C000; /* No Rx_OOD */
TITAN_GE_WRITE((TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 9)), reg_data);
#else // CONFIG_PMC_SEQUOIA
/* IR register for the XDMA */
reg_data = TITAN_GE_READ(TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8));
reg_data |= 0x80068000; /* No Rx_OOD */
TITAN_GE_WRITE((TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)), reg_data);
#endif // CONFIG_PMC_SEQUOIA
#ifdef CONFIG_PMC_SEQUOIA
/* Start the Tx and Rx XDMA controller */
reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 9));
reg_data &= 0x5fffffff; /* Clear tx reset */
reg_data &= 0xffebffff; /* Clear rx reset */
#ifdef TITAN_GE_JUMBO_FRAMES
reg_data |= 0xa0;
reg_data &= ~(0x38070000);
#else
reg_data |= 0x40;
reg_data &= ~(0x38070000);
#endif
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 9)), reg_data);
/* Rx desc count */
count = titan_ge_rx_task(netdev, titan_port);
TITAN_GE_WRITE((0x3048 + (port_num << 9)), count);
count = TITAN_GE_READ(0x3048 + (port_num << 9));
#else // CONFIG_PMC_SEQUOIA
/* Start the Tx and Rx XDMA controller */
reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 8));
reg_data &= 0x4fffffff; /* Clear tx reset */
reg_data &= 0xfff4ffff; /* Clear rx reset */
#ifdef TITAN_GE_JUMBO_FRAMES
reg_data |= 0xa0 | 0x30030000;
#else
reg_data |= 0x40 | 0x30030000;
#endif
#ifndef CONFIG_SMP
if (port_num == 1) {
reg_data &= ~(0x10);
reg_data |= 0x0f; /* All of the packet */
}
#endif
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)), reg_data);
/* Rx desc count */
count = titan_ge_rx_task(netdev, titan_port);
TITAN_GE_WRITE((0x5048 + (port_num << 8)), count);
count = TITAN_GE_READ(0x5048 + (port_num << 8));
#endif // CONFIG_PMC_SEQUOIA
udelay(30);
/*
* Step 2: Configure the SDQPF, i.e. FIFO
*/
if (config_done == 0) {
reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL);
reg_data = 0x1;
TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
reg_data &= ~(0x1);
TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL);
TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL);
reg_data = 0x1;
TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
reg_data &= ~(0x1);
TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL);
TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
}
#ifdef CONFIG_PMC_SEQUOIA
/*
* Enable RX FIFO 0 and 8
*/
if (port_num == 0) {
reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_0);
reg_data |= 0x100000;
reg_data |= (0xff << 10);
TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data);
/*
* BAV2,BAV and DAV settings for the Rx FIFO
*/
reg_data1 = TITAN_GE_READ(0x2844);
reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
TITAN_GE_WRITE(0x2844, reg_data1);
reg_data &= ~(0x00100000);
reg_data |= 0x200000;
TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data);
reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_0);
reg_data |= 0x100000;
TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
reg_data |= (0xff << 10);
TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
/*
* BAV2, BAV and DAV settings for the Tx FIFO
*/
reg_data1 = TITAN_GE_READ(0x2910);
reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
TITAN_GE_WRITE(0x2910, reg_data1);
reg_data &= ~(0x00100000);
reg_data |= 0x200000;
TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
}
if (port_num == 1) {
reg_data = TITAN_GE_READ(0x28A0);
reg_data |= 0x100000;
reg_data |= (0xff << 10) | (0xff + 1);
TITAN_GE_WRITE(0x28A0, reg_data);
/*
* BAV2,BAV and DAV settings for the Rx FIFO
*/
reg_data1 = TITAN_GE_READ(0x28A4);
reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
TITAN_GE_WRITE(0x28A4, reg_data1);
reg_data &= ~(0x00100000);
reg_data |= 0x200000;
TITAN_GE_WRITE(0x28A0, reg_data);
reg_data = TITAN_GE_READ(0x2918);
reg_data |= 0x100000;
TITAN_GE_WRITE(0x2918, reg_data);
reg_data |= (0xff << 10) | (0xff + 1);
TITAN_GE_WRITE(0x2918, reg_data);
/*
* BAV2, BAV and DAV settings for the Tx FIFO
*/
reg_data1 = TITAN_GE_READ(0x291C);
reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
TITAN_GE_WRITE(0x291C, reg_data1);
reg_data &= ~(0x00100000);
reg_data |= 0x200000;
TITAN_GE_WRITE(0x2918, reg_data);
}
#else //CONFIG_PMC_SEQUOIA
/*
* Enable RX FIFO 0, 4 and 8
*/
if (port_num == 0) {
reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_0);
reg_data |= 0x100000;
reg_data |= (0xff << 10);
TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data);
/*
* BAV2,BAV and DAV settings for the Rx FIFO
*/
reg_data1 = TITAN_GE_READ(0x4844);
reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
TITAN_GE_WRITE(0x4844, reg_data1);
reg_data &= ~(0x00100000);
reg_data |= 0x200000;
TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data);
reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_0);
reg_data |= 0x100000;
TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
reg_data |= (0xff << 10);
TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
/*
* BAV2, BAV and DAV settings for the Tx FIFO
*/
reg_data1 = TITAN_GE_READ(0x4944);
reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
TITAN_GE_WRITE(0x4944, reg_data1);
reg_data &= ~(0x00100000);
reg_data |= 0x200000;
TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
}
if (port_num == 1) {
reg_data = TITAN_GE_READ(0x4870);
reg_data |= 0x100000;
reg_data |= (0xff << 10) | (0xff + 1);
TITAN_GE_WRITE(0x4870, reg_data);
/*
* BAV2,BAV and DAV settings for the Rx FIFO
*/
reg_data1 = TITAN_GE_READ(0x4874);
reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
TITAN_GE_WRITE(0x4874, reg_data1);
reg_data &= ~(0x00100000);
reg_data |= 0x200000;
TITAN_GE_WRITE(0x4870, reg_data);
reg_data = TITAN_GE_READ(0x494c);
reg_data |= 0x100000;
TITAN_GE_WRITE(0x494c, reg_data);
reg_data |= (0xff << 10) | (0xff + 1);
TITAN_GE_WRITE(0x494c, reg_data);
/*
* BAV2, BAV and DAV settings for the Tx FIFO
*/
reg_data1 = TITAN_GE_READ(0x4950);
reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
TITAN_GE_WRITE(0x4950, reg_data1);
reg_data &= ~(0x00100000);
reg_data |= 0x200000;
TITAN_GE_WRITE(0x494c, reg_data);
}
if (port_num == 2) {
reg_data = TITAN_GE_READ(0x48a0);
reg_data |= 0x100000;
reg_data |= (0xff << 10) | (2*(0xff + 1));
TITAN_GE_WRITE(0x48a0, reg_data);
/*
* BAV2,BAV and DAV settings for the Rx FIFO
*/
reg_data1 = TITAN_GE_READ(0x48a4);
reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
TITAN_GE_WRITE(0x48a4, reg_data1);
reg_data &= ~(0x00100000);
reg_data |= 0x200000;
TITAN_GE_WRITE(0x48a0, reg_data);
reg_data = TITAN_GE_READ(0x4958);
reg_data |= 0x100000;
TITAN_GE_WRITE(0x4958, reg_data);
reg_data |= (0xff << 10) | (2*(0xff + 1));
TITAN_GE_WRITE(0x4958, reg_data);
/*
* BAV2, BAV and DAV settings for the Tx FIFO
*/
reg_data1 = TITAN_GE_READ(0x495c);
reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
TITAN_GE_WRITE(0x495c, reg_data1);
reg_data &= ~(0x00100000);
reg_data |= 0x200000;
TITAN_GE_WRITE(0x4958, reg_data);
}
#endif //CONFIG_PMC_SEQUOIA
/*
* Step 3: TRTG block enable
*/
reg_data = TITAN_GE_READ(TITAN_GE_TRTG_CONFIG + (port_num << 12));
#ifdef CONFIG_PMC_SEQUOIA
reg_data_1 = TITAN_GE_READ(0x103c + (port_num << 12));
reg_data_1 |= 0x02020202;
TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
TITAN_GE_WRITE((0x1040 + (port_num << 12)), reg_data_1);
mdelay(5);
#else //CONFIG_PMC_SEQUOIA
#ifdef TITAN_GE_12
/*
* This is the 1.2 revision of the chip. It has fix for the
* IP header alignment. Now, the IP header begins at an
* aligned address and this wont need an extra copy in the
* driver. This performance drawback existed in the previous
* versions of the silicon
*/
reg_data_1 = TITAN_GE_READ(0x103c + (port_num << 12));
reg_data_1 |= 0x40000000;
TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
reg_data_1 |= 0x04000000;
TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
mdelay(5);
reg_data_1 &= ~(0x04000000);
TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
mdelay(5);
#endif
#endif //CONFIG_PMC_SEQUOIA
reg_data |= 0x0001;
TITAN_GE_WRITE((TITAN_GE_TRTG_CONFIG + (port_num << 12)), reg_data);
/*
* Step 4: Start the Tx activity
*/
TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_2 + (port_num << 12)), 0xe197);
#ifdef TITAN_GE_JUMBO_FRAMES
TITAN_GE_WRITE((0x1258 + (port_num << 12)), 0x4000);
#endif
reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12));
reg_data |= 0x0001; /* Enable TMAC */
reg_data |= 0x6c70; /* PAUSE also set */
TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)), reg_data);
udelay(30);
/* Destination Address drop bit */
reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_2 + (port_num << 12));
#ifdef CONFIG_PMC_SEQUOIA
reg_data |= 0x108; /* DA_DROP bit and pause */
#else
reg_data |= 0x218; /* DA_DROP bit and pause */
#endif
TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)), reg_data);
TITAN_GE_WRITE((0x1218 + (port_num << 12)), 0x3);
#ifdef TITAN_GE_JUMBO_FRAMES
TITAN_GE_WRITE((0x1208 + (port_num << 12)), 0x4000);
#endif
/* Start the Rx activity */
reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12));
reg_data |= 0x0001; /* RMAC Enable */
#ifdef CONFIG_PMC_SEQUOIA
/* CRC Check enable */
/* Min Frame check enable */
/* Max Frame check enable */
reg_data |= 0x4CAA;
#else
reg_data |= 0x0010; /* CRC Check enable */
reg_data |= 0x0040; /* Min Frame check enable */
reg_data |= 0x4400; /* Max Frame check enable */
#endif //CONFIG_PMC_SEQUOIA
TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data);
udelay(30);
/*
* Enable the Interrupts for Tx and Rx
*/
reg_data1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
if (port_num == 0) {
reg_data1 |= 0x3;
}
#ifdef CONFIG_PMC_SEQUOIA
if (port_num == 1) {
reg_data1 |= 0x30000;
}
#else //CONFIG_PMC_SEQUOIA
if (port_num == 1) {
reg_data1 |= 0x300;
}
#endif //CONFIG_PMC_SEQUOIA
if (port_num == 2) {
reg_data1 |= 0x30000;
}
TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data1);
if (config_done == 0) {
#ifndef CONFIG_PMC_SEQUOIA
TITAN_GE_WRITE(0x0038, 0x00303);
TITAN_GE_WRITE(0x003c, 0x00300);
#endif
#ifdef CONFIG_PMC_SEQUOIA
// XD_OOD_INTSMSG = 0x61, XD_INTSMSG = 0x62,
// XD_RX_INTSMSG = XD_TX_INTSMSG = 0x60
TITAN_GE_WRITE(0x0060, RM9150_GCIC_INTMSG >> 4);
reg_data = 0x61626060;
TITAN_GE_WRITE(0x0044, reg_data);
reg_data = TITAN_GE_READ(0x0080);
reg_data |= 0x1;
TITAN_GE_WRITE(0x0080, reg_data);
#else
#ifdef TITAN_GE_12
TITAN_GE_WRITE(0x0024, 0x04844424);
#else
TITAN_GE_WRITE(0x0024, 0x04000024); /* IRQ vector */
#endif
TITAN_GE_WRITE(0x0020, 0x000fb000); /* INTMSG base */
#endif // CONFIG_PMC_SEQUOIA
}
/* Priority */
reg_data = TITAN_GE_READ(0x1038 + (port_num << 12));
reg_data &= ~(0x00f00000);
TITAN_GE_WRITE((0x1038 + (port_num << 12)), reg_data);
/* Step 5: GMII config */
titan_ge_gmii_config(port_num);
if (config_done == 0) {
#ifndef CONFIG_PMC_SEQUOIA
TITAN_GE_WRITE(0x1a80, 0);
#endif
config_done = 1;
}
return TITAN_OK;
}
/*
* Function to queue the packet for the Ethernet device
*/
static void titan_ge_tx_queue(titan_ge_port_info * titan_ge_eth,
struct sk_buff * skb)
{
volatile titan_ge_tx_desc *tx_curr;
int port_num = titan_ge_eth->port_num;
unsigned int curr_desc =
titan_ge_eth->tx_curr_desc_q;
tx_curr = &(titan_ge_eth->tx_desc_area[curr_desc]);
tx_curr->buffer_addr =
pci_map_single(0, skb->data, skb->len - skb->data_len,
PCI_DMA_TODEVICE);
titan_ge_eth->tx_skb[curr_desc] = (struct sk_buff *) skb;
tx_curr->buffer_len = skb->len - skb->data_len;
/* Last descriptor enables interrupt and changes ownership */
tx_curr->cmd_sts = 0x1 | (1 << 15) | (1 << 5);
#ifdef CONFIG_PMC_SEQUOIA
/* Kick the XDMA to start the transfer from memory to the FIFO */
TITAN_GE_WRITE((0x3044 + (port_num << 9)), 0x1);
#else
/* Kick the XDMA to start the transfer from memory to the FIFO */
TITAN_GE_WRITE((0x5044 + (port_num << 8)), 0x1);
#endif //CONFIG_PMC_SEQUOIA
/* Current descriptor updated */
titan_ge_eth->tx_curr_desc_q = (curr_desc + 1) % TITAN_GE_TX_QUEUE;
/* Prefetch the next descriptor */
#ifdef CONFIG_CPU_HAS_PREFETCH
if (port_num == 1)
rm9000_prefetch(&(titan_ge_eth->tx_desc_area[
titan_ge_eth->tx_curr_desc_q]));
#endif
}
/*
* Actually does the open of the Ethernet device
*/
static int titan_ge_eth_open(struct net_device *netdev)
{
titan_ge_port_info *titan_ge_eth;
unsigned int port_num, size, phy_reg;
unsigned long reg_data;
int err = 0;
titan_ge_eth = netdev->priv;
port_num = titan_ge_eth->port_num;
/* Stop the Rx activity */
reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 +
(port_num << 12));
reg_data &= ~(0x00000001);
TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 +
(port_num << 12)), reg_data);
#ifdef CONFIG_PMC_SEQUOIA
/* Clear the port interrupts */
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT +
(port_num << 9)), 0x0);
#else //CONFIG_PMC_SEQUOIA
/* Clear the port interrupts */
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT +
(port_num << 8)), 0x0);
#endif //CONFIG_PMC_SEQUOIA
if (config_done == 0) {
TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0);
#ifndef CONFIG_PMC_SEQUOIA
TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_B, 0);
#endif
}
/* Set the MAC Address */
memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6);
if (config_done == 0)
titan_port_init(netdev, titan_ge_eth);
titan_ge_update_afx(titan_ge_eth);
/* Allocate the Tx ring now */
titan_ge_eth->tx_ring_skbs = 0;
titan_ge_eth->tx_ring_size = TITAN_GE_TX_QUEUE;
size = titan_ge_eth->tx_ring_size * sizeof(titan_ge_tx_desc);
/* Allocate space in the SRAM for the descriptors */
if (port_num == 1) {
titan_ge_eth->tx_desc_area =
(titan_ge_tx_desc *) (TITAN_GE_SRAM_BASE_VIRTUAL);
titan_ge_eth->tx_dma = (TITAN_GE_SRAM_BASE_PHYSICAL);
} else {
#ifdef CONFIG_PMC_SEQUOIA
titan_ge_eth->tx_desc_area =
(titan_ge_tx_desc *) (TITAN_GE_SRAM_BASE_VIRTUAL + 0x2000);
titan_ge_eth->tx_dma = (TITAN_GE_SRAM_BASE_PHYSICAL + 0x2000);
#else
titan_ge_eth->tx_desc_area =
(titan_ge_tx_desc *) pci_alloc_consistent(NULL, size,
&titan_ge_eth->tx_dma);
#endif
}
if (!titan_ge_eth->tx_desc_area) {
printk(KERN_ERR
"%s: Cannot allocate Tx Ring (size %d bytes)\n",
netdev->name, size);
return -ENOMEM;
}
memset((void *) titan_ge_eth->tx_desc_area, 0,
titan_ge_eth->tx_desc_area_size);
/* Now initialize the Tx descriptor ring */
titan_ge_init_tx_desc_ring(titan_ge_eth,
titan_ge_eth->tx_ring_size,
(unsigned long) titan_ge_eth->
tx_desc_area,
(unsigned long) titan_ge_eth->tx_dma);
/* Allocate the Rx ring now */
titan_ge_eth->rx_ring_size = TITAN_GE_RX_QUEUE;
titan_ge_eth->rx_ring_skbs = 0;
size = titan_ge_eth->rx_ring_size * sizeof(titan_ge_rx_desc);
if (port_num == 1) {
titan_ge_eth->rx_desc_area =
(titan_ge_rx_desc *)(TITAN_GE_SRAM_BASE_VIRTUAL + 0x1000);
titan_ge_eth->rx_dma = (TITAN_GE_SRAM_BASE_PHYSICAL + 0x1000);
}
else {
#ifdef CONFIG_PMC_SEQUOIA
titan_ge_eth->rx_desc_area =
(titan_ge_rx_desc *)(TITAN_GE_SRAM_BASE_VIRTUAL + 0x3000);
titan_ge_eth->rx_dma = (TITAN_GE_SRAM_BASE_PHYSICAL + 0x3000);
#else
titan_ge_eth->rx_desc_area =
(titan_ge_rx_desc *) pci_alloc_consistent(NULL, size,
&titan_ge_eth->rx_dma);
#endif
}
if (!titan_ge_eth->rx_desc_area) {
printk(KERN_ERR
"%s: Cannot allocate Rx Ring (size %d bytes)\n",
netdev->name, size);
printk(KERN_ERR
"%s: Freeing previously allocated TX queues...",
netdev->name);
pci_free_consistent(0, titan_ge_eth->tx_desc_area_size,
(void *) titan_ge_eth->tx_desc_area,
titan_ge_eth->tx_dma);
return -ENOMEM;
}
memset((void *) titan_ge_eth->rx_desc_area, 0,
titan_ge_eth->tx_desc_area_size);
/* Now initialize the Rx ring */
#ifdef TITAN_GE_JUMBO_FRAMES
if ((titan_ge_init_rx_desc_ring
(titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_JUMBO_BUFSIZE,
(unsigned long) titan_ge_eth->rx_desc_area, 0,
(unsigned long) titan_ge_eth->rx_dma)) == 0)
#else
if ((titan_ge_init_rx_desc_ring
(titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_STD_BUFSIZE,
(unsigned long) titan_ge_eth->rx_desc_area, 0,
(unsigned long) titan_ge_eth->rx_dma)) == 0)
#endif
panic("%s: Error initializing RX Ring\n", netdev->name);
/* Fill the Rx ring with the SKBs */
titan_ge_port_start(netdev, titan_ge_eth);
/*
* Check if Interrupt Coalscing needs to be turned on. The
* values specified in the register is multiplied by
* (8 x 64 nanoseconds) to determine when an interrupt should
* be sent to the CPU.
*/
#ifndef TITAN_RX_NAPI
/*
* If NAPI is turned on, we disable Rx interrupts
* completely. So, we dont need coalescing then. Tx side
* coalescing set to very high value. Maybe, disable
* Tx side interrupts completely
*/
if (TITAN_GE_RX_COAL) {
titan_ge_eth->rx_int_coal =
titan_ge_rx_coal(TITAN_GE_RX_COAL, port_num);
}
#endif
if (TITAN_GE_TX_COAL) {
titan_ge_eth->tx_int_coal =
titan_ge_tx_coal(TITAN_GE_TX_COAL, port_num);
}
err =
titan_ge_mdio_read(port_num,
TITAN_GE_MDIO_PHY_STATUS, &phy_reg);
if (err == TITAN_GE_MDIO_ERROR) {
printk(KERN_ERR
"Could not read PHY control register 0x11 \n");
return TITAN_ERROR;
}
if (!(phy_reg & 0x0400)) {
netif_carrier_off(netdev);
netif_stop_queue(netdev);
return TITAN_ERROR;
} else {
netif_carrier_on(netdev);
netif_start_queue(netdev);
}
return TITAN_OK;
}
/*
* Queue the packet for Tx. Currently no support for zero copy,
* checksum offload and Scatter Gather. The chip does support
* Scatter Gather only. But, that wont help here since zero copy
* requires support for Tx checksumming also.
*/
int titan_ge_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{
titan_ge_port_info *titan_ge_eth;
unsigned long flags;
#ifdef EXTRA_STATS
struct net_device_stats *stats;
#endif
titan_ge_eth = netdev->priv;
#ifdef EXTRA_STATS
stats = &titan_ge_eth->stats;
#endif
#ifdef CONFIG_SMP
spin_lock_irqsave(&titan_ge_eth->lock, flags);
#else
local_irq_save(flags);
#endif
if ((TITAN_GE_TX_QUEUE - titan_ge_eth->tx_ring_skbs) <=
(skb_shinfo(skb)->nr_frags + 1)) {
netif_stop_queue(netdev);
#ifdef CONFIG_SMP
spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
#else
local_irq_restore(flags);
#endif
printk(KERN_ERR "Tx OOD \n");
return 1;
}
titan_ge_tx_queue(titan_ge_eth, skb);
titan_ge_eth->tx_ring_skbs++;
if (TITAN_GE_TX_QUEUE <= (titan_ge_eth->tx_ring_skbs + 4)) {
#ifdef CONFIG_SMP
spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
#else
local_irq_restore(flags);
#endif
titan_ge_free_tx_queue(titan_ge_eth);
#ifdef CONFIG_SMP
spin_lock_irqsave(&titan_ge_eth->lock, flags);
#else
local_irq_save(flags);
#endif
}
#ifdef EXTRA_STATS
stats->tx_bytes += skb->len;
stats->tx_packets++;
#endif
#ifdef CONFIG_SMP
spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
#else
local_irq_restore(flags);
#endif
netdev->trans_start = jiffies;
return 0;
}
#ifdef CONFIG_NET_FASTROUTE
/*
* Fast forward function for the fast routing. Helps
* in IP forwarding. No semi fast forward since we
* have to do that extra copy on the Rx for the IP
* header alignment
*/
static int titan_ge_fast_forward(struct net_device *dev,
struct sk_buff *skb, int len)
{
titan_ge_port_info *titan_ge_eth =
(titan_ge_port_info *)dev->priv;
struct ethhdr *eth = (void*)skb->data;
if (eth->h_proto == __constant_htons(ETH_P_IP)) {
struct rtable *rt;
struct iphdr *iph;
unsigned h;
iph = (struct iphdr*)(skb->data + ETH_HLEN);
h=(*(u8*)&iph->daddr^*(u8*)&iph->saddr)&NETDEV_FASTROUTE_HMASK;
rt = (struct rtable*)(dev->fastpath[h]);
if (rt &&
((u16*)&iph->daddr)[0] == ((u16*)&rt->key.dst)[0] &&
((u16*)&iph->daddr)[1] == ((u16*)&rt->key.dst)[1] &&
((u16*)&iph->saddr)[0] == ((u16*)&rt->key.src)[0] &&
((u16*)&iph->saddr)[1] == ((u16*)&rt->key.src)[1] &&
rt->u.dst.obsolete == 0) {
struct net_device *odev = rt->u.dst.dev;
if (*(u8*)iph != 0x45 ||
(eth->h_dest[0]&1) ||
!neigh_is_valid(rt->u.dst.neighbour) ||
iph->ttl <= 1) {
return 1;
}
ip_decrease_ttl(iph);
skb_put(skb, len);
memcpy(eth->h_source, odev->dev_addr, 6);
memcpy(eth->h_dest, rt->u.dst.neighbour->ha, 6);
skb->dev = odev;
skb->pkt_type = PACKET_FASTROUTE;
if (netif_running(odev) &&
(spin_trylock(&odev->xmit_lock))) {
if(odev->xmit_lock_owner != 0) {
odev->xmit_lock_owner=0;
}
if (odev->hard_start_xmit(skb,odev) == 0) {
odev->xmit_lock_owner=-1;
spin_unlock(&odev->xmit_lock);
return 0;
}
}
skb->nh.raw = skb->data + ETH_HLEN;
skb->protocol = __constant_htons(ETH_P_IP);
return 1;
}
}
return 1;
}
#endif
/*
* Actually does the Rx. Rx side checksumming supported.
*/
static int titan_ge_rx(struct net_device *netdev, int port_num,
titan_ge_port_info * titan_ge_port,
titan_ge_packet * packet)
{
int rx_curr_desc, rx_used_desc;
volatile titan_ge_rx_desc *rx_desc;
rx_curr_desc = titan_ge_port->rx_curr_desc_q;
rx_used_desc = titan_ge_port->rx_used_desc_q;
if (((rx_curr_desc + 1) % TITAN_GE_RX_QUEUE) == rx_used_desc)
return TITAN_ERROR;
rx_desc = &(titan_ge_port->rx_desc_area[rx_curr_desc]);
if (rx_desc->cmd_sts & TITAN_GE_RX_BUFFER_OWNED)
return TITAN_ERROR;
packet->skb = titan_ge_port->rx_skb[rx_curr_desc];
packet->len = (rx_desc->cmd_sts & 0x7fff);
#ifdef TITAN_GE_JUMBO_FRAMES
pci_unmap_single(0, rx_desc->buffer_addr, TITAN_GE_JUMBO_BUFSIZE - 2,
PCI_DMA_FROMDEVICE);
#else
pci_unmap_single(0, rx_desc->buffer_addr, TITAN_GE_STD_BUFSIZE - 2,
PCI_DMA_FROMDEVICE);
#endif
/*
* At this point, we dont know if the checksumming
* actually helps relieve CPU. So, keep it for
* port 0 only
*/
if (port_num == 0)
packet->checksum = ntohs((rx_desc->buffer & 0xffff0000) >> 16);
titan_ge_port->rx_curr_desc_q =
(rx_curr_desc + 1) % TITAN_GE_RX_QUEUE;
/* Prefetch the next descriptor */
#ifdef CONFIG_CPU_HAS_PREFETCH
if (port_num == 1)
rm9000_prefetch(&(titan_ge_port->rx_desc_area[
titan_ge_port->rx_curr_desc_q + 1]));
#endif
return TITAN_OK;
}
/*
* Free the Tx queue of the used SKBs
*/
static int titan_ge_free_tx_queue(titan_ge_port_info *titan_ge_eth)
{
unsigned long flags;
/* Take the lock */
#ifdef CONFIG_SMP
spin_lock_irqsave(&(titan_ge_eth->lock), flags);
#else
local_irq_save(flags);
#endif
while (titan_ge_return_tx_desc(titan_ge_eth, titan_ge_eth->port_num) == 0)
if (titan_ge_eth->tx_ring_skbs > 0)
titan_ge_eth->tx_ring_skbs--;
#ifdef CONFIG_SMP
spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
#else
local_irq_restore(flags);
#endif
return TITAN_OK;
}
/*
* Do the slowpath route. This route is kicked off
* when the IP header is misaligned. Grrr ..
*/
static int titan_ge_slowpath(struct sk_buff *skb,
titan_ge_packet *packet,
struct net_device *netdev)
{
struct sk_buff *copy_skb;
copy_skb = dev_alloc_skb(packet->len + 2);
if (!copy_skb) {
dev_kfree_skb_any(packet->skb);
return -1;
}
copy_skb->dev = netdev;
skb_reserve(copy_skb, 2);
skb_put(copy_skb, packet->len);
memcpy(copy_skb->data, skb->data, packet->len);
/* Titan supports Rx checksum offload */
copy_skb->ip_summed = CHECKSUM_HW;
copy_skb->csum = packet->checksum;
copy_skb->protocol = eth_type_trans(copy_skb, netdev);
__kfree_skb(packet->skb);
#ifdef TITAN_RX_NAPI
netif_receive_skb(copy_skb);
#else
netif_rx(copy_skb);
#endif
return 0;
}
/*
* Threshold beyond which we do the cleaning of
* Tx queue and new allocation for the Rx
* queue
*/
#define TX_THRESHOLD 4
#define RX_THRESHOLD 10
/*
* Receive the packets and send it to the kernel.
*/
int titan_ge_receive_queue(struct net_device *netdev, unsigned int max)
{
titan_ge_port_info *titan_ge_eth;
unsigned int port_num;
titan_ge_packet packet;
#ifdef EXTRA_STATS
struct net_device_stats *stats;
#endif
struct sk_buff *skb;
unsigned long received_packets = 0;
unsigned int ack;
int i = 0;
titan_ge_eth = netdev->priv;
port_num = titan_ge_eth->port_num;
#ifdef EXTRA_STATS
stats = &titan_ge_eth->stats;
#endif
while ((--max)
&& (titan_ge_rx(netdev, port_num, titan_ge_eth, &packet) == TITAN_OK)) {
titan_ge_eth->rx_ring_skbs--;
#ifdef TITAN_RX_NAPI
if (--titan_ge_eth->rx_work_limit < 0)
break;
received_packets++;
#endif
#ifdef EXTRA_STATS
stats->rx_packets++;
stats->rx_bytes += packet.len;
#endif
/*
* Either support fast path or slow path. Decision
* making can really slow down the performance. The
* idea is to cut down the number of checks and improve
* the fastpath.
*/
#if (defined(CONFIG_NET_FASTROUTE) && !defined(TITAN_RX_NAPI))
if (port_num == 1) {
switch (titan_ge_fast_forward(netdev,
packet.skb, packet.len)) {
case 0:
goto gone;
case 1:
break;
}
}
#endif
skb = (struct sk_buff *) packet.skb;
/*
* This chip is wierd. Does not have a byte level offset
* to fix the IP header alignment issue. Now, do an extra
* copy only if the custom pattern is not present
*/
#ifdef TITAN_GE_12
skb_put(skb, packet.len - 2);
#else
skb_put(skb, packet.len);
#endif
#ifdef TITAN_GE_12
/*
* Increment data pointer by two since thats where
* the MAC starts
*/
skb_reserve(skb, 2);
#endif
#if (defined(TITAN_GE_10) || defined(TITAN_GE_11))
/*
* This is where Titan 1.0 and Titan 1.1 have a performance
* drawback. Since the IP header is misaligned, the driver has
* to perform an extra copy. However, we can send custom packets
* from Smartbits to avoid this copy. This __hack__ was used to
* determine the max IP forwarding throughput Titan 1.2 can deliver
* Check to make sure this is the custom packet
*/
if (*(skb->data) == 0x0) {
skb_reserve(skb, 2);
#endif
skb->protocol = eth_type_trans(skb, netdev);
netif_receive_skb(skb);
#if (defined(TITAN_GE_10) || defined(TITAN_GE_11))
}
else
if (titan_ge_slowpath(skb, &packet, netdev) < 0)
goto out_next;
#endif
gone:
#ifdef TITAN_RX_NAPI
if (titan_ge_eth->rx_threshold > RX_THRESHOLD) {
ack = titan_ge_rx_task(netdev, titan_ge_eth);
#ifdef CONFIG_PMC_SEQUOIA
TITAN_GE_WRITE((0x3048 + (port_num << 9)), ack);
#else
TITAN_GE_WRITE((0x5048 + (port_num << 8)), ack);
#endif
titan_ge_eth->rx_threshold = 0;
} else
titan_ge_eth->rx_threshold++;
#else
ack = titan_ge_rx_task(netdev, titan_ge_eth);
#ifdef CONFIG_PMC_SEQUOIA
TITAN_GE_WRITE((0x3048 + (port_num << 9)), ack);
#else
TITAN_GE_WRITE((0x5048 + (port_num << 8)), ack);
#endif
#endif
out_next:
#ifdef TITAN_RX_NAPI
if (titan_ge_eth->tx_threshold > TX_THRESHOLD) {
titan_ge_eth->tx_threshold = 0;
titan_ge_free_tx_queue(titan_ge_eth);
}
else
titan_ge_eth->tx_threshold++;
#endif
}
return received_packets;
}
#ifdef TITAN_RX_NAPI
/*
* Enable the Rx side interrupts
*/
static void titan_ge_enable_int(unsigned int port_num,
titan_ge_port_info *titan_ge_eth,
struct net_device *netdev)
{
unsigned long reg_data =
TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
if (port_num == 0)
reg_data |= 0x3;
#ifdef CONFIG_PMC_SEQUOIA
if (port_num == 1)
reg_data |= 0x30000;
#else
if (port_num == 1)
reg_data |= 0x300;
#endif
if (port_num == 2)
reg_data |= 0x30000;
/* Re-enable interrupts */
TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data);
}
/*
* Main function to handle the polling for Rx side NAPI.
* Receive interrupts have been disabled at this point.
* The poll schedules the transmit followed by receive.
*/
static int titan_ge_poll(struct net_device *netdev, int *budget)
{
titan_ge_port_info *titan_ge_eth = netdev->priv;
int port_num = titan_ge_eth->port_num;
int work_done = 0;
unsigned long flags, status;
titan_ge_eth->rx_work_limit = *budget;
if (titan_ge_eth->rx_work_limit > netdev->quota)
titan_ge_eth->rx_work_limit = netdev->quota;
if (port_num == 0) {
/* Do the transmit cleaning work here */
titan_ge_free_tx_queue(titan_ge_eth);
TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x3);
work_done += titan_ge_receive_queue(netdev, 0);
goto done;
}
do {
/* Do the transmit cleaning work here */
titan_ge_free_tx_queue(titan_ge_eth);
/* Ack the Rx interrupts */
#ifdef CONFIG_PMC_SEQUOIA
if (port_num == 1)
TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x30000);
#else
if (port_num == 1)
TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x300);
#endif
if (port_num == 2)
TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x30000);
work_done += titan_ge_receive_queue(netdev, 0);
/* Out of quota and there is work to be done */
if (titan_ge_eth->rx_work_limit < 0)
goto not_done;
/* Receive alloc_skb could lead to OOM */
if (oom_flag == 1) {
oom_flag = 0;
goto oom;
}
status = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A);
}
#ifdef CONFIG_PMC_SEQUOIA
while (status & 0x30000);
#else
while (status & 0x30300);
#endif
/* If we are here, then no more interrupts to process */
goto done;
not_done:
*budget -= work_done;
netdev->quota -= work_done;
return 1;
oom:
printk(KERN_ERR "OOM \n");
netif_rx_complete(netdev);
return 0;
done:
/*
* No more packets on the poll list. Turn the interrupts
* back on and we should be able to catch the new
* packets in the interrupt handler
*/
if (!work_done)
work_done = 1;
*budget -= work_done;
netdev->quota -= work_done;
#ifdef CONFIG_SMP
spin_lock_irqsave(&titan_ge_eth->lock, flags);
#else
local_irq_save(flags);
#endif
/* Remove us from the poll list */
netif_rx_complete(netdev);
/* Re-enable interrupts */
titan_ge_enable_int(port_num, titan_ge_eth, netdev);
#ifdef CONFIG_SMP
spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
#else
local_irq_restore(flags);
#endif
return 0;
}
#endif
/*
* Close the network device
*/
int titan_ge_stop(struct net_device *netdev)
{
titan_ge_port_info *titan_ge_eth;
unsigned int port_num;
titan_ge_eth = netdev->priv;
port_num = titan_ge_eth->port_num;
spin_lock_irq(&(titan_ge_eth->lock));
titan_ge_eth_stop(netdev);
free_irq(netdev->irq, netdev);
MOD_DEC_USE_COUNT;
#ifdef CONFIG_NET_SKB_RECYCLING
titan_ge_recycle_remove();
#endif
spin_unlock_irq(&titan_ge_eth->lock);
return TITAN_OK;
}
/*
* Free the Tx ring
*/
static void titan_ge_free_tx_rings(struct net_device *netdev)
{
titan_ge_port_info *titan_ge_eth;
unsigned int port_num, curr;
unsigned long reg_data;
volatile titan_ge_tx_desc *tx_curr;
titan_ge_eth = netdev->priv;
port_num = titan_ge_eth->port_num;
/* Stop the Tx DMA */
#ifdef CONFIG_PMC_SEQUOIA
reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG +
(port_num << 9));
#else
reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG +
(port_num << 8));
#endif
reg_data |= 0xc0000000;
#ifdef CONFIG_PMC_SEQUOIA
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG +
(port_num << 9)), reg_data);
#else
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG +
(port_num << 8)), reg_data);
#endif
/* Disable the TMAC */
reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 +
(port_num << 12));
reg_data &= ~(0x00000001);
TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 +
(port_num << 12)), reg_data);
/* Going in the order: disable Tx XDMA -> disable TMAC */
/* -> disable RMAC -> disable Rx XDMA. */
/* Wait till TMAC is brought down. */
reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 +
(port_num << 12));
while (reg_data & 0x8000) {
reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 +
(port_num << 12));
}
for (curr = 0;
(titan_ge_eth->tx_ring_skbs) && (curr < TITAN_GE_TX_QUEUE);
curr++) {
if (titan_ge_eth->tx_skb[curr]) {
tx_curr = &(titan_ge_eth->tx_desc_area[curr]);
pci_unmap_single(0, tx_curr->buffer_addr, tx_curr->buffer_len, PCI_DMA_TODEVICE);
dev_kfree_skb(titan_ge_eth->tx_skb[curr]);
titan_ge_eth->tx_ring_skbs--;
}
}
if (titan_ge_eth->tx_ring_skbs != 0)
printk
("%s: Error on Tx descriptor free - could not free %d"
" descriptors\n", netdev->name,
titan_ge_eth->tx_ring_skbs);
pci_free_consistent(0, titan_ge_eth->tx_desc_area_size,
(void *) titan_ge_eth->tx_desc_area,
titan_ge_eth->tx_dma);
}
/*
* Free the Rx ring
*/
static void titan_ge_free_rx_rings(struct net_device *netdev)
{
titan_ge_port_info *titan_ge_eth;
unsigned int port_num, curr;
unsigned long reg_data;
volatile titan_ge_rx_desc *rx_desc;
titan_ge_eth = netdev->priv;
port_num = titan_ge_eth->port_num;
/* Going in the order: disable Tx XDMA -> disable TMAC */
/* -> disable RMAC -> disable Rx XDMA. */
/* Disable the RMAC */
reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 +
(port_num << 12));
reg_data &= ~(0x00000001);
TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 +
(port_num << 12)), reg_data);
/* Wait till all packets received and RMAC brought down. */
reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 +
(port_num << 12));
while (reg_data & 0x8000) {
reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 +
(port_num << 12));
}
udelay(60);
#ifdef CONFIG_PMC_SEQUOIA
/* Stop the Rx DMA */
reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG +
(port_num << 9));
reg_data |= 0x00180000;
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG +
(port_num << 9)), reg_data);
#else
/* Stop the Rx DMA */
reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG +
(port_num << 8));
reg_data |= 0x000c0000;
TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG +
(port_num << 8)), reg_data);
#endif
for (curr = 0;
titan_ge_eth->rx_ring_skbs && (curr < TITAN_GE_RX_QUEUE);
curr++) {
if (titan_ge_eth->rx_skb[curr]) {
rx_desc = &(titan_ge_eth->rx_desc_area[curr]);
#ifdef TITAN_GE_JUMBO_FRAMES
pci_unmap_single(0, rx_desc->buffer_addr, TITAN_GE_JUMBO_BUFSIZE - 2,
PCI_DMA_FROMDEVICE);
#else
pci_unmap_single(0, rx_desc->buffer_addr, TITAN_GE_STD_BUFSIZE - 2,
PCI_DMA_FROMDEVICE);
#endif
/* The garbage collection code removes child */
/* nodes without removing parents causing Linux */
/* to crash. Either (i) don't call this at all */
/* - in this case, few Rx descriptors remain */
/* alive and would cause memory leak without */
/* any functional error; or, (ii) do it right */
/* so that Linux does not crash. */
/* If it is on a list, first remove the buffer */
/* from the list ... */
if (titan_ge_eth->rx_skb[curr]->list)
skb_unlink(titan_ge_eth->rx_skb[curr]);
/* And then remove it. */
titan_ge_eth->rx_ring_skbs--;
}
}
if (titan_ge_eth->rx_ring_skbs != 0)
printk(KERN_ERR
"%s: Error in freeing Rx Ring. %d skb's still"
" stuck in RX Ring - ignoring them\n", netdev->name,
titan_ge_eth->rx_ring_skbs);
pci_free_consistent(0, titan_ge_eth->rx_desc_area_size,
(void *) titan_ge_eth->rx_desc_area,
titan_ge_eth->rx_dma);
}
static void titan_ge_eth_disable_int(struct net_device *netdev)
{
titan_ge_port_info *titan_ge_eth = netdev->priv;
int port_num = titan_ge_eth->port_num;
int channel = port_num<<2;
unsigned int r;
#ifdef CONFIG_PMC_SEQUOIA
channel = channel << 1;
#endif
r = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
r &= ~(0x1<<(channel<<1));
TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, r);
}
/*
* Actually does the stop of the Ethernet device
*/
static int titan_ge_eth_stop(struct net_device *netdev)
{
titan_ge_port_info *titan_ge_eth;
unsigned int port_num;
titan_ge_eth = netdev->priv;
port_num = titan_ge_eth->port_num;
netif_stop_queue(netdev);
/* Going in the order: disable Tx XDMA -> disable TMAC */
/* -> disable RMAC -> disable Rx XDMA. */
titan_ge_free_tx_rings(netdev);
titan_ge_port_reset(titan_ge_eth->port_num);
titan_ge_free_rx_rings(netdev);
/* Disable the Tx and Rx Interrupts for the specified port */
titan_ge_eth_disable_int(netdev);
return TITAN_OK;
}
/*
* Update the MAC address. Note that we have to write the
* address in three station registers, 16 bits each. And this
* has to be done for TMAC and RMAC
*/
static void titan_ge_update_mac_address(struct net_device *netdev)
{
titan_ge_port_info *titan_ge_eth = netdev->priv;
unsigned int port_num = titan_ge_eth->port_num;
u8 p_addr[6];
memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6);
memcpy(p_addr, netdev->dev_addr, 6);
/* Update the Address Filtering Match tables */
titan_ge_update_afx(titan_ge_eth);
printk("Station MAC : %d %d %d %d %d %d \n",
p_addr[5], p_addr[4], p_addr[3],
p_addr[2], p_addr[1], p_addr[0]);
/* Set the MAC address here for TMAC and RMAC */
TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port_num << 12)),
((p_addr[5] << 8) | p_addr[4]));
TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port_num << 12)),
((p_addr[3] << 8) | p_addr[2]));
TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port_num << 12)),
((p_addr[1] << 8) | p_addr[0]));
TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port_num << 12)),
((p_addr[5] << 8) | p_addr[4]));
TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port_num << 12)),
((p_addr[3] << 8) | p_addr[2]));
TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port_num << 12)),
((p_addr[1] << 8) | p_addr[0]));
return;
}
/*
* Set the MAC address of the Ethernet device
*/
int titan_ge_set_mac_address(struct net_device *netdev, void *addr)
{
int i;
for (i = 0; i < 6; i++)
netdev->dev_addr[i] = ((unsigned char *) addr)[i + 2];
titan_ge_update_mac_address(netdev);
return 0;
}
/*
* Get the Ethernet device stats
*/
static struct net_device_stats *titan_ge_get_stats(struct net_device
*netdev)
{
titan_ge_port_info *titan_ge_eth;
unsigned int port_num;
titan_ge_eth = netdev->priv;
port_num = titan_ge_eth->port_num;
return &titan_ge_eth->stats;
}
/*
* Register the Titan GE with the kernel
*/
static int __init titan_ge_init_module(void)
{
unsigned long version, device;
printk(KERN_NOTICE
"PMC-Sierra TITAN 10/100/1000 Ethernet Driver \n");
device = TITAN_GE_READ(TITAN_GE_DEVICE_ID);
#ifdef CONFIG_PMC_SEQUOIA
version = (device & 0x0f000000) >> 16;
device &= 0x00ffffff;
#else
version = (device & 0x000f0000) >> 16;
device &= 0x0000ffff;
#endif
printk(KERN_NOTICE "Device Id : %x, Version : %x \n", device,
version);
/* Register only one port */
if (titan_ge_init(0))
printk(KERN_ERR
"Error registering the TITAN Ethernet driver"
"for port 0 \n");
if (titan_ge_init(1))
printk(KERN_ERR "Error registering the TITAN Ethernet"
"driver for port 1\n");
#ifndef CONFIG_PMC_SEQUOIA
#ifdef TITAN_GE_12
if (titan_ge_init(2))
printk(KERN_ERR "Error registering the TITAN Ethernet"
"driver for port 2 \n");
#endif
#endif // CONFIG_PMC_SEQUOIA
#ifdef CONFIG_NET_SKB_RECYCLING
titan_ge_recycle_init();
#endif
return 0;
}
/*
* Unregister the Titan GE from the kernel
*/
static void __init titan_ge_cleanup_module(void)
{
/* Nothing to do here */
}
module_init(titan_ge_init_module);
module_exit(titan_ge_cleanup_module);
/*
* Initialize the Rx descriptor ring for the Titan Ge
*/
static int titan_ge_init_rx_desc_ring(titan_ge_port_info * titan_eth_port,
int rx_desc_num,
int rx_buff_size,
unsigned long rx_desc_base_addr,
unsigned long rx_buff_base_addr,
unsigned long rx_dma)
{
volatile titan_ge_rx_desc *rx_desc;
unsigned long buffer_addr;
int index;
unsigned long titan_ge_rx_desc_bus = rx_dma;
volatile unsigned long reg_data;
buffer_addr = rx_buff_base_addr;
rx_desc = (titan_ge_rx_desc *) rx_desc_base_addr;
/* Check alignment */
if (rx_buff_base_addr & 0xF)
return 0;
/* Check Rx buffer size */
if ((rx_buff_size < 8) || (rx_buff_size > TITAN_GE_MAX_RX_BUFFER))
return 0;
/* 64-bit alignment
if ((rx_buff_base_addr + rx_buff_size) & 0x7)
return 0; */
/* Initialize the Rx desc ring */
for (index = 0; index < rx_desc_num; index++) {
titan_ge_rx_desc_bus += sizeof(titan_ge_rx_desc);
rx_desc[index].cmd_sts = 0;
rx_desc[index].buffer_addr = buffer_addr;
titan_eth_port->rx_skb[index] = NULL;
buffer_addr += rx_buff_size;
}
titan_eth_port->rx_curr_desc_q = 0;
titan_eth_port->rx_used_desc_q = 0;
titan_eth_port->rx_desc_area =
(titan_ge_rx_desc *) rx_desc_base_addr;
titan_eth_port->rx_desc_area_size =
rx_desc_num * sizeof(titan_ge_rx_desc);
titan_eth_port->rx_dma = rx_dma;
return TITAN_OK;
}
/*
* Initialize the Tx descriptor ring. Descriptors in the SRAM
*/
static int titan_ge_init_tx_desc_ring(titan_ge_port_info * titan_ge_port,
int tx_desc_num,
unsigned long tx_desc_base_addr,
unsigned long tx_dma)
{
titan_ge_tx_desc *tx_desc;
int index;
unsigned long titan_ge_tx_desc_bus = tx_dma;
if (tx_desc_base_addr & 0xF)
return 0;
tx_desc = (titan_ge_tx_desc *) tx_desc_base_addr;
for (index = 0; index < tx_desc_num; index++) {
titan_ge_port->tx_dma_array[index] =
(dma_addr_t) titan_ge_tx_desc_bus;
titan_ge_tx_desc_bus += sizeof(titan_ge_tx_desc);
tx_desc[index].cmd_sts = 0x0000;
tx_desc[index].buffer_len = 0;
tx_desc[index].buffer_addr = 0x00000000;
titan_ge_port->tx_skb[index] = NULL;
}
titan_ge_port->tx_curr_desc_q = 0;
titan_ge_port->tx_used_desc_q = 0;
titan_ge_port->tx_desc_area =
(titan_ge_tx_desc *) tx_desc_base_addr;
titan_ge_port->tx_desc_area_size =
tx_desc_num * sizeof(titan_ge_tx_desc);
titan_ge_port->tx_dma = tx_dma;
return TITAN_OK;
}
/*
* Initialize the device as an Ethernet device
*/
static int titan_ge_init(int port)
{
titan_ge_port_info *titan_ge_eth;
struct net_device *netdev;
int err;
int i;
netdev = alloc_etherdev(sizeof(titan_ge_port_info));
if (!netdev) {
err = -ENODEV;
goto out;
}
netdev->open = titan_ge_open;
netdev->stop = titan_ge_stop;
netdev->hard_start_xmit = titan_ge_start_xmit;
netdev->get_stats = titan_ge_get_stats;
netdev->set_multicast_list = titan_ge_set_multi;
netdev->set_mac_address = titan_ge_set_mac_address;
/* Tx timeout */
netdev->tx_timeout = titan_ge_tx_timeout;
netdev->watchdog_timeo = 2 * HZ;
#ifdef TITAN_RX_NAPI
/* Set these to very high values */
netdev->poll = titan_ge_poll;
netdev->weight = 64;
#endif
netdev->tx_queue_len = TITAN_GE_TX_QUEUE;
netif_carrier_off(netdev);
netdev->base_addr = 0;
#ifdef CONFIG_NET_FASTROUTE
netdev->accept_fastpath = titan_accept_fastpath;
#endif
#ifdef CONFIG_NET_SKB_RECYCLING
netdev->mem_reclaim = titan_ge_mem_reclaim;
#endif
netdev->change_mtu = titan_ge_change_mtu;
titan_ge_eth = netdev->priv;
/* Allocation of memory for the driver structures */
titan_ge_eth->port_num = port;
memset(&titan_ge_eth->stats, 0, sizeof(struct net_device_stats));
/* Configure the Tx timeout handler */
INIT_TQUEUE(&titan_ge_eth->tx_timeout_task,
(void (*)(void *)) titan_ge_tx_timeout_task, netdev);
spin_lock_init(&titan_ge_eth->lock);
/* set MAC addresses */
#ifdef CONFIG_PMC_SEQUOIA
memcpy(netdev->dev_addr, titan_ge_mac_addr_base, 6);
netdev->dev_addr[5] += port;
#else //CONFIG_PMC_SEQUOIA
netdev->dev_addr[0] = (unsigned char)
TITAN_GE_READ(TITAN_GE_RMAC_STATION_LOW + (port << 12));
netdev->dev_addr[1] = (unsigned char)
(TITAN_GE_READ(TITAN_GE_RMAC_STATION_LOW + (port << 12)) >> 8);
netdev->dev_addr[2] = (unsigned char)
TITAN_GE_READ(TITAN_GE_RMAC_STATION_MID + (port << 12));
netdev->dev_addr[3] = (unsigned char)
(TITAN_GE_READ(TITAN_GE_RMAC_STATION_MID + (port << 12)) >> 8);
netdev->dev_addr[4] = (unsigned char)
TITAN_GE_READ(TITAN_GE_RMAC_STATION_HI + (port << 12));
netdev->dev_addr[5] = (unsigned char)
(TITAN_GE_READ(TITAN_GE_RMAC_STATION_HI + (port << 12)) >> 8);
#endif //CONFIG_PMC_SEQUOIA
err = register_netdev(netdev);
if (err)
goto out_free_private;
printk(KERN_NOTICE
"%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
netdev->name, port, netdev->dev_addr[0],
netdev->dev_addr[1], netdev->dev_addr[2],
netdev->dev_addr[3], netdev->dev_addr[4],
netdev->dev_addr[5]);
#ifdef TITAN_RX_NAPI
printk(KERN_NOTICE "Rx NAPI supported, Tx Coalescing ON \n");
#else
printk(KERN_NOTICE "Rx and Tx Coalescing ON \n");
#endif
#ifdef CONFIG_NET_FASTROUTE
printk(KERN_NOTICE "Fastpath Routing turned ON \n");
#endif
#ifdef CONFIG_NET_SKB_RECYCLING
for(i=0; i < 1; i++) {
titan_ge_rc[i].qlen += RC_QUEUE_PER_DEV;
}
#endif
return 0;
out_free_private:
out_free_netdev:
// free_netdev(netdev);
out:
return err;
}
/*
* Reset the Ethernet port
*/
static void titan_ge_port_reset(unsigned int port_num)
{
unsigned int reg_data;
/* Stop the Tx port activity */
reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 +
(port_num << 12));
reg_data &= ~(0x0001);
TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 +
(port_num << 12)), reg_data);
/* Wait till TMAC is brought down. */
reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 +
(port_num << 12));
while (reg_data & 0x8000) {
reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 +
(port_num << 12));
}
/* Stop the Rx port activity */
reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 +
(port_num << 12));
reg_data &= ~(0x0001);
TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 +
(port_num << 12)), reg_data);
/* Wait till all packets received and RMAC brought down. */
reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 +
(port_num << 12));
while (reg_data & 0x8000) {
reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 +
(port_num << 12));
}
return;
}
/*
* Return the Tx desc after use by the XDMA
*/
static int titan_ge_return_tx_desc(titan_ge_port_info * titan_ge_eth, int port)
{
int tx_desc_used;
struct sk_buff *skb;
volatile titan_ge_tx_desc *tx_curr;
tx_desc_used = titan_ge_eth->tx_used_desc_q;
/* return right away */
if (tx_desc_used == titan_ge_eth->tx_curr_desc_q)
return TITAN_ERROR;
/* Now the critical stuff */
skb = titan_ge_eth->tx_skb[tx_desc_used];
tx_curr = &(titan_ge_eth->tx_desc_area[tx_desc_used]);
pci_unmap_single(0, tx_curr->buffer_addr, tx_curr->buffer_len, PCI_DMA_TODEVICE);
#ifdef CONFIG_NET_FASTROUTE
if (port == 1)
__kfree_skb(skb);
else
#endif
dev_kfree_skb_any(skb);
titan_ge_eth->tx_skb[tx_desc_used] = NULL;
titan_ge_eth->tx_used_desc_q =
(tx_desc_used + 1) % TITAN_GE_TX_QUEUE;
return 0;
}
/*
* Coalescing for the Rx path
*/
static unsigned long titan_ge_rx_coal(unsigned long delay, int port)
{
TITAN_GE_WRITE(TITAN_GE_INT_COALESCING, delay);
#ifdef CONFIG_PMC_SEQUOIA
TITAN_GE_WRITE(0x3034, delay);
#else
TITAN_GE_WRITE(0x5038, delay);
#endif
return delay;
}
/*
* Coalescing for the Tx path
*/
static unsigned long titan_ge_tx_coal(unsigned long delay, int port)
{
unsigned long rx_delay;
rx_delay = TITAN_GE_READ(TITAN_GE_INT_COALESCING);
delay = (delay << 16) | rx_delay;
TITAN_GE_WRITE(TITAN_GE_INT_COALESCING, delay);
#ifdef CONFIG_PMC_SEQUOIA
TITAN_GE_WRITE(0x3034, delay);
#else
TITAN_GE_WRITE(0x5038, delay);
#endif
return delay;
}
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: booting with NFS root
2006-05-26 1:38 ` Yoichi Yuasa
@ 2006-05-26 2:40 ` Roman Mashak
2006-05-26 2:40 ` Roman Mashak
0 siblings, 1 reply; 9+ messages in thread
From: Roman Mashak @ 2006-05-26 2:40 UTC (permalink / raw)
To: Yoichi Yuasa; +Cc: linux-mips
Hello, Yoichi
and thanks for reply.
YY> <snip>
??>> Freeing unused kernel memory: 104k freed
??>> do_cpu invoked from kernel context! in traps.c::do_cpu, line 676:
YY> This error is coprocessor unusable exception.
May this be caused by hardware error/bug ?
??>> $0 : 00000000 9004a000 2ab03fe0 2ab03fe0 2ab01560 00000000 00000ae0
??>> 00000ae0 $8 : 00000020 2ab01fe0 2ab01520 00001000 00000019 00000080
??>> 811d7b18 00000c62 $16: 2ab010c0 811d7c58 87f8cfe0 00000003 00000080
??>> 2ab01520 87f841a0 00000001 $24: 00000000 00000080
??>> 811d6000 811d7ba0 2aaa8000 8015f414 Hi : 00000000 Lo : 00000000 epc
??>> : 80256e14 Not tainted
YY> The exception program counter is 0x80256e14 .
YY> You can check instructions(0x80256e14 and before) in your kernel
YY> object.
I ran 'objdump -d /tftpboot/vmlinux | grep -B7 ^80256e14' and got the
following:
80256df8: 732f6330 0x732f6330
80256dfc: 64347000 daddiu s4,at,28672
80256e00: 63636973 daddi v1,k1,26995
80256e04: 732f6330 0x732f6330
80256e08: 64357000 daddiu s5,at,28672
80256e0c: 63636973 daddi v1,k1,26995
80256e10: 732f6330 0x732f6330
80256e14: 64367000 daddiu s6,at,28672
But I'm not good in MIPS assembling. Does this give you some clue?
??>> Status: 9004a003
??>> Cause : 1000002c
??>> PrId : 000034c1
??>> Process init (pid: 1, stackpage=811d6000)
??>> Stack: 8015f8a8 8015f9a8 87f71180 8012b2fc 00000000 80135330
With best regards, Roman Mashak. E-mail: mrv@corecom.co.kr
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: booting with NFS root
2006-05-26 2:40 ` Roman Mashak
@ 2006-05-26 2:40 ` Roman Mashak
0 siblings, 0 replies; 9+ messages in thread
From: Roman Mashak @ 2006-05-26 2:40 UTC (permalink / raw)
To: Yoichi Yuasa; +Cc: linux-mips
Hello, Yoichi
and thanks for reply.
YY> <snip>
??>> Freeing unused kernel memory: 104k freed
??>> do_cpu invoked from kernel context! in traps.c::do_cpu, line 676:
YY> This error is coprocessor unusable exception.
May this be caused by hardware error/bug ?
??>> $0 : 00000000 9004a000 2ab03fe0 2ab03fe0 2ab01560 00000000 00000ae0
??>> 00000ae0 $8 : 00000020 2ab01fe0 2ab01520 00001000 00000019 00000080
??>> 811d7b18 00000c62 $16: 2ab010c0 811d7c58 87f8cfe0 00000003 00000080
??>> 2ab01520 87f841a0 00000001 $24: 00000000 00000080
??>> 811d6000 811d7ba0 2aaa8000 8015f414 Hi : 00000000 Lo : 00000000 epc
??>> : 80256e14 Not tainted
YY> The exception program counter is 0x80256e14 .
YY> You can check instructions(0x80256e14 and before) in your kernel
YY> object.
I ran 'objdump -d /tftpboot/vmlinux | grep -B7 ^80256e14' and got the
following:
80256df8: 732f6330 0x732f6330
80256dfc: 64347000 daddiu s4,at,28672
80256e00: 63636973 daddi v1,k1,26995
80256e04: 732f6330 0x732f6330
80256e08: 64357000 daddiu s5,at,28672
80256e0c: 63636973 daddi v1,k1,26995
80256e10: 732f6330 0x732f6330
80256e14: 64367000 daddiu s6,at,28672
But I'm not good in MIPS assembling. Does this give you some clue?
??>> Status: 9004a003
??>> Cause : 1000002c
??>> PrId : 000034c1
??>> Process init (pid: 1, stackpage=811d6000)
??>> Stack: 8015f8a8 8015f9a8 87f71180 8012b2fc 00000000 80135330
With best regards, Roman Mashak. E-mail: mrv@corecom.co.kr
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: booting with NFS root
2006-05-26 2:07 booting with NFS root Kiran Thota
@ 2006-05-26 3:05 ` Roman Mashak
2006-05-26 3:05 ` Roman Mashak
2006-05-26 17:56 ` Braden Marr
1 sibling, 1 reply; 9+ messages in thread
From: Roman Mashak @ 2006-05-26 3:05 UTC (permalink / raw)
To: Kiran Thota; +Cc: linux-mips
Hello, Kiran!
You wrote to "Roman Mashak" <mrv@corecom.co.kr>; <linux-mips@linux-mips.org>
on Thu, 25 May 2006 19:07:13 -0700:
KT> Roman,
KT> You have an older version of the linux kernel. I can send you latest
snapshot.
I've taken the latest 2.4.x available on ftp.pmc-sierra.com
KT> There was a software bug. I don't know your source version to send patch
but I am
KT> attaching the source titan_ge.c
Thank you Kiran, I recompliled the kernel with driver you attached and now
there's no panic at least, kernel only hangs up waiting for reply from NFS:
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
Looking up port of RPC 100003/2 on 192.168.11.43
I ran 'tcpdump' on server's side and observed that it's unable to obtain MAC
address of Sequoia board. Where have I done mistake?
With best regards, Roman Mashak. E-mail: mrv@corecom.co.kr
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: booting with NFS root
2006-05-26 3:05 ` Roman Mashak
@ 2006-05-26 3:05 ` Roman Mashak
0 siblings, 0 replies; 9+ messages in thread
From: Roman Mashak @ 2006-05-26 3:05 UTC (permalink / raw)
To: Kiran Thota; +Cc: linux-mips
Hello, Kiran!
You wrote to "Roman Mashak" <mrv@corecom.co.kr>; <linux-mips@linux-mips.org>
on Thu, 25 May 2006 19:07:13 -0700:
KT> Roman,
KT> You have an older version of the linux kernel. I can send you latest
snapshot.
I've taken the latest 2.4.x available on ftp.pmc-sierra.com
KT> There was a software bug. I don't know your source version to send patch
but I am
KT> attaching the source titan_ge.c
Thank you Kiran, I recompliled the kernel with driver you attached and now
there's no panic at least, kernel only hangs up waiting for reply from NFS:
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
Looking up port of RPC 100003/2 on 192.168.11.43
I ran 'tcpdump' on server's side and observed that it's unable to obtain MAC
address of Sequoia board. Where have I done mistake?
With best regards, Roman Mashak. E-mail: mrv@corecom.co.kr
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: booting with NFS root
2006-05-26 2:07 booting with NFS root Kiran Thota
2006-05-26 3:05 ` Roman Mashak
@ 2006-05-26 17:56 ` Braden Marr
1 sibling, 0 replies; 9+ messages in thread
From: Braden Marr @ 2006-05-26 17:56 UTC (permalink / raw)
To: Kiran Thota; +Cc: Roman Mashak, linux-mips
[-- Attachment #1: Type: text/plain, Size: 6155 bytes --]
Kiran Thota wrote:
> Roman,
> You have an older version of the linux kernel. I can send you latest snapshot.
> There was a software bug. I don't know your source version to send patch but I am
> attaching the source titan_ge.c
>
> Regards,
> Kiran
Kiran,
I noticed in this driver update that the INTMSG vector is set after
interrupts are enabled.
We have confirmed that if the Titan GE's INTMSG vector is configured
instead to point to the Interrupt Controller's INTMSG register before
the interrupts are enabled, then the chance of this exception occurring
is reduced or removed.
I have attached a patch against your earlier titan_ge.c attachment that
illustrates this change.
As I understand it, if an interrupt is pending from some previous use of
the Titan GE block, such as in PMON (which uses a polling interrupt
handler), where tftp is used to load the kernel into RAM via an Ethernet
port, then when the interrupts are enabled in the kernel's titan_ge.c
driver, a pending interrupt (from Ethernet packets received before while
the kernel is booting, for example) could cause the Titan GE block to
send the interrupt status message to a undetermined address within the
RM9150 core! Since there is likely no conventional way to trap this type
of exception, an erroneous do_cpu exception is the result.
Conceivably, any core block that attempts to use an INTMSG vector with
an undetermined value could cause the same conditions.
cheers,
Braden Marr. (email to: bmarr at sutus dot com)
>
> -----Original Message-----
> From: linux-mips-bounce@linux-mips.org [mailto:linux-mips-bounce@linux-mips.org] On Behalf Of Roman Mashak
> Sent: Thursday, May 25, 2006 5:50 PM
> To: linux-mips@linux-mips.org
> Subject: booting with NFS root
>
> Hello!
>
> I have evaluation board from PMC-sierra, their CPU is using E9000 core.
> Kernel (2.4.26), root FS are provided by them. I set up NFS and TFTP servers on my linux box, kernel loads into board but fails to boot woth the following message (I skipped some lines of kernel):
>
> =====================
> PMC-Sierra TITAN 10/100/1000 Ethernet Driver Device Id : 206014, Version : 0
> eth0: port 0 with MAC address 30:30:3a:31:31:3a Rx NAPI supported, Tx Coalescing ON
> eth1: port 1 with MAC address 30:30:3a:31:31:3b Rx NAPI supported, Tx Coalescing ON
> NET4: Linux TCP/IP 1.0 for NET4.0
> IP Protocols: ICMP, UDP, TCP, IGMP
> IP: routing cache hash table of 1024 buckets, 8Kbytes
> TCP: Hash tables configured (established 8192 bind 16384)
> IP-Config: Entered.
> ipconfig.c 1194
> dev.c 1998
> dev.c 2013
> dev.c 750
> irq.c 539
> irq.c 571
> irq.c 840
> irq.c 879
> handler->startup 80259d14
> irq.c 892
> irq.c 576
> Assigned IRQ 6 to port 0
> titan_ge.c 2256
> titan_ge.c 2278
> titan_ge.c 2316
> titan_ge.c 2359
> titan_ge.c 1614
> titan_ge.c 1659
> titan_ge.c 1698
> titan_ge.c 1717
> titan_ge.c 1837
> titan_ge.c 2025
> titan_ge.c 2118
> titan_ge.c 2177
> dev_addr= 1, reg_addr= 11
> val= 4111
> val= 1
> titan_ge.c 2184
> titan_ge.c 2397
> dev_addr= 1, reg_addr= 11
> val= 4112
> val= 1
> dev.c 788
> dev.c 2034
> dev.c 2043
> dev.c 2059
> IP-Config: eth0 UP (able=1, xid=57c63687) dev.c 1998 dev.c 2013 dev.c 750 irq.c 539 irq.c 571 irq.c 840 irq.c 879 irq.c 892 irq.c 576 Assigned IRQ 6 to port 1 titan_ge.c 2256 titan_ge.c 2278 titan_ge.c 2316 titan_ge.c 2359 titan_ge.c 1659 titan_ge.c 1698 titan_ge.c 1717 titan_ge.c 1837 titan_ge.c 2025 titan_ge.c 2118 titan_ge.c 2177
> dev_addr= 2, reg_addr= 11
> val= 4111
> val= 1
> titan_ge.c 2184
> titan_ge.c 2397
> dev_addr= 2, reg_addr= 11
> val= 4212
> val= 1
> eth1: Error opening interface
> dev.c 788
> dev.c 2034
> dev.c 2043
> dev.c 2059
> IP-Config: Failed to open eth1
> ipconfig.c 1199
> IP-Config: Guessing netmask 255.255.255.0
> IP-Config: Complete:
> device=eth0, addr=192.168.11.42, mask=255.255.255.0, gw=255.255.255.255,
> host=192.168.11.42, domain=, nis-domain=(none),
> bootserver=255.255.255.255, rootserver=192.168.11.43, rootpath=
> NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
> Looking up port of RPC 100003/2 on 192.168.11.43 Looking up port of RPC 100005/1 on 192.168.11.43
> VFS: Mounted root (nfs filesystem).
> Freeing unused kernel memory: 104k freed do_cpu invoked from kernel context! in traps.c::do_cpu, line 676:
> $0 : 00000000 9004a000 2ab03fe0 2ab03fe0 2ab01560 00000000 00000ae0 00000ae0
> $8 : 00000020 2ab01fe0 2ab01520 00001000 00000019 00000080 811d7b18 00000c62
> $16: 2ab010c0 811d7c58 87f8cfe0 00000003 00000080 2ab01520 87f841a0 00000001
> $24: 00000000 00000080 811d6000 811d7ba0 2aaa8000 8015f414
> Hi : 00000000
> Lo : 00000000
> epc : 80256e14 Not tainted
> Status: 9004a003
> Cause : 1000002c
> PrId : 000034c1
> Process init (pid: 1, stackpage=811d6000)
> Stack: 8015f8a8 8015f9a8 87f71180 8012b2fc 00000000 80135330 00002012
> 00000019 87f8cf60 2ab019e4 00000004 00002012 000590c0 2ab01000 10000000
> 811d7d88 87ff5740 00000000 811d7ef8 81164e80 00000000 00000002 87f841a0
> 8015ffd8 811d7c20 811d6000 811d7cbc 801975a4 00006012 0000000a 811d7c18
> 811d7c18 7f454c46 01020100 00000000 00000000 00020008 00000001 00401980
> 00000034 ...
> Call Trace: [<8015f8a8>] [<8015f9a8>] [<8012b2fc>] [<80135330>]
> [<8015ffd8>]
> [<801975a4>] [<8015fbc0>] [<801493ac>] [<801007b8>] [<8014889c>] [<801495bc>] [<801495a8>] [<801007b8>] [<80108f80>] [<801007b8>] [<8014fcc4>] [<801095c0>] [<8025ad30>] [<801007b8>] [<8025ad30>] [<8014af50>] [<801007b8>] [<80117888>] [<801194a0>] [<80100884>] [<801007b8>] [<8010079c>] [<8025de14>] [<80104320>] [<80117aec>] [<8026b7a8>] [<801b2054>] [<80104310>]
>
> Code: 30c8003c 01244821 24840040 <ac85ffc0> ac85ffc4 ac85ffc8 ac85ffcc ac85ffd0 ac85ffd4 Kernel panic: Attempted to kill init!
> =====================
>
> I load kernel with the following parameters:
> tftp://192.168.11.43/vmlinux ip=192.168.11.42 root=/dev/nfs nfsroot=192.168.11.43:/export/linux/mips-fs-be
>
> What may be the problem here?
>
> Thanks in advance!
>
> With best regards, Roman Mashak. E-mail: mrv@corecom.co.kr
>
>
>
[-- Attachment #2: titan_ge-intmsg.patch --]
[-- Type: text/plain, Size: 1525 bytes --]
--- titan_ge.c.pmc 2006-05-25 20:10:29.000000000 -0700
+++ titan_ge.c 2006-05-25 20:12:34.000000000 -0700
@@ -2094,6 +2094,28 @@
udelay(30);
+#ifdef CONFIG_PMC_SEQUOIA
+
+// XD_OOD_INTSMSG = 0x61, XD_INTSMSG = 0x62,
+// XD_RX_INTSMSG = XD_TX_INTSMSG = 0x60
+ TITAN_GE_WRITE(0x0060, RM9150_GCIC_INTMSG >> 4);
+
+ reg_data = 0x61626060;
+ TITAN_GE_WRITE(0x0044, reg_data);
+ reg_data = TITAN_GE_READ(0x0080);
+ reg_data |= 0x1;
+ TITAN_GE_WRITE(0x0080, reg_data);
+
+#else
+#ifdef TITAN_GE_12
+ TITAN_GE_WRITE(0x0024, 0x04844424);
+#else
+ TITAN_GE_WRITE(0x0024, 0x04000024); /* IRQ vector */
+#endif
+ TITAN_GE_WRITE(0x0020, 0x000fb000); /* INTMSG base */
+#endif // CONFIG_PMC_SEQUOIA
+ }
+
/*
* Enable the Interrupts for Tx and Rx
*/
@@ -2128,28 +2150,6 @@
TITAN_GE_WRITE(0x003c, 0x00300);
#endif
-#ifdef CONFIG_PMC_SEQUOIA
-
-// XD_OOD_INTSMSG = 0x61, XD_INTSMSG = 0x62,
-// XD_RX_INTSMSG = XD_TX_INTSMSG = 0x60
- TITAN_GE_WRITE(0x0060, RM9150_GCIC_INTMSG >> 4);
-
- reg_data = 0x61626060;
- TITAN_GE_WRITE(0x0044, reg_data);
- reg_data = TITAN_GE_READ(0x0080);
- reg_data |= 0x1;
- TITAN_GE_WRITE(0x0080, reg_data);
-
-#else
-#ifdef TITAN_GE_12
- TITAN_GE_WRITE(0x0024, 0x04844424);
-#else
- TITAN_GE_WRITE(0x0024, 0x04000024); /* IRQ vector */
-#endif
- TITAN_GE_WRITE(0x0020, 0x000fb000); /* INTMSG base */
-#endif // CONFIG_PMC_SEQUOIA
- }
-
/* Priority */
reg_data = TITAN_GE_READ(0x1038 + (port_num << 12));
reg_data &= ~(0x00f00000);
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2006-05-26 17:56 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-05-26 2:07 booting with NFS root Kiran Thota
2006-05-26 3:05 ` Roman Mashak
2006-05-26 3:05 ` Roman Mashak
2006-05-26 17:56 ` Braden Marr
-- strict thread matches above, loose matches on Subject: below --
2006-05-26 0:49 Roman Mashak
2006-05-26 0:49 ` Roman Mashak
2006-05-26 1:38 ` Yoichi Yuasa
2006-05-26 2:40 ` Roman Mashak
2006-05-26 2:40 ` Roman Mashak
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox