OpenFSI Updates for dev-4.10 kernel
cover OpenFSI Updates for dev-4.10 kernel
These changes bring the 4.10 kernel FSI device driver up to date with the 4.7 kernel version.
* Add basic and hub interrupt support
* Bug fixes introduced during 4.7 to 4.10 migration
* FSI protocol modification for added operational stability
Christopher Bostic (5):
drivers/fsi: Add slave interrupt polling drivers/fsi: Scan for hub sourced IRQ's drivers/fsi: Set IRQ masks along hub path drivers/fsi: Unscan on master unregister drivers/fsi: GPIO stability changes for Cronus/Hostboot
Eddie James (2):
drivers/fsi: Add Client IRQ Enable / Disable drivers/fsi: Fix one and two byte bus reads/writes
Signature · 1 line
1.8.2.2
PATCH 1/7 drivers/fsi: Add slave interrupt polling
Scan slaves present for asserting interrupt signals in the si1s register and call a registered client's interrupt handler as appropriate.
Includes initial code from Eddie James <[email protected]>
--- drivers/fsi/fsi-core.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/fsi/fsi-master.h | 1 + include/linux/fsi.h | 5 +++ 3 files changed, 116 insertions(+)
drivers/fsi/fsi-core.c +110 -0
@@ -15,9 +15,11 @@#include <linux/device.h> #include <linux/fsi.h> +#include <linux/kthread.h> #include <linux/idr.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/jiffies.h> #include "fsi-master.h"
@@ -38,8 +40,11 @@#define FSI_PEEK_BASE 0x410static const int engine_page_size =0x400 ; +static struct task_struct *master_ipoll; +static unsigned int fsi_ipoll_period_ms =100 ;#define FSI_SLAVE_BASE 0x800 +#define FSI_IPOLL_PERIOD msecs_to_jiffies(fsi_ipoll_period_ms)/* * FSI slave engine control register offsets
@@ -47,6 +52,8 @@#define FSI_SMODE 0x0/* R/W: Mode register */ #define FSI_SISC 0x8/* R/W: Interrupt condition */ #define FSI_SSTAT 0x14/* R : Slave status */ +#define FSI_SI1M 0x18/* R/W: IRQ mask */ +#define FSI_SI1S 0x1C/* R : IRQ status */ #define FSI_LLMODE 0x100/* R/W: Link layer mode register */ /*
@@ -342,6 +349,7 @@ static int fsi_slave_scan(struct fsi_slave *slave)uint32_t engine_addr;uint32_t conf;int rc, i; +uint8_t si1s_bit =1 ;/* * scan engines
@@ -396,6 +404,7 @@ static int fsi_slave_scan(struct fsi_slave *slave) dev->unit = i; dev->addr = engine_addr; dev->size = slots * engine_page_size; + dev->si1s_bit = si1s_bit++; dev_info(&slave->dev, "engine[%i]: type %x, version %x, addr %x size %x\n",
@@ -761,6 +770,90 @@ static void fsi_master_unscan(struct fsi_master *master)device_for_each_child (&master->dev,NULL , __fsi_master_remove_slave); } +static int __fsi_dev_irq (struct device *dev,void *data) +{ +uint32_t *si1s = data; +struct fsi_device *fsi_dev =to_fsi_dev (dev); + +if (!fsi_dev || !si1s) { +dev_dbg (dev,"Invalid input: %p %p\n" , fsi_dev, si1s); +return -EINVAL ; + } + +if (*si1s & (0x80000000 >> fsi_dev->si1s_bit) && + fsi_dev->irq_handler) { + fsi_dev->irq_handler (0 , &fsi_dev->dev); +return 1 ; + } + +return 0 ; +} + +static int __fsi_slave_irq (struct device *dev,void *data) +{ +return device_for_each_child (dev, data, __fsi_dev_irq); +} + +static void fsi_master_irq (struct fsi_master *master,int link,uint32_t si1s) +{ +device_for_each_child (&master->dev, &si1s, __fsi_slave_irq); +} + +static int fsi_master_ipoll (void *data) +{ +int rc; +uint32_t si1s; +unsigned long elapsed =0 ; +unsigned long previous_jiffies = jiffies; +struct fsi_master *master = data; + +while (!kthread_should_stop ()) { +if (!master->ipoll) + goto done; + +/* Ignore errors for now */ + rc = master->read (master,0 ,0 ,FSI_SLAVE_BASE +FSI_SI1S , + &si1s,sizeof (uint32_t )); +if (rc) + goto done; + +if (si1s & master->ipoll) +fsi_master_irq (master,0 , si1s); +done: + elapsed = jiffies = previous_jiffies; +if (elapsed <FSI_IPOLL_PERIOD ) { +set_current_state (TASK_UNINTERRUPTIBLE ); +schedule_timeout (FSI_IPOLL_PERIOD - elapsed); + } + previous_jiffies = jiffies; + } + +return 0 ; +} + +/* +* TODO: move this to master->start_ipoll() - each master may have its +* own way of doing this +*/ +int fsi_master_start_ipoll (struct fsi_master *master) +{ +if (master_ipoll) { +dev_err (&master->dev,"Already polling for irqs\n" ); +return -EALREADY ; + } + master_ipoll =kthread_create (fsi_master_ipoll, master, +"fsi_master_ipoll" ); +if (IS_ERR (master_ipoll)) { +dev_err (&master->dev,"Coudn't create ipoll thread rc:%d\n" , + (int )PTR_ERR (master_ipoll)); +return PTR_ERR (master_ipoll); + } +wake_up_process (master_ipoll); + +return 0 ; +} +EXPORT_SYMBOL_GPL (fsi_master_start_ipoll); +static ssize_t master_rescan_store (struct device *dev,struct device_attribute *attr,const char *buf,size_t count) {
@@ -768,6 +861,7 @@ static ssize_t master_rescan_store(struct device *dev,fsi_master_unscan (master);fsi_master_scan (master); +fsi_master_start_ipoll (master);return count; }
@@ -829,6 +923,11 @@ void fsi_master_unregister(struct fsi_master *master) master->idx =-1 ; } +if (master_ipoll) { +kthread_stop (master_ipoll); + master_ipoll =NULL ; + } +device_unregister (&master->dev); }EXPORT_SYMBOL_GPL (fsi_master_unregister);
@@ -872,6 +971,17 @@ void fsi_driver_unregister(struct fsi_driver *fsi_drv) }EXPORT_SYMBOL_GPL (fsi_driver_unregister); +int fsi_enable_irq (struct fsi_device *dev) +{ +return 0 ; +} +EXPORT_SYMBOL (fsi_enable_irq); + +void fsi_disable_irq (struct fsi_device *dev) +{ +} +EXPORT_SYMBOL (fsi_disable_irq); +struct bus_type fsi_bus_type = { .name ="fsi" , .match = fsi_bus_match,
drivers/fsi/fsi-master.h +1 -0
@@ -26,6 +26,7 @@ struct fsi_master {int idx;int n_links;int flags; +uint32_t ipoll;int (*read)(struct fsi_master *,int link,uint8_t id,uint32_t addr,void *val,size_t size); int (*write)(struct fsi_master *, int link, uint8_t id,
include/linux/fsi.h +5 -0
@@ -22,9 +22,11 @@ struct fsi_device {u8 engine_type;u8 version;u8 unit; +u8 si1s_bit;struct fsi_slave *slave;uint32_t addr;uint32_t size; +int (*irq_handler)(int ,void *); }; extern int fsi_device_read(struct fsi_device *dev, uint32_t addr,
@@ -80,4 +82,7 @@ extern int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,extern struct bus_type fsi_bus_type; +extern int fsi_enable_irq (struct fsi_device *dev); +extern void fsi_disable_irq (struct fsi_device *dev); +#endif /* LINUX_FSI_H */
Signature · 1 line
1.8.2.2
Re: [PATCH linux dev-4.10 1/7] drivers/fsi: Add slave interrupt polling
Quoted 159 lines · Christopher Bostic
Scan slaves present for asserting interrupt signals in the si1s register and call a registered client's interrupt handler as appropriate.
Includes initial code from Eddie James <[email protected]>
Signed-off-by Eddie James <[email protected]>Signed-off-by Christopher Bostic <[email protected]>--- drivers/fsi/fsi-core.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/fsi/fsi-master.h | 1 + include/linux/fsi.h | 5 +++ 3 files changed, 116 insertions(+)drivers/fsi/fsi-core.c +93
-0@@ -15,9 +15,11 @@#include <linux/device.h> #include <linux/fsi.h> +#include <linux/kthread.h> #include <linux/idr.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/jiffies.h> #include "fsi-master.h" @@ -38,8 +40,11 @@#define FSI_PEEK_BASE 0x410static const int engine_page_size =0x400 ; +static struct task_struct *master_ipoll; +static unsigned int fsi_ipoll_period_ms =100 ;#define FSI_SLAVE_BASE 0x800 +#define FSI_IPOLL_PERIOD msecs_to_jiffies(fsi_ipoll_period_ms)/* * FSI slave engine control register offsets @@ -47,6 +52,8 @@#define FSI_SMODE 0x0/* R/W: Mode register */ #define FSI_SISC 0x8/* R/W: Interrupt condition */ #define FSI_SSTAT 0x14/* R : Slave status */ +#define FSI_SI1M 0x18/* R/W: IRQ mask */ +#define FSI_SI1S 0x1C/* R : IRQ status */ #define FSI_LLMODE 0x100/* R/W: Link layer mode register */ /* @@ -342,6 +349,7 @@ static int fsi_slave_scan(struct fsi_slave *slave)uint32_t engine_addr;uint32_t conf;int rc, i; +uint8_t si1s_bit =1 ;/* * scan engines @@ -396,6 +404,7 @@ static int fsi_slave_scan(struct fsi_slave *slave) dev->unit = i; dev->addr = engine_addr; dev->size = slots * engine_page_size; + dev->si1s_bit = si1s_bit++; dev_info(&slave->dev, "engine[%i]: type %x, version %x, addr %x size %x\n",@@ -761,6 +770,90 @@ static void fsi_master_unscan(struct fsi_master *master)device_for_each_child (&master->dev,NULL , __fsi_master_remove_slave); } +static int __fsi_dev_irq (struct device *dev,void *data) +{ +uint32_t *si1s = data; +struct fsi_device *fsi_dev =to_fsi_dev (dev); + +if (!fsi_dev || !si1s) { +dev_dbg (dev,"Invalid input: %p %p\n" , fsi_dev, si1s); +return -EINVAL ; + } + +if (*si1s & (0x80000000 >> fsi_dev->si1s_bit) && + fsi_dev->irq_handler) { + fsi_dev->irq_handler (0 , &fsi_dev->dev); +return 1 ; + } + +return 0 ; +} + +static int __fsi_slave_irq (struct device *dev,void *data) +{ +return device_for_each_child (dev, data, __fsi_dev_irq); +} + +static void fsi_master_irq (struct fsi_master *master,int link,uint32_t si1s) +{ +device_for_each_child (&master->dev, &si1s, __fsi_slave_irq); +} + +static int fsi_master_ipoll (void *data) +{ +int rc; +uint32_t si1s; +unsigned long elapsed =0 ; +unsigned long previous_jiffies = jiffies; +struct fsi_master *master = data; + +while (!kthread_should_stop ()) { +if (!master->ipoll) + goto done; + +/* Ignore errors for now */ + rc = master->read (master,0 ,0 ,FSI_SLAVE_BASE +FSI_SI1S , + &si1s,sizeof (uint32_t )); +if (rc) + goto done; + +if (si1s & master->ipoll) +fsi_master_irq (master,0 , si1s); +done: + elapsed = jiffies = previous_jiffies; +if (elapsed <FSI_IPOLL_PERIOD ) { +set_current_state (TASK_UNINTERRUPTIBLE ); +schedule_timeout (FSI_IPOLL_PERIOD - elapsed); + } + previous_jiffies = jiffies; + } + +return 0 ; +} + +/* +* TODO: move this to master->start_ipoll() - each master may have its +* own way of doing this +*/ +int fsi_master_start_ipoll (struct fsi_master *master) +{ +if (master_ipoll) { +dev_err (&master->dev,"Already polling for irqs\n" ); +return -EALREADY ; + } + master_ipoll =kthread_create (fsi_master_ipoll, master, +"fsi_master_ipoll" ); +if (IS_ERR (master_ipoll)) { +dev_err (&master->dev,"Coudn't create ipoll thread rc:%d\n" , + (int )PTR_ERR (master_ipoll)); +return PTR_ERR (master_ipoll); + } +wake_up_process (master_ipoll); + +return 0 ; +} +EXPORT_SYMBOL_GPL (fsi_master_start_ipoll); +static ssize_t master_rescan_store (struct device *dev,struct device_attribute *attr,const char *buf,size_t count) {
drivers/fsi/fsi-core.c static ssize_t master_rescan_store(struct device *dev, · line 864
Quoted 4 lines
drivers/fsi/fsi-core.c +1
-0@@ -768,6 +861,7 @@ static ssize_t master_rescan_store(struct device *dev,fsi_master_unscan (master);fsi_master_scan (master); +fsi_master_start_ipoll (master);
I have been having some problems in 4.10 with this patch in the build. BMC is hanging and requires AC cycle to recover, directly after scanning fsi. I haven't had time to debug but so far it seems to follow this patch. I do not think this should be merged until Chris and I have done more testing.
Thanks,
Eddie
Quoted 69 lines
drivers/fsi/fsi-core.c +16
-0return count; }@@ -829,6 +923,11 @@ void fsi_master_unregister(struct fsi_master *master) master->idx =-1 ; } +if (master_ipoll) { +kthread_stop (master_ipoll); + master_ipoll =NULL ; + } +device_unregister (&master->dev); }EXPORT_SYMBOL_GPL (fsi_master_unregister);@@ -872,6 +971,17 @@ void fsi_driver_unregister(struct fsi_driver *fsi_drv) }EXPORT_SYMBOL_GPL (fsi_driver_unregister); +int fsi_enable_irq (struct fsi_device *dev) +{ +return 0 ; +} +EXPORT_SYMBOL (fsi_enable_irq); + +void fsi_disable_irq (struct fsi_device *dev) +{ +} +EXPORT_SYMBOL (fsi_disable_irq); +struct bus_type fsi_bus_type = { .name ="fsi" , .match = fsi_bus_match,drivers/fsi/fsi-master.h +1
-0@@ -26,6 +26,7 @@ struct fsi_master {int idx;int n_links;int flags; +uint32_t ipoll;int (*read)(struct fsi_master *,int link,uint8_t id,uint32_t addr,void *val,size_t size); int (*write)(struct fsi_master *, int link, uint8_t id,include/linux/fsi.h +5
-0@@ -22,9 +22,11 @@ struct fsi_device {u8 engine_type;u8 version;u8 unit; +u8 si1s_bit;struct fsi_slave *slave;uint32_t addr;uint32_t size; +int (*irq_handler)(int ,void *); }; extern int fsi_device_read(struct fsi_device *dev, uint32_t addr,@@ -80,4 +82,7 @@ extern int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,extern struct bus_type fsi_bus_type; +extern int fsi_enable_irq (struct fsi_device *dev); +extern void fsi_disable_irq (struct fsi_device *dev); +#endif /* LINUX_FSI_H */
PATCH 2/7 drivers/fsi: Add Client IRQ Enable / Disable
In reply to Christopher BosticFrom: Eddie James <[email protected]>
Allow FSI client drivers to enable and disable their engine IRQ's via the exported interfaces fsi_enable_irq and fsi_disable_irq.
--- drivers/fsi/fsi-core.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+)
drivers/fsi/fsi-core.c +45 -0
@@ -973,12 +973,57 @@ void fsi_driver_unregister(struct fsi_driver *fsi_drv)int fsi_enable_irq (struct fsi_device *dev) { +int rc; +uint32_t si1m; +uint32_t bit =0x80000000 >> dev->si1s_bit; +struct fsi_master *master = dev->slave->master; + +if (!dev->irq_handler) +return -EINVAL ; + + rc = master->read (master,0 ,0 ,FSI_SLAVE_BASE +FSI_SI1M , &si1m, +sizeof (uint32_t )); +if (rc) { +dev_err (&master->dev,"Coudn't read si1m:%d\n" , rc); +return rc; + } + + si1m |= bit; + rc = master->write (master,0 ,0 ,FSI_SLAVE_BASE +FSI_SI1M , &si1m, +sizeof (uint32_t )); +if (rc) { +dev_err (&master->dev,"Coudn't write si1m:%d\n" , rc); +return rc; + } + + master->ipoll |= bit;return 0 ; }EXPORT_SYMBOL (fsi_enable_irq);void fsi_disable_irq (struct fsi_device *dev) { +int rc; +uint32_t si1m; +uint32_t bits = ~(0x80000000 >> dev->si1s_bit); +struct fsi_master *master = dev->slave->master; + + master->ipoll &= bits; + + rc = master->read (master,0 ,0 ,FSI_SLAVE_BASE +FSI_SI1M , &si1m, +sizeof (uint32_t )); +if (rc) { +dev_err (&master->dev,"Couldn't read si1m:%d\n" , rc); +return ; + } + + si1m &= bits; + rc = master->write (master,0 ,0 ,FSI_SLAVE_BASE +FSI_SI1M , &si1m, +sizeof (uint32_t )); +if (rc) { +dev_err (&master->dev,"Coudn't write si1m:%d\n" , rc); +return ; + } }EXPORT_SYMBOL (fsi_disable_irq);
Signature · 1 line
1.8.2.2
PATCH 3/7 drivers/fsi: Scan for hub sourced IRQ's
In reply to Christopher BosticLook for the hub link that may have sourced the IRQ being handled. Clear out hub link interrupting conditions that are latched in hardware after FSI client handler has been dispatched.
--- drivers/fsi/fsi-core.c | 32 ++++++++++++--- drivers/fsi/fsi-master-hub.c | 93 ++++++++++++++++++++++++++++++++++++++++++++ drivers/fsi/fsi-master.h | 2 + 3 files changed, 122 insertions(+), 5 deletions(-)
drivers/fsi/fsi-core.c +27 -5
@@ -54,6 +54,8 @@#define FSI_SSTAT 0x14/* R : Slave status */ #define FSI_SI1M 0x18/* R/W: IRQ mask */ #define FSI_SI1S 0x1C/* R : IRQ status */ +#define FSI_SRSIC0 0x68/* R/W: Hub IRQ condition 0 */ +#define FSI_SRSIC1 0x6C/* R/W: Hub IRQ condition 1 */ #define FSI_LLMODE 0x100/* R/W: Link layer mode register */ /*
@@ -573,6 +575,21 @@ static void fsi_slave_release(struct device *dev)kfree (slave); } +static int fsi_slave_irq_clear (struct fsi_slave *slave) +{ +uint32_t clear = ~0 ; +int rc; + + rc =fsi_slave_write (slave,FSI_SLAVE_BASE +FSI_SRSIC0 , &clear, +sizeof (clear)); +if (rc) { +dev_dbg (&slave->dev,"Failed on write to SRSIC0\n" ); +return rc; + } +return fsi_slave_write (slave,FSI_SLAVE_BASE +FSI_SRSIC1 , &clear, +sizeof (clear)); +} +static int fsi_slave_init (struct fsi_master *master,int link,uint8_t id) {uint32_t chip_id, llmode;
@@ -657,8 +674,11 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)if (rc)dev_warn (&slave->dev,"failed to create term attr: %d\n" , rc); -fsi_slave_scan (slave); -return 0 ; + rc =fsi_slave_scan (slave); +if (rc) +return rc; + +return fsi_slave_irq_clear (slave); }/* FSI master support */
@@ -774,6 +794,7 @@ static int __fsi_dev_irq(struct device *dev, void *data) {uint32_t *si1s = data;struct fsi_device *fsi_dev =to_fsi_dev (dev); +int rc;if (!fsi_dev || !si1s) {dev_dbg (dev,"Invalid input: %p %p\n" , fsi_dev, si1s);
@@ -782,8 +803,8 @@ static int __fsi_dev_irq(struct device *dev, void *data)if (*si1s & (0x80000000 >> fsi_dev->si1s_bit) && fsi_dev->irq_handler) { - fsi_dev->irq_handler (0 , &fsi_dev->dev); -return 1 ; + rc = fsi_dev->irq_handler (0 , &fsi_dev->dev); +dev_dbg (dev,"IRQ handler exit: %d\n" , rc); }return 0 ;
@@ -794,7 +815,7 @@ static int __fsi_slave_irq(struct device *dev, void *data)return device_for_each_child (dev, data, __fsi_dev_irq); } -static void fsi_master_irq (struct fsi_master *master,int link,uint32_t si1s) +void fsi_master_irq (struct fsi_master *master,int link,uint32_t si1s) {device_for_each_child (&master->dev, &si1s, __fsi_slave_irq); }
@@ -817,6 +838,7 @@ static int fsi_master_ipoll(void *data)if (rc) goto done; + si1s =be32_to_cpu (si1s);if (si1s & master->ipoll)fsi_master_irq (master,0 , si1s); done:
drivers/fsi/fsi-master-hub.c +93 -0
117 lines not on this page · raw message
drivers/fsi/fsi-master.h +2 -0
@@ -41,6 +41,8 @@ struct fsi_master {extern int fsi_master_register (struct fsi_master *master);extern void fsi_master_unregister (struct fsi_master *master); +void fsi_master_irq (struct fsi_master *master,int link,uint32_t si1s); +/** * crc4 helper: Given a starting crc4 state @c, calculate the crc4 vaue of @x, * which is @bits in length. This may be required by master implementations
Signature · 1 line
1.8.2.2
PATCH 4/7 drivers/fsi: Set IRQ masks along hub path
In reply to Christopher BosticEnable/disable client engine IRQ masks including those along the hub path to a particular engine. This includes slave Si1M, SRSIM, and hub master MSIEP, MMODE.
--- drivers/fsi/fsi-core.c | 145 +++++++++++++++++++++++++++++++++++++++++-- drivers/fsi/fsi-master-hub.c | 6 +- 2 files changed, 144 insertions(+), 7 deletions(-)
drivers/fsi/fsi-core.c +139 -6
@@ -56,6 +56,8 @@#define FSI_SI1S 0x1C/* R : IRQ status */ #define FSI_SRSIC0 0x68/* R/W: Hub IRQ condition 0 */ #define FSI_SRSIC1 0x6C/* R/W: Hub IRQ condition 1 */ +#define FSI_SRSIM0 0x70/* R/W: Hub IRQ mask 0 */ +#define FSI_SRSIS0 0x78/* R: Hub IRQ status 0 */ #define FSI_LLMODE 0x100/* R/W: Link layer mode register */ /*
@@ -72,6 +74,13 @@#define FSI_SMODE_LBCRR_SHIFT 8/* Clk ratio shift */ #define FSI_SMODE_LBCRR_MASK 0xf/* Clk ratio mask */ +#define FSI_SI1S_HUB_SRC 0x00100000 + +/* +* SRSIM, SRSIS, SRSIC fields +*/ +#define FSI_SRSIX_BITS_PER_LINK 8 +/* * LLMODE fields */
@@ -79,6 +88,12 @@#define FSI_SLAVE_SIZE_23b 0x800000 +/* Master control regs */ +#define FSI_HUB_CONTROL 0x3400 +#define FSI_MMODE 0x0/* R/W: mode */ +#define FSI_MSIEP0 0x30/* R/W: Slave IRQ enable */ +#define FSI_MSIEP_BITS_PER_LINK 4 +static DEFINE_IDA (master_ida);struct fsi_slave {
@@ -807,7 +822,7 @@ static int __fsi_dev_irq(struct device *dev, void *data)dev_dbg (dev,"IRQ handler exit: %d\n" , rc); } -return 0 ; +return 1 ; }static int __fsi_slave_irq (struct device *dev,void *data)
@@ -993,17 +1008,129 @@ void fsi_driver_unregister(struct fsi_driver *fsi_drv) }EXPORT_SYMBOL_GPL (fsi_driver_unregister); +static uint32_t link_to_srsim_mask (int link) +{ +return ((0x80000000 >>6 ) >>FSI_SRSIX_BITS_PER_LINK * link); +} + +static uint32_t link_to_msiep_mask (int link) +{ +return (0xf0000000 >> (FSI_MSIEP_BITS_PER_LINK * link)); +} + +static int fsi_write_mask (struct fsi_master *master,struct fsi_slave *slave, +uint32_t offset,uint32_t mask,int on) +{ +int rc; +uint32_t val; + +if (!slave && !master) +return -EINVAL ; + +if (slave) + rc =fsi_slave_read (slave,FSI_SLAVE_BASE + offset, &val, +sizeof (val)); +else + rc = master->read (master,0 ,0 , offset, &val,sizeof (val)); + +if (rc) { +dev_dbg (&slave->dev,"Failed to read offset %04x\n" , + offset); +return rc; + } + val =be32_to_cpu (val); + +if (on) + val |= mask; +else + val &= ~mask; + + val =cpu_to_be32 (val); +if (slave) + rc =fsi_slave_write (slave,FSI_SLAVE_BASE + offset, &val, +sizeof (val)); +else + rc = master->write (master,0 ,0 , offset, &val,sizeof (val)); + +return rc; +} + +static int set_upstream_irq_masks (struct fsi_master *master, +struct fsi_slave *slave,int on) +{ +struct fsi_slave *upstream_slave; +struct fsi_master *upstream_master; +uint32_t mask, si1m; +int rc; + +if (!master->idx) +return 0 ; + + upstream_slave =to_fsi_slave (slave->master->dev.parent); +if (!upstream_slave) { +dev_dbg (&slave->dev,"No upstream slave found\n" ); +return -ENODEV ; + } + + mask =link_to_srsim_mask (slave->link); + rc =fsi_write_mask (NULL , upstream_slave,FSI_SRSIM0 , mask, on); +if (rc) +return rc; + + upstream_master = upstream_slave->master; +if (!upstream_master) { +dev_dbg (&upstream_slave->dev,"Cannot find master\n" ); +return -ENODEV ; + } + + mask =link_to_msiep_mask (slave->link); + +/* +* TODO: Remove these HUB control references by creating a new master +* method master->write_control(msiep) +*/ + rc =fsi_write_mask (upstream_master,NULL ,FSI_HUB_CONTROL +FSI_MSIEP0 , + mask, on); + + mask =FSI_SI1S_HUB_SRC ; +if (on) + upstream_master->ipoll |= mask; +else + upstream_master->ipoll &= mask; + +if (rc) +return rc; + + si1m =be32_to_cpu (0xd0040410 ); + +/* +* TODO: Remove the HUB control reference by creating a new master +* method master->write_control(mmode) +*/ + rc = upstream_master->write (upstream_master,0 ,0 , +FSI_HUB_CONTROL +FSI_MMODE , &si1m, +sizeof (si1m)); +if (rc) { +dev_dbg (&upstream_slave->dev, +"Failed to set i-poll\n" ); + } + +return fsi_write_mask (NULL , upstream_slave,FSI_SI1M , mask, on); +} +int fsi_enable_irq (struct fsi_device *dev) {int rc;uint32_t si1m;uint32_t bit =0x80000000 >> dev->si1s_bit;struct fsi_master *master = dev->slave->master; +struct fsi_slave *slave = dev->slave; +int link = slave->link;if (!dev->irq_handler)return -EINVAL ; - rc = master->read (master,0 ,0 ,FSI_SLAVE_BASE +FSI_SI1M , &si1m, + rc = master->read (master, link,0 ,FSI_SLAVE_BASE +FSI_SI1M , &si1m,sizeof (uint32_t ));if (rc) {dev_err (&master->dev,"Coudn't read si1m:%d\n" , rc);
@@ -1011,7 +1138,7 @@ int fsi_enable_irq(struct fsi_device *dev) } si1m |= bit; - rc = master->write (master,0 ,0 ,FSI_SLAVE_BASE +FSI_SI1M , &si1m, + rc = master->write (master, link,0 ,FSI_SLAVE_BASE +FSI_SI1M , &si1m,sizeof (uint32_t ));if (rc) {dev_err (&master->dev,"Coudn't write si1m:%d\n" , rc);
@@ -1019,20 +1146,23 @@ int fsi_enable_irq(struct fsi_device *dev) } master->ipoll |= bit; -return 0 ; +return set_upstream_irq_masks (master, slave,1 ); }EXPORT_SYMBOL (fsi_enable_irq); +void fsi_disable_irq (struct fsi_device *dev) {int rc;uint32_t si1m;uint32_t bits = ~(0x80000000 >> dev->si1s_bit);struct fsi_master *master = dev->slave->master; +struct fsi_slave *slave = dev->slave; +int link = slave->link; master->ipoll &= bits; - rc = master->read (master,0 ,0 ,FSI_SLAVE_BASE +FSI_SI1M , &si1m, + rc = master->read (master, link,0 ,FSI_SLAVE_BASE +FSI_SI1M , &si1m,sizeof (uint32_t ));if (rc) {dev_err (&master->dev,"Couldn't read si1m:%d\n" , rc);
@@ -1040,12 +1170,15 @@ void fsi_disable_irq(struct fsi_device *dev) } si1m &= bits; - rc = master->write (master,0 ,0 ,FSI_SLAVE_BASE +FSI_SI1M , &si1m, + rc = master->write (master, link,0 ,FSI_SLAVE_BASE +FSI_SI1M , &si1m,sizeof (uint32_t ));if (rc) {dev_err (&master->dev,"Coudn't write si1m:%d\n" , rc);return ; } + +if (!master->ipoll) +set_upstream_irq_masks (master, slave,0 ); }EXPORT_SYMBOL (fsi_disable_irq);
drivers/fsi/fsi-master-hub.c +5 -1
@@ -59,7 +59,11 @@#define FSI_MMODE_CRS1SHFT 8/* Clk rate selection 1 shift */ #define FSI_MMODE_CRS1MASK 0x3ff/* Clk rate selection 1 mask */ -/* MRESB: Reset brindge */ +/* MSIEP: Per slave interrupt enable */ +#define FSI_MSIEP0 0x30/* R/W: Slave IRQ enable */ +#define FSI_MSIEP_BITS_PER_LINK 4 + +/* MRESB: Reset bridge */ #define FSI_MRESB_RST_GEN 0x80000000/* General reset */ #define FSI_MRESB_RST_ERR 0x40000000/* Error Reset */
Signature · 1 line
1.8.2.2
PATCH 5/7 drivers/fsi: Unscan on master unregister
In reply to Christopher BosticUnscan all devices whatn a master unregisters - ensures full cleanup.
--- drivers/fsi/fsi-core.c | 1 + 1 file changed, 1 insertion(+)
drivers/fsi/fsi-core.c +1 -0
@@ -965,6 +965,7 @@ void fsi_master_unregister(struct fsi_master *master) master_ipoll =NULL ; } +fsi_master_unscan (master);device_unregister (&master->dev); }EXPORT_SYMBOL_GPL (fsi_master_unregister);
Signature · 1 line
1.8.2.2
Joel Stanley
AppliedRe: [PATCH linux dev-4.10 5/7] drivers/fsi: Unscan on master unregister
Quoted 4 lines · Christopher Bostic
Unscan all devices whatn a master unregisters - ensures full cleanup.
Signed-off-by Christopher Bostic <[email protected]>
Applied to dev-4.10.
Cheers,
Joel
PATCH 6/7 drivers/fsi: GPIO stability changes for Cronus/Hostboot
In reply to Christopher BosticImprove stability in the FSI protocol by re-ordering the clocking delays. Increase clocking delays to 3 microseconds. Remove delay prior to sampling input - now redundant given new clocking delay order.
New effective delay per clock toggle is now 6 microseconds. Previous clocking summed up to 3 nS but real time measurements of each 1 nS delay actually was approx 1.8 microseconds. Previous total delay was then 1.8 * 3 = 5.4 microseconds.
--- drivers/fsi/fsi-master-gpio.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/fsi/fsi-master-gpio.c +3 -4
@@ -14,7 +14,7 @@#include "fsi-master.h" -#define FSI_GPIO_STD_DLY 1/* Standard pin delay in nS */ +#define FSI_GPIO_STD_DLY 3/* Standard pin delay in uS */ #define FSI_ECHO_DELAY_CLOCKS 16/* Number clocks for echo delay */ #define FSI_PRE_BREAK_CLOCKS 50/* Number clocks to prep for break */ #define FSI_BREAK_CLOCKS 256/* Number of clocks to issue break */
@@ -76,10 +76,10 @@ static void clock_toggle(struct fsi_master_gpio *master, int count)int i;for (i =0 ; i < count; i++) { -ndelay (FSI_GPIO_STD_DLY );gpiod_set_value (master->gpio_clk,0 ); -ndelay (FSI_GPIO_STD_DLY ); +udelay (FSI_GPIO_STD_DLY );gpiod_set_value (master->gpio_clk,1 ); +udelay (FSI_GPIO_STD_DLY ); } }
@@ -87,7 +87,6 @@ static int sda_in(struct fsi_master_gpio *master) {int in; -ndelay (FSI_GPIO_STD_DLY ); in =gpiod_get_value (master->gpio_data);return in ?1 :0 ; }
Signature · 1 line
1.8.2.2
Joel Stanley
AppliedRe: [PATCH linux dev-4.10 6/7] drivers/fsi: GPIO stability changes for Cronus/Hostboot
Quoted 11 lines · Christopher Bostic
Improve stability in the FSI protocol by re-ordering the clocking delays. Increase clocking delays to 3 microseconds. Remove delay prior to sampling input - now redundant given new clocking delay order.
New effective delay per clock toggle is now 6 microseconds. Previous clocking summed up to 3 nS but real time measurements of each 1 nS delay actually was approx 1.8 microseconds. Previous total delay was then 1.8 * 3 = 5.4 microseconds.
Signed-off-by Christopher Bostic <[email protected]>
Applied to dev-4.10 with a note about this being a temporary fix until we find the root cause.
Keep us updated with the investigation.
Cheers,
Joel
PATCH 7/7 drivers/fsi: Fix one and two byte bus reads/writes
In reply to Christopher BosticFrom: Eddie James <[email protected]>
Address checker fixed to allow one and two byte reads/writes. Address alignments for each size verified.
--- drivers/fsi/fsi-core.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/fsi/fsi-core.c +7 -4
@@ -699,10 +699,13 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)/* FSI master support */ static int fsi_check_access (uint32_t addr,size_t size) { -if (size !=1 && size !=2 && size !=4 ) -return -EINVAL ; - -if ((addr &0x3 ) != (size &0x3 )) +if (size ==4 ) { +if (addr &0x3 ) +return -EINVAL ; + }else if (size ==2 ) { +if (addr &0x1 ) +return -EINVAL ; + }else if (size !=1 )return -EINVAL ;return 0 ;
Signature · 1 line
1.8.2.2
Joel Stanley
AppliedRe: [PATCH linux dev-4.10 7/7] drivers/fsi: Fix one and two byte bus reads/writes
Quoted 7 lines · Christopher Bostic
From: Eddie James <[email protected]>
Address checker fixed to allow one and two byte reads/writes. Address alignments for each size verified.
Signed-off-by Edward James <[email protected]>Signed-off-by Christopher Bostic <[email protected]>
Applied to dev-4.10.
Cheers,
Joel
Hi Chris,
If (and only if) you're planning to send another revision of the fsi patches upstream, I'd suggest squashing these into their original commits:
Quoted 2 lines
drivers/fsi: Unscan on master unregisterdrivers/fsi: Fix one and two byte bus reads/writes
But if not, I'm happy for these to stay separate.
Other than that, this series should be fine for the openbmc tree.
Cheers,
Jeremy
Quoted 9 lines · Jeremy Kerr
Hi Chris,
If (and only if) you're planning to send another revision of the fsi patches upstream, I'd suggest squashing these into their original commits:
Quoted 2 lines
drivers/fsi: Unscan on master unregisterdrivers/fsi: Fix one and two byte bus reads/writesBut if not, I'm happy for these to stay separate.
Hi Jeremy,
Yep, I have that squashed into the v7 set.
Thanks,
Chris
Quoted 7 lines
Other than that, this series should be fine for the openbmc tree.
Cheers,
Jeremy
Quoted 7 lines · Christopher Bostic
These changes bring the 4.10 kernel FSI device driver up to date with the 4.7 kernel version.
* Add basic and hub interrupt support
* Bug fixes introduced during 4.7 to 4.10 migration
* FSI protocol modification for added operational stability
Quoted 5 lines
Christopher Bostic (5):
drivers/fsi: Add slave interrupt polling
drivers/fsi: Scan for hub sourced IRQ's
drivers/fsi: Set IRQ masks along hub path
drivers/fsi: Add Client IRQ Enable / Disable
As discussed we will hold off on these until the stability issues are resolved.
Quoted 3 lines
drivers/fsi: Unscan on master unregisterdrivers/fsi: GPIO stability changes for Cronus/Hostbootdrivers/fsi: Fix one and two byte bus reads/writes
These three have been applied.
Cheers,
Joel