* Re: Recently removed io accessors
From: Peter Korsgaard @ 2006-10-13 8:43 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: sfr, linuxppc-dev
In-Reply-To: <1160724670.4792.195.camel@localhost.localdomain>
>>>>> "BH" == Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:
Hi,
BH> Well, I still don't see it. It all depends how the HW has been
BH> wired I suppose but you should not need byteswap regardless of the
BH> 32 bits being broken in packs of 2x16 bits or whatever... If the
BH> chip has a HW byteswap for registers and not for the packet
BH> buffer, that makes it even more clear that such swapping should
BH> not be necessary.
Ok, a bit of details:
We're using the smsc9117
(http://www.smsc.com/main/datasheets/9117.pdf) connected over a 16bit
EMC bus (together with a spansion 29PL127 flash) to a Xilinx V4FX FPGA
with a 405 core in it.
LSB of the processor is connected to LSB of of the 9117 (and same for
the flash) and so on.
Reading the byte test register of the 9117 (supposed to contain
0x87654321) gives:
Endian register set to little endian (default at powerup):
RedBoot> x -b 0x8e000064 -2 -l 4
8E000064: 4321 8765
RedBoot> x -b 0x8e000064 -4 -l 4
8E000064: 43218765
And with it set to big endian:
RedBoot> x -b 0x8e000064 -2 -l 4
8E000064: 8765 4321
RedBoot> x -b 0x8e000064 -4 -l 4
8E000064: 87654321
So with this setup I need to enable the big endian mode to read
registers without byteswapping and use byteswapping for the packet
fifos.
If on the other hand the hw people had inverted the 2 byte lanes
(connected b0..b7 on the CPU to b8..b15, and b8..15 to b0..b7) I would
need to use byteswapping on the normal register accesses and no byte
swapping on the packet fifos.
They didn't unfortunately :/
BH> Unless the chip has been wired backward on the processor bus (in
BH> which case, btw, DMA will not work either unless you have one of
BH> those magically swapping dma controllers)..
True. We are not using DMA though.
BH> So I still claim that you should not need them and if you do, then
BH> the chip has probably been incorrect wired to your CPU bus. In
BH> which case, you can either grab an old copy of the functions and
BH> put them in your driver for your platform or add a cpu_to_leXX()
BH> loop to byteswap the data in/out, but it's probably not the right
BH> thing to do in the generic driver since it would be a problem
BH> specific to your board.
I could add another #ifdef CONFIG_<my board> to the smc911x.h to
select the right I/O accessors, but sticking the implementation of
_insl/_outsl in my platform file isn't that nice - Couldn't we put
them back in misc.S?
BH> Unless I'm missing something ... It would be useful to have more
BH> details about your setup.
I hope this makes it a bit more clear.
--
Bye, Peter Korsgaard
^ permalink raw reply
* [PATCH 5/5] powerpc: Cell timebase bug workaround
From: Benjamin Herrenschmidt @ 2006-10-13 8:04 UTC (permalink / raw)
To: linuxppc-dev list
The Cell CPU timebase has an errata. When reading the entire 64 bits of
the timebase with one mftb instruction, there is a handful of cycles
window during which one might read a value with the low order 32 bits
already reset to 0x00000000 but the high order bits not yet incremeted
by one. Simply reading the timebase a second time if the low order bits
are 0 is enough (the second read will always miss that window).
Note that there is still a potential issue if the process gets
interrupted between the 2 reads for long enough that the second reads
pricely hits that same window on the next 32 bits wrap. However, this is
so extremely unlikely to happen that we choose not to do anything
against it (the 32 bits wrap happens every few seconds or so, in fact
every few minutes on IBM cell blades).
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
This is the "old" patch adapted to apply on top of the previous changes.
I'll post a new version of the patch using a different technique for the
workaround asap. (should have been today but testing & debugging the
previous patches of this serie took more time than expected).
Index: linux-cell/arch/powerpc/kernel/vdso64/gettimeofday.S
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/vdso64/gettimeofday.S 2006-10-13 16:00:25.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/vdso64/gettimeofday.S 2006-10-13 16:59:41.000000000 +1000
@@ -229,8 +229,10 @@ V_FUNCTION_BEGIN(__do_get_xsec)
xor r0,r8,r8 /* create dependency */
add r3,r3,r0
- /* Get TB & offset it */
- mftb r7
+ /* Get TB & offset it. We use the MFTB macro which will generate
+ * workaround code for Cell.
+ */
+ MFTB(r7)
ld r9,CFG_TB_ORIG_STAMP(r3)
subf r7,r9,r7
Index: linux-cell/include/asm-powerpc/cputable.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/cputable.h 2006-10-13 16:58:13.000000000 +1000
+++ linux-cell/include/asm-powerpc/cputable.h 2006-10-13 16:59:41.000000000 +1000
@@ -143,6 +143,7 @@ extern struct cpu_spec *identify_cpu(uns
#define CPU_FTR_CI_LARGE_PAGE LONG_ASM_CONST(0x0000100000000000)
#define CPU_FTR_PAUSE_ZERO LONG_ASM_CONST(0x0000200000000000)
#define CPU_FTR_PURR LONG_ASM_CONST(0x0000400000000000)
+#define CPU_FTR_CELL_TB_BUG LONG_ASM_CONST(0x0000800000000000)
#ifndef __ASSEMBLY__
@@ -331,7 +332,7 @@ extern struct cpu_spec *identify_cpu(uns
#define CPU_FTRS_CELL (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
- CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE)
+ CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE | CPU_FTR_CELL_TB_BUG)
#define CPU_FTRS_PA6T (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \
Index: linux-cell/include/asm-powerpc/ppc_asm.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/ppc_asm.h 2006-10-13 16:00:25.000000000 +1000
+++ linux-cell/include/asm-powerpc/ppc_asm.h 2006-10-13 16:59:41.000000000 +1000
@@ -30,9 +30,9 @@ BEGIN_FTR_SECTION; \
mfspr ra,SPRN_PURR; /* get processor util. reg */ \
END_FTR_SECTION_IFSET(CPU_FTR_PURR); \
BEGIN_FTR_SECTION; \
- mftb ra; /* or get TB if no PURR */ \
+ MFTB(ra); /* or get TB if no PURR */ \
END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
- ld rb,PACA_STARTPURR(r13); \
+ ld rb,PACA_STARTPURR(r13); \
std ra,PACA_STARTPURR(r13); \
subf rb,rb,ra; /* subtract start value */ \
ld ra,PACA_USER_TIME(r13); \
@@ -45,9 +45,9 @@ BEGIN_FTR_SECTION; \
mfspr ra,SPRN_PURR; /* get processor util. reg */ \
END_FTR_SECTION_IFSET(CPU_FTR_PURR); \
BEGIN_FTR_SECTION; \
- mftb ra; /* or get TB if no PURR */ \
+ MFTB(ra); /* or get TB if no PURR */ \
END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
- ld rb,PACA_STARTPURR(r13); \
+ ld rb,PACA_STARTPURR(r13); \
std ra,PACA_STARTPURR(r13); \
subf rb,rb,ra; /* subtract start value */ \
ld ra,PACA_SYSTEM_TIME(r13); \
@@ -274,6 +274,18 @@ END_FTR_SECTION_IFSET(CPU_FTR_601)
#define ISYNC_601
#endif
+#ifdef CONFIG_PPC_CELL
+#define MFTB(dest) \
+ mftb dest; \
+BEGIN_FTR_SECTION_NESTED(96); \
+ cmpwi dest,0; \
+ bne+ 90f; \
+ mftb dest; \
+90: \
+END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96)
+#else
+#define MFTB(dest) mftb dest
+#endif
#ifndef CONFIG_SMP
#define TLBSYNC
Index: linux-cell/include/asm-powerpc/reg.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/reg.h 2006-10-13 16:00:25.000000000 +1000
+++ linux-cell/include/asm-powerpc/reg.h 2006-10-13 16:59:41.000000000 +1000
@@ -617,11 +617,34 @@
asm volatile("mfspr %0," __stringify(rn) \
: "=r" (rval)); rval;})
#define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v))
-
+#ifdef CONFIG_PPC_CELL
+#define mftb() ({unsigned long rval; \
+ asm volatile( \
+ " mftb %0;\n" \
+ "97: cmpwi %0,0;\n" \
+ " bne+ 99f;\n" \
+ " mftb %0;\n" \
+ "99:\n" \
+ ".section __ftr_fixup,\"a\"\n" \
+ ".align 3\n" \
+ "98:\n" \
+ " .llong %1\n" \
+ " .llong %1\n" \
+ " .llong 97b-98b\n" \
+ " .llong 99b-98b\n" \
+ ".previous" \
+ : "=r" (rval) : "i" (CPU_FTR_CELL_TB_BUG)); rval;})
+#else
#define mftb() ({unsigned long rval; \
asm volatile("mftb %0" : "=r" (rval)); rval;})
+#endif
+
+#ifndef __powerpc64__
#define mftbl() ({unsigned long rval; \
asm volatile("mftbl %0" : "=r" (rval)); rval;})
+#define mftbu() ({unsigned long rval; \
+ asm volatile("mftbu %0" : "=r" (rval)); rval;})
+#endif /* __powerpc64__ */
#define mttbl(v) asm volatile("mttbl %0":: "r"(v))
#define mttbu(v) asm volatile("mttbu %0":: "r"(v))
Index: linux-cell/include/asm-powerpc/time.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/time.h 2006-10-13 16:00:25.000000000 +1000
+++ linux-cell/include/asm-powerpc/time.h 2006-10-13 16:59:41.000000000 +1000
@@ -85,26 +85,28 @@ struct div_result {
/* On ppc64 this gets us the whole timebase; on ppc32 just the lower half */
static inline unsigned long get_tbl(void)
{
- unsigned long tbl;
-
#if defined(CONFIG_403GCX)
+ unsigned long tbl;
asm volatile("mfspr %0, 0x3dd" : "=r" (tbl));
+ return tbl;
+#elif defined(CONFIG_PPC32)
+ return mftbl();
#else
- asm volatile("mftb %0" : "=r" (tbl));
+ return mftb();
#endif
- return tbl;
}
static inline unsigned int get_tbu(void)
{
+#ifdef CONFIG_403GCX
unsigned int tbu;
-
-#if defined(CONFIG_403GCX)
asm volatile("mfspr %0, 0x3dc" : "=r" (tbu));
+ return tbu;
+#elif defined(CONFIG_PPC32)
+ return mftbu();
#else
- asm volatile("mftbu %0" : "=r" (tbu));
+ return mftb();
#endif
- return tbu;
}
static inline unsigned int get_rtcl(void)
Index: linux-cell/include/asm-powerpc/timex.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/timex.h 2006-10-13 16:58:13.000000000 +1000
+++ linux-cell/include/asm-powerpc/timex.h 2006-10-13 16:59:41.000000000 +1000
@@ -8,6 +8,7 @@
*/
#include <asm/cputable.h>
+#include <asm/reg.h>
#define CLOCK_TICK_RATE 1024000 /* Underlying HZ */
@@ -15,13 +16,11 @@ typedef unsigned long cycles_t;
static inline cycles_t get_cycles(void)
{
- cycles_t ret;
-
#ifdef __powerpc64__
-
- __asm__ __volatile__("mftb %0" : "=r" (ret) : );
-
+ return mftb();
#else
+ cycles_t ret;
+
/*
* For the "cycle" counter we use the timebase lower half.
* Currently only used on SMP.
@@ -41,9 +40,8 @@ static inline cycles_t get_cycles(void)
" .long 99b-98b\n"
".previous"
: "=r" (ret) : "i" (CPU_FTR_601));
-#endif
-
return ret;
+#endif
}
#endif /* __KERNEL__ */
^ permalink raw reply
* [PATCH 4/5] powerpc: Support feature fixups in modules
From: Benjamin Herrenschmidt @ 2006-10-13 8:04 UTC (permalink / raw)
To: linuxppc-dev list
This patch adds support for feature fixups in modules. This involves
adding support for R_PPC64_REL64 relocs to the 64 bits module loader.
It also modifies modpost.c to ignore the powerpc fixup sections (or it
would warn when used in .init.text).
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Index: linux-cell/arch/powerpc/kernel/module_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/module_32.c 2006-10-13 16:00:26.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/module_32.c 2006-10-13 16:59:36.000000000 +1000
@@ -24,6 +24,8 @@
#include <linux/kernel.h>
#include <linux/cache.h>
+#include "setup.h"
+
#if 0
#define DEBUGP printk
#else
@@ -269,33 +271,50 @@ int apply_relocate_add(Elf32_Shdr *sechd
return 0;
}
+static const Elf_Shdr *find_section(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ const char *name)
+{
+ char *secstrings;
+ unsigned int i;
+
+ secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+ for (i = 1; i < hdr->e_shnum; i++)
+ if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0)
+ return &sechdrs[i];
+ return NULL;
+}
+
int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
struct module *me)
{
- char *secstrings;
- unsigned int i;
+ const Elf_Shdr *sect;
me->arch.bug_table = NULL;
me->arch.num_bugs = 0;
/* Find the __bug_table section, if present */
- secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
- for (i = 1; i < hdr->e_shnum; i++) {
- if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table"))
- continue;
- me->arch.bug_table = (void *) sechdrs[i].sh_addr;
- me->arch.num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry);
- break;
+ sect = find_section(hdr, sechdrs, "__bug_table");
+ if (sect != NULL) {
+ me->arch.bug_table = (void *) sect->sh_addr;
+ me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry);
}
- /*
+ /*
* Strictly speaking this should have a spinlock to protect against
* traversals, but since we only traverse on BUG()s, a spinlock
* could potentially lead to deadlock and thus be counter-productive.
*/
list_add(&me->arch.bug_list, &module_bug_list);
+ /* Apply feature fixups */
+ sect = find_section(hdr, sechdrs, "__ftr_fixup");
+ if (sect != NULL)
+ do_feature_fixups(cur_cpu_spec->cpu_features,
+ (void *)sect->sh_addr,
+ (void *)sect->sh_addr + sect->sh_size);
+
return 0;
}
Index: linux-cell/arch/powerpc/kernel/module_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/module_64.c 2006-10-13 16:00:26.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/module_64.c 2006-10-13 16:59:36.000000000 +1000
@@ -22,6 +22,9 @@
#include <linux/vmalloc.h>
#include <asm/module.h>
#include <asm/uaccess.h>
+#include <asm/firmware.h>
+
+#include "setup.h"
/* FIXME: We don't do .init separately. To do this, we'd need to have
a separate r2 value in the init and core section, and stub between
@@ -400,6 +403,11 @@ int apply_relocate_add(Elf64_Shdr *sechd
| (value & 0x03fffffc);
break;
+ case R_PPC64_REL64:
+ /* 64 bits relative (used by features fixups) */
+ *location = value - (unsigned long)location;
+ break;
+
default:
printk("%s: Unknown ADD relocation: %lu\n",
me->name,
@@ -413,23 +421,33 @@ int apply_relocate_add(Elf64_Shdr *sechd
LIST_HEAD(module_bug_list);
-int module_finalize(const Elf_Ehdr *hdr,
- const Elf_Shdr *sechdrs, struct module *me)
+static const Elf_Shdr *find_section(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ const char *name)
{
char *secstrings;
unsigned int i;
+ secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+ for (i = 1; i < hdr->e_shnum; i++)
+ if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0)
+ return &sechdrs[i];
+ return NULL;
+}
+
+int module_finalize(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs, struct module *me)
+{
+ const Elf_Shdr *sect;
+
me->arch.bug_table = NULL;
me->arch.num_bugs = 0;
/* Find the __bug_table section, if present */
- secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
- for (i = 1; i < hdr->e_shnum; i++) {
- if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table"))
- continue;
- me->arch.bug_table = (void *) sechdrs[i].sh_addr;
- me->arch.num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry);
- break;
+ sect = find_section(hdr, sechdrs, "__bug_table");
+ if (sect != NULL) {
+ me->arch.bug_table = (void *) sect->sh_addr;
+ me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry);
}
/*
@@ -439,6 +457,19 @@ int module_finalize(const Elf_Ehdr *hdr,
*/
list_add(&me->arch.bug_list, &module_bug_list);
+ /* Apply feature fixups */
+ sect = find_section(hdr, sechdrs, "__ftr_fixup");
+ if (sect != NULL)
+ do_feature_fixups(cur_cpu_spec->cpu_features,
+ (void *)sect->sh_addr,
+ (void *)sect->sh_addr + sect->sh_size);
+
+ sect = find_section(hdr, sechdrs, "__fw_ftr_fixup");
+ if (sect != NULL)
+ do_feature_fixups(powerpc_firmware_features,
+ (void *)sect->sh_addr,
+ (void *)sect->sh_addr + sect->sh_size);
+
return 0;
}
Index: linux-cell/scripts/mod/modpost.c
===================================================================
--- linux-cell.orig/scripts/mod/modpost.c 2006-10-06 13:48:29.000000000 +1000
+++ linux-cell/scripts/mod/modpost.c 2006-10-13 17:19:55.000000000 +1000
@@ -921,6 +921,8 @@ static int init_section_ref_ok(const cha
".fixup",
".smp_locks",
".plt", /* seen on ARCH=um build on x86_64. Harmless */
+ "__ftr_fixup", /* powerpc cpu feature fixup */
+ "__fw_ftr_fixup", /* powerpc firmware feature fixup */
NULL
};
/* Start of section names */
^ permalink raw reply
* [PATCH 3/5] powerpc: Support feature fixups in vdso's
From: Benjamin Herrenschmidt @ 2006-10-13 8:04 UTC (permalink / raw)
To: linuxppc-dev list
This patch reworks the feature fixup mecanism so vdso's can be fixed up.
The main issue was that the construct:
.long label (or .llong on 64 bits)
will not work in the case of a shared library like the vdso. It will
generate an empty placeholder in the fixup table along with a reloc,
which is not something we can deal with in the vdso.
The idea here (thanks Alan Modra !) is to instead use something like:
1:
.long label - 1b
That is, the feature fixup tables no longer contain addresses of bits of
code to patch, but offsets of such code from the fixup table entry
itself. That is properly resolved by ld when building the .so's. I've
modified the fixup mecanism generically to use that method for the rest
of the kernel as well.
Another trick is that the 32 bits vDSO included in the 64 bits kernel
need to have a table in the 64 bits format. However, gas does not
support 32 bits code with a statement of the form:
.llong label - 1b (Or even just .llong label)
That is, it cannot emit the right fixup/relocation for the linker to use
to assign a 32 bits address to an .llong field. Thus, in the specific
case of the 32 bits vdso built as part of the 64 bits kernel, we are
using a modified macro that generates:
.long 0xffffffff
.llong label - 1b
Note that is assumes that the value is negative which is enforced by
the .lds (those offsets are always negative as the .text is always
before the fixup table and gas doesn't support emiting the reloc the
other way around).
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Index: linux-cell/arch/powerpc/kernel/vdso.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/vdso.c 2006-10-13 16:00:27.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/vdso.c 2006-10-13 16:58:13.000000000 +1000
@@ -36,6 +36,8 @@
#include <asm/vdso.h>
#include <asm/vdso_datapage.h>
+#include "setup.h"
+
#undef DEBUG
#ifdef DEBUG
@@ -586,6 +588,43 @@ static __init int vdso_fixup_datapage(st
return 0;
}
+
+static __init int vdso_fixup_features(struct lib32_elfinfo *v32,
+ struct lib64_elfinfo *v64)
+{
+ void *start32;
+ unsigned long size32;
+
+#ifdef CONFIG_PPC64
+ void *start64;
+ unsigned long size64;
+
+ start64 = find_section64(v64->hdr, "__ftr_fixup", &size64);
+ if (start64)
+ do_feature_fixups(cur_cpu_spec->cpu_features,
+ start64, start64 + size64);
+
+ start64 = find_section64(v64->hdr, "__fw_ftr_fixup", &size64);
+ if (start64)
+ do_feature_fixups(powerpc_firmware_features,
+ start64, start64 + size64);
+#endif /* CONFIG_PPC64 */
+
+ start32 = find_section32(v32->hdr, "__ftr_fixup", &size32);
+ if (start32)
+ do_feature_fixups(cur_cpu_spec->cpu_features,
+ start32, start32 + size32);
+
+#ifdef CONFIG_PPC64
+ start32 = find_section32(v32->hdr, "__fw_ftr_fixup", &size32);
+ if (start32)
+ do_feature_fixups(powerpc_firmware_features,
+ start32, start32 + size32);
+#endif /* CONFIG_PPC64 */
+
+ return 0;
+}
+
static __init int vdso_fixup_alt_funcs(struct lib32_elfinfo *v32,
struct lib64_elfinfo *v64)
{
@@ -634,6 +673,9 @@ static __init int vdso_setup(void)
if (vdso_fixup_datapage(&v32, &v64))
return -1;
+ if (vdso_fixup_features(&v32, &v64))
+ return -1;
+
if (vdso_fixup_alt_funcs(&v32, &v64))
return -1;
@@ -714,6 +756,7 @@ void __init vdso_init(void)
* Setup the syscall map in the vDOS
*/
vdso_setup_syscall_map();
+
/*
* Initialize the vDSO images in memory, that is do necessary
* fixups of vDSO symbols, locate trampolines, etc...
Index: linux-cell/arch/powerpc/kernel/vdso32/vdso32.lds.S
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/vdso32/vdso32.lds.S 2006-10-13 16:00:27.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/vdso32/vdso32.lds.S 2006-10-13 16:58:13.000000000 +1000
@@ -32,6 +32,18 @@ SECTIONS
PROVIDE (_etext = .);
PROVIDE (etext = .);
+ . = ALIGN(8);
+ __ftr_fixup : {
+ *(__ftr_fixup)
+ }
+
+#ifdef CONFIG_PPC64
+ . = ALIGN(8);
+ __fw_ftr_fixup : {
+ *(__fw_ftr_fixup)
+ }
+#endif
+
/* Other stuff is appended to the text segment: */
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
Index: linux-cell/arch/powerpc/kernel/vdso64/vdso64.lds.S
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/vdso64/vdso64.lds.S 2006-10-13 16:00:27.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/vdso64/vdso64.lds.S 2006-10-13 16:58:13.000000000 +1000
@@ -31,6 +31,16 @@ SECTIONS
PROVIDE (_etext = .);
PROVIDE (etext = .);
+ . = ALIGN(8);
+ __ftr_fixup : {
+ *(__ftr_fixup)
+ }
+
+ . = ALIGN(8);
+ __fw_ftr_fixup : {
+ *(__fw_ftr_fixup)
+ }
+
/* Other stuff is appended to the text segment: */
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
Index: linux-cell/arch/powerpc/kernel/setup-common.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup-common.c 2006-10-13 16:39:03.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/setup-common.c 2006-10-13 16:58:55.000000000 +1000
@@ -521,14 +521,13 @@ void __init setup_panic(void)
atomic_notifier_chain_register(&panic_notifier_list, &ppc_panic_block);
}
-void do_feature_fixups(unsigned long offset, unsigned long value,
- void *fixup_start, void *fixup_end)
+void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
{
struct fixup_entry {
unsigned long mask;
unsigned long value;
- unsigned int *start;
- unsigned int *end;
+ long start_off;
+ long end_off;
} *fcur, *fend;
fcur = fixup_start;
@@ -543,8 +542,8 @@ void do_feature_fixups(unsigned long off
/* These PTRRELOCs will disappear once the new scheme for
* modules and vdso is implemented
*/
- pstart = PTRRELOC(fcur->start);
- pend = PTRRELOC(fcur->end);
+ pstart = ((unsigned int *)fcur) + (fcur->start_off / 4);
+ pend = ((unsigned int *)fcur) + (fcur->end_off / 4);
for (p = pstart; p < pend; p++) {
*p = 0x60000000u;
Index: linux-cell/arch/powerpc/kernel/setup.h
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup.h 2006-10-13 16:06:24.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/setup.h 2006-10-13 16:58:13.000000000 +1000
@@ -4,8 +4,8 @@
extern void check_for_initrd(void);
extern void do_init_bootmem(void);
extern void setup_panic(void);
-extern void do_feature_fixups(unsigned long offset, unsigned long value,
- void *fixup_start, void *fixup_end);
+extern void do_feature_fixups(unsigned long value, void *fixup_start,
+ void *fixup_end);
extern int do_early_xmon;
Index: linux-cell/arch/powerpc/kernel/setup_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup_32.c 2006-10-13 16:38:21.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/setup_32.c 2006-10-13 16:59:28.000000000 +1000
@@ -104,7 +104,7 @@ unsigned long __init early_init(unsigned
*/
spec = identify_cpu(offset);
- do_feature_fixups(offset, spec->cpu_features,
+ do_feature_fixups(spec->cpu_features,
PTRRELOC(&__start___ftr_fixup),
PTRRELOC(&__stop___ftr_fixup));
Index: linux-cell/arch/powerpc/kernel/setup_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup_64.c 2006-10-13 16:42:44.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/setup_64.c 2006-10-13 16:58:13.000000000 +1000
@@ -357,9 +357,9 @@ void __init setup_system(void)
/* Apply the CPUs-specific and firmware specific fixups to kernel
* text (nop out sections not relevant to this CPU or this firmware)
*/
- do_feature_fixups(0, cur_cpu_spec->cpu_features,
+ do_feature_fixups(cur_cpu_spec->cpu_features,
&__start___ftr_fixup, &__stop___ftr_fixup);
- do_feature_fixups(0, powerpc_firmware_features,
+ do_feature_fixups(powerpc_firmware_features,
&__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
/*
Index: linux-cell/include/asm-powerpc/asm-compat.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/asm-compat.h 2006-10-13 16:00:27.000000000 +1000
+++ linux-cell/include/asm-powerpc/asm-compat.h 2006-10-13 16:58:13.000000000 +1000
@@ -14,6 +14,58 @@
# define ASM_CONST(x) __ASM_CONST(x)
#endif
+
+/*
+ * Feature section common macros
+ *
+ * Note that the entries now contain offsets between the table entry
+ * and the code rather than absolute code pointers in order to be
+ * useable with the vdso shared library. There is also an assumption
+ * that values will be negative, that is, the fixup table has to be
+ * located after the code it fixes up.
+ */
+#ifdef CONFIG_PPC64
+#ifdef __powerpc64__
+/* 64 bits kernel, 64 bits code */
+#define MAKE_FTR_SECTION_ENTRY(msk, val, label, sect) \
+99: \
+ .section sect,"a"; \
+ .align 3; \
+98: \
+ .llong msk; \
+ .llong val; \
+ .llong label##b-98b; \
+ .llong 99b-98b; \
+ .previous
+#else /* __powerpc64__ */
+/* 64 bits kernel, 32 bits code (ie. vdso32) */
+#define MAKE_FTR_SECTION_ENTRY(msk, val, label, sect) \
+99: \
+ .section sect,"a"; \
+ .align 3; \
+98: \
+ .llong msk; \
+ .llong val; \
+ .long 0xffffffff; \
+ .long label##b-98b; \
+ .long 0xffffffff; \
+ .long 99b-98b; \
+ .previous
+#endif /* !__powerpc64__ */
+#else /* CONFIG_PPC64 */
+/* 32 bits kernel, 32 bits code */
+#define MAKE_FTR_SECTION_ENTRY(msk, val, label, sect) \
+99: \
+ .section sect,"a"; \
+ .align 2; \
+98: \
+ .long msk; \
+ .long val; \
+ .long label##b-98b; \
+ .long 99b-98b; \
+ .previous
+#endif /* !CONFIG_PPC64 */
+
#ifdef __powerpc64__
/* operations for longs and pointers */
Index: linux-cell/include/asm-powerpc/cputable.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/cputable.h 2006-10-13 16:58:07.000000000 +1000
+++ linux-cell/include/asm-powerpc/cputable.h 2006-10-13 16:58:13.000000000 +1000
@@ -431,32 +431,11 @@ static inline int cpu_has_feature(unsign
#ifdef __ASSEMBLY__
#define BEGIN_FTR_SECTION_NESTED(label) label:
-#define BEGIN_FTR_SECTION BEGIN_FTR_SECTION_NESTED(98)
-
-#ifndef __powerpc64__
-#define END_FTR_SECTION_NESTED(msk, val, label) \
-99: \
- .section __ftr_fixup,"a"; \
- .align 2; \
- .long msk; \
- .long val; \
- .long label##b; \
- .long 99b; \
- .previous
-#else /* __powerpc64__ */
+#define BEGIN_FTR_SECTION BEGIN_FTR_SECTION_NESTED(97)
#define END_FTR_SECTION_NESTED(msk, val, label) \
-99: \
- .section __ftr_fixup,"a"; \
- .align 3; \
- .llong msk; \
- .llong val; \
- .llong label##b; \
- .llong 99b; \
- .previous
-#endif /* __powerpc64__ */
-
+ MAKE_FTR_SECTION_ENTRY(msk, val, label, __ftr_fixup)
#define END_FTR_SECTION(msk, val) \
- END_FTR_SECTION_NESTED(msk, val, 98)
+ END_FTR_SECTION_NESTED(msk, val, 97)
#define END_FTR_SECTION_IFSET(msk) END_FTR_SECTION((msk), (msk))
#define END_FTR_SECTION_IFCLR(msk) END_FTR_SECTION((msk), 0)
Index: linux-cell/include/asm-powerpc/firmware.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/firmware.h 2006-10-13 16:00:27.000000000 +1000
+++ linux-cell/include/asm-powerpc/firmware.h 2006-10-13 16:58:13.000000000 +1000
@@ -98,17 +98,12 @@ extern int fwnmi_active;
#else /* __ASSEMBLY__ */
-#define BEGIN_FW_FTR_SECTION 96:
-
+#define BEGIN_FW_FTR_SECTION_NESTED(label) label:
+#define BEGIN_FW_FTR_SECTION BEGIN_FW_FTR_SECTION_NESTED(97)
+#define END_FW_FTR_SECTION_NESTED(msk, val, label) \
+ MAKE_FTR_SECTION_ENTRY(msk, val, label, __fw_ftr_fixup)
#define END_FW_FTR_SECTION(msk, val) \
-97: \
- .section __fw_ftr_fixup,"a"; \
- .align 3; \
- .llong msk; \
- .llong val; \
- .llong 96b; \
- .llong 97b; \
- .previous
+ END_FW_FTR_SECTION_NESTED(msk, val, 97)
#define END_FW_FTR_SECTION_IFSET(msk) END_FW_FTR_SECTION((msk), (msk))
#define END_FW_FTR_SECTION_IFCLR(msk) END_FW_FTR_SECTION((msk), 0)
Index: linux-cell/include/asm-powerpc/timex.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/timex.h 2006-10-13 16:00:27.000000000 +1000
+++ linux-cell/include/asm-powerpc/timex.h 2006-10-13 16:58:13.000000000 +1000
@@ -30,13 +30,15 @@ static inline cycles_t get_cycles(void)
ret = 0;
__asm__ __volatile__(
- "98: mftb %0\n"
+ "97: mftb %0\n"
"99:\n"
".section __ftr_fixup,\"a\"\n"
+ ".align 2\n"
+ "98:\n"
" .long %1\n"
" .long 0\n"
- " .long 98b\n"
- " .long 99b\n"
+ " .long 97b-98b\n"
+ " .long 99b-98b\n"
".previous"
: "=r" (ret) : "i" (CPU_FTR_601));
#endif
^ permalink raw reply
* [PATCH 2/5] powerpc: support nested cpu features
From: Benjamin Herrenschmidt @ 2006-10-13 8:04 UTC (permalink / raw)
To: linuxppc-dev list
This patch adds some macros that can be used with an explicit label in
order to nest cpu features. This should be used very careful but is
necessary for the upcoming cell TB fixup.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Index: linux-cell/include/asm-powerpc/cputable.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/cputable.h 2006-10-13 16:19:51.000000000 +1000
+++ linux-cell/include/asm-powerpc/cputable.h 2006-10-13 16:58:07.000000000 +1000
@@ -430,30 +430,34 @@ static inline int cpu_has_feature(unsign
#ifdef __ASSEMBLY__
-#define BEGIN_FTR_SECTION 98:
+#define BEGIN_FTR_SECTION_NESTED(label) label:
+#define BEGIN_FTR_SECTION BEGIN_FTR_SECTION_NESTED(98)
#ifndef __powerpc64__
-#define END_FTR_SECTION(msk, val) \
+#define END_FTR_SECTION_NESTED(msk, val, label) \
99: \
.section __ftr_fixup,"a"; \
.align 2; \
.long msk; \
.long val; \
- .long 98b; \
+ .long label##b; \
.long 99b; \
.previous
#else /* __powerpc64__ */
-#define END_FTR_SECTION(msk, val) \
+#define END_FTR_SECTION_NESTED(msk, val, label) \
99: \
.section __ftr_fixup,"a"; \
.align 3; \
.llong msk; \
.llong val; \
- .llong 98b; \
+ .llong label##b; \
.llong 99b; \
.previous
#endif /* __powerpc64__ */
+#define END_FTR_SECTION(msk, val) \
+ END_FTR_SECTION_NESTED(msk, val, 98)
+
#define END_FTR_SECTION_IFSET(msk) END_FTR_SECTION((msk), (msk))
#define END_FTR_SECTION_IFCLR(msk) END_FTR_SECTION((msk), 0)
#endif /* __ASSEMBLY__ */
^ permalink raw reply
* [PATCH 1/5] powerpc: consolidate feature fixup code
From: Benjamin Herrenschmidt @ 2006-10-13 8:04 UTC (permalink / raw)
To: linuxppc-dev list
There are currently two versions of the functions for applying the
feature fixups, one for CPU features and one for firmware features. In
addition, they are both in assembly and with separate implementations
for 32 and 64 bits. identify_cpu() is also implemented in assembly and
separately for 32 and 64 bits.
This patch replaces them with a pair of C functions. The call sites are
slightly moved on ppc64 as well to be called from C instead of from
assembly, though it's a very small change, and thus shouldn't cause any
problem.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Index: linux-cell/arch/powerpc/kernel/head_64.S
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/head_64.S 2006-10-13 16:04:10.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/head_64.S 2006-10-13 16:43:05.000000000 +1000
@@ -1580,11 +1580,6 @@ _STATIC(__start_initialization_iSeries)
li r0,0
stdu r0,-STACK_FRAME_OVERHEAD(r1)
- LOAD_REG_IMMEDIATE(r3,cpu_specs)
- LOAD_REG_IMMEDIATE(r4,cur_cpu_spec)
- li r5,0
- bl .identify_cpu
-
LOAD_REG_IMMEDIATE(r2,__toc_start)
addi r2,r2,0x4000
addi r2,r2,0x4000
@@ -1964,13 +1959,6 @@ _STATIC(start_here_multiplatform)
addi r2,r2,0x4000
add r2,r2,r26
- LOAD_REG_IMMEDIATE(r3, cpu_specs)
- add r3,r3,r26
- LOAD_REG_IMMEDIATE(r4,cur_cpu_spec)
- add r4,r4,r26
- mr r5,r26
- bl .identify_cpu
-
/* Do very early kernel initializations, including initial hash table,
* stab and slb setup before we turn on relocation. */
@@ -2000,13 +1988,6 @@ _STATIC(start_here_common)
li r0,0
stdu r0,-STACK_FRAME_OVERHEAD(r1)
- /* Apply the CPUs-specific fixups (nop out sections not relevant
- * to this CPU
- */
- li r3,0
- bl .do_cpu_ftr_fixups
- bl .do_fw_ftr_fixups
-
/* ptr to current */
LOAD_REG_IMMEDIATE(r4, init_task)
std r4,PACACURRENT(r13)
Index: linux-cell/arch/powerpc/kernel/misc_64.S
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/misc_64.S 2006-10-13 16:04:10.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/misc_64.S 2006-10-13 16:40:14.000000000 +1000
@@ -246,130 +246,6 @@ _GLOBAL(__flush_dcache_icache)
isync
blr
-/*
- * identify_cpu and calls setup_cpu
- * In: r3 = base of the cpu_specs array
- * r4 = address of cur_cpu_spec
- * r5 = relocation offset
- */
-_GLOBAL(identify_cpu)
- mfpvr r7
-1:
- lwz r8,CPU_SPEC_PVR_MASK(r3)
- and r8,r8,r7
- lwz r9,CPU_SPEC_PVR_VALUE(r3)
- cmplw 0,r9,r8
- beq 1f
- addi r3,r3,CPU_SPEC_ENTRY_SIZE
- b 1b
-1:
- sub r0,r3,r5
- std r0,0(r4)
- ld r4,CPU_SPEC_SETUP(r3)
- cmpdi 0,r4,0
- add r4,r4,r5
- beqlr
- ld r4,0(r4)
- add r4,r4,r5
- mtctr r4
- /* Calling convention for cpu setup is r3=offset, r4=cur_cpu_spec */
- mr r4,r3
- mr r3,r5
- bctr
-
-/*
- * do_cpu_ftr_fixups - goes through the list of CPU feature fixups
- * and writes nop's over sections of code that don't apply for this cpu.
- * r3 = data offset (not changed)
- */
-_GLOBAL(do_cpu_ftr_fixups)
- /* Get CPU 0 features */
- LOAD_REG_IMMEDIATE(r6,cur_cpu_spec)
- sub r6,r6,r3
- ld r4,0(r6)
- sub r4,r4,r3
- ld r4,CPU_SPEC_FEATURES(r4)
- /* Get the fixup table */
- LOAD_REG_IMMEDIATE(r6,__start___ftr_fixup)
- sub r6,r6,r3
- LOAD_REG_IMMEDIATE(r7,__stop___ftr_fixup)
- sub r7,r7,r3
- /* Do the fixup */
-1: cmpld r6,r7
- bgelr
- addi r6,r6,32
- ld r8,-32(r6) /* mask */
- and r8,r8,r4
- ld r9,-24(r6) /* value */
- cmpld r8,r9
- beq 1b
- ld r8,-16(r6) /* section begin */
- ld r9,-8(r6) /* section end */
- subf. r9,r8,r9
- beq 1b
- /* write nops over the section of code */
- /* todo: if large section, add a branch at the start of it */
- srwi r9,r9,2
- mtctr r9
- sub r8,r8,r3
- lis r0,0x60000000@h /* nop */
-3: stw r0,0(r8)
- andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE@l
- beq 2f
- dcbst 0,r8 /* suboptimal, but simpler */
- sync
- icbi 0,r8
-2: addi r8,r8,4
- bdnz 3b
- sync /* additional sync needed on g4 */
- isync
- b 1b
-
-/*
- * do_fw_ftr_fixups - goes through the list of firmware feature fixups
- * and writes nop's over sections of code that don't apply for this firmware.
- * r3 = data offset (not changed)
- */
-_GLOBAL(do_fw_ftr_fixups)
- /* Get firmware features */
- LOAD_REG_IMMEDIATE(r6,powerpc_firmware_features)
- sub r6,r6,r3
- ld r4,0(r6)
- /* Get the fixup table */
- LOAD_REG_IMMEDIATE(r6,__start___fw_ftr_fixup)
- sub r6,r6,r3
- LOAD_REG_IMMEDIATE(r7,__stop___fw_ftr_fixup)
- sub r7,r7,r3
- /* Do the fixup */
-1: cmpld r6,r7
- bgelr
- addi r6,r6,32
- ld r8,-32(r6) /* mask */
- and r8,r8,r4
- ld r9,-24(r6) /* value */
- cmpld r8,r9
- beq 1b
- ld r8,-16(r6) /* section begin */
- ld r9,-8(r6) /* section end */
- subf. r9,r8,r9
- beq 1b
- /* write nops over the section of code */
- /* todo: if large section, add a branch at the start of it */
- srwi r9,r9,2
- mtctr r9
- sub r8,r8,r3
- lis r0,0x60000000@h /* nop */
-3: stw r0,0(r8)
-BEGIN_FTR_SECTION
- dcbst 0,r8 /* suboptimal, but simpler */
- sync
- icbi 0,r8
-END_FTR_SECTION_IFSET(CPU_FTR_SPLIT_ID_CACHE)
- addi r8,r8,4
- bdnz 3b
- sync /* additional sync needed on g4 */
- isync
- b 1b
#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE)
/*
Index: linux-cell/arch/powerpc/kernel/setup-common.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup-common.c 2006-10-13 16:04:10.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/setup-common.c 2006-10-13 16:39:03.000000000 +1000
@@ -520,3 +520,39 @@ void __init setup_panic(void)
{
atomic_notifier_chain_register(&panic_notifier_list, &ppc_panic_block);
}
+
+void do_feature_fixups(unsigned long offset, unsigned long value,
+ void *fixup_start, void *fixup_end)
+{
+ struct fixup_entry {
+ unsigned long mask;
+ unsigned long value;
+ unsigned int *start;
+ unsigned int *end;
+ } *fcur, *fend;
+
+ fcur = fixup_start;
+ fend = fixup_end;
+
+ for (; fcur < fend; fcur++) {
+ unsigned int *pstart, *pend, *p;
+
+ if ((value & fcur->mask) == fcur->value)
+ continue;
+
+ /* These PTRRELOCs will disappear once the new scheme for
+ * modules and vdso is implemented
+ */
+ pstart = PTRRELOC(fcur->start);
+ pend = PTRRELOC(fcur->end);
+
+ for (p = pstart; p < pend; p++) {
+ *p = 0x60000000u;
+ asm volatile ("dcbst 0, %0" : : "r" (p));
+ }
+ asm volatile ("sync" : : : "memory");
+ for (p = pstart; p < pend; p++)
+ asm volatile ("icbi 0,%0" : : "r" (p));
+ asm volatile ("sync; isync" : : : "memory");
+ }
+}
Index: linux-cell/arch/powerpc/kernel/setup.h
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup.h 2006-10-13 16:04:10.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/setup.h 2006-10-13 16:06:24.000000000 +1000
@@ -1,9 +1,12 @@
#ifndef _POWERPC_KERNEL_SETUP_H
#define _POWERPC_KERNEL_SETUP_H
-void check_for_initrd(void);
-void do_init_bootmem(void);
-void setup_panic(void);
+extern void check_for_initrd(void);
+extern void do_init_bootmem(void);
+extern void setup_panic(void);
+extern void do_feature_fixups(unsigned long offset, unsigned long value,
+ void *fixup_start, void *fixup_end);
+
extern int do_early_xmon;
#endif /* _POWERPC_KERNEL_SETUP_H */
Index: linux-cell/arch/powerpc/kernel/setup_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup_32.c 2006-10-13 16:04:10.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/setup_32.c 2006-10-13 16:38:21.000000000 +1000
@@ -90,7 +90,9 @@ int ucache_bsize;
*/
unsigned long __init early_init(unsigned long dt_ptr)
{
+ extern unsigned int __start___ftr_fixup, __stop___ftr_fixup;
unsigned long offset = reloc_offset();
+ struct cpu_spec *spec;
/* First zero the BSS -- use memset_io, some platforms don't have
* caches on yet */
@@ -100,8 +102,11 @@ unsigned long __init early_init(unsigned
* Identify the CPU type and fix up code sections
* that depend on which cpu we have.
*/
- identify_cpu(offset, 0);
- do_cpu_ftr_fixups(offset);
+ spec = identify_cpu(offset);
+
+ do_feature_fixups(offset, spec->cpu_features,
+ PTRRELOC(&__start___ftr_fixup),
+ PTRRELOC(&__stop___ftr_fixup));
return KERNELBASE + offset;
}
Index: linux-cell/arch/powerpc/kernel/setup_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup_64.c 2006-10-13 16:04:10.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/setup_64.c 2006-10-13 16:42:44.000000000 +1000
@@ -170,6 +170,9 @@ void __init setup_paca(int cpu)
void __init early_setup(unsigned long dt_ptr)
{
+ /* Identify CPU type */
+ identify_cpu(0);
+
/* Assume we're on cpu 0 for now. Don't write to the paca yet! */
setup_paca(0);
@@ -346,8 +349,19 @@ static void __init initialize_cache_info
*/
void __init setup_system(void)
{
+ extern unsigned int __start___ftr_fixup, __stop___ftr_fixup;
+ extern unsigned int __start___fw_ftr_fixup, __stop___fw_ftr_fixup;
+
DBG(" -> setup_system()\n");
+ /* Apply the CPUs-specific and firmware specific fixups to kernel
+ * text (nop out sections not relevant to this CPU or this firmware)
+ */
+ do_feature_fixups(0, cur_cpu_spec->cpu_features,
+ &__start___ftr_fixup, &__stop___ftr_fixup);
+ do_feature_fixups(0, powerpc_firmware_features,
+ &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
+
/*
* Unflatten the device-tree passed by prom_init or kexec
*/
Index: linux-cell/arch/powerpc/kernel/cputable.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/cputable.c 2006-10-06 13:47:54.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/cputable.c 2006-10-13 16:47:31.000000000 +1000
@@ -73,7 +73,7 @@ extern void __restore_cpu_ppc970(void);
#define PPC_FEATURE_SPE_COMP 0
#endif
-struct cpu_spec cpu_specs[] = {
+static struct cpu_spec cpu_specs[] = {
#ifdef CONFIG_PPC64
{ /* Power3 */
.pvr_mask = 0xffff0000,
@@ -1152,3 +1152,25 @@ struct cpu_spec cpu_specs[] = {
#endif /* !CLASSIC_PPC */
#endif /* CONFIG_PPC32 */
};
+
+struct cpu_spec *identify_cpu(unsigned long offset)
+{
+ struct cpu_spec *s = cpu_specs;
+ struct cpu_spec **cur = &cur_cpu_spec;
+ unsigned int pvr = mfspr(SPRN_PVR);
+ int i;
+
+ s = PTRRELOC(s);
+ cur = PTRRELOC(cur);
+
+ if (*cur != NULL)
+ return PTRRELOC(*cur);
+
+ for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++)
+ if ((pvr & s->pvr_mask) == s->pvr_value) {
+ *cur = cpu_specs + i;
+ return s;
+ }
+ BUG();
+ return NULL;
+}
Index: linux-cell/arch/powerpc/kernel/misc_32.S
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/misc_32.S 2006-10-06 13:47:54.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/misc_32.S 2006-10-13 16:26:43.000000000 +1000
@@ -102,80 +102,6 @@ _GLOBAL(reloc_got2)
blr
/*
- * identify_cpu,
- * called with r3 = data offset and r4 = CPU number
- * doesn't change r3
- */
-_GLOBAL(identify_cpu)
- addis r8,r3,cpu_specs@ha
- addi r8,r8,cpu_specs@l
- mfpvr r7
-1:
- lwz r5,CPU_SPEC_PVR_MASK(r8)
- and r5,r5,r7
- lwz r6,CPU_SPEC_PVR_VALUE(r8)
- cmplw 0,r6,r5
- beq 1f
- addi r8,r8,CPU_SPEC_ENTRY_SIZE
- b 1b
-1:
- addis r6,r3,cur_cpu_spec@ha
- addi r6,r6,cur_cpu_spec@l
- sub r8,r8,r3
- stw r8,0(r6)
- blr
-
-/*
- * do_cpu_ftr_fixups - goes through the list of CPU feature fixups
- * and writes nop's over sections of code that don't apply for this cpu.
- * r3 = data offset (not changed)
- */
-_GLOBAL(do_cpu_ftr_fixups)
- /* Get CPU 0 features */
- addis r6,r3,cur_cpu_spec@ha
- addi r6,r6,cur_cpu_spec@l
- lwz r4,0(r6)
- add r4,r4,r3
- lwz r4,CPU_SPEC_FEATURES(r4)
-
- /* Get the fixup table */
- addis r6,r3,__start___ftr_fixup@ha
- addi r6,r6,__start___ftr_fixup@l
- addis r7,r3,__stop___ftr_fixup@ha
- addi r7,r7,__stop___ftr_fixup@l
-
- /* Do the fixup */
-1: cmplw 0,r6,r7
- bgelr
- addi r6,r6,16
- lwz r8,-16(r6) /* mask */
- and r8,r8,r4
- lwz r9,-12(r6) /* value */
- cmplw 0,r8,r9
- beq 1b
- lwz r8,-8(r6) /* section begin */
- lwz r9,-4(r6) /* section end */
- subf. r9,r8,r9
- beq 1b
- /* write nops over the section of code */
- /* todo: if large section, add a branch at the start of it */
- srwi r9,r9,2
- mtctr r9
- add r8,r8,r3
- lis r0,0x60000000@h /* nop */
-3: stw r0,0(r8)
- andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE@l
- beq 2f
- dcbst 0,r8 /* suboptimal, but simpler */
- sync
- icbi 0,r8
-2: addi r8,r8,4
- bdnz 3b
- sync /* additional sync needed on g4 */
- isync
- b 1b
-
-/*
* call_setup_cpu - call the setup_cpu function for this cpu
* r3 = data offset, r24 = cpu number
*
Index: linux-cell/include/asm-powerpc/cputable.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/cputable.h 2006-10-13 16:00:28.000000000 +1000
+++ linux-cell/include/asm-powerpc/cputable.h 2006-10-13 16:19:51.000000000 +1000
@@ -89,8 +89,7 @@ struct cpu_spec {
extern struct cpu_spec *cur_cpu_spec;
-extern void identify_cpu(unsigned long offset, unsigned long cpu);
-extern void do_cpu_ftr_fixups(unsigned long offset);
+extern struct cpu_spec *identify_cpu(unsigned long offset);
#endif /* __ASSEMBLY__ */
Index: linux-cell/include/asm-powerpc/system.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/system.h 2006-10-06 13:48:24.000000000 +1000
+++ linux-cell/include/asm-powerpc/system.h 2006-10-13 16:24:45.000000000 +1000
@@ -378,7 +378,11 @@ extern unsigned long reloc_offset(void);
extern unsigned long add_reloc_offset(unsigned long);
extern void reloc_got2(unsigned long);
+#ifdef CONFIG_PPC64
+#define PTRRELOC(x) x
+#else
#define PTRRELOC(x) ((typeof(x)) add_reloc_offset((unsigned long)(x)))
+#endif
static inline void create_instruction(unsigned long addr, unsigned int instr)
{
Index: linux-cell/arch/powerpc/platforms/iseries/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/iseries/setup.c 2006-10-06 13:47:54.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/iseries/setup.c 2006-10-13 16:49:14.000000000 +1000
@@ -694,6 +694,11 @@ void * __init iSeries_early_setup(void)
{
unsigned long phys_mem_size;
+ /* Identify CPU type. This is done again by the common code later
+ * on but calling this function multiple times is fine.
+ */
+ identify_cpu(0);
+
powerpc_firmware_features |= FW_FEATURE_ISERIES;
powerpc_firmware_features |= FW_FEATURE_LPAR;
^ permalink raw reply
* [PATCH 0/5] powerpc: feature fixup updates
From: Benjamin Herrenschmidt @ 2006-10-13 8:04 UTC (permalink / raw)
To: linuxppc-dev list
Here's a new batch of the feature fixup updates.
Changes since last time:
- moves identify_cpu() to C code (removes more assembly gunk)
- works on 32 bits :)
- invert use of nested in MFTB for the cell fixup
- adds a patch for fixup in modules support
- the fixup code does 2 loops as suggested by Olof
The bulk could be merged if you want, except the cell TB fix which still
needs to change to the new workaround method. I haven't had time to
finish that today.
^ permalink raw reply
* Re: Recently removed io accessors
From: Benjamin Herrenschmidt @ 2006-10-13 7:31 UTC (permalink / raw)
To: Peter Korsgaard; +Cc: sfr, linuxppc-dev
In-Reply-To: <87iriovh3x.fsf@sleipner.barco.com>
On Fri, 2006-10-13 at 08:56 +0200, Peter Korsgaard wrote:
> >>>>> "BH" == Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:
>
> Hi,
>
> >> Any chance of getting them back or should I implement a (slower)
> >> loop myself before submitting the patch?
>
> BH> Well, a "packet buffer" should have no endian. When streaming in
> BH> our out a fifo, you basically stream bytes that happen to come out
> BH> 2 at a time. So unless somebody wired the hardware backward, you
> BH> should do no swapping when using the fifo.
>
> I agree in principle, but the issue gets complicated by the fact that
> the chip works in chunks of 32bit, but the 911{5..7} chips only have a
> 16bit interface to lower costs, and that the chip has a builtin endian
> swap feature (which works for all direct registers, but apparently not
> for the packet buffers).
>
> The memory controller automatically translates a 32bit access to two
> 16 bit accesses.
Well, that is not necessarily broken :)
> You could be right that the hw people screwed something up, but that
> doesn't help much once there's units in the field :/
Well, I still don't see it. It all depends how the HW has been wired I
suppose but you should not need byteswap regardless of the 32 bits being
broken in packs of 2x16 bits or whatever... If the chip has a HW
byteswap for registers and not for the packet buffer, that makes it even
more clear that such swapping should not be necessary.
Unless the chip has been wired backward on the processor bus (in which
case, btw, DMA will not work either unless you have one of those
magically swapping dma controllers)..
So I still claim that you should not need them and if you do, then the
chip has probably been incorrect wired to your CPU bus. In which case,
you can either grab an old copy of the functions and put them in your
driver for your platform or add a cpu_to_leXX() loop to byteswap the
data in/out, but it's probably not the right thing to do in the generic
driver since it would be a problem specific to your board.
Unless I'm missing something ... It would be useful to have more details
about your setup.
Cheers.
Ben.
^ permalink raw reply
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
From: Peter Korsgaard @ 2006-10-13 7:22 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <452F3A82.7070803@dlasys.net>
>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:
Hi,
David> Nobody has given me a reason yet why the UartLite should
David> init different from the 8250, and absent a reason, I would
David> mimic the 8250. I do not think there is reason for a different
David> routing name. The ml403 8250 init code deals with multiple
David> 8250's, I did the same with UartLite.
8250 is not the only serial driver. I think the reason why 8250 uses
it's own struct is simple that it's a really old driver. Newer drivers
like atmel_serial.c also uses the platform bus.
David> I am not sure I did nto follow everything on linux-serial -
David> but I think Peter was asked to remove support for additional
David> uarts. I am not sure why.
Remove support? I don't remember anything about that.
--
Bye, Peter Korsgaard
^ permalink raw reply
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
From: Peter Korsgaard @ 2006-10-13 7:15 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <452F36AE.6040205@dlasys.net>
>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:
Hi,
David> Peter's driver uses the IORESOURCE requests to pull platform
David> data. Most other serial platformdevices pull a uart_port
David> object. My limited understanding of IORESOURCE is that it is
David> not sufficiently deep to support the parameters that are needed
David> to support UartLite such as a DCR flag and a regoffset.
I'm still not convinced that DCR access and variable register offsets
are needed - But it can always be added (through a seperate struct in
platform_data) - Patches are welcome.
The same with interrupt-less support if the changes are not too
intrusive.
David> You are welcome to do that. I already patched his driver to
David> work with my early console support as well as adding the
David> boot-bash stuff similar to yours. But I gave up actually using
David> it when I could not get it to work.
Which is odd as I've gotten positive feedback from others.
David> Next time I get an opportunity I am going to try to setup an
David> ml403 to atleast verify that Peter's driver is working there.
Great.
--
Bye, Peter Korsgaard
^ permalink raw reply
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
From: Peter Korsgaard @ 2006-10-13 7:11 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <609d5c8e0610122221i7c5e5049n4db5fcf3f61bd132@mail.gmail.com>
>>>>> "David" == David Bolcsfoldi <dbolcsfoldi@gmail.com> writes:
David> Here's an initial patch based on a modified uartlite (by Peter
David> Korsgaard), it's by no means ment to be final and any feedback
David> would be appreciated.
Could you make it relative to my driver so the changes are easier to
see?
David> - readb/writeb to in_be32/out_be32.
David> For some reason on my board the readb and writeb don't behave
David> correctly when reading and writing to the uartlite device. I
David> haven't looked into it but if this is unacceptable I will try
David> to revert to readb/writeb.
The PPC is big endian - Did you remember to add 3 to your base
address?
--
Bye, Peter Korsgaard
^ permalink raw reply
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
From: David H. Lynch Jr. @ 2006-10-13 7:04 UTC (permalink / raw)
To: David Bolcsfoldi; +Cc: linuxppc-embedded
In-Reply-To: <609d5c8e0610122221i7c5e5049n4db5fcf3f61bd132@mail.gmail.com>
David Bolcsfoldi wrote:
> Here's an initial patch based on a modified uartlite (by Peter
> Korsgaard), it's by no means ment to be final and any feedback would
> be appreciated.
>
> What I have changed:
>
> - Early console support.
>
> Since the platform bus isn't initialized by the time the first printk
> comes I've added a call 'early_uart_get_pdev' fashioned after the CPM
> serial driver.
>
If you want to mess with this my recomendation would be to switch to
passing a uart_port
like the 8250 does. You can find 8250 early serial init code in
xilinx_ml403.c
I beleive the init routine is called early_console_init().
Nobody has given me a reason yet why the UartLite should init
different from the 8250,
and absent a reason, I would mimic the 8250. I do not think there is
reason for a different routing name.
The ml403 8250 init code deals with multiple 8250's, I did the same
with UartLite.
I am not sure I did nto follow everything on linux-serial - but I
think Peter was asked to remove support
for additional uarts. I am not sure why.
> - Platform device.
>
> The 'uartlite' is now a platform device although I am not entirely
> happy how this is done since there's only one VIRTEX_UARTLITE device
> with id of 0 although there might be several more described by the
> plafrom_data. Maybe the additional devices can be added to the
> platform bus in the probe call or would it be better to add these
> devices at compile time to the list of platform_devices in virtex.c?
>
> - readb/writeb to in_be32/out_be32.
>
> For some reason on my board the readb and writeb don't behave
> correctly when reading and writing to the uartlite device. I haven't
> looked into it but if this is unacceptable I will try to revert to
> readb/writeb.
>
I would appreciate some further elaboration. I think they were
working for me when I tried Peter's driver.
I even think that is one change I made to my own driver based on
Peter's.
But maybe I am wrong and that has something to do with my inability
to get Peter's driver working on my hardware.
> - Embedded boot serial support.
>
> There's now support for embedded boot serial I/O over uartlite device 0.
>
> - uartlite.h
>
To be consistent with other uarts I think it should be
include/linux/serial_uartlite.h
> A shared header file between the embedded boot serial driver and the
> real one with all the reg offsets and such. I don't know if the
> location for this file is ok though.
>
Finally, I think that this really needs submitted to linux-serial if
you are looking to get it in.
> diff -urN 2.6.18/arch/ppc/boot/common/misc-common.c
> patched-uartlite/arch/ppc/boot/common/misc-common.c
> --- 2.6.18/arch/ppc/boot/common/misc-common.c 2006-10-04
> 14:31:15.000000000 -0700
> +++ patched-uartlite/arch/ppc/boot/common/misc-common.c 2006-10-12
> 12:47:31.000000000 -0700
> @@ -57,7 +57,8 @
>
Just a minor nit, but you can make the patches simpler by adding
SERIAL_UARTLITE_CONSOLE into the middle of the list instead of the end.
> #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
> extern unsigned long com_port;
>
> extern int serial_tstc(unsigned long com_port);
> @@ -80,7 +81,8 @@
> {
> #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
> if(keyb_present)
> return (CRT_tstc() || serial_tstc(com_port));
> else
> @@ -95,7 +97,8 @@
> while (1) {
> #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
> if (serial_tstc(com_port))
> return (serial_getc(com_port));
> #endif /* serial console */
> @@ -112,7 +115,8 @@
>
> #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
> serial_putc(com_port, c);
> if ( c == '\n' )
> serial_putc(com_port, '\r');
> @@ -161,7 +165,8 @@
> while ( ( c = *s++ ) != '\0' ) {
> #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
> serial_putc(com_port, c);
> if ( c == '\n' ) serial_putc(com_port, '\r');
> #endif /* serial console */
> diff -urN 2.6.18/arch/ppc/boot/simple/Makefile
> patched-uartlite/arch/ppc/boot/simple/Makefile
> --- 2.6.18/arch/ppc/boot/simple/Makefile 2006-10-04 14:31:15.000000000 -0700
> +++ patched-uartlite/arch/ppc/boot/simple/Makefile 2006-10-12
> 12:45:53.000000000 -0700
> @@ -205,6 +205,7 @@
> endif
> boot-$(CONFIG_SERIAL_MPC52xx_CONSOLE) += mpc52xx_tty.o
> boot-$(CONFIG_SERIAL_MPSC_CONSOLE) += mv64x60_tty.o
> +boot-$(CONFIG_SERIAL_UARTLITE_CONSOLE) += uartlite_tty.o
>
> LIBS := $(common)/lib.a $(bootlib)/lib.a
> ifeq ($(CONFIG_PPC_PREP),y)
> diff -urN 2.6.18/arch/ppc/boot/simple/misc.c
> patched-uartlite/arch/ppc/boot/simple/misc.c
> --- 2.6.18/arch/ppc/boot/simple/misc.c 2006-10-04 14:31:15.000000000 -0700
> +++ patched-uartlite/arch/ppc/boot/simple/misc.c 2006-10-12
> 12:48:01.000000000 -0700
> @@ -48,7 +48,8 @@
> #if (defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_VGA_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)) \
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)) \
> && !defined(CONFIG_GEMINI)
> #define INTERACTIVE_CONSOLE 1
> #endif
> diff -urN 2.6.18/arch/ppc/boot/simple/uartlite_tty.c
> patched-uartlite/arch/ppc/boot/simple/uartlite_tty.c
> --- 2.6.18/arch/ppc/boot/simple/uartlite_tty.c 1969-12-31
> 16:00:00.000000000 -0800
> +++ patched-uartlite/arch/ppc/boot/simple/uartlite_tty.c 2006-10-12
> 22:10:44.000000000 -0700
> @@ -0,0 +1,69 @@
> +/*
> + * Xilinx UART Lite support.
> + * Right now it only works over UART0 and none other.
> + *
> + * Copyright (C) 2006 David Bolcsfoldi <dbolcsfoldi@gmail.com>
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +#include <asm/io.h>
> +#include <asm/uartlite.h>
> +#include <platforms/4xx/xparameters/xparameters.h>
> +
> +static inline int is_xmit_full(unsigned int address)
> +{
> + return ((in_be32((volatile unsigned *) (address + ULITE_STATUS)) &
> ULITE_STATUS_TXFULL) == ULITE_STATUS_TXFULL);
> +}
> +
> +static inline int is_recv_empty(unsigned int address)
> +{
> + return ((in_be32((volatile unsigned *) (address + ULITE_STATUS)) &
> ULITE_STATUS_RXVALID) != ULITE_STATUS_RXVALID);
> +}
> +
> +unsigned long serial_init(int chan, void *ignored)
> +{
> + switch (chan) {
> + #ifdef XPAR_XUL_UART_0_BASEADDR
> + case 0:
> + return XPAR_XUL_UART_0_BASEADDR;
> + #endif
> + #ifdef XPAR_XUL_UART_1_BASEADDR
> + case 1:
> + return XPAR_XUL_UART_1_BASEADDR;
> + #endif
> + #ifdef XPAR_XUL_UART_2_BASEADDR
> + case 2:
> + return XPAR_XUL_UART_2_BASEADDR;
> + #endif
> + #ifdef XPAR_XUL_UART_3_BASEADDR
> + case 3:
> + return XPAR_XUL_UART_3_BASEADDR;
> + #endif
> + default:
> + goto out;
> + }
> +
> +out:
> + return -1;
> +}
> +
> +void serial_putc(unsigned long com_port, unsigned char c)
> +{
> + while(is_xmit_full(XPAR_XUL_UART_0_BASEADDR));
> + out_be32((volatile unsigned *) (XPAR_XUL_UART_0_BASEADDR + ULITE_TX), c);
> +}
> +
> +unsigned char serial_getc(unsigned long com_port)
> +{
> + while(is_recv_empty(XPAR_XUL_UART_0_BASEADDR));
> + return in_be32((volatile unsigned *) (XPAR_XUL_UART_0_BASEADDR + ULITE_RX));
> +}
> +
> +int serial_tstc(unsigned long com_port)
> +{
> + return !(is_recv_empty(XPAR_XUL_UART_0_BASEADDR));
> +}
> +
> Binary files 2.6.18/arch/ppc/boot/simple/.uartlite_tty.c.swp and
> patched-uartlite/arch/ppc/boot/simple/.uartlite_tty.c.swp differ
> diff -urN 2.6.18/arch/ppc/platforms/4xx/virtex.c
> patched-uartlite/arch/ppc/platforms/4xx/virtex.c
> --- 2.6.18/arch/ppc/platforms/4xx/virtex.c 2006-10-04 14:31:15.000000000 -0700
> +++ patched-uartlite/arch/ppc/platforms/4xx/virtex.c 2006-10-12
> 16:37:23.000000000 -0700
> @@ -46,11 +46,71 @@
> { }, /* terminated by empty record */
> };
>
> +#define XPAR_UARTLITE(num) { \
> + .mapbase = XPAR_XUL_UART_##num##_BASEADDR, \
> + .irq = XPAR_INTC_0_XUL_UART_##num##_VEC_ID, \
> + .size = (XPAR_XUL_UART_##num##_HIGHADDR -
> XPAR_XUL_UART_##num##_BASEADDR) + 1, \
> + .baud = XPAR_XUL_UART_##num##_BAUDRATE, \
> + .bits = XPAR_XUL_UART_##num##_DATA_BITS, \
> + .parity = XPAR_XUL_UART_##num##_USE_PARITY, \
> + .odd_parity = XPAR_XUL_UART_##num##_ODD_PARITY, \
> +}
> +
> +struct plat_uartlite_port uartlite_platform_data[] = {
> +#ifdef XPAR_XUL_UART_0_BASEADDR
> + XPAR_UARTLITE(0),
> +#endif
> +#ifdef XPAR_XUL_UART_1_BASEADDR
> + XPAR_UARTLITE(1),
> +#endif
> +#ifdef XPAR_XUL_UART_2_BASEADDR
> + XPAR_UARTLITE(2),
> +#endif
> +#ifdef XPAR_XUL_UART_3_BASEADDR
> + XPAR_UARTLITE(3),
> +#endif
> + { }, /* terminated by empty record */
> +};
> +
> struct platform_device ppc_sys_platform_devices[] = {
> [VIRTEX_UART] = {
> .name = "serial8250",
> .id = 0,
> .dev.platform_data = serial_platform_data,
> },
> +
> + [VIRTEX_UARTLITE] = {
> + .name = "uartlite",
> + .id = 0,
> + .dev.platform_data = uartlite_platform_data,
> +#ifdef XPAR_XUL_UART_0_BASEADDR
> + .num_resources = 2,
> + .resource = (struct resource[]) {
> + {
> + .start = XPAR_XUL_UART_0_BASEADDR,
> + .end = XPAR_XUL_UART_0_HIGHADDR,
> + .flags = IORESOURCE_MEM,
> + },
> + {
> + .start = XPAR_INTC_0_XUL_UART_0_VEC_ID,
> + .end = XPAR_INTC_0_XUL_UART_0_VEC_ID,
> + .flags = IORESOURCE_IRQ,
> + },
> + },
> +#endif /* XPAR_XUL_UART_0_BASEADDR */
> + },
> };
>
> +/* For early console on the uartlite serial port some way of
> + * getting to the platform_device is needed */
> +
> +struct platform_device* early_uart_get_pdev(int dev)
> +{
> + if (dev < 0 ||
> + dev >= NUM_PPC_SYS_DEVS) {
> + return NULL;
> + }
> +
> + return &ppc_sys_platform_devices[dev];
> +}
> +
> diff -urN 2.6.18/arch/ppc/platforms/4xx/virtex.h
> patched-uartlite/arch/ppc/platforms/4xx/virtex.h
> --- 2.6.18/arch/ppc/platforms/4xx/virtex.h 2006-10-04 14:31:15.000000000 -0700
> +++ patched-uartlite/arch/ppc/platforms/4xx/virtex.h 2006-10-12
> 16:37:41.000000000 -0700
> @@ -27,8 +27,21 @@
> /* Device type enumeration for platform bus definitions */
> #ifndef __ASSEMBLY__
> enum ppc_sys_devices {
> - VIRTEX_UART, NUM_PPC_SYS_DEVS,
> + VIRTEX_UART,
> + VIRTEX_UARTLITE,
> + NUM_PPC_SYS_DEVS,
> };
> +
> +struct plat_uartlite_port {
> + unsigned int mapbase;
> + unsigned int irq;
> + unsigned int size;
> + unsigned int baud;
> + unsigned char bits;
> + unsigned char parity;
> + unsigned char odd_parity;
> +};
> +
> #endif
>
> #endif /* __ASM_VIRTEX_H__ */
> diff -urN 2.6.18/arch/ppc/platforms/4xx/xilinx_ml403.c
> patched-uartlite/arch/ppc/platforms/4xx/xilinx_ml403.c
> --- 2.6.18/arch/ppc/platforms/4xx/xilinx_ml403.c 2006-10-04
> 14:31:15.000000000 -0700
> +++ patched-uartlite/arch/ppc/platforms/4xx/xilinx_ml403.c 2006-10-12
> 13:15:36.000000000 -0700
> @@ -65,10 +65,11 @@
> .ppc_sys_name = "Xilinx ML403 Reference Design",
> .mask = 0x00000000,
> .value = 0x00000000,
> - .num_devices = 1,
> + .num_devices = 2,
> .device_list = (enum ppc_sys_devices[])
> {
> VIRTEX_UART,
> + VIRTEX_UARTLITE,
> },
> },
> };
> diff -urN 2.6.18/drivers/serial/Kconfig patched-uartlite/drivers/serial/Kconfig
> --- 2.6.18/drivers/serial/Kconfig 2006-10-04 14:31:18.000000000 -0700
> +++ patched-uartlite/drivers/serial/Kconfig 2006-10-12 12:15:32.000000000 -0700
> @@ -511,6 +511,25 @@
> your boot loader (lilo or loadlin) about how to pass options to the
> kernel at boot time.)
>
> +config SERIAL_UARTLITE
> + tristate "Xilinx uartlite serial port support"
> + depends on PPC32
> + select SERIAL_CORE
> + help
> + Say Y here if you want to use the Xilinx uartlite serial controller.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called uartlite.ko.
> +
> +config SERIAL_UARTLITE_CONSOLE
> + bool "Support for console on Xilinx uartlite serial port"
> + depends on SERIAL_UARTLITE=y
> + select SERIAL_CORE_CONSOLE
> + help
> + Say Y here if you wish to use a Xilinx uartlite as the system
> + console (the system console is the device which receives all kernel
> + messages and warnings and which allows logins in single user mode).
> +
> config SERIAL_SUNCORE
> bool
> depends on SPARC
> diff -urN 2.6.18/drivers/serial/Makefile
> patched-uartlite/drivers/serial/Makefile
> --- 2.6.18/drivers/serial/Makefile 2006-10-04 14:31:18.000000000 -0700
> +++ patched-uartlite/drivers/serial/Makefile 2006-10-12 12:15:32.000000000 -0700
> @@ -55,4 +55,5 @@
> obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
> obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
> obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
> +obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
> obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
> diff -urN 2.6.18/drivers/serial/uartlite.c
> patched-uartlite/drivers/serial/uartlite.c
> --- 2.6.18/drivers/serial/uartlite.c 1969-12-31 16:00:00.000000000 -0800
> +++ patched-uartlite/drivers/serial/uartlite.c 2006-10-12
> 22:10:57.000000000 -0700
> @@ -0,0 +1,551 @@
> +/*
> + * uartlite.c: Serial driver for Xilinx uartlite serial controller
> + *
> + * Peter Korsgaard <jacmet@sunsite.dk>
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +#include <linux/platform_device.h>
> +#include <linux/module.h>
> +#include <linux/console.h>
> +#include <linux/serial.h>
> +#include <linux/serial_core.h>
> +#include <linux/tty.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <asm/io.h>
> +#include <asm/uartlite.h>
> +
> +#define ULITE_MAJOR 204
> +#define ULITE_MINOR 187
> +#define ULITE_NR_UARTS 4
> +
> +static struct uart_port ports[ULITE_NR_UARTS];
> +
> +/* Place-holder for board-specific stuff */
> +struct platform_device* __attribute__ ((weak)) __init
> +early_uart_get_pdev(int index)
> +{
> + return NULL;
> +}
> +
> +static int ulite_receive(struct uart_port *port, int stat)
> +{
> + struct tty_struct *tty = port->info->tty;
> + unsigned char ch = 0;
> + char flag = TTY_NORMAL;
> +
> + if ((stat & (ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
> + | ULITE_STATUS_FRAME)) == 0)
> + return 0;
> +
> + /* stats */
> + if (stat & ULITE_STATUS_RXVALID) {
> + port->icount.rx++;
> + ch = in_be32((unsigned volatile *) (port->membase + ULITE_RX));
> +
> + if (stat & ULITE_STATUS_PARITY)
> + port->icount.parity++;
> + }
> +
> + if (stat & ULITE_STATUS_OVERRUN)
> + port->icount.overrun++;
> +
> + if (stat & ULITE_STATUS_FRAME)
> + port->icount.frame++;
> +
> +
> + /* drop byte with parity error if IGNPAR specificed */
> + if (stat & port->ignore_status_mask & ULITE_STATUS_PARITY)
> + stat &= ~ULITE_STATUS_RXVALID;
> +
> + stat &= port->read_status_mask;
> +
> + if (stat & ULITE_STATUS_PARITY)
> + flag = TTY_PARITY;
> +
> +
> + stat &= ~port->ignore_status_mask;
> +
> + if (stat & ULITE_STATUS_RXVALID)
> + tty_insert_flip_char(tty, ch, flag);
> +
> + if (stat & ULITE_STATUS_FRAME)
> + tty_insert_flip_char(tty, 0, TTY_FRAME);
> +
> + if (stat & ULITE_STATUS_OVERRUN)
> + tty_insert_flip_char(tty, 0, TTY_OVERRUN);
> +
> + return 1;
> +}
> +
> +static int ulite_transmit(struct uart_port *port, int stat)
> +{
> + struct circ_buf *xmit = &port->info->xmit;
> +
> + if (stat & ULITE_STATUS_TXFULL)
> + return 0;
> +
> + if (port->x_char) {
> + out_be32((unsigned volatile *) (port->membase + ULITE_TX), port->x_char);
> + port->x_char = 0;
> + port->icount.tx++;
> + return 1;
> + }
> +
> + if (uart_circ_empty(xmit) || uart_tx_stopped(port))
> + return 0;
> +
> + out_be32((unsigned volatile *) (port->membase + ULITE_TX),
> xmit->buf[xmit->tail]);
> + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
> + port->icount.tx++;
> +
> + /* wake up */
> + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> + uart_write_wakeup(port);
> +
> + return 1;
> +}
> +
> +static irqreturn_t ulite_isr(int irq, void *dev_id, struct pt_regs *regs)
> +{
> + struct uart_port *port = (struct uart_port *)dev_id;
> + int busy;
> +
> + spin_lock(&port->lock); /* Lock the port in case of printk */
> +
> + do {
> + int stat = in_be32((unsigned volatile *) (port->membase + ULITE_STATUS));
> + busy = ulite_receive(port, stat);
> + busy |= ulite_transmit(port, stat);
> + } while (busy);
> +
> + spin_unlock(&port->lock);
> +
> + tty_flip_buffer_push(port->info->tty);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static unsigned int ulite_tx_empty(struct uart_port *port)
> +{
> + unsigned long flags;
> + unsigned int ret;
> +
> + spin_lock_irqsave(&port->lock, flags);
> + ret = in_be32((unsigned volatile *) (port->membase + ULITE_STATUS));
> + spin_unlock_irqrestore(&port->lock, flags);
> +
> + return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
> +}
> +
> +static unsigned int ulite_get_mctrl(struct uart_port *port)
> +{
> + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
> +}
> +
> +static void ulite_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> + /* N/A */
> +}
> +
> +static void ulite_stop_tx(struct uart_port *port)
> +{
> + /* N/A */
> +}
> +
> +static void ulite_start_tx(struct uart_port *port)
> +{
> + ulite_transmit(port, in_be32((unsigned volatile *) (port->membase +
> ULITE_STATUS)));
> +}
> +
> +static void ulite_stop_rx(struct uart_port *port)
> +{
> + /* don't forward any more data (like !CREAD) */
> + port->ignore_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
> + | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
> +}
> +
> +static void ulite_enable_ms(struct uart_port *port)
> +{
> + /* N/A */
> +}
> +
> +static void ulite_break_ctl(struct uart_port *port, int ctl)
> +{
> + /* N/A */
> +}
> +
> +static int ulite_startup(struct uart_port *port)
> +{
> + int ret;
> +
> + ret = request_irq(port->irq, ulite_isr,
> + IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "uartlite", port);
> + if (ret)
> + return ret;
> +
> + out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL),
> ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX);
> + out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL),
> ULITE_CONTROL_IE);
> +
> + return 0;
> +}
> +
> +static void ulite_shutdown(struct uart_port *port)
> +{
> + writeb(0, port->membase + ULITE_CONTROL);
> + free_irq(port->irq, port);
> +}
> +
> +static void ulite_set_termios(struct uart_port *port, struct termios *termios,
> + struct termios *old)
> +{
> + struct plat_uartlite_port *uport;
> + unsigned long flags;
> + unsigned int baud;
> +
> + spin_lock_irqsave(&port->lock, flags);
> +
> + port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
> + | ULITE_STATUS_TXFULL;
> +
> + if (termios->c_iflag & INPCK)
> + port->read_status_mask |=
> + ULITE_STATUS_PARITY | ULITE_STATUS_FRAME;
> +
> + port->ignore_status_mask = 0;
> + if (termios->c_iflag & IGNPAR)
> + port->ignore_status_mask |= ULITE_STATUS_PARITY
> + | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
> +
> + /* ignore all characters if CREAD is not set */
> + if ((termios->c_cflag & CREAD) == 0)
> + port->ignore_status_mask |=
> + ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
> + | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
> +
> + /* update timeout */
> + uport = &((struct plat_uartlite_port *)port->dev->platform_data)[port->line];
> +
> + baud = uart_get_baud_rate(port, termios, old, uport->baud, uport->baud);
> + uart_update_timeout(port, termios->c_cflag, baud);
> +
> + spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static const char *ulite_type(struct uart_port *port)
> +{
> + return port->type == PORT_UARTLITE ? "uartlite" : NULL;
> +}
> +
> +static void ulite_release_port(struct uart_port *port)
> +{
> + release_mem_region(port->mapbase, ULITE_REGION);
> + iounmap(port->membase);
> + port->membase = 0;
> +}
> +
> +static int ulite_request_port(struct uart_port *port)
> +{
> + if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) {
> + dev_err(port->dev, "Memory region busy\n");
> + return -EBUSY;
> + }
> +
> + if (port->flags & UPF_IOREMAP) {
> + port->membase = ioremap(port->mapbase, ULITE_REGION);
> + }
> +
> + if (!port->membase) {
> + dev_err(port->dev, "Unable to map registers\n");
> + release_mem_region(port->mapbase, ULITE_REGION);
> + return -EBUSY;
> + }
> +
> + return 0;
> +}
> +
> +static void ulite_config_port(struct uart_port *port, int flags)
> +{
> + ulite_request_port(port);
> + port->type = PORT_UARTLITE;
> +}
> +
> +static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
> +{
> + /* we don't want the core code to modify any port params */
> + return -EINVAL;
> +}
> +
> +static struct uart_ops ulite_ops = {
> + .tx_empty = ulite_tx_empty,
> + .set_mctrl = ulite_set_mctrl,
> + .get_mctrl = ulite_get_mctrl,
> + .stop_tx = ulite_stop_tx,
> + .start_tx = ulite_start_tx,
> + .stop_rx = ulite_stop_rx,
> + .enable_ms = ulite_enable_ms,
> + .break_ctl = ulite_break_ctl,
> + .startup = ulite_startup,
> + .shutdown = ulite_shutdown,
> + .set_termios = ulite_set_termios,
> + .type = ulite_type,
> + .release_port = ulite_release_port,
> + .request_port = ulite_request_port,
> + .config_port = ulite_config_port,
> + .verify_port = ulite_verify_port
> +};
> +
> +static inline void ulite_init_port(struct uart_port *port)
> +{
> + port->uartclk = 0;
> + port->membase = 0;
> + port->fifosize = 16;
> + port->regshift = 2;
> + port->iobase = 1; /* Mark port in use */
> + port->iotype = UPIO_MEM;
> + port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
> + port->ops = &ulite_ops;
> + port->type = PORT_UNKNOWN;
> +}
> +
> +#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
> +static void ulite_console_wait_tx(struct uart_port *port)
> +{
> + int i;
> +
> + /* wait up to 10ms for the character(s) to be sent */
> + for (i=0; i<10000; i++) {
> + if (in_be32((unsigned volatile *) (port->membase + ULITE_STATUS)) &
> ULITE_STATUS_TXEMPTY)
> + break;
> + udelay(1);
> + }
> +}
> +
> +static void ulite_console_putchar(struct uart_port *port, int ch)
> +{
> + ulite_console_wait_tx(port);
> + out_be32((unsigned volatile *) (port->membase + ULITE_TX), ch);
> +}
> +
> +static void ulite_console_write(struct console *co, const char *s,
> + unsigned int count)
> +{
> + struct uart_port *port = &ports[co->index];
> + unsigned long flags;
> + unsigned int ier;
> + int locked = 1;
> +
> + if (oops_in_progress) {
> + locked = spin_trylock_irqsave(&port->lock, flags);
> + } else
> + spin_lock_irqsave(&port->lock, flags);
> +
> + /* save and disable interrupt */
> + ier = in_be32((unsigned volatile *) (port->membase + ULITE_STATUS))
> & ULITE_STATUS_IE;
> +
> + //writeb(0, port->membase + ULITE_CONTROL);
> + out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL), 0);
> +
> + uart_console_write(port, s, count, ulite_console_putchar);
> +
> + ulite_console_wait_tx(port);
> +
> + /* restore interrupt state */
> + if (ier)
> + out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL),
> ULITE_CONTROL_IE);
> +
> + if (locked)
> + spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static int __init ulite_console_setup(struct console *co, char *options)
> +{
> + int i;
> + struct uart_port *port;
> + struct platform_device *pdev;
> + struct plat_uartlite_port *uport;
> +
> + if (co->index < 0 || co->index >= ULITE_NR_UARTS)
> + return -EINVAL;
> +
> + port = &ports[co->index];
> +
> + /* not initialized yet? */
> + if (!port->membase) {
> + /* We might be early console */
> + pdev = early_uart_get_pdev(VIRTEX_UARTLITE);
> +
> + if (pdev == NULL) {
> + return -ENODEV;
> + }
> +
> + uport = pdev->dev.platform_data;
> +
> + for (i = 0; i <= co->index; ++i) {
> + /* We need to count the number of ports available */
> + /* List of ports is terminated by a 0 record */
> +
> + if (uport[i].baud == 0) {
> + return -ENODEV;
> + }
> + }
> +
> + ulite_init_port(port);
> +
> + port->irq = uport[co->index].irq;
> + port->mapbase = uport[co->index].mapbase;
> + port->line = co->index;
> + spin_lock_init(&port->lock);
> + port->membase = ioremap(port->mapbase, ULITE_REGION);
> +
> + if(port->membase == NULL) {
> + port->iobase = 0;
> + return -EINVAL;
> + }
> +
> + /* Clear ioremap since this port has been mapped already */
> + port->flags &= ~UPF_IOREMAP;
> + }
> +
> + return 0;
> +}
> +
> +static struct uart_driver ulite_uart_driver;
> +
> +static struct console ulite_console = {
> + .name = "ttyUL",
> + .write = ulite_console_write,
> + .device = uart_console_device,
> + .setup = ulite_console_setup,
> + .flags = CON_PRINTBUFFER,
> + .index = -1, /* Specified on the cmdline (e.g. console=ttyUL0 ) */
> + .data = &ulite_uart_driver,
> +};
> +
> +static int __init ulite_console_init(void)
> +{
> + register_console(&ulite_console);
> + return 0;
> +}
> +
> +console_initcall(ulite_console_init);
> +
> +#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
> +
> +static struct uart_driver ulite_uart_driver = {
> + .owner = THIS_MODULE,
> + .driver_name = "uartlite",
> + .dev_name = "ttyUL",
> + .major = ULITE_MAJOR,
> + .minor = ULITE_MINOR,
> + .nr = ULITE_NR_UARTS,
> +#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
> + .cons = &ulite_console,
> +#endif
> +};
> +
> +static int __devinit ulite_probe(struct platform_device *pdev)
> +{
> + struct resource *res, *res2;
> + struct uart_port *port;
> + int ret;
> +
> + if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS)
> + return -EINVAL;
> +
> + if (ports[pdev->id].membase) {
> + if (ports[pdev->id].flags & UPF_IOREMAP) {
> + return -EBUSY; /* Port is busy */
> + }
> +
> + else {
> + /* This port as be remapped so it must have been an early console */
> + port = &ports[pdev->id];
> + goto add_port;
> + }
> + }
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +
> + if (!res)
> + return -ENODEV;
> +
> + res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +
> + if (!res2)
> + return -ENODEV;
> +
> + port = &ports[pdev->id];
> +
> + ulite_init_port(port);
> +
> + port->mapbase = res->start;
> + port->irq = res2->start;
> + port->line = pdev->id;
> +
> +add_port:
> + port->dev = &pdev->dev;
> +
> + ret = uart_add_one_port(&ulite_uart_driver, port);
> +
> + if(ret == 0)
> + platform_set_drvdata(pdev, port);
> +
> + return ret;
> +}
> +
> +static int ulite_remove(struct platform_device *pdev)
> +{
> + struct uart_port *port = platform_get_drvdata(pdev);
> +
> + platform_set_drvdata(pdev, NULL);
> +
> + if (port)
> + uart_remove_one_port(&ulite_uart_driver, port);
> +
> + /* mark port as free */
> + port->membase = 0;
> +
> + return 0;
> +}
> +
> +static struct platform_driver ulite_platform_driver = {
> + .probe = ulite_probe,
> + .remove = ulite_remove,
> + .driver = {
> + .owner = THIS_MODULE,
> + .name = "uartlite",
> + },
> +};
> +
> +int __init ulite_init(void)
> +{
> + int ret;
> +
> + ret = uart_register_driver(&ulite_uart_driver);
> + if (ret)
> + return ret;
> +
> + ret = platform_driver_register(&ulite_platform_driver);
> + if (ret)
> + uart_unregister_driver(&ulite_uart_driver);
> +
> + return ret;
> +}
> +
> +void __exit ulite_exit(void)
> +{
> + platform_driver_unregister(&ulite_platform_driver);
> + uart_unregister_driver(&ulite_uart_driver);
> +}
> +
> +module_init(ulite_init);
> +module_exit(ulite_exit);
> +
> +MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
> +MODULE_DESCRIPTION("Xilinx uartlite serial driver");
> +MODULE_LICENSE("GPL");
> Binary files 2.6.18/drivers/serial/.uartlite.c.swp and
> patched-uartlite/drivers/serial/.uartlite.c.swp differ
> diff -urN 2.6.18/include/asm-ppc/uartlite.h
> patched-uartlite/include/asm-ppc/uartlite.h
> --- 2.6.18/include/asm-ppc/uartlite.h 1969-12-31 16:00:00.000000000 -0800
> +++ patched-uartlite/include/asm-ppc/uartlite.h 2006-10-12
> 21:53:00.000000000 -0700
> @@ -0,0 +1,28 @@
> +#ifndef __ASM_UARTLITE_H__
> +#define __ASM_UARTLITE_H__
> +
> +/* For register details see datasheet:
> + http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf
> +*/
> +#define ULITE_RX 0x00
> +#define ULITE_TX 0x04
> +#define ULITE_STATUS 0x08
> +#define ULITE_CONTROL 0x0c
> +
> +#define ULITE_REGION 16
> +
> +#define ULITE_STATUS_RXVALID 0x01
> +#define ULITE_STATUS_RXFULL 0x02
> +#define ULITE_STATUS_TXEMPTY 0x04
> +#define ULITE_STATUS_TXFULL 0x08
> +#define ULITE_STATUS_IE 0x10
> +#define ULITE_STATUS_OVERRUN 0x20
> +#define ULITE_STATUS_FRAME 0x40
> +#define ULITE_STATUS_PARITY 0x80
> +
> +#define ULITE_CONTROL_RST_TX 0x01
> +#define ULITE_CONTROL_RST_RX 0x02
> +#define ULITE_CONTROL_IE 0x10
> +
> +#endif /* __ASM_UARTLITE_H__ */
> +
> diff -urN 2.6.18/include/linux/serial_core.h
> patched-uartlite/include/linux/serial_core.h
> --- 2.6.18/include/linux/serial_core.h 2006-10-04 14:31:19.000000000 -0700
> +++ patched-uartlite/include/linux/serial_core.h 2006-10-12
> 12:15:32.000000000 -0700
> @@ -132,6 +132,8 @@
>
> #define PORT_S3C2412 73
>
> +/* Xilinx uartlite */
> +#define PORT_UARTLITE 74
>
> #ifdef __KERNEL__
>
> diff -urN 2.6.18/MAINTAINERS patched-uartlite/MAINTAINERS
> --- 2.6.18/MAINTAINERS 2006-10-04 14:31:14.000000000 -0700
> +++ patched-uartlite/MAINTAINERS 2006-10-12 12:15:32.000000000 -0700
> @@ -3311,6 +3311,12 @@
> T: git git://oss.sgi.com:8090/xfs/xfs-2.6
> S: Supported
>
> +XILINX UARTLITE SERIAL DRIVER
> +P: Peter Korsgaard
> +M: jacmet@sunsite.dk
> +L: linux-serial@vger.kernel.org
> +S: Maintained
> +
> X86 3-LEVEL PAGING (PAE) SUPPORT
> P: Ingo Molnar
> M: mingo@redhat.com
> --
>
> Cheers,
> David
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>
--
Dave Lynch DLA Systems
Software Development: Embedded Linux
717.627.3770 dhlii@dlasys.net http://www.dlasys.net
fax: 1.253.369.9244 Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.
"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein
^ permalink raw reply
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
From: Peter Korsgaard @ 2006-10-13 7:08 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <609d5c8e0610121412o1288ef6i667b908597bf3d76@mail.gmail.com>
>>>>> "David" == David Bolcsfoldi <dbolcsfoldi@gmail.com> writes:
Hi,
David> No I did not know that unfortunately, it could have saved me
David> some work. You are of course right and I'd much prefer to make
David> changes to your driver instead of writing another one.
It unfortunately happens all the time - Googling a bit around before
writing code often pays off ;)
David> I've noticed that in the probe function it tries to get some
David> resources from the platform_device structure but it looks like
David> that this operation will always fail unless I add a 'uartlite'
David> platform device or have I completely misunderstood how platform
David> devices work?
Yes, you need a platform device with the info, E.G. something like:
#include <linux/platform_device.h>
static struct resource myuartlite_resources[] = {
[0] = {
.start = 0xa1000003,
.end = 0xa1000012,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 2,
.end = 2,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device my_uartlite = {
.name = "uartlite",
.id = 0,
.num_resources = ARRAY_SIZE(myuartlite_resources),
.resource = myuartlite_resources,
.dev.platform_data = 0,
};
Which you then add to the platform bus (platform_add_devices).
David> But yes, I will try to add support for the things I need to
David> this driver instead, most importantly early console support and
David> move the #defines for register offsets and such into a separate
David> header file per Grants comment.
Great!
--
Bye, Peter Korsgaard
^ permalink raw reply
* unresolved symbol on target ... while insmod
From: kwkang @ 2006-10-13 6:49 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 518 bytes --]
Hi Srideep,
Can anyone show me how I can overcome below problem?
I have searched mailing list but I can not find any answer for that problem.
[test ~]#insmod linux-kernel-bde.o
Using linux-kernel-bde.o
Using linux-kernel-bde.o
insmod: Warning: kernel-module version mismatch
linux-kernel-bde.o was compiled for kernel version 2.4.20_dev
while this kernel is version 2.4.21-pre5
insmod: unresolved symbol devfs_register
insmod: unresolved symbol devfs_unregister
Thanks.
William.
[-- Attachment #2: Type: text/html, Size: 5638 bytes --]
^ permalink raw reply
* Re: Recently removed io accessors
From: Peter Korsgaard @ 2006-10-13 6:56 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: sfr, linuxppc-dev
In-Reply-To: <1160697861.4792.177.camel@localhost.localdomain>
>>>>> "BH" == Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:
Hi,
>> Any chance of getting them back or should I implement a (slower)
>> loop myself before submitting the patch?
BH> Well, a "packet buffer" should have no endian. When streaming in
BH> our out a fifo, you basically stream bytes that happen to come out
BH> 2 at a time. So unless somebody wired the hardware backward, you
BH> should do no swapping when using the fifo.
I agree in principle, but the issue gets complicated by the fact that
the chip works in chunks of 32bit, but the 911{5..7} chips only have a
16bit interface to lower costs, and that the chip has a builtin endian
swap feature (which works for all direct registers, but apparently not
for the packet buffers).
The memory controller automatically translates a 32bit access to two
16 bit accesses.
You could be right that the hw people screwed something up, but that
doesn't help much once there's units in the field :/
--
Bye, Peter Korsgaard
^ permalink raw reply
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
From: David H. Lynch Jr. @ 2006-10-13 6:48 UTC (permalink / raw)
To: David Bolcsfoldi; +Cc: linuxppc-embedded
In-Reply-To: <609d5c8e0610121412o1288ef6i667b908597bf3d76@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 3876 bytes --]
David Bolcsfoldi wrote:
> No I did not know that unfortunately, it could have saved me some work.
> You are of course right and I'd much prefer to make changes to your driver
> instead of writing another one.
>
I am sorry you put so much effort in. However, you could have
checked the archives.
I think there are atleast 3 different UartLite drivers posted since
January.
It would be really nice if we could all standardize on one driver.
But I would not sweat this too much.
Peter ignored the fact that my driver was posted here in January,
too and went off and wrote his own
which does not have early serial port - yours and mine do.
and does not have polled support - mine does.
and does not have DCR support - there is another one out there that
has DCR support.
and I can not get to work on my hardware - the only Xilinx V4 based
product that actually defaults to a UartLite
> I've noticed that in the probe function it tries to get some resources
> from the platform_device structure but it looks like that this
> operation will always fail unless I add a 'uartlite' platform device
> or have I completely misunderstood how platform devices work?
>
Peter's driver uses the IORESOURCE requests to pull platform data.
Most other serial platformdevices pull a uart_port object.
My limited understanding of IORESOURCE is that it is not
sufficiently deep to support
the parameters that are needed to support UartLite such as a DCR
flag and a regoffset.
Counting yours that is 4.
> But yes, I will try to add support for the things I need to this
> driver instead, most importantly early console support and move the
> #defines for register offsets and such into a separate header file per
> Grants comments
>
You are welcome to do that. I already patched his driver to work
with my early console support as well as adding the boot-bash stuff
similar to yours. But I gave up actually using it when I could not
get it to work.
Next time I get an opportunity I am going to try to setup an ml403
to atleast verify that Peter's driver is working there.
> Cheers,
> David
>
> On 10/12/06, Peter Korsgaard <jacmet@sunsite.dk> wrote:
>
>>>>>>> "David" == David Bolcsfoldi <dbolcsfoldi@gmail.com> writes:
>>>>>>>
>> Hi David,
>>
>> David> here's a set of patches that adds support for Xilinx UART lite
>> David> devices. It has been tested on an ML403-FX using xapp902
>> David> (ml403_ppc_plb_temac) using a 2.6.18 kernel and a BusyBox
>> David> userspace.
>>
>> I guess you didn't know, but there already exists a uartlite driver!
>> It unfortunately didn't made it into 2.6.19-rc1 because Russell
>> stopped maintaining serial stuff, but it's in -mm.
>>
>> It also has an official lanana.org assigned set of device nodes.
>>
>> I didn't look at your patch yet, but I think it would be more useful
>> to add any features missing to my driver than writing yet another
>> driver (I think we're up to 3 now).
>>
>> --
>> Bye, Peter Korsgaard
>> _______________________________________________
>> Linuxppc-embedded mailing list
>> Linuxppc-embedded@ozlabs.org
>> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>>
>>
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>
--
Dave Lynch DLA Systems
Software Development: Embedded Linux
717.627.3770 dhlii@dlasys.net http://www.dlasys.net
fax: 1.253.369.9244 Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.
"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein
[-- Attachment #2: Type: text/html, Size: 5960 bytes --]
^ permalink raw reply
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
From: David Bolcsfoldi @ 2006-10-13 5:21 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <609d5c8e0610121412o1288ef6i667b908597bf3d76@mail.gmail.com>
Here's an initial patch based on a modified uartlite (by Peter
Korsgaard), it's by no means ment to be final and any feedback would
be appreciated.
What I have changed:
- Early console support.
Since the platform bus isn't initialized by the time the first printk
comes I've added a call 'early_uart_get_pdev' fashioned after the CPM
serial driver.
- Platform device.
The 'uartlite' is now a platform device although I am not entirely
happy how this is done since there's only one VIRTEX_UARTLITE device
with id of 0 although there might be several more described by the
plafrom_data. Maybe the additional devices can be added to the
platform bus in the probe call or would it be better to add these
devices at compile time to the list of platform_devices in virtex.c?
- readb/writeb to in_be32/out_be32.
For some reason on my board the readb and writeb don't behave
correctly when reading and writing to the uartlite device. I haven't
looked into it but if this is unacceptable I will try to revert to
readb/writeb.
- Embedded boot serial support.
There's now support for embedded boot serial I/O over uartlite device 0.
- uartlite.h
A shared header file between the embedded boot serial driver and the
real one with all the reg offsets and such. I don't know if the
location for this file is ok though.
diff -urN 2.6.18/arch/ppc/boot/common/misc-common.c
patched-uartlite/arch/ppc/boot/common/misc-common.c
--- 2.6.18/arch/ppc/boot/common/misc-common.c 2006-10-04
14:31:15.000000000 -0700
+++ patched-uartlite/arch/ppc/boot/common/misc-common.c 2006-10-12
12:47:31.000000000 -0700
@@ -57,7 +57,8 @@
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
extern unsigned long com_port;
extern int serial_tstc(unsigned long com_port);
@@ -80,7 +81,8 @@
{
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
if(keyb_present)
return (CRT_tstc() || serial_tstc(com_port));
else
@@ -95,7 +97,8 @@
while (1) {
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
if (serial_tstc(com_port))
return (serial_getc(com_port));
#endif /* serial console */
@@ -112,7 +115,8 @@
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
serial_putc(com_port, c);
if ( c == '\n' )
serial_putc(com_port, '\r');
@@ -161,7 +165,8 @@
while ( ( c = *s++ ) != '\0' ) {
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
serial_putc(com_port, c);
if ( c == '\n' ) serial_putc(com_port, '\r');
#endif /* serial console */
diff -urN 2.6.18/arch/ppc/boot/simple/Makefile
patched-uartlite/arch/ppc/boot/simple/Makefile
--- 2.6.18/arch/ppc/boot/simple/Makefile 2006-10-04 14:31:15.000000000 -0700
+++ patched-uartlite/arch/ppc/boot/simple/Makefile 2006-10-12
12:45:53.000000000 -0700
@@ -205,6 +205,7 @@
endif
boot-$(CONFIG_SERIAL_MPC52xx_CONSOLE) += mpc52xx_tty.o
boot-$(CONFIG_SERIAL_MPSC_CONSOLE) += mv64x60_tty.o
+boot-$(CONFIG_SERIAL_UARTLITE_CONSOLE) += uartlite_tty.o
LIBS := $(common)/lib.a $(bootlib)/lib.a
ifeq ($(CONFIG_PPC_PREP),y)
diff -urN 2.6.18/arch/ppc/boot/simple/misc.c
patched-uartlite/arch/ppc/boot/simple/misc.c
--- 2.6.18/arch/ppc/boot/simple/misc.c 2006-10-04 14:31:15.000000000 -0700
+++ patched-uartlite/arch/ppc/boot/simple/misc.c 2006-10-12
12:48:01.000000000 -0700
@@ -48,7 +48,8 @@
#if (defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_VGA_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)) \
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)) \
&& !defined(CONFIG_GEMINI)
#define INTERACTIVE_CONSOLE 1
#endif
diff -urN 2.6.18/arch/ppc/boot/simple/uartlite_tty.c
patched-uartlite/arch/ppc/boot/simple/uartlite_tty.c
--- 2.6.18/arch/ppc/boot/simple/uartlite_tty.c 1969-12-31
16:00:00.000000000 -0800
+++ patched-uartlite/arch/ppc/boot/simple/uartlite_tty.c 2006-10-12
22:10:44.000000000 -0700
@@ -0,0 +1,69 @@
+/*
+ * Xilinx UART Lite support.
+ * Right now it only works over UART0 and none other.
+ *
+ * Copyright (C) 2006 David Bolcsfoldi <dbolcsfoldi@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <asm/io.h>
+#include <asm/uartlite.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+
+static inline int is_xmit_full(unsigned int address)
+{
+ return ((in_be32((volatile unsigned *) (address + ULITE_STATUS)) &
ULITE_STATUS_TXFULL) == ULITE_STATUS_TXFULL);
+}
+
+static inline int is_recv_empty(unsigned int address)
+{
+ return ((in_be32((volatile unsigned *) (address + ULITE_STATUS)) &
ULITE_STATUS_RXVALID) != ULITE_STATUS_RXVALID);
+}
+
+unsigned long serial_init(int chan, void *ignored)
+{
+ switch (chan) {
+ #ifdef XPAR_XUL_UART_0_BASEADDR
+ case 0:
+ return XPAR_XUL_UART_0_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_1_BASEADDR
+ case 1:
+ return XPAR_XUL_UART_1_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_2_BASEADDR
+ case 2:
+ return XPAR_XUL_UART_2_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_3_BASEADDR
+ case 3:
+ return XPAR_XUL_UART_3_BASEADDR;
+ #endif
+ default:
+ goto out;
+ }
+
+out:
+ return -1;
+}
+
+void serial_putc(unsigned long com_port, unsigned char c)
+{
+ while(is_xmit_full(XPAR_XUL_UART_0_BASEADDR));
+ out_be32((volatile unsigned *) (XPAR_XUL_UART_0_BASEADDR + ULITE_TX), c);
+}
+
+unsigned char serial_getc(unsigned long com_port)
+{
+ while(is_recv_empty(XPAR_XUL_UART_0_BASEADDR));
+ return in_be32((volatile unsigned *) (XPAR_XUL_UART_0_BASEADDR + ULITE_RX));
+}
+
+int serial_tstc(unsigned long com_port)
+{
+ return !(is_recv_empty(XPAR_XUL_UART_0_BASEADDR));
+}
+
Binary files 2.6.18/arch/ppc/boot/simple/.uartlite_tty.c.swp and
patched-uartlite/arch/ppc/boot/simple/.uartlite_tty.c.swp differ
diff -urN 2.6.18/arch/ppc/platforms/4xx/virtex.c
patched-uartlite/arch/ppc/platforms/4xx/virtex.c
--- 2.6.18/arch/ppc/platforms/4xx/virtex.c 2006-10-04 14:31:15.000000000 -0700
+++ patched-uartlite/arch/ppc/platforms/4xx/virtex.c 2006-10-12
16:37:23.000000000 -0700
@@ -46,11 +46,71 @@
{ }, /* terminated by empty record */
};
+#define XPAR_UARTLITE(num) { \
+ .mapbase = XPAR_XUL_UART_##num##_BASEADDR, \
+ .irq = XPAR_INTC_0_XUL_UART_##num##_VEC_ID, \
+ .size = (XPAR_XUL_UART_##num##_HIGHADDR -
XPAR_XUL_UART_##num##_BASEADDR) + 1, \
+ .baud = XPAR_XUL_UART_##num##_BAUDRATE, \
+ .bits = XPAR_XUL_UART_##num##_DATA_BITS, \
+ .parity = XPAR_XUL_UART_##num##_USE_PARITY, \
+ .odd_parity = XPAR_XUL_UART_##num##_ODD_PARITY, \
+}
+
+struct plat_uartlite_port uartlite_platform_data[] = {
+#ifdef XPAR_XUL_UART_0_BASEADDR
+ XPAR_UARTLITE(0),
+#endif
+#ifdef XPAR_XUL_UART_1_BASEADDR
+ XPAR_UARTLITE(1),
+#endif
+#ifdef XPAR_XUL_UART_2_BASEADDR
+ XPAR_UARTLITE(2),
+#endif
+#ifdef XPAR_XUL_UART_3_BASEADDR
+ XPAR_UARTLITE(3),
+#endif
+ { }, /* terminated by empty record */
+};
+
struct platform_device ppc_sys_platform_devices[] = {
[VIRTEX_UART] = {
.name = "serial8250",
.id = 0,
.dev.platform_data = serial_platform_data,
},
+
+ [VIRTEX_UARTLITE] = {
+ .name = "uartlite",
+ .id = 0,
+ .dev.platform_data = uartlite_platform_data,
+#ifdef XPAR_XUL_UART_0_BASEADDR
+ .num_resources = 2,
+ .resource = (struct resource[]) {
+ {
+ .start = XPAR_XUL_UART_0_BASEADDR,
+ .end = XPAR_XUL_UART_0_HIGHADDR,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = XPAR_INTC_0_XUL_UART_0_VEC_ID,
+ .end = XPAR_INTC_0_XUL_UART_0_VEC_ID,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+#endif /* XPAR_XUL_UART_0_BASEADDR */
+ },
};
+/* For early console on the uartlite serial port some way of
+ * getting to the platform_device is needed */
+
+struct platform_device* early_uart_get_pdev(int dev)
+{
+ if (dev < 0 ||
+ dev >= NUM_PPC_SYS_DEVS) {
+ return NULL;
+ }
+
+ return &ppc_sys_platform_devices[dev];
+}
+
diff -urN 2.6.18/arch/ppc/platforms/4xx/virtex.h
patched-uartlite/arch/ppc/platforms/4xx/virtex.h
--- 2.6.18/arch/ppc/platforms/4xx/virtex.h 2006-10-04 14:31:15.000000000 -0700
+++ patched-uartlite/arch/ppc/platforms/4xx/virtex.h 2006-10-12
16:37:41.000000000 -0700
@@ -27,8 +27,21 @@
/* Device type enumeration for platform bus definitions */
#ifndef __ASSEMBLY__
enum ppc_sys_devices {
- VIRTEX_UART, NUM_PPC_SYS_DEVS,
+ VIRTEX_UART,
+ VIRTEX_UARTLITE,
+ NUM_PPC_SYS_DEVS,
};
+
+struct plat_uartlite_port {
+ unsigned int mapbase;
+ unsigned int irq;
+ unsigned int size;
+ unsigned int baud;
+ unsigned char bits;
+ unsigned char parity;
+ unsigned char odd_parity;
+};
+
#endif
#endif /* __ASM_VIRTEX_H__ */
diff -urN 2.6.18/arch/ppc/platforms/4xx/xilinx_ml403.c
patched-uartlite/arch/ppc/platforms/4xx/xilinx_ml403.c
--- 2.6.18/arch/ppc/platforms/4xx/xilinx_ml403.c 2006-10-04
14:31:15.000000000 -0700
+++ patched-uartlite/arch/ppc/platforms/4xx/xilinx_ml403.c 2006-10-12
13:15:36.000000000 -0700
@@ -65,10 +65,11 @@
.ppc_sys_name = "Xilinx ML403 Reference Design",
.mask = 0x00000000,
.value = 0x00000000,
- .num_devices = 1,
+ .num_devices = 2,
.device_list = (enum ppc_sys_devices[])
{
VIRTEX_UART,
+ VIRTEX_UARTLITE,
},
},
};
diff -urN 2.6.18/drivers/serial/Kconfig patched-uartlite/drivers/serial/Kconfig
--- 2.6.18/drivers/serial/Kconfig 2006-10-04 14:31:18.000000000 -0700
+++ patched-uartlite/drivers/serial/Kconfig 2006-10-12 12:15:32.000000000 -0700
@@ -511,6 +511,25 @@
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
+config SERIAL_UARTLITE
+ tristate "Xilinx uartlite serial port support"
+ depends on PPC32
+ select SERIAL_CORE
+ help
+ Say Y here if you want to use the Xilinx uartlite serial controller.
+
+ To compile this driver as a module, choose M here: the
+ module will be called uartlite.ko.
+
+config SERIAL_UARTLITE_CONSOLE
+ bool "Support for console on Xilinx uartlite serial port"
+ depends on SERIAL_UARTLITE=y
+ select SERIAL_CORE_CONSOLE
+ help
+ Say Y here if you wish to use a Xilinx uartlite as the system
+ console (the system console is the device which receives all kernel
+ messages and warnings and which allows logins in single user mode).
+
config SERIAL_SUNCORE
bool
depends on SPARC
diff -urN 2.6.18/drivers/serial/Makefile
patched-uartlite/drivers/serial/Makefile
--- 2.6.18/drivers/serial/Makefile 2006-10-04 14:31:18.000000000 -0700
+++ patched-uartlite/drivers/serial/Makefile 2006-10-12 12:15:32.000000000 -0700
@@ -55,4 +55,5 @@
obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
+obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
diff -urN 2.6.18/drivers/serial/uartlite.c
patched-uartlite/drivers/serial/uartlite.c
--- 2.6.18/drivers/serial/uartlite.c 1969-12-31 16:00:00.000000000 -0800
+++ patched-uartlite/drivers/serial/uartlite.c 2006-10-12
22:10:57.000000000 -0700
@@ -0,0 +1,551 @@
+/*
+ * uartlite.c: Serial driver for Xilinx uartlite serial controller
+ *
+ * Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/uartlite.h>
+
+#define ULITE_MAJOR 204
+#define ULITE_MINOR 187
+#define ULITE_NR_UARTS 4
+
+static struct uart_port ports[ULITE_NR_UARTS];
+
+/* Place-holder for board-specific stuff */
+struct platform_device* __attribute__ ((weak)) __init
+early_uart_get_pdev(int index)
+{
+ return NULL;
+}
+
+static int ulite_receive(struct uart_port *port, int stat)
+{
+ struct tty_struct *tty = port->info->tty;
+ unsigned char ch = 0;
+ char flag = TTY_NORMAL;
+
+ if ((stat & (ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
+ | ULITE_STATUS_FRAME)) == 0)
+ return 0;
+
+ /* stats */
+ if (stat & ULITE_STATUS_RXVALID) {
+ port->icount.rx++;
+ ch = in_be32((unsigned volatile *) (port->membase + ULITE_RX));
+
+ if (stat & ULITE_STATUS_PARITY)
+ port->icount.parity++;
+ }
+
+ if (stat & ULITE_STATUS_OVERRUN)
+ port->icount.overrun++;
+
+ if (stat & ULITE_STATUS_FRAME)
+ port->icount.frame++;
+
+
+ /* drop byte with parity error if IGNPAR specificed */
+ if (stat & port->ignore_status_mask & ULITE_STATUS_PARITY)
+ stat &= ~ULITE_STATUS_RXVALID;
+
+ stat &= port->read_status_mask;
+
+ if (stat & ULITE_STATUS_PARITY)
+ flag = TTY_PARITY;
+
+
+ stat &= ~port->ignore_status_mask;
+
+ if (stat & ULITE_STATUS_RXVALID)
+ tty_insert_flip_char(tty, ch, flag);
+
+ if (stat & ULITE_STATUS_FRAME)
+ tty_insert_flip_char(tty, 0, TTY_FRAME);
+
+ if (stat & ULITE_STATUS_OVERRUN)
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
+ return 1;
+}
+
+static int ulite_transmit(struct uart_port *port, int stat)
+{
+ struct circ_buf *xmit = &port->info->xmit;
+
+ if (stat & ULITE_STATUS_TXFULL)
+ return 0;
+
+ if (port->x_char) {
+ out_be32((unsigned volatile *) (port->membase + ULITE_TX), port->x_char);
+ port->x_char = 0;
+ port->icount.tx++;
+ return 1;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+ return 0;
+
+ out_be32((unsigned volatile *) (port->membase + ULITE_TX),
xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
+ port->icount.tx++;
+
+ /* wake up */
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ return 1;
+}
+
+static irqreturn_t ulite_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct uart_port *port = (struct uart_port *)dev_id;
+ int busy;
+
+ spin_lock(&port->lock); /* Lock the port in case of printk */
+
+ do {
+ int stat = in_be32((unsigned volatile *) (port->membase + ULITE_STATUS));
+ busy = ulite_receive(port, stat);
+ busy |= ulite_transmit(port, stat);
+ } while (busy);
+
+ spin_unlock(&port->lock);
+
+ tty_flip_buffer_push(port->info->tty);
+
+ return IRQ_HANDLED;
+}
+
+static unsigned int ulite_tx_empty(struct uart_port *port)
+{
+ unsigned long flags;
+ unsigned int ret;
+
+ spin_lock_irqsave(&port->lock, flags);
+ ret = in_be32((unsigned volatile *) (port->membase + ULITE_STATUS));
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int ulite_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void ulite_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ /* N/A */
+}
+
+static void ulite_stop_tx(struct uart_port *port)
+{
+ /* N/A */
+}
+
+static void ulite_start_tx(struct uart_port *port)
+{
+ ulite_transmit(port, in_be32((unsigned volatile *) (port->membase +
ULITE_STATUS)));
+}
+
+static void ulite_stop_rx(struct uart_port *port)
+{
+ /* don't forward any more data (like !CREAD) */
+ port->ignore_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
+ | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
+}
+
+static void ulite_enable_ms(struct uart_port *port)
+{
+ /* N/A */
+}
+
+static void ulite_break_ctl(struct uart_port *port, int ctl)
+{
+ /* N/A */
+}
+
+static int ulite_startup(struct uart_port *port)
+{
+ int ret;
+
+ ret = request_irq(port->irq, ulite_isr,
+ IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "uartlite", port);
+ if (ret)
+ return ret;
+
+ out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL),
ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX);
+ out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL),
ULITE_CONTROL_IE);
+
+ return 0;
+}
+
+static void ulite_shutdown(struct uart_port *port)
+{
+ writeb(0, port->membase + ULITE_CONTROL);
+ free_irq(port->irq, port);
+}
+
+static void ulite_set_termios(struct uart_port *port, struct termios *termios,
+ struct termios *old)
+{
+ struct plat_uartlite_port *uport;
+ unsigned long flags;
+ unsigned int baud;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
+ | ULITE_STATUS_TXFULL;
+
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |=
+ ULITE_STATUS_PARITY | ULITE_STATUS_FRAME;
+
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= ULITE_STATUS_PARITY
+ | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
+
+ /* ignore all characters if CREAD is not set */
+ if ((termios->c_cflag & CREAD) == 0)
+ port->ignore_status_mask |=
+ ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
+ | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
+
+ /* update timeout */
+ uport = &((struct plat_uartlite_port *)port->dev->platform_data)[port->line];
+
+ baud = uart_get_baud_rate(port, termios, old, uport->baud, uport->baud);
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *ulite_type(struct uart_port *port)
+{
+ return port->type == PORT_UARTLITE ? "uartlite" : NULL;
+}
+
+static void ulite_release_port(struct uart_port *port)
+{
+ release_mem_region(port->mapbase, ULITE_REGION);
+ iounmap(port->membase);
+ port->membase = 0;
+}
+
+static int ulite_request_port(struct uart_port *port)
+{
+ if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) {
+ dev_err(port->dev, "Memory region busy\n");
+ return -EBUSY;
+ }
+
+ if (port->flags & UPF_IOREMAP) {
+ port->membase = ioremap(port->mapbase, ULITE_REGION);
+ }
+
+ if (!port->membase) {
+ dev_err(port->dev, "Unable to map registers\n");
+ release_mem_region(port->mapbase, ULITE_REGION);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static void ulite_config_port(struct uart_port *port, int flags)
+{
+ ulite_request_port(port);
+ port->type = PORT_UARTLITE;
+}
+
+static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ /* we don't want the core code to modify any port params */
+ return -EINVAL;
+}
+
+static struct uart_ops ulite_ops = {
+ .tx_empty = ulite_tx_empty,
+ .set_mctrl = ulite_set_mctrl,
+ .get_mctrl = ulite_get_mctrl,
+ .stop_tx = ulite_stop_tx,
+ .start_tx = ulite_start_tx,
+ .stop_rx = ulite_stop_rx,
+ .enable_ms = ulite_enable_ms,
+ .break_ctl = ulite_break_ctl,
+ .startup = ulite_startup,
+ .shutdown = ulite_shutdown,
+ .set_termios = ulite_set_termios,
+ .type = ulite_type,
+ .release_port = ulite_release_port,
+ .request_port = ulite_request_port,
+ .config_port = ulite_config_port,
+ .verify_port = ulite_verify_port
+};
+
+static inline void ulite_init_port(struct uart_port *port)
+{
+ port->uartclk = 0;
+ port->membase = 0;
+ port->fifosize = 16;
+ port->regshift = 2;
+ port->iobase = 1; /* Mark port in use */
+ port->iotype = UPIO_MEM;
+ port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+ port->ops = &ulite_ops;
+ port->type = PORT_UNKNOWN;
+}
+
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+static void ulite_console_wait_tx(struct uart_port *port)
+{
+ int i;
+
+ /* wait up to 10ms for the character(s) to be sent */
+ for (i=0; i<10000; i++) {
+ if (in_be32((unsigned volatile *) (port->membase + ULITE_STATUS)) &
ULITE_STATUS_TXEMPTY)
+ break;
+ udelay(1);
+ }
+}
+
+static void ulite_console_putchar(struct uart_port *port, int ch)
+{
+ ulite_console_wait_tx(port);
+ out_be32((unsigned volatile *) (port->membase + ULITE_TX), ch);
+}
+
+static void ulite_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct uart_port *port = &ports[co->index];
+ unsigned long flags;
+ unsigned int ier;
+ int locked = 1;
+
+ if (oops_in_progress) {
+ locked = spin_trylock_irqsave(&port->lock, flags);
+ } else
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* save and disable interrupt */
+ ier = in_be32((unsigned volatile *) (port->membase + ULITE_STATUS))
& ULITE_STATUS_IE;
+
+ //writeb(0, port->membase + ULITE_CONTROL);
+ out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL), 0);
+
+ uart_console_write(port, s, count, ulite_console_putchar);
+
+ ulite_console_wait_tx(port);
+
+ /* restore interrupt state */
+ if (ier)
+ out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL),
ULITE_CONTROL_IE);
+
+ if (locked)
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int __init ulite_console_setup(struct console *co, char *options)
+{
+ int i;
+ struct uart_port *port;
+ struct platform_device *pdev;
+ struct plat_uartlite_port *uport;
+
+ if (co->index < 0 || co->index >= ULITE_NR_UARTS)
+ return -EINVAL;
+
+ port = &ports[co->index];
+
+ /* not initialized yet? */
+ if (!port->membase) {
+ /* We might be early console */
+ pdev = early_uart_get_pdev(VIRTEX_UARTLITE);
+
+ if (pdev == NULL) {
+ return -ENODEV;
+ }
+
+ uport = pdev->dev.platform_data;
+
+ for (i = 0; i <= co->index; ++i) {
+ /* We need to count the number of ports available */
+ /* List of ports is terminated by a 0 record */
+
+ if (uport[i].baud == 0) {
+ return -ENODEV;
+ }
+ }
+
+ ulite_init_port(port);
+
+ port->irq = uport[co->index].irq;
+ port->mapbase = uport[co->index].mapbase;
+ port->line = co->index;
+ spin_lock_init(&port->lock);
+ port->membase = ioremap(port->mapbase, ULITE_REGION);
+
+ if(port->membase == NULL) {
+ port->iobase = 0;
+ return -EINVAL;
+ }
+
+ /* Clear ioremap since this port has been mapped already */
+ port->flags &= ~UPF_IOREMAP;
+ }
+
+ return 0;
+}
+
+static struct uart_driver ulite_uart_driver;
+
+static struct console ulite_console = {
+ .name = "ttyUL",
+ .write = ulite_console_write,
+ .device = uart_console_device,
+ .setup = ulite_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1, /* Specified on the cmdline (e.g. console=ttyUL0 ) */
+ .data = &ulite_uart_driver,
+};
+
+static int __init ulite_console_init(void)
+{
+ register_console(&ulite_console);
+ return 0;
+}
+
+console_initcall(ulite_console_init);
+
+#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
+
+static struct uart_driver ulite_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "uartlite",
+ .dev_name = "ttyUL",
+ .major = ULITE_MAJOR,
+ .minor = ULITE_MINOR,
+ .nr = ULITE_NR_UARTS,
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+ .cons = &ulite_console,
+#endif
+};
+
+static int __devinit ulite_probe(struct platform_device *pdev)
+{
+ struct resource *res, *res2;
+ struct uart_port *port;
+ int ret;
+
+ if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS)
+ return -EINVAL;
+
+ if (ports[pdev->id].membase) {
+ if (ports[pdev->id].flags & UPF_IOREMAP) {
+ return -EBUSY; /* Port is busy */
+ }
+
+ else {
+ /* This port as be remapped so it must have been an early console */
+ port = &ports[pdev->id];
+ goto add_port;
+ }
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!res)
+ return -ENODEV;
+
+ res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+
+ if (!res2)
+ return -ENODEV;
+
+ port = &ports[pdev->id];
+
+ ulite_init_port(port);
+
+ port->mapbase = res->start;
+ port->irq = res2->start;
+ port->line = pdev->id;
+
+add_port:
+ port->dev = &pdev->dev;
+
+ ret = uart_add_one_port(&ulite_uart_driver, port);
+
+ if(ret == 0)
+ platform_set_drvdata(pdev, port);
+
+ return ret;
+}
+
+static int ulite_remove(struct platform_device *pdev)
+{
+ struct uart_port *port = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (port)
+ uart_remove_one_port(&ulite_uart_driver, port);
+
+ /* mark port as free */
+ port->membase = 0;
+
+ return 0;
+}
+
+static struct platform_driver ulite_platform_driver = {
+ .probe = ulite_probe,
+ .remove = ulite_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "uartlite",
+ },
+};
+
+int __init ulite_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&ulite_uart_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&ulite_platform_driver);
+ if (ret)
+ uart_unregister_driver(&ulite_uart_driver);
+
+ return ret;
+}
+
+void __exit ulite_exit(void)
+{
+ platform_driver_unregister(&ulite_platform_driver);
+ uart_unregister_driver(&ulite_uart_driver);
+}
+
+module_init(ulite_init);
+module_exit(ulite_exit);
+
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("Xilinx uartlite serial driver");
+MODULE_LICENSE("GPL");
Binary files 2.6.18/drivers/serial/.uartlite.c.swp and
patched-uartlite/drivers/serial/.uartlite.c.swp differ
diff -urN 2.6.18/include/asm-ppc/uartlite.h
patched-uartlite/include/asm-ppc/uartlite.h
--- 2.6.18/include/asm-ppc/uartlite.h 1969-12-31 16:00:00.000000000 -0800
+++ patched-uartlite/include/asm-ppc/uartlite.h 2006-10-12
21:53:00.000000000 -0700
@@ -0,0 +1,28 @@
+#ifndef __ASM_UARTLITE_H__
+#define __ASM_UARTLITE_H__
+
+/* For register details see datasheet:
+ http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf
+*/
+#define ULITE_RX 0x00
+#define ULITE_TX 0x04
+#define ULITE_STATUS 0x08
+#define ULITE_CONTROL 0x0c
+
+#define ULITE_REGION 16
+
+#define ULITE_STATUS_RXVALID 0x01
+#define ULITE_STATUS_RXFULL 0x02
+#define ULITE_STATUS_TXEMPTY 0x04
+#define ULITE_STATUS_TXFULL 0x08
+#define ULITE_STATUS_IE 0x10
+#define ULITE_STATUS_OVERRUN 0x20
+#define ULITE_STATUS_FRAME 0x40
+#define ULITE_STATUS_PARITY 0x80
+
+#define ULITE_CONTROL_RST_TX 0x01
+#define ULITE_CONTROL_RST_RX 0x02
+#define ULITE_CONTROL_IE 0x10
+
+#endif /* __ASM_UARTLITE_H__ */
+
diff -urN 2.6.18/include/linux/serial_core.h
patched-uartlite/include/linux/serial_core.h
--- 2.6.18/include/linux/serial_core.h 2006-10-04 14:31:19.000000000 -0700
+++ patched-uartlite/include/linux/serial_core.h 2006-10-12
12:15:32.000000000 -0700
@@ -132,6 +132,8 @@
#define PORT_S3C2412 73
+/* Xilinx uartlite */
+#define PORT_UARTLITE 74
#ifdef __KERNEL__
diff -urN 2.6.18/MAINTAINERS patched-uartlite/MAINTAINERS
--- 2.6.18/MAINTAINERS 2006-10-04 14:31:14.000000000 -0700
+++ patched-uartlite/MAINTAINERS 2006-10-12 12:15:32.000000000 -0700
@@ -3311,6 +3311,12 @@
T: git git://oss.sgi.com:8090/xfs/xfs-2.6
S: Supported
+XILINX UARTLITE SERIAL DRIVER
+P: Peter Korsgaard
+M: jacmet@sunsite.dk
+L: linux-serial@vger.kernel.org
+S: Maintained
+
X86 3-LEVEL PAGING (PAE) SUPPORT
P: Ingo Molnar
M: mingo@redhat.com
--
Cheers,
David
^ permalink raw reply
* [PATCH] powerpc: change bad ptr handling in simple_alloc
From: Mark A. Greer @ 2006-10-13 3:59 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <20061012013544.GE9143@mag.az.mvista.com>
Some minor changes to simple_alloc.c:
- Make simple_realloc return NULL if the ptr passed to it wasn't from a
previous simple_malloc or simple_realloc.
- Change tracking of base of unused memory.
Signed-off-by: Mark A. Greer <mgreer@mvista.com>
---
simple_alloc.c | 19 ++++++++++---------
1 files changed, 10 insertions(+), 9 deletions(-)
---
diff --git a/arch/powerpc/boot/simple_alloc.c b/arch/powerpc/boot/simple_alloc.c
index 478a381..7cc3389 100644
--- a/arch/powerpc/boot/simple_alloc.c
+++ b/arch/powerpc/boot/simple_alloc.c
@@ -26,6 +26,7 @@ static struct alloc_info {
static u32 tbl_entries;
static u32 alloc_min;
+static u32 next_base;
static u32 space_left;
/*
@@ -36,20 +37,20 @@ static u32 space_left;
static void *simple_malloc(u32 size)
{
u32 i;
- struct alloc_info *p = alloc_tbl, *prevp = NULL;
+ struct alloc_info *p = alloc_tbl;
if (size == 0)
goto err_out;
size = _ALIGN_UP(size, alloc_min);
- for (i=0; i<tbl_entries; i++) {
+ for (i=0; i<tbl_entries; i++, p++)
if (!(p->flags & ENTRY_BEEN_USED)) { /* never been used */
if (size <= space_left) {
- if (i > 0)
- p->base = prevp->base + prevp->size;
+ p->base = next_base;
p->size = size;
p->flags = ENTRY_BEEN_USED | ENTRY_IN_USE;
+ next_base += size;
space_left -= size;
return (void *)p->base;
}
@@ -60,8 +61,6 @@ static void *simple_malloc(u32 size)
p->flags |= ENTRY_IN_USE;
return (void *)p->base;
}
- prevp = p++;
- }
err_out:
return NULL;
}
@@ -103,10 +102,12 @@ static void *simple_realloc(void *ptr, u
return NULL;
}
- /* also malloc if ptr didn't come from simple_malloc/realloc */
- if ((ptr == NULL) || ((p = simple_find_entry(ptr)) == NULL))
+ if (ptr == NULL)
return simple_malloc(size);
+ p = simple_find_entry(ptr);
+ if (p == NULL) /* ptr not from simple_malloc/simple_realloc */
+ return NULL;
if (size <= p->size) /* fits in current block */
return ptr;
@@ -136,7 +137,7 @@ void *simple_alloc_init(char *base, u32
heap_base = _ALIGN_UP((u32)alloc_tbl + tbl_size, alloc_min);
- alloc_tbl[0].base = heap_base;
+ next_base = heap_base;
space_left = heap_size;
platform_ops.malloc = simple_malloc;
^ permalink raw reply related
* [PATCH] powerpc: realloc & other bug fixes for flatdevtree
From: Mark A. Greer @ 2006-10-13 3:57 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <20061012013427.GC9143@mag.az.mvista.com>
Fix some bugs in flatdevtree.c:
- ft_reorder should update cxt->p.
- ft_make_space didn't follow realloc() semantics properly and
accessed freed memory.
- Fix some other bugs in ft_make_space.
- Don't set cxt->isordered in ft_open to force an ft_reorder the first
time ft_make_space is called. Required so that a malloc is used to
get a pointer that the the realloc in ft_make_space can validly use
later.
- Make ft_end_tree only call adjust_string_offsets if the offsets changed.
Signed-off-by: Mark A. Greer <mgreer@mvista.com>
---
flatdevtree.c | 22 +++++++++++++---------
1 files changed, 13 insertions(+), 9 deletions(-)
---
diff --git a/arch/powerpc/boot/flatdevtree.c b/arch/powerpc/boot/flatdevtree.c
index 0d24f50..c76c194 100644
--- a/arch/powerpc/boot/flatdevtree.c
+++ b/arch/powerpc/boot/flatdevtree.c
@@ -176,6 +176,7 @@ static int ft_reorder(struct ft_cxt *cxt
memcpy(p, cxt->rgn[FT_STRUCT].start, cxt->rgn[FT_STRUCT].size);
ft_node_update_after(cxt, cxt->rgn[FT_STRUCT].start,
p - cxt->rgn[FT_STRUCT].start);
+ cxt->p += p - cxt->rgn[FT_STRUCT].start;
cxt->rgn[FT_STRUCT].start = p;
p = pend - cxt->rgn[FT_STRINGS].size;
@@ -281,7 +282,7 @@ static int ft_make_space(struct ft_cxt *
/* cast is to shut gcc up; we know nextra >= 0 */
if (tot < (unsigned int)nextra) {
/* have to reallocate */
- char *newp, *oldp, *new_start;
+ char *newp, *new_start;
int shift;
if (!cxt->realloc)
@@ -291,21 +292,18 @@ static int ft_make_space(struct ft_cxt *
if (!newp)
return 0;
cxt->max_size = size;
- oldp = (char *)cxt->bph;
- shift = newp - oldp;
+ shift = newp - (char *)cxt->bph;
- if (shift != 0) { /* realloc can return same addr */
+ if (shift) { /* realloc can return same addr */
cxt->bph = (struct boot_param_header *)newp;
- memmove(newp, oldp, sizeof(struct boot_param_header));
ft_node_update_after(cxt, cxt->rgn[FT_STRUCT].start,
shift);
- for (r = FT_RSVMAP; r <= FT_STRUCT; ++r) {
+ for (r = FT_RSVMAP; r <= FT_STRINGS; ++r) {
new_start = cxt->rgn[r].start + shift;
- memmove(new_start, cxt->rgn[r].start,
- cxt->rgn[r].size);
cxt->rgn[r].start = new_start;
}
*pp += shift;
+ cxt->str_anchor += shift;
}
/* move strings up to the end */
@@ -561,7 +559,10 @@ int ft_open(struct ft_cxt *cxt, void *bl
cxt->rgn[FT_STRUCT].size = struct_size(cxt);
cxt->rgn[FT_STRINGS].start = blob + be32_to_cpu(bph->off_dt_strings);
cxt->rgn[FT_STRINGS].size = be32_to_cpu(bph->dt_strings_size);
+ /* Leave as '0' to force first ft_make_space call to do a ft_reorder
+ * and move dt to an area allocated by realloc.
cxt->isordered = ft_ordered(cxt);
+ */
cxt->p = cxt->rgn[FT_STRUCT].start;
cxt->str_anchor = cxt->rgn[FT_STRINGS].start;
@@ -597,13 +598,16 @@ void ft_end_tree(struct ft_cxt *cxt)
struct boot_param_header *bph = cxt->bph;
char *p, *oldstr, *str, *endp;
unsigned long ssize;
+ int adj;
if (!cxt->isordered)
return; /* we haven't touched anything */
/* adjust string offsets */
oldstr = cxt->rgn[FT_STRINGS].start;
- adjust_string_offsets(cxt, cxt->str_anchor - oldstr);
+ adj = cxt->str_anchor - oldstr;
+ if (adj)
+ adjust_string_offsets(cxt, adj);
/* make strings end on 8-byte boundary */
ssize = cxt->rgn[FT_STRINGS].size;
^ permalink raw reply related
* Re: [PATCH 1/2] Add support for stopping spus from xmon
From: Luke Browning @ 2006-10-13 3:18 UTC (permalink / raw)
To: Michael Ellerman
Cc: linuxppc-dev, linuxppc-dev-bounces+lukebrowning=us.ibm.com,
Arnd Bergmann, cbe-oss-dev
In-Reply-To: <20061012120310.6B5A967BD5@ozlabs.org>
[-- Attachment #1: Type: text/plain, Size: 7685 bytes --]
linuxppc-dev-bounces+lukebrowning=us.ibm.com@ozlabs.org wrote on
10/12/2006 09:03:08 AM:
> This patch adds support for stopping, and restarting, spus
> from xmon. We use the spu master runcntl bit to stop execution,
> this is apparently the "right" way to control spu execution and
> spufs will be changed in the future to use this bit.
>
> Testing has shown that to restart execution we have to turn the
> master runcntl bit on and also rewrite the spu runcntl bit, even
> if it is already set to 1 (running).
>
> Stopping spus is triggered by the xmon command 'ss' - "spus stop"
> perhaps. Restarting them is triggered via 'sr'. Restart doesn't
> start execution on spus unless they were running prior to being
> stopped by xmon.
>
> Walking the spu->full_list in xmon after a panic, would mean
> corruption of any spu struct would make all the others
> inaccessible. To avoid this, and also to make the next patch
> easier, we cache pointers to all spus during boot.
The spe affinity code drop created an array of spu pointers that
is indexed by spu->number. We have a couple of other fields in
there that are needed for multiple spu scheduling operations.
Maybe, you can use this array. The name of the arry is lspu[]
for logical spus.
>
> We attempt to catch and recover from errors while stopping and
> restarting the spus, but as with most xmon functionality there are
> no guarantees that performing these operations won't crash xmon
> itself.
>
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
> ---
>
> arch/powerpc/platforms/cell/spu_base.c | 4
> arch/powerpc/xmon/xmon.c | 142
> ++++++++++++++++++++++++++++++++-
> include/asm-powerpc/xmon.h | 2
> 3 files changed, 146 insertions(+), 2 deletions(-)
>
> Index: to-merge/arch/powerpc/platforms/cell/spu_base.c
> ===================================================================
> --- to-merge.orig/arch/powerpc/platforms/cell/spu_base.c
> +++ to-merge/arch/powerpc/platforms/cell/spu_base.c
> @@ -38,6 +38,7 @@
> #include <asm/spu.h>
> #include <asm/spu_priv1.h>
> #include <asm/mmu_context.h>
> +#include <asm/xmon.h>
>
> #include "interrupt.h"
>
> @@ -914,6 +915,9 @@ static int __init init_spu_base(void)
> break;
> }
> }
> +
> + xmon_register_spus(&spu_full_list);
> +
> return ret;
> }
> module_init(init_spu_base);
> Index: to-merge/arch/powerpc/xmon/xmon.c
> ===================================================================
> --- to-merge.orig/arch/powerpc/xmon/xmon.c
> +++ to-merge/arch/powerpc/xmon/xmon.c
> @@ -35,6 +35,8 @@
> #include <asm/rtas.h>
> #include <asm/sstep.h>
> #include <asm/bug.h>
> +#include <asm/spu.h>
> +#include <asm/spu_priv1.h>
>
> #ifdef CONFIG_PPC64
> #include <asm/hvcall.h>
> @@ -145,6 +147,8 @@ static void xmon_print_symbol(unsigned l
> const char *after);
> static const char *getvecname(unsigned long vec);
>
> +static int do_spu_cmd(void);
> +
> int xmon_no_auto_backtrace;
>
> extern int print_insn_powerpc(unsigned long, unsigned long, int);
> @@ -207,8 +211,12 @@ Commands:\n\
> mi show information about memory allocation\n\
> p call a procedure\n\
> r print registers\n\
> - s single step\n\
> - S print special registers\n\
> + s single step\n"
> +#ifdef CONFIG_PPC_CELL
> +" ss stop execution on all spus\n\
> + sr restore execution on stopped spus\n"
> +#endif
> +" S print special registers\n\
> t print backtrace\n\
> x exit monitor and recover\n\
> X exit monitor and dont recover\n"
> @@ -516,6 +524,7 @@ int xmon(struct pt_regs *excp)
> xmon_save_regs(®s);
> excp = ®s;
> }
> +
> return xmon_core(excp, 0);
> }
> EXPORT_SYMBOL(xmon);
> @@ -808,6 +817,8 @@ cmds(struct pt_regs *excp)
> cacheflush();
> break;
> case 's':
> + if (do_spu_cmd() == 0)
> + break;
> if (do_step(excp))
> return cmd;
> break;
> @@ -2630,3 +2641,130 @@ void __init xmon_setup(void)
> if (xmon_early)
> debugger(NULL);
> }
> +
> +#ifdef CONFIG_PPC_CELL
> +
> +struct spu_info {
> + struct spu *spu;
> + u64 saved_mfc_sr1_RW;
> + u32 saved_spu_runcntl_RW;
> + u8 stopped_ok;
> +};
> +
> +#define XMON_NUM_SPUS 16 /* Enough for current hardware */
> +
> +static struct spu_info spu_info[XMON_NUM_SPUS];
> +
> +void xmon_register_spus(struct list_head *list)
> +{
> + struct spu *spu;
> +
> + list_for_each_entry(spu, list, full_list) {
> + if (spu->number >= XMON_NUM_SPUS) {
> + WARN_ON(1);
> + continue;
> + }
> +
> + spu_info[spu->number].spu = spu;
> + spu_info[spu->number].stopped_ok = 0;
> + }
> +}
> +
> +static void stop_spus(void)
> +{
> + struct spu *spu;
> + int i;
> + u64 tmp;
> +
> + for (i = 0; i < XMON_NUM_SPUS; i++) {
> + if (!spu_info[i].spu)
> + continue;
> +
> + if (setjmp(bus_error_jmp) == 0) {
> + catch_memory_errors = 1;
> + sync();
> +
> + spu = spu_info[i].spu;
> +
> + spu_info[i].saved_spu_runcntl_RW =
> + in_be32(&spu->problem->spu_runcntl_RW);
> +
> + tmp = spu_mfc_sr1_get(spu);
> + spu_info[i].saved_mfc_sr1_RW = tmp;
> +
> + tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
> + spu_mfc_sr1_set(spu, tmp);
> +
> + sync();
> + __delay(200);
> +
> + spu_info[i].stopped_ok = 1;
> + printf("Stopped spu %.2d\n", i);
> + } else {
> + catch_memory_errors = 0;
> + printf("*** Error stopping spu %.2d\n", i);
> + }
> + catch_memory_errors = 0;
> + }
> +}
> +
> +static void restart_spus(void)
> +{
> + struct spu *spu;
> + int i;
> +
> + for (i = 0; i < XMON_NUM_SPUS; i++) {
> + if (!spu_info[i].spu)
> + continue;
> +
> + if (!spu_info[i].stopped_ok) {
> + printf("*** Error, spu %d was not successfully stopped"
> + ", not restarting\n", i);
> + continue;
> + }
> +
> + if (setjmp(bus_error_jmp) == 0) {
> + catch_memory_errors = 1;
> + sync();
> +
> + spu = spu_info[i].spu;
> + spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
> + out_be32(&spu->problem->spu_runcntl_RW,
> + spu_info[i].saved_spu_runcntl_RW);
> +
> + sync();
> + __delay(200);
> +
> + printf("Restarted spu %.2d\n", i);
> + } else {
> + catch_memory_errors = 0;
> + printf("*** Error restarting spu %.2d\n", i);
> + }
> + catch_memory_errors = 0;
> + }
> +}
> +
> +static int do_spu_cmd(void)
> +{
> + int cmd;
> +
> + cmd = inchar();
> + switch (cmd) {
> + case 's':
> + stop_spus();
> + break;
> + case 'r':
> + restart_spus();
> + break;
> + default:
> + return -1;
> + }
> +
> + return 0;
> +}
> +#else /* ! CONFIG_PPC_CELL */
> +static int do_spu_cmd(void)
> +{
> + return -1;
> +}
> +#endif
> Index: to-merge/include/asm-powerpc/xmon.h
> ===================================================================
> --- to-merge.orig/include/asm-powerpc/xmon.h
> +++ to-merge/include/asm-powerpc/xmon.h
> @@ -14,8 +14,10 @@
>
> #ifdef CONFIG_XMON
> extern void xmon_setup(void);
> +extern void xmon_register_spus(struct list_head *list);
> #else
> static inline void xmon_setup(void) { };
> +static inline void xmon_register_spus(struct list_head *list) { };
> #endif
>
> #endif /* __KERNEL __ */
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
[-- Attachment #2: Type: text/html, Size: 11975 bytes --]
^ permalink raw reply
* Re: [PATCH 1/2] Add support for stopping spus from xmon
From: Haren Myneni @ 2006-10-13 3:10 UTC (permalink / raw)
To: Michael Ellerman; +Cc: linuxppc-dev, Arnd Bergmann, cbe-oss-dev
In-Reply-To: <20061012120310.6B5A967BD5@ozlabs.org>
Michael Ellerman wrote:
>This patch adds support for stopping, and restarting, spus
>from xmon. We use the spu master runcntl bit to stop execution,
>this is apparently the "right" way to control spu execution and
>spufs will be changed in the future to use this bit.
>
>Testing has shown that to restart execution we have to turn the
>master runcntl bit on and also rewrite the spu runcntl bit, even
>if it is already set to 1 (running).
>
>Stopping spus is triggered by the xmon command 'ss' - "spus stop"
>perhaps. Restarting them is triggered via 'sr'. Restart doesn't
>start execution on spus unless they were running prior to being
>stopped by xmon.
>
>Walking the spu->full_list in xmon after a panic, would mean
>corruption of any spu struct would make all the others
>inaccessible. To avoid this, and also to make the next patch
>easier, we cache pointers to all spus during boot.
>
>We attempt to catch and recover from errors while stopping and
>restarting the spus, but as with most xmon functionality there are
>no guarantees that performing these operations won't crash xmon
>itself.
>
>
>
I think, kdump also need stop_spus() functionality when the dump support
is included on cell. If so, how about both stop_spus() and start_spus()
in platforms/cell/.
Thanks
Haren
^ permalink raw reply
* [PATCH] Check for offline nodes in pci NUMA code
From: Anton Blanchard @ 2006-10-13 2:26 UTC (permalink / raw)
To: linuxppc-dev; +Cc: paulus
During boot we bring up all memory and cpu nodes. Normally a PCI device
will be in one of these online nodes, however in some weird setups it
may not.
We have only seen this in the lab but we may as well check for the case
and fallback to -1 (all nodes).
Signed-off-by: Anton Blanchard <anton@samba.org>
---
Index: build/arch/powerpc/kernel/pci_64.c
===================================================================
--- build.orig/arch/powerpc/kernel/pci_64.c 2006-10-08 01:18:30.000000000 +1000
+++ build/arch/powerpc/kernel/pci_64.c 2006-10-08 01:23:05.000000000 +1000
@@ -199,8 +199,14 @@ struct pci_controller * pcibios_alloc_co
pci_setup_pci_controller(phb);
phb->arch_data = dev;
phb->is_dynamic = mem_init_done;
- if (dev)
- PHB_SET_NODE(phb, of_node_to_nid(dev));
+ if (dev) {
+ int nid = of_node_to_nid(dev);
+
+ if (nid < 0 || !node_online(nid))
+ nid = -1;
+
+ PHB_SET_NODE(phb, nid);
+ }
return phb;
}
^ permalink raw reply
* [PATCH] Better check in show_instructions
From: Anton Blanchard @ 2006-10-13 2:17 UTC (permalink / raw)
To: linuxppc-dev; +Cc: paulus
Instead of just checking that an address is in the right range, use the
provided __kernel_text_address() helper which covers both the kernel and
module text sections.
Signed-off-by: Anton Blanchard <anton@samba.org>
---
Index: build/arch/powerpc/kernel/process.c
===================================================================
--- build.orig/arch/powerpc/kernel/process.c 2006-07-01 20:27:57.000000000 +1000
+++ build/arch/powerpc/kernel/process.c 2006-09-22 20:01:22.000000000 +1000
@@ -341,13 +341,6 @@ struct task_struct *__switch_to(struct t
static int instructions_to_print = 16;
-#ifdef CONFIG_PPC64
-#define BAD_PC(pc) ((REGION_ID(pc) != KERNEL_REGION_ID) && \
- (REGION_ID(pc) != VMALLOC_REGION_ID))
-#else
-#define BAD_PC(pc) ((pc) < KERNELBASE)
-#endif
-
static void show_instructions(struct pt_regs *regs)
{
int i;
@@ -366,7 +359,8 @@ static void show_instructions(struct pt_
* bad address because the pc *should* only be a
* kernel address.
*/
- if (BAD_PC(pc) || __get_user(instr, (unsigned int __user *)pc)) {
+ if (!__kernel_text_address(pc) ||
+ __get_user(instr, (unsigned int __user *)pc)) {
printk("XXXXXXXX ");
} else {
if (regs->nip == pc)
^ permalink raw reply
* [PATCH] POWER6 has 6 PMCs
From: Anton Blanchard @ 2006-10-13 2:13 UTC (permalink / raw)
To: linuxppc-dev; +Cc: paulus
Change ->num_pmcs to match the number of PMCs in POWER6.
Signed-off-by: Anton Blanchard <anton@samba.org>
---
Index: build/arch/powerpc/kernel/cputable.c
===================================================================
--- build.orig/arch/powerpc/kernel/cputable.c 2006-09-22 19:04:56.000000000 +1000
+++ build/arch/powerpc/kernel/cputable.c 2006-09-22 19:24:11.000000000 +1000
@@ -268,7 +268,7 @@ struct cpu_spec cpu_specs[] = {
.cpu_user_features = COMMON_USER_POWER6,
.icache_bsize = 128,
.dcache_bsize = 128,
- .num_pmcs = 8,
+ .num_pmcs = 6,
.oprofile_cpu_type = "ppc64/power6",
.oprofile_type = PPC_OPROFILE_POWER4,
.oprofile_mmcra_sihv = POWER6_MMCRA_SIHV,
^ permalink raw reply
* [PATCH] Never panic when taking altivec exceptions from userspace
From: Anton Blanchard @ 2006-10-13 1:41 UTC (permalink / raw)
To: linuxppc-dev; +Cc: paulus
At the moment we rely on a cpu feature bit or a firmware property to
detect altivec. If we dont have either of these and the cpu does in fact
support altivec we can cause a panic from userspace.
It seems safer to always send a signal if we manage to get an 0xf20
exception from userspace.
Signed-off-by: Anton Blanchard <anton@samba.org>
---
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index d9f10f2..5ed4c2c 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -900,14 +900,13 @@ void kernel_fp_unavailable_exception(str
void altivec_unavailable_exception(struct pt_regs *regs)
{
-#if !defined(CONFIG_ALTIVEC)
if (user_mode(regs)) {
/* A user program has executed an altivec instruction,
but this kernel doesn't support altivec. */
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
return;
}
-#endif
+
printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception "
"%lx at %lx\n", regs->trap, regs->nip);
die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox