On Sat, 8 Sep 2007 02:18:49 +0200, Matteo Croce <technoboy85@xxxxxxxxx> wrote: > Support for memory mapping, clock and the vlynq bus Just some random comments. > diff --git a/arch/mips/ar7/Makefile b/arch/mips/ar7/Makefile > new file mode 100644 > index 0000000..e6ba02c > --- /dev/null > +++ b/arch/mips/ar7/Makefile > @@ -0,0 +1,13 @@ > + > +obj-y := \ > + prom.o \ > + setup.o \ > + memory.o \ > + irq.o \ > + time.o \ > + platform.o \ > + gpio.o \ > + clock.o \ > + vlynq.o > + > +EXTRA_AFLAGS := $(CFLAGS) This EXTRA_AFLAGS line is redundant. You can drop it safely. > diff --git a/arch/mips/ar7/irq.c b/arch/mips/ar7/irq.c > new file mode 100644 > index 0000000..f131301 > --- /dev/null > +++ b/arch/mips/ar7/irq.c ... > +#include <linux/init.h> > +#include <linux/interrupt.h> > +#include <linux/ioport.h> > +#include <linux/irq.h> No need to include <linux/irq.h> > +#define REG(addr) (*(volatile u32 *)(KSEG1ADDR(AR7_REGS_IRQ) + addr)) You can remove this "volatile" rewriting something like: #define REG_RD(addr) \ readl((void __iomem *)(KSEG1ADDR(AR7_REGS_IRQ) + (addr))) #define REG_WR(val, addr) \ writel(val, (void __iomem *)(KSEG1ADDR(AR7_REGS_IRQ) + (addr))) > +static struct irq_chip ar7_irq_type = { > + .typename = "AR7", The typename is obsolete and not needed if you have name field. > +static void ar7_unmask_irq(unsigned int irq) > +{ > + unsigned long flags; > + local_irq_save(flags); > + /* enable the interrupt channel bit */ > + REG(ESR_OFFSET(irq)) = 1 << ((irq - ar7_irq_base) % 32); > + local_irq_restore(flags); > +} > + > +static void ar7_mask_irq(unsigned int irq) > +{ > + unsigned long flags; > + local_irq_save(flags); > + /* disable the interrupt channel bit */ > + REG(ECR_OFFSET(irq)) = 1 << ((irq - ar7_irq_base) % 32); > + local_irq_restore(flags); > +} > + > +static void ar7_unmask_secondary_irq(unsigned int irq) > +{ > + unsigned long flags; > + local_irq_save(flags); > + /* enable the interrupt channel bit */ > + REG(SEC_ESR_OFFSET) = 1 << (irq - ar7_irq_base - 40); > + local_irq_restore(flags); > +} > + > +static void ar7_mask_secondary_irq(unsigned int irq) > +{ > + unsigned long flags; > + local_irq_save(flags); > + /* disable the interrupt channel bit */ > + REG(SEC_ECR_OFFSET) = 1 << (irq - ar7_irq_base - 40); > + local_irq_restore(flags); > +} The mask, unmask routines are always called irq disabled. So you can drop these local_irqsave/restore pairs. > + for (i = 0; i < 40; i++) { > + REG(CHNL_OFFSET(i)) = i; > + /* Primary IRQ's */ > + irq_desc[i + base].status = IRQ_DISABLED; > + irq_desc[i + base].action = NULL; > + irq_desc[i + base].depth = 1; > + irq_desc[i + base].chip = &ar7_irq_type; > + /* Secondary IRQ's */ > + if (i < 32) { > + irq_desc[i + base + 40].status = IRQ_DISABLED; > + irq_desc[i + base + 40].action = NULL; > + irq_desc[i + base + 40].depth = 1; > + irq_desc[i + base + 40].chip = &ar7_secondary_irq_type; > + } > + } Use set_irq_chip() or its variants instead of touching irq_desc[] directly. It seems this platform can set GENERIC_HARDIRQS_NO__DO_IRQ in Kconfig, using handle_level_irq irq handler. > +asmlinkage void plat_irq_dispatch(void) > +{ > + unsigned int pending = read_c0_status() & read_c0_cause(); > + if (pending & STATUSF_IP7) /* cpu timer */ > + do_IRQ(7); > + else if (pending & STATUSF_IP2) /* int0 hardware line */ > + do_IRQ(2); > + else > + spurious_interrupt(); > +} It would be safer to mask 'pending' with ST0_IM. > diff --git a/arch/mips/ar7/prom.c b/arch/mips/ar7/prom.c > new file mode 100644 > index 0000000..0437f65 ... > +/* from adm5120/prom.c */ > +void prom_printf(char *fmt, ...) > +{ > + va_list args; > + int l; > + char *p, *buf_end; > + char buf[1024]; > + > + va_start(args, fmt); > + l = vsprintf(buf, fmt, args); /* hopefully i < sizeof(buf) */ > + va_end(args); > + > + buf_end = buf + l; > + > + for (p = buf; p < buf_end; p++) { > + /* Crude cr/nl handling is better than none */ > + if (*p == '\n') > + prom_putchar('\r'); > + prom_putchar(*p); > + } > +} prom_printf() is not used in recent linux-mips. > diff --git a/arch/mips/ar7/time.c b/arch/mips/ar7/time.c > new file mode 100644 > index 0000000..fea75c1 > --- /dev/null > +++ b/arch/mips/ar7/time.c ... > +#include <linux/types.h> > +#include <linux/init.h> > +#include <linux/kernel_stat.h> > +#include <linux/sched.h> > +#include <linux/spinlock.h> > +#include <linux/interrupt.h> > +#include <linux/time.h> > +#include <linux/timex.h> > +#include <linux/mc146818rtc.h> > +#include <linux/ptrace.h> > +#include <linux/hardirq.h> > +#include <linux/irq.h> > +#include <linux/cpu.h> > +#include <asm/time.h> You do not have to include so many headers. > diff --git a/arch/mips/ar7/vlynq.c b/arch/mips/ar7/vlynq.c > new file mode 100644 > index 0000000..dd4796e > --- /dev/null > +++ b/arch/mips/ar7/vlynq.c ... > +struct vlynq_regs { > + volatile u32 revision; > + volatile u32 control; > + volatile u32 status; > + volatile u32 int_prio; > + volatile u32 int_status; > + volatile u32 int_pending; > + volatile u32 int_ptr; > + volatile u32 tx_offset; > + volatile struct vlynq_mapping rx_mapping[4]; > + volatile u32 chip; > + volatile u32 autonego; > + volatile u32 unused[6]; > + volatile u32 int_device[8]; > +} __attribute__ ((packed)); You can drop these volatile, using readl/writel for accessing these members. > +static void vlynq_irq_unmask(unsigned int irq) > +{ > + volatile u32 val; > + struct vlynq_device *dev = irq_desc[irq].chip_data; This "volatile" should be removed. Use get_irq_chip_data(irq) instead of using irq_desc[] directly. > +static void vlynq_irq_mask(unsigned int irq) > +{ > + volatile u32 val; This "volatile" should be removed. > +static int vlynq_irq_type(unsigned int irq, unsigned int flow_type) > +{ > + volatile u32 val; This "volatile" should be removed. > +static struct irq_chip vlynq_irq_chip = { > + .typename = "VLYNQ", The typename is obsolete and not needed if you have name field. > + for (i = 0; i < PER_DEVICE_IRQS; i++) { > + if ((i == dev->local_irq) || (i == dev->remote_irq)) > + continue; > + irq_desc[dev->irq_start + i].status = IRQ_DISABLED; > + irq_desc[dev->irq_start + i].action = 0; > + irq_desc[dev->irq_start + i].depth = 1; > + irq_desc[dev->irq_start + i].chip = &vlynq_irq_chip; > + irq_desc[dev->irq_start + i].chip_data = dev; > + dev->remote->int_device[i >> 2] = 0; > + } Use set_irq_chip() or its variants. > + dev = kmalloc(sizeof(struct vlynq_device), GFP_KERNEL); > + if (!dev) { > + printk(KERN_ERR "vlynq: failed to allocate device structure\n"); > + return -ENOMEM; > + } > + > + memset(dev, 0, sizeof(struct vlynq_device)); Use kzalloc(). > +int __init vlynq_init(void) This can be static. > diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c > index 6379003..75a46ba 100644 > --- a/arch/mips/kernel/traps.c > +++ b/arch/mips/kernel/traps.c > @@ -1075,9 +1075,23 @@ void *set_except_vector(int n, void *addr) > > exception_handlers[n] = handler; > if (n == 0 && cpu_has_divec) { > +#ifdef CONFIG_AR7 > + /* lui k0, 0x0000 */ > + *(volatile u32 *)(CAC_BASE+0x200) = > + 0x3c1a0000 | (handler >> 16); > + /* ori k0, 0x0000 */ > + *(volatile u32 *)(CAC_BASE+0x204) = > + 0x375a0000 | (handler & 0xffff); > + /* jr k0 */ > + *(volatile u32 *)(CAC_BASE+0x208) = 0x03400008; > + /* nop */ > + *(volatile u32 *)(CAC_BASE+0x20C) = 0x00000000; > + flush_icache_range(CAC_BASE+0x200, CAC_BASE+0x210); > +#else > *(volatile u32 *)(ebase + 0x200) = 0x08000000 | > (0x03ffffff & (handler >> 2)); > flush_icache_range(ebase + 0x200, ebase + 0x204); > +#endif > } > return (void *)old_handler; > } Runtime checking, something like this would be better than ifdef: if ((handler ^ (ebase + 4)) & 0xfc000000) /* use jr */ ... } else { /* use j */ ... } --- Atsushi Nemoto