Difference between revisions of "Porting"

From LinuxMIPS
Redirect page
Jump to: navigation, search
(Unmodified cut'n'paste of Jun's Linux MIPS Porting Guide)
 
 
(37 intermediate revisions by 7 users not shown)
Line 1: Line 1:
Jun Sun's
+
#REDIRECT [[Linux/MIPS_Porting_Guide]]
+
Linux MIPS Porting Guide
+
+
\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff
+
+
I want your feedback: info, errors, spelling, dead links, comments, or even
+
compliments :-)
+
+
\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff
+
+
Prefix
+
+
This document reflects what I have learned through porting several MIPS
+
machines and other related Linux work. Hopefully it will help beginners to get
+
started and give the experienced a reference point.
+
+
This document goes through all the major steps to port Linux to a MIPS machine.
+
The focus can perhaps be called "MIPS machine abstraction layer", i.e., the
+
interface between machine-specific code and, mostly, MIPS common code. Another
+
useful document focuses on "Linux hardware abstraction layer", i.e., the
+
interface between Linux common code and architecture-specific code. The
+
document is written by C Hanish Menon (www.hanishkvc.com).
+
+
There are some notations used in this document.
+
+
TODO
+
    Reminder for incomplete part
+
HELP
+
    Really need your help on this
+
DEBATE
+
    Here is my opinion. What do you think?
+
THANKS
+
    Thanks to the person who pointed this out
+
NOTE
+
    Additional note added later, but the original comment may be still useful
+
+
Chapter 1: An overview
+
+
Prerequisites:
+
+
  \uffff\uffff\uffff Know C programming.
+
  \uffff\uffff\uffff Have some knowledge of OS concepts, such as interrupt handling, system
+
    calls, memory management.
+
  \uffff\uffff\uffff Know how to configure and make Linux kernel. You can find many helps on
+
    this if you are not very comfortable.
+
  \uffff\uffff\uffff Have some knowledge of MIPS CPU. More than likely you will need to deal
+
    with CP0 registers, enable or disable interrupts, etc..
+
  \uffff\uffff\uffff You don't have to be an expert in MIPS assembly, but total ignorance of it    might make you handicapped in some situations.
+
  \uffff\uffff\uffff Obviously, you need a MIPS hardware to play with.
+
  \uffff\uffff\uffff Finally but most importantly, you need a willing-to-learn heart and perhaps
+
    many restless debugging hours. :-)
+
+
It is also highly recommanded to read through the Linux MIPS HOWTO by Ralf
+
B\uffff\uffffchle, ralf@gnu.org. By the way, as part of the pre-requisite, you should alsoremember Ralf's name. :-)
+
+
Kernel source trees
+
+
The common MIPS tree is the CVS tree at linux-mips.org. See the instructions in
+
"Anonymous CVS servers" section in Linux/MIPS HOWTO. The current kernel version
+
as of 2004/01/26 is 2.6.1. You can always check out earlier stable revisions by
+
using "linux_2_4" or even "linux_2_2" branch tag.
+
+
Kernel patches
+
+
For various reasons, a kernel tree may leave bugs there for a quite long time
+
before a suitable fix is checked in. There are various places to get patches.
+
Here are some of the more common ones:
+
+
    Jun Sun patches
+
    Linux/MIPS FTP archive
+
    Maciej W. Rozyki patches
+
    Brad LaRonde's patches
+
+
Cross-compilation and toolchains
+
+
More than likely your MIPS box does not run Linux yet (why would you bother
+
otherwise?). Therefore you will need another machine to build the kernel image.
+
Once the image is built, you need to download this image to your MIPS machine
+
and let it run your MIPS kernel. This is called cross-development. Your MIPS
+
box is often called the target machine and the machine used to build the kernel
+
image is called the host machine.
+
+
Cross-development is common for developing on embedded targets, because usually
+
embedded targets do not have enough power or the peripherals to develop
+
natively.
+
+
The most common host machine is probably Linux on i386/PCs.
+
+
You need to have cross-development tools setup on your host before you can
+
start. While you can find instructions, such as in Linux/MIPS HOWTO, to build
+
cross-compilation tools, your best bet is probably to get some ready-made ones.
+
+
MontaVista used to offer for free Journeyman edition, which includes a full
+
featured toolchain. Unfortunately, it does not offer that anymore. Instead you
+
can download the preview kit, which includes a "slim" version of toolchain. You
+
can get the kit from http://www.mvista.com/previewkit/index.html
+
+
Dan Kegel has a set of scripts that build cross-compiling tools. You can check
+
it out here.
+
+
The following are links to pre-build toolchains, instructions to build your own
+
toolchain and finally pre-compiled distributions for MIPS boards:
+
+
    Brad LaRonde's cross toolchain for Linux
+
    Steve Hill's toolchains for glibc and uClibc
+
    MIPS free toolchains
+
    Distributions for MIPS
+
+
Overall porting steps :
+
+
Depending on your specific cases, some of the following steps can be skipped.
+
+
1. Hello World! - Get board setup, serial porting working, and print out
+
    "Hello, world!" through the serial port.
+
2. Add your own code.
+
3. Get early printk working - Make the first MIPS image and see the printk
+
    output from kernel.
+
4. Serial driver and serial console - Get the real printk working with the
+
    serial console.
+
5. KGDB - KGDB can be enormously helpful in your development. It is highly
+
    recommended and it is not that difficult to set up.
+
6. CPU support - If your MIPS CPU is not currently supported, you need to add
+
    new code that supports it.
+
7. Board specific support - Create your board-specific directory. Setup
+
    interrupt routing/handling and kernel timer services.
+
8. PCI subsystems - If your machine has PCI, you need to get the PCI subsystem
+
    working before you can use PCI devices.
+
9. Ethernet drivers - You should already have the serial port working before
+
    attempting this. Usually the next driver you want is the ethernet driver.
+
    With ethernet driver working, you can set up a NFS root file system which
+
    gives you a fully working Linux userland.
+
10. ROMFS root file system - Alternatively you can create a userland file
+
    system as a ROMFS image stored in a ramdisk.
+
+
Chapter 2: "Hello, world!"
+
+
In cross development, the serial port is usually the most important interface:
+
That is where you can see anything happening! It might be worthwhile to make
+
sure you get serial porting work before you even start playing with Linux. You
+
can find the sample code or gzipped tar ball of a stand-alone program that can
+
do printf. Such a program can even be useful in later debugging staging, e.g.,
+
printing out hardware register values.
+
+
Before you rush to type 'make', check and modify the following configurations:
+
+
1. The sample code assumes R4K style CP0 structure. It should apply to most
+
    CPUs named above number 4000 and the recent MIPS32/MIPS64.
+
2. Check if you have 1MB RAM size. (You really should have at 1MB to run Linux
+
    at all.) It is recommanded you have 8MB RAM or more.
+
3. Is your serial port a standard UART type? If yes, modify the serial code
+
    and parameters. If not, you will have to supply your own functions to
+
    utilize the UART.
+
4. What is your cross-tool name and path? Modify the Makefile accordingly.
+
+
Now, fire your "make" command.
+
+
Depending on your downloader on your MIPS box, you may need to generate ELF
+
image, binary image or a SREC image.
+
+
Download the barebone image to your target and give it a run! Connect the
+
serial port to your host machine. Start minicom and hopefully you can see the
+
"Hello, world!" message.
+
+
Trouble shooting:
+
+
  \uffff\uffff\uffff Make sure your bootloader downloads the image to uncached KSEG1 segment. If
+
    your bootloader downloads to the cached KSEG0 area, you will want to run
+
    the image from the KSEG0 area too.
+
  \uffff\uffff\uffff If your bootloader has already initialized the serial port, you may want to
+
    skip your own initialization.
+
  \uffff\uffff\uffff Did you set up minicom correctly? Test it with other machines.
+
  \uffff\uffff\uffff Hopefully it is not the toolchain problem...
+
+
Chapter 3 : Add your own code
+
+
Let us add some code to the tree and make a Linux image. For conveninence sake,
+
let us say we are porting Linux to a MIPS board called Aloha.
+
+
Create the right directory for your board
+
+
Your code for a new board can be classified into board-support code (or
+
board-specific code) and drivers. Driver code should be placed under the
+
'drivers' directory and board specific code should be placed under 'arch/mips'
+
directory.
+
+
The easiest choice is to create a directory called 'arch/mips/aloha'.
+
+
However, a couple of other considerations might make it slightly complicated.
+
+
  \uffff\uffff\uffff If Aloha uses a chipset or System on a Chip (SOC) that is already supported
+
    or belongs to a bigger family, such as NEC VR41xx and gt64120, it makes
+
    sense to put Aloha code under those sub-directories. You can re-use and
+
    share a lot of common code.
+
  \uffff\uffff\uffff Similarly, if Aloha is the first board that uses a chipset or SOC which is    expected to be used in many other boards, you may want to create similar
+
    directory structure. However, if you are not sure, just create your own
+
    board specific directory.
+
+
In the past people have created directories based on the board manufacturer's
+
name, such as "mips-boards". This generally is not a good idea. It is almost
+
certain that some of these boards do not share anything common at all.
+
+
To make things worse, sometimes boards made by different companies use the same
+
chipset or SOC. Now what are you going to do? Are you going to duplicate the
+
common code? Or are you going stick one company's board under another company's
+
name?
+
+
For header files, you usually create similar directory or header files under
+
include/asm-mips. [DEBATE] For board specific header files, I would encourage
+
people to place them under the corresponding 'arch/mips' directory if possible.
+
+
In our exmaple, we will create 'arch/mips/aloha' directory.
+
+
Write the minimum Aloha code
+
+
Let us write some code for the Aloha board which can generate a complete Linux
+
image without complaining about missing symbols.
+
+
Go to this directory to browse 'arch/mips/aloha' directory. Or download the
+
gzipped file of the directory.
+
+
Obviously the code is not complete yet, but if you follow the following steps
+
and everything is correct, you should be able to generate a Linux/MIPS kernel
+
image of your very own!
+
+
Hook up your code with the Linux tree
+
+
Most of the steps are fairly straightforward:
+
+
  \uffff\uffff\uffff include/asm-mip/bootinfo.h - Add your machine group ID, machine group name    and Aloha machine ID.
+
  \uffff\uffff\uffff arch/mips/kernel/setup.c - Add 'aloha_setup' function declaration and
+
    invocation code.
+
  \uffff\uffff\uffff arch/mips/Makefile - Add a section that links your Aloha code in.
+
+
        #
+
        # Hawaii Aloha board
+
        #
+
        ifdef CONFIG_ALOHA
+
        SUBDIRS      += arch/mips/aloha
+
        LIBS          += arch/mips/aloha/aloha.o
+
        LOADADDR      += 0x80002000
+
        endif
+
+
+
    LOADADDR is the starting address for your Linux image when it is loaded
+
    into RAM. Note that the first 0x200 bytes are used by the exception vectors
+
    on most CPUs. Some CPUs will requries a larger space, so modify the
+
    LOADADDR accordingly. Due to the linker's addressing limit, the start
+
    address is aligned on a 8KB boundary, so setting your LOADADDR to
+
    0x80002000 should be reasonable.
+
  \uffff\uffff\uffff arch/mips/config-shared.in - Add necessary config information for Aloha
+
    board.
+
    1. Add the following to 'Machine selection'.
+
+
            dep_bool 'Support for Hawaii Aloha board  (EXPERIMENTAL)' CONFIG_ALOHA $CONFIG_EXPERIMENTAL
+
+
+
+
    2. Add a set of default configs for the board, which depends on the
+
        features and drivers that Linux port will supports. Here is a very
+
        simple example for our minimum Aloha board configurations.
+
+
            if [ "$CONFIG_ALOHA" = "y" ]; then
+
              define_bool CONFIG_CPU_R4X00 y
+
              define_bool CONFIG_CPU_LITTLE_ENDIAN y
+
              define_bool CONFIG_SERIAL y
+
              define_bool CONFIG_SERIAL_MANY_PORTS y
+
              define_bool CONFIG_NEW_IRQ y
+
              define_bool CONFIG_NEW_TIME_C y
+
              define_bool CONFIG_SCSI n
+
            fi
+
+
+
+
    There are two kinds of configuration options here. The first kind are those
+
    you cannot select interactively during 'make config' or 'make menuconfig'
+
    or 'make xconfig'. Examples are CONFIG_NEW_IRQ and CONFIG_NEW_TIME_C. You
+
    must put them here, or else they will not get selected. The second kind of
+
    options are those you can select interactively, such as CONFIG_CPU_R4X00
+
    and CONFIG_SERIAL. However you may also put them here if you know which
+
    selection is right for the board. This way people will make fewer mistakes
+
    when they configure for the board.
+
+
For instant gratification, you can find a complete patch for adding the Aloha
+
board support to the Linux/MIPS CVS tree checked out on January 20, 2004.
+
+
Configure and build a kernel image
+
+
Now you are ready to run your favorite configuration tool. Since we do not have
+
much code added yet, do not be too greedy with selecting options. Just pick a
+
couple of simple options such as the serial and serial console.
+
+
  \uffff\uffff\uffff If you denoted the Aloha board support to be EXPERIMENTAL, select 'Prompt
+
    for development and/or incomplete code/drivers' under 'Code maturity level
+
    options'.
+
  \uffff\uffff\uffff Select 'Support for Hawaii Aloha board' and unselect all other machines
+
    under 'Machine selection'.
+
  \uffff\uffff\uffff Select the right CPU. Under 'CPU selection' select your CPU. If there is no
+
    entry for the CPU on your board, you will need to add support for it. Most
+
    recent CPUs can generally run to some degree with CPU_R4X00.
+
  \uffff\uffff\uffff Under 'Character devices', select 'Standard/generic (8250/16550 and
+
    compatible UARTs) serial support' and 'Support for console on serial port'.
+
    Unselect the 'Virtual terminal' option.
+
  \uffff\uffff\uffff Under the 'Kernel hacking' option, select 'Are you using a crosscompiler'.  \uffff\uffff\uffff For other options either take the default or select 'no'.
+
+
Here is a sample minimum config for our Aloha board.
+
+
Before you type 'make', double-check the 'arch/mips/Makefile' and make sure the
+
cross-toolchain program names are correct and in your execution path i.e. your
+
PATH environment variable.
+
+
Now type 'make dep' and 'make'. Then wait for a miracle to happen!
+
+
Chapter 4 : Early printk
+
+
Assuming you are lucky and actually generate an image from the last chapter,
+
don't bother running it because you won't see anything. This is not strange
+
because all our board-specific code is empty and we have not told Linux kernel
+
anything about our serial port or I/O devices yet.
+
+
The sign of a live Linux kernel comes from the output of printk, which is
+
routed to the first console. Since we have configured a serial console, we
+
should be able to see something on the serial wire if we have set it up
+
correctly.
+
+
Unfortunately, setup of the serial console happens much later during the kernel
+
startup process. (See Appendix A for a chart of the kernel start-up sequence).
+
Chances are your new kernel probably dies even before that. That is where the
+
early printk patch comes in handy. It allows you to see printk as early as the
+
first line of C code.
+
+
By the way the first line of C code for Linux MIPS is the first line of code of
+
'init_arch()' function in the 'arch/mips/setup.c' file.
+
+
For kernel version earlier than 2.4.10, you can find the early printk patch
+
here for boards with standard UART serial ports. Starting from 2.4.10 and
+
beyond, a new printk patch is needed. If you have already got the stand-alone
+
"Hello, world!" program running, the early printk should be easy to get going,
+
and you should have printk output from the Linux kernel very soon.
+
+
Chapter 5 : Serial driver and console
+
+
While early printk is rather useful, you still need to get the real serial
+
driver working.
+
+
Assuming you have a standard serial port, there are two ways to add serial
+
support: static defines and run-time setup.
+
+
With static defines, you modify the 'include/asm-mips/serial.h' file. Looking
+
through the code, it is not difficult to figure out how to add support for your
+
board's serial port(s).
+
+
As more boards are supported by Linux/MIPS, the 'serial.h' file gets crowded.
+
One potential solution is to do run-time serial setup. Sometimes run-time
+
serial setup is necessary if any of the parameters can only be detected at the
+
run-time where settings are read from a non-volatile memory device or an option
+
is passed on the kernel command line.
+
+
There are two elements to consider for doing run-time serial setup:
+
+
  \uffff\uffff\uffff Reserve the 'rs_table[]' size, see the 'drivers/char/serial.c' file.
+
    Unfortunately there is not a clean way to accomplish this yet. A temporary
+
    workaround is to define CONFIG_SERIAL_MANY_PORTS in 'arch/mips/
+
    config-shared.in' for your board. This configuration reserves up to 64
+
    serial port entries for your board!
+
  \uffff\uffff\uffff Call the 'early_serial_setup()' routine in your board setup routine. Here
+
    is a piece of sample run-time initialization code.
+
+
Serial parameters
+
+
Most of the parameter settings are rather obvious. Here is a list of some less
+
obvious ones:
+
+
line
+
    Only used for run-time serial configuration. It is the index into the
+
    'rs_table[] array'.
+
io_type
+
    io_type determines how your serial registers are accessed. Two common types
+
    are SERIAL_IO_PORT and SERIAL_IO_MEM. A SERIAL_IO_PORT type driver uses the
+
    inb/outb macros to access registers whose base address is at port. In other
+
    words, if you specify SERIAL_IO_PORT as the io_type, you should also
+
    specify the port parameter.
+
    For SERIAL_IO_MEM, the driver uses readb/writeb macros to access regsiters
+
    whose address is at iomem_base plus a shifted offset. The number of digits
+
    shifted is specified by iomem_reg_shift. For example, all the serial
+
    registers are placed at 4-byte boundary, then you have an iomem_reg_shift
+
    of 2.
+
    Generally SERIAL_IO_PORT is for serial ports on an ISA bus and
+
    SERIAL_IO_MEM is for memory-mapped serial ports.
+
    There are also SERIAL_IO_HUB6 and SERIAL_IO_GSC. The HUB6 was a multi-port
+
    serial card produced by Bell Technologies. The GSC is a special bus found
+
    on PA-RISC systems. These options will not be used on any MIPS boards.
+
+
Non-standard serial ports
+
+
If you have a non-standard serial port, you will have to write your own serial
+
driver.
+
+
Some people derive their code from the standard serial driver. Unfortunately
+
this is a very daunting task. The 'drivers/char/serial.c' file has over 6000
+
lines of code!
+
+
Fortunately, there is an alternative [THANKS: Fillod Stephane]. There is a
+
generic serial driver, 'drivers/char/generic_serial.c'. This file provides a
+
set of serial routines that are hardware independent. Then your task is to
+
provide only the routines that are hardware dependent such as the interrupt
+
handler routine and low-level I/O functions. There are plenty of examples. Just
+
look inside the 'drivers/char/Makefile' and look for drivers that link with
+
'generic_serial.o' file.
+
+
[HELP: Would appreciate if you can share your experience of writing proprietary
+
serial driver code or using the 'generic_serial.c' file.]
+
+
Chapter 6: KGDB
+
+
For many Linux kernel developers, KGDB is a life-saving tool. With KGDB, you
+
can debug the kernel while it runs! You can set breakpoints or do single
+
stepping at the source code level.
+
+
To do this, you will need a dedicated serial port on your target, and use a
+
crossover-cable (also known as a null-modem) to connect it to your development
+
host. If you are also using a serial console, this implies you will need two
+
serial ports on your target. It is possible to do both kernel debug and serial
+
console through a single serial port. This will be mentioned later in this
+
chapter.
+
+
When you configure the kernel, select the 'Remote GDB kernel debugging' which
+
is listed under "Kernel hacking". Do a 'make clean' and recompile the kernel so
+
that debugging symbols are compiled into your kernel image. Try to make a new
+
image. You will soon discover two missing symbols in the final linking stage:
+
+
    arch/mips/kernel/kernel.o: In function `getpacket':
+
    arch/mips/kernel/kernel.o(.text+0x85ac): undefined reference to `getDebugChar'
+
    arch/mips/kernel/kernel.o(.text+0x85cc): undefined reference to `getDebugChar'
+
    arch/mips/kernel/kernel.o(.text+0x8634): undefined reference to `getDebugChar'
+
    arch/mips/kernel/kernel.o(.text+0x864c): undefined reference to `getDebugChar'
+
    arch/mips/kernel/kernel.o(.text+0x8670): undefined reference to `putDebugChar'
+
    arch/mips/kernel/kernel.o(.text+0x8680): undefined reference to `putDebugChar'
+
    arch/mips/kernel/kernel.o(.text+0x8698): undefined reference to `putDebugChar'
+
    arch/mips/kernel/kernel.o(.text+0x86a0): undefined reference to `putDebugChar'
+
+
+
You need to supply these two functions for your own boards:
+
+
    int putDebugChar(uint8 byte)
+
    uint8 getDebugChar(void)
+
+
+
As an example, here is the dbg_io.c for DDB5476 board. DDB5476 uses a standard
+
UART serial port to implement those two functions.
+
+
After supplying those two functions, you are ready to debug the kernel. Run the
+
new kernel image. If you also use the early printk patch, you should be able to
+
see something like this on your console:
+
+
    Wait for gdb client connection ...
+
+
+
Assuming you have already connected a cross-over serial cable between the
+
dedicated serial port on the target and a serial port on your host (say, COM0),
+
you can then set the appropriate baud rate and start the cross gdb on your
+
host:
+
+
    stty -F /dev/ttyS0 38400
+
    mipsel-linux-gdb vmlinux
+
+
+
At the gdb prompt, type
+
+
    target remote /dev/ttyS0
+
+
+
And, voila! You should be talking to the kernel through KGDB - if you are lucky
+
enough!
+
+
A couple of tips on using KGDB:
+
+
  \uffff\uffff\uffff Any functions preceded with the '__init' label will not break very well
+
    with breakpoints. Sometimes it will screw up the line numbers of other
+
    functions in the same file. Try undefining __init to be an empty macro in
+
    your 'include/linux/init.h' file. Refer to the patch. [NOTE: This problem
+
    is fixed in the latest gdb version, at least in gdb 5.2]
+
  \uffff\uffff\uffff Sometimes if you break on a function, you cannot see the correct value in
+
    variables and cannot do back-tracing. This is probably because certain
+
    registers are still not initialized [HELP: because kernel is compiled with
+
    -O2 flag?]. Step into the function a couple of lines, and you should see
+
    the variable and back-tracing fine.
+
+
What if the board only has one serial port?
+
+
Some boards only have one serial port. If you use it as serial console, you
+
cannot really use it for KGDB - unless you do some tricks to it.
+
+
There are two solutions. One is GDB console, and the other is to use a KGDB
+
demuxing script.
+
+
It is easy to use the GDB console. When you select 'Remote GDB kernel
+
debugging' under the 'Kernel hacking' sub-menu, you are also prompted for
+
'Console output to GDB'. Simply selecting that choice will work! In fact, this
+
option is so easy to use you might want to use it even if you have a second
+
serial port.
+
+
However, this option has a limit. When the kernel goes to userland, the console
+
stops working. This is because the KGDB stub in the kernel and GDB are not
+
designed to provide interactive output. [HELP: any volunteers?]
+
+
The second option uses a script called 'kgdb_demux' written by Brian Moyle. It
+
creates two virtual ports, typically ttya0 and ttya1. It then listens to the
+
real serial port (such as ttyS0). It will forward console traffic to ttya0 and
+
KGDB traffic to ttya1. All you have to do then is to start minicom on /dev/
+
ttya0 (port setting does not matter) and KGDB on /dev/ttya1.
+
+
You can download the tarball here. A couple of usage tips.
+
+
  \uffff\uffff\uffff Untar the file to some place.
+
  \uffff\uffff\uffff Copy kgdb_demux script to your execution path, and modify it properly.
+
  \uffff\uffff\uffff Set the port parameters properly before you start kgdb_demux.
+
+
Chapter 7 : CPU support
+
+
In the MIPS world, there are different families of MIPS cores. For example
+
Toshiba TX49, SiByte SB1, NEC VR41XX, MIPS32, and MIPS64 to name a few. These
+
different families may have different cache architectures, may be 32-bit or
+
64-bit, and may or may not have a FP unit. A complete list of families is found
+
in the 'arch/mips/config-shared.in' and 'include/asm-mips/cpu.h' files. When
+
you are configuring your kernel the complete list will appear under the 'CPU
+
type' menu selection. If you are adding support for an entirely new family of
+
MIPS cores, you will need to change the following files:
+
+
  \uffff\uffff\uffff arch/mips/config-shared.in - You will need to add your processor family to    the list under 'CPU type'.
+
  \uffff\uffff\uffff include/asm-mip/cpu.h - You will need to add a PRID_COMP and PRID_IMP
+
    entries for your processor family if they do not already exist. You will
+
    also need to then add the CPU types that you will support in that family.
+
    Adding CPU types is covered below.
+
  \uffff\uffff\uffff arch/mips/kernel/cpu-probe.c - For each processor family, there is
+
    typically a cpu_probe_XXX function that probes and fills in the struct
+
    cpuinfo_mips which contains information about the CPU type, whether a FP
+
    unit exists, the number of TLBs available, etc. Your function is
+
    responsible for properly probing and filling in this information for the
+
    entire family of processors. Finally, if your family does something special
+
    for CPU idle, then you will have to define a 'wait' function. Most likely,
+
    you will be able to use one that already exists. If not, add your 'wait'
+
    function and enable detection of it in check_wait.
+
  \uffff\uffff\uffff arch/mips/mm - If your processor family has a unique cache architecture or    anything out of the ordinary, you will need to either add or modify files
+
    in this directory.
+
+
Within each family of MIPS cores, there are multiple processors. For example,
+
Alchemy processors and Broadcom processors are in the MIPS32 family, the Sibyte
+
1250 is in the SB1 family, and so on. Once you have decided what family your
+
processor is in, you need to verify that a unique CPU identification exists for
+
it. The 'include/asm-mips/cpu.h' file contains all of the currently supported
+
CPU types for the Linux/MIPS kernel.
+
+
If your processor is already listed in the 'include/asm-mips/cpu.h' file, the
+
existing Linux/MIPS code should auto-detect it. If your processor is not
+
listed, you will need to change three files to properly detect your processor:
+
+
  \uffff\uffff\uffff include/asm-mip/cpu.h - Add your processor at the end of the CPU_XXX
+
    definitions. Make sure you update the 'CPU_LAST' value to match that of the
+
    processor you added.
+
  \uffff\uffff\uffff arch/mips/kernel/proc.c - Add an entry to the cpu_name array so that your
+
    CPU name can be properly displayed in /proc/cpuinfo.
+
  \uffff\uffff\uffff arch/mips/kernel/cpu-probe.c - Add your processor into the case statement
+
    in the function check_wait if your CPU can do some sort of wait or idle
+
    operation. Add the necessary code in the cpu_probe_XX function to detect
+
    and set your CPU type.
+
+
Once you have support for your processor family and specific CPU type, you
+
should be able to take full advantage of its capabilities.
+
+
Chapter 8 : Board support - interrupts
+
+
It you followed the previous steps, most likely you will see kernel hanging at
+
the BogusMIPS calibration step. The reason is simple: The interrupt code is not
+
there and jiffies are never updated. Therefore the calibration can never be
+
done.
+
+
Before you start writing interrupt code, it really pays to study the hardware
+
first. Pay particular attention to identify all interrupt sources, their
+
corresponding controllers and how they are routed.
+
+
Then you need to come up with a strategy, which typically includes:
+
+
  \uffff\uffff\uffff a static interrupt routing map
+
  \uffff\uffff\uffff a list of interrupt sources
+
  \uffff\uffff\uffff a list of their corresponding controllers
+
  \uffff\uffff\uffff how interrupt controllers cascade from each other
+
+
Interrupt code overview
+
+
To completely service an interrupt, four different pieces of code work
+
together:
+
+
IRQ detection/dispatching
+
    This is typically assembly code in a file called 'int_handler.S'. Sometimes
+
    there is also secondary-level dispatching code written in C for complicated
+
    IRQ detection. The end result is that we identify and select a single IRQ
+
    source, represented by an integer, and then pass it to function 'do_IRQ()'.
+
do_IRQ()
+
    do_IRQ() is provided in the 'arch/mips/kernel/irq.c' file. It provides a
+
    common framework for IRQ handling. It invokes the individual IRQ controller
+
    code to enable/disable a particular interrupt. It calls the driver supplied
+
    interrupt handling routine that does the real processing.
+
hw_irq_handler
+
    It is a structure associated with each IRQ source. The structure is a
+
    collection of function pointers, which tells do_IRQ() how it should deal
+
    with this particular IRQ.
+
driver interrupt handling code
+
    The code that does the real job.
+
+
Obviously for our porting purposes we need to write IRQ detection/disptaching
+
code and the hw_irq_handler code for any new IRQ controller used in the system.
+
In addition, there is also IRQ setup and initialization code.
+
+
CPU as an IRQ controller
+
+
Most R4K-compatible MIPS CPUs have the ability to support eight interrupt
+
sources. The first two are software interrupts, and the last one is typically
+
used for CPU counter interrupt. Therefore you can have up to five external
+
interrupt sources.
+
+
Luckily if the CPU is the only IRQ controller in the system, you are done! The
+
hw_irq_handler code is written in arch/mips/kernel/irq_cpu.c file. All you have
+
to do is to define "CONFIG_IRQ_CPU" for your machine. And in your irq setup
+
routine make sure you call mips_cpu_irq_init(0). This call will initialize the
+
interrupt descriptor and set up the IRQ numbers to range from 0 to 7.
+
+
You can also find a matching interrupt dispatching code in this file.
+
+
Set up cascading interrupts
+
+
More than likely you will have more interrupt sources than those that can
+
directly connect to the CPU interrupt pins. A second or even third-level
+
interrupt controller may connect to one or more of those CPU pins. In that
+
case, you have cascading interrupts.
+
+
There are plenty of examples of how cascading interrupt works, such as the
+
DDB5477 and the Osprey. Here is a short summary:
+
+
  \uffff\uffff\uffff Assign blocks of IRQ numbers to various interrupt controllers in the whole    system. For example, in the case of the Osprey, CPU interrupts occupy IRQ 0
+
    to 7. Vr4181 system interrupts occupy IRQ 8 to 39, and GPIO interrupts
+
    occupy 40 to 56. In most cases, the actual IRQ numbers do not matter, as
+
    long as the driver knows which IRQ number it should use. However, if you
+
    have an i8259 interrupt controller and an ISA bus, you should try to assign
+
    IRQ number 0 to 16 for the i8259 interrupts because it will make the legacy
+
    PC drivers happy. (Please note before ~12/08/2001 in version 2.4.16 of the
+
    Linux kernel, the 'i8259.c' file set the base vector to be 0x20. If you use
+
    the IRQ acknowledgement cycle to obtain the interrupt vector, you will get
+
    an IRQ number from 0x20 to 0x2f. You will then need to substract 0x20 from
+
    the return value to get the correct IRQ number.)
+
  \uffff\uffff\uffff Write the 'hw_irq_controller' member functinos for your specific
+
    controllers. Note that CPU and i8259 already have their code written. You
+
    just need to define appropriate CONFIG options for your board. See the next
+
    sub-section for more details about writing 'hw_irq_controller' member
+
    functions.
+
  \uffff\uffff\uffff In your IRQ setup routine, initialize all the controllers, usually by
+
    calling 'interrupt_controller_XXX_init()' functions.
+
  \uffff\uffff\uffff In your IRQ setup routine, setup the cascading IRQs. This setup will enable
+
    interrupts for the upper interrupt controller so that the lower-level
+
    interrupts can cascade through once they are enabled. A typical way of
+
    doing this is to have a dummy 'irqaction struct' and setup as follows:
+
+
        static struct irqaction cascade =
+
                { no_action, SA_INTERRUPT, 0, "cascade", NULL, NULL };
+
+
        extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
+
+
        void __init <my>_irq_init(void)
+
        {
+
                ....
+
                setup_irq(CPU_IP3, &cascade);
+
        }
+
+
+
  \uffff\uffff\uffff You need to expand your interrupt dispatching code properly to identify the
+
    added interrupt sources. If the code is simple enough, you can do it in the
+
    same int_handler.S file. If it is more complicated, you may do it in a
+
    separate C function (such as in the DDB5476 board).
+
+
The hw_irq_controller struct
+
+
The 'hw_irq_controller structure' is a defined in the 'include/linux/irq.h'
+
file as an alias for the 'hw_interrupt_type' structure.
+
+
    struct hw_interrupt_type {
+
            const char * typename;
+
            unsigned int (*startup)(unsigned int irq);
+
            void (*shutdown)(unsigned int irq);
+
            void (*enable)(unsigned int irq);
+
            void (*disable)(unsigned int irq);
+
            void (*ack)(unsigned int irq);
+
            void (*end)(unsigned int irq);
+
            void (*set_affinity)(unsigned int irq, unsigned long mask);
+
    };
+
+
+
The 'arch/mips/kernel/irq_cpu.c' is a good sample code to write
+
'hw_irq_controller' member functions. Here are some more programming notes for
+
each of these functions:
+
+
    const char * typename;
+
        Controller name. Will be displayed under /proc/interrupts.
+
    unsigned int (*startup)(unsigned int irq);
+
        Invoked when request_irq() or setup_irq are called. You need to enable
+
        this interrupt here. Other than that you may also want to do some
+
        IRQ-specific initialization (such as turning on power for this
+
        interrupt, perhaps).
+
    void (*shutdown)(unsigned int irq);
+
        Invoked when free_irq() is called. You need to disable this interrupt
+
        and perhaps some other IRQ-specific cleanup.
+
    void (*enable)(unsigned int irq) and void (*disable)(unsigned int irq)
+
        They are used to implement enable_irq(), disable_irq() and
+
        disable_irq_nosync(), which in turn are used by driver code.
+
    void (*ack)(unsigned int irq)
+
        ack() is invoked at the beginning of do_IRQ() when we want to
+
        acknoledge an interrupt. I think you need also to disable this
+
        interrupt here so that you don't get recursive interrupts on the same
+
        interrupt source. [HELP: can someone confirm?]
+
    void (*end)(unsigned int irq)
+
        This is called by do_IRQ() after it has handled this interrupt. If you
+
        disabled interrupt in ack() function, you should enable it here. [HELP:
+
        generally what else we should do here?]
+
    void (*set_affinity)(unsigned int irq, unsigned long mask)
+
        This is used in SMP machines to set up interrupt handling affinity with
+
        certain CPUs. [TODO] [HELP]
+
+
The IRQ initialization code
+
+
The IRQ initialization is done in 'init_IRQ()'. Currently it is supplied by
+
each individual board. In the future, it will probably be a MIPS common
+
routine, which will further invoke a board-specific function, board_irq_init().
+
board_irq_init will be a function pointer that <my_board>_setup() function
+
needs to assign propoer value.
+
+
In any case, the following is a skeleton code for a normal init_IRQ() routine.
+
+
+
    extern asmlinkage void vr4181_handle_irq(void);
+
    extern void breakpoint(void);
+
    extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
+
    extern void mips_cpu_irq_init(u32 irq_base);
+
    extern void init_generic_irq(void);
+
+
    static struct irqaction cascade =
+
            { no_action, SA_INTERRUPT, 0, "cascade", NULL, NULL };
+
    static struct irqaction reserved =
+
            { no_action, SA_INTERRUPT, 0, "reserved", NULL, NULL };
+
    static struct irqaction error_irq =
+
            { error_action, SA_INTERRUPT, 0, "error", NULL, NULL };
+
+
    void __init init_IRQ(void)
+
    {
+
            int i;
+
            extern irq_desc_t irq_desc[];
+
+
            /* hardware initialization code */
+
            ....
+
+
            /* this is the routine defined in int_handler.S file */
+
            set_except_vector(0, my_irq_dispatcher);
+
+
            /* setup the default irq descriptor */
+
            init_generic_irq();
+
+
            /* init all interrupt controllers */
+
            mips_cpu_irq_init(CPU_IRQ_BASE);
+
            ....
+
+
            /* set up cascading IRQ */
+
            setup_irq(CPU_IRQ_IP3, &cascade);
+
+
            /* set up reserved IRQ so that others can not mistakingly request
+
            * it later.
+
            */
+
            setup_irq(CPU_IRQ_IP4, &reserved);
+
+
    #ifdef CONFIG_DEBUG
+
            /* setup debug IRQ so that if that interrupt happens, we can
+
            * capture it.
+
            */
+
            setup_irq(CPU_IRQ_IP4, &error_irq);
+
    #endif
+
+
    #ifdef CONFIG_REMOTE_DEBUG
+
            printk("Setting debug traps - please connect the remote debugger.\n");
+
            set_debug_traps();
+
            breakpoint();
+
    #endif
+
    }
+
+
+
+
Final notes
+
+
What is described in this chapter is what is so-called new style interrupt
+
handling. We used to have three different ways to handle interrupts: new style
+
(CONFIG_NEW_IRQ), the old style (CONFIG_ROTTEN_IRQ) and board-private ad hoc
+
routines. New style is now the only valid method since October 2002.
+
+
Chapter 9 : Board support - system time and timer
+
+
Linux relies on an RTC (real-time clock) device to obtain the real calendar
+
data and time when it boots up. It relies on a system timer to advance the tick
+
count, jiffies. If you don't provide proper time and timer code, Linux won't
+
run. In fact it will stick in 'calibrate_delay()' during the startup process
+
because jiffies is never incremented. (See Appendix B for more details about
+
Linux/MIPS startup sequence).
+
+
There is an excellent document (I becomes a little shameless. :-0) under
+
'Documentations/mips/time.README' that should be read to further understand
+
timekeeping for Linux/MIPS. It is a must read.
+
+
Here are some comments on implementing time and timer services:
+
+
  \uffff\uffff\uffff If your system has a CPU counter and another hardware timer, use the
+
    hardware timer over the CPU counter, even though CPU counter might be
+
    easier to setup and use. This is because CPU counter relies on the CPU
+
    frequency which is more likely to change in the future. In addition,
+
    performance-critical code may need to access the CPU counter for its own
+
    measurements. Some CPUs may have a variable CPU frequency which makes CPU
+
    counter not usable as a timer source. [DEBATE: 03/12/04, I changed my
+
    preference on this issue. Linux in the future will have richer and higher
+
    resolution time support. If all MIPS boards use CPU counter as the system
+
    timer, we can maximize the code sharing.]
+
  \uffff\uffff\uffff Unless you have to use interrupts to calibrate the CPU frequency, you can
+
    generally avoid implementing the 'board_time_init()' function. Most of its
+
    work can be done in the board setup routine.
+
  \uffff\uffff\uffff When you implement 'rtc_set_time()', more than likely you need to call the    'to_tm()' function which converts a single jiffy value to a full 'struct
+
    rtc_time'. This function is provided in 'arch/mips/kernel/time.c' and
+
    declared in 'include/asm-mips/time.h'.
+
+
Chapter 10 : Board support - PCI subsystem
+
+
The PCI subsystem is perhaps the most complex code you have to deal with during
+
the porting process. The key to making the PCI subsystem work properly is a
+
good understanding of the PCI bus itself, the code layout, and the execution
+
flow in Linux. Like many other parts of porting, you will find in the end, the
+
actual code writen is minimumal.
+
+
References
+
+
Pete Popov wrote a fine document on PCI and Linux/MIPS. It is under
+
'Documentation/mips/pci/pci.README'. It is highly recommended reading.
+
+
For those who want to know more about the PCI bus itself, I recommend the book
+
PCI System Architecture published by MindShare Inc.
+
+
Overview of the PCI bus
+
+
Here we summarize some facts of the PCI bus:
+
+
  \uffff\uffff\uffff The PCI bus has three separate address spaces, config, I/O, and memory
+
    space.
+
  \uffff\uffff\uffff Every PCI device responds to config commands, and it can respond to I/O
+
    accesses and/or memory accesses.
+
  \uffff\uffff\uffff During the boot time, the BIOS or the OS sets the base address registers
+
    (BARs) through configuration space. BARs determine address ranges in I/O or
+
    memory space that a device should respond to. Obviously, those ranges
+
    should not be duplicated anywhere else in the I/O space or memory space on
+
    the same PCI bus.
+
  \uffff\uffff\uffff Multiple PCI buses can be connected through PCI-PCI bridges.
+
+
BAR assignment in Linux
+
+
On all IBM PC-compatible machines, BARs are assigned by the BIOS. Linux simply
+
scans through the buses and records the BAR values.
+
+
Some MIPS boards adopt similar approaches, where BARs are assigned by firmware.
+
However, the quality of BAR assignment by firmware vary quite a bit. Some
+
firmware simply assigns BARs to on-board PCI devices and ignore all add-on PCI
+
cards. In that case, Linux cannot solely rely on the firmware's assignment.
+
+
There is another issue of depending on the firmware assignment. You need to
+
stick with the address range setup by the firmware. In other words, if the
+
firmware assigns PCI memory space from 0x10000000 to 0x14000000, you cannot
+
easily move it to a different address space somewhere else in Linux.
+
+
There three ways to possibly fix this:
+
+
  \uffff\uffff\uffff The first way is to fix the BAR assignment manually in your board setup
+
    routine. This only works if your board does not have a PCI slot to plug in
+
    an arbitrary PCI card. You need to carefully examine the existing PCI
+
    resource assignment done by firmware so that you do not assign overlapping
+
    address ranges.
+
  \uffff\uffff\uffff The second way is to do a complete PCI resource assignment *before* Linux
+
    starts PCI bus scanning. In other words, we discard any PCI resource
+
    assignment done in firmware, if there is any, and do a new assignment by
+
    ourselves. This approach gives us complete control over the address range
+
    and resource allocation. With the CONFIG_PCI_AUTO option used in 'arch/mips
+
    /config-shared.in' and 'arch/mips/kernel/pci_auto.c' file, it turns out to
+
    be quite easy to do. This approach is the focus of this chapter.
+
  \uffff\uffff\uffff Another approach is to call the 'pci_assign_unassigned_resources()'
+
    function, which is defined in the 'drivers/pci/setup-bus.c' file in recent
+
    2.4.x kernels *after* Linux completes the PCI bus scan. With earlier
+
    versions of this function, Linux will assign resources to PCI devices whose
+
    BAR have *not* been properly assigned. With the recent versions (that have
+
    "optimal" resource assignment based on sizes), this PCI routine apparently
+
    does a complete resource re-assignment. In other words, it does almost
+
    exactly the same as what the 'pci_auto.c' file does.
+
+
[DEBATE] The 'pci_auto' and 'assign_unassigned_resource' approaches have their
+
own advantages and disadvantages. Ideally, the whole PCI subsystem should be
+
completely re-written so that several things can be taken into consideration
+
which are not currently addressed:
+
+
  \uffff\uffff\uffff A notion of a host-PCI controller, and supporting multiple host-PCI
+
    controllers.
+
  \uffff\uffff\uffff A kernel-independent abstraction layer to access configuration space,
+
    distinguishing Type 0 and Type 1 configuration accesses. This removes the
+
    need for 'pci_dev' in the lowest-level PCI routines.
+
  \uffff\uffff\uffff Pass 1 scan to do bus number assignment and record bus topology through the
+
    top-level host-PCI controller structure.
+
  \uffff\uffff\uffff Pass 2 scan to discover all other PCI devices and assign the resources
+
    along the way.
+
  \uffff\uffff\uffff If we want to do optimal resource assignment, we need to do the resource
+
    assignment in Pass 3 instead of Pass 2.
+
  \uffff\uffff\uffff A complete PCI device list is built during the above passes.
+
  \uffff\uffff\uffff The address range for PCI memory space and I/O space are set when host-PCI    controller structures are initially created.
+
+
PCI startup sequence
+
+
1. do_basic_setup() calls pci_init(), which is defined in 'drivers/pci/pci.c'.
+
2. pci_init() first calls pcibios_init(). If you enable CONFIG_NEW_PCI,
+
    pcibios_init() is implemented in the 'arch/mips/kernel/pci.c' file.
+
    Otherwise you need to provide it in your own board-dependent code.
+
3. Optionally, pcibios_init() may call pciauto_assign_resources() to do a
+
    complete PCI resource assignment.
+
4. Somewhere inside pcibios_init(), pci_scan_bus() is called. If a machine has
+
    multiple host-PCI controllers, pci_scan_bus() should be called for each of
+
    the top-level PCI buses. Apparently, bus numbers should have already been
+
    setup before pci_scan_bus() can properly run.
+
5. Optionally, after pci_scan_bus() is called, pcibios_init() may choose to
+
    call pci_assign_unassigned_resources() to do a complete PCI resource
+
    assignment.
+
6. pcibios_init() will do some more fixups (resources, IRQs, etc.).
+
7. Returning from pcibios_init(), pci_init() will do a final round of
+
    device-based fixups.
+
+
In this chapter, we focus on the approach where both CONFIG_NEW_PCI and
+
CONFIG_PCI_AUTO are enabled.
+
+
PCI driver interface
+
+
All of this work for PCI is to eventually setup a structure where all PCI
+
device drivers can run happily. Knowing how PCI device drivers access PCI
+
resources can greatly help you understand how you should do PCI initialization
+
and setup.
+
+
  \uffff\uffff\uffff inb()/outb()/inw()/outw()/inl()/outl()
+
    Defined in 'include/asm-mips/io.h'. Drivers use these macros to read/write
+
    into PCI IO space. The address arguments are addresses in PCI IO space, and
+
    should correspond to one of the BAR values of the device. On MIPS machines,
+
    we assume PCI IO space is mapped into a contiguous physical address block.
+
    The base address of the block is mips_io_port_base, which you need to set
+
    up at the beginning of board setup time. The proper way to set it up is
+
    call set_io_port_base().
+
  \uffff\uffff\uffff readb()/writeb()/readw()/writew()/readl()/writel()
+
    Defined in the 'include/asm-mips/io.h' file. Drivers use them to access PCI
+
    memory space. On MIPS machines, we assume PCI memory space is 1:1 mapped
+
    into a block of physical address. Therefore those macros are equivalent to
+
    direct physical memory access.
+
  \uffff\uffff\uffff pci_read_config_word() and friends
+
    Defined in 'include/linux.pci.h' (through PCI_OP()). Drivers use them to
+
    read or write the configuration registers of devices. Low-level routines
+
    are abstracted as struct pci_ops, where each board must supply one.
+
  \uffff\uffff\uffff pci_map_single() and friends
+
    Defined in 'include/asm-mips/pci.h'. Drivers use these macros to map a
+
    virtual address to a bus address (so you can tell the device to do DMA).
+
    They don't usually affect PCI porting.
+
+
Setting up the host-PCI controller
+
+
As we can see from the above discussion, we need to set up the host-PCI
+
controller such that:
+
+
1. It has a 1:1 mapping between PCI memory space and CPU physical address
+
    space
+
2. It maps the beginning part of PCI IO space into a address block in physical
+
    address space.
+
+
The Host-PCI controller usually allows you to map PCI memory space into a
+
window in physical address space. Let us say the base address is ba_mem and
+
size is sz_mem. It usually allows you to translate that address into another
+
one with a fixed offset, say off. (Note off can be both positive or negative).
+
So if a driver accesses the address ba_mem+x (0 <= x < sz_mem), the host-PCI
+
controller will intercept the command and translate it into a PCI memory access
+
at address ba_mem+off+x.
+
+
To maintain 1:1 mapping, it implies we must set up the PCI addressing such that
+
off is 0. Also note that with this setup, we cannot access the PCI memory range
+
[0x0, ba_mem] and [ba_mem + sz_mem, 0xffffffff].
+
+
Additionaly, we must also make system RAM visible on the PCI memory bus at
+
address 0x0 (assuming that is the address in physical address space) in order
+
for PCI devices to do DMA transfers.
+
+
The beginning part of PCI IO space is usually mapped into another window in
+
physical address space, say [ba_io, ba_io + sz_io]. In other words, a range [0,
+
sz_io] in PCI IO space corresponds to the range [ba_io, ba_io + sz_io].
+
Obviously, mips_io_port_base should be set to ba_io.
+
+
The above setup is typically done in the board-specific setup routine (i.e.,
+
<board>_setup()). You typically also setup ioport_resource and iomem_resource
+
as well:
+
+
            ioport_resource.start = 0x0;
+
            ioport_resource.end = sz_io;
+
            iomem_resource.start = 0x0;
+
            iomem_resource.end = sz_mem;
+
+
+
These variables are the roots of all IO and memory resources (roughly
+
corresponding to the ancient ISA IO space and ISA memory space). For simplicity
+
you can also set the end to be 0xffffffff.
+
+
Board-specific functions and variables
+
+
Here is a list of board-specific functions you must implement. Again, I assume
+
this board has CONFIG_NEW_PCI and CONFIG_PCI_AUTO options enabled.
+
+
  \uffff\uffff\uffff struct pci_ops my_pci_ops
+
    You implement six functions to fill into this structure, which is needed by
+
    pci_scan_bus() and pciauto_assign_resources(). Note that you need to
+
    dintinguish type 0 or type 1 configuration in those functions. You can
+
    typically check that by checking whether the bus's parent (dev->bus->
+
    parent) is NULL.
+
  \uffff\uffff\uffff mips_pci_channels[]
+
    You need to define this array in order to use pciauto resource assignment.
+
    For each top-level PCI bus, you need to supply an element data to this
+
    array. The array ends with an all-NULL element. Each element is a structure
+
    that consists a pci_ops, pci_io_resource, and pci_mem_resource, which
+
    usually represents a top-level PCI bus connected to CPU. pci_ops defines
+
    the functions access the PCI bus's config space. pci_io_resource and
+
    pci_mem_resource specifies the address range that pciauto will use to
+
    assign to the BARs of PCI devices. For pci_io_resource, it starts with 0x0
+
    (or 0x1000 to leave some room for legacy ISA devices), and it ends at
+
    sz_io. For pci_mem_resource, it starts at ba_mem and ends at ba_mem +
+
    sz_mem. Note these addresses are in PCI IO and PCI memory space
+
    respectively. However, since we maintain 1:1 mapping between PCI memory
+
    space and CPU physical address space, pci_mem_resource also represents the
+
    PCI memory space window in CPU physical address space.
+
  \uffff\uffff\uffff pcibios_fixup_resources()
+
    This routine is passed to pci_scan_bus() and invoked right after when the
+
    PCI device is discovered. This is place where you can do some
+
    device-specific fixup (BARs, pci_dev structure, etc). Note you can do the
+
    same fixup in pcibios_fixup(). I recommand leave this function empty unless
+
    you have some specific need that requires immediate fixup.
+
  \uffff\uffff\uffff pcibios_fixup()
+
    This function is invoked after pci_scan_bus() is done, i.e., all PCI
+
    bridges and devices are discovered by Linux. Here you can enumerate through
+
    PCI devices and do device based fixup. Or you can do bus or contoller
+
    related fixups.
+
  \uffff\uffff\uffff pcibios_fixup_irqs()
+
    This is the place to fix up PCI related IRQs. It is invoked after
+
    pci_scan_bus() is done and next to pcibios_fixup(). A typical strategy is
+
    to assign irq based on the slot number and possibly bus number if there are
+
    more than top-level buses in the system. Note that you can do the fixup in
+
    pcibios_fixup() as well and leave this function empty.
+
  \uffff\uffff\uffff pcibios_assign_all_busses()
+
    Return 1 to indicate that all bus numbers have been assigned by pciauto.
+
    [TODO:Should this function be included in pciauto by default?][TODO: the
+
    driver/pci/pci.c file seems to have a typo when it calls this function. The
+
    logic is inversed.]
+
+
Tips for writting PCI code
+
+
  \uffff\uffff\uffff Some ill-behaviored PCI device may spoil the party. The best way to deal
+
    with them is to signle them out in the PCI configuration routines (in
+
    pci_ops). Inside those routines you check for the slot number and function
+
    number corresponding to the bad devices and return some NULL numbers.
+
  \uffff\uffff\uffff If you have mulitple top-level PCI buses, it is tricky to do PCI IO
+
    assignment. Assume you have two PCI buses and their IO spaces are mapped
+
    into [ba_io1, ba_io1 + sz_io1] and [ba_io2, ba_io2+sz_io2] (ba_io1 + sz_io1
+
    <= ba_io2). You need to
+
    1. Set mips_io_port_base to be ba_io1
+
    2. Set pci_io_resource to be [0x0, sz_io1] for the first PCI bus
+
    3. Set pci_io_resource to be [ba_io2 - ba_io1, ba_io2 - ba_io1 + sz_io2]
+
        for the 2nd PCI bus. In addition, the legacy ISA devices on the second
+
        PCI bus cannot be used without modifying their drivers.
+
+
Chapter 11 : Ether drivers and networking
+
+
[TODO]
+
+
Chapter 12 : Romfs root filesystem
+
+
[TODO]
+
+
Chapter 13 : Debugging
+
+
Although it is the last chapter, it is probably the most necessary one. In this
+
chapter, I will list some commonly used debugging tips and tricks.
+
+
Kernel Oops
+
+
ksymoops is a program that deciphers all the secret numbers in a kernel core
+
dump. Old versions of ksymoops may not work well for MIPS.
+
+
I sometimes use a script, call2sym, written by Phil Hollenback. You just cut
+
and past the call trace part to feed the script and it will display a possible
+
function call stack at the time crash. Note it is likely some symbols are
+
bogus, but the real ones should be displayed. You will have to use your own
+
judgement.
+
+
In 2.6, the brack trace is automatically printed for you when a kernel core
+
dump happens.
+
+
Appendix A: Linux startup sequence in 2.4.x
+
+
+
    kernel_entry() - arch/mips/kernel/head.S
+
      set stack;
+
      prepare argc/argp/envp;
+
      jal init_arch - arch/mips/kernel/setup.c
+
            cpu_probe() -
+
            prom_init(...) - arch/mips/ddb5074/prom.c
+
            loadmmu()
+
            start_kernel()  - init/main.c
+
                    setup_arch(&commaind_line); - arch/mips/kernel/setup.c
+
                            ddb_setup()        - arch/mips/ddb5074/setup.c
+
                    parse_options(command_line);
+
                    trap_init();
+
                    init_IRQ();                - arch/mips/kernel/irq.c
+
                    sched_init();
+
                    softirq_init();
+
                    time_init();
+
                            if (board_time_init) board_time_init();
+
                            set xtime by calling rtc_get_time();
+
                            pick appropriate do_gettimeoffset()
+
                            board_timer_setup(&timer_irqaction);
+
                    console_init();
+
                    init_modules();
+
                    kmem_cache_init();
+
                    sti();                  /* interrupt first open */
+
                    calibrate_delay();
+
                    mem_init();
+
                    kmem_cache_sizes_init();
+
                    pgtable_cache_init();
+
                    fork_init();
+
                    proc_caches_init();
+
                    vfs_caches_init();
+
                    buffer_init();
+
                    page_cache_init();
+
                    signals_init();
+
                    smp_init();
+
                    kernel_thread(init, ...)
+
                    cpu_idle();
+
+
+
    init() - init/main.c
+
      - lock_kernel();
+
        do_basic_setup();
+
          - [MTRR] mtrr_init();
+
            [SYSCTL] sysctl_init();
+
            [S390] s390_init_machine_check();
+
            [ACPI] acpi_init();
+
            [PCI] pci_init();
+
            [SBUS] sbus_init();
+
            [PPC] ppc_init();
+
            [MCA] mca_init();
+
            [ARCH_ACORN] ecard_init();
+
            [ZORRO] zorro_init();
+
            [DIO] dio_init();
+
            [MAC] nubus_init();
+
            [ISAPNP] isapnp_init();
+
            [TC] tc_init();
+
            sock_init();
+
            start_context_thread();
+
            do_initcalls();
+
            [IRDA] irda_proto_init();
+
            [IRDA] irda_device_init();
+
            [PCMCIA] init_pcmcia_ds();
+
+
        prepare_namespace();
+
        free_initmem();
+
        unlock_kernel();
+
+
        files = current->files;
+
        if(unshare_files())
+
                panic("unshare");
+
        put_files_struct(files);
+
+
        if (open("/dev/console", O_RDWR, 0) < 0)
+
                    printk("Warning: unable to open an initial console.\n");
+
        (void) dup(0);
+
        (void) dup(0);
+
+
        if (execute_command)
+
                    run_init_process(execute_command);
+
        run_init_process("/sbin/init");
+
        run_init_process("/etc/init");
+
        run_init_process("/bin/init");
+
        run_init_process("/bin/sh");
+
+
        panic("No init found.  Try passing init= option to kernel.");
+
+
+
+
Appendix B: Credits and thanks
+
+
People in the following list have generously given their feedback to me. In
+
spite of my effort to keep the list as complete as possible, I am afraid many
+
people are still missing here.
+
+
            Dirk Behme <dirk.behme@de.bosch.com>
+
            Fillod Stephane <FillodS@thmulti.com>
+
            Geoffrey Espin <espin@idiom.com>
+
            Gerald Champagne <gerald.champagne@esstech.com>
+
            Henri Girard <khgirard@broadbandnetdevices.com>
+
            Neal Crook <ncrook@micron.com>
+
            Steven J. Hill <James.Hill@timesys.com>
+
            TAKANO Ryousei <takano@axe-inc.co.jp>
+
+
+
Appendix C: Change logs
+
+
2004/03/29
+
    Include the second batch of changes and updates from Steven Hill (Humongous
+
    thanks!). The content is more less current with respect to 2.4 tree. Notes
+
    for porting to 2.6 will hopefully follow soon.
+
2004/01/26
+
    Included initial batch of changes and updates from Steven Hill (Big
+
    thanks!). External links are now shown in a separate window.
+
2002/08/23
+
    Add change log. Make external links the _top frame. Update tools (thanks to
+
    Henri Girard)
+
2002/12/11
+
    Incorporate comments from Neal Crook.
+

Latest revision as of 02:55, 23 October 2005