From 7e9204265b4ec6680fad9abc7a78b94087983916 Mon Sep 17 00:00:00 2001 From: Mikael Starvik Date: Wed, 27 Jul 2005 11:44:34 -0700 Subject: [PATCH] [PATCH] CRIS update: drivers Updates to device drivers. * Use I/O and DMA allocators. * Use wait_event_interruptible instead of interrutiple_sleep_on. * Added spinlocks SMP. * Changed restore_flags to local_irq_restore etc. * Updated IDE driver include to fit 2.6.12. Signed-off-by: Mikael Starvik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/cris/arch-v10/drivers/axisflashmap.c | 5 +- arch/cris/arch-v10/drivers/ds1302.c | 71 +++++--- arch/cris/arch-v10/drivers/eeprom.c | 29 ++-- arch/cris/arch-v10/drivers/gpio.c | 201 ++++++++++++---------- arch/cris/arch-v10/drivers/i2c.c | 62 ++++++- arch/cris/arch-v10/drivers/pcf8563.c | 20 ++- arch/cris/arch-v10/kernel/Makefile | 5 +- arch/cris/arch-v10/kernel/fasttimer.c | 55 +++--- include/asm-cris/arch-v10/ide.h | 99 +++++++++++ include/asm-cris/ide.h | 1 + 10 files changed, 376 insertions(+), 172 deletions(-) create mode 100644 include/asm-cris/arch-v10/ide.h create mode 100644 include/asm-cris/ide.h diff --git a/arch/cris/arch-v10/drivers/axisflashmap.c b/arch/cris/arch-v10/drivers/axisflashmap.c index fb7d4855ea62..11ab3836aac6 100644 --- a/arch/cris/arch-v10/drivers/axisflashmap.c +++ b/arch/cris/arch-v10/drivers/axisflashmap.c @@ -11,6 +11,9 @@ * partition split defined below. * * $Log: axisflashmap.c,v $ + * Revision 1.11 2004/11/15 10:27:14 starvik + * Corrected typo (Thanks to Milton Miller ). + * * Revision 1.10 2004/08/16 12:37:22 starvik * Merge of Linux 2.6.8 * @@ -161,7 +164,7 @@ #elif CONFIG_ETRAX_FLASH_BUSWIDTH==2 #define flash_data __u16 #elif CONFIG_ETRAX_FLASH_BUSWIDTH==4 -#define flash_data __u16 +#define flash_data __u32 #endif /* From head.S */ diff --git a/arch/cris/arch-v10/drivers/ds1302.c b/arch/cris/arch-v10/drivers/ds1302.c index fba530fcfaeb..10795f67f687 100644 --- a/arch/cris/arch-v10/drivers/ds1302.c +++ b/arch/cris/arch-v10/drivers/ds1302.c @@ -7,6 +7,15 @@ *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init *! *! $Log: ds1302.c,v $ +*! Revision 1.18 2005/01/24 09:11:26 mikaelam +*! Minor changes to get DS1302 RTC chip driver to work +*! +*! Revision 1.17 2005/01/05 06:11:22 starvik +*! No need to do local_irq_disable after local_irq_save. +*! +*! Revision 1.16 2004/12/13 12:21:52 starvik +*! Added I/O and DMA allocators from Linux 2.4 +*! *! Revision 1.14 2004/08/24 06:48:43 starvik *! Whitespace cleanup *! @@ -124,9 +133,9 @@ *! *! --------------------------------------------------------------------------- *! -*! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN +*! (C) Copyright 1999, 2000, 2001, 2002, 2003, 2004 Axis Communications AB, LUND, SWEDEN *! -*! $Id: ds1302.c,v 1.14 2004/08/24 06:48:43 starvik Exp $ +*! $Id: ds1302.c,v 1.18 2005/01/24 09:11:26 mikaelam Exp $ *! *!***************************************************************************/ @@ -145,6 +154,7 @@ #include #include #include +#include #define RTC_MAJOR_NR 121 /* local major, change later */ @@ -320,7 +330,6 @@ get_rtc_time(struct rtc_time *rtc_tm) unsigned long flags; local_irq_save(flags); - local_irq_disable(); rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); @@ -358,7 +367,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - unsigned long flags; + unsigned long flags; switch(cmd) { case RTC_RD_TIME: /* read the time/date from RTC */ @@ -382,7 +391,7 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, return -EPERM; if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) - return -EFAULT; + return -EFAULT; yrs = rtc_tm.tm_year + 1900; mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ @@ -419,7 +428,6 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, BIN_TO_BCD(yrs); local_irq_save(flags); - local_irq_disable(); CMOS_WRITE(yrs, RTC_YEAR); CMOS_WRITE(mon, RTC_MONTH); CMOS_WRITE(day, RTC_DAY_OF_MONTH); @@ -438,7 +446,7 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */ { - int tcs_val; + int tcs_val; if (!capable(CAP_SYS_TIME)) return -EPERM; @@ -492,8 +500,8 @@ print_rtc_status(void) /* The various file operations we support. */ static struct file_operations rtc_fops = { - .owner = THIS_MODULE, - .ioctl = rtc_ioctl, + .owner = THIS_MODULE, + .ioctl = rtc_ioctl, }; /* Probe for the chip by writing something to its RAM and try reading it back. */ @@ -532,7 +540,7 @@ ds1302_probe(void) "PB", #endif CONFIG_ETRAX_DS1302_RSTBIT); - print_rtc_status(); + print_rtc_status(); retval = 1; } else { stop(); @@ -548,7 +556,9 @@ ds1302_probe(void) int __init ds1302_init(void) { +#ifdef CONFIG_ETRAX_I2C i2c_init(); +#endif if (!ds1302_probe()) { #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT @@ -558,25 +568,42 @@ ds1302_init(void) * * Make sure that R_GEN_CONFIG is setup correct. */ - genconfig_shadow = ((genconfig_shadow & - ~IO_MASK(R_GEN_CONFIG, ata)) | - (IO_STATE(R_GEN_CONFIG, ata, select))); - *R_GEN_CONFIG = genconfig_shadow; + /* Allocating the ATA interface will grab almost all + * pins in I/O groups a, b, c and d. A consequence of + * allocating the ATA interface is that the fixed + * interfaces shared RAM, parallel port 0, parallel + * port 1, parallel port W, SCSI-8 port 0, SCSI-8 port + * 1, SCSI-W, serial port 2, serial port 3, + * synchronous serial port 3 and USB port 2 and almost + * all GPIO pins on port g cannot be used. + */ + if (cris_request_io_interface(if_ata, "ds1302/ATA")) { + printk(KERN_WARNING "ds1302: Failed to get IO interface\n"); + return -1; + } + #elif CONFIG_ETRAX_DS1302_RSTBIT == 0 - - /* Set the direction of this bit to out. */ - genconfig_shadow = ((genconfig_shadow & - ~IO_MASK(R_GEN_CONFIG, g0dir)) | - (IO_STATE(R_GEN_CONFIG, g0dir, out))); - *R_GEN_CONFIG = genconfig_shadow; + if (cris_io_interface_allocate_pins(if_gpio_grp_a, + 'g', + CONFIG_ETRAX_DS1302_RSTBIT, + CONFIG_ETRAX_DS1302_RSTBIT)) { + printk(KERN_WARNING "ds1302: Failed to get IO interface\n"); + return -1; + } + + /* Set the direction of this bit to out. */ + genconfig_shadow = ((genconfig_shadow & + ~IO_MASK(R_GEN_CONFIG, g0dir)) | + (IO_STATE(R_GEN_CONFIG, g0dir, out))); + *R_GEN_CONFIG = genconfig_shadow; #endif if (!ds1302_probe()) { printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name); - return -1; + return -1; } #else printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name); - return -1; + return -1; #endif } /* Initialise trickle charger */ diff --git a/arch/cris/arch-v10/drivers/eeprom.c b/arch/cris/arch-v10/drivers/eeprom.c index 316ca15d6802..512f16dec060 100644 --- a/arch/cris/arch-v10/drivers/eeprom.c +++ b/arch/cris/arch-v10/drivers/eeprom.c @@ -20,6 +20,12 @@ *! in the spin-lock. *! *! $Log: eeprom.c,v $ +*! Revision 1.12 2005/06/19 17:06:46 starvik +*! Merge of Linux 2.6.12. +*! +*! Revision 1.11 2005/01/26 07:14:46 starvik +*! Applied diff from kernel janitors (Nish Aravamudan). +*! *! Revision 1.10 2003/09/11 07:29:48 starvik *! Merge of Linux 2.6.0-test5 *! @@ -94,6 +100,7 @@ #include #include #include +#include #include #include "i2c.h" @@ -526,15 +533,10 @@ static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t return -EFAULT; } - while(eeprom.busy) - { - interruptible_sleep_on(&eeprom.wait_q); + wait_event_interruptible(eeprom.wait_q, !eeprom.busy); + if (signal_pending(current)) + return -EINTR; - /* bail out if we get interrupted */ - if (signal_pending(current)) - return -EINTR; - - } eeprom.busy++; page = (unsigned char) (p >> 8); @@ -604,13 +606,10 @@ static ssize_t eeprom_write(struct file * file, const char * buf, size_t count, return -EFAULT; } - while(eeprom.busy) - { - interruptible_sleep_on(&eeprom.wait_q); - /* bail out if we get interrupted */ - if (signal_pending(current)) - return -EINTR; - } + wait_event_interruptible(eeprom.wait_q, !eeprom.busy); + /* bail out if we get interrupted */ + if (signal_pending(current)) + return -EINTR; eeprom.busy++; for(i = 0; (i < EEPROM_RETRIES) && (restart > 0); i++) { diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c index c095de82a0da..09963fe299a7 100644 --- a/arch/cris/arch-v10/drivers/gpio.c +++ b/arch/cris/arch-v10/drivers/gpio.c @@ -1,4 +1,4 @@ -/* $Id: gpio.c,v 1.12 2004/08/24 07:19:59 starvik Exp $ +/* $Id: gpio.c,v 1.17 2005/06/19 17:06:46 starvik Exp $ * * Etrax general port I/O device * @@ -9,6 +9,18 @@ * Johan Adolfsson (read/set directions, write, port G) * * $Log: gpio.c,v $ + * Revision 1.17 2005/06/19 17:06:46 starvik + * Merge of Linux 2.6.12. + * + * Revision 1.16 2005/03/07 13:02:29 starvik + * Protect driver global states with spinlock + * + * Revision 1.15 2005/01/05 06:08:55 starvik + * No need to do local_irq_disable after local_irq_save. + * + * Revision 1.14 2004/12/13 12:21:52 starvik + * Added I/O and DMA allocators from Linux 2.4 + * * Revision 1.12 2004/08/24 07:19:59 starvik * Whitespace cleanup * @@ -142,6 +154,7 @@ #include #include #include +#include #define GPIO_MAJOR 120 /* experimental MAJOR number */ @@ -194,6 +207,8 @@ static struct gpio_private *alarmlist = 0; static int gpio_some_alarms = 0; /* Set if someone uses alarm */ static unsigned long gpio_pa_irq_enabled_mask = 0; +static DEFINE_SPINLOCK(gpio_lock); /* Protect directions etc */ + /* Port A and B use 8 bit access, but Port G is 32 bit */ #define NUM_PORTS (GPIO_MINOR_B+1) @@ -241,6 +256,9 @@ static volatile unsigned char *dir_shadow[NUM_PORTS] = { &port_pb_dir_shadow }; +/* All bits in port g that can change dir. */ +static const unsigned long int changeable_dir_g_mask = 0x01FFFF01; + /* Port G is 32 bit, handle it special, some bits are both inputs and outputs at the same time, only some of the bits can change direction and some of them in groups of 8 bit. */ @@ -260,6 +278,7 @@ gpio_poll(struct file *file, unsigned int mask = 0; struct gpio_private *priv = (struct gpio_private *)file->private_data; unsigned long data; + spin_lock(&gpio_lock); poll_wait(file, &priv->alarm_wq, wait); if (priv->minor == GPIO_MINOR_A) { unsigned long flags; @@ -270,10 +289,10 @@ gpio_poll(struct file *file, */ tmp = ~data & priv->highalarm & 0xFF; tmp = (tmp << R_IRQ_MASK1_SET__pa0__BITNR); - save_flags(flags); cli(); + local_irq_save(flags); gpio_pa_irq_enabled_mask |= tmp; *R_IRQ_MASK1_SET = tmp; - restore_flags(flags); + local_irq_restore(flags); } else if (priv->minor == GPIO_MINOR_B) data = *R_PORT_PB_DATA; @@ -286,8 +305,11 @@ gpio_poll(struct file *file, (~data & priv->lowalarm)) { mask = POLLIN|POLLRDNORM; } + + spin_unlock(&gpio_lock); DP(printk("gpio_poll ready: mask 0x%08X\n", mask)); + return mask; } @@ -296,6 +318,7 @@ int etrax_gpio_wake_up_check(void) struct gpio_private *priv = alarmlist; unsigned long data = 0; int ret = 0; + spin_lock(&gpio_lock); while (priv) { if (USE_PORTS(priv)) { data = *priv->port; @@ -310,6 +333,7 @@ int etrax_gpio_wake_up_check(void) } priv = priv->next; } + spin_unlock(&gpio_lock); return ret; } @@ -327,6 +351,7 @@ static irqreturn_t gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned long tmp; + spin_lock(&gpio_lock); /* Find what PA interrupts are active */ tmp = (*R_IRQ_READ1); @@ -337,6 +362,8 @@ gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs) *R_IRQ_MASK1_CLR = tmp; gpio_pa_irq_enabled_mask &= ~tmp; + spin_unlock(&gpio_lock); + if (gpio_some_alarms) { return IRQ_RETVAL(etrax_gpio_wake_up_check()); } @@ -350,6 +377,9 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, struct gpio_private *priv = (struct gpio_private *)file->private_data; unsigned char data, clk_mask, data_mask, write_msb; unsigned long flags; + + spin_lock(&gpio_lock); + ssize_t retval = count; if (priv->minor !=GPIO_MINOR_A && priv->minor != GPIO_MINOR_B) { return -EFAULT; @@ -372,7 +402,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, data = *buf++; if (priv->write_msb) { for (i = 7; i >= 0;i--) { - local_irq_save(flags); local_irq_disable(); + local_irq_save(flags); *priv->port = *priv->shadow &= ~clk_mask; if (data & 1<port = *priv->shadow |= data_mask; @@ -384,7 +414,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, } } else { for (i = 0; i <= 7;i++) { - local_irq_save(flags); local_irq_disable(); + local_irq_save(flags); *priv->port = *priv->shadow &= ~clk_mask; if (data & 1<port = *priv->shadow |= data_mask; @@ -396,6 +426,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, } } } + spin_unlock(&gpio_lock); return retval; } @@ -452,9 +483,14 @@ gpio_open(struct inode *inode, struct file *filp) static int gpio_release(struct inode *inode, struct file *filp) { - struct gpio_private *p = alarmlist; - struct gpio_private *todel = (struct gpio_private *)filp->private_data; - + struct gpio_private *p; + struct gpio_private *todel; + + spin_lock(&gpio_lock); + + p = alarmlist; + todel = (struct gpio_private *)filp->private_data; + /* unlink from alarmlist and free the private structure */ if (p == todel) { @@ -476,7 +512,7 @@ gpio_release(struct inode *inode, struct file *filp) p = p->next; } gpio_some_alarms = 0; - + spin_unlock(&gpio_lock); return 0; } @@ -491,14 +527,14 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg) */ unsigned long flags; if (USE_PORTS(priv)) { - local_irq_save(flags); local_irq_disable(); + local_irq_save(flags); *priv->dir = *priv->dir_shadow &= ~((unsigned char)arg & priv->changeable_dir); local_irq_restore(flags); return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */ } else if (priv->minor == GPIO_MINOR_G) { /* We must fiddle with R_GEN_CONFIG to change dir */ - save_flags(flags); cli(); + local_irq_save(flags); if (((arg & dir_g_in_bits) != arg) && (arg & changeable_dir_g)) { arg &= changeable_dir_g; @@ -533,7 +569,7 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg) /* Must be a >120 ns delay before writing this again */ } - restore_flags(flags); + local_irq_restore(flags); return dir_g_in_bits; } return 0; @@ -543,14 +579,14 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg) { unsigned long flags; if (USE_PORTS(priv)) { - local_irq_save(flags); local_irq_disable(); + local_irq_save(flags); *priv->dir = *priv->dir_shadow |= ((unsigned char)arg & priv->changeable_dir); local_irq_restore(flags); return *priv->dir_shadow; } else if (priv->minor == GPIO_MINOR_G) { /* We must fiddle with R_GEN_CONFIG to change dir */ - save_flags(flags); cli(); + local_irq_save(flags); if (((arg & dir_g_out_bits) != arg) && (arg & changeable_dir_g)) { /* Set bits in genconfig to set to output */ @@ -583,7 +619,7 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg) *R_GEN_CONFIG = genconfig_shadow; /* Must be a >120 ns delay before writing this again */ } - restore_flags(flags); + local_irq_restore(flags); return dir_g_out_bits & 0x7FFFFFFF; } return 0; @@ -598,22 +634,26 @@ gpio_ioctl(struct inode *inode, struct file *file, { unsigned long flags; unsigned long val; + int ret = 0; + struct gpio_private *priv = (struct gpio_private *)file->private_data; if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) { return -EINVAL; } + spin_lock(&gpio_lock); + switch (_IOC_NR(cmd)) { case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ // read the port if (USE_PORTS(priv)) { - return *priv->port; + ret = *priv->port; } else if (priv->minor == GPIO_MINOR_G) { - return (*R_PORT_G_DATA) & 0x7FFFFFFF; + ret = (*R_PORT_G_DATA) & 0x7FFFFFFF; } break; case IO_SETBITS: - local_irq_save(flags); local_irq_disable(); + local_irq_save(flags); // set changeable bits with a 1 in arg if (USE_PORTS(priv)) { *priv->port = *priv->shadow |= @@ -624,7 +664,7 @@ gpio_ioctl(struct inode *inode, struct file *file, local_irq_restore(flags); break; case IO_CLRBITS: - local_irq_save(flags); local_irq_disable(); + local_irq_save(flags); // clear changeable bits with a 1 in arg if (USE_PORTS(priv)) { *priv->port = *priv->shadow &= @@ -666,33 +706,34 @@ gpio_ioctl(struct inode *inode, struct file *file, case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ /* Read direction 0=input 1=output */ if (USE_PORTS(priv)) { - return *priv->dir_shadow; + ret = *priv->dir_shadow; } else if (priv->minor == GPIO_MINOR_G) { /* Note: Some bits are both in and out, * Those that are dual is set here as well. */ - return (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF; + ret = (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF; } + break; case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */ /* Set direction 0=unchanged 1=input, * return mask with 1=input */ - return setget_input(priv, arg) & 0x7FFFFFFF; + ret = setget_input(priv, arg) & 0x7FFFFFFF; break; case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */ /* Set direction 0=unchanged 1=output, * return mask with 1=output */ - return setget_output(priv, arg) & 0x7FFFFFFF; - + ret = setget_output(priv, arg) & 0x7FFFFFFF; + break; case IO_SHUTDOWN: SOFT_SHUTDOWN(); break; case IO_GET_PWR_BT: #if defined (CONFIG_ETRAX_SOFT_SHUTDOWN) - return (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT)); + ret = (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT)); #else - return 0; + ret = 0; #endif break; case IO_CFG_WRITE_MODE: @@ -709,7 +750,7 @@ gpio_ioctl(struct inode *inode, struct file *file, { priv->clk_mask = 0; priv->data_mask = 0; - return -EPERM; + ret = -EPERM; } break; case IO_READ_INBITS: @@ -720,8 +761,7 @@ gpio_ioctl(struct inode *inode, struct file *file, val = *R_PORT_G_DATA; } if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) - return -EFAULT; - return 0; + ret = -EFAULT; break; case IO_READ_OUTBITS: /* *arg is result of reading the output shadow */ @@ -731,36 +771,43 @@ gpio_ioctl(struct inode *inode, struct file *file, val = port_g_data_shadow; } if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) - return -EFAULT; + ret = -EFAULT; break; case IO_SETGET_INPUT: /* bits set in *arg is set to input, * *arg updated with current input pins. */ if (copy_from_user(&val, (unsigned long*)arg, sizeof(val))) - return -EFAULT; + { + ret = -EFAULT; + break; + } val = setget_input(priv, val); if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) - return -EFAULT; + ret = -EFAULT; break; case IO_SETGET_OUTPUT: /* bits set in *arg is set to output, * *arg updated with current output pins. */ if (copy_from_user(&val, (unsigned long*)arg, sizeof(val))) - return -EFAULT; + { + ret = -EFAULT; + break; + } val = setget_output(priv, val); if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) - return -EFAULT; + ret = -EFAULT; break; default: if (priv->minor == GPIO_MINOR_LEDS) - return gpio_leds_ioctl(cmd, arg); + ret = gpio_leds_ioctl(cmd, arg); else - return -EINVAL; + ret = -EINVAL; } /* switch */ - - return 0; + + spin_unlock(&gpio_lock); + return ret; } static int @@ -802,60 +849,20 @@ struct file_operations gpio_fops = { }; -static void __init gpio_init_port_g(void) +void ioif_watcher(const unsigned int gpio_in_available, + const unsigned int gpio_out_available, + const unsigned char pa_available, + const unsigned char pb_available) { -#define GROUPA (0x0000FF3F) -#define GROUPB (1<<6 | 1<<7) -#define GROUPC (1<<30 | 1<<31) -#define GROUPD (0x3FFF0000) -#define GROUPD_LOW (0x00FF0000) - unsigned long used_in_bits = 0; - unsigned long used_out_bits = 0; - if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0, select)){ - used_in_bits |= GROUPA | GROUPB | 0 | 0; - used_out_bits |= GROUPA | GROUPB | 0 | 0; - } - if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ata, select)) { - used_in_bits |= GROUPA | GROUPB | GROUPC | (GROUPD & ~(1<<25|1<<26)); - used_out_bits |= GROUPA | GROUPB | GROUPC | GROUPD; - } + unsigned long int flags; + D(printk("gpio.c: ioif_watcher called\n")); + D(printk("gpio.c: G in: 0x%08x G out: 0x%08x PA: 0x%02x PB: 0x%02x\n", + gpio_in_available, gpio_out_available, pa_available, pb_available)); - if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par0, select)) { - used_in_bits |= (GROUPA & ~(1<<0)) | 0 | 0 | 0; - used_out_bits |= (GROUPA & ~(1<<0)) | 0 | 0 | 0; - } - if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser2, select)) { - used_in_bits |= 0 | GROUPB | 0 | 0; - used_out_bits |= 0 | GROUPB | 0 | 0; - } - /* mio same as shared RAM ? */ - if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio, select)) { - used_in_bits |= (GROUPA & ~(1<<0)) | 0 |0 |GROUPD_LOW; - used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 |0 |GROUPD_LOW; - } - if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi1, select)) { - used_in_bits |= 0 | 0 | GROUPC | GROUPD; - used_out_bits |= 0 | 0 | GROUPC | GROUPD; - } - if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0w, select)) { - used_in_bits |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24); - used_out_bits |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24 | 1<<25|1<<26); - } + spin_lock_irqsave(&gpio_lock, flags); - if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par1, select)) { - used_in_bits |= 0 | 0 | 0 | (GROUPD & ~(1<<24)); - used_out_bits |= 0 | 0 | 0 | (GROUPD & ~(1<<24)); - } - if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser3, select)) { - used_in_bits |= 0 | 0 | GROUPC | 0; - used_out_bits |= 0 | 0 | GROUPC | 0; - } - /* mio same as shared RAM-W? */ - if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio_w, select)) { - used_in_bits |= (GROUPA & ~(1<<0)) | 0 | 0 |GROUPD_LOW; - used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 | 0 |GROUPD_LOW; - } - /* TODO: USB p2, parw, sync ser3? */ + dir_g_in_bits = gpio_in_available; + dir_g_out_bits = gpio_out_available; /* Initialise the dir_g_shadow etc. depending on genconfig */ /* 0=input 1=output */ @@ -868,10 +875,7 @@ static void __init gpio_init_port_g(void) if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g24dir, out)) dir_g_shadow |= (1 << 24); - dir_g_in_bits = ~used_in_bits; - dir_g_out_bits = ~used_out_bits; - - changeable_dir_g = 0x01FFFF01; /* all that can change dir */ + changeable_dir_g = changeable_dir_g_mask; changeable_dir_g &= dir_g_out_bits; changeable_dir_g &= dir_g_in_bits; /* Correct the bits that can change direction */ @@ -880,6 +884,7 @@ static void __init gpio_init_port_g(void) dir_g_in_bits &= ~changeable_dir_g; dir_g_in_bits |= (~dir_g_shadow & changeable_dir_g); + spin_unlock_irqrestore(&gpio_lock, flags); printk(KERN_INFO "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: %08lX\n", dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA); @@ -896,6 +901,7 @@ gpio_init(void) #if defined (CONFIG_ETRAX_CSP0_LEDS) int i; #endif + printk("gpio init\n"); /* do the formalities */ @@ -919,8 +925,13 @@ gpio_init(void) #endif #endif - gpio_init_port_g(); - printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis Communications AB\n"); + /* The I/O interface allocation watcher will be called when + * registering it. */ + if (cris_io_interface_register_watcher(ioif_watcher)){ + printk(KERN_WARNING "gpio_init: Failed to install IO if allocator watcher\n"); + } + + printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002, 2003, 2004 Axis Communications AB\n"); /* We call etrax_gpio_wake_up_check() from timer interrupt and * from cpu_idle() in kernel/process.c * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms diff --git a/arch/cris/arch-v10/drivers/i2c.c b/arch/cris/arch-v10/drivers/i2c.c index 8bbe233ba7b1..b38267d60d30 100644 --- a/arch/cris/arch-v10/drivers/i2c.c +++ b/arch/cris/arch-v10/drivers/i2c.c @@ -12,6 +12,15 @@ *! don't use PB_I2C if DS1302 uses same bits, *! use PB. *! $Log: i2c.c,v $ +*! Revision 1.13 2005/03/07 13:13:07 starvik +*! Added spinlocks to protect states etc +*! +*! Revision 1.12 2005/01/05 06:11:22 starvik +*! No need to do local_irq_disable after local_irq_save. +*! +*! Revision 1.11 2004/12/13 12:21:52 starvik +*! Added I/O and DMA allocators from Linux 2.4 +*! *! Revision 1.9 2004/08/24 06:49:14 starvik *! Whitespace cleanup *! @@ -75,7 +84,7 @@ *! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN *! *!***************************************************************************/ -/* $Id: i2c.c,v 1.9 2004/08/24 06:49:14 starvik Exp $ */ +/* $Id: i2c.c,v 1.13 2005/03/07 13:13:07 starvik Exp $ */ /****************** INCLUDE FILES SECTION ***********************************/ @@ -95,6 +104,7 @@ #include #include #include +#include #include "i2c.h" @@ -184,6 +194,7 @@ static const char i2c_name[] = "i2c"; #define i2c_delay(usecs) udelay(usecs) +static DEFINE_SPINLOCK(i2c_lock); /* Protect directions etc */ /****************** FUNCTION DEFINITION SECTION *************************/ @@ -488,13 +499,14 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg, int error, cntr = 3; unsigned long flags; + spin_lock(&i2c_lock); + do { error = 0; /* * we don't like to be interrupted */ local_irq_save(flags); - local_irq_disable(); i2c_start(); /* @@ -538,6 +550,8 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg, i2c_delay(CLOCK_LOW_TIME); + spin_unlock(&i2c_lock); + return -error; } @@ -555,13 +569,14 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) int error, cntr = 3; unsigned long flags; + spin_lock(&i2c_lock); + do { error = 0; /* * we don't like to be interrupted */ local_irq_save(flags); - local_irq_disable(); /* * generate start condition */ @@ -620,6 +635,8 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) } while(error && cntr--); + spin_unlock(&i2c_lock); + return b; } @@ -686,15 +703,26 @@ static struct file_operations i2c_fops = { int __init i2c_init(void) { + static int res = 0; + static int first = 1; + + if (!first) { + return res; + } + /* Setup and enable the Port B I2C interface */ #ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C + if ((res = cris_request_io_interface(if_i2c, "I2C"))) { + printk(KERN_CRIT "i2c_init: Failed to get IO interface\n"); + return res; + } + *R_PORT_PB_I2C = port_pb_i2c_shadow |= IO_STATE(R_PORT_PB_I2C, i2c_en, on) | IO_FIELD(R_PORT_PB_I2C, i2c_d, 1) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, 1) | IO_STATE(R_PORT_PB_I2C, i2c_oe_, enable); -#endif port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir0); port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir1); @@ -702,8 +730,26 @@ i2c_init(void) *R_PORT_PB_DIR = (port_pb_dir_shadow |= IO_STATE(R_PORT_PB_DIR, dir0, input) | IO_STATE(R_PORT_PB_DIR, dir1, output)); +#else + if ((res = cris_io_interface_allocate_pins(if_i2c, + 'b', + CONFIG_ETRAX_I2C_DATA_PORT, + CONFIG_ETRAX_I2C_DATA_PORT))) { + printk(KERN_WARNING "i2c_init: Failed to get IO pin for I2C data port\n"); + return res; + } else if ((res = cris_io_interface_allocate_pins(if_i2c, + 'b', + CONFIG_ETRAX_I2C_CLK_PORT, + CONFIG_ETRAX_I2C_CLK_PORT))) { + cris_io_interface_free_pins(if_i2c, + 'b', + CONFIG_ETRAX_I2C_DATA_PORT, + CONFIG_ETRAX_I2C_DATA_PORT); + printk(KERN_WARNING "i2c_init: Failed to get IO pin for I2C clk port\n"); + } +#endif - return 0; + return res; } static int __init @@ -711,14 +757,16 @@ i2c_register(void) { int res; - i2c_init(); + res = i2c_init(); + if (res < 0) + return res; res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops); if(res < 0) { printk(KERN_ERR "i2c: couldn't get a major number.\n"); return res; } - printk(KERN_INFO "I2C driver v2.2, (c) 1999-2001 Axis Communications AB\n"); + printk(KERN_INFO "I2C driver v2.2, (c) 1999-2004 Axis Communications AB\n"); return 0; } diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c index b3dfdf7b8fc5..201f4c90d961 100644 --- a/arch/cris/arch-v10/drivers/pcf8563.c +++ b/arch/cris/arch-v10/drivers/pcf8563.c @@ -15,7 +15,7 @@ * * Author: Tobias Anderberg . * - * $Id: pcf8563.c,v 1.8 2004/08/24 06:42:51 starvik Exp $ + * $Id: pcf8563.c,v 1.11 2005/03/07 13:13:07 starvik Exp $ */ #include @@ -40,7 +40,7 @@ #define PCF8563_MAJOR 121 /* Local major number. */ #define DEVICE_NAME "rtc" /* Name which is registered in /proc/devices. */ #define PCF8563_NAME "PCF8563" -#define DRIVER_VERSION "$Revision: 1.8 $" +#define DRIVER_VERSION "$Revision: 1.11 $" /* I2C bus slave registers. */ #define RTC_I2C_READ 0xa3 @@ -49,6 +49,8 @@ /* Two simple wrapper macros, saves a few keystrokes. */ #define rtc_read(x) i2c_readreg(RTC_I2C_READ, x) #define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y) + +static DEFINE_SPINLOCK(rtc_lock); /* Protect state etc */ static const unsigned char days_in_month[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; @@ -125,9 +127,12 @@ get_rtc_time(struct rtc_time *tm) int __init pcf8563_init(void) { - unsigned char ret; + int ret; - i2c_init(); + if ((ret = i2c_init())) { + printk(KERN_CRIT "pcf8563_init: failed to init i2c\n"); + return ret; + } /* * First of all we need to reset the chip. This is done by @@ -200,12 +205,15 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned { struct rtc_time tm; + spin_lock(&rtc_lock); get_rtc_time(&tm); if (copy_to_user((struct rtc_time *) arg, &tm, sizeof(struct rtc_time))) { + spin_unlock(&rtc_lock); return -EFAULT; } + spin_unlock(&rtc_lock); return 0; } break; @@ -250,6 +258,8 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned BIN_TO_BCD(tm.tm_min); BIN_TO_BCD(tm.tm_sec); tm.tm_mon |= century; + + spin_lock(&rtc_lock); rtc_write(RTC_YEAR, tm.tm_year); rtc_write(RTC_MONTH, tm.tm_mon); @@ -258,6 +268,8 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned rtc_write(RTC_MINUTES, tm.tm_min); rtc_write(RTC_SECONDS, tm.tm_sec); + spin_unlock(&rtc_lock); + return 0; #endif /* !CONFIG_ETRAX_RTC_READONLY */ } diff --git a/arch/cris/arch-v10/kernel/Makefile b/arch/cris/arch-v10/kernel/Makefile index 52761603b6a5..dcfec41d3533 100644 --- a/arch/cris/arch-v10/kernel/Makefile +++ b/arch/cris/arch-v10/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.5 2004/06/02 08:24:38 starvik Exp $ +# $Id: Makefile,v 1.6 2004/12/13 12:21:51 starvik Exp $ # # Makefile for the linux kernel. # @@ -7,7 +7,8 @@ extra-y := head.o obj-y := entry.o traps.o shadows.o debugport.o irq.o \ - process.o setup.o signal.o traps.o time.o ptrace.o + process.o setup.o signal.o traps.o time.o ptrace.o \ + dma.o io_interface_mux.o obj-$(CONFIG_ETRAX_KGDB) += kgdb.o obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o diff --git a/arch/cris/arch-v10/kernel/fasttimer.c b/arch/cris/arch-v10/kernel/fasttimer.c index 4717f7ae8e51..094ff45ae85b 100644 --- a/arch/cris/arch-v10/kernel/fasttimer.c +++ b/arch/cris/arch-v10/kernel/fasttimer.c @@ -1,10 +1,20 @@ -/* $Id: fasttimer.c,v 1.6 2004/05/14 10:18:39 starvik Exp $ +/* $Id: fasttimer.c,v 1.9 2005/03/04 08:16:16 starvik Exp $ * linux/arch/cris/kernel/fasttimer.c * * Fast timers for ETRAX100/ETRAX100LX * This may be useful in other OS than Linux so use 2 space indentation... * * $Log: fasttimer.c,v $ + * Revision 1.9 2005/03/04 08:16:16 starvik + * Merge of Linux 2.6.11. + * + * Revision 1.8 2005/01/05 06:09:29 starvik + * cli()/sti() will be obsolete in 2.6.11. + * + * Revision 1.7 2005/01/03 13:35:46 starvik + * Removed obsolete stuff. + * Mark fast timer IRQ as not shared. + * * Revision 1.6 2004/05/14 10:18:39 starvik * Export fast_timer_list * @@ -148,8 +158,7 @@ static int debug_log_cnt_wrapped = 0; #define DEBUG_LOG(string, value) \ { \ unsigned long log_flags; \ - save_flags(log_flags); \ - cli(); \ + local_irq_save(log_flags); \ debug_log_string[debug_log_cnt] = (string); \ debug_log_value[debug_log_cnt] = (unsigned long)(value); \ if (++debug_log_cnt >= DEBUG_LOG_MAX) \ @@ -157,7 +166,7 @@ static int debug_log_cnt_wrapped = 0; debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \ debug_log_cnt_wrapped = 1; \ } \ - restore_flags(log_flags); \ + local_irq_restore(log_flags); \ } #else #define DEBUG_LOG(string, value) @@ -320,8 +329,7 @@ void start_one_shot_timer(struct fast_timer *t, D1(printk("sft %s %d us\n", name, delay_us)); - save_flags(flags); - cli(); + local_irq_save(flags); do_gettimeofday_fast(&t->tv_set); tmp = fast_timer_list; @@ -395,7 +403,7 @@ void start_one_shot_timer(struct fast_timer *t, D2(printk("start_one_shot_timer: %d us done\n", delay_us)); - restore_flags(flags); + local_irq_restore(flags); } /* start_one_shot_timer */ static inline int fast_timer_pending (const struct fast_timer * t) @@ -425,11 +433,10 @@ int del_fast_timer(struct fast_timer * t) unsigned long flags; int ret; - save_flags(flags); - cli(); + local_irq_save(flags); ret = detach_fast_timer(t); t->next = t->prev = NULL; - restore_flags(flags); + local_irq_restore(flags); return ret; } /* del_fast_timer */ @@ -444,8 +451,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) struct fast_timer *t; unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); /* Clear timer1 irq */ *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr); @@ -462,7 +468,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) fast_timer_running = 0; fast_timer_ints++; - restore_flags(flags); + local_irq_restore(flags); t = fast_timer_list; while (t) @@ -482,8 +488,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) fast_timers_expired++; /* Remove this timer before call, since it may reuse the timer */ - save_flags(flags); - cli(); + local_irq_save(flags); if (t->prev) { t->prev->next = t->next; @@ -498,7 +503,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) } t->prev = NULL; t->next = NULL; - restore_flags(flags); + local_irq_restore(flags); if (t->function != NULL) { @@ -515,8 +520,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) D1(printk(".\n")); } - save_flags(flags); - cli(); + local_irq_save(flags); if ((t = fast_timer_list) != NULL) { /* Start next timer.. */ @@ -535,7 +539,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) #endif start_timer1(us); } - restore_flags(flags); + local_irq_restore(flags); break; } else @@ -546,7 +550,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) D1(printk("e! %d\n", us)); } } - restore_flags(flags); + local_irq_restore(flags); } if (!t) @@ -748,13 +752,12 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len #endif used += sprintf(bigbuf + used, "Active timers:\n"); - save_flags(flags); - cli(); + local_irq_save(flags); t = fast_timer_list; while (t != NULL && (used+100 < BIG_BUF_SIZE)) { nextt = t->next; - restore_flags(flags); + local_irq_restore(flags); used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " "d: %6li us data: 0x%08lX" /* " func: 0x%08lX" */ @@ -768,14 +771,14 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len t->data /* , t->function */ ); - cli(); + local_irq_disable(); if (t->next != nextt) { printk(KERN_WARNING "timer removed!\n"); } t = nextt; } - restore_flags(flags); + local_irq_restore(flags); } if (used - offset < len) @@ -963,7 +966,7 @@ void fast_timer_init(void) if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 ))) fasttimer_proc_entry->read_proc = proc_fasttimer_read; #endif /* PROC_FS */ - if(request_irq(TIMER1_IRQ_NBR, timer1_handler, SA_SHIRQ, + if(request_irq(TIMER1_IRQ_NBR, timer1_handler, 0, "fast timer int", NULL)) { printk("err: timer1 irq\n"); diff --git a/include/asm-cris/arch-v10/ide.h b/include/asm-cris/arch-v10/ide.h new file mode 100644 index 000000000000..8cf2d7cb22ac --- /dev/null +++ b/include/asm-cris/arch-v10/ide.h @@ -0,0 +1,99 @@ +/* + * linux/include/asm-cris/ide.h + * + * Copyright (C) 2000, 2001, 2002 Axis Communications AB + * + * Authors: Bjorn Wesen + * + */ + +/* + * This file contains the ETRAX 100LX specific IDE code. + */ + +#ifndef __ASMCRIS_IDE_H +#define __ASMCRIS_IDE_H + +#ifdef __KERNEL__ + +#include +#include +#include + + +/* ETRAX 100 can support 4 IDE busses on the same pins (serialized) */ + +#define MAX_HWIFS 4 + +extern __inline__ int ide_default_irq(unsigned long base) +{ + /* all IDE busses share the same IRQ, number 4. + * this has the side-effect that ide-probe.c will cluster our 4 interfaces + * together in a hwgroup, and will serialize accesses. this is good, because + * we can't access more than one interface at the same time on ETRAX100. + */ + return 4; +} + +extern __inline__ unsigned long ide_default_io_base(int index) +{ + /* we have no real I/O base address per interface, since all go through the + * same register. but in a bitfield in that register, we have the i/f number. + * so we can use the io_base to remember that bitfield. + */ + static const unsigned long io_bases[MAX_HWIFS] = { + IO_FIELD(R_ATA_CTRL_DATA, sel, 0), + IO_FIELD(R_ATA_CTRL_DATA, sel, 1), + IO_FIELD(R_ATA_CTRL_DATA, sel, 2), + IO_FIELD(R_ATA_CTRL_DATA, sel, 3) + }; + return io_bases[index]; +} + +/* this is called once for each interface, to setup the port addresses. data_port is the result + * of the ide_default_io_base call above. ctrl_port will be 0, but that is don't care for us. + */ + +extern __inline__ void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, unsigned long ctrl_port, int *irq) +{ + int i; + + /* fill in ports for ATA addresses 0 to 7 */ + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = data_port | + IO_FIELD(R_ATA_CTRL_DATA, addr, i) | + IO_STATE(R_ATA_CTRL_DATA, cs0, active); + } + + /* the IDE control register is at ATA address 6, with CS1 active instead of CS0 */ + + hw->io_ports[IDE_CONTROL_OFFSET] = data_port | + IO_FIELD(R_ATA_CTRL_DATA, addr, 6) | + IO_STATE(R_ATA_CTRL_DATA, cs1, active); + + /* whats this for ? */ + + hw->io_ports[IDE_IRQ_OFFSET] = 0; +} + +extern __inline__ void ide_init_default_hwifs(void) +{ + hw_regs_t hw; + int index; + + for(index = 0; index < MAX_HWIFS; index++) { + ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL); + hw.irq = ide_default_irq(ide_default_io_base(index)); + ide_register_hw(&hw, NULL); + } +} + +/* some configuration options we don't need */ + +#undef SUPPORT_VLB_SYNC +#define SUPPORT_VLB_SYNC 0 + +#endif /* __KERNEL__ */ + +#endif /* __ASMCRIS_IDE_H */ diff --git a/include/asm-cris/ide.h b/include/asm-cris/ide.h new file mode 100644 index 000000000000..a894f66665f8 --- /dev/null +++ b/include/asm-cris/ide.h @@ -0,0 +1 @@ +#include -- GitLab