* [PATCH linux v5 0/7] Introducing the FSI device driver
@ 2016-08-24 19:54 christopher.lee.bostic
2016-08-24 19:54 ` [PATCH linux v5 1/7] drivers/fsi: Initial stubs for " christopher.lee.bostic
` (7 more replies)
0 siblings, 8 replies; 19+ messages in thread
From: christopher.lee.bostic @ 2016-08-24 19:54 UTC (permalink / raw)
To: openbmc
From: Chris Bostic <cbostic@us.ibm.com>
Introduction of the IBM 'Flexible Support Interface' (FSI) bus device
driver. FSI is a high fan out serial bus consisting of a clock and a serial
data line capable of running at speeds up to 166 MHz.
This set provides the core functionality of the FSI device driver. Core
function is defined as:
* FSI client registration and notification of bus state changes
* Device scanning and hotplug reporting to clients
* Interrupt detection and routing
* Bus error detection and cleanup
This patch set does not include extended FSI function such as:
* Hub master support
* Cascaded master support
* Application layer hot plug notification
* Application layer FSI bus status interface
* Host configuration allowing for various hardware / firmware
emulation implementations of the FSI master.
* Soft FSI support. Soft FSI is a device driver method of emulating
FSI master hardware by 'bit banging' standard I/O lines.
Common FSI terminology:
* Master
Controller of the FSI bus. Only the master is allowed to control the
clock line and is the initiator of all transactions on a bus.
* Slave
The receiver or target of a master initiated transaction. The slave
cannot initiate communications on a bus and must respond to any
master requests for data.
* CFAM
Stands for Common Field replaceable unit Access Macro. A CFAM is an
ASIC residing in any device requiring FSI communications. CFAMs
consist of an array of hardware 'engines' used for various purposes.
I2C masters, UARTs, General Purpose IO hardware are common types of
these engines.
* Configuration Space / Table
A table contained at the beginning of each CFAM address space.
This table lists information such as the CFAM's ID, which engine types
and versions it has available, as well as its addressing range.
* Link
The combination of a serial clock and data line constituting one
FSI communications element. For each link there is a master on one
end and a CFAM/slave on the other end.
* Engine
A self contained hardware function found within a CFAM. Examples
include I2C masters, UARTs, GPIOs, etc...
* Client
A device driver requiring access to its hardware via an FSI bus.
For example an I2C client would be a device driver requiring
access to an I2C master engine on a remote CFAM accessible via
an FSI link. Clients register with the FSI bus and will receive
notifications of bus state changes as well as hot plug events related
to engines of interest to them.
* Build Up
The process scanning a bus and creating a data structure representation
of all devices discovered in a tree. A tree in this context is a
series of links and devices connected to those links.
* Hub / Hub master
Provides extension to the existing primary FSI master. Allows for
several chained FSI links in series to a target device thus increasing
potential fan out.
* Cascaded master
A subset of functionality of the hub master. Cascaded masters can
access only a limited address range compared to hub masters. This was
the first generation implementation, essentially, of hub type function.
---
Chris Bostic (6):
drivers/fsi: Add FSI Master Functionality and Initialization
drivers/fsi: Add FSI master target device scanning function
drivers/fsi: Add initial FSI link buildup
drivers/fsi: Add FSI bus type and hook into LDM
drivers/fsi: Add FSI Bus Support for Clients
drivers/fsi: Add CFAM scanning function
Christopher Bostic (1):
drivers/fsi: Initial stubs for FSI device driver.
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/fsi/Kconfig | 7 +
drivers/fsi/Makefile | 5 +
drivers/fsi/build.c | 876 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/fsi/fsi.h | 134 +++++++
drivers/fsi/fsi_private.h | 123 +++++++
drivers/fsi/fsicfam.h | 161 +++++++++
drivers/fsi/fsiinit.c | 92 +++++
drivers/fsi/fsiinit.h | 43 +++
drivers/fsi/fsilink.h | 99 ++++++
drivers/fsi/fsimaster.c | 619 ++++++++++++++++++++++++++++++++
drivers/fsi/fsimaster.h | 682 ++++++++++++++++++++++++++++++++++++
drivers/fsi/fsislave.h | 415 ++++++++++++++++++++++
drivers/fsi/ldm.c | 347 ++++++++++++++++++
drivers/fsi/readwrite.c | 123 +++++++
16 files changed, 3729 insertions(+)
create mode 100644 drivers/fsi/Kconfig
create mode 100644 drivers/fsi/Makefile
create mode 100644 drivers/fsi/build.c
create mode 100644 drivers/fsi/fsi.h
create mode 100644 drivers/fsi/fsi_private.h
create mode 100644 drivers/fsi/fsicfam.h
create mode 100644 drivers/fsi/fsiinit.c
create mode 100644 drivers/fsi/fsiinit.h
create mode 100644 drivers/fsi/fsilink.h
create mode 100644 drivers/fsi/fsimaster.c
create mode 100644 drivers/fsi/fsimaster.h
create mode 100644 drivers/fsi/fsislave.h
create mode 100644 drivers/fsi/ldm.c
create mode 100644 drivers/fsi/readwrite.c
--
1.8.2.2
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH linux v5 1/7] drivers/fsi: Initial stubs for FSI device driver.
2016-08-24 19:54 [PATCH linux v5 0/7] Introducing the FSI device driver christopher.lee.bostic
@ 2016-08-24 19:54 ` christopher.lee.bostic
2016-08-24 19:54 ` [PATCH linux v5 2/7] drivers/fsi: Add FSI Master Functionality and Initialization christopher.lee.bostic
` (6 subsequent siblings)
7 siblings, 0 replies; 19+ messages in thread
From: christopher.lee.bostic @ 2016-08-24 19:54 UTC (permalink / raw)
To: openbmc
From: Christopher Bostic <cbostic@us.ibm.com>
Initial stubs for the Flexible Support Interface (FSI) device driver.
Provides support for FSI serial communications across generic I/O
or dedicated master hardware.
Signed-off-by: Christopher Bostic <cbostic@us.ibm.com>
---
Changes to this patch based on reviewer feedback
V2:
- Removed enums in fsiinit.h and replaced with #defines
- Added proper file copyright and license headers
- Added certificate of origin
- Removed version string
- Replace kobject with struct device in struct fsidd
- Suggestions to implement standard bus_type will be implemented in
later patches
V3:
- Removed white space
- Suggestions to add Kconfig will be added in follow on patches
V4:
- Removed blank line at end of fsiinit.c
V5:
- Move fsiinit.h container_of macros from patch2 in series to patch1
- Replace printk with dev_dbg
- Add Kconfig for FSI function
- Remove structure number field from struct fsicfam
- Rename fsidefines.h to fsi_private.h
- Move all internal only accessible structs and data to fsi_private.h
- Move all globally accessible interfaces and structs to fsi.h
- Remove struct fsidd from fsi_private.h
- Remove EXPORT_SYMBOL(prim) from fsiinit.c
- Add further comments on what fsimaster_build_init() does in fsiinit.c
- Rename goto tag 'out1' to 'err' in fsi_start()
- Remove gotos where its simply to return immediately
- Remove all volatile spcifiers on register data types
- Remove explicit read/write memory barriers in I/O access code
- Rename local_* register accessors to virt_master* to clarify purpose
- Condense/resuse virtual_master* register accessor functions
- Rename FSI_IS_SU/CU_REG to CLEAR/SET_MASK for readability
- Rename fsimaster read_f/writef methods to read_reg/write_reg
- Change u8 to bool where true/false is intended
- Change variable names from p-> to master-> to improve readability
- Initialize all pointers to NULL;
- Rename struct fsimaster registers pointer to base
- fsimaster_reset(): reuse existing variables to cut down on total number
- Replace u32[2] data types with u64 where appropriate
- Remove unnecessary error checking in fsimaster_reset()
- Remove unnecessary return codes and error checking for low level register access
- Remove bitfield types
- Remove redundant fsi_nextbit() utility and repace with __clz()
- Rename FSI_PLUG_CHECK to indicate it is a time quantity.
- Clarify the hot plug state check in plugmgr()
- Change unsigned char/short/long to u8/u16/u32 where appropriate
- Remove fsi_calloc wrapper
- Remove use of kzalloc
---
drivers/Kconfig | 2 ++
drivers/Makefile | 1 +
drivers/fsi/Kconfig | 7 +++++++
drivers/fsi/Makefile | 5 +++++
drivers/fsi/fsiinit.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++
drivers/fsi/fsiinit.h | 41 +++++++++++++++++++++++++++++++++++++++
6 files changed, 109 insertions(+)
create mode 100644 drivers/fsi/Kconfig
create mode 100644 drivers/fsi/Makefile
create mode 100644 drivers/fsi/fsiinit.c
create mode 100644 drivers/fsi/fsiinit.h
diff --git a/drivers/Kconfig b/drivers/Kconfig
index d2ac339..6dd9f61 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -198,4 +198,6 @@ source "drivers/hwtracing/intel_th/Kconfig"
source "drivers/fpga/Kconfig"
+source "drivers/fsi/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 795d0ca..63019ff 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -172,3 +172,4 @@ obj-$(CONFIG_STM) += hwtracing/stm/
obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_NVMEM) += nvmem/
obj-$(CONFIG_FPGA) += fpga/
+obj-$(CONFIG_FSI) += fsi/
diff --git a/drivers/fsi/Kconfig b/drivers/fsi/Kconfig
new file mode 100644
index 0000000..36f29c9
--- /dev/null
+++ b/drivers/fsi/Kconfig
@@ -0,0 +1,7 @@
+menu "FSI Support"
+
+config FSI
+ tristate "FSI bus support"
+ help
+ Enables FSI bus support.
+endmenu
diff --git a/drivers/fsi/Makefile b/drivers/fsi/Makefile
new file mode 100644
index 0000000..f547c08
--- /dev/null
+++ b/drivers/fsi/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the FSI bus specific drivers.
+#
+
+obj-y += fsiinit.o
diff --git a/drivers/fsi/fsiinit.c b/drivers/fsi/fsiinit.c
new file mode 100644
index 0000000..767c0c3
--- /dev/null
+++ b/drivers/fsi/fsiinit.c
@@ -0,0 +1,53 @@
+/*
+ * FSI Master device driver
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * Christopher Bostic <cbostic@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "fsiinit.h"
+
+MODULE_AUTHOR("Christopher Bostic cbostic@us.ibm.com");
+MODULE_DESCRIPTION("FSI master device driver");
+
+#define FSIDD_MAJOR 0 /* FSI device driver major */
+#define FSIDD_TOSTR(x) #x
+#define FSIDD_VERNO 4000
+#define FSIDD_VER(x) FSIDD_TOSTR(x)
+
+struct fsidd fsidd = { /* FSI device driver structure definition */
+ .magic = FSI_DD_MAGIC,
+ .strno = FSI_DD_STRNO,
+};
+
+static int fsi_start(void)
+{
+ int rc = 0;
+
+ dev_dbg(&fsidd.dev, "FSI DD v:%d installation ok\n", FSIDD_VERNO);
+ return rc;
+}
+
+static void fsi_exit(void)
+{
+}
+
+static int __init fsi_init(void)
+{
+ int rc = 0;
+
+ /* Set up the host controller */
+ fsi_start();
+ return rc;
+}
+
+module_init(fsi_init);
+module_exit(fsi_exit);
diff --git a/drivers/fsi/fsiinit.h b/drivers/fsi/fsiinit.h
new file mode 100644
index 0000000..93662533
--- /dev/null
+++ b/drivers/fsi/fsiinit.h
@@ -0,0 +1,41 @@
+/*
+ * FSI Master device driver structure definitions and defines
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * Christopher Bostic <cbostic@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef DRIVERS_FSIINIT_H
+#define DRIVERS_FSIINIT_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/hrtimer.h>
+
+#define FSI_DD_MAGIC 0x64644632 /* ddF2 */
+#define FSI_DD_STRNO 0x1 /* Structure version number */
+
+struct fsidd { /* FSI Main structure */
+ unsigned long magic; /* Magic number */
+ unsigned long strno; /* Structure version number */
+ dev_t major; /* Major number of device */
+ struct workqueue_struct *hotp_wq; /* Hot plug work queue */
+ wait_queue_head_t error_wq; /* Wait queue for port errors */
+ wait_queue_head_t lbus_wq; /* Wait queue for lbus events */
+ wait_queue_head_t irq_wq; /* Wait queue for IRQ loops */
+ wait_queue_head_t link_wq; /* Wait queue for link changes */
+ unsigned long state; /* State driver is in */
+ struct device dev; /* Anchor point in /sys/kernel */
+};
+
+#define to_fsidd_prim(a) container_of(a, struct fsidd, pri_master)
+
+#endif /* DRIVERS_FSIINIT_H */
--
1.8.2.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH linux v5 2/7] drivers/fsi: Add FSI Master Functionality and Initialization
2016-08-24 19:54 [PATCH linux v5 0/7] Introducing the FSI device driver christopher.lee.bostic
2016-08-24 19:54 ` [PATCH linux v5 1/7] drivers/fsi: Initial stubs for " christopher.lee.bostic
@ 2016-08-24 19:54 ` christopher.lee.bostic
2016-09-08 0:09 ` Joel Stanley
2016-08-24 19:54 ` [PATCH linux v5 3/7] drivers/fsi: Add FSI master target device scanning function christopher.lee.bostic
` (5 subsequent siblings)
7 siblings, 1 reply; 19+ messages in thread
From: christopher.lee.bostic @ 2016-08-24 19:54 UTC (permalink / raw)
To: openbmc
From: Chris Bostic <cbostic@us.ibm.com>
Define the FSI master control register set and its accessors.
Initialize the primary FSI master.
Signed-off-by: Chris Bostic <cbostic@us.ibm.com>
---
drivers/fsi/Makefile | 2 +-
drivers/fsi/fsi.h | 32 +++
drivers/fsi/fsi_private.h | 97 +++++++
drivers/fsi/fsicfam.h | 46 ++++
drivers/fsi/fsiinit.c | 22 ++
drivers/fsi/fsiinit.h | 2 +
drivers/fsi/fsimaster.c | 242 +++++++++++++++++
drivers/fsi/fsimaster.h | 655 ++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 1097 insertions(+), 1 deletion(-)
create mode 100644 drivers/fsi/fsi.h
create mode 100644 drivers/fsi/fsi_private.h
create mode 100644 drivers/fsi/fsicfam.h
create mode 100644 drivers/fsi/fsimaster.c
create mode 100644 drivers/fsi/fsimaster.h
diff --git a/drivers/fsi/Makefile b/drivers/fsi/Makefile
index f547c08..9800c15 100644
--- a/drivers/fsi/Makefile
+++ b/drivers/fsi/Makefile
@@ -2,4 +2,4 @@
# Makefile for the FSI bus specific drivers.
#
-obj-y += fsiinit.o
+obj-y += fsiinit.o fsimaster.o
diff --git a/drivers/fsi/fsi.h b/drivers/fsi/fsi.h
new file mode 100644
index 0000000..f146396
--- /dev/null
+++ b/drivers/fsi/fsi.h
@@ -0,0 +1,32 @@
+/*
+ * FSI device driver structure definitions and defines
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * Christopher Bostic <cbostic@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef DRIVERS_FSI_H
+#define DRIVERS_FSI_H
+
+#include <linux/device.h>
+
+struct fsimap {
+ u8 link; /* Master link # */
+ u8 cfam; /* CFAM # on link */
+ u32 offset; /* Address offset into CFAM */
+ u32 va; /* Virtual address */
+};
+
+struct fsidevice {
+ u32 irq_start; /* IRQ Number */
+ struct fsidevice *parent; /* Parent of this device */
+ struct device dev; /* LDM entry for bus */
+ struct fsimap map; /* Address & location info */
+};
+
+#endif /* DRIVERS_FSI_H */
diff --git a/drivers/fsi/fsi_private.h b/drivers/fsi/fsi_private.h
new file mode 100644
index 0000000..be327ef
--- /dev/null
+++ b/drivers/fsi/fsi_private.h
@@ -0,0 +1,97 @@
+/*
+ * FSI device driver structure definitions and defines
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * Christopher Bostic <cbostic@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef DRIVERS_FSI_PRIVATE_H
+#define DRIVERS_FSI_PRIVATE_H
+
+#include "fsi.h"
+
+#define FSIDD_NAME "fsi" /* FSI device driver name */
+
+/*
+ * Universal FSI constants - Applicable for any FSI device
+ */
+#define FSI_MAX_LINKS 64 /* FSI Master # of links */
+#define FSI_MAX_CASCADE 4 /* # of CFAMS in cascade */
+#define FSI_MAX_MASTERS 1 /* # of masters in system */
+#define FSI_LINK_ENG_MASK 0xE0007FFF /* Used for minor num calcs */
+#define FSI_MAX_DEPTH 3 /* Max # of links in path */
+#define FSI_LINK_SHIFT 23 /* Bits to shift */
+#define FSI_LINK_SIZE (1 << FSI_LINK_SHIFT) /* 8 MB */
+#define FSI_CFAM_SHIFT 21 /* Bits to shift */
+#define FSI_CFAM_SIZE (1 << FSI_CFAM_SHIFT) /* 2 MB */
+#define FSI_ENGINE_SHIFT 10 /* Bits to shift */
+#define FSI_ENGINE_SIZE (1 << FSI_ENGINE_SHIFT) /* 1 KB */
+#define FSI_LINK_MASK 0x1f800000 /* Bits for link */
+#define FSI_CFAM_MASK 0x00600000 /* Bits for cfam */
+#define FSI_ENGINE_MASK 0x000ffc00 /* Bits for engine */
+#define FSI_PEEK_OFFSET FSI_ENGINE_SIZE
+#define FSI_SLAVE0_OFFSET (2 * FSI_ENGINE_SIZE)
+#define FSI_SLV_NO_ERROR 100 /* Slave has no error data */
+#define FSI_BREAK 0xc0de0000 /* BREAK command */
+#define FSI_TERM 0xecc00000 /* TERM command */
+#define FSI_BREAK_TIME 180 /* # Seconds to allow BREAKs */
+#define FSI_BREAK_CNT 3 /* limit for BREAK attempts */
+#define FSI_PRIM 0 /* Generic Primary FSI master */
+#define FSI_MBIT_MASK 0x3 /* FSI master bits in pa */
+#define FSI_ENG_MASK 0x00007FFF /* The engine mask in MATRB */
+/* FSI Events */
+#define FSI_EVT_PLUG 6 /* Device plugged */
+#define FSI_LINK_BUILD 10 /* In build up phase */
+#define FSI_LINK_PROBE 11 /* In probing phase */
+
+/*
+ * Return the link number where this device is attached
+ */
+static inline int fsi_my_link(struct fsidevice *fdev)
+{
+ return fdev->map.link;
+}
+
+/*
+ * Return CFAM number on link where this device is attached
+ */
+static inline int fsi_my_cfam(struct fsidevice *fdev)
+{
+ return fdev->map.cfam;
+}
+
+/*
+ * Determine the link address to send the break command to
+ * This is master dependent
+ */
+static inline int fsi_mtype_2break_id(u8 mtype)
+{
+ return FSI_MAX_CASCADE - 1;
+}
+
+/*
+ * Build a mask where bit index 'x' is set (numbering from left to right.
+ * Bit 0 is MSB and bit 31 is LSM.
+ */
+static inline unsigned long mask32(int x)
+{
+ return 1 << (BITS_PER_LONG - x - 1);
+}
+
+/*
+ * Various function prototypes
+ */
+int slv_install(void);
+void slv_uninstall(void);
+
+void fsi_exit_fileio(dev_t);
+
+int fsibus_init(void);
+void fsibus_exit(void);
+
+#endif /* DRIVERS_FSI_PRIVATE_H */
diff --git a/drivers/fsi/fsicfam.h b/drivers/fsi/fsicfam.h
new file mode 100644
index 0000000..dde7036
--- /dev/null
+++ b/drivers/fsi/fsicfam.h
@@ -0,0 +1,46 @@
+/*
+ * FSI CFAM structure definitions and defines
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * Christopher Bostic <cbostic@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef DRIVERS_FSICFAM_H
+#define DRIVERS_FSICFAM_H
+
+#include "fsi.h"
+#include "fsi_private.h"
+
+#define FSI_MAX_ENGINES 32 /* Max # of engines per CFAM */
+
+struct fsicfam { /* CFAM internal structure */
+ struct fsidevice *engines[FSI_MAX_ENGINES]; /* CFAM engine data */
+ u32 cfgtab[FSI_MAX_ENGINES]; /* Configuration word */
+ u16 chipid; /* CFAM chip type (IOU, CFAM-S, etc) */
+ u8 id; /* CFAM Id */
+ bool has_submaster; /* CFAM with cascaded or hub masters */
+ bool has_mux; /* CFAM with multiplexer */
+ u8 ec_maj; /* Major EC Level */
+ u8 ec_min; /* Minor EC Level or version number */
+ u16 pages; /* # Mapped pages */
+ u8 no_eng; /* Number of engines[] */
+ struct fsidevice fsidev; /* LDM entry */
+ struct fsidevice hpdone; /* Dummy engine to signal completion */
+ unsigned long eng_build; /* True during engine activate */
+ struct fsimaster *master; /* pointer to parent master */
+};
+
+#define to_fsicfam(x) container_of((x), struct fsicfam, fsidev)
+
+/*
+ * CFAM specific function prototypes.
+ */
+int fsi_cfamirq_request(int, struct fsicfam *);
+void fsi_cfamirq_free(struct fsicfam *);
+
+#endif /* DRIVERS_FSICFAM_H */
diff --git a/drivers/fsi/fsiinit.c b/drivers/fsi/fsiinit.c
index 767c0c3..c589294 100644
--- a/drivers/fsi/fsiinit.c
+++ b/drivers/fsi/fsiinit.c
@@ -13,7 +13,9 @@
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/kdev_t.h>
#include "fsiinit.h"
+#include "fsimaster.h"
MODULE_AUTHOR("Christopher Bostic cbostic@us.ibm.com");
MODULE_DESCRIPTION("FSI master device driver");
@@ -26,6 +28,7 @@ MODULE_DESCRIPTION("FSI master device driver");
struct fsidd fsidd = { /* FSI device driver structure definition */
.magic = FSI_DD_MAGIC,
.strno = FSI_DD_STRNO,
+ .major = MKDEV(FSIDD_MAJOR, 0),
};
static int fsi_start(void)
@@ -33,6 +36,25 @@ static int fsi_start(void)
int rc = 0;
dev_dbg(&fsidd.dev, "FSI DD v:%d installation ok\n", FSIDD_VERNO);
+
+ init_waitqueue_head(&fsidd.error_wq);
+ init_waitqueue_head(&fsidd.lbus_wq);
+ init_waitqueue_head(&fsidd.irq_wq);
+ init_waitqueue_head(&fsidd.link_wq);
+
+ /*
+ * Initialize the the master
+ */
+ if (!fsimaster_build_init(&fsidd.pri_master, FSI_PRIM, 0)) {
+ rc = PTR_ERR(0);
+ goto err;
+ }
+ fsimaster_start(&fsidd.pri_master);
+ dev_dbg(&fsidd.dev, "FSI DD v%d installation ok\n", FSIDD_VERNO);
+ return rc;
+
+err:
+ dev_dbg(&fsidd.dev, "FSI DD v:%d installation failed\n", FSIDD_VERNO);
return rc;
}
diff --git a/drivers/fsi/fsiinit.h b/drivers/fsi/fsiinit.h
index 93662533..10ddfc0 100644
--- a/drivers/fsi/fsiinit.h
+++ b/drivers/fsi/fsiinit.h
@@ -19,6 +19,7 @@
#include <linux/device.h>
#include <linux/workqueue.h>
#include <linux/hrtimer.h>
+#include "fsimaster.h"
#define FSI_DD_MAGIC 0x64644632 /* ddF2 */
#define FSI_DD_STRNO 0x1 /* Structure version number */
@@ -34,6 +35,7 @@ struct fsidd { /* FSI Main structure */
wait_queue_head_t link_wq; /* Wait queue for link changes */
unsigned long state; /* State driver is in */
struct device dev; /* Anchor point in /sys/kernel */
+ struct fsimaster pri_master; /* Primary FSI master */
};
#define to_fsidd_prim(a) container_of(a, struct fsidd, pri_master)
diff --git a/drivers/fsi/fsimaster.c b/drivers/fsi/fsimaster.c
new file mode 100644
index 0000000..b5d16db
--- /dev/null
+++ b/drivers/fsi/fsimaster.c
@@ -0,0 +1,242 @@
+/*
+ * FSI Master Control
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * Christopher Bostic <cbostic@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/ktime.h>
+#include <linux/io.h>
+#include "fsi.h"
+#include "fsiinit.h"
+#include "fsimaster.h"
+#include "fsicfam.h"
+
+static int hpinfo_alloc(struct fsimaster *master)
+{
+ return 0;
+}
+
+static inline unsigned int fsimid(struct fsimaster *master)
+{
+ return master->myid;
+}
+
+static void primaster_exit(struct fsimaster *master)
+{
+ if (master->dcr_alloc) {
+ master->base = NULL;
+ master->dcr_alloc = false;
+ }
+}
+
+/*
+ * Read/write functions to access primary FSI master registers
+ * Note that this master is virtual as we don't yet have any
+ * real FSI masters implemented in hardware
+ */
+static u32 virt_master_readreg(struct fsi_mreg *mbase, int regnm)
+{
+ u32 *base = (u32 *)mbase;
+
+ return *(base + regnm);
+}
+
+static void virt_master_readreg2(struct fsi_mreg *mbase, int regnm, u64 *dest)
+{
+ u32 *base = (u32 *)mbase;
+
+ memcpy(dest, base + regnm, sizeof(u64));
+}
+
+static void virt_master_readreg4(struct fsi_mreg *mbase, int regnm, u32 *dest)
+{
+ u32 *base = (u32 *)mbase;
+
+ memcpy(dest, base + regnm, 4 * sizeof(u32));
+}
+
+static void writereg_array(struct fsi_mreg *mbase, int regnm,
+ u32 *val, size_t size)
+{
+ int i;
+ u32 r_value, new_value[size];
+ u32 *base = (u32 *)mbase;
+
+ if (regnm == FSI_N_MRESB0) {
+ /* A write to the reset register clears out MESRB */
+ *(base + regnm) = 0;
+ return;
+ }
+
+ for (i = 0, base += regnm; i < size; ++i) {
+ new_value[i] = *(val + i);
+
+ /*
+ * The master control registers have various modes when
+ * written; direct copy or set/clear under mask
+ */
+ if (FSI_CLEAR_UNDER_MASK(regnm)) {
+ r_value = virt_master_readreg(mbase, regnm);
+ new_value[i] = r_value &= ~(*(val + i));
+ } else if (FSI_SET_UNDER_MASK(regnm)) {
+ r_value = virt_master_readreg(mbase, regnm);
+ new_value[i] = r_value |= *(val + i);
+ }
+ /*
+ * If not set or clear under mask type register then simply
+ * copy value
+ */
+ *base++ = new_value[i];
+ }
+}
+
+static void virt_master_writereg(struct fsi_mreg *base, int regnm, u32 val)
+{
+ writereg_array(base, regnm, &val, 1);
+}
+
+static void virt_master_writereg2(struct fsi_mreg *base, int regnm, u64 *val)
+{
+ writereg_array(base, regnm, (u32 *)val, 2);
+}
+
+static void virt_master_writereg8(struct fsi_mreg *base, int regnm, u32 *val)
+{
+ writereg_array(base, regnm, val, 8);
+}
+
+static int primaster_init(struct fsimaster *master)
+{
+ master->read_reg = virt_master_readreg;
+ master->read_reg2 = virt_master_readreg2;
+ master->read_reg4 = virt_master_readreg4;
+ master->write_reg = virt_master_writereg;
+ master->write_reg2 = virt_master_writereg2;
+ master->write_reg8 = virt_master_writereg8;
+ master->maxlinks = PRI_MAX_LINKS;
+ master->have_peek = true;
+ master->irqbase = 0;
+ memset(&master->base, 0, sizeof(struct fsi_mreg));
+ master->dcr_alloc = true;
+ if (hpinfo_alloc(master))
+ primaster_exit(master);
+
+ return master->base ? 0 : 1;
+}
+
+static int fsimaster_init(struct fsimaster *master)
+{
+ int rc = 0;
+
+ memset(&master->quirks, 0, sizeof(struct master_quirks));
+ master->quirks.break_cfam_id = fsi_mtype_2break_id(master->type);
+ master->cfam_size = 0;
+ master->m_get = NULL;
+ master->m_pa2irq = NULL;
+ master->m_exit = NULL;
+
+ rc = primaster_init(master);
+
+ return rc;
+}
+
+struct fsimaster *fsimaster_get_top_master(struct fsimaster *master)
+{
+ struct fsimaster *parent = NULL;
+
+ while (master) {
+ parent = master;
+ master = master->parent;
+ }
+
+ return parent;
+}
+
+static int fsimaster_reset(struct fsimaster *master)
+{
+ u32 reg = 0;
+ u64 reg2 = 0;
+ int rc = 0;
+ struct fsidd *dd = NULL;
+
+ dd = to_fsidd_prim(fsimaster_get_top_master(master));
+
+ reg = master->read_reg(master->base, FSI_N_MVER);
+ if (fsi_mver_extlink(reg) != master->maxlinks) {
+ rc = -EINVAL;
+ goto out;
+ }
+ /* Reset all bridges and ports */
+ reg = FSI_MRESP_RST_ALL_MSTR | FSI_MRESP_RST_ALL_LINK
+ | FSI_MRESP_RST_MCR | FSI_MRESP_RST_PYE;
+ master->write_reg(master->base, FSI_N_MRESP0, reg);
+
+ /* Set up control */
+ reg = (master->type == FSI_PRIM) ? FSI_MECTRL_FPME : FSI_MECTRL_EOAE;
+ master->write_reg(master->base, FSI_N_MECTRL, reg);
+
+ /* Set up mode */
+ reg = fsi_mmode_crs0(1) | fsi_mmode_crs1(1);
+ master->write_reg(master->base, FSI_N_MMODE, reg);
+
+ /* Set up delay characteristics */
+ master->write_reg(master->base, FSI_N_MDLYR, FSI_MDLYR_DFLT);
+
+ /* Enable all links for a short time */
+ reg2 = ~0;
+ master->write_reg2(master->base, FSI_N_MSENP0, ®2);
+
+ mdelay(1);
+ master->write_reg2(master->base, FSI_N_MCENP0, ®2);
+
+ reg2 = FSI_MRESP_RST_ALL_MSTR | FSI_MRESP_RST_ALL_LINK;
+ master->write_reg(master->base, FSI_N_MRESP0, reg2);
+out:
+ return rc;
+}
+
+struct fsimaster *fsimaster_build_init(struct fsimaster *master, int type,
+ struct fsidevice *parent)
+{
+ int rc = 0;
+ struct fsidd *dd = NULL;
+
+ if (!master)
+ goto out;
+ if (!parent)
+ dd = to_fsidd_prim(master);
+ else {
+ struct fsicfam *cfam = to_fsicfam(parent->parent);
+
+ dd = to_fsidd_prim(fsimaster_get_top_master(cfam->master));
+ }
+ master->type = type;
+ master->fsidev = parent;
+ if (fsimaster_init(master)) {
+ master = NULL;
+ goto out;
+ }
+ if (fsimaster_reset(master)) {
+ rc = -EIO;
+ master = NULL;
+ goto out;
+ }
+out:
+ return master ? : ERR_PTR(rc);
+}
+
+/*
+ * Kick off the master so it can start probing for attached CFAMs
+ */
+void fsimaster_start(struct fsimaster *master)
+{
+}
diff --git a/drivers/fsi/fsimaster.h b/drivers/fsi/fsimaster.h
new file mode 100644
index 0000000..4df2caf
--- /dev/null
+++ b/drivers/fsi/fsimaster.h
@@ -0,0 +1,655 @@
+/*
+ * FSI Master device driver structure definitions and defines
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * Christopher Bostic <cbostic@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef DRIVERS_FSIMASTER_H
+#define DRIVERS_FSIMASTER_H
+
+#include "fsi_private.h"
+#include "fsi.h"
+#include "fsicfam.h"
+
+#define FSI_MAX_PING_ATTEMPTS 12
+#define FSI_PLUG_CHECK_TIME 100
+#define FSI_DFLT_IPOLL_CHECK 800
+
+/* FSI master register numbers */
+#define FSI_N_MMODE 0 /* 0x0 R/W: mode register */
+#define FSI_N_MDLYR 1 /* 0x4 R/W: delay register */
+#define FSI_N_MCRSP0 2 /* 0x8 R/W: clock rate selector register 0 */
+#define FSI_N_MCRSP32 3 /* 0xC R/W: clock rate selector register 1 */
+#define FSI_N_MENP 4 /* 0x10 R/W: enable clock register 0 */
+#define FSI_N_MENP32 5 /* 0x14 R/W: enable clock register 1 */
+#define FSI_N_MLEVP 6 /* 0x18 R: static level register 0 */
+#define FSI_N_MLEVP32 7 /* 0x1C R: static level register 1 */
+#define FSI_N_MSENP0 6 /* 0x18 S: set enable clock register 0 */
+#define FSI_N_MREFP0 8 /* 0x20 R: link reference register 0 */
+#define FSI_N_MCENP0 8 /* 0x20 W: clear enable port register 0 */
+#define FSI_N_MHPMP0 10 /* 0x28 R: hot plug reference register 0 */
+#define FSI_N_MCHPMP0 10 /* 0x28 W: clear hot plug reference reg 0 */
+#define FSI_N_MSIEP0 12 /* 0x30 R/W: Ipoll register 0 */
+#define FSI_N_MSIEP32 16 /* 0x40 R/W: Ipoll register 4 */
+#define FSI_N_MAESP0 20 /* 0x50 R: any error port register 0 */
+#define FSI_N_MAESP32 24 /* 0x60 R: any error port register 4 */
+#define FSI_N_MSSIEP0 20 /* 0x50 W: set Ipoll register 0 */
+#define FSI_N_MAEB 28 /* 0x70 R: any error bridge */
+#define FSI_N_MVER 29 /* 0x74 R: version register */
+#define FSI_N_MBSYP0 30 /* 0x78 R: port busy register 0 */
+#define FSI_N_MCSIEP0 28 /* 0x70 W: clear Ipoll register 0 */
+#define FSI_N_MDRSB1 36 /* 0x90 R/W: DMA select register master 1 */
+#define FSI_N_MSTAP0 52 /* 0xd0 R: port status reg 0-63 (0xd0-0x1cc) */
+#define FSI_N_MRESP0 52 /* 0xd0 W: port reset regr 0-63 (0xd0-0x1cc) */
+#define FSI_N_MESRB0 116 /* 0x1d0 R: error syndrome register 0-16 */
+#define FSI_N_MRESB0 116 /* 0x1d0 W: reset reg master 0-16 (x1d0-x210) */
+#define FSI_N_MSCSB0 117 /* 0x1d4 R: master sub cmd stack register 0 */
+#define FSI_N_MATRB0 118 /* 0x1d8 R: master address trace register 0 */
+#define FSI_N_MDTRB0 119 /* 0x1dc R: master data trace register 0 */
+#define FSI_N_MECTRL 184 /* 0x2e0 R/W: error control register master 0 */
+#define FSI_N_MAESP_SZ 8 /* # of error port register 0-7 */
+
+#define FSI_MSIEP_REG_COUNT 8
+#define PRI_MAX_LINKS FSI_MAX_LINKS
+
+/*
+ * Model clear under mask (CU) and set under mask (SU) Read only (RO)
+ * and Write only (WO) behavior for virtual Primary FSI Master
+ */
+#define FSI_CLEAR_UNDER_MASK(x) ((x) == FSI_N_MCENP0 \
+ || ((x) == FSI_N_MCENP0 + 1) \
+ || (x) == FSI_N_MCHPMP0 \
+ || ((x) == FSI_N_MCHPMP0 + 1) \
+ || (x) == FSI_N_MCSIEP0 \
+ || ((x) == FSI_N_MCSIEP0 + 1) \
+ || ((x) == FSI_N_MCSIEP0 + 2) \
+ || ((x) == FSI_N_MCSIEP0 + 3) \
+ || ((x) == FSI_N_MCSIEP0 + 4) \
+ || ((x) == FSI_N_MCSIEP0 + 5) \
+ || ((x) == FSI_N_MCSIEP0 + 6) \
+ || ((x) == FSI_N_MCSIEP0 + 7))
+#define FSI_SET_UNDER_MASK(x) ((x) == FSI_N_MSENP0 \
+ || ((x) == FSI_N_MSENP0 + 1) \
+ || (x) == FSI_N_MSSIEP0 \
+ || ((x) == FSI_N_MSSIEP0 + 1) \
+ || ((x) == FSI_N_MSSIEP0 + 2) \
+ || ((x) == FSI_N_MSSIEP0 + 3) \
+ || ((x) == FSI_N_MSSIEP0 + 4) \
+ || ((x) == FSI_N_MSSIEP0 + 5) \
+ || ((x) == FSI_N_MSSIEP0 + 6) \
+ || ((x) == FSI_N_MSSIEP0 + 7))
+
+/*
+ * Return FSI master error information register number for master x
+ */
+static inline int fsi_mesrb_nr(int master)
+{
+ return (FSI_N_MESRB0 + master * 4);
+}
+
+/*
+ * Return FSI master reset register number for master x
+ */
+static inline int fsi_mresb_nr(int master)
+{
+ return FSI_N_MRESB0 + master;
+}
+
+/*
+ * Return FSI master port status register number for link x
+ */
+static inline int fsi_mstap_nr(int link)
+{
+ return FSI_N_MSTAP0 + link;
+}
+
+/*
+ * Return FSI master port error reset register number for link x
+ */
+static inline int fsi_mresp_nr(int link)
+{
+ return FSI_N_MRESP0 + link;
+}
+
+/*
+ * Return FSI master ipoll register number for index x
+ */
+static inline int fsi_msiep_nr(int idx)
+{
+ return FSI_N_MSIEP0 + idx;
+}
+
+/*
+ * Return FSI master error information register number for master x
+ */
+static inline int fsi_maesp_nr(int portreg)
+{
+ return FSI_N_MAESP0 + portreg;
+}
+
+struct fsi_mei { /* FSI master error information */
+ u32 mesrb; /* Master error status register */
+ u32 mscsb; /* Subcommand stack register */
+ u32 matrb; /* Address trace register */
+ u32 mdtrb; /* Data trace register */
+};
+
+/* FSI Master register set */
+struct fsi_mreg {
+ u32 mmode; /* 0x0 */
+ u32 mdlyr; /* 0x4 */
+ u64 mcrsp; /* 0x8 - 0xc */
+ u64 menp; /* 0x10 - 0x14 */
+ u64 mlevp; /* 0x18 - 0x1c */
+ u64 mrefp; /* 0x20 - 0x24 */
+ u64 mhpmp; /* 0x28 - 0x2c */
+ u32 msiep0[8]; /* 0x30 - 0x4c */
+ u32 maesp0[8]; /* 0x50 - 0x6c */
+ u32 maeb0[8]; /* 0x70 - 0x8c */
+ u32 mdrsb0[16]; /* 0x90 - 0xcc */
+ u32 mstap0[FSI_MAX_LINKS]; /* 0xd0 - 0x1cc */
+ struct fsi_mei mresb0[FSI_MAX_MASTERS]; /* 0x1d0 - 0x2dc */
+ u32 mectrl; /* 0x2e0 */
+ u32 mver; /* Master version ID, read only */
+};
+
+#define PORT_BUSY_CHECKS_MAX 10
+
+/* FSI Port controller reset types */
+#define FSI_PORT_GENERAL_RESET 0x80000000
+#define FSI_PORT_ERROR_RESET 0x40000000
+#define FSI_PORT_GENERAL_RESET_BRIDGE 0x20000000
+#define FSI_PORT_GENERAL_RESET_PORT 0x10000000
+#define FSI_PORT_RESET_CNTRL_REGS 0x08000000
+#define FSI_PORT_RESET_PA_ERROR 0x04000000
+
+/* FSI Port controller error masks */
+#define FSI_PORT_EMASK_ID0 0xf0000000
+#define FSI_PORT_EMASK_ID1 0x0f000000
+#define FSI_PORT_EMASK_ID2 0x00f00000
+#define FSI_PORT_EMASK_ID3 0x000f0000
+#define FSI_PORT_CRCMASK 0x0000f000
+#define FSI_PORT_HOTPLUG 0x00000800
+
+/*
+ * FSI Slave interrupt enable/disable bit setting. Return the bit setting
+ * given a link and cfam number. The result of this function can be input
+ * to the mssiepX and mcsiepX registers or or'ed in to msiepX.
+ * The formula is 1 << 31 - (link % 8 * 4 + cfam).
+ *
+ * Not in FSI Spec (0..30):
+ * MSIEPx register bit 0 is port 0 and cfam 0.
+ * MSIEPx register bit 1 is port 0 and cfam 1.
+ * MSIEPx register bit 31 is port 7 and cfam 3.
+ */
+static inline u32 fsi_mk_msiep(int link, int cfam)
+{
+ return mask32((link % (BITS_PER_LONG / FSI_MAX_CASCADE))
+ * FSI_MAX_CASCADE + cfam);
+}
+
+/*
+ * Return mask for all CFAMs id x to 3 (end of cascade) on a specific link.
+ */
+static inline u32 fsi_mk_msiep_plus(int link, int cfam)
+{
+ u32 bits = (0xf >> cfam) << 28;
+
+ return bits >> (link % (BITS_PER_LONG / FSI_MAX_CASCADE)
+ * FSI_MAX_CASCADE);
+}
+
+/*
+ * Return mask for all CFAMs on a specific link.
+ */
+static inline u32 fsi_mk_msiep_all(int link)
+{
+ return 0xf0000000 >> (link % (BITS_PER_LONG / FSI_MAX_CASCADE)
+ * FSI_MAX_CASCADE);
+}
+
+/*
+ * Return index for msiepX register
+ */
+static inline int fsi_mk_msiep_idx(int link)
+{
+ return link / (BITS_PER_LONG / FSI_MAX_CASCADE);
+}
+
+/*
+ * FSI Master Mode register setting
+ */
+#define FSI_MMODE_EIP 0x80000000 /* Enable interrupt polling */
+#define FSI_MMODE_ECRC 0x40000000 /* Enable hw error recovery */
+#define FSI_MMODE_ERAC 0x20000000 /* Enable relative addr cmds */
+#define FSI_MMODE_EPC 0x10000000 /* Enable parity checking */
+#define FSI_MMODE_CRS0SHFT 18 /* Clock select 0 mask shift */
+#define FSI_MMODE_CRS0MASK 0x3ff /* Clock select 0 mask */
+#define FSI_MMODE_CRS1SHFT 8 /* Clock select 1 mask shift */
+#define FSI_MMODE_CRS1MASK 0x3ff /* Clock select 1 mask */
+#define FSI_MMODE_P63 0x80 /* Route link 63 IOU slave C */
+#define FSI_MMODE_DIV4 0x00000040 /* Divide by 4 (legacy mode) */
+
+/*
+ * Rolf Fritz Nov 20, 2013:
+ * MSB=1, LSB=0 is 0.8 ms
+ * MSB=0, LSB=1 is 0.9 ms
+ */
+#define FSI_MMODE_P8_TO_MSB 0x00000020 /* Timeout val most sig bit */
+#define FSI_MMODE_P8_TO_LSB 0x00000010 /* Timeout val least sig bit */
+
+static inline u32 fsi_mmode_crs0(u32 x)
+{
+ return (x & FSI_MMODE_CRS0MASK) << FSI_MMODE_CRS0SHFT;
+}
+
+static inline u32 fsi_mmode_crs1(u32 x)
+{
+ return (x & FSI_MMODE_CRS1MASK) << FSI_MMODE_CRS1SHFT;
+}
+
+static inline u32 fsi_mmode_extcrs0(u32 x)
+{
+ return (x >> FSI_MMODE_CRS0SHFT) & FSI_MMODE_CRS0MASK;
+}
+
+static inline u32 fsi_mmode_extcrs1(u32 x)
+{
+ return (x >> FSI_MMODE_CRS1SHFT) & FSI_MMODE_CRS1MASK;
+}
+
+/*
+ * FSI master delay register
+ */
+#define FSI_MDLYR_ECHO0_SHFT 28 /* Selection 0 echo delay cycles */
+#define FSI_MDLYR_ECHO0_MASK 0xf /* Selection 0 echo delay cycles */
+#define FSI_MDLYR_SEND0_SHFT 24 /* Selection 0 send delay cycles */
+#define FSI_MDLYR_SEND0_MASK 0xf /* Selection 0 send delay cycles */
+#define FSI_MDLYR_ECHO1_SHFT 20 /* Selection 1 echo delay cycles */
+#define FSI_MDLYR_ECHO1_MASK 0xf /* Selection 1 echo delay cycles */
+#define FSI_MDLYR_SEND1_SHFT 16 /* Selection 1 send delay cycles */
+#define FSI_MDLYR_SEND1_MASK 0xf /* Selection 1 send delay cycles */
+#define FSI_MDLYR_DFLT 0xffff0000 /* Default setting */
+
+static inline int fsi_mdlyr_echo0(int x)
+{
+ return (x & FSI_MDLYR_ECHO0_MASK) << FSI_MDLYR_ECHO0_SHFT;
+}
+
+static inline int fsi_mdlyr_echo1(int x)
+{
+ return (x & FSI_MDLYR_ECHO1_MASK) << FSI_MDLYR_ECHO1_SHFT;
+}
+
+static inline int fsi_mdlyr_send0(int x)
+{
+ return (x & FSI_MDLYR_SEND0_MASK) << FSI_MDLYR_SEND0_SHFT;
+}
+
+static inline int fsi_mdlyr_send1(int x)
+{
+ return (x & FSI_MDLYR_SEND1_MASK) << FSI_MDLYR_SEND1_SHFT;
+}
+
+static inline int fsi_mdlyr_extecho0(u32 x)
+{
+ return (x >> FSI_MDLYR_ECHO0_SHFT) & FSI_MDLYR_ECHO0_MASK;
+}
+
+static inline int fsi_mdlyr_extecho1(u32 x)
+{
+ return (x >> FSI_MDLYR_ECHO1_SHFT) & FSI_MDLYR_ECHO1_MASK;
+}
+
+static inline int fsi_mdlyr_extsend0(u32 x)
+{
+ return (x >> FSI_MDLYR_SEND0_SHFT) & FSI_MDLYR_SEND0_MASK;
+}
+
+static inline int fsi_mdlyr_extsend1(u32 x)
+{
+ return (x >> FSI_MDLYR_SEND1_SHFT) & FSI_MDLYR_SEND1_MASK;
+}
+
+/*
+ * MAEB Register
+ */
+#define FSI_MASTER0 0x80000000 /* Primary Master */
+
+/*
+ * MVER Register
+ */
+#define FSI_MVER_VER_MASK 0xff /* FSI master version mask */
+#define FSI_MVER_VER_SHFT 24 /* FSI master version shift */
+#define FSI_MVER_BRG_MASK 0xff /* FSI master FSI bridges mask */
+#define FSI_MVER_BRG_SHFT 16 /* FSI master FSI bridges shift */
+#define FSI_MVER_LINK_MASK 0xff /* FSI master links mask */
+#define FSI_MVER_LINK_SHFT 8 /* FSI master links shift */
+
+static inline int fsi_mver_extversion(u32 x)
+{
+ return (x >> FSI_MVER_VER_SHFT) & FSI_MVER_VER_MASK;
+}
+
+static inline int fsi_mver_extport(u32 x)
+{
+ return (x >> FSI_MVER_BRG_SHFT) & FSI_MVER_BRG_MASK;
+}
+
+static inline int fsi_mver_extlink(u32 x)
+{
+ return (x >> FSI_MVER_LINK_SHFT) & FSI_MVER_LINK_MASK;
+}
+
+/*
+ * Master reset types
+ */
+#define FSI_MRESB_RST_GEN 0x80000000 /* General reset */
+#define FSI_MRESB_RST_ERR 0x40000000 /* Error Reset, don't use */
+#define FSI_MRESB_DELAY 0x01000000 /* do delay settings */
+
+/*
+ * Port reset types
+ */
+#define FSI_MRESP_RST_GEN 0x80000000 /* General reset */
+#define FSI_MRESP_RST_ERR 0x40000000 /* Error Reset, don't use */
+#define FSI_MRESP_RST_ALL_MSTR 0x20000000 /* Reset all FSI masters */
+#define FSI_MRESP_RST_ALL_LINK 0x10000000 /* Reset all FSI port contr. */
+#define FSI_MRESP_RST_MCR 0x08000000 /* Reset FSI master reg. */
+#define FSI_MRESP_RST_PYE 0x04000000 /* Reset FSI parity error */
+#define FSI_MRESP_RST_ALL 0xfc000000 /* Reset any error */
+
+/*
+ * MESRB Register
+ */
+#define FSI_MESRB_EC_MASK 0xf /* Error code mask */
+#define FSI_MESRB_EC_SHFT 28 /* Error code shift */
+#define FSI_MESRB_PARITY_MASK 0xff /* Parity bits shift */
+#define FSI_MESRB_PARITY_SHFT 16 /* Parity bits Mask */
+#define FSI_MESRB_CRC_MASK 0xf /* CRC mask */
+#define FSI_MESRB_CRC_SHFT 24 /* CRC shift */
+#define FSI_MESRB_RESERVED_MASK 0xffff /* Reserved mask */
+#define FSI_MESRB_OPB_PYE 0x0001000 /* OPB Parity Error */
+#define FSI_MESRB_NE 0 /* No error */
+#define FSI_MESRB_OPBE 1 /* OPB Error */
+#define FSI_MESRB_IOPBS 2 /* Illegal OPB state */
+#define FSI_MESRB_PAE 3 /* Port access error */
+#define FSI_MESRB_IDM 4 /* ID mismatch */
+#define FSI_MESRB_DMASE 5 /* DMA select error */
+#define FSI_MESRB_PTOE 6 /* Port time out error */
+#define FSI_MESRB_MTOE 7 /* Master time out error */
+#define FSI_MESRB_MCRCE 8 /* Master CRC error */
+#define FSI_MESRB_ERRA 9 /* Any error response */
+#define FSI_MESRB_ERRC 10 /* CRC error response */
+#define FSI_MESRB_PE 11 /* Protocol error */
+#define FSI_MESRB_PYE 12 /* Parity err/Reg access err */
+#define FSI_MESRB_LAST (FSI_MESRB_PYE + 1) /* Last entry */
+
+/* Extract error conditon */
+static inline u32 fsi_mesrb_extec(u32 x)
+{
+ return (x >> FSI_MESRB_EC_SHFT) & FSI_MESRB_EC_MASK;
+}
+
+/* Extract CRC error counter */
+static inline u32 fsi_mesrb_extcrc(u32 x)
+{
+ return (x >> FSI_MESRB_CRC_SHFT) & FSI_MESRB_CRC_MASK;
+}
+
+/* Extract parity error bits */
+static inline u32 fsi_mesrb_extparity(u32 x)
+{
+ return (x >> FSI_MESRB_PARITY_SHFT) & FSI_MESRB_PARITY_MASK;
+}
+
+/*
+ * MATRB Register
+ */
+#define FSI_MATRB_LPA_MASK 0x3f /* Last port/link addr mask */
+#define FSI_MATRB_LPA_SHFT 26 /* Last port/link addr shift */
+#define FSI_MATRB_LSID_MASK 3 /* Last slave id mask */
+#define FSI_MATRB_LSID_SHFT 24 /* Last slave id shift */
+#define FSI_MATRB_P8_ADDR_HI_MASK 3 /* Upper 2 bits of addr */
+#define FSI_MATRB_P8_ADDR_HI_SHFT 24 /* Upper 2 bits of addr shift */
+#define FSI_MATRB_SLPA_MASK 3 /* Last sublink address mask */
+#define FSI_MATRB_SLPA_SHFT 19 /* Last sublink address shift */
+#define FSI_MATRB_SLSID_SHFT 17 /* Last subslave id shift */
+#define FSI_MATRB_READ_MASK 0x00400000 /* Last cmd was Read */
+#define FSI_MATRB_ADDR_MASK 0x1fffff /* Last address mask */
+#define FSI_MATRB_ADDR_SHFT 1 /* Last address shift */
+#define FSI_MATRB_P8_ADDR_SHFT 3 /* Non contiguous upper bits */
+#define FSI_MATRB_DATAS_MASK 1 /* Last addr data size mask */
+#define FSI_MATRB_CM_MASK 0x00200000 /* Cascaded FSI mask */
+
+/* Extract link number */
+static inline int fsi_matrb_lpa(u32 x)
+{
+ return (x >> FSI_MATRB_LPA_SHFT) & FSI_MATRB_LPA_MASK;
+}
+
+/* Extract data size of last command */
+static inline int fsi_matrb_datasize(u32 x)
+{
+ return x & FSI_MATRB_DATAS_MASK;
+}
+
+/* Extract read/write command */
+static inline int fsi_matrb_isread(u32 x)
+{
+ return x & FSI_MATRB_READ_MASK;
+}
+
+/*
+ * MSTAP Register
+ */
+#define FSI_MSTAP_MASK 0xf /* Error mask ID 0..3 */
+#define FSI_MSTAP_ID0_SHFT 28 /* CFAM 0 error shift */
+#define FSI_MSTAP_ID1_SHFT 24 /* CFAM 1 error shift */
+#define FSI_MSTAP_ID2_SHFT 20 /* CFAM 2 error shift */
+#define FSI_MSTAP_ID3_SHFT 16 /* CFAM 3 error shift */
+#define FSI_MSTAP_CRC_MASK 0xf /* CRC mask */
+#define FSI_MSTAP_CRC_SHFT 12 /* CRC error counter */
+#define FSI_MSTAP_HOTPLUG 0x800 /* Hotplug indicator */
+#define FSI_MSTAP_NE 0 /* No error */
+#define FSI_MSTAP_ERRA 1 /* Any error response */
+#define FSI_MSTAP_ERRC 2 /* CRC error response */
+#define FSI_MSTAP_UCRCE 3 /* Port detected CRC error */
+#define FSI_MSTAP_IDM 4 /* ID mismatch */
+#define FSI_MSTAP_PTOE 5 /* Port time out error */
+#define FSI_MSTAP_IIPSE 6 /* Invalid I-Poll state error */
+#define FSI_MSTAP_LAST (FSI_MSTAP_IIPSE + 1) /* Last entry */
+
+/* Extract error reason for slave id 0..3 */
+static inline u32 fsi_mstap_extec(u32 x, int id)
+{
+ return (x >> (FSI_MSTAP_ID0_SHFT - id * FSI_MAX_CASCADE))
+ & FSI_MSTAP_MASK;
+}
+
+/* Extract crc counter */
+static inline u32 fsi_mstap_extcrc(u32 x)
+{
+ return (x >> FSI_MSTAP_CRC_SHFT) & FSI_MSTAP_CRC_MASK;
+}
+
+/*
+ * MECTRL Register
+ */
+#define FSI_MECTRL_TP_SHFT 24 /* parity error generation */
+#define FSI_MECTRL_TP_MASK 0xff /* Mask for parity errors */
+#define FSI_MECTRL_IPE_SHFT 16 /* Shift inhibit parity error */
+#define FSI_MECTRL_IPE_MASK 0xff /* Mask inhibit parity err */
+#define FSI_MECTRL_EOAE 0x8000 /* Enable machine check */
+#define FSI_MECTRL_P8_AUTO_TERM 0x4000 /* Auto terminate */
+#define FSI_MECTRL_FPME 0x2000 /* Freeze port on master err */
+#define FSI_MECTRL_P8_SID_TO_3 0x0800 /* Force slave ID to 3 */
+
+/* Force parity error events */
+static inline u32 fsi_mectrl_fpe(int id)
+{
+ return (id & FSI_MECTRL_TP_MASK) << FSI_MECTRL_TP_SHFT;
+}
+
+/* Inhibit parity errors */
+static inline u32 fsi_mectrl_ipe(int id)
+{
+ return (id & FSI_MECTRL_IPE_MASK) << FSI_MECTRL_IPE_SHFT;
+}
+
+/*
+ * Returns the virtual address of the FSI slave configuration word 0 given
+ * the FSI slave engine 0 virtual address.
+ *
+ * NOTE: Assumes address space is mapped without holes. This is ok as both
+ * engines 2 2KB apart and Linux uses 4KB pages.
+ */
+static inline void *get_termva(void *slv_va)
+{
+ return (void *)((unsigned long)slv_va & ~0xfff);
+}
+
+static inline unsigned long get_termpa(unsigned long slv_pa)
+{
+ return slv_pa & ~0xfff;
+}
+
+struct master_quirks {
+ int break_cfam_id;
+ void (*port_reset)(struct fsidevice *, struct fsidevice *, int);
+ int (*send_break)(struct fsimaster *, void *, int, struct fsicfam *);
+ int (*break_set_cfam_id)(void *, int);
+};
+
+struct fsimaster { /* FSI master definition */
+ struct fsimaster *parent; /* Parent of this master */
+ char name[8]; /* Name for /sysfs */
+ unsigned long peek40c; /* Peek engine identifications */
+ u32 membase; /* Base MMIO address */
+ int irqbase; /* Base IRQ number */
+ struct fsidevice *fsidev; /* Pointer to fsi cascaded engine */
+ struct fsidevice *fsislv; /* Pointer to fsi slave engine */
+ struct fsi_mreg *base; /* Ptr to register space */
+ spinlock_t lock; /* Lock */
+ bool dcr_alloc; /* True if ioremap for dcr reg space */
+ bool have_peek; /* True if peek engine read needed */
+ unsigned char myid; /* FSI master identifier for traces */
+ unsigned char type; /* Type FSI master */
+ unsigned char hw_version; /* FSI master hardware version */
+ unsigned char maxlinks; /* FSI master links */
+ struct fsilink *link[FSI_MAX_LINKS];
+ void (*write_reg)(struct fsi_mreg *, int, u32); /* Write 32 bit word */
+ u32 (*read_reg)(struct fsi_mreg *, int); /* Read 32 bit word */
+ void (*write_reg2)(struct fsi_mreg *, int, u64 *); /* 64 bit */
+ void (*read_reg2)(struct fsi_mreg *, int, u64 *); /* 64 bit */
+ void (*read_reg4)(struct fsi_mreg *, int, u32 *); /* 4 words */
+ void (*write_reg8)(struct fsi_mreg *, int, u32 *); /* 8 words */
+ struct fsidevice * (*m_get)(struct fsimaster *, int, int);
+ int (*m_pa2irq)(struct fsimaster *, u32);
+ void (*m_exit)(struct fsimaster *);
+ struct master_quirks quirks; /* hardware quirks functions/data */
+ unsigned char srsic; /* master specific register offset */
+ unsigned char srsim; /* master specific register offset */
+ unsigned long cfam_size; /* master specific cfam size */
+};
+#define to_fsimaster_probe(a) \
+ container_of(a, struct fsimaster, hotp.probework)
+#define to_fsimaster_build(a) \
+ container_of(a, struct fsimaster, hotp.buildwork)
+
+/*
+ * Functions to create/delete an FSI Master
+ */
+struct fsimaster *fsimaster_build_init(struct fsimaster *, int,
+ struct fsidevice *);
+struct fsimaster *fsimaster_build(int, struct fsidevice *);
+void fsimaster_free(struct fsimaster *);
+void fsimaster_put(struct fsimaster *);
+struct fsimaster *fsimaster_get(struct fsimaster *);
+struct fsimaster *fsimaster_find(u32);
+int fsimaster_plugcheck(u32);
+void fsimaster_start(struct fsimaster *);
+int fsimaster_stop(struct fsimaster *);
+void fsimaster_stopsync(struct fsimaster *);
+int fsi_linkbuild(struct fsimaster *, int);
+int fsi_linkdown(struct fsimaster *, int);
+void fsi_linklost(struct fsimaster *, int);
+
+/*
+ * Master commands
+ */
+int fsi_sendbreak(struct fsimaster *, u32, int);
+struct fsimaster *fsimaster_get_top_master(struct fsimaster *);
+
+/*
+ * FSI master register access functions (without locking)
+ */
+int fsimaster_reseterror_nl(struct fsimaster *, int);
+int fsimaster_resetgeneral_nl(struct fsimaster *, int);
+
+/*
+ * Helper utilities for register access
+ */
+void fsimaster_setspeed(struct fsimaster *, int, int);
+int fsimaster_ipoll_off_link_mask(struct fsimaster *, int, u32 *);
+int fsimaster_ipoll_off_link(struct fsimaster *, int);
+int fsimaster_ipoll_on_link(struct fsimaster *, int, u32);
+void fsimaster_disable_link(struct fsimaster *, int);
+void fsimaster_enable_link(struct fsimaster *, int);
+u64 fsimaster_read_menp(struct fsimaster *);
+u64 fsimaster_read_menp_nl(struct fsimaster *);
+u32 fsimaster_read_mmode(struct fsimaster *);
+u32 fsimaster_read_mmode_nl(struct fsimaster *);
+void fsimaster_read_mcrsp(struct fsimaster *, u64 *);
+int fsimaster_read_msiep(struct fsimaster *);
+int fsimaster_read_msiep_nl(struct fsimaster *);
+int fsimaster_write_msiep(struct fsimaster *, u32 *);
+int fsimaster_write_msiep_nl(struct fsimaster *, u32 *);
+int setup_me(struct fsimaster *, int);
+
+/*
+ * Utilities to decode master error registers
+ */
+int fsi_matrb_lsid(u32);
+unsigned long fsi_matrb_addr(unsigned long);
+
+/*
+ * Helper utilities for link/cfam calculations.
+ */
+u32 fsimaster_cfam2pa(struct fsimaster *, int, int);
+u32 fsimaster_linksz(struct fsimaster *);
+u32 fsimaster_cfamsz(struct fsimaster *);
+
+/*
+ * Helper utilities for IRQ number calculations.
+ */
+int fsimaster_pa2irq(struct fsimaster *, u32);
+int fsi_pa2irq(u32);
+
+/*
+ * Functions for link reference
+ */
+void fsimaster_linkref_add(struct fsimaster *, struct fsilink *);
+struct fsilink *fsimaster_linkref_del(struct fsimaster *, int);
+struct fsilink *fsimaster_linkref_markdel(struct fsimaster *, int);
+struct fsilink *fsimaster_linkget(struct fsimaster *, int);
+struct fsilink *fsimaster_linkget_inirq(struct fsimaster *, int);
+struct fsicfam *fsimaster_cfamget(struct fsimaster *, int, int);
+struct fsidevice *fsimaster_slvget(struct fsimaster *, int, int);
+struct fsidevice *fsimaster_slvget_inirq(struct fsimaster *, int, int);
+struct fsidevice *fsimaster_engget(struct fsimaster *, int, int, int);
+struct fsidevice *fsimaster_engget_inirq(struct fsimaster *, int, int, int);
+void fsimaster_linkput(struct fsilink *);
+void fsimaster_cfamput(struct fsicfam *);
+void fsimaster_slvput(struct fsidevice *);
+void fsimaster_engput(struct fsidevice *);
+void fsi_rst_error2(struct fsimaster *, struct fsidevice *, int, int, int, int);
+int port_reset(struct fsimaster *, int);
+
+#endif /* DRIVERS_FSIMASTER_H */
--
1.8.2.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH linux v5 3/7] drivers/fsi: Add FSI master target device scanning function
2016-08-24 19:54 [PATCH linux v5 0/7] Introducing the FSI device driver christopher.lee.bostic
2016-08-24 19:54 ` [PATCH linux v5 1/7] drivers/fsi: Initial stubs for " christopher.lee.bostic
2016-08-24 19:54 ` [PATCH linux v5 2/7] drivers/fsi: Add FSI Master Functionality and Initialization christopher.lee.bostic
@ 2016-08-24 19:54 ` christopher.lee.bostic
2016-08-24 19:54 ` [PATCH linux v5 4/7] drivers/fsi: Add initial FSI link buildup christopher.lee.bostic
` (4 subsequent siblings)
7 siblings, 0 replies; 19+ messages in thread
From: christopher.lee.bostic @ 2016-08-24 19:54 UTC (permalink / raw)
To: openbmc
From: Chris Bostic <cbostic@us.ibm.com>
Initialize and start the periodic target device presence detect function.
Add FSI master control register accessors to allow check of physical target
device plug state. Any target devices will show as present with a '1' in
the FSI master control MLEVP register.
Signed-off-by: Chris Bostic <cbostic@us.ibm.com>
---
drivers/fsi/fsimaster.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/fsi/fsimaster.h | 21 +++++++++
2 files changed, 140 insertions(+)
diff --git a/drivers/fsi/fsimaster.c b/drivers/fsi/fsimaster.c
index b5d16db..8054051 100644
--- a/drivers/fsi/fsimaster.c
+++ b/drivers/fsi/fsimaster.c
@@ -15,6 +15,7 @@
#include <linux/delay.h>
#include <linux/ktime.h>
#include <linux/io.h>
+#include <linux/bitops.h>
#include "fsi.h"
#include "fsiinit.h"
#include "fsimaster.h"
@@ -161,6 +162,20 @@ struct fsimaster *fsimaster_get_top_master(struct fsimaster *master)
return parent;
}
+/*
+ * Work queue function to probe links
+ */
+static void probe_wq(struct work_struct *work)
+{
+}
+
+/*
+ * Work queue function to build up links
+ */
+static void build_wq(struct work_struct *work)
+{
+}
+
static int fsimaster_reset(struct fsimaster *master)
{
u32 reg = 0;
@@ -221,6 +236,10 @@ struct fsimaster *fsimaster_build_init(struct fsimaster *master, int type,
}
master->type = type;
master->fsidev = parent;
+ init_timer(&master->hotp.mytimer);
+ init_completion(&master->hotp.link_dead);
+ INIT_WORK(&master->hotp.probework, probe_wq);
+ INIT_WORK(&master->hotp.buildwork, build_wq);
if (fsimaster_init(master)) {
master = NULL;
goto out;
@@ -234,9 +253,109 @@ out:
return master ? : ERR_PTR(rc);
}
+static void plugadd_link(struct fsimaster *master, struct fsi_hotplug *hp)
+{
+ hp->error_code = 0;
+ atomic_set(&hp->state, FSI_LINK_PROBE);
+ set_bit(hp->linkno, &master->hotp.probing);
+}
+
+static void plugadd(struct fsimaster *master, u64 *now_avail)
+{
+ int linkno;
+ struct fsidd *dd = to_fsidd_prim(fsimaster_get_top_master(master));
+
+ set_bit(FSI_LINK_PROBE, &dd->state);
+ while ((linkno = ffs(*now_avail)) >= 0) {
+ if (linkno >= master->maxlinks)
+ break;
+ plugadd_link(master, master->hotp.plug[linkno]);
+ }
+}
+
+static void plugdel(struct fsimaster *master, u64 *missing)
+{
+}
+
+/*
+ * Read in data on CFAM plug states
+ * nl: Not wrapped in a spin lock for those situations that don't require it
+ */
+void fsimaster_staticplug_nl(struct fsimaster *master, u64 *menp, u64 *mlevp)
+{
+ master->read_reg2(master->base, FSI_N_MENP, menp);
+ master->read_reg2(master->base, FSI_N_MLEVP, mlevp);
+}
+
+void fsimaster_staticplug(struct fsimaster *master, u64 *menp, u64 *mlevp)
+{
+ unsigned long msr = 0;
+
+ spin_lock_irqsave(&master->lock, msr);
+ fsimaster_staticplug_nl(master, menp, mlevp);
+ spin_unlock_irqrestore(&master->lock, msr);
+}
+
+/*
+ * Periodically called to check for static plug changes
+ */
+static void plugmgr(unsigned long para)
+{
+ struct fsimaster *master = (struct fsimaster *)para;
+ struct fsidd *dd;
+ u64 curr_plug_state, curr_enable_state, changed, now_avail, missing;
+
+ fsimaster_staticplug(master, &curr_enable_state, &curr_plug_state);
+ dd = to_fsidd_prim(fsimaster_get_top_master(master));
+
+ /* What is currently plugged and in use */
+ curr_plug_state |= curr_enable_state;
+
+ /* What plug states have changed since last checked */
+ changed = master->hotp.mlevp_last ^ curr_plug_state;
+
+ /* Slots where something has shown up since last checked */
+ now_avail = changed & curr_plug_state;
+
+ /* Slots where something disappeared since last checked */
+ missing = changed & master->hotp.mlevp_last;
+
+ /* Save off current plug state for next pass */
+ master->hotp.mlevp_last = curr_plug_state;
+
+ if (missing)
+ plugdel(master, &missing);
+ if (now_avail)
+ plugadd(master, &now_avail);
+
+ /* We have links to probe based on newest plug state data */
+ queue_work(dd->hotp_wq, &master->hotp.probework);
+ if (master->hotp.building == 0)
+ clear_bit(FSI_LINK_PROBE, &dd->state);
+
+ /* Probe has finished so can now proceed with link scan, aka 'build' */
+ if (master->hotp.building)
+ queue_work(dd->hotp_wq, &master->hotp.buildwork);
+
+ mod_timer(&master->hotp.mytimer,
+ jiffies + msecs_to_jiffies(FSI_PLUG_CHECK_TIME));
+}
+
/*
* Kick off the master so it can start probing for attached CFAMs
*/
void fsimaster_start(struct fsimaster *master)
{
+ /*
+ * TODO: Implement presence detect via I/O
+ * For now we'll define the default as only link 0 present
+ */
+ master->base->mlevp = 0x8000000000000000ULL;
+
+ /* Kick off the presence detect polling routine */
+ master->hotp.mytimer.function = plugmgr;
+ master->hotp.mytimer.data = (unsigned long)master;
+ master->hotp.mytimer.expires = jiffies +
+ msecs_to_jiffies(FSI_PLUG_CHECK_TIME);
+ add_timer(&master->hotp.mytimer);
}
diff --git a/drivers/fsi/fsimaster.h b/drivers/fsi/fsimaster.h
index 4df2caf..61e8c8a 100644
--- a/drivers/fsi/fsimaster.h
+++ b/drivers/fsi/fsimaster.h
@@ -520,6 +520,26 @@ static inline unsigned long get_termpa(unsigned long slv_pa)
return slv_pa & ~0xfff;
}
+struct fsi_hotplug { /* Hot plug information */
+ struct completion done; /* Link build done */
+ u16 tries; /* # of tries before probing */
+ u8 linkno; /* Link # */
+ atomic_t state; /* State of this entry */
+ int error_code; /* Error code */
+ unsigned long wait_state; /* Wait state */
+};
+
+struct hotplug { /* Hot Plug work */
+ u64 mlevp_last; /* Last known plug state */
+ unsigned long building; /* Bit mask of links to build up */
+ unsigned long probing; /* Bit mask of links to probe */
+ struct timer_list mytimer; /* For plug check period */
+ struct work_struct probework; /* Probe worker */
+ struct work_struct buildwork; /* Build worker */
+ struct completion link_dead; /* Wait for workw to finish */
+ struct fsi_hotplug *plug[FSI_MAX_LINKS]; /* Data to work on */
+};
+
struct master_quirks {
int break_cfam_id;
void (*port_reset)(struct fsidevice *, struct fsidevice *, int);
@@ -544,6 +564,7 @@ struct fsimaster { /* FSI master definition */
unsigned char hw_version; /* FSI master hardware version */
unsigned char maxlinks; /* FSI master links */
struct fsilink *link[FSI_MAX_LINKS];
+ struct hotplug hotp; /* CFAM plug status information */
void (*write_reg)(struct fsi_mreg *, int, u32); /* Write 32 bit word */
u32 (*read_reg)(struct fsi_mreg *, int); /* Read 32 bit word */
void (*write_reg2)(struct fsi_mreg *, int, u64 *); /* 64 bit */
--
1.8.2.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH linux v5 4/7] drivers/fsi: Add initial FSI link buildup
2016-08-24 19:54 [PATCH linux v5 0/7] Introducing the FSI device driver christopher.lee.bostic
` (2 preceding siblings ...)
2016-08-24 19:54 ` [PATCH linux v5 3/7] drivers/fsi: Add FSI master target device scanning function christopher.lee.bostic
@ 2016-08-24 19:54 ` christopher.lee.bostic
[not found] ` <CACPK8XfE0LpLnU64bw-8JA70wvAwbfO7L-fb6foyOLv-nMfNeg@mail.gmail.com>
2016-08-24 19:54 ` [PATCH linux v5 5/7] drivers/fsi: Add FSI bus type and hook into LDM christopher.lee.bostic
` (3 subsequent siblings)
7 siblings, 1 reply; 19+ messages in thread
From: christopher.lee.bostic @ 2016-08-24 19:54 UTC (permalink / raw)
To: openbmc
From: Chris Bostic <cbostic@us.ibm.com>
Add function to allow the primary FSI master to begin a buildup of a link
when a target device is found. Buildup is the process of creating an
internal device tree representing the physical target device connections
on a given master. First a master must create a link structure and
initialize it when there is a target device present on the other end of the
link.
Begin process of 'pinging' target device called a 'CFAM'. CFAM (Common
Field replaceable unit Access Macro) contains an FSI slave that is the
target of any FSI master communications. First the master pings by sending
a BREAK command to determine if anyone is listening. If CFAM is accessible
by reading its configuration space then the link buildup process begins.
Signed-off-by: Chris Bostic <cbostic@us.ibm.com>
---
drivers/fsi/Makefile | 2 +-
drivers/fsi/build.c | 114 +++++++++++++
drivers/fsi/fsi.h | 20 +++
drivers/fsi/fsi_private.h | 21 +++
drivers/fsi/fsiinit.c | 3 +
drivers/fsi/fsilink.h | 99 ++++++++++++
drivers/fsi/fsimaster.c | 218 +++++++++++++++++++++++++
drivers/fsi/fsimaster.h | 5 +
drivers/fsi/fsislave.h | 404 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/fsi/ldm.c | 29 ++++
drivers/fsi/readwrite.c | 34 ++++
11 files changed, 948 insertions(+), 1 deletion(-)
create mode 100644 drivers/fsi/build.c
create mode 100644 drivers/fsi/fsilink.h
create mode 100644 drivers/fsi/fsislave.h
create mode 100644 drivers/fsi/ldm.c
create mode 100644 drivers/fsi/readwrite.c
diff --git a/drivers/fsi/Makefile b/drivers/fsi/Makefile
index 9800c15..2445cee 100644
--- a/drivers/fsi/Makefile
+++ b/drivers/fsi/Makefile
@@ -2,4 +2,4 @@
# Makefile for the FSI bus specific drivers.
#
-obj-y += fsiinit.o fsimaster.o
+obj-y += fsiinit.o fsimaster.o build.o readwrite.o ldm.o
diff --git a/drivers/fsi/build.c b/drivers/fsi/build.c
new file mode 100644
index 0000000..c9a31c0
--- /dev/null
+++ b/drivers/fsi/build.c
@@ -0,0 +1,114 @@
+/*
+ * FSI Link Build up
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * Christopher Bostic <cbostic@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include "fsi.h"
+#include "fsi_private.h"
+#include "fsimaster.h"
+#include "fsicfam.h"
+#include "fsilink.h"
+
+static void link_release(struct device *devp)
+{
+}
+
+/*
+ * Create a FSI link struct and assign it to the FSI tree
+ */
+static struct fsilink *link_add(struct fsimaster *master, int no)
+{
+ int rc = 0;
+ struct fsilink *link = NULL;
+ int id = 0;
+
+ id = fsi_mtype_2break_id(master->type);
+
+ link = kmalloc(sizeof(struct fsilink), GFP_KERNEL);
+ if (!link)
+ return link;
+
+ dev_set_name(&link->fsidev.dev, "link-%d", no);
+ link->id3_addr = (FSI_MAX_CASCADE - 1) * FSI_CFAM_SIZE;
+ link->master = master;
+ link->linkno = no;
+ link->fsidev.map.va = link->id3_addr;
+ link->fsidev.map.cmtype = master->type;
+ link->fsidev.id.engine_type = FSI_ENGID_LINK;
+ link->fsidev.map.kb = fsimaster_linksz(master) / FSI_ENGINE_SIZE;
+ link->fsidev.irq_start = no * (FSI_MAX_CASCADE * FSI_MAX_ENGINES);
+ link->fsidev.irq_range = FSI_MAX_CASCADE * FSI_MAX_ENGINES;
+ if (!master->fsidev)
+ link->fsidev.dev.parent = 0;
+ else
+ link->fsidev.dev.parent = &master->fsidev->dev;
+ link->fsidev.dev.release = link_release;
+
+ /* stub */
+
+ return link ? : ERR_PTR(rc);
+}
+
+static void linkbuild2(struct fsimaster *master, struct fsilink *link)
+{
+}
+
+/*
+ * Return number of CFAMs discovered. If something fails during the build up
+ * process return error reason
+ */
+static int linkbuild1(struct fsimaster *master, int no)
+{
+ int i, rc = 0;
+ struct fsilink *link = link_add(master, no);
+
+ if (IS_ERR(link))
+ return PTR_ERR(link);
+
+ /* stub */
+
+ linkbuild2(master, link);
+ i = link->cascade;
+ if (i == 0) {
+
+ /* stub */
+
+ rc = -EIO;
+ } else {
+
+ /* stub */
+ }
+
+ return rc;
+}
+
+/*
+ * Build up a link. Returns number of CFAMs discovered.
+ */
+int fsi_linkbuild(struct fsimaster *master, int no)
+{
+ int rc;
+ u64 menp;
+
+ menp = fsimaster_read_menp(master);
+ if (menp & mask64(no))
+ return -EEXIST; /* Already running */
+
+ fsimaster_enable_link(master, no);
+ rc = linkbuild1(master, no);
+ if (rc < 0)
+ fsimaster_disable_link(master, no);
+
+ return rc;
+}
diff --git a/drivers/fsi/fsi.h b/drivers/fsi/fsi.h
index f146396..b723208 100644
--- a/drivers/fsi/fsi.h
+++ b/drivers/fsi/fsi.h
@@ -15,15 +15,35 @@
#include <linux/device.h>
+/*
+ * Engine ID's
+ */
+#define FSI_ENGID_LINK 0xff /* Link Identifier */
+
+/* Engine ID as it appears in the CFAM configuration table */
+struct fsi_engine_id {
+ u8 match_flags;
+ u8 engine_type;
+ u8 engine_version;
+ u8 engine_vendor;
+};
+
+/* Location information for a FSI device */
struct fsimap {
u8 link; /* Master link # */
u8 cfam; /* CFAM # on link */
+ u8 eng; /* Engine # on CFAM */
+ u8 cmtype; /* Type of master upstream */
u32 offset; /* Address offset into CFAM */
u32 va; /* Virtual address */
+ u16 kb; /* Size of dev engine space */
+ u16 kb_off; /* CFAM config table offset data */
};
struct fsidevice {
+ struct fsi_engine_id id; /* Engine type/version */
u32 irq_start; /* IRQ Number */
+ u16 irq_range; /* Number of IRQs */
struct fsidevice *parent; /* Parent of this device */
struct device dev; /* LDM entry for bus */
struct fsimap map; /* Address & location info */
diff --git a/drivers/fsi/fsi_private.h b/drivers/fsi/fsi_private.h
index be327ef..afa2553 100644
--- a/drivers/fsi/fsi_private.h
+++ b/drivers/fsi/fsi_private.h
@@ -44,10 +44,22 @@
#define FSI_PRIM 0 /* Generic Primary FSI master */
#define FSI_MBIT_MASK 0x3 /* FSI master bits in pa */
#define FSI_ENG_MASK 0x00007FFF /* The engine mask in MATRB */
+
/* FSI Events */
+#define FSI_EVT_LBUSLOST 1 /* Local bus loss */
+#define FSI_EVT_LBUSRECV 2 /* Local bus gained */
+#define FSI_EVT_IRQLOOP 3 /* IRQ loop detected */
+#define FSI_EVT_LINKCHG 4 /* Link state change */
+#define FSI_EVT_UNPLUG 5 /* Device unplugged */
#define FSI_EVT_PLUG 6 /* Device plugged */
+#define FSI_EVT_CFAMADD 7 /* New CFAM found */
+#define FSI_EVT_CFAMDELETE 8 /* Removing a CFAM */
+#define FSI_EVT_CFAMDEAD 9 /* CFAM no longer functions */
#define FSI_LINK_BUILD 10 /* In build up phase */
#define FSI_LINK_PROBE 11 /* In probing phase */
+#define FSI_LINK_RUNNING 12 /* Link up and running */
+#define FSI_LINK_DEAD 13 /* Link defective */
+#define FSI_LINK_WAITFOR 14 /* Wait for buildup */
/*
* Return the link number where this device is attached
@@ -76,6 +88,15 @@ static inline int fsi_mtype_2break_id(u8 mtype)
/*
* Build a mask where bit index 'x' is set (numbering from left to right.
+ * Bit 0 is MSB and bit 63 is LSM.
+ */
+static inline u64 mask64(int x)
+{
+ return 1 << (BITS_PER_LONG_LONG - x - 1);
+}
+
+/*
+ * Build a mask where bit index 'x' is set (numbering from left to right.
* Bit 0 is MSB and bit 31 is LSM.
*/
static inline unsigned long mask32(int x)
diff --git a/drivers/fsi/fsiinit.c b/drivers/fsi/fsiinit.c
index c589294..eaa3582 100644
--- a/drivers/fsi/fsiinit.c
+++ b/drivers/fsi/fsiinit.c
@@ -14,8 +14,11 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
+#include <linux/io.h>
+#include <linux/slab.h>
#include "fsiinit.h"
#include "fsimaster.h"
+#include "fsi_private.h"
MODULE_AUTHOR("Christopher Bostic cbostic@us.ibm.com");
MODULE_DESCRIPTION("FSI master device driver");
diff --git a/drivers/fsi/fsilink.h b/drivers/fsi/fsilink.h
new file mode 100644
index 0000000..f923650
--- /dev/null
+++ b/drivers/fsi/fsilink.h
@@ -0,0 +1,99 @@
+/*
+ * FSI link structure definitions and defines
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * Christopher Bostic <cbostic@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef DRIVERS_FSILINK_H
+#define DRIVERS_FSILINK_H
+
+#include <linux/types.h>
+#include <linux/kobject.h>
+#include <linux/device.h>
+#include "fsi.h"
+#include "fsi_private.h"
+
+/*
+ * Extended FSI error counting and thresholding. Count the FSI errors with
+ * time they occurred.
+ */
+#define FSI_MAX_PE 6 /* Max # of FSI port errors */
+#define FSI_MAX_ME 11 /* Max # of FSI master errors */
+#define FSI_MAX_SE 10 /* Max # of FSI slave V3 errors */
+#define FSI_MAX_SEV2 6 /* Max # of FSI slave V2 errors */
+
+struct fsi_ecnt { /* Structure for counting errors */
+ unsigned short cnt; /* Counter */
+ struct timeval seen_1st; /* First occurrence */
+ struct timeval seen_last; /* Last occurrence */
+};
+
+struct fsi_eport { /* Port error statistics */
+ unsigned short pec[FSI_MAX_PE]; /* Port errors counter per type */
+ unsigned short pcrc_cnt; /* Recovered CRC counter port */
+};
+
+struct fsi_eslv { /* Slave error statistics */
+ unsigned short sec[FSI_MAX_SE]; /* Slave errors counter per type */
+ unsigned short scrc_cnt; /* Recovered CRC counter slave */
+};
+
+struct fsi_emaster { /* Master error statistics */
+ unsigned short mec[FSI_MAX_ME]; /* Master errors counter per type */
+ unsigned short mcrc_cnt; /* Recovered CRC counter master */
+};
+
+struct fsi_elink { /* Link error statistics */
+ struct fsi_emaster master; /* Master errors */
+ struct fsi_eport port; /* Port errors */
+ struct fsi_eslv slv[FSI_MAX_CASCADE]; /* Slave errors */
+ struct fsi_ecnt breaked; /* BREAK command sent */
+};
+
+enum fsilink_state { /* Bit mask for error states */
+ fsilink_lost = 1, /* Link already schedule for removal */
+ fsilink_up = 2, /* Link up & running */
+ fsilink_going = 3 /* Link removal in progress */
+};
+
+struct fsilink { /* Information per link */
+ u8 speedset; /* Link speed set (0 or 1) */
+ u8 cascade; /* Length of cascade */
+ u8 top_cfam; /* # CFAM found on initial scan */
+ u8 linkno; /* Number of this link */
+ unsigned long state; /* Bit mask for error states */
+ struct fsicfam *cfams[FSI_MAX_CASCADE]; /* CFAMs per link */
+ struct fsidevice fsidev;
+ u32 id3_addr; /* CFAM id3 page */
+ struct fsimaster *master; /* Ptr to controlling fsi master */
+ struct fsi_elink error; /* Errors on this link */
+};
+
+#define FSILINK_ATTR(_name, _mode, _show, _store) \
+struct device_attribute fsilink_attr_##_name = { \
+ .attr = { \
+ .name = __stringify(_name), \
+ .mode = _mode, \
+ }, \
+ .show = _show, \
+ .store = _store \
+}
+
+/*
+ * Pointer conversion from fsidevice member to fsilink.
+ */
+#define to_fsilink(x) container_of((x), struct fsilink, fsidev)
+
+unsigned char fsilink_get_top_cfam(struct fsilink *);
+unsigned char fsilink_get_linkno(struct fsilink *);
+unsigned long fsilink_get_state(struct fsilink *);
+struct fsicfam *fsilink_get_cfam(struct fsilink *, int);
+struct device *fsilink_get_device(struct fsilink *);
+
+#endif /* DRIVERS_FSILINK_H */
diff --git a/drivers/fsi/fsimaster.c b/drivers/fsi/fsimaster.c
index 8054051..427231f 100644
--- a/drivers/fsi/fsimaster.c
+++ b/drivers/fsi/fsimaster.c
@@ -17,9 +17,11 @@
#include <linux/io.h>
#include <linux/bitops.h>
#include "fsi.h"
+#include "fsi_private.h"
#include "fsiinit.h"
#include "fsimaster.h"
#include "fsicfam.h"
+#include "fsislave.h"
static int hpinfo_alloc(struct fsimaster *master)
{
@@ -150,6 +152,9 @@ static int fsimaster_init(struct fsimaster *master)
return rc;
}
+/*
+ * Retrieve the first master in the chain
+ */
struct fsimaster *fsimaster_get_top_master(struct fsimaster *master)
{
struct fsimaster *parent = NULL;
@@ -163,10 +168,195 @@ struct fsimaster *fsimaster_get_top_master(struct fsimaster *master)
}
/*
+ * Get the address space size of a link/CFAM
+ */
+
+u32 fsimaster_cfamsz(struct fsimaster *master)
+{
+ return master->cfam_size;
+}
+
+u32 fsimaster_linksz(struct fsimaster *master)
+{
+ return FSI_MAX_CASCADE * fsimaster_cfamsz(master);
+}
+
+/*
+ * Find physical address given master and link #
+ */
+u32 fsimaster_link2pa(struct fsimaster *master, int link)
+{
+ u32 offset = link * fsimaster_linksz(master);
+
+ return master->membase + offset;
+}
+
+/*
+ * Find physical address given master, link # and CFAM #
+ */
+u32 fsimaster_cfam2pa(struct fsimaster *master, int link, int cfam)
+{
+ u32 offset = link * fsimaster_linksz(master) +
+ cfam * fsimaster_cfamsz(master);
+
+ return master->membase + offset;
+}
+
+int fsim_pa2irq(struct fsimaster *master, u32 pa)
+{
+ return 0;
+}
+
+int fsi_pa2irq(u32 pa)
+{
+ return 0;
+}
+
+/*
+ * Master control register accessors
+ */
+
+/*
+ * Read/write mode register: MMODE
+ */
+u32 fsimaster_read_mmode_nl(struct fsimaster *master)
+{
+ return master->read_reg(master->base, FSI_N_MMODE);
+}
+
+u32 fsimaster_read_mmode(struct fsimaster *master)
+{
+ return 0;
+}
+
+void fsimaster_write_mmode(struct fsimaster *master, u32 value)
+{
+}
+
+/*
+ * Read/write enable port register: MENP
+ */
+u64 fsimaster_read_menp_nl(struct fsimaster *master)
+{
+ return 0;
+}
+
+u64 fsimaster_read_menp(struct fsimaster *master)
+{
+ return 0;
+}
+
+void fsimaster_write_menp(struct fsimaster *master, u64 *menp, int on_off)
+{
+}
+
+void fsimaster_disable_link(struct fsimaster *master, int link)
+{
+}
+
+void fsimaster_enable_link(struct fsimaster *master, int link)
+{
+}
+
+/*
+ * Send out a BREAK command and see if anything response. Part of the scan
+ * process
+ */
+static int ping_cfam(struct fsimaster *master, struct fsi_hotplug *hp,
+ const int count)
+{
+ int i = 0, rc = -EIO;
+ u32 value, pa;
+ int id = fsi_mtype_2break_id(master->type);
+
+ pa = fsimaster_cfam2pa(master, hp->linkno, id);
+
+ fsimaster_enable_link(master, hp->linkno);
+ if (fsi_sendbreak(master, pa, hp->linkno))
+ goto out;
+
+ while (i++ < count) {
+ rc = fsi_readw_int(master, pa + FSI_SLAVE0_OFFSET + FSI_SMODE,
+ &value);
+ if (rc == 0)
+ break;
+
+ udelay(FSI_CFAM_PING_DELAY);
+ }
+out:
+ fsimaster_disable_link(master, hp->linkno);
+
+ return rc;
+}
+
+/*
+ * Probe for CFAMs
+ */
+static int probe_link(struct fsimaster *master, struct fsi_hotplug *hp)
+{
+ int rc = 0;
+ struct fsidd *dd = to_fsidd_prim(fsimaster_get_top_master(master));
+
+ hp->tries++;
+ rc = ping_cfam(master, hp, FSI_MAX_CASCADE - 1);
+ if (rc == 0) {
+ atomic_set(&hp->state, FSI_LINK_BUILD);
+ set_bit(FSI_LINK_BUILD, &dd->state);
+ set_bit(hp->linkno, &master->hotp.building);
+ clear_bit(hp->linkno, &master->hotp.probing);
+ rc = 1;
+ } else if (hp->tries > FSI_MAX_PING_ATTEMPTS) {
+ atomic_set(&hp->state, FSI_EVT_CFAMDEAD);
+ clear_bit(hp->linkno, &master->hotp.probing);
+ }
+
+ return rc;
+}
+
+/*
* Work queue function to probe links
*/
static void probe_wq(struct work_struct *work)
{
+ struct fsimaster *master = to_fsimaster_probe(work);
+ struct fsidd *dd = to_fsidd_prim(fsimaster_get_top_master(master));
+ int i, cnt = 0;
+
+ for (i = 0; i < master->maxlinks; ++i) {
+ if (test_bit(i, &master->hotp.probing))
+ cnt += probe_link(master, master->hotp.plug[i]);
+ }
+ if (cnt)
+ queue_work(dd->hotp_wq, &master->hotp.buildwork);
+}
+
+/*
+ * Called from worker in process/task context
+ */
+static int build(struct fsimaster *master, struct fsi_hotplug *hp)
+{
+ int rc;
+
+ rc = fsi_linkbuild(master, hp->linkno);
+ atomic_set(&hp->state, rc ? FSI_LINK_RUNNING : FSI_LINK_DEAD);
+ if (test_and_clear_bit(FSI_LINK_WAITFOR, &hp->wait_state))
+ complete_all(&hp->done);
+
+ return rc;
+}
+
+static int remove(struct fsimaster *master, struct fsi_hotplug *hp)
+{
+ return 0;
+}
+
+/*
+ * Actual link build function. Called in process context.
+ */
+static void build_link(struct fsimaster *master, struct fsi_hotplug *hp)
+{
+ hp->error_code = (hp->cmd == FSI_EVT_CFAMADD) ? build(master, hp)
+ : remove(master, hp);
}
/*
@@ -174,6 +364,34 @@ static void probe_wq(struct work_struct *work)
*/
static void build_wq(struct work_struct *work)
{
+ struct fsimaster *master = to_fsimaster_build(work);
+ struct fsidd *dd = to_fsidd_prim(fsimaster_get_top_master(master));
+ int i;
+
+ set_bit(FSI_LINK_BUILD, &dd->state);
+again:
+ for (i = 0; i < master->maxlinks; ++i) {
+ if (test_and_clear_bit(i, &master->hotp.building))
+ build_link(master, master->hotp.plug[i]);
+ }
+
+ /* stub */
+
+ /*
+ * Make sure all bits were cleared before leaving.
+ * This worker runs in process context. While running, an FSI error
+ * interrupt can occur and schedule a link for removal.
+ * If we are past this new bit in our loop above, the link is not
+ * removed. Iterate on non zero.
+ */
+ if (master->hotp.building)
+ goto again;
+
+ /*
+ * If the same described above happens here, we are toast again.
+ * Another perodic check is done on plugmgr()
+ */
+ clear_bit(FSI_LINK_BUILD, &dd->state);
}
static int fsimaster_reset(struct fsimaster *master)
diff --git a/drivers/fsi/fsimaster.h b/drivers/fsi/fsimaster.h
index 61e8c8a..0d47dc6 100644
--- a/drivers/fsi/fsimaster.h
+++ b/drivers/fsi/fsimaster.h
@@ -20,6 +20,7 @@
#define FSI_MAX_PING_ATTEMPTS 12
#define FSI_PLUG_CHECK_TIME 100
#define FSI_DFLT_IPOLL_CHECK 800
+#define FSI_CFAM_PING_DELAY 20 /* in microseconds */
/* FSI master register numbers */
#define FSI_N_MMODE 0 /* 0x0 R/W: mode register */
@@ -524,6 +525,7 @@ struct fsi_hotplug { /* Hot plug information */
struct completion done; /* Link build done */
u16 tries; /* # of tries before probing */
u8 linkno; /* Link # */
+ u8 cmd; /* State add/delete */
atomic_t state; /* State of this entry */
int error_code; /* Error code */
unsigned long wait_state; /* Wait state */
@@ -673,4 +675,7 @@ void fsimaster_engput(struct fsidevice *);
void fsi_rst_error2(struct fsimaster *, struct fsidevice *, int, int, int, int);
int port_reset(struct fsimaster *, int);
+int fsi_writew_int(struct fsimaster *, u32, u32);
+int fsi_readw_int(struct fsimaster *, u32, u32*);
+
#endif /* DRIVERS_FSIMASTER_H */
diff --git a/drivers/fsi/fsislave.h b/drivers/fsi/fsislave.h
new file mode 100644
index 0000000..f2095d3
--- /dev/null
+++ b/drivers/fsi/fsislave.h
@@ -0,0 +1,404 @@
+/*
+ * FSI slave structure definitions and defines
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * Christopher Bostic <cbostic@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef DRIVERS_FSISLAVE_H
+#define DRIVERS_FSISLAVE_H
+
+/*
+ * Define read address for peek engine referring to
+ * side/series/node-id/frame-id
+ */
+#define FSI_PEEK_IDADDR 0xc
+
+#define FSI_SLV_CFAM_OFFSET 0x800
+
+/*
+ * Defines for address locations of certain register in FSI Slave. All register
+ * names start with FSI_S for slave register. Some registers have the
+ * same address but different meanings for read and write access.
+ */
+#define FSI_SMODE 0x0 /* R/W: Slave mode register */
+#define FSI_SDMA 0x4 /* R/W: DMA control register */
+#define FSI_SISC 0x8 /* Read: read Interrupt condition register */
+#define FSI_SCISC 0x8 /* Write: Clear Interrupt condition register */
+#define FSI_SISM 0xC /* R/W: Interrupt mask register */
+#define FSI_SISS 0x10 /* Read: Interrupt status register */
+#define FSI_SSISM 0x10 /* Write: Set interrupt mask */
+#define FSI_SSTAT 0x14 /* Read: Read slave status register */
+#define FSI_SCISM 0x14 /* Write: Clear interrupt mask */
+#define FSI_SI1M 0x18 /* R/W: Interrupt 1 mask register */
+#define FSI_SI1S 0x1C /* Read: Read Interrupt 1 status register */
+#define FSI_SSI1M 0x1C /* Write: Set Interrupt 1 mask register */
+#define FSI_SIC 0x20 /* Read: Read engine interrupt condition reg */
+#define FSI_SCI1M 0x20 /* Write: Clear Interrupt 1 mask register */
+#define FSI_SI2M 0x24 /* R/W: Interrupt 2 mask register */
+#define FSI_SI2S 0x28 /* Read: Read Interrupt 2 status register */
+#define FSI_SSI2M 0x28 /* Write: Set Interrupt 2 mask register */
+#define FSI_SCMDT 0x2C /* Read: Command trace register */
+#define FSI_SCI2M 0x2C /* Write: Clear Interrupt 2 mask register */
+#define FSI_SDATAT 0x30 /* Read: Data trace register */
+#define FSI_SLBUS 0x30 /* Write: local bus address commands */
+#define FSI_SLASTD 0x34 /* Read: Last data send register */
+#define FSI_SRES 0x34 /* Write: Reset command register */
+#define FSI_SMBL 0x38 /* R/W: Mailbox register left port */
+#define FSI_SOML 0x3C /* Read: Mailbox old data register left port */
+#define FSI_SSMBL 0x3C /* Write: Set Mailbox bits register left port */
+#define FSI_SNML 0x40 /* Read: Mailbox new data register left port */
+#define FSI_SCMBL 0x40 /* Write: Clear mailbox bits left port */
+#define FSI_SMBR 0x44 /* R/W: Mailbox register right port */
+#define FSI_SOMR 0x48 /* Read: Mailbox old data register right port */
+#define FSI_SSMBR 0x48 /* Write: Set Mailbox bits register right port*/
+#define FSI_SNMR 0x4c /* Read: Mailbox new data register right port */
+#define FSI_SCMBR 0x4c /* Write: Clear mailbox bits right port */
+
+/* Same as above except Word offsets into the FSI slave engine */
+#define FSI_N_SISC 0x2 /* Read: read Interrupt condition register */
+#define FSI_N_SSTAT 0x5 /* Read: Slave Status register */
+#define FSI_N_SCMDT 0xB /* Read: Command trace register */
+#define FSI_N_SDATAT 0xC /* Read: Data trace register */
+#define FSI_N_SLASTD 0xD /* Read: Last data send register */
+
+/* Next registers are only valid for FSI slave version 3 */
+#define FSI_SRSIC 0x50 /* Read slave remote slave IRQ condition */
+#define FSI_SCRSIC 0x50 /* Write: Clear Slave remote slave IRQ cond */
+#define FSI_SRSIM 0x54 /* R/W: Slave remote slave IRQ mask */
+#define FSI_SRSIS 0x58 /* Read: Slave remote slave IRQ status */
+
+/* Next registers are only valid for FSI slave version 4 */
+/* cmFSI */
+#define FSI_ScRSIC0 0x50 /* Read / Write: to clear cmFSI remote */
+/* slave IRQ condition ports 0-3 */
+#define FSI_ScRSIC4 0x54 /* Read / Write: to clear cmFSI remote */
+/* slave IRQ condition ports 4-7 */
+#define FSI_ScRSIM0 0x58 /* R/W: cmFSI remote slave IRQ mask */
+/* ports 0-3 */
+#define FSI_ScRSIM4 0x5C /* R/W: cmFSI remote slave IRQ mask */
+/* ports 4-7 */
+#define FSI_ScRSIS0 0x60 /* Read: cmFSI remote slave IRQ status */
+/* ports 0-3 */
+#define FSI_ScRSIS4 0x64 /* Read: cMFSI remote slave IRQ status */
+/* ports 4-7 */
+/* hFSI */
+#define FSI_SRSIC0 0x68 /* Read / Write: to clear hFSI remote */
+/* slave IRQ condition ports 0-3 */
+#define FSI_SRSIC4 0x6C /* Read / Write: to clear hFSI remote */
+/* slave IRQ condition ports 4-7 */
+#define FSI_SRSIM0 0x70 /* R/W: hFSI remote slave IRQ mask */
+/* ports 0-3 */
+#define FSI_SRSIM4 0x74 /* R/W: hFSI remote slave IRQ mask */
+/* ports 4-7 */
+#define FSI_SRSIS0 0x78 /* Read: hFSI remote slave IRQ status */
+/* ports 0-3 */
+#define FSI_SRSIS4 0x7C /* Read: hFSI remote slave IRQ status */
+/* ports 4-7 */
+
+#define FSI_SRSIM_SID3_SHIFT 6
+
+/* Slave ID 3 on interrupt level 1 for all sub/hub links */
+#define SRSIM_ID3_IRPT1_MASK 0x02020202
+#define SRSIM_MAGIC SRSIM_ID3_IRPT1_MASK
+
+struct fsi_sreg { /* FSI slave register definition */
+ u32 smode; /* 0x0: Mode register */
+ u32 sdma; /* 0x4: DMA control register */
+ u32 sisc; /* 0x8: Slave interrupt condition register */
+ u32 sism; /* 0xc: Slave interrupt mask register */
+ u32 siss; /* 0x10: Slave interrupt status register */
+ u32 sstat; /* 0x14: Slave status register */
+ u32 si1m; /* 0x18: interrupt 1 mask register */
+ u32 si1s; /* 0x1c: interrupt 1 status register */
+ u32 sic; /* 0x20: engine interrupt condition register */
+ u32 si2m; /* 0x24: interrupt 2 mask register */
+ u32 si2s; /* 0x28: interrupt 2 status register */
+ u32 scmdt; /* 0x2c: read command trace register */
+ u32 sdatat; /* 0x30: read data trace register */
+ u32 slastd; /* 0x34: read last FSI data register */
+ u32 smbl; /* 0x38: mail box to left port register */
+ u32 soml; /* 0x3c: old mail left port register */
+ u32 snml; /* 0x40: new mail left port register */
+ u32 smbr; /* 0x44: mail box to right port register */
+ u32 somr; /* 0x48: old mail right port register */
+ u32 snmr; /* 0x4c: new mail right port register */
+ u32 srsic0; /* 0x50: slave remote slave IRQ cond. 0-3 */
+ u32 srsic4; /* 0x54: slave remote slave IRQ cond. 4-7 */
+ u32 srsim0; /* 0x58: slave remote slave IRQ mask 0-3 */
+ u32 srsim4; /* 0x5C: slave remote slave IRQ mask 4-7 */
+ u32 srsis0; /* 0x60: slave remote slave IRQ stat 0-3 */
+ u32 srsis4; /* 0x64: slave remote slave IRQ stat 4-7 */
+};
+
+/*
+ * FSI slave mode register
+ */
+#define FSI_SMODE_WSC 0x80000000 /* Warm start completed */
+#define FSI_SMODE_EAP 0x40000000 /* Enable auxiliary port */
+#define FSI_SMODE_ECRC 0x20000000 /* Enable CRC checking by hw */
+#define FSI_SMODE_SID_SHIFT 24 /* Slave identifier shift */
+#define FSI_SMODE_SID_MASK 3 /* Slave identifier mask */
+#define FSI_SMODE_ED_SHIFT 20 /* Echo delay cycles shift */
+#define FSI_SMODE_ED_MASK 0xf /* Echo delay cycles mask */
+#define FSI_SMODE_SD_SHIFT 16 /* Send delay cycles shift */
+#define FSI_SMODE_SD_MASK 0xf /* Send delay cycles mask */
+#define FSI_SMODE_LBCRR_SHIFT 8 /* Local bus clk rate shift */
+#define FSI_SMODE_LBCRR_MASK 0xf /* Local bus clk rate mask */
+#define FSI_SMODE_BDL_SHIFT 4 /* Briefing data left shift */
+#define FSI_SMODE_BDL_MASK 0xf /* Briefing data mask */
+#define FSI_SMODE_BDR_SHIFT 0 /* Briefing data right shift */
+#define FSI_SMODE_BDR_MASK 0xf /* Briefing data mask */
+#define FSI_SMODE_RSV_MASK 0xe3ff0fff /* Mask for used bit clr rsvd */
+
+/* FSI slave local bus echo delay */
+static inline u32 fsi_smode_echodly(int x)
+{
+ return (x & FSI_SMODE_ED_MASK) << FSI_SMODE_ED_SHIFT;
+}
+
+/* FSI slave local bus send delay */
+static inline u32 fsi_smode_senddly(int x)
+{
+ return (x & FSI_SMODE_SD_MASK) << FSI_SMODE_SD_SHIFT;
+}
+
+/* FSI slave local bus clock rate ratio */
+static inline int fsi_smode_extlbcrr(u32 x)
+{
+ return (x >> FSI_SMODE_LBCRR_SHIFT) & FSI_SMODE_LBCRR_MASK;
+}
+
+/* FSI slave local bus clock rate ratio */
+static inline u32 fsi_smode_lbcrr(int x)
+{
+ return (x & FSI_SMODE_LBCRR_MASK) << FSI_SMODE_LBCRR_SHIFT;
+}
+
+/* FSI slave identifier setting */
+static inline u32 fsi_smode_sid(int x)
+{
+ return (x & FSI_SMODE_SID_MASK) << FSI_SMODE_SID_SHIFT;
+}
+
+/* FSI slave briefing data right port */
+static inline u32 fsi_smode_bdr(int x)
+{
+ return (x & FSI_SMODE_BDR_MASK) << FSI_SMODE_BDR_SHIFT;
+}
+
+static inline int fsi_smode_extbdr(u32 x)
+{
+ return (x >> FSI_SMODE_BDR_SHIFT) & FSI_SMODE_BDR_MASK;
+}
+
+/* FSI slave briefing data left port */
+static inline u32 fsi_smode_bdl(int x)
+{
+ return (x & FSI_SMODE_BDL_MASK) << FSI_SMODE_BDL_SHIFT;
+}
+
+static inline int fsi_smode_extbdl(u32 x)
+{
+ return (x >> FSI_SMODE_BDL_SHIFT) & FSI_SMODE_BDL_MASK;
+}
+
+/* FSI slave echo delay */
+static inline u32 fsi_smode_ed(int x)
+{
+ return (x & FSI_SMODE_ED_MASK) << FSI_SMODE_ED_SHIFT;
+}
+
+static inline int fsi_smode_exted(u32 x)
+{
+ return (x >> FSI_SMODE_ED_SHIFT) & FSI_SMODE_ED_MASK;
+}
+
+/* FSI slave send delay */
+static inline u32 fsi_smode_sd(int x)
+{
+ return (x & FSI_SMODE_SD_MASK) << FSI_SMODE_SD_SHIFT;
+}
+
+static inline int fsi_smode_extsd(u32 x)
+{
+ return (x >> FSI_SMODE_SD_SHIFT) & FSI_SMODE_SD_MASK;
+}
+
+/*
+ * FSI slave interrupt register: interrupt conditions, status and mask
+ */
+#define FSI_SSI_CRCE 0x80000000 /* FSI CRC error */
+#define FSI_SSI_PROTE 0x40000000 /* FSI protocol error */
+#define FSI_SSI_LBPE 0x20000000 /* FSI local bus parity error */
+#define FSI_SSI_LBPROTE 0x10000000 /* FSI local bus protocol err */
+#define FSI_SSI_LBAE 0x08000000 /* FSI local bus access error */
+#define FSI_SSI_LBOE 0x04000000 /* FSI local bus owner error */
+#define FSI_SSI_LBOC 0x02000000 /* FSI local bus owner change */
+#define FSI_SSI_HPE 0x01000000 /* Hot plug event */
+#define FSI_SSI_MRL 0x00800000 /* Mail received left port */
+#define FSI_SSI_MDL 0x00400000 /* Mail send left port */
+#define FSI_SSI_WSL 0x00200000 /* Warm start flag left port */
+#define FSI_SSI_LBRL 0x00100000 /* Local bus requ left port */
+#define FSI_SSI_MRR 0x00080000 /* Mail received right port */
+#define FSI_SSI_MDR 0x00040000 /* Mail delivered right port */
+#define FSI_SSI_WSR 0x00020000 /* Warm start flag right port */
+#define FSI_SSI_LBRR 0x00010000 /* Local bus req right port */
+#define FSI_SSI_CMEL 0x00008000 /* Clocks monitor event left */
+#define FSI_SSI_CMER 0x00004000 /* Clocks monitor event right */
+#define FSI_SSI_OPB_FNC 0x00001000 /* OPB Fenced (cMFSI & hMFSI) */
+#define FSI_SSI_OBP_PA 0x00000800 /* OPB Parity (cMFSI) */
+#define FSI_SSI_OBP_PR 0x00000400 /* OPB Protocol (cMFSI) */
+#define FSI_SSI_OBP_TO 0x00000200 /* OPB Timeout (cMFSI) */
+#define FSI_SSI_OBP_EA 0x00000100 /* OPB ErrorAck (cMFSI) */
+#define FSI_SSI_OBP_IA 0x00002000 /* OPB Invalid Address (cMFSI)*/
+#define FSI_SSI_CMFSI_AME 0x00000080 /* CMFSI any-master-error */
+#define FSI_SSI_CMFSI_APE 0x00000040 /* CMFSI any-port-error */
+#define FSI_SSI_CMFSI_HPE 0x00000020 /* CMFSI Hot plug event */
+#define FSI_SSI_CMFSI_CRPA 0x00000010 /* CMFSI Contr reg parity err */
+#define FSI_SSI_ANY_IRQ 0xffffc000 /* Valid bits */
+#define FSI_SSI_ANY_IRQ3 (FSI_SSI_CMFSI_AME | FSI_SSI_CMFSI_APE \
+ | FSI_SSI_CMFSI_HPE | FSI_SSI_CMFSI_CRPA)
+ /* Valid bits (cMFSI) */
+#define FSI_SSI_ANY_ERROR 0xfc000000 /* Valid error bits */
+#define FSI_SSI_ANY_ERROR3 (FSI_SSI_OBP_PA \
+ | FSI_SSI_OBP_PR | FSI_SSI_OBP_TO \
+ | FSI_SSI_OBP_EA | FSI_SSI_OBP_IA)
+ /* Valid error bits (cMFSI) */
+#define FSI_SSI_ERR_MASK 0x3f /* Any error bits mask */
+#define FSI_SSI_ERR_SHFT 26 /* Any error bits shift */
+#define FSI_SISC_CRCE 0 /* Slave CRC error bit */
+#define FSI_SISC_PE 1 /* Slave protocol error bit */
+#define FSI_SISC_LBPE 2 /* Slave lcl bus parity err */
+#define FSI_SISC_LBPROTOE 3 /* Slave lcl bus prot err */
+#define FSI_SISC_LBAE 4 /* Slave access error bit */
+#define FSI_SISC_LBOE 5 /* Slave lcl bus owner err */
+#define FSI_SISC_OPBPA 20 /* Slave OPB parity error */
+#define FSI_SISC_OPBPR 21 /* Slave OPB protocol error */
+#define FSI_SISC_OPBTO 22 /* Slave OPB timeout error */
+#define FSI_SISC_OPBEA 23 /* Slave OPB ack error */
+#define FSI_SISC_CM_ERRS 0x000000f0 /* CMP8 sourced errors */
+#define FSI_SISC_HM_ERRS 0x0000000f /* HMP8 sourced errors */
+
+/* FSI slave error interrupt */
+static inline int fsi_sisc_iserror(u32 x)
+{
+ return x & (FSI_SSI_ANY_ERROR3 | FSI_SSI_ANY_ERROR);
+}
+
+/*
+ * FSI slave interrupt mask register: interrupt conditions, status and mask
+ */
+#define FSI_SSI_ENG0 0x80000000 /* FSI slave */
+#define FSI_SSI_ENG_MBX 0x400 /* FSI IOU Mailbox */
+#define FSI_SSI_ENG_ANY 0x7fffffff /* FSI engine 1..31 */
+#define FSI_SSI_ENG_NOLBUS (FSI_SSI_ENG0 | FSI_SSI_ENG_MBX)
+ /* Engines without local bus */
+/*
+ * FSI slave status register SSTAT
+ */
+#define FSI_SSTAT_AE 0x80000000 /* Any error bit */
+#define FSI_SSTAT_IDD 0x40000000 /* CFAM ID dirty at PON lvl) */
+#define FSI_SSTAT_LSW 0x40000000 /* Left side warm start flag */
+#define FSI_SSTAT_RSW 0x10000000 /* Rt side warm start flag */
+#define FSI_SSTAT_MDL 0x08000000 /* Mail delivered left side */
+#define FSI_SSTAT_MDR 0x04000000 /* Mail delivered right side */
+#define FSI_SSTAT_MRL 0x02000000 /* Mail received left side */
+#define FSI_SSTAT_MRR 0x01000000 /* Mail received right side */
+#define FSI_SSTAT_BDL_SHIFT 20 /* Brief data left side shft */
+#define FSI_SSTAT_BDL_MASK 0xf /* Brief data left side mask */
+#define FSI_SSTAT_BDR_SHIFT 16 /* Brief data rt side shift */
+#define FSI_SSTAT_BDR_MASK 0xf /* Brief data rt side mask */
+#define FSI_SSTAT_LSLBR 0x8000 /* Left side local bus req */
+#define FSI_SSTAT_RSLBR 0x4000 /* Right side local bus req */
+#define FSI_SSTAT_TSLBR 0x2000 /* This side local bus req */
+#define FSI_SSTAT_BLBA 0x1000 /* Block C-side lcl bus acc */
+#define FSI_SSTAT_LBO_SHIFT 10 /* Local bus owner shift */
+#define FSI_SSTAT_LBO_MASK 3 /* Local bus owner mask */
+#define FSI_SSTAT_TSF_SHIFT 8 /* This side A=01 B=10 C=11 */
+#define FSI_SSTAT_TSF_MASK 3 /* This side flag mask */
+#define FSI_SSTAT_CAL 0x00000080 /* Clocks active left port */
+#define FSI_SSTAT_CAR 0x00000040 /* Clocks active right port */
+#define FSI_SSTAT_APIL 0x00000020 /* Aux port input level */
+#define FSI_SSTAT_APRL 0x00000010 /* Aux port reference level */
+#define FSI_SSTAT_CRC_SHIFT 0 /* CRC error counter */
+#define FSI_SSTAT_CRC_MASK 0xf /* CRC mask */
+#define FSI_SSTAT_SIDE_NONE 0 /* Unknown Side */
+#define FSI_SSTAT_SIDE_A 1 /* A-Side */
+#define FSI_SSTAT_SIDE_B 2 /* B-Side */
+#define FSI_SSTAT_SIDE_C 3 /* C-Side */
+
+/* FSI status local bus request */
+static inline int fsi_sstat_tsf(u32 x)
+{
+ return (x >> FSI_SSTAT_TSF_SHIFT) & FSI_SSTAT_TSF_MASK;
+}
+
+/* FSI status get local bus owner */
+static inline int fsi_sstat_lbo(u32 x)
+{
+ return (x >> FSI_SSTAT_LBO_SHIFT) & FSI_SSTAT_LBO_MASK;
+}
+
+/* FSI status get right side briefing data */
+static inline int fsi_sstat_bdr(u32 x)
+{
+ return (x >> FSI_SSTAT_BDR_SHIFT) & FSI_SSTAT_BDR_MASK;
+}
+
+/* FSI status get left side briefing data */
+static inline int fsi_sstat_bdl(u32 x)
+{
+ return (x >> FSI_SSTAT_BDL_SHIFT) & FSI_SSTAT_BDL_MASK;
+}
+
+/* FSI status get CRC counter */
+static inline int fsi_sstat_crc(u32 x)
+{
+ return (x >> FSI_SSTAT_CRC_SHIFT) & FSI_SSTAT_CRC_MASK;
+}
+
+/*
+ * FSI slave local bus access register SLBUS
+ */
+#define FSI_SLBUS_FLBO 0x80000000 /* Force local bus ownership */
+#define FSI_SLBUS_RLBA 0x40000000 /* Request local bus access */
+#define FSI_SLBUS_RLBO_SHIFT 28 /* Release local bus shift */
+#define FSI_SLBUS_RLBO_MASK 3 /* Release local bus mask */
+#define FSI_SLBUS_RLBR 0x08000000 /* Reset local bus req */
+#define FSI_SLBUS_BLBA_SHIFT 16 /* Block local bus acc shift */
+#define FSI_SLBUS_BLBA_MASK 0xff /* Block local bus acc mask */
+#define FSI_SLBUS_BLBA 0xff /* Block local bus acc */
+#define FSI_SLBUS_UBLBA 0xec /* Unblock local bus access */
+#define FSI_SLBUS_RESERVE_MASK 0xf8ff0000 /* Mask off reserved bits */
+
+/* Release local bus */
+static inline u32 fsi_slbus_rlbo(int side)
+{
+ return (side & FSI_SLBUS_RLBO_MASK) << FSI_SLBUS_RLBO_SHIFT;
+}
+
+/* Block local bus access */
+static inline u32 fsi_slbus_blba(int side)
+{
+ return (side & FSI_SLBUS_BLBA_MASK) << FSI_SLBUS_BLBA_SHIFT;
+}
+
+/* FSI Slave Error Reset Register SRES */
+#define FSI_SRES_RFS 0x80000000 /* Reset FSI slave */
+#define FSI_SRES_REFS 0x40000000 /* Reset Errors FSI slave */
+#define FSI_SRES_RLBE 0x20000000 /* Reset Local bus engs slave */
+#define FSI_SRES_RESERVE_MASK 0x1fffffff /* Mask off reserved bits */
+
+int slave_readreg(struct fsimaster *, void *, u32 *, u32);
+int slave_writereg(struct fsimaster *, void *, u32, u32);
+int slave_irqclear(struct fsimaster *, void *, u32, u32);
+int p8_cfam_fixup(struct fsicfam *, int);
+u32 xmp8_srsim_mask(int);
+
+#endif /* DRIVERS_FSISLAVE_H */
diff --git a/drivers/fsi/ldm.c b/drivers/fsi/ldm.c
new file mode 100644
index 0000000..4a2f90b
--- /dev/null
+++ b/drivers/fsi/ldm.c
@@ -0,0 +1,29 @@
+/*
+ * FSI interface to the LDM
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * Christopher Bostic <cbostic@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include "fsi.h"
+#include "fsi_private.h"
+
+/*
+ * Register a FSI device with the Linux device model
+ */
+int fsidev_register_nolock(struct fsidevice *fsidev,
+ struct device_attribute **ap)
+{
+ return 0;
+}
+
+int fsidev_register(struct fsidevice *fsidev, struct device_attribute **ap)
+{
+ return 0;
+}
+EXPORT_SYMBOL(fsidev_register);
diff --git a/drivers/fsi/readwrite.c b/drivers/fsi/readwrite.c
new file mode 100644
index 0000000..33d972c
--- /dev/null
+++ b/drivers/fsi/readwrite.c
@@ -0,0 +1,34 @@
+/*
+ * FSI I/O accesses
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * Christopher Bostic <cbostic@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include "fsi.h"
+#include "fsi_private.h"
+#include "fsimaster.h"
+
+int fsi_readw_int(struct fsimaster *master, u32 pa, u32 *value)
+{
+ return 0;
+}
+
+int fsi_writew_int(struct fsimaster *master, u32 pa, u32 value)
+{
+ return 0;
+}
+
+/*
+ * Send out a BREAK command on a given link - Resets the logic of any slaves
+ * present
+ */
+int fsi_sendbreak(struct fsimaster *master, u32 cfam_base, int linkno)
+{
+ return 0;
+}
--
1.8.2.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH linux v5 5/7] drivers/fsi: Add FSI bus type and hook into LDM
2016-08-24 19:54 [PATCH linux v5 0/7] Introducing the FSI device driver christopher.lee.bostic
` (3 preceding siblings ...)
2016-08-24 19:54 ` [PATCH linux v5 4/7] drivers/fsi: Add initial FSI link buildup christopher.lee.bostic
@ 2016-08-24 19:54 ` christopher.lee.bostic
[not found] ` <CACPK8XcKuNAdrCiDuXpj5QgM+_U_+7hGKZd0ueZEGPcuurL=1g@mail.gmail.com>
2016-08-24 19:54 ` [PATCH linux v5 6/7] drivers/fsi: Add FSI Bus Support for Clients christopher.lee.bostic
` (2 subsequent siblings)
7 siblings, 1 reply; 19+ messages in thread
From: christopher.lee.bostic @ 2016-08-24 19:54 UTC (permalink / raw)
To: openbmc
From: Chris Bostic <cbostic@us.ibm.com>
Add FSI bus type. Add fsi device registration hooks into the LDM
Provide bus match/probe/remove/etc... callbacks for the LDM to invoke.
Signed-off-by: Chris Bostic <cbostic@us.ibm.com>
---
drivers/fsi/fsi.h | 42 ++++++++++++++++
drivers/fsi/fsiinit.c | 6 +++
drivers/fsi/ldm.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 184 insertions(+)
diff --git a/drivers/fsi/fsi.h b/drivers/fsi/fsi.h
index b723208..67d4666 100644
--- a/drivers/fsi/fsi.h
+++ b/drivers/fsi/fsi.h
@@ -28,6 +28,20 @@ struct fsi_engine_id {
u8 engine_vendor;
};
+/*
+ * Bit fields to search for device/driver match. A driver may handle several
+ * engines. If a driver handles all versions, just specify the type and
+ * set match_flags to FSI_ENGINE_ID_MATCH_TYPE.
+ * If a driver handles only certain versions, specify type and engine and
+ * set match_flags to FSI_ENGINE_ID_MATCH_TYPE | FSI_ENGINE_ID_MATCH_VERSION.
+ * Set the engine_vendor identifier and FSI_ENGINE_ID_MATCH_VENDOR if a
+ * certain vendor has to be supported.
+ */
+#define FSI_ENGINE_ID_MATCH_NONE 0 /* Last entry in chain */
+#define FSI_ENGINE_ID_MATCH_TYPE 1 /* Match the type */
+#define FSI_ENGINE_ID_MATCH_VERSION 2 /* Match the version */
+#define FSI_ENGINE_ID_MATCH_VENDOR 4 /* Match the vendor */
+
/* Location information for a FSI device */
struct fsimap {
u8 link; /* Master link # */
@@ -40,6 +54,18 @@ struct fsimap {
u16 kb_off; /* CFAM config table offset data */
};
+#define FSI_DEV_MEMRES 1 /* Physical address of device */
+#define FSI_DEV_IRQRES 2 /* IRQ resource */
+#define FSI_DEV_VARES 3 /* Virtual address of device */
+#define FSI_DEV_NONE 4 /* Empty indicator */
+#define FSI_DEV_PSEUDO 5 /* Pseudo engine */
+#define FSI_DEV_IRQ 6 /* Has an IRQ */
+#define FSI_DEV_ACTIVE 7 /* Is activated */
+#define FSI_DEV_RLS_SLV 8 /* Release slave */
+#define FSI_DEV_PROBE_OK 9 /* Probe succeeded */
+#define FSI_DEV_PROBE_ERR 10 /* Probe failed */
+
+
struct fsidevice {
struct fsi_engine_id id; /* Engine type/version */
u32 irq_start; /* IRQ Number */
@@ -47,6 +73,22 @@ struct fsidevice {
struct fsidevice *parent; /* Parent of this device */
struct device dev; /* LDM entry for bus */
struct fsimap map; /* Address & location info */
+ unsigned long state; /* flags for state */
};
+#define to_fsidevice(x) container_of((x), struct fsidevice, dev)
+
+/*
+ * FSI driver type
+ */
+struct fsidriver {
+ struct module *owner; /* Module owner */
+ struct fsi_engine_id *idlist; /* List of IDs, terminated by */
+ /* FSI_ENGINE_ID_MATCH_NONE */
+ struct device_driver driver; /* LDM hook */
+ int (*reset)(void *); /* Client defined reset method */
+};
+
+#define to_fsidriver(x) container_of((x), struct fsidriver, driver)
+
#endif /* DRIVERS_FSI_H */
diff --git a/drivers/fsi/fsiinit.c b/drivers/fsi/fsiinit.c
index eaa3582..d83992e 100644
--- a/drivers/fsi/fsiinit.c
+++ b/drivers/fsi/fsiinit.c
@@ -53,6 +53,12 @@ static int fsi_start(void)
goto err;
}
fsimaster_start(&fsidd.pri_master);
+
+ if (fsibus_init()) { /* Create the FSI bus */
+ rc = -ENFILE;
+ goto err;
+ }
+
dev_dbg(&fsidd.dev, "FSI DD v%d installation ok\n", FSIDD_VERNO);
return rc;
diff --git a/drivers/fsi/ldm.c b/drivers/fsi/ldm.c
index 4a2f90b..9fe10b3 100644
--- a/drivers/fsi/ldm.c
+++ b/drivers/fsi/ldm.c
@@ -10,6 +10,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/blkdev.h>
#include "fsi.h"
#include "fsi_private.h"
@@ -27,3 +28,138 @@ int fsidev_register(struct fsidevice *fsidev, struct device_attribute **ap)
return 0;
}
EXPORT_SYMBOL(fsidev_register);
+
+/*
+ * FSI bus functions.
+ */
+
+/*
+ * Call a client's probe function if available
+ */
+static int fsi_bus_probe(struct device *dev)
+{
+ struct fsidevice *fsidev = to_fsidevice(dev);
+ struct device_driver *drv = dev->driver;
+ struct fsidriver *fsidrv = to_fsidriver(dev->driver);
+ int rc = -ENOENT;
+
+ dev_dbg(dev, "probe >> fsidrv:%p probe:%p resume:%p\n",
+ fsidrv, drv->probe, drv->resume);
+
+ if (!drv->probe)
+ goto err;
+ rc = drv->probe(dev);
+ dev_dbg(dev, "drv->probe rc:%d\n", rc);
+ if (rc) {
+ /* Device unsupported or error in probe call back */
+ if (rc != -ENODEV && rc != -ENXIO && rc != -ENOLINK) {
+ set_bit(FSI_DEV_PROBE_ERR, &fsidev->state);
+ goto err;
+ }
+ }
+ set_bit(FSI_DEV_PROBE_OK, &fsidev->state);
+ rc = 1;
+
+ if (rc > 0 && drv->resume) {
+ rc = drv->resume(dev);
+ dev_dbg(dev, "probe resume rc:%d\n", rc);
+ }
+ rc = 0;
+err:
+ dev_dbg(dev, "probe << rc:%d\n", rc);
+ return rc;
+
+}
+
+static int fsi_bus_remove(struct device *dev)
+{
+ dev_dbg(dev, "remove:%p %s\n", dev, dev_name(dev));
+ return 0;
+}
+
+static void fsi_bus_shutdown(struct device *dev)
+{
+ dev_dbg(dev, "shutdown:%p %s\n", dev, dev_name(dev));
+}
+
+/*
+ * Check if a particular engine matches the driver's list of supported devices.
+ */
+static int fsi_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct fsidevice *fsidev = to_fsidevice(dev);
+ struct fsidriver *fsidrv = to_fsidriver(drv);
+ int match_ok = 0;
+ struct fsi_engine_id *idlist = fsidrv->idlist;
+
+ for (; idlist->match_flags != FSI_ENGINE_ID_MATCH_NONE; ++idlist) {
+ match_ok = 0;
+
+ if ((idlist->match_flags & FSI_ENGINE_ID_MATCH_TYPE) != 0
+ && fsidev->id.engine_type == idlist->engine_type)
+ match_ok = 1;
+
+ if (match_ok
+ && (idlist->match_flags & FSI_ENGINE_ID_MATCH_VERSION) != 0)
+ match_ok =
+ fsidev->id.engine_version == idlist->engine_version;
+
+ if (match_ok
+ && (idlist->match_flags & FSI_ENGINE_ID_MATCH_VENDOR) != 0)
+ match_ok =
+ fsidev->id.engine_vendor == idlist->engine_vendor;
+
+ if (match_ok)
+ break;
+ }
+ dev_dbg(dev,
+ "match type:%02x version:%d vendor:%d match_ok:%d\n",
+ fsidev->id.engine_type, fsidev->id.engine_version,
+ fsidev->id.engine_vendor, match_ok);
+
+ return match_ok;
+}
+
+
+static int fsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+
+ dev_dbg(dev, "%s device:%p\n", dev_name(dev), dev);
+ if (MAJOR(dev->devt)) {
+ if (add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)))
+ return -ENOMEM;
+ if (add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)))
+ return -ENOMEM;
+ }
+
+ /* Add bus name of physical device */
+ if (dev->bus) {
+ if (add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name))
+ return -ENOMEM;
+ }
+
+ /* Add driver name of physical device */
+ if (dev->driver) {
+ if (add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name))
+ return -ENOMEM;
+ }
+ return 0;
+};
+
+struct bus_type fsi_bus_type = {
+ .name = "fsi",
+ .match = fsi_bus_match,
+ .uevent = fsi_bus_uevent,
+ .probe = fsi_bus_probe,
+ .remove = fsi_bus_remove,
+ .shutdown = fsi_bus_shutdown,
+};
+EXPORT_SYMBOL(fsi_bus_type);
+
+/*
+ * Create and install the FSI bus
+ */
+int fsibus_init(void)
+{
+ return bus_register(&fsi_bus_type);
+}
--
1.8.2.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH linux v5 6/7] drivers/fsi: Add FSI Bus Support for Clients
2016-08-24 19:54 [PATCH linux v5 0/7] Introducing the FSI device driver christopher.lee.bostic
` (4 preceding siblings ...)
2016-08-24 19:54 ` [PATCH linux v5 5/7] drivers/fsi: Add FSI bus type and hook into LDM christopher.lee.bostic
@ 2016-08-24 19:54 ` christopher.lee.bostic
2016-08-24 19:54 ` [PATCH linux v5 7/7] drivers/fsi: Add CFAM scanning function christopher.lee.bostic
2016-09-02 5:05 ` [PATCH linux v5 0/7] Introducing the FSI device driver Joel Stanley
7 siblings, 0 replies; 19+ messages in thread
From: christopher.lee.bostic @ 2016-08-24 19:54 UTC (permalink / raw)
To: openbmc
From: Chris Bostic <cbostic@us.ibm.com>
Provide means for a client to register with an FSI bus and get
notifications of hot plug events. A client is a device driver that
needs access to a physical FSI bus in order to communicate with
hardware it controls. Utilities added to allow client to retrieve
resource information on its hardware.
Signed-off-by: Chris Bostic <cbostic@us.ibm.com>
---
drivers/fsi/fsi.h | 15 +++++
drivers/fsi/fsicfam.h | 2 +
drivers/fsi/fsiinit.c | 8 +++
drivers/fsi/ldm.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++-
drivers/fsi/readwrite.c | 4 ++
5 files changed, 188 insertions(+), 2 deletions(-)
diff --git a/drivers/fsi/fsi.h b/drivers/fsi/fsi.h
index 67d4666..f0ed5b7 100644
--- a/drivers/fsi/fsi.h
+++ b/drivers/fsi/fsi.h
@@ -65,6 +65,10 @@ struct fsimap {
#define FSI_DEV_PROBE_OK 9 /* Probe succeeded */
#define FSI_DEV_PROBE_ERR 10 /* Probe failed */
+struct fsi_resource {
+ u32 start; /* Start of range */
+ u32 end; /* End of range */
+};
struct fsidevice {
struct fsi_engine_id id; /* Engine type/version */
@@ -91,4 +95,15 @@ struct fsidriver {
#define to_fsidriver(x) container_of((x), struct fsidriver, driver)
+int fsidev_register(struct fsidevice *, struct device_attribute **);
+void fsidev_unregister(struct fsidevice *);
+int fsi_get_resource(struct fsidevice *, int, struct fsi_resource *);
+char *fsidevice_name(struct fsidevice *, const char *, const char *,
+ char *, size_t);
+int fsidevice_get_minor(struct fsidevice *);
+int fsidrv_register(struct fsidriver *);
+void fsidrv_unregister(struct fsidriver *);
+void fsi_lock_mutex(void);
+void fsi_unlock_mutex(void);
+
#endif /* DRIVERS_FSI_H */
diff --git a/drivers/fsi/fsicfam.h b/drivers/fsi/fsicfam.h
index dde7036..8ccff5c 100644
--- a/drivers/fsi/fsicfam.h
+++ b/drivers/fsi/fsicfam.h
@@ -43,4 +43,6 @@ struct fsicfam { /* CFAM internal structure */
int fsi_cfamirq_request(int, struct fsicfam *);
void fsi_cfamirq_free(struct fsicfam *);
+#define FSI_CFAM_SLAVEIDX 2 /* Slave engine */
+
#endif /* DRIVERS_FSICFAM_H */
diff --git a/drivers/fsi/fsiinit.c b/drivers/fsi/fsiinit.c
index d83992e..4941062 100644
--- a/drivers/fsi/fsiinit.c
+++ b/drivers/fsi/fsiinit.c
@@ -34,6 +34,14 @@ struct fsidd fsidd = { /* FSI device driver structure definition */
.major = MKDEV(FSIDD_MAJOR, 0),
};
+void fsi_lock_mutex(void)
+{
+}
+
+void fsi_unlock_mutex(void)
+{
+}
+
static int fsi_start(void)
{
int rc = 0;
diff --git a/drivers/fsi/ldm.c b/drivers/fsi/ldm.c
index 9fe10b3..cb6679f 100644
--- a/drivers/fsi/ldm.c
+++ b/drivers/fsi/ldm.c
@@ -13,6 +13,48 @@
#include <linux/blkdev.h>
#include "fsi.h"
#include "fsi_private.h"
+#include "fsicfam.h"
+
+/*
+ * /sys/devices/ < name > format:
+ *
+ * fsi-LL.C.EE
+ *
+ * Where:
+ * L = link, C = CFAM, E = engine
+ *
+ * TODO: expand for cascaded and hub masters
+ */
+static void myname(struct fsidevice *fsidev)
+{
+ if (dev_name(&fsidev->dev))
+ return;
+
+ dev_set_name(&fsidev->dev, "fsi-%02d.%d.%02d",
+ fsidev->map.link, fsidev->map.cfam, fsidev->map.eng);
+}
+
+/*
+ * Unregister a FSI device with the Linux device model
+ */
+void fsidev_unregister_nolock(struct fsidevice *fsidev)
+{
+
+ dev_dbg(&fsidev->dev, "fsidev_unregister fsidev:%p\n", fsidev);
+ if (!test_and_clear_bit(FSI_DEV_ACTIVE, &fsidev->state)) {
+ dev_dbg(&fsidev->dev, "fsidev_unregister build incomplete\n");
+ return;
+ }
+ device_unregister(&fsidev->dev);
+}
+
+void fsidev_unregister(struct fsidevice *fsidev)
+{
+ fsi_lock_mutex();
+ fsidev_unregister_nolock(fsidev);
+ fsi_unlock_mutex();
+}
+EXPORT_SYMBOL(fsidev_unregister);
/*
* Register a FSI device with the Linux device model
@@ -20,15 +62,101 @@
int fsidev_register_nolock(struct fsidevice *fsidev,
struct device_attribute **ap)
{
- return 0;
+ int rc, slave_idx;
+
+ dev_dbg(&fsidev->dev, "register >> %d.%d.%d\n",
+ fsidev->map.link, fsidev->map.cfam, fsidev->map.eng);
+ myname(fsidev);
+
+ rc = device_register(&fsidev->dev);
+ if (rc) {
+ dev_dbg(&fsidev->dev, "register dev_register error:%d\n", rc);
+ if (fsidev->dev.release)
+ fsidev->dev.release(&fsidev->dev);
+ return rc;
+ }
+ set_bit(FSI_DEV_ACTIVE, &fsidev->state);
+ if (test_bit(FSI_DEV_PROBE_ERR, &fsidev->state)) {
+ dev_dbg(&fsidev->dev, "register dev probe error\n");
+ slave_idx = (fsidev->map.eng == FSI_CFAM_SLAVEIDX);
+ rc = slave_idx ? -ENODEV : 0;
+ fsidev_unregister_nolock(fsidev);
+ return rc;
+ }
+ dev_dbg(&fsidev->dev, "register << %d.%d.%d success\n",
+ fsidev->map.link, fsidev->map.cfam, fsidev->map.eng);
+
+ return rc;
}
int fsidev_register(struct fsidevice *fsidev, struct device_attribute **ap)
{
- return 0;
+ int rc;
+
+ fsi_lock_mutex();
+ rc = fsidev_register_nolock(fsidev, ap);
+ fsi_unlock_mutex();
+
+ return rc;
}
EXPORT_SYMBOL(fsidev_register);
+int fsi_get_resource(struct fsidevice *fsidev, int idx,
+ struct fsi_resource *res)
+{
+ switch (idx) {
+ case FSI_DEV_IRQRES:
+ if (fsidev->irq_start == 0)
+ res->end = 0;
+ else
+ res->end = fsidev->irq_start + fsidev->irq_range - 1;
+ break;
+ case FSI_DEV_MEMRES:
+ res->start = fsidev->map.va;
+ res->end = res->start + fsidev->map.kb * FSI_ENGINE_SIZE - 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(fsi_get_resource);
+
+/*
+ * Return the fsidevice full engine name.
+ * Name consists of:
+ * - prefix
+ * - link number
+ * - a dot '.'
+ * - cfam number
+ * - a dot '.'
+ * - engine number
+ * - postfix (client's choosing)
+ *
+ * Returns NULL if buffer space is insufficient.
+ */
+char *fsidevice_name(struct fsidevice *fsidev, const char *prefix,
+ const char *postfix, char *buf, size_t len)
+{
+ int size;
+ struct fsimap *map = &fsidev->map;
+
+ size = snprintf(buf, len, "%sL%02dC%dE%02dP%s",
+ prefix, map->link, map->cfam, map->eng, postfix);
+
+ return (size >= len) ? NULL : buf;
+}
+EXPORT_SYMBOL(fsidevice_name);
+
+/*
+ * Retrieve minor number for the FSI device
+ */
+int fsidevice_get_minor(struct fsidevice *fsidev)
+{
+ return MINOR(fsidev->dev.devt);
+}
+EXPORT_SYMBOL(fsidevice_get_minor);
+
/*
* FSI bus functions.
*/
@@ -163,3 +291,32 @@ int fsibus_init(void)
{
return bus_register(&fsi_bus_type);
}
+
+/*
+ * Unregister a client FSI driver from the system
+ */
+void fsidrv_unregister(struct fsidriver *fsidrv)
+{
+ fsidrv->reset = NULL;
+ driver_unregister(&fsidrv->driver);
+}
+EXPORT_SYMBOL(fsidrv_unregister);
+
+/*
+ * Register a client FSI driver with the system
+ */
+int fsidrv_register(struct fsidriver *fsidrv)
+{
+ int rc = 0;
+
+ if (fsidrv->idlist == NULL)
+ return -EINVAL;
+ if (!fsidrv->driver.owner)
+ fsidrv->driver.owner = fsidrv->owner;
+
+ fsidrv->driver.bus = &fsi_bus_type;
+ rc = driver_register(&fsidrv->driver);
+
+ return rc;
+}
+EXPORT_SYMBOL(fsidrv_register);
diff --git a/drivers/fsi/readwrite.c b/drivers/fsi/readwrite.c
index 33d972c..3427e52 100644
--- a/drivers/fsi/readwrite.c
+++ b/drivers/fsi/readwrite.c
@@ -14,6 +14,10 @@
#include "fsi_private.h"
#include "fsimaster.h"
+/*
+ * Read/write functions to be used only by the FSI driver itself. FSI clients
+ * will use separate interfaces
+ */
int fsi_readw_int(struct fsimaster *master, u32 pa, u32 *value)
{
return 0;
--
1.8.2.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH linux v5 7/7] drivers/fsi: Add CFAM scanning function
2016-08-24 19:54 [PATCH linux v5 0/7] Introducing the FSI device driver christopher.lee.bostic
` (5 preceding siblings ...)
2016-08-24 19:54 ` [PATCH linux v5 6/7] drivers/fsi: Add FSI Bus Support for Clients christopher.lee.bostic
@ 2016-08-24 19:54 ` christopher.lee.bostic
2016-09-02 5:05 ` [PATCH linux v5 0/7] Introducing the FSI device driver Joel Stanley
7 siblings, 0 replies; 19+ messages in thread
From: christopher.lee.bostic @ 2016-08-24 19:54 UTC (permalink / raw)
To: openbmc
From: Chris Bostic <cbostic@us.ibm.com>
Scan a CFAM's configuration table for basic information on its ID and
capabilities. A 'Common Field replaceable unit Access Macro' (CFAM) is
a target device an FSI master can communicate with. Each CFAM contains
at its base address offset 0 a configuration table. This table contains
data on what type of CFAM it is, what its address range is as well as
what types of engines it contains. An I2C master, for example, is a type
of engine that can be found on various CFAMs.
Signed-off-by: Chris Bostic <cbostic@us.ibm.com>
---
drivers/fsi/build.c | 774 +++++++++++++++++++++++++++++++++++++++++++++-
drivers/fsi/fsi.h | 25 ++
drivers/fsi/fsi_private.h | 5 +
drivers/fsi/fsicfam.h | 113 +++++++
drivers/fsi/fsimaster.c | 40 +++
drivers/fsi/fsimaster.h | 1 +
drivers/fsi/fsislave.h | 11 +
drivers/fsi/ldm.c | 25 ++
drivers/fsi/readwrite.c | 91 +++++-
9 files changed, 1076 insertions(+), 9 deletions(-)
diff --git a/drivers/fsi/build.c b/drivers/fsi/build.c
index c9a31c0..ccb82b3 100644
--- a/drivers/fsi/build.c
+++ b/drivers/fsi/build.c
@@ -14,11 +14,13 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/io.h>
+#include <linux/mm.h>
#include "fsi.h"
#include "fsi_private.h"
#include "fsimaster.h"
#include "fsicfam.h"
#include "fsilink.h"
+#include "fsislave.h"
static void link_release(struct device *devp)
{
@@ -60,8 +62,761 @@ static struct fsilink *link_add(struct fsimaster *master, int no)
return link ? : ERR_PTR(rc);
}
+/*
+ * When a CFAM is gone delete the assigned resources. Called when a CFAM
+ * fsidevice is unregistered _and_ its refcount drops to zero (meaning all
+ * child devices are gone too).
+ */
+static void cfam_release(struct device *dev)
+{
+ struct fsidevice *fsidev = to_fsidevice(dev);
+ struct fsicfam *cfam = to_fsicfam(fsidev);
+
+ dev_dbg(&cfam->fsidev.dev, "cfam_release: base:%08X\n",
+ cfam->fsidev.map.addr);
+
+ kfree(cfam);
+}
+
+/*
+ * Allocate memory for and initialize a CFAM structure
+ */
+static struct fsicfam *cfam_init(struct fsilink *link, int id)
+{
+ struct fsimaster *master = link->master;
+ struct fsicfam *cfam = NULL;
+ u32 addr = fsimaster_cfam2pa(master, link->linkno, id);
+
+ dev_dbg(&link->fsidev.dev, "cfam_init >> link:%d addr:%08X id:%d\n",
+ link->linkno, addr, id);
+
+ cfam = kmalloc(sizeof(struct fsicfam), GFP_KERNEL);
+ if (cfam == NULL)
+ return NULL;
+
+
+ cfam->fsidev.map.addr = addr;
+ cfam->fsidev.map.va = link->id3_addr;
+ cfam->fsidev.map.kb = fsimaster_cfamsz(master) / FSI_ENGINE_SIZE;
+ cfam->fsidev.id.engine_type = FSI_ENGID_CFAM;
+ cfam->id = id;
+ dev_set_name(&cfam->fsidev.dev, "cfam-%d.%d", link->linkno, cfam->id);
+ cfam->fsidev.dev.bus = NULL; /* CFAMs not on fsibus */
+ cfam->fsidev.dev.parent = &link->fsidev.dev;
+ cfam->fsidev.parent = &link->fsidev;
+ cfam->fsidev.dev.release = cfam_release;
+ cfam->fsidev.irq_start = 0;
+ cfam->fsidev.irq_range = 0;
+
+ return cfam;
+}
+
+/*
+ * Calculate a CRC of type x^4+x^2+x^1+1 from the provided source
+ */
+u8 fsi_crc4_gen(u8 *source, int length)
+{
+ u8 result[4] = {0, };
+ u8 feedback = 0;
+ u8 bb = length / 8;
+ u8 rem = length % 8;
+ u8 act;
+ u8 crc4 = 0;
+ int b, i;
+
+ for (b = 0; b < bb; b++) {
+ for (i = 7; i >= 0; i--) {
+ act = *(source + b);
+ feedback = result[3] ^ ((act >> i) & 1);
+ result[3] = result[2];
+ result[2] = result[1] ^ feedback;
+ result[1] = result[0] ^ feedback;
+ result[0] = feedback;
+ }
+ }
+ act = *(source + bb);
+ for (i = 0; i < rem; i++) {
+ feedback = result[3] ^ ((act >> (7 - i)) & 1);
+ result[3] = result[2];
+ result[2] = result[1] ^ feedback;
+ result[1] = result[0] ^ feedback;
+ result[0] = feedback;
+ }
+ if (result[3])
+ crc4 |= 8;
+ if (result[2])
+ crc4 |= 4;
+ if (result[1])
+ crc4 |= 2;
+ if (result[0])
+ crc4 |= 1;
+
+ return crc4;
+}
+
+void fsi_check_crc4(struct fsicfam *cfam, u32 config_entry)
+{
+ u8 crc = config_entry & 0xf, my_crc, frame[4];
+
+ frame[0] = (config_entry >> 24) & 0xff;
+ frame[1] = (config_entry >> 16) & 0xff;
+ frame[2] = (config_entry >> 8) & 0xff;
+ frame[3] = config_entry & 0xf0; /* Zero out CRC bits */
+ my_crc = fsi_crc4_gen(frame, 28);
+ if (crc != my_crc)
+ dev_dbg(&cfam->fsidev.dev,
+ "crc mismatch! entry:%08X crc:%02X calculated:%02X\n",
+ config_entry, crc, my_crc);
+}
+
+/*
+ * Return true if this engine is recognized
+ */
+static int valid_engine(int type, int version)
+{
+ return ((type >= FSI_ENGID_FIRST && type <= FSI_ENGID_LAST) ||
+ type == FSI_ENGID_PS_CLOCK);
+}
+
+/* Is this configuration word for a port ? */
+static int fsi_is_port_slot(u32 config_word)
+{
+ int type = fsi_cfg_type(config_word);
+
+ return (type == FSI_ENGID_CMFSI_PORT || type == FSI_ENGID_HMFSI_PORT);
+}
+
+/*
+ * Read the configuration table and return the number of engines and total
+ * address space needed. Unknown engine version causes the CFAM to be ignored.
+ */
+static int cfam_scan(struct fsicfam *cfam)
+{
+ int kb, more, type, version, idx = 0;
+ u32 addr = cfam->fsidev.map.addr;
+ u32 *config_entry = cfam->cfgtab;
+ u16 *to_map = &cfam->pages;
+ bool valid = false;
+
+ *to_map = 0;
+ do {
+ if (fsi_readw_int(cfam->master, addr, config_entry)) {
+ idx = -EIO;
+ goto bad;
+ }
+ if (!idx)
+ dev_dbg(&cfam->fsidev.dev, "addr:%08X idx:%d word:%08X\n",
+ addr, idx, *config_entry);
+ fsi_check_crc4(cfam, *config_entry);
+ type = fsi_cfg_type(*config_entry);
+ version = fsi_cfg_version(*config_entry);
+ if (idx)
+ kb = fsi_cfg_slot(*config_entry);
+ else
+ kb = 1; /* Configuration space always 1 slot */
+ *to_map += kb;
+ dev_dbg(&cfam->fsidev.dev,
+ "scan: type:%02X v:%02X kb:%d tomap:%d word:%08X\n",
+ type, version, kb, *to_map, *config_entry);
+
+ /* 1. Word is CFAM identifier, type == 0 is empty slot */
+ valid = valid_engine(type, version);
+ if (idx && (type != FSI_ENGID_NONE) && !valid) {
+ idx = -ENODEV;
+ dev_dbg(&cfam->fsidev.dev, "scan: unknown type:%02X\n",
+ type);
+ goto bad;
+ }
+ more = fsi_cfg_next(*config_entry);
+ addr += sizeof(u32);
+ ++config_entry;
+
+ } while (++idx < FSI_MAX_ENGINES && more);
+
+ dev_dbg(&cfam->fsidev.dev, "scan: idx prior empty slots:%d\n", idx);
+
+ /*
+ * TODO: Check for assumptions on no empty engine slots on this CFAM.
+ * Adjust the amount of memory to map to account for those engines
+ * Not requiring any space of their own.
+ *
+ * TODO: Instead of taking away, add this check above where we're adding
+ * up amount of memory space needed.
+ */
+ while (fsi_cfg_type(*--config_entry) == FSI_ENGID_NONE ||
+ fsi_is_port_slot(*config_entry)) {
+ --idx;
+ kb = fsi_cfg_slot(*config_entry);
+ *to_map -= kb;
+ }
+ *to_map = PAGE_ALIGN(*to_map * FSI_ENGINE_SIZE) / PAGE_SIZE;
+bad:
+ dev_dbg(&cfam->fsidev.dev, "scan: return:%d to_map:%d\n", idx, *to_map);
+ return idx;
+}
+
+/*
+ * Set CFAM to a given ID and initialize slave mode to general defaults
+ */
+static int setid(struct fsicfam *cfam, u32 addr, int id)
+{
+ u32 smode = FSI_SMODE_ECRC | fsi_smode_echodly(0xf)
+ | fsi_smode_senddly(0xf)
+ | fsi_smode_lbcrr(1)
+ | fsi_smode_sid(id);
+
+ return fsi_writew_int(cfam->master, addr + FSI_SMODE, smode);
+}
+
+/*
+ * Set CFAM id to the target value.
+ * Send a reset commant to a slave, also clear mail delivered status.
+ * Enable/Disable auxiliary port to allow clocks on successor CFAM in chain -
+ * necessary to give the next CFAM (if one exists) a chance to get into a known
+ * state. Note that as of now there is minimal support for extra CFAMs on a
+ * link.
+ */
+static int cfam_setup(struct fsilink *link, u32 id3_addr, struct fsicfam *cfam)
+{
+ u32 slave_addr = id3_addr + FSI_SLAVE0_OFFSET;
+ u32 smode;
+ int rc;
+ int id = cfam->id;
+
+ /*
+ * CFAM will now appear at different address if we change its link ID
+ * here
+ */
+ rc = setid(cfam, slave_addr, id);
+ if (rc) {
+ dev_dbg(&link->fsidev.dev, "cfam_setup setid fail rc:%d\n", rc);
+ goto out;
+ }
+
+ dev_dbg(&link->fsidev.dev, "cfam_setup slave addr:%08X\n", slave_addr);
+ rc = fsi_readw_int(cfam->master, slave_addr + FSI_SMODE, &smode);
+ if (rc)
+ goto out;
+
+ rc = fsi_writew_int(cfam->master, slave_addr + FSI_SMODE,
+ smode | FSI_SMODE_EAP);
+ if (rc)
+ goto out;
+ udelay(100);
+ rc = fsi_writew_int(cfam->master, slave_addr + FSI_SMODE, smode);
+ if (rc)
+ goto out;
+
+ rc = fsi_writew_int(cfam->master, slave_addr + FSI_SRES, FSI_SRES_RFS);
+ if (rc)
+ goto out;
+
+ rc = fsi_writew_int(cfam->master, slave_addr + FSI_SCISC,
+ FSI_SSI_HPE | FSI_SSI_MDL | FSI_SSI_MDR);
+out:
+ dev_dbg(&link->fsidev.dev, "cfam_setup << rc:%d\n", rc);
+
+ return rc;
+}
+
+
+/*
+ * Allocate space to cover all engine address range on a CFAM
+ */
+static int cfam_iomem(struct fsimaster *master, int link, struct fsicfam *cfam)
+{
+ /*
+ * TODO: For now the address space is virtualized since there is no
+ * fsimaster defined in hardware. Will require ioremap once one is
+ * available.
+ */
+
+ return 0;
+}
+
+/*
+ * Create a single CFAM, read its config space, allocate memory and set id
+ */
+static struct fsicfam *cfam_create(struct fsilink *link, int id)
+{
+ int rc = 0;
+ struct fsicfam *cfam;
+
+ dev_dbg(&link->fsidev.dev, "cfam_create >> link:%d cfam:%d\n",
+ link->linkno, id);
+
+ cfam = cfam_init(link, id);
+ if (cfam == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = cfam_scan(cfam);
+ if (rc < 0) {
+ kfree(cfam);
+ goto out;
+ }
+
+ rc = cfam_iomem(link->master, link->linkno, cfam);
+ if (rc) {
+ kfree(cfam);
+ goto out;
+ }
+
+ if (cfam_setup(link, link->id3_addr, cfam)) {
+ cfam_release(&cfam->fsidev.dev);
+ rc = -EIO;
+ goto out;
+ }
+ link->cfams[id] = cfam;
+out:
+ if (rc)
+ cfam = ERR_PTR(rc);
+ dev_dbg(&link->fsidev.dev, "cfam_create << link:%d cfam:%d rc:%d\n",
+ link->linkno, id, rc);
+
+ return cfam;
+}
+
+/*
+ * Switch on or off the auxiliary port control
+ */
+static int auxport(struct fsicfam *cfam, u32 addr, int onoff)
+{
+ u32 smode;
+ int rc;
+
+ addr += FSI_SLAVE0_OFFSET;
+ rc = fsi_readw_int(cfam->master, addr + FSI_SMODE, &smode);
+ if (rc)
+ return rc;
+ if (onoff)
+ smode |= FSI_SMODE_EAP;
+ else
+ smode &= ~FSI_SMODE_EAP;
+ rc = fsi_writew_int(cfam->master, addr + FSI_SMODE, smode);
+
+ return rc;
+}
+
+/*
+ * Disable predecessor AUX port in case of error building cascade
+ * Remove all CFAMs when auxport cannot be turned off.
+ */
+static void oomcfam(int i, struct fsilink *link)
+{
+ struct fsicfam *cfam = NULL;
+ struct fsimap *map = NULL;
+
+ if (i == 0)
+ return;
+
+ cfam = link->cfams[i-1];
+ map = &cfam->fsidev.map;
+ if (i > 0 && auxport(cfam, map->addr, 0)) {
+ while (--i >= 0) {
+ cfam_release(&link->cfams[i]->fsidev.dev);
+ link->cfams[i] = NULL;
+ }
+ link->cascade = 0;
+ } else
+ link->cascade = i;
+}
+
+/*
+ * Check if another CFAM is present on this link
+ */
+static int morecfam(u32 addr)
+{
+ /*
+ * TODO: Phase in multi CFAM per link support.
+ */
+ return 0;
+}
+
+/*
+ * Scan the slots of a new link and find any attached CFAMs.
+ * Return number found.
+ */
+static int findcfams(struct fsimaster *master, struct fsilink *link)
+{
+ int i, more, done = 0;
+ struct fsicfam *cfam;
+ u32 base = 0;
+
+ dev_dbg(&master->fsidev->dev, "findcfams >> link:%d\n", link->linkno);
+ link->top_cfam = 1;
+
+ for (i = 0; i < FSI_MAX_CASCADE && !done; ++i) {
+ cfam = cfam_create(link, i);
+ if (IS_ERR(cfam)) {
+ oomcfam(i, link);
+ break;
+ }
+ base = cfam->fsidev.map.addr;
+ if (i == FSI_MAX_CASCADE - 1)
+ more = 0;
+ else
+ more = morecfam(base);
+
+ if (more > 0) {
+ ++link->top_cfam;
+ dev_dbg(&master->fsidev->dev, "more:%d id:%d top:%d\n",
+ more, i, link->top_cfam);
+ if (auxport(cfam, base, 1)) {
+ done = i + 1;
+ link->cascade = done; /* Done scanning */
+ }
+ } else {
+ done = i + 1;
+ link->cascade = done;
+ }
+ }
+ dev_dbg(&master->fsidev->dev, "findcfams << found:%d top:%d link:%d\n",
+ link->cascade, link->top_cfam, link->linkno);
+
+ return link->cascade;
+}
+
+/*
+ * Register one CFAM with the LDM
+ */
+static int cfam_register(int id, struct fsicfam *cfam, int link)
+{
+ int rc;
+
+ dev_dbg(&cfam->fsidev.dev, "cfam_register >> id:%d link:%d\n",
+ id, link);
+
+ rc = fsidev_register_nolock(&cfam->fsidev, NULL);
+ if (rc)
+ cfam_release(&cfam->fsidev.dev);
+
+ return rc;
+}
+
+/*
+ * Register all newly disovered CFAMs with the LDM
+ */
+static int cfam_export(struct fsimaster *master, struct fsilink *link)
+{
+ int rc, i, j;
+
+ dev_dbg(&master->fsidev->dev, "cfam_export >>\n");
+
+ for (i = 0; i < link->cascade; ++i) {
+ struct fsicfam *cfam = link->cfams[i];
+
+ rc = cfam_register(master->myid, cfam, link->linkno);
+ if (rc) {
+ /* Delete allocated CFAMs not yet exported */
+ for (j = i + 1; j < link->cascade; ++j)
+ cfam_release(&link->cfams[j]->fsidev.dev);
+ link->cascade = i;
+ break;
+ }
+ }
+
+ dev_dbg(&master->fsidev->dev, "cfam_export << link:%d cascade:%d\n",
+ link->linkno, link->cascade);
+
+ return link->cascade;
+}
+
+/*
+ * Read in the configuration table header of this CFAM
+ */
+static void cfam_read_header(struct fsicfam *cfam)
+{
+ u32 header = cfam->cfgtab[FSI_CFAM_CFGIDX];
+
+ if (fsi_cfg_vpd(header)) {
+ cfam->ec_maj = fsi_cfg_ecmaj(header);
+ cfam->ec_min = fsi_cfg_ecmin(header);
+ } else {
+ cfam->ec_maj = 0;
+ cfam->ec_min = fsi_cfg_version(header);
+ }
+ cfam->chipid = fsi_cfg_type(header);
+}
+
+/*
+ * Called when fsidev_unregister() is performed on slave device and no users.
+ */
+static void slave_release(struct device *dev)
+{
+ struct fsidevice *fsidev = to_fsidevice(dev);
+ struct fsislave *slave = to_fsislave(fsidev);
+ struct fsicfam *cfam = to_fsicfam(fsidev->parent);
+
+ cfam->engines[fsidev->map.eng] = 0;
+ kfree(slave);
+}
+
+static void fsidev_release(struct device *dev)
+{
+ struct fsidevice *fsidev = to_fsidevice(dev);
+
+ dev_dbg(&fsidev->dev, "fsidev_release >> fsidev:%p\n", fsidev);
+ if (fsidev->parent &&
+ fsidev->parent->id.engine_type == FSI_ENGID_CFAM) {
+ /* If parent ic CFAM handle engines */
+ struct fsicfam *cfam = to_fsicfam(fsidev->parent);
+
+ cfam->engines[fsidev->map.eng] = NULL;
+ }
+}
+
+static struct fsidevice *fsidev_alloc(void)
+{
+ struct fsidevice *fsidev = kmalloc(sizeof(struct fsidevice),
+ GFP_KERNEL);
+
+ if (fsidev)
+ fsidev->dev.release = fsidev_release;
+
+ return fsidev;
+}
+
+static struct fsidevice *fsislave_alloc(void)
+{
+ struct fsislave *slave = kmalloc(sizeof(struct fsislave),
+ GFP_KERNEL);
+
+ if (!slave)
+ return NULL;
+ slave->fsidev.dev.release = slave_release;
+
+ return &slave->fsidev;
+}
+
+/*
+ * Find the offset in kilobytes from the start of the CFAM address space
+ * for a given engine.
+ */
+u32 fsi_get_eng_offset(struct fsicfam *cfam, int engine)
+{
+ u32 add = 1;
+ int i;
+
+ for (i = 1; i < engine; ++i)
+ add += fsi_cfg_slot(cfam->cfgtab[i]);
+
+ return add * FSI_ENGINE_SIZE;
+}
+
+static struct fsidevice *mkengine(int engine, struct fsicfam *cfam)
+{
+ struct fsidevice *fsidev = NULL;
+ u32 slot = cfam->cfgtab[engine];
+
+ switch (fsi_cfg_type(slot)) {
+ case FSI_ENGID_SLAVE_3P:
+ case FSI_ENGID_SLAVE_2P:
+ fsidev = fsislave_alloc();
+ break;
+ default:
+ fsidev = fsidev_alloc();
+ break;
+ }
+ if (fsidev)
+ fsidev_fill(fsidev, engine, slot, cfam);
+
+ return fsidev;
+}
+
+/*
+ * Create, initialize and fill in the properties of a CFAM engine
+ */
+static int setup_engine(int engine, struct fsicfam *cfam)
+{
+ int rc = 0;
+ struct fsidevice *fsidev = NULL;
+
+ fsidev = mkengine(engine, cfam);
+ if (fsidev == NULL) {
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ rc = fsidev_register_nolock(fsidev, fsidev->attr);
+done:
+ dev_dbg(&cfam->fsidev.dev, "setup_engine << engine:%d rc:%d\n",
+ engine, rc);
+
+ return rc;
+}
+
+/*
+ * Scan through the configruation table and install fsidevices for each
+ * new engine found.
+ */
+static int cfg_scan(struct fsicfam *cfam, u32 new, u32 *done)
+{
+ u32 type = 0;
+ int rc = 0, i;
+
+ dev_dbg(&cfam->fsidev.dev, "cfg_scan >> new:%08X\n", new);
+
+ *done = 0;
+
+ for (i = FSI_CFAM_PEEKIDX; i < cfam->no_eng; ++i) {
+ if ((mask32(i) & new) == 0) /* Not in mask */
+ continue;
+ if (cfam->cfgtab[i])
+ type = fsi_cfg_type(cfam->cfgtab[i]);
+ else
+ continue;
+
+ if (!cfam->engines[i])
+ rc = setup_engine(i, cfam);
+
+ clear_bit(i, &cfam->eng_build);
+ if (rc)
+ break;
+ *done |= mask32(i);
+ }
+ dev_dbg(&cfam->fsidev.dev, "cfg_scan << rc:%d done:%08X\n", rc, *done);
+
+ return rc;
+}
+
+/*
+ * Build up the list of CFAM engines
+ */
+static int cfg_find_engines(struct fsicfam *cfam, u32 new)
+{
+ u32 done = 0;
+ int rc = cfg_scan(cfam, new, &done);
+
+ dev_dbg(&cfam->fsidev.dev, "cfg_find_eng << new:%d done:%d rc:%d\n",
+ new, done, rc);
+
+ return new != done;
+}
+
+/*
+ * Identify engines that should be exported first. This is any engine whos
+ * presence is available by default without any external MUX configuration
+ * required to make them visible.
+ */
+static u32 firstlist(void)
+{
+ /*
+ * As of now there is no first/second export phase, all are same.
+ * Once support for muxed in engines is added this will need to
+ * make sure those aren't done in first round. Muxed devices will
+ * show up once the MUX is switched in for them (after first phase).
+ */
+ u32 eng_mask = ~0;
+
+ return eng_mask;
+}
+
+/*
+ * Unregister CFAM engines if something bad happens during the engine discovery
+ * process. Bad path only.
+ */
+static void cfg_undo(struct fsicfam *cfam)
+{
+ int i = cfam->no_eng;
+
+ dev_dbg(&cfam->fsidev.dev, "cfg_undo >> engines:%d\n", i);
+
+ while (--i >= FSI_CFAM_PEEKIDX) {
+ if (cfam->engines[i])
+ fsidev_unregister_nolock(cfam->engines[i]);
+ }
+}
+
+/*
+ * Walk the CFAM configuration table to discover all engines present
+ */
+static int cfg_build(struct fsilink *link, int linkno)
+{
+ int rc;
+ struct fsicfam *cfam = link->cfams[linkno];
+
+ dev_dbg(&cfam->fsidev.dev, "cfg_build >> link:%d cfamid:%d\n",
+ linkno, cfam->id);
+ cfam_read_header(cfam);
+ rc = cfg_find_engines(cfam, firstlist());
+ if (rc)
+ cfg_undo(cfam);
+
+ dev_dbg(&cfam->fsidev.dev, "cfg_build << rc:%d\n", rc);
+
+ return rc;
+}
+
+/*
+ * Buildup and export all CFAM engines to the LDM
+ */
+static int cfam_final(struct fsilink *link)
+{
+ int i, rc = 0;
+
+ for (i = 0; i < link->cascade; ++i) {
+ rc = cfg_build(link, i);
+ if (rc)
+ break;
+ }
+
+ return rc;
+}
+
+static void cfam_remove(struct fsicfam *cfam)
+{
+ cfg_undo(cfam);
+ fsidev_unregister_nolock(&cfam->fsidev);
+}
+
+static void cfam_remove_all(struct fsilink *link)
+{
+ int i;
+
+ for (i = 0; i < link->cascade; ++i)
+ cfam_remove(link->cfams[i]);
+ link->cascade = 0;
+}
+
+/*
+ * Send a BREAK command and build up all discovered CFAMs
+ */
static void linkbuild2(struct fsimaster *master, struct fsilink *link)
{
+ int rc = 0;
+
+ dev_dbg(&master->fsidev->dev, "linkbuild2 >> mid:%d link:%d\n",
+ master->myid, link->linkno);
+
+ rc = fsi_sendbreak(master, link->id3_addr, link->linkno);
+ if (rc)
+ goto out;
+
+ /*
+ * Setting all links for maximum speed. Note that some CFAM types
+ * may require slower speeds
+ */
+ fsimaster_setspeed(master, link->linkno, 0);
+ if (master->myid == 0 && rc < 0)
+ goto out;
+
+ rc = findcfams(master, link);
+ if (rc)
+ goto out;
+
+ rc = cfam_export(master, link);
+ if (rc <= 0)
+ goto out;
+
+ rc = cfam_final(link);
+ if (rc)
+ cfam_remove_all(link);
+
+out:
+ dev_dbg(&master->fsidev->dev, "linkbuild2 << link:%d len:%d rc:%d\n",
+ link->linkno, link->cascade, rc);
}
/*
@@ -76,19 +831,20 @@ static int linkbuild1(struct fsimaster *master, int no)
if (IS_ERR(link))
return PTR_ERR(link);
- /* stub */
+ master->link[link->linkno] = link;
linkbuild2(master, link);
i = link->cascade;
if (i == 0) {
-
- /* stub */
-
+ master->link[link->linkno] = NULL;
+ fsidev_unregister_nolock(&link->fsidev);
rc = -EIO;
} else {
-
- /* stub */
+ rc = link->top_cfam;
}
+ dev_dbg(&master->fsidev->dev,
+ "linkbuild1 << link:%d #cfams:%d top:%d rc:%d\n",
+ no, i, link->top_cfam, rc);
return rc;
}
@@ -101,6 +857,9 @@ int fsi_linkbuild(struct fsimaster *master, int no)
int rc;
u64 menp;
+ dev_dbg(&master->fsidev->dev, "fsi_linkbuild >> mid:%d link:%d\n",
+ master->myid, no);
+
menp = fsimaster_read_menp(master);
if (menp & mask64(no))
return -EEXIST; /* Already running */
@@ -110,5 +869,8 @@ int fsi_linkbuild(struct fsimaster *master, int no)
if (rc < 0)
fsimaster_disable_link(master, no);
+ dev_dbg(&master->fsidev->dev, "fsi_linkbuild << mid: %d link:%d rc:%d\n",
+ master->myid, no, rc);
+
return rc;
}
diff --git a/drivers/fsi/fsi.h b/drivers/fsi/fsi.h
index f0ed5b7..2227c71 100644
--- a/drivers/fsi/fsi.h
+++ b/drivers/fsi/fsi.h
@@ -42,6 +42,28 @@ struct fsi_engine_id {
#define FSI_ENGINE_ID_MATCH_VERSION 2 /* Match the version */
#define FSI_ENGINE_ID_MATCH_VENDOR 4 /* Match the vendor */
+/*
+ * Known engine types and versions
+ */
+#define FSI_ENGID_PS_CLOCK 0xfd /* Pseudo clock */
+#define FSI_ENGID_CFAM 0xfe /* CFAM type */
+#define FSI_ENGID_LINK 0xff /* Link type */
+#define FSI_ENGID_NONE 0x00 /* Empty slot */
+#define FSI_ENGID_PEEK_B 0x02 /* Peek engine 1 byte per eng */
+/* ... */
+#define FSI_ENGID_SLAVE_3P 0x03 /* 3 Port slave */
+/* ... */
+#define FSI_ENGID_SLAVE_2P 0x11 /* 2 Port slave */
+/* ... */
+#define FSI_ENGID_CMFSI 0x1a /* Cascaded FSI Master engine */
+#define FSI_ENGID_CMFSI_PORT 0x1b /* Cascaded FSI Master link */
+#define FSI_ENGID_HMFSI 0x1c /* Hub FSI Master engine */
+#define FSI_ENGID_HMFSI_PORT 0x1d /* Hub FSI Master link */
+/* ... */
+#define FSI_ENGID_SFC 0x21 /* System Flash Controller */
+#define FSI_ENGID_FIRST FSI_ENGID_PEEK_B /* First number */
+#define FSI_ENGID_LAST FSI_ENGID_SFC /* Last number */
+
/* Location information for a FSI device */
struct fsimap {
u8 link; /* Master link # */
@@ -49,9 +71,11 @@ struct fsimap {
u8 eng; /* Engine # on CFAM */
u8 cmtype; /* Type of master upstream */
u32 offset; /* Address offset into CFAM */
+ u32 addr; /* Physical address */
u32 va; /* Virtual address */
u16 kb; /* Size of dev engine space */
u16 kb_off; /* CFAM config table offset data */
+ u8 depth; /* How many links in path to target */
};
#define FSI_DEV_MEMRES 1 /* Physical address of device */
@@ -78,6 +102,7 @@ struct fsidevice {
struct device dev; /* LDM entry for bus */
struct fsimap map; /* Address & location info */
unsigned long state; /* flags for state */
+ struct device_attribute **attr; /* Default attributes */
};
#define to_fsidevice(x) container_of((x), struct fsidevice, dev)
diff --git a/drivers/fsi/fsi_private.h b/drivers/fsi/fsi_private.h
index afa2553..db3e192 100644
--- a/drivers/fsi/fsi_private.h
+++ b/drivers/fsi/fsi_private.h
@@ -14,6 +14,7 @@
#define DRIVERS_FSI_PRIVATE_H
#include "fsi.h"
+#include "fsicfam.h"
#define FSIDD_NAME "fsi" /* FSI device driver name */
@@ -115,4 +116,8 @@ void fsi_exit_fileio(dev_t);
int fsibus_init(void);
void fsibus_exit(void);
+int fsidev_register_nolock(struct fsidevice *, struct device_attribute **);
+void fsidev_unregister_nolock(struct fsidevice *);
+void fsidev_fill(struct fsidevice *, int, u32, struct fsicfam *);
+
#endif /* DRIVERS_FSI_PRIVATE_H */
diff --git a/drivers/fsi/fsicfam.h b/drivers/fsi/fsicfam.h
index 8ccff5c..59f3a58 100644
--- a/drivers/fsi/fsicfam.h
+++ b/drivers/fsi/fsicfam.h
@@ -43,6 +43,119 @@ struct fsicfam { /* CFAM internal structure */
int fsi_cfamirq_request(int, struct fsicfam *);
void fsi_cfamirq_free(struct fsicfam *);
+/* Config space entry encoding */
+#define FSI_CFG_NEXT 0x80000000 /* Next entry is valid */
+#define FSI_CFG_VPD 0x40000000 /* VPD data available */
+#define FSI_CFG_SLOT_SHIFT 16 /* # bits to shift for slot */
+#define FSI_CFG_SLOT_MASK 0xff
+#define FSI_CFG_VERS_SHIFT 12 /* # bits to shift for vers */
+#define FSI_CFG_VERS_MASK 0xf
+#define FSI_CFG_TYPE_SHIFT 4 /* # bits to shift for type */
+#define FSI_CFG_TYPE_MASK 0xff
+#define FSI_CFG_CRC_SHIFT 0 /* # bits to shift for crc */
+#define FSI_CFG_CRC_MASK 0xf
+#define FSI_CFG_ECMAJ_SHIFT 16 /* # bits to shift major ec */
+#define FSI_CFG_ECMAJ_MASK 0xff
+#define FSI_CFG_ECMIN_SHIFT 12 /* # bits to shift minor ec */
+#define FSI_CFG_ECMIN_MASK 0xf
+#define FSI_CFG_CHIPID_SHIFT 4 /* # bits to shift for ID */
+#define FSI_CFG_CHIPID_MASK 0xf
+
+/* These engines are in the same location in all CFAMs */
+#define FSI_CFAM_CFGIDX 0 /* Config space "engine" */
+#define FSI_CFAM_PEEKIDX 1 /* Peek engine */
#define FSI_CFAM_SLAVEIDX 2 /* Slave engine */
+#define FSI_CFAM_CMFSIIDX 12 /* Cascaded master engine */
+#define FSI_CFAM_HMFSIIDX 13 /* Hub master engine */
+
+/*
+ * Return next field in the configuration space entry.
+ */
+static inline int fsi_cfg_next(u32 x)
+{
+ return x & FSI_CFG_NEXT;
+}
+
+/*
+ * Return VPD field in the configuration space entry.
+ */
+static inline int fsi_cfg_vpd(u32 x)
+{
+ return x & FSI_CFG_VPD;
+}
+
+/*
+ * Set slot field
+ */
+static inline u32 fsi_cfg_mkslot(u32 x)
+{
+ return (x & FSI_CFG_SLOT_MASK) << FSI_CFG_SLOT_SHIFT;
+}
+
+/*
+ * Return slot field in the configuration space entry.
+ */
+static inline int fsi_cfg_slot(u32 x)
+{
+ return x >> FSI_CFG_SLOT_SHIFT & FSI_CFG_SLOT_MASK;
+}
+
+/*
+ * Return version field in the configuration space entry.
+ */
+static inline int fsi_cfg_version(u32 x)
+{
+ return x >> FSI_CFG_VERS_SHIFT & FSI_CFG_VERS_MASK;
+}
+
+/*
+ * Set type field.
+ */
+static inline u32 fsi_cfg_mktype(u32 x)
+{
+ return (x & FSI_CFG_TYPE_MASK) << FSI_CFG_TYPE_SHIFT;
+}
+
+/*
+ * Return type field in the configuration space.
+ */
+static inline int fsi_cfg_type(u32 x)
+{
+ return x >> FSI_CFG_TYPE_SHIFT & FSI_CFG_TYPE_MASK;
+}
+
+/*
+ * Return CRC field in the configuration field.
+ */
+static inline int fsi_cfg_crc(u32 x)
+{
+ return x >> FSI_CFG_CRC_SHIFT & FSI_CFG_CRC_MASK;
+}
+
+/*
+ * Return Major EC field in configuration space word 0.
+ */
+static inline int fsi_cfg_ecmaj(u32 x)
+{
+ return x >> FSI_CFG_ECMAJ_SHIFT & FSI_CFG_ECMAJ_MASK;
+}
+
+/*
+ * Return Minor EC field in configuration space word 0.
+ */
+static inline int fsi_cfg_ecmin(u32 x)
+{
+ return x >> FSI_CFG_ECMIN_SHIFT & FSI_CFG_ECMIN_MASK;
+}
+
+/*
+ * Return Chip ID field in configuration space word 0.
+ */
+static inline int fsi_cfg_chipid(u32 x)
+{
+ return x >> FSI_CFG_CHIPID_SHIFT & FSI_CFG_CHIPID_MASK;
+}
+
+u32 fsi_get_eng_offset(struct fsicfam *, int);
#endif /* DRIVERS_FSICFAM_H */
diff --git a/drivers/fsi/fsimaster.c b/drivers/fsi/fsimaster.c
index 427231f..5889bb1 100644
--- a/drivers/fsi/fsimaster.c
+++ b/drivers/fsi/fsimaster.c
@@ -248,14 +248,54 @@ u64 fsimaster_read_menp(struct fsimaster *master)
void fsimaster_write_menp(struct fsimaster *master, u64 *menp, int on_off)
{
+ int regnm = on_off ? FSI_N_MSENP0 : FSI_N_MCENP0;
+
+ master->write_reg2(master->base, regnm, menp);
+}
+
+void fsimaster_read_mcrsp(struct fsimaster *master, u64 *mcrsp)
+{
+ return master->read_reg2(master->base, FSI_N_MCRSP0, mcrsp);
+}
+
+void fsimaster_write_mcrsp(struct fsimaster *master, u64 *mcrsp)
+{
+ master->write_reg2(master->base, FSI_N_MCRSP0, mcrsp);
+}
+
+u32 fsimaster_read_maeb(struct fsimaster *master)
+{
+ return master->read_reg(master->base, FSI_N_MAEB);
}
void fsimaster_disable_link(struct fsimaster *master, int link)
{
+ u64 menp = 0;
+
+ menp = mask64(link);
+ fsimaster_write_menp(master, &menp, 0);
}
void fsimaster_enable_link(struct fsimaster *master, int link)
{
+ u64 menp = 0;
+
+ menp = mask64(link);
+ fsimaster_write_menp(master, &menp, 1);
+}
+
+void fsimaster_setspeed(struct fsimaster *master, int linkno, int set)
+{
+ u64 mcrsp, mask;
+
+ mask = mask64(linkno);
+
+ fsimaster_read_mcrsp(master, &mcrsp);
+ mcrsp &= ~mask;
+ if (set)
+ mcrsp |= mask;
+
+ fsimaster_write_mcrsp(master, &mcrsp);
}
/*
diff --git a/drivers/fsi/fsimaster.h b/drivers/fsi/fsimaster.h
index 0d47dc6..e70621c 100644
--- a/drivers/fsi/fsimaster.h
+++ b/drivers/fsi/fsimaster.h
@@ -634,6 +634,7 @@ int fsimaster_read_msiep(struct fsimaster *);
int fsimaster_read_msiep_nl(struct fsimaster *);
int fsimaster_write_msiep(struct fsimaster *, u32 *);
int fsimaster_write_msiep_nl(struct fsimaster *, u32 *);
+u32 fsimaster_read_maeb(struct fsimaster *);
int setup_me(struct fsimaster *, int);
/*
diff --git a/drivers/fsi/fsislave.h b/drivers/fsi/fsislave.h
index f2095d3..98c602a 100644
--- a/drivers/fsi/fsislave.h
+++ b/drivers/fsi/fsislave.h
@@ -401,4 +401,15 @@ int slave_irqclear(struct fsimaster *, void *, u32, u32);
int p8_cfam_fixup(struct fsicfam *, int);
u32 xmp8_srsim_mask(int);
+struct fsislave { /* FSI slave (always engine 2) */
+ struct fsidevice fsidev; /* LDM entry */
+ u8 myside; /* FSI slave port side */
+ u8 lbusspeed; /* FSI slave local bus clock ratio */
+ u8 buddyclk; /* FSI slave with buddy clock line */
+ u8 nextirq; /* FSI slave last IRQ handled */
+ u32 smode; /* FSI slave copy of smode register */
+};
+
+#define to_fsislave(x) container_of((x), struct fsislave, fsidev)
+
#endif /* DRIVERS_FSISLAVE_H */
diff --git a/drivers/fsi/ldm.c b/drivers/fsi/ldm.c
index cb6679f..5c2855f 100644
--- a/drivers/fsi/ldm.c
+++ b/drivers/fsi/ldm.c
@@ -285,6 +285,31 @@ struct bus_type fsi_bus_type = {
EXPORT_SYMBOL(fsi_bus_type);
/*
+ * Fill in the details for a given CFAM engine
+ */
+void fsidev_fill(struct fsidevice *fsidev, int engine, u32 slot,
+ struct fsicfam *cfam)
+{
+ u32 offset = fsi_get_eng_offset(cfam, engine);
+ u32 addr = cfam->fsidev.map.addr;
+
+ if (fsi_cfg_type(slot) == FSI_ENGID_PS_CLOCK)
+ offset = fsi_get_eng_offset(cfam, 4);
+
+ addr += offset;
+ offset = (addr & FSI_ENGINE_MASK) >> FSI_ENGINE_SHIFT;
+ fsidev->id.engine_type = fsi_cfg_type(slot);
+ fsidev->id.engine_version = fsi_cfg_version(slot);
+ fsidev->map.kb_off = offset;
+ fsidev->map.eng = engine;
+ fsidev->map.addr = addr;
+ fsidev->map.kb = fsi_cfg_slot(slot);
+ fsidev->dev.bus = &fsi_bus_type;
+ fsidev->dev.parent = &cfam->fsidev.dev;
+ fsidev->parent = &cfam->fsidev;
+}
+
+/*
* Create and install the FSI bus
*/
int fsibus_init(void)
diff --git a/drivers/fsi/readwrite.c b/drivers/fsi/readwrite.c
index 3427e52..ba839c1 100644
--- a/drivers/fsi/readwrite.c
+++ b/drivers/fsi/readwrite.c
@@ -10,22 +10,75 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/io.h>
+#include <linux/delay.h>
#include "fsi.h"
#include "fsi_private.h"
#include "fsimaster.h"
+#include "fsislave.h"
+
+/* Clean up master errors */
+static int fspme(int master_nr)
+{
+ return 0;
+}
/*
* Read/write functions to be used only by the FSI driver itself. FSI clients
* will use separate interfaces
*/
+
+/* Check if the master has logged any bus errors */
+static int fsi_check_errors(struct fsimaster *master)
+{
+ u32 maeb = fsimaster_read_maeb(master);
+ int rc = 0;
+
+ if (maeb & FSI_MASTER0)
+ rc = fspme(0);
+
+ return rc;
+};
+
int fsi_readw_int(struct fsimaster *master, u32 pa, u32 *value)
{
- return 0;
+ /*
+ * How we access hardware will be dependent on various factors.
+ * Could be an actual readl( ) MMIO operation or an emulated
+ * fsi master bit bang operation. g_host will be initialized
+ * with the proper value at init time.
+ */
+ /* *value = g_host->fops->in_be32(g_host, address); */
+ return fsi_check_errors(master);
}
int fsi_writew_int(struct fsimaster *master, u32 pa, u32 value)
{
- return 0;
+ /*
+ * How we access hardware will be dependent on various factors.
+ * Could be an actual readl( ) MMIO operation or an emulated
+ * fsi master bit bang operation. g_host will be initialized
+ * with the proper value at init time.
+ */
+ /* g_host->fops->out_be32(g_host, address, value); */
+ return fsi_check_errors(master);
+}
+
+/* Encode CFAM ID and basic setup for SMODE */
+static u32 cfam_id_to_smode(int id)
+{
+ u32 smode = FSI_SMODE_WSC | FSI_SMODE_ECRC
+ | fsi_smode_echodly(0xf) | fsi_smode_senddly(0xf)
+ | fsi_smode_lbcrr(1) | fsi_smode_sid(id);
+
+ return smode;
+}
+
+static int setcfam_id(struct fsimaster *master, u32 address, int id)
+{
+ u32 smode = cfam_id_to_smode(id);
+
+ return fsi_writew_int(master, address + FSI_SMODE, smode);
}
/*
@@ -34,5 +87,37 @@ int fsi_writew_int(struct fsimaster *master, u32 pa, u32 value)
*/
int fsi_sendbreak(struct fsimaster *master, u32 cfam_base, int linkno)
{
- return 0;
+ int rc = 0;
+ u32 smode;
+
+ dev_dbg(&master->fsidev->dev, "fsi_sendbreak >> mid:%d base:%d, link:%d\n",
+ master->myid, cfam_base, linkno);
+
+ rc = fsi_writew_int(master, cfam_base, FSI_BREAK);
+ if (rc)
+ goto done;
+
+ /* Wait for any CFAMs present to initialize */
+ udelay(200);
+ rc = fsi_readw_int(master, cfam_base + FSI_SLAVE0_OFFSET + FSI_SMODE,
+ &smode);
+ if (rc)
+ goto done;
+
+ dev_dbg(&master->fsidev->dev, "fsi_sendbreak: SMODE after break:%08X\n",
+ smode);
+
+ /* For now only one CFAM allowed per link so must have an ID of 0 */
+ setcfam_id(master, cfam_base + FSI_SLAVE0_OFFSET, 0);
+
+ rc = fsi_readw_int(master, cfam_base + FSI_SLAVE0_OFFSET + FSI_SMODE,
+ &smode);
+ dev_dbg(&master->fsidev->dev, "fsi_sendbreak: SMODE post SID set:%08X\n",
+ smode);
+
+ /* Wait for AUX port disable */
+ udelay(10);
+done:
+ dev_dbg(&master->fsidev->dev, "fsi_sendbreak << rc:%d\n", rc);
+ return rc;
}
--
1.8.2.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH linux v5 0/7] Introducing the FSI device driver
2016-08-24 19:54 [PATCH linux v5 0/7] Introducing the FSI device driver christopher.lee.bostic
` (6 preceding siblings ...)
2016-08-24 19:54 ` [PATCH linux v5 7/7] drivers/fsi: Add CFAM scanning function christopher.lee.bostic
@ 2016-09-02 5:05 ` Joel Stanley
2016-09-08 0:10 ` Joel Stanley
2016-09-21 17:42 ` Christopher Bostic
7 siblings, 2 replies; 19+ messages in thread
From: Joel Stanley @ 2016-09-02 5:05 UTC (permalink / raw)
To: Christopher Bostic; +Cc: OpenBMC Maillist, Chris Bostic
Hi Chris,
On Thu, Aug 25, 2016 at 5:24 AM, <christopher.lee.bostic@gmail.com> wrote:
> From: Chris Bostic <cbostic@us.ibm.com>
>
> Introduction of the IBM 'Flexible Support Interface' (FSI) bus device
> driver. FSI is a high fan out serial bus consisting of a clock and a serial
> data line capable of running at speeds up to 166 MHz.
Nice work on the cover letter. It's a good introduction.
I haven't had a chance to take a close look a the patches yet. They
are on top of the stack for Monday.
I was wondering if you have had a look at Jeremy's implementation yet?
If so, are there any ideas you have incorporated into your series?
Cheers,
Joel
>
> This set provides the core functionality of the FSI device driver. Core
> function is defined as:
> * FSI client registration and notification of bus state changes
> * Device scanning and hotplug reporting to clients
> * Interrupt detection and routing
> * Bus error detection and cleanup
>
> This patch set does not include extended FSI function such as:
> * Hub master support
> * Cascaded master support
> * Application layer hot plug notification
> * Application layer FSI bus status interface
> * Host configuration allowing for various hardware / firmware
> emulation implementations of the FSI master.
> * Soft FSI support. Soft FSI is a device driver method of emulating
> FSI master hardware by 'bit banging' standard I/O lines.
>
> Common FSI terminology:
>
> * Master
> Controller of the FSI bus. Only the master is allowed to control the
> clock line and is the initiator of all transactions on a bus.
>
> * Slave
> The receiver or target of a master initiated transaction. The slave
> cannot initiate communications on a bus and must respond to any
> master requests for data.
>
> * CFAM
> Stands for Common Field replaceable unit Access Macro. A CFAM is an
> ASIC residing in any device requiring FSI communications. CFAMs
> consist of an array of hardware 'engines' used for various purposes.
> I2C masters, UARTs, General Purpose IO hardware are common types of
> these engines.
>
> * Configuration Space / Table
> A table contained at the beginning of each CFAM address space.
> This table lists information such as the CFAM's ID, which engine types
> and versions it has available, as well as its addressing range.
>
> * Link
> The combination of a serial clock and data line constituting one
> FSI communications element. For each link there is a master on one
> end and a CFAM/slave on the other end.
>
> * Engine
> A self contained hardware function found within a CFAM. Examples
> include I2C masters, UARTs, GPIOs, etc...
>
> * Client
> A device driver requiring access to its hardware via an FSI bus.
> For example an I2C client would be a device driver requiring
> access to an I2C master engine on a remote CFAM accessible via
> an FSI link. Clients register with the FSI bus and will receive
> notifications of bus state changes as well as hot plug events related
> to engines of interest to them.
>
> * Build Up
> The process scanning a bus and creating a data structure representation
> of all devices discovered in a tree. A tree in this context is a
> series of links and devices connected to those links.
>
> * Hub / Hub master
> Provides extension to the existing primary FSI master. Allows for
> several chained FSI links in series to a target device thus increasing
> potential fan out.
>
> * Cascaded master
> A subset of functionality of the hub master. Cascaded masters can
> access only a limited address range compared to hub masters. This was
> the first generation implementation, essentially, of hub type function.
>
> ---
>
> Chris Bostic (6):
> drivers/fsi: Add FSI Master Functionality and Initialization
> drivers/fsi: Add FSI master target device scanning function
> drivers/fsi: Add initial FSI link buildup
> drivers/fsi: Add FSI bus type and hook into LDM
> drivers/fsi: Add FSI Bus Support for Clients
> drivers/fsi: Add CFAM scanning function
>
> Christopher Bostic (1):
> drivers/fsi: Initial stubs for FSI device driver.
>
> drivers/Kconfig | 2 +
> drivers/Makefile | 1 +
> drivers/fsi/Kconfig | 7 +
> drivers/fsi/Makefile | 5 +
> drivers/fsi/build.c | 876 ++++++++++++++++++++++++++++++++++++++++++++++
> drivers/fsi/fsi.h | 134 +++++++
> drivers/fsi/fsi_private.h | 123 +++++++
> drivers/fsi/fsicfam.h | 161 +++++++++
> drivers/fsi/fsiinit.c | 92 +++++
> drivers/fsi/fsiinit.h | 43 +++
> drivers/fsi/fsilink.h | 99 ++++++
> drivers/fsi/fsimaster.c | 619 ++++++++++++++++++++++++++++++++
> drivers/fsi/fsimaster.h | 682 ++++++++++++++++++++++++++++++++++++
> drivers/fsi/fsislave.h | 415 ++++++++++++++++++++++
> drivers/fsi/ldm.c | 347 ++++++++++++++++++
> drivers/fsi/readwrite.c | 123 +++++++
> 16 files changed, 3729 insertions(+)
> create mode 100644 drivers/fsi/Kconfig
> create mode 100644 drivers/fsi/Makefile
> create mode 100644 drivers/fsi/build.c
> create mode 100644 drivers/fsi/fsi.h
> create mode 100644 drivers/fsi/fsi_private.h
> create mode 100644 drivers/fsi/fsicfam.h
> create mode 100644 drivers/fsi/fsiinit.c
> create mode 100644 drivers/fsi/fsiinit.h
> create mode 100644 drivers/fsi/fsilink.h
> create mode 100644 drivers/fsi/fsimaster.c
> create mode 100644 drivers/fsi/fsimaster.h
> create mode 100644 drivers/fsi/fsislave.h
> create mode 100644 drivers/fsi/ldm.c
> create mode 100644 drivers/fsi/readwrite.c
>
> --
> 1.8.2.2
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH linux v5 2/7] drivers/fsi: Add FSI Master Functionality and Initialization
2016-08-24 19:54 ` [PATCH linux v5 2/7] drivers/fsi: Add FSI Master Functionality and Initialization christopher.lee.bostic
@ 2016-09-08 0:09 ` Joel Stanley
2016-09-21 18:38 ` Christopher Bostic
2016-09-21 21:15 ` Christopher Bostic
0 siblings, 2 replies; 19+ messages in thread
From: Joel Stanley @ 2016-09-08 0:09 UTC (permalink / raw)
To: Christopher Bostic; +Cc: OpenBMC Maillist, Chris Bostic
On Thu, Aug 25, 2016 at 5:24 AM, <christopher.lee.bostic@gmail.com> wrote:
> From: Chris Bostic <cbostic@us.ibm.com>
>
> Define the FSI master control register set and its accessors.
> Initialize the primary FSI master.
>
> Signed-off-by: Chris Bostic <cbostic@us.ibm.com>
> ---
I recall reading this patch in the past. No changelog?
> drivers/fsi/Makefile | 2 +-
> drivers/fsi/fsi.h | 32 +++
> drivers/fsi/fsi_private.h | 97 +++++++
> drivers/fsi/fsicfam.h | 46 ++++
> drivers/fsi/fsiinit.c | 22 ++
> drivers/fsi/fsiinit.h | 2 +
> drivers/fsi/fsimaster.c | 242 +++++++++++++++++
> drivers/fsi/fsimaster.h | 655 ++++++++++++++++++++++++++++++++++++++++++++++
> 8 files changed, 1097 insertions(+), 1 deletion(-)
> create mode 100644 drivers/fsi/fsi.h
> create mode 100644 drivers/fsi/fsi_private.h
> create mode 100644 drivers/fsi/fsicfam.h
> create mode 100644 drivers/fsi/fsimaster.c
> create mode 100644 drivers/fsi/fsimaster.h
>
> diff --git a/drivers/fsi/Makefile b/drivers/fsi/Makefile
> index f547c08..9800c15 100644
> --- a/drivers/fsi/Makefile
> +++ b/drivers/fsi/Makefile
> @@ -2,4 +2,4 @@
> # Makefile for the FSI bus specific drivers.
> #
>
> -obj-y += fsiinit.o
> +obj-y += fsiinit.o fsimaster.o
> diff --git a/drivers/fsi/fsi.h b/drivers/fsi/fsi.h
> new file mode 100644
> index 0000000..f146396
> --- /dev/null
> +++ b/drivers/fsi/fsi.h
> @@ -0,0 +1,32 @@
> +/*
> + * FSI device driver structure definitions and defines
> + *
> + * Copyright 2016 IBM Corp.
> + *
> + * Christopher Bostic <cbostic@us.ibm.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + */
> +#ifndef DRIVERS_FSI_H
> +#define DRIVERS_FSI_H
> +
> +#include <linux/device.h>
> +
> +struct fsimap {
> + u8 link; /* Master link # */
> + u8 cfam; /* CFAM # on link */
> + u32 offset; /* Address offset into CFAM */
> + u32 va; /* Virtual address */
> +};
> +
> +struct fsidevice {
> + u32 irq_start; /* IRQ Number */
> + struct fsidevice *parent; /* Parent of this device */
> + struct device dev; /* LDM entry for bus */
> + struct fsimap map; /* Address & location info */
> +};
> +
> +#endif /* DRIVERS_FSI_H */
> diff --git a/drivers/fsi/fsi_private.h b/drivers/fsi/fsi_private.h
> new file mode 100644
> index 0000000..be327ef
> --- /dev/null
> +++ b/drivers/fsi/fsi_private.h
> @@ -0,0 +1,97 @@
> +/*
> + * FSI device driver structure definitions and defines
> + *
> + * Copyright 2016 IBM Corp.
> + *
> + * Christopher Bostic <cbostic@us.ibm.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + */
> +#ifndef DRIVERS_FSI_PRIVATE_H
> +#define DRIVERS_FSI_PRIVATE_H
> +
> +#include "fsi.h"
> +
> +#define FSIDD_NAME "fsi" /* FSI device driver name */
> +
> +/*
> + * Universal FSI constants - Applicable for any FSI device
> + */
> +#define FSI_MAX_LINKS 64 /* FSI Master # of links */
> +#define FSI_MAX_CASCADE 4 /* # of CFAMS in cascade */
> +#define FSI_MAX_MASTERS 1 /* # of masters in system */
> +#define FSI_LINK_ENG_MASK 0xE0007FFF /* Used for minor num calcs */
> +#define FSI_MAX_DEPTH 3 /* Max # of links in path */
> +#define FSI_LINK_SHIFT 23 /* Bits to shift */
> +#define FSI_LINK_SIZE (1 << FSI_LINK_SHIFT) /* 8 MB */
> +#define FSI_CFAM_SHIFT 21 /* Bits to shift */
> +#define FSI_CFAM_SIZE (1 << FSI_CFAM_SHIFT) /* 2 MB */
> +#define FSI_ENGINE_SHIFT 10 /* Bits to shift */
> +#define FSI_ENGINE_SIZE (1 << FSI_ENGINE_SHIFT) /* 1 KB */
> +#define FSI_LINK_MASK 0x1f800000 /* Bits for link */
> +#define FSI_CFAM_MASK 0x00600000 /* Bits for cfam */
> +#define FSI_ENGINE_MASK 0x000ffc00 /* Bits for engine */
> +#define FSI_PEEK_OFFSET FSI_ENGINE_SIZE
> +#define FSI_SLAVE0_OFFSET (2 * FSI_ENGINE_SIZE)
> +#define FSI_SLV_NO_ERROR 100 /* Slave has no error data */
> +#define FSI_BREAK 0xc0de0000 /* BREAK command */
> +#define FSI_TERM 0xecc00000 /* TERM command */
> +#define FSI_BREAK_TIME 180 /* # Seconds to allow BREAKs */
> +#define FSI_BREAK_CNT 3 /* limit for BREAK attempts */
> +#define FSI_PRIM 0 /* Generic Primary FSI master */
> +#define FSI_MBIT_MASK 0x3 /* FSI master bits in pa */
> +#define FSI_ENG_MASK 0x00007FFF /* The engine mask in MATRB */
> +/* FSI Events */
> +#define FSI_EVT_PLUG 6 /* Device plugged */
> +#define FSI_LINK_BUILD 10 /* In build up phase */
> +#define FSI_LINK_PROBE 11 /* In probing phase */
> +
> +/*
> + * Return the link number where this device is attached
> + */
> +static inline int fsi_my_link(struct fsidevice *fdev)
> +{
> + return fdev->map.link;
> +}
> +
> +/*
> + * Return CFAM number on link where this device is attached
> + */
> +static inline int fsi_my_cfam(struct fsidevice *fdev)
> +{
> + return fdev->map.cfam;
> +}
> +
> +/*
> + * Determine the link address to send the break command to
> + * This is master dependent
> + */
> +static inline int fsi_mtype_2break_id(u8 mtype)
> +{
> + return FSI_MAX_CASCADE - 1;
> +}
> +
> +/*
> + * Build a mask where bit index 'x' is set (numbering from left to right.
> + * Bit 0 is MSB and bit 31 is LSM.
> + */
> +static inline unsigned long mask32(int x)
> +{
> + return 1 << (BITS_PER_LONG - x - 1);
Is this masking in IBM bit ordering?
We should pull the macros (or at least copy them) from arch/powerpc so
we can use them here.
> +}
> +
> +/*
> + * Various function prototypes
> + */
> +int slv_install(void);
> +void slv_uninstall(void);
> +
> +void fsi_exit_fileio(dev_t);
> +
> +int fsibus_init(void);
> +void fsibus_exit(void);
> +
> +#endif /* DRIVERS_FSI_PRIVATE_H */
> diff --git a/drivers/fsi/fsicfam.h b/drivers/fsi/fsicfam.h
> new file mode 100644
> index 0000000..dde7036
> --- /dev/null
> +++ b/drivers/fsi/fsicfam.h
> @@ -0,0 +1,46 @@
> +/*
> + * FSI CFAM structure definitions and defines
> + *
> + * Copyright 2016 IBM Corp.
> + *
> + * Christopher Bostic <cbostic@us.ibm.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + */
> +#ifndef DRIVERS_FSICFAM_H
> +#define DRIVERS_FSICFAM_H
> +
> +#include "fsi.h"
> +#include "fsi_private.h"
> +
> +#define FSI_MAX_ENGINES 32 /* Max # of engines per CFAM */
> +
> +struct fsicfam { /* CFAM internal structure */
> + struct fsidevice *engines[FSI_MAX_ENGINES]; /* CFAM engine data */
> + u32 cfgtab[FSI_MAX_ENGINES]; /* Configuration word */
> + u16 chipid; /* CFAM chip type (IOU, CFAM-S, etc) */
> + u8 id; /* CFAM Id */
> + bool has_submaster; /* CFAM with cascaded or hub masters */
> + bool has_mux; /* CFAM with multiplexer */
> + u8 ec_maj; /* Major EC Level */
> + u8 ec_min; /* Minor EC Level or version number */
> + u16 pages; /* # Mapped pages */
> + u8 no_eng; /* Number of engines[] */
> + struct fsidevice fsidev; /* LDM entry */
> + struct fsidevice hpdone; /* Dummy engine to signal completion */
> + unsigned long eng_build; /* True during engine activate */
> + struct fsimaster *master; /* pointer to parent master */
> +};
> +
> +#define to_fsicfam(x) container_of((x), struct fsicfam, fsidev)
Make this a function.
> +
> +/*
> + * CFAM specific function prototypes.
> + */
> +int fsi_cfamirq_request(int, struct fsicfam *);
> +void fsi_cfamirq_free(struct fsicfam *);
> +
> +#endif /* DRIVERS_FSICFAM_H */
> diff --git a/drivers/fsi/fsiinit.c b/drivers/fsi/fsiinit.c
> index 767c0c3..c589294 100644
> --- a/drivers/fsi/fsiinit.c
> +++ b/drivers/fsi/fsiinit.c
> @@ -13,7 +13,9 @@
>
> #include <linux/init.h>
> #include <linux/module.h>
> +#include <linux/kdev_t.h>
> #include "fsiinit.h"
> +#include "fsimaster.h"
>
> MODULE_AUTHOR("Christopher Bostic cbostic@us.ibm.com");
> MODULE_DESCRIPTION("FSI master device driver");
> @@ -26,6 +28,7 @@ MODULE_DESCRIPTION("FSI master device driver");
> struct fsidd fsidd = { /* FSI device driver structure definition */
> .magic = FSI_DD_MAGIC,
> .strno = FSI_DD_STRNO,
> + .major = MKDEV(FSIDD_MAJOR, 0),
> };
>
> static int fsi_start(void)
> @@ -33,6 +36,25 @@ static int fsi_start(void)
> int rc = 0;
>
> dev_dbg(&fsidd.dev, "FSI DD v:%d installation ok\n", FSIDD_VERNO);
> +
> + init_waitqueue_head(&fsidd.error_wq);
> + init_waitqueue_head(&fsidd.lbus_wq);
> + init_waitqueue_head(&fsidd.irq_wq);
> + init_waitqueue_head(&fsidd.link_wq);
> +
> + /*
> + * Initialize the the master
> + */
> + if (!fsimaster_build_init(&fsidd.pri_master, FSI_PRIM, 0)) {
> + rc = PTR_ERR(0);
???
> + goto err;
> + }
> + fsimaster_start(&fsidd.pri_master);
> + dev_dbg(&fsidd.dev, "FSI DD v%d installation ok\n", FSIDD_VERNO);
> + return rc;
> +
> +err:
> + dev_dbg(&fsidd.dev, "FSI DD v:%d installation failed\n", FSIDD_VERNO);
> return rc;
Your formatting is broken.
> }
>
> diff --git a/drivers/fsi/fsiinit.h b/drivers/fsi/fsiinit.h
> index 93662533..10ddfc0 100644
> --- a/drivers/fsi/fsiinit.h
> +++ b/drivers/fsi/fsiinit.h
> @@ -19,6 +19,7 @@
> #include <linux/device.h>
> #include <linux/workqueue.h>
> #include <linux/hrtimer.h>
> +#include "fsimaster.h"
>
> #define FSI_DD_MAGIC 0x64644632 /* ddF2 */
> #define FSI_DD_STRNO 0x1 /* Structure version number */
> @@ -34,6 +35,7 @@ struct fsidd { /* FSI Main structure */
> wait_queue_head_t link_wq; /* Wait queue for link changes */
> unsigned long state; /* State driver is in */
> struct device dev; /* Anchor point in /sys/kernel */
> + struct fsimaster pri_master; /* Primary FSI master */
> };
>
> #define to_fsidd_prim(a) container_of(a, struct fsidd, pri_master)
> diff --git a/drivers/fsi/fsimaster.c b/drivers/fsi/fsimaster.c
> new file mode 100644
> index 0000000..b5d16db
> --- /dev/null
> +++ b/drivers/fsi/fsimaster.c
> @@ -0,0 +1,242 @@
> +/*
> + * FSI Master Control
> + *
> + * Copyright 2016 IBM Corp.
> + *
> + * Christopher Bostic <cbostic@us.ibm.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/delay.h>
> +#include <linux/ktime.h>
> +#include <linux/io.h>
> +#include "fsi.h"
> +#include "fsiinit.h"
> +#include "fsimaster.h"
> +#include "fsicfam.h"
> +
> +static int hpinfo_alloc(struct fsimaster *master)
> +{
> + return 0;
> +}
> +
> +static inline unsigned int fsimid(struct fsimaster *master)
> +{
> + return master->myid;
> +}
> +
> +static void primaster_exit(struct fsimaster *master)
> +{
> + if (master->dcr_alloc) {
> + master->base = NULL;
> + master->dcr_alloc = false;
> + }
> +}
> +
> +/*
> + * Read/write functions to access primary FSI master registers
> + * Note that this master is virtual as we don't yet have any
> + * real FSI masters implemented in hardware
"virtual"? What's the purpose of this code?
> + */
> +static u32 virt_master_readreg(struct fsi_mreg *mbase, int regnm)
> +{
> + u32 *base = (u32 *)mbase;
> +
> + return *(base + regnm);
> +}
> +
> +static void virt_master_readreg2(struct fsi_mreg *mbase, int regnm, u64 *dest)
> +{
> + u32 *base = (u32 *)mbase;
> +
> + memcpy(dest, base + regnm, sizeof(u64));
> +}
> +
> +static void virt_master_readreg4(struct fsi_mreg *mbase, int regnm, u32 *dest)
> +{
> + u32 *base = (u32 *)mbase;
> +
> + memcpy(dest, base + regnm, 4 * sizeof(u32));
> +}
> +
> +static void writereg_array(struct fsi_mreg *mbase, int regnm,
> + u32 *val, size_t size)
> +{
> + int i;
> + u32 r_value, new_value[size];
> + u32 *base = (u32 *)mbase;
> +
> + if (regnm == FSI_N_MRESB0) {
> + /* A write to the reset register clears out MESRB */
> + *(base + regnm) = 0;
> + return;
> + }
> +
> + for (i = 0, base += regnm; i < size; ++i) {
> + new_value[i] = *(val + i);
> +
> + /*
> + * The master control registers have various modes when
> + * written; direct copy or set/clear under mask
> + */
> + if (FSI_CLEAR_UNDER_MASK(regnm)) {
> + r_value = virt_master_readreg(mbase, regnm);
> + new_value[i] = r_value &= ~(*(val + i));
> + } else if (FSI_SET_UNDER_MASK(regnm)) {
> + r_value = virt_master_readreg(mbase, regnm);
> + new_value[i] = r_value |= *(val + i);
> + }
> + /*
> + * If not set or clear under mask type register then simply
> + * copy value
> + */
> + *base++ = new_value[i];
> + }
> +}
> +
> +static void virt_master_writereg(struct fsi_mreg *base, int regnm, u32 val)
> +{
> + writereg_array(base, regnm, &val, 1);
> +}
> +
> +static void virt_master_writereg2(struct fsi_mreg *base, int regnm, u64 *val)
> +{
> + writereg_array(base, regnm, (u32 *)val, 2);
> +}
> +
> +static void virt_master_writereg8(struct fsi_mreg *base, int regnm, u32 *val)
> +{
> + writereg_array(base, regnm, val, 8);
> +}
> +
> +static int primaster_init(struct fsimaster *master)
> +{
> + master->read_reg = virt_master_readreg;
> + master->read_reg2 = virt_master_readreg2;
> + master->read_reg4 = virt_master_readreg4;
> + master->write_reg = virt_master_writereg;
> + master->write_reg2 = virt_master_writereg2;
> + master->write_reg8 = virt_master_writereg8;
> + master->maxlinks = PRI_MAX_LINKS;
> + master->have_peek = true;
> + master->irqbase = 0;
> + memset(&master->base, 0, sizeof(struct fsi_mreg));
> + master->dcr_alloc = true;
> + if (hpinfo_alloc(master))
> + primaster_exit(master);
> +
> + return master->base ? 0 : 1;
> +}
> +
> +static int fsimaster_init(struct fsimaster *master)
> +{
> + int rc = 0;
> +
> + memset(&master->quirks, 0, sizeof(struct master_quirks));
> + master->quirks.break_cfam_id = fsi_mtype_2break_id(master->type);
> + master->cfam_size = 0;
> + master->m_get = NULL;
> + master->m_pa2irq = NULL;
> + master->m_exit = NULL;
> +
> + rc = primaster_init(master);
> +
> + return rc;
> +}
> +
> +struct fsimaster *fsimaster_get_top_master(struct fsimaster *master)
> +{
> + struct fsimaster *parent = NULL;
> +
> + while (master) {
> + parent = master;
> + master = master->parent;
> + }
> +
> + return parent;
> +}
> +
> +static int fsimaster_reset(struct fsimaster *master)
> +{
> + u32 reg = 0;
> + u64 reg2 = 0;
> + int rc = 0;
> + struct fsidd *dd = NULL;
> +
> + dd = to_fsidd_prim(fsimaster_get_top_master(master));
> +
> + reg = master->read_reg(master->base, FSI_N_MVER);
> + if (fsi_mver_extlink(reg) != master->maxlinks) {
> + rc = -EINVAL;
> + goto out;
> + }
> + /* Reset all bridges and ports */
> + reg = FSI_MRESP_RST_ALL_MSTR | FSI_MRESP_RST_ALL_LINK
> + | FSI_MRESP_RST_MCR | FSI_MRESP_RST_PYE;
> + master->write_reg(master->base, FSI_N_MRESP0, reg);
> +
> + /* Set up control */
> + reg = (master->type == FSI_PRIM) ? FSI_MECTRL_FPME : FSI_MECTRL_EOAE;
> + master->write_reg(master->base, FSI_N_MECTRL, reg);
> +
> + /* Set up mode */
> + reg = fsi_mmode_crs0(1) | fsi_mmode_crs1(1);
> + master->write_reg(master->base, FSI_N_MMODE, reg);
> +
> + /* Set up delay characteristics */
> + master->write_reg(master->base, FSI_N_MDLYR, FSI_MDLYR_DFLT);
> +
> + /* Enable all links for a short time */
> + reg2 = ~0;
> + master->write_reg2(master->base, FSI_N_MSENP0, ®2);
> +
> + mdelay(1);
> + master->write_reg2(master->base, FSI_N_MCENP0, ®2);
> +
> + reg2 = FSI_MRESP_RST_ALL_MSTR | FSI_MRESP_RST_ALL_LINK;
> + master->write_reg(master->base, FSI_N_MRESP0, reg2);
> +out:
> + return rc;
> +}
> +
> +struct fsimaster *fsimaster_build_init(struct fsimaster *master, int type,
> + struct fsidevice *parent)
> +{
> + int rc = 0;
> + struct fsidd *dd = NULL;
> +
> + if (!master)
> + goto out;
> + if (!parent)
> + dd = to_fsidd_prim(master);
> + else {
> + struct fsicfam *cfam = to_fsicfam(parent->parent);
> +
> + dd = to_fsidd_prim(fsimaster_get_top_master(cfam->master));
> + }
> + master->type = type;
> + master->fsidev = parent;
> + if (fsimaster_init(master)) {
> + master = NULL;
> + goto out;
> + }
> + if (fsimaster_reset(master)) {
> + rc = -EIO;
> + master = NULL;
> + goto out;
> + }
> +out:
> + return master ? : ERR_PTR(rc);
> +}
> +
> +/*
> + * Kick off the master so it can start probing for attached CFAMs
> + */
> +void fsimaster_start(struct fsimaster *master)
> +{
> +}
> diff --git a/drivers/fsi/fsimaster.h b/drivers/fsi/fsimaster.h
> new file mode 100644
> index 0000000..4df2caf
> --- /dev/null
> +++ b/drivers/fsi/fsimaster.h
> @@ -0,0 +1,655 @@
> +/*
> + * FSI Master device driver structure definitions and defines
> + *
> + * Copyright 2016 IBM Corp.
> + *
> + * Christopher Bostic <cbostic@us.ibm.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + */
> +#ifndef DRIVERS_FSIMASTER_H
> +#define DRIVERS_FSIMASTER_H
> +
> +#include "fsi_private.h"
> +#include "fsi.h"
> +#include "fsicfam.h"
> +
> +#define FSI_MAX_PING_ATTEMPTS 12
> +#define FSI_PLUG_CHECK_TIME 100
> +#define FSI_DFLT_IPOLL_CHECK 800
> +
> +/* FSI master register numbers */
> +#define FSI_N_MMODE 0 /* 0x0 R/W: mode register */
> +#define FSI_N_MDLYR 1 /* 0x4 R/W: delay register */
> +#define FSI_N_MCRSP0 2 /* 0x8 R/W: clock rate selector register 0 */
> +#define FSI_N_MCRSP32 3 /* 0xC R/W: clock rate selector register 1 */
> +#define FSI_N_MENP 4 /* 0x10 R/W: enable clock register 0 */
> +#define FSI_N_MENP32 5 /* 0x14 R/W: enable clock register 1 */
> +#define FSI_N_MLEVP 6 /* 0x18 R: static level register 0 */
> +#define FSI_N_MLEVP32 7 /* 0x1C R: static level register 1 */
> +#define FSI_N_MSENP0 6 /* 0x18 S: set enable clock register 0 */
> +#define FSI_N_MREFP0 8 /* 0x20 R: link reference register 0 */
> +#define FSI_N_MCENP0 8 /* 0x20 W: clear enable port register 0 */
> +#define FSI_N_MHPMP0 10 /* 0x28 R: hot plug reference register 0 */
> +#define FSI_N_MCHPMP0 10 /* 0x28 W: clear hot plug reference reg 0 */
> +#define FSI_N_MSIEP0 12 /* 0x30 R/W: Ipoll register 0 */
> +#define FSI_N_MSIEP32 16 /* 0x40 R/W: Ipoll register 4 */
> +#define FSI_N_MAESP0 20 /* 0x50 R: any error port register 0 */
> +#define FSI_N_MAESP32 24 /* 0x60 R: any error port register 4 */
> +#define FSI_N_MSSIEP0 20 /* 0x50 W: set Ipoll register 0 */
> +#define FSI_N_MAEB 28 /* 0x70 R: any error bridge */
> +#define FSI_N_MVER 29 /* 0x74 R: version register */
> +#define FSI_N_MBSYP0 30 /* 0x78 R: port busy register 0 */
> +#define FSI_N_MCSIEP0 28 /* 0x70 W: clear Ipoll register 0 */
> +#define FSI_N_MDRSB1 36 /* 0x90 R/W: DMA select register master 1 */
> +#define FSI_N_MSTAP0 52 /* 0xd0 R: port status reg 0-63 (0xd0-0x1cc) */
> +#define FSI_N_MRESP0 52 /* 0xd0 W: port reset regr 0-63 (0xd0-0x1cc) */
> +#define FSI_N_MESRB0 116 /* 0x1d0 R: error syndrome register 0-16 */
> +#define FSI_N_MRESB0 116 /* 0x1d0 W: reset reg master 0-16 (x1d0-x210) */
> +#define FSI_N_MSCSB0 117 /* 0x1d4 R: master sub cmd stack register 0 */
> +#define FSI_N_MATRB0 118 /* 0x1d8 R: master address trace register 0 */
> +#define FSI_N_MDTRB0 119 /* 0x1dc R: master data trace register 0 */
> +#define FSI_N_MECTRL 184 /* 0x2e0 R/W: error control register master 0 */
> +#define FSI_N_MAESP_SZ 8 /* # of error port register 0-7 */
> +
> +#define FSI_MSIEP_REG_COUNT 8
> +#define PRI_MAX_LINKS FSI_MAX_LINKS
> +
> +/*
> + * Model clear under mask (CU) and set under mask (SU) Read only (RO)
> + * and Write only (WO) behavior for virtual Primary FSI Master
> + */
> +#define FSI_CLEAR_UNDER_MASK(x) ((x) == FSI_N_MCENP0 \
> + || ((x) == FSI_N_MCENP0 + 1) \
> + || (x) == FSI_N_MCHPMP0 \
> + || ((x) == FSI_N_MCHPMP0 + 1) \
> + || (x) == FSI_N_MCSIEP0 \
> + || ((x) == FSI_N_MCSIEP0 + 1) \
> + || ((x) == FSI_N_MCSIEP0 + 2) \
> + || ((x) == FSI_N_MCSIEP0 + 3) \
> + || ((x) == FSI_N_MCSIEP0 + 4) \
> + || ((x) == FSI_N_MCSIEP0 + 5) \
> + || ((x) == FSI_N_MCSIEP0 + 6) \
> + || ((x) == FSI_N_MCSIEP0 + 7))
> +#define FSI_SET_UNDER_MASK(x) ((x) == FSI_N_MSENP0 \
> + || ((x) == FSI_N_MSENP0 + 1) \
> + || (x) == FSI_N_MSSIEP0 \
> + || ((x) == FSI_N_MSSIEP0 + 1) \
> + || ((x) == FSI_N_MSSIEP0 + 2) \
> + || ((x) == FSI_N_MSSIEP0 + 3) \
> + || ((x) == FSI_N_MSSIEP0 + 4) \
> + || ((x) == FSI_N_MSSIEP0 + 5) \
> + || ((x) == FSI_N_MSSIEP0 + 6) \
> + || ((x) == FSI_N_MSSIEP0 + 7))
> +
> +/*
> + * Return FSI master error information register number for master x
> + */
> +static inline int fsi_mesrb_nr(int master)
> +{
> + return (FSI_N_MESRB0 + master * 4);
> +}
> +
> +/*
> + * Return FSI master reset register number for master x
> + */
> +static inline int fsi_mresb_nr(int master)
> +{
> + return FSI_N_MRESB0 + master;
> +}
> +
> +/*
> + * Return FSI master port status register number for link x
> + */
> +static inline int fsi_mstap_nr(int link)
> +{
> + return FSI_N_MSTAP0 + link;
> +}
> +
> +/*
> + * Return FSI master port error reset register number for link x
> + */
> +static inline int fsi_mresp_nr(int link)
> +{
> + return FSI_N_MRESP0 + link;
> +}
> +
> +/*
> + * Return FSI master ipoll register number for index x
> + */
> +static inline int fsi_msiep_nr(int idx)
> +{
> + return FSI_N_MSIEP0 + idx;
> +}
> +
> +/*
> + * Return FSI master error information register number for master x
> + */
> +static inline int fsi_maesp_nr(int portreg)
> +{
> + return FSI_N_MAESP0 + portreg;
> +}
> +
> +struct fsi_mei { /* FSI master error information */
> + u32 mesrb; /* Master error status register */
> + u32 mscsb; /* Subcommand stack register */
> + u32 matrb; /* Address trace register */
> + u32 mdtrb; /* Data trace register */
> +};
> +
> +/* FSI Master register set */
> +struct fsi_mreg {
> + u32 mmode; /* 0x0 */
> + u32 mdlyr; /* 0x4 */
> + u64 mcrsp; /* 0x8 - 0xc */
> + u64 menp; /* 0x10 - 0x14 */
> + u64 mlevp; /* 0x18 - 0x1c */
> + u64 mrefp; /* 0x20 - 0x24 */
> + u64 mhpmp; /* 0x28 - 0x2c */
> + u32 msiep0[8]; /* 0x30 - 0x4c */
> + u32 maesp0[8]; /* 0x50 - 0x6c */
> + u32 maeb0[8]; /* 0x70 - 0x8c */
> + u32 mdrsb0[16]; /* 0x90 - 0xcc */
> + u32 mstap0[FSI_MAX_LINKS]; /* 0xd0 - 0x1cc */
> + struct fsi_mei mresb0[FSI_MAX_MASTERS]; /* 0x1d0 - 0x2dc */
> + u32 mectrl; /* 0x2e0 */
> + u32 mver; /* Master version ID, read only */
> +};
> +
> +#define PORT_BUSY_CHECKS_MAX 10
> +
> +/* FSI Port controller reset types */
> +#define FSI_PORT_GENERAL_RESET 0x80000000
> +#define FSI_PORT_ERROR_RESET 0x40000000
> +#define FSI_PORT_GENERAL_RESET_BRIDGE 0x20000000
> +#define FSI_PORT_GENERAL_RESET_PORT 0x10000000
> +#define FSI_PORT_RESET_CNTRL_REGS 0x08000000
> +#define FSI_PORT_RESET_PA_ERROR 0x04000000
> +
> +/* FSI Port controller error masks */
> +#define FSI_PORT_EMASK_ID0 0xf0000000
> +#define FSI_PORT_EMASK_ID1 0x0f000000
> +#define FSI_PORT_EMASK_ID2 0x00f00000
> +#define FSI_PORT_EMASK_ID3 0x000f0000
> +#define FSI_PORT_CRCMASK 0x0000f000
> +#define FSI_PORT_HOTPLUG 0x00000800
> +
> +/*
> + * FSI Slave interrupt enable/disable bit setting. Return the bit setting
> + * given a link and cfam number. The result of this function can be input
> + * to the mssiepX and mcsiepX registers or or'ed in to msiepX.
> + * The formula is 1 << 31 - (link % 8 * 4 + cfam).
> + *
> + * Not in FSI Spec (0..30):
> + * MSIEPx register bit 0 is port 0 and cfam 0.
> + * MSIEPx register bit 1 is port 0 and cfam 1.
> + * MSIEPx register bit 31 is port 7 and cfam 3.
> + */
> +static inline u32 fsi_mk_msiep(int link, int cfam)
> +{
> + return mask32((link % (BITS_PER_LONG / FSI_MAX_CASCADE))
> + * FSI_MAX_CASCADE + cfam);
> +}
> +
> +/*
> + * Return mask for all CFAMs id x to 3 (end of cascade) on a specific link.
> + */
> +static inline u32 fsi_mk_msiep_plus(int link, int cfam)
> +{
> + u32 bits = (0xf >> cfam) << 28;
> +
> + return bits >> (link % (BITS_PER_LONG / FSI_MAX_CASCADE)
> + * FSI_MAX_CASCADE);
> +}
> +
> +/*
> + * Return mask for all CFAMs on a specific link.
> + */
> +static inline u32 fsi_mk_msiep_all(int link)
> +{
> + return 0xf0000000 >> (link % (BITS_PER_LONG / FSI_MAX_CASCADE)
> + * FSI_MAX_CASCADE);
> +}
> +
> +/*
> + * Return index for msiepX register
> + */
> +static inline int fsi_mk_msiep_idx(int link)
> +{
> + return link / (BITS_PER_LONG / FSI_MAX_CASCADE);
> +}
> +
> +/*
> + * FSI Master Mode register setting
> + */
> +#define FSI_MMODE_EIP 0x80000000 /* Enable interrupt polling */
> +#define FSI_MMODE_ECRC 0x40000000 /* Enable hw error recovery */
> +#define FSI_MMODE_ERAC 0x20000000 /* Enable relative addr cmds */
> +#define FSI_MMODE_EPC 0x10000000 /* Enable parity checking */
> +#define FSI_MMODE_CRS0SHFT 18 /* Clock select 0 mask shift */
> +#define FSI_MMODE_CRS0MASK 0x3ff /* Clock select 0 mask */
> +#define FSI_MMODE_CRS1SHFT 8 /* Clock select 1 mask shift */
> +#define FSI_MMODE_CRS1MASK 0x3ff /* Clock select 1 mask */
> +#define FSI_MMODE_P63 0x80 /* Route link 63 IOU slave C */
> +#define FSI_MMODE_DIV4 0x00000040 /* Divide by 4 (legacy mode) */
> +
> +/*
> + * Rolf Fritz Nov 20, 2013:
> + * MSB=1, LSB=0 is 0.8 ms
> + * MSB=0, LSB=1 is 0.9 ms
> + */
> +#define FSI_MMODE_P8_TO_MSB 0x00000020 /* Timeout val most sig bit */
> +#define FSI_MMODE_P8_TO_LSB 0x00000010 /* Timeout val least sig bit */
> +
> +static inline u32 fsi_mmode_crs0(u32 x)
> +{
> + return (x & FSI_MMODE_CRS0MASK) << FSI_MMODE_CRS0SHFT;
> +}
> +
> +static inline u32 fsi_mmode_crs1(u32 x)
> +{
> + return (x & FSI_MMODE_CRS1MASK) << FSI_MMODE_CRS1SHFT;
> +}
> +
> +static inline u32 fsi_mmode_extcrs0(u32 x)
> +{
> + return (x >> FSI_MMODE_CRS0SHFT) & FSI_MMODE_CRS0MASK;
> +}
> +
> +static inline u32 fsi_mmode_extcrs1(u32 x)
> +{
> + return (x >> FSI_MMODE_CRS1SHFT) & FSI_MMODE_CRS1MASK;
> +}
> +
> +/*
> + * FSI master delay register
> + */
> +#define FSI_MDLYR_ECHO0_SHFT 28 /* Selection 0 echo delay cycles */
> +#define FSI_MDLYR_ECHO0_MASK 0xf /* Selection 0 echo delay cycles */
> +#define FSI_MDLYR_SEND0_SHFT 24 /* Selection 0 send delay cycles */
> +#define FSI_MDLYR_SEND0_MASK 0xf /* Selection 0 send delay cycles */
> +#define FSI_MDLYR_ECHO1_SHFT 20 /* Selection 1 echo delay cycles */
> +#define FSI_MDLYR_ECHO1_MASK 0xf /* Selection 1 echo delay cycles */
> +#define FSI_MDLYR_SEND1_SHFT 16 /* Selection 1 send delay cycles */
> +#define FSI_MDLYR_SEND1_MASK 0xf /* Selection 1 send delay cycles */
> +#define FSI_MDLYR_DFLT 0xffff0000 /* Default setting */
> +
> +static inline int fsi_mdlyr_echo0(int x)
> +{
> + return (x & FSI_MDLYR_ECHO0_MASK) << FSI_MDLYR_ECHO0_SHFT;
> +}
> +
> +static inline int fsi_mdlyr_echo1(int x)
> +{
> + return (x & FSI_MDLYR_ECHO1_MASK) << FSI_MDLYR_ECHO1_SHFT;
> +}
> +
> +static inline int fsi_mdlyr_send0(int x)
> +{
> + return (x & FSI_MDLYR_SEND0_MASK) << FSI_MDLYR_SEND0_SHFT;
> +}
> +
> +static inline int fsi_mdlyr_send1(int x)
> +{
> + return (x & FSI_MDLYR_SEND1_MASK) << FSI_MDLYR_SEND1_SHFT;
> +}
> +
> +static inline int fsi_mdlyr_extecho0(u32 x)
> +{
> + return (x >> FSI_MDLYR_ECHO0_SHFT) & FSI_MDLYR_ECHO0_MASK;
> +}
> +
> +static inline int fsi_mdlyr_extecho1(u32 x)
> +{
> + return (x >> FSI_MDLYR_ECHO1_SHFT) & FSI_MDLYR_ECHO1_MASK;
> +}
> +
> +static inline int fsi_mdlyr_extsend0(u32 x)
> +{
> + return (x >> FSI_MDLYR_SEND0_SHFT) & FSI_MDLYR_SEND0_MASK;
> +}
> +
> +static inline int fsi_mdlyr_extsend1(u32 x)
> +{
> + return (x >> FSI_MDLYR_SEND1_SHFT) & FSI_MDLYR_SEND1_MASK;
> +}
> +
> +/*
> + * MAEB Register
> + */
> +#define FSI_MASTER0 0x80000000 /* Primary Master */
> +
> +/*
> + * MVER Register
> + */
> +#define FSI_MVER_VER_MASK 0xff /* FSI master version mask */
> +#define FSI_MVER_VER_SHFT 24 /* FSI master version shift */
> +#define FSI_MVER_BRG_MASK 0xff /* FSI master FSI bridges mask */
> +#define FSI_MVER_BRG_SHFT 16 /* FSI master FSI bridges shift */
> +#define FSI_MVER_LINK_MASK 0xff /* FSI master links mask */
> +#define FSI_MVER_LINK_SHFT 8 /* FSI master links shift */
> +
> +static inline int fsi_mver_extversion(u32 x)
> +{
> + return (x >> FSI_MVER_VER_SHFT) & FSI_MVER_VER_MASK;
> +}
> +
> +static inline int fsi_mver_extport(u32 x)
> +{
> + return (x >> FSI_MVER_BRG_SHFT) & FSI_MVER_BRG_MASK;
> +}
> +
> +static inline int fsi_mver_extlink(u32 x)
> +{
> + return (x >> FSI_MVER_LINK_SHFT) & FSI_MVER_LINK_MASK;
> +}
> +
> +/*
> + * Master reset types
> + */
> +#define FSI_MRESB_RST_GEN 0x80000000 /* General reset */
> +#define FSI_MRESB_RST_ERR 0x40000000 /* Error Reset, don't use */
> +#define FSI_MRESB_DELAY 0x01000000 /* do delay settings */
> +
> +/*
> + * Port reset types
> + */
> +#define FSI_MRESP_RST_GEN 0x80000000 /* General reset */
> +#define FSI_MRESP_RST_ERR 0x40000000 /* Error Reset, don't use */
> +#define FSI_MRESP_RST_ALL_MSTR 0x20000000 /* Reset all FSI masters */
> +#define FSI_MRESP_RST_ALL_LINK 0x10000000 /* Reset all FSI port contr. */
> +#define FSI_MRESP_RST_MCR 0x08000000 /* Reset FSI master reg. */
> +#define FSI_MRESP_RST_PYE 0x04000000 /* Reset FSI parity error */
> +#define FSI_MRESP_RST_ALL 0xfc000000 /* Reset any error */
> +
> +/*
> + * MESRB Register
> + */
> +#define FSI_MESRB_EC_MASK 0xf /* Error code mask */
> +#define FSI_MESRB_EC_SHFT 28 /* Error code shift */
> +#define FSI_MESRB_PARITY_MASK 0xff /* Parity bits shift */
> +#define FSI_MESRB_PARITY_SHFT 16 /* Parity bits Mask */
> +#define FSI_MESRB_CRC_MASK 0xf /* CRC mask */
> +#define FSI_MESRB_CRC_SHFT 24 /* CRC shift */
> +#define FSI_MESRB_RESERVED_MASK 0xffff /* Reserved mask */
> +#define FSI_MESRB_OPB_PYE 0x0001000 /* OPB Parity Error */
> +#define FSI_MESRB_NE 0 /* No error */
> +#define FSI_MESRB_OPBE 1 /* OPB Error */
> +#define FSI_MESRB_IOPBS 2 /* Illegal OPB state */
> +#define FSI_MESRB_PAE 3 /* Port access error */
> +#define FSI_MESRB_IDM 4 /* ID mismatch */
> +#define FSI_MESRB_DMASE 5 /* DMA select error */
> +#define FSI_MESRB_PTOE 6 /* Port time out error */
> +#define FSI_MESRB_MTOE 7 /* Master time out error */
> +#define FSI_MESRB_MCRCE 8 /* Master CRC error */
> +#define FSI_MESRB_ERRA 9 /* Any error response */
> +#define FSI_MESRB_ERRC 10 /* CRC error response */
> +#define FSI_MESRB_PE 11 /* Protocol error */
> +#define FSI_MESRB_PYE 12 /* Parity err/Reg access err */
> +#define FSI_MESRB_LAST (FSI_MESRB_PYE + 1) /* Last entry */
> +
> +/* Extract error conditon */
> +static inline u32 fsi_mesrb_extec(u32 x)
> +{
> + return (x >> FSI_MESRB_EC_SHFT) & FSI_MESRB_EC_MASK;
> +}
> +
> +/* Extract CRC error counter */
> +static inline u32 fsi_mesrb_extcrc(u32 x)
> +{
> + return (x >> FSI_MESRB_CRC_SHFT) & FSI_MESRB_CRC_MASK;
> +}
> +
> +/* Extract parity error bits */
> +static inline u32 fsi_mesrb_extparity(u32 x)
> +{
> + return (x >> FSI_MESRB_PARITY_SHFT) & FSI_MESRB_PARITY_MASK;
> +}
> +
> +/*
> + * MATRB Register
> + */
> +#define FSI_MATRB_LPA_MASK 0x3f /* Last port/link addr mask */
> +#define FSI_MATRB_LPA_SHFT 26 /* Last port/link addr shift */
> +#define FSI_MATRB_LSID_MASK 3 /* Last slave id mask */
> +#define FSI_MATRB_LSID_SHFT 24 /* Last slave id shift */
> +#define FSI_MATRB_P8_ADDR_HI_MASK 3 /* Upper 2 bits of addr */
> +#define FSI_MATRB_P8_ADDR_HI_SHFT 24 /* Upper 2 bits of addr shift */
> +#define FSI_MATRB_SLPA_MASK 3 /* Last sublink address mask */
> +#define FSI_MATRB_SLPA_SHFT 19 /* Last sublink address shift */
> +#define FSI_MATRB_SLSID_SHFT 17 /* Last subslave id shift */
> +#define FSI_MATRB_READ_MASK 0x00400000 /* Last cmd was Read */
> +#define FSI_MATRB_ADDR_MASK 0x1fffff /* Last address mask */
> +#define FSI_MATRB_ADDR_SHFT 1 /* Last address shift */
> +#define FSI_MATRB_P8_ADDR_SHFT 3 /* Non contiguous upper bits */
> +#define FSI_MATRB_DATAS_MASK 1 /* Last addr data size mask */
> +#define FSI_MATRB_CM_MASK 0x00200000 /* Cascaded FSI mask */
> +
> +/* Extract link number */
> +static inline int fsi_matrb_lpa(u32 x)
> +{
> + return (x >> FSI_MATRB_LPA_SHFT) & FSI_MATRB_LPA_MASK;
> +}
> +
> +/* Extract data size of last command */
> +static inline int fsi_matrb_datasize(u32 x)
> +{
> + return x & FSI_MATRB_DATAS_MASK;
> +}
> +
> +/* Extract read/write command */
> +static inline int fsi_matrb_isread(u32 x)
> +{
> + return x & FSI_MATRB_READ_MASK;
> +}
> +
> +/*
> + * MSTAP Register
> + */
> +#define FSI_MSTAP_MASK 0xf /* Error mask ID 0..3 */
> +#define FSI_MSTAP_ID0_SHFT 28 /* CFAM 0 error shift */
> +#define FSI_MSTAP_ID1_SHFT 24 /* CFAM 1 error shift */
> +#define FSI_MSTAP_ID2_SHFT 20 /* CFAM 2 error shift */
> +#define FSI_MSTAP_ID3_SHFT 16 /* CFAM 3 error shift */
> +#define FSI_MSTAP_CRC_MASK 0xf /* CRC mask */
> +#define FSI_MSTAP_CRC_SHFT 12 /* CRC error counter */
> +#define FSI_MSTAP_HOTPLUG 0x800 /* Hotplug indicator */
> +#define FSI_MSTAP_NE 0 /* No error */
> +#define FSI_MSTAP_ERRA 1 /* Any error response */
> +#define FSI_MSTAP_ERRC 2 /* CRC error response */
> +#define FSI_MSTAP_UCRCE 3 /* Port detected CRC error */
> +#define FSI_MSTAP_IDM 4 /* ID mismatch */
> +#define FSI_MSTAP_PTOE 5 /* Port time out error */
> +#define FSI_MSTAP_IIPSE 6 /* Invalid I-Poll state error */
> +#define FSI_MSTAP_LAST (FSI_MSTAP_IIPSE + 1) /* Last entry */
> +
> +/* Extract error reason for slave id 0..3 */
> +static inline u32 fsi_mstap_extec(u32 x, int id)
> +{
> + return (x >> (FSI_MSTAP_ID0_SHFT - id * FSI_MAX_CASCADE))
> + & FSI_MSTAP_MASK;
> +}
> +
> +/* Extract crc counter */
> +static inline u32 fsi_mstap_extcrc(u32 x)
> +{
> + return (x >> FSI_MSTAP_CRC_SHFT) & FSI_MSTAP_CRC_MASK;
> +}
> +
> +/*
> + * MECTRL Register
> + */
> +#define FSI_MECTRL_TP_SHFT 24 /* parity error generation */
> +#define FSI_MECTRL_TP_MASK 0xff /* Mask for parity errors */
> +#define FSI_MECTRL_IPE_SHFT 16 /* Shift inhibit parity error */
> +#define FSI_MECTRL_IPE_MASK 0xff /* Mask inhibit parity err */
> +#define FSI_MECTRL_EOAE 0x8000 /* Enable machine check */
> +#define FSI_MECTRL_P8_AUTO_TERM 0x4000 /* Auto terminate */
> +#define FSI_MECTRL_FPME 0x2000 /* Freeze port on master err */
> +#define FSI_MECTRL_P8_SID_TO_3 0x0800 /* Force slave ID to 3 */
> +
> +/* Force parity error events */
> +static inline u32 fsi_mectrl_fpe(int id)
> +{
> + return (id & FSI_MECTRL_TP_MASK) << FSI_MECTRL_TP_SHFT;
> +}
> +
> +/* Inhibit parity errors */
> +static inline u32 fsi_mectrl_ipe(int id)
> +{
> + return (id & FSI_MECTRL_IPE_MASK) << FSI_MECTRL_IPE_SHFT;
> +}
> +
> +/*
> + * Returns the virtual address of the FSI slave configuration word 0 given
> + * the FSI slave engine 0 virtual address.
> + *
> + * NOTE: Assumes address space is mapped without holes. This is ok as both
> + * engines 2 2KB apart and Linux uses 4KB pages.
> + */
> +static inline void *get_termva(void *slv_va)
> +{
> + return (void *)((unsigned long)slv_va & ~0xfff);
> +}
> +
> +static inline unsigned long get_termpa(unsigned long slv_pa)
> +{
> + return slv_pa & ~0xfff;
> +}
> +
> +struct master_quirks {
> + int break_cfam_id;
> + void (*port_reset)(struct fsidevice *, struct fsidevice *, int);
> + int (*send_break)(struct fsimaster *, void *, int, struct fsicfam *);
> + int (*break_set_cfam_id)(void *, int);
> +};
> +
> +struct fsimaster { /* FSI master definition */
> + struct fsimaster *parent; /* Parent of this master */
> + char name[8]; /* Name for /sysfs */
> + unsigned long peek40c; /* Peek engine identifications */
> + u32 membase; /* Base MMIO address */
> + int irqbase; /* Base IRQ number */
> + struct fsidevice *fsidev; /* Pointer to fsi cascaded engine */
> + struct fsidevice *fsislv; /* Pointer to fsi slave engine */
> + struct fsi_mreg *base; /* Ptr to register space */
> + spinlock_t lock; /* Lock */
> + bool dcr_alloc; /* True if ioremap for dcr reg space */
> + bool have_peek; /* True if peek engine read needed */
> + unsigned char myid; /* FSI master identifier for traces */
> + unsigned char type; /* Type FSI master */
> + unsigned char hw_version; /* FSI master hardware version */
> + unsigned char maxlinks; /* FSI master links */
> + struct fsilink *link[FSI_MAX_LINKS];
> + void (*write_reg)(struct fsi_mreg *, int, u32); /* Write 32 bit word */
> + u32 (*read_reg)(struct fsi_mreg *, int); /* Read 32 bit word */
> + void (*write_reg2)(struct fsi_mreg *, int, u64 *); /* 64 bit */
> + void (*read_reg2)(struct fsi_mreg *, int, u64 *); /* 64 bit */
> + void (*read_reg4)(struct fsi_mreg *, int, u32 *); /* 4 words */
> + void (*write_reg8)(struct fsi_mreg *, int, u32 *); /* 8 words */
> + struct fsidevice * (*m_get)(struct fsimaster *, int, int);
> + int (*m_pa2irq)(struct fsimaster *, u32);
> + void (*m_exit)(struct fsimaster *);
> + struct master_quirks quirks; /* hardware quirks functions/data */
> + unsigned char srsic; /* master specific register offset */
> + unsigned char srsim; /* master specific register offset */
> + unsigned long cfam_size; /* master specific cfam size */
> +};
> +#define to_fsimaster_probe(a) \
> + container_of(a, struct fsimaster, hotp.probework)
> +#define to_fsimaster_build(a) \
> + container_of(a, struct fsimaster, hotp.buildwork)
> +
> +/*
> + * Functions to create/delete an FSI Master
> + */
> +struct fsimaster *fsimaster_build_init(struct fsimaster *, int,
> + struct fsidevice *);
> +struct fsimaster *fsimaster_build(int, struct fsidevice *);
> +void fsimaster_free(struct fsimaster *);
> +void fsimaster_put(struct fsimaster *);
> +struct fsimaster *fsimaster_get(struct fsimaster *);
> +struct fsimaster *fsimaster_find(u32);
> +int fsimaster_plugcheck(u32);
> +void fsimaster_start(struct fsimaster *);
> +int fsimaster_stop(struct fsimaster *);
> +void fsimaster_stopsync(struct fsimaster *);
> +int fsi_linkbuild(struct fsimaster *, int);
> +int fsi_linkdown(struct fsimaster *, int);
> +void fsi_linklost(struct fsimaster *, int);
> +
> +/*
> + * Master commands
> + */
> +int fsi_sendbreak(struct fsimaster *, u32, int);
> +struct fsimaster *fsimaster_get_top_master(struct fsimaster *);
> +
> +/*
> + * FSI master register access functions (without locking)
> + */
> +int fsimaster_reseterror_nl(struct fsimaster *, int);
> +int fsimaster_resetgeneral_nl(struct fsimaster *, int);
> +
> +/*
> + * Helper utilities for register access
> + */
> +void fsimaster_setspeed(struct fsimaster *, int, int);
> +int fsimaster_ipoll_off_link_mask(struct fsimaster *, int, u32 *);
> +int fsimaster_ipoll_off_link(struct fsimaster *, int);
> +int fsimaster_ipoll_on_link(struct fsimaster *, int, u32);
> +void fsimaster_disable_link(struct fsimaster *, int);
> +void fsimaster_enable_link(struct fsimaster *, int);
> +u64 fsimaster_read_menp(struct fsimaster *);
> +u64 fsimaster_read_menp_nl(struct fsimaster *);
> +u32 fsimaster_read_mmode(struct fsimaster *);
> +u32 fsimaster_read_mmode_nl(struct fsimaster *);
> +void fsimaster_read_mcrsp(struct fsimaster *, u64 *);
> +int fsimaster_read_msiep(struct fsimaster *);
> +int fsimaster_read_msiep_nl(struct fsimaster *);
> +int fsimaster_write_msiep(struct fsimaster *, u32 *);
> +int fsimaster_write_msiep_nl(struct fsimaster *, u32 *);
> +int setup_me(struct fsimaster *, int);
> +
> +/*
> + * Utilities to decode master error registers
> + */
> +int fsi_matrb_lsid(u32);
> +unsigned long fsi_matrb_addr(unsigned long);
> +
> +/*
> + * Helper utilities for link/cfam calculations.
> + */
> +u32 fsimaster_cfam2pa(struct fsimaster *, int, int);
> +u32 fsimaster_linksz(struct fsimaster *);
> +u32 fsimaster_cfamsz(struct fsimaster *);
> +
> +/*
> + * Helper utilities for IRQ number calculations.
> + */
> +int fsimaster_pa2irq(struct fsimaster *, u32);
> +int fsi_pa2irq(u32);
> +
> +/*
> + * Functions for link reference
> + */
> +void fsimaster_linkref_add(struct fsimaster *, struct fsilink *);
> +struct fsilink *fsimaster_linkref_del(struct fsimaster *, int);
> +struct fsilink *fsimaster_linkref_markdel(struct fsimaster *, int);
> +struct fsilink *fsimaster_linkget(struct fsimaster *, int);
> +struct fsilink *fsimaster_linkget_inirq(struct fsimaster *, int);
> +struct fsicfam *fsimaster_cfamget(struct fsimaster *, int, int);
> +struct fsidevice *fsimaster_slvget(struct fsimaster *, int, int);
> +struct fsidevice *fsimaster_slvget_inirq(struct fsimaster *, int, int);
> +struct fsidevice *fsimaster_engget(struct fsimaster *, int, int, int);
> +struct fsidevice *fsimaster_engget_inirq(struct fsimaster *, int, int, int);
> +void fsimaster_linkput(struct fsilink *);
> +void fsimaster_cfamput(struct fsicfam *);
> +void fsimaster_slvput(struct fsidevice *);
> +void fsimaster_engput(struct fsidevice *);
> +void fsi_rst_error2(struct fsimaster *, struct fsidevice *, int, int, int, int);
> +int port_reset(struct fsimaster *, int);
> +
> +#endif /* DRIVERS_FSIMASTER_H */
> --
> 1.8.2.2
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH linux v5 0/7] Introducing the FSI device driver
2016-09-02 5:05 ` [PATCH linux v5 0/7] Introducing the FSI device driver Joel Stanley
@ 2016-09-08 0:10 ` Joel Stanley
2016-09-21 18:49 ` Christopher Bostic
2016-09-21 18:52 ` Christopher Bostic
2016-09-21 17:42 ` Christopher Bostic
1 sibling, 2 replies; 19+ messages in thread
From: Joel Stanley @ 2016-09-08 0:10 UTC (permalink / raw)
To: Christopher Bostic; +Cc: OpenBMC Maillist, Chris Bostic, Jeremy Kerr
Hi Chris,
On Fri, Sep 2, 2016 at 2:35 PM, Joel Stanley <joel@jms.id.au> wrote:
> Hi Chris,
>
> On Thu, Aug 25, 2016 at 5:24 AM, <christopher.lee.bostic@gmail.com> wrote:
>> From: Chris Bostic <cbostic@us.ibm.com>
>>
>> Introduction of the IBM 'Flexible Support Interface' (FSI) bus device
>> driver. FSI is a high fan out serial bus consisting of a clock and a serial
>> data line capable of running at speeds up to 166 MHz.
>
I've taken a look at the patches. There doesn't seem to be much
improvement over the last version.
> I was wondering if you have had a look at Jeremy's implementation yet?
> If so, are there any ideas you have incorporated into your series?
I recommend you consider these questions and get back to me.
Cheers,
Joel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH linux v5 0/7] Introducing the FSI device driver
2016-09-02 5:05 ` [PATCH linux v5 0/7] Introducing the FSI device driver Joel Stanley
2016-09-08 0:10 ` Joel Stanley
@ 2016-09-21 17:42 ` Christopher Bostic
1 sibling, 0 replies; 19+ messages in thread
From: Christopher Bostic @ 2016-09-21 17:42 UTC (permalink / raw)
To: Joel Stanley; +Cc: OpenBMC Maillist, Chris Bostic
On Fri, Sep 2, 2016 at 12:05 AM, Joel Stanley <joel@jms.id.au> wrote:
> Hi Chris,
>
> On Thu, Aug 25, 2016 at 5:24 AM, <christopher.lee.bostic@gmail.com> wrote:
>> From: Chris Bostic <cbostic@us.ibm.com>
>>
>> Introduction of the IBM 'Flexible Support Interface' (FSI) bus device
>> driver. FSI is a high fan out serial bus consisting of a clock and a serial
>> data line capable of running at speeds up to 166 MHz.
>
> Nice work on the cover letter. It's a good introduction.
>
> I haven't had a chance to take a close look a the patches yet. They
> are on top of the stack for Monday.
>
> I was wondering if you have had a look at Jeremy's implementation yet?
> If so, are there any ideas you have incorporated into your series?
>
Joel, apologies for the slow response. Yes I've had a look at
Jeremy's suggestions and I'm in process of adapting my patch set to
incorporate those changes. Will reply to his note directly on
specifics. I've been focusing on getting all the core code ready for
submission and will have something for you by end of week.
> Cheers,
>
> Joel
>
>>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH linux v5 5/7] drivers/fsi: Add FSI bus type and hook into LDM
[not found] ` <CACPK8XcKuNAdrCiDuXpj5QgM+_U_+7hGKZd0ueZEGPcuurL=1g@mail.gmail.com>
@ 2016-09-21 18:16 ` Christopher Bostic
0 siblings, 0 replies; 19+ messages in thread
From: Christopher Bostic @ 2016-09-21 18:16 UTC (permalink / raw)
To: Joel Stanley, OpenBMC Maillist
On Wed, Sep 7, 2016 at 7:08 PM, Joel Stanley <joel@jms.id.au> wrote:
> On Thu, Aug 25, 2016 at 5:24 AM, <christopher.lee.bostic@gmail.com> wrote:
>> From: Chris Bostic <cbostic@us.ibm.com>
>>
>> Add FSI bus type. Add fsi device registration hooks into the LDM
>> Provide bus match/probe/remove/etc... callbacks for the LDM to invoke.
>>
>> Signed-off-by: Chris Bostic <cbostic@us.ibm.com>
>> ---
>> drivers/fsi/fsi.h | 42 ++++++++++++++++
>> drivers/fsi/fsiinit.c | 6 +++
>> drivers/fsi/ldm.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 184 insertions(+)
>>
>> diff --git a/drivers/fsi/fsi.h b/drivers/fsi/fsi.h
>> index b723208..67d4666 100644
>> --- a/drivers/fsi/fsi.h
>> +++ b/drivers/fsi/fsi.h
>> @@ -28,6 +28,20 @@ struct fsi_engine_id {
>> u8 engine_vendor;
>> };
>>
>> +/*
>> + * Bit fields to search for device/driver match. A driver may handle several
>> + * engines. If a driver handles all versions, just specify the type and
>> + * set match_flags to FSI_ENGINE_ID_MATCH_TYPE.
>> + * If a driver handles only certain versions, specify type and engine and
>> + * set match_flags to FSI_ENGINE_ID_MATCH_TYPE | FSI_ENGINE_ID_MATCH_VERSION.
>> + * Set the engine_vendor identifier and FSI_ENGINE_ID_MATCH_VENDOR if a
>> + * certain vendor has to be supported.
>> + */
>> +#define FSI_ENGINE_ID_MATCH_NONE 0 /* Last entry in chain */
>> +#define FSI_ENGINE_ID_MATCH_TYPE 1 /* Match the type */
>> +#define FSI_ENGINE_ID_MATCH_VERSION 2 /* Match the version */
>> +#define FSI_ENGINE_ID_MATCH_VENDOR 4 /* Match the vendor */
>> +
>> /* Location information for a FSI device */
>> struct fsimap {
>> u8 link; /* Master link # */
>> @@ -40,6 +54,18 @@ struct fsimap {
>> u16 kb_off; /* CFAM config table offset data */
>> };
>>
>> +#define FSI_DEV_MEMRES 1 /* Physical address of device */
>> +#define FSI_DEV_IRQRES 2 /* IRQ resource */
>> +#define FSI_DEV_VARES 3 /* Virtual address of device */
>> +#define FSI_DEV_NONE 4 /* Empty indicator */
>> +#define FSI_DEV_PSEUDO 5 /* Pseudo engine */
>> +#define FSI_DEV_IRQ 6 /* Has an IRQ */
>> +#define FSI_DEV_ACTIVE 7 /* Is activated */
>> +#define FSI_DEV_RLS_SLV 8 /* Release slave */
>> +#define FSI_DEV_PROBE_OK 9 /* Probe succeeded */
>> +#define FSI_DEV_PROBE_ERR 10 /* Probe failed */
>> +
>> +
>> struct fsidevice {
>> struct fsi_engine_id id; /* Engine type/version */
>> u32 irq_start; /* IRQ Number */
>> @@ -47,6 +73,22 @@ struct fsidevice {
>> struct fsidevice *parent; /* Parent of this device */
>> struct device dev; /* LDM entry for bus */
>> struct fsimap map; /* Address & location info */
>> + unsigned long state; /* flags for state */
>> };
>>
>> +#define to_fsidevice(x) container_of((x), struct fsidevice, dev)
>> +
>> +/*
>> + * FSI driver type
>> + */
>> +struct fsidriver {
>> + struct module *owner; /* Module owner */
>> + struct fsi_engine_id *idlist; /* List of IDs, terminated by */
>> + /* FSI_ENGINE_ID_MATCH_NONE */
>> + struct device_driver driver; /* LDM hook */
>> + int (*reset)(void *); /* Client defined reset method */
>> +};
>> +
>> +#define to_fsidriver(x) container_of((x), struct fsidriver, driver)
>> +
>> #endif /* DRIVERS_FSI_H */
>> diff --git a/drivers/fsi/fsiinit.c b/drivers/fsi/fsiinit.c
>> index eaa3582..d83992e 100644
>> --- a/drivers/fsi/fsiinit.c
>> +++ b/drivers/fsi/fsiinit.c
>> @@ -53,6 +53,12 @@ static int fsi_start(void)
>> goto err;
>> }
>> fsimaster_start(&fsidd.pri_master);
>> +
>> + if (fsibus_init()) { /* Create the FSI bus */
>> + rc = -ENFILE;
>> + goto err;
>> + }
>> +
>> dev_dbg(&fsidd.dev, "FSI DD v%d installation ok\n", FSIDD_VERNO);
>> return rc;
>>
>> diff --git a/drivers/fsi/ldm.c b/drivers/fsi/ldm.c
>> index 4a2f90b..9fe10b3 100644
>> --- a/drivers/fsi/ldm.c
>> +++ b/drivers/fsi/ldm.c
>> @@ -10,6 +10,7 @@
>> * as published by the Free Software Foundation; either version
>> * 2 of the License, or (at your option) any later version.
>> */
>> +#include <linux/blkdev.h>
>> #include "fsi.h"
>> #include "fsi_private.h"
>>
>> @@ -27,3 +28,138 @@ int fsidev_register(struct fsidevice *fsidev, struct device_attribute **ap)
>> return 0;
>> }
>> EXPORT_SYMBOL(fsidev_register);
>> +
>> +/*
>> + * FSI bus functions.
>> + */
>> +
>> +/*
>> + * Call a client's probe function if available
>> + */
>> +static int fsi_bus_probe(struct device *dev)
>> +{
>> + struct fsidevice *fsidev = to_fsidevice(dev);
>> + struct device_driver *drv = dev->driver;
>> + struct fsidriver *fsidrv = to_fsidriver(dev->driver);
>> + int rc = -ENOENT;
>> +
>> + dev_dbg(dev, "probe >> fsidrv:%p probe:%p resume:%p\n",
>> + fsidrv, drv->probe, drv->resume);
>> +
>> + if (!drv->probe)
>> + goto err;
>> + rc = drv->probe(dev);
>> + dev_dbg(dev, "drv->probe rc:%d\n", rc);
>> + if (rc) {
>> + /* Device unsupported or error in probe call back */
>> + if (rc != -ENODEV && rc != -ENXIO && rc != -ENOLINK) {
>> + set_bit(FSI_DEV_PROBE_ERR, &fsidev->state);
>> + goto err;
>> + }
>> + }
>> + set_bit(FSI_DEV_PROBE_OK, &fsidev->state);
>> + rc = 1;
>> +
>> + if (rc > 0 && drv->resume) {
>> + rc = drv->resume(dev);
>> + dev_dbg(dev, "probe resume rc:%d\n", rc);
>> + }
>> + rc = 0;
>> +err:
>> + dev_dbg(dev, "probe << rc:%d\n", rc);
>> + return rc;
>> +
>> +}
>> +
>> +static int fsi_bus_remove(struct device *dev)
>> +{
>> + dev_dbg(dev, "remove:%p %s\n", dev, dev_name(dev));
>> + return 0;
>> +}
>> +
>> +static void fsi_bus_shutdown(struct device *dev)
>> +{
>> + dev_dbg(dev, "shutdown:%p %s\n", dev, dev_name(dev));
>> +}
>> +
>
> These are empty, delete them.
Deleting.
>
>> +/*
>> + * Check if a particular engine matches the driver's list of supported devices.
>> + */
>> +static int fsi_bus_match(struct device *dev, struct device_driver *drv)
>> +{
>> + struct fsidevice *fsidev = to_fsidevice(dev);
>> + struct fsidriver *fsidrv = to_fsidriver(drv);
>> + int match_ok = 0;
>> + struct fsi_engine_id *idlist = fsidrv->idlist;
>> +
>> + for (; idlist->match_flags != FSI_ENGINE_ID_MATCH_NONE; ++idlist) {
>> + match_ok = 0;
>> +
>> + if ((idlist->match_flags & FSI_ENGINE_ID_MATCH_TYPE) != 0
>> + && fsidev->id.engine_type == idlist->engine_type)
>> + match_ok = 1;
>> +
>> + if (match_ok
>> + && (idlist->match_flags & FSI_ENGINE_ID_MATCH_VERSION) != 0)
>> + match_ok =
>> + fsidev->id.engine_version == idlist->engine_version;
>> +
>> + if (match_ok
>> + && (idlist->match_flags & FSI_ENGINE_ID_MATCH_VENDOR) != 0)
>> + match_ok =
>> + fsidev->id.engine_vendor == idlist->engine_vendor;
>> +
>> + if (match_ok)
>> + break;
>> + }
>> + dev_dbg(dev,
>> + "match type:%02x version:%d vendor:%d match_ok:%d\n",
>> + fsidev->id.engine_type, fsidev->id.engine_version,
>> + fsidev->id.engine_vendor, match_ok);
>> +
>> + return match_ok;
>> +}
>> +
>> +
>> +static int fsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
>> +{
>> +
>> + dev_dbg(dev, "%s device:%p\n", dev_name(dev), dev);
>> + if (MAJOR(dev->devt)) {
>> + if (add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)))
>> + return -ENOMEM;
>> + if (add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)))
>> + return -ENOMEM;
>> + }
>> +
>> + /* Add bus name of physical device */
>> + if (dev->bus) {
>> + if (add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name))
>> + return -ENOMEM;
>> + }
>> +
>> + /* Add driver name of physical device */
>> + if (dev->driver) {
>> + if (add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name))
>> + return -ENOMEM;
>> + }
>> + return 0;
>> +};
>> +
>> +struct bus_type fsi_bus_type = {
>> + .name = "fsi",
>> + .match = fsi_bus_match,
>> + .uevent = fsi_bus_uevent,
>> + .probe = fsi_bus_probe,
>> + .remove = fsi_bus_remove,
>> + .shutdown = fsi_bus_shutdown,
>
> Only register the callbacks that are going to do something. You don't
> need to add ones that only print a message and return.
Removing .remove and .shutdown.
>
>> +};
>> +EXPORT_SYMBOL(fsi_bus_type);
>> +
>> +/*
>> + * Create and install the FSI bus
>> + */
>> +int fsibus_init(void)
>> +{
>> + return bus_register(&fsi_bus_type);
>> +}
>> --
>> 1.8.2.2
>>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH linux v5 2/7] drivers/fsi: Add FSI Master Functionality and Initialization
2016-09-08 0:09 ` Joel Stanley
@ 2016-09-21 18:38 ` Christopher Bostic
2016-09-21 22:59 ` Brad Bishop
2016-09-21 21:15 ` Christopher Bostic
1 sibling, 1 reply; 19+ messages in thread
From: Christopher Bostic @ 2016-09-21 18:38 UTC (permalink / raw)
To: Joel Stanley; +Cc: OpenBMC Maillist, Chris Bostic
On Wed, Sep 7, 2016 at 7:09 PM, Joel Stanley <joel@jms.id.au> wrote:
> On Thu, Aug 25, 2016 at 5:24 AM, <christopher.lee.bostic@gmail.com> wrote:
>> From: Chris Bostic <cbostic@us.ibm.com>
>>
>> Define the FSI master control register set and its accessors.
>> Initialize the primary FSI master.
>>
>> Signed-off-by: Chris Bostic <cbostic@us.ibm.com>
>> ---
>
> I recall reading this patch in the past. No changelog?
Had the changes specific to this patch in 0001, will move those to 0002.
>
>> drivers/fsi/Makefile | 2 +-
>> drivers/fsi/fsi.h | 32 +++
>> drivers/fsi/fsi_private.h | 97 +++++++
>> drivers/fsi/fsicfam.h | 46 ++++
>> drivers/fsi/fsiinit.c | 22 ++
>> drivers/fsi/fsiinit.h | 2 +
>> drivers/fsi/fsimaster.c | 242 +++++++++++++++++
>> drivers/fsi/fsimaster.h | 655 ++++++++++++++++++++++++++++++++++++++++++++++
>> 8 files changed, 1097 insertions(+), 1 deletion(-)
>> create mode 100644 drivers/fsi/fsi.h
>> create mode 100644 drivers/fsi/fsi_private.h
>> create mode 100644 drivers/fsi/fsicfam.h
>> create mode 100644 drivers/fsi/fsimaster.c
>> create mode 100644 drivers/fsi/fsimaster.h
>>
>> diff --git a/drivers/fsi/Makefile b/drivers/fsi/Makefile
>> index f547c08..9800c15 100644
>> --- a/drivers/fsi/Makefile
>> +++ b/drivers/fsi/Ma
>> + * Determine the link address to send the break command to
>> + * This is master dependent
>> + */
>> +static inline int fsi_mtype_2break_id(u8 mtype)
>> +{
>> + return FSI_MAX_CASCADE - 1;
>> +}
>> +
>> +/*
>> + * Build a mask where bit index 'x' is set (numbering from left to right.
>> + * Bit 0 is MSB and bit 31 is LSM.
>> + */
>> +static inline unsigned long mask32(int x)
>> +{
>> + return 1 << (BITS_PER_LONG - x - 1);
>
> Is this masking in IBM bit ordering?
>
> We should pull the macros (or at least copy them) from arch/powerpc so
> we can use them here.
Will do, should be easy
>
>> +}
>> +
>> +/*
>> + * Various function prototypes
>> + */
>> +int slv_install(void);
>> +void slv_uninstall(void);
>> +
>> +void fsi_exit_fileio(dev_t);
>> +
>> +int fsibus_init(void);
>> +void fsibus_exit(void);
>> +
>> +#endif /* DRIVERS_FSI_PRIVATE_H */
>> diff --git a/drivers/fsi/fsicfam.h b/drivers/fsi/fsicfam.h
>> new file mode 100644
>> index 0000000..dde7036
>> --- /dev/null
>> +++ b/drivers/fsi/fsicfam.h
>> @@ -0,0 +1,46 @@
>> +/*
>> + * FSI CFAM structure definitions and defines
>> + *
>> + * Copyright 2016 IBM Corp.
>> + *
>> + * Christopher Bostic <cbostic@us.ibm.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * as published by the Free Software Foundation; either version
>> + * 2 of the License, or (at your option) any later version.
>> + */
>> +#ifndef DRIVERS_FSICFAM_H
>> +#define DRIVERS_FSICFAM_H
>> +
>> +#include "fsi.h"
>> +#include "fsi_private.h"
>> +
>> +#define FSI_MAX_ENGINES 32 /* Max # of engines per CFAM */
>> +
>> +struct fsicfam { /* CFAM internal structure */
>> + struct fsidevice *engines[FSI_MAX_ENGINES]; /* CFAM engine data */
>> + u32 cfgtab[FSI_MAX_ENGINES]; /* Configuration word */
>> + u16 chipid; /* CFAM chip type (IOU, CFAM-S, etc) */
>> + u8 id; /* CFAM Id */
>> + bool has_submaster; /* CFAM with cascaded or hub masters */
>> + bool has_mux; /* CFAM with multiplexer */
>> + u8 ec_maj; /* Major EC Level */
>> + u8 ec_min; /* Minor EC Level or version number */
>> + u16 pages; /* # Mapped pages */
>> + u8 no_eng; /* Number of engines[] */
>> + struct fsidevice fsidev; /* LDM entry */
>> + struct fsidevice hpdone; /* Dummy engine to signal completion */
>> + unsigned long eng_build; /* True during engine activate */
>> + struct fsimaster *master; /* pointer to parent master */
>> +};
>> +
>> +#define to_fsicfam(x) container_of((x), struct fsicfam, fsidev)
>
> Make this a function.
Will change.
>
>> +
>> +/*
>> + * CFAM specific function prototypes.
>> + */
>> +int fsi_cfamirq_request(int, struct fsicfam *);
>> +void fsi_cfamirq_free(struct fsicfam *);
>> +
>> +#endif /* DRIVERS_FSICFAM_H */
>> diff --git a/drivers/fsi/fsiinit.c b/drivers/fsi/fsiinit.c
>> index 767c0c3..c589294 100644
>> --- a/drivers/fsi/fsiinit.c
>> +++ b/drivers/fsi/fsiinit.c
>> @@ -13,7 +13,9 @@
>>
>> #include <linux/init.h>
>> #include <linux/module.h>
>> +#include <linux/kdev_t.h>
>> #include "fsiinit.h"
>> +#include "fsimaster.h"
>>
>> MODULE_AUTHOR("Christopher Bostic cbostic@us.ibm.com");
>> MODULE_DESCRIPTION("FSI master device driver");
>> @@ -26,6 +28,7 @@ MODULE_DESCRIPTION("FSI master device driver");
>> struct fsidd fsidd = { /* FSI device driver structure definition */
>> .magic = FSI_DD_MAGIC,
>> .strno = FSI_DD_STRNO,
>> + .major = MKDEV(FSIDD_MAJOR, 0),
>> };
>>
>> static int fsi_start(void)
>> @@ -33,6 +36,25 @@ static int fsi_start(void)
>> int rc = 0;
>>
>> dev_dbg(&fsidd.dev, "FSI DD v:%d installation ok\n", FSIDD_VERNO);
>> +
>> + init_waitqueue_head(&fsidd.error_wq);
>> + init_waitqueue_head(&fsidd.lbus_wq);
>> + init_waitqueue_head(&fsidd.irq_wq);
>> + init_waitqueue_head(&fsidd.link_wq);
>> +
>> + /*
>> + * Initialize the the master
>> + */
>> + if (!fsimaster_build_init(&fsidd.pri_master, FSI_PRIM, 0)) {
>> + rc = PTR_ERR(0);
>
> ???
>
>> + goto err;
>> + }
>> + fsimaster_start(&fsidd.pri_master);
>> + dev_dbg(&fsidd.dev, "FSI DD v%d installation ok\n", FSIDD_VERNO);
>> + return rc;
>> +
>> +err:
>> + dev_dbg(&fsidd.dev, "FSI DD v:%d installation failed\n", FSIDD_VERNO);
>> return rc;
>
> Your formatting is broken.
How is it broken? Not sure what '???' means.
>
>> }
>>
>> diff --git a/drivers/fsi/fsiinit.h b/drivers/fsi/fsiinit.h
>> index 93662533..10ddfc0 100644
>> --- a/drivers/fsi/fsiinit.h
>> +++ b/drivers/fsi/fsiinit.h
>> @@ -19,6 +19,7 @@
>> #include <linux/device.h>
>> #include <linux/workqueue.h>
>> #include <linux/hrtimer.h>
>> +#include "fsimaster.h"
>>
>> #define FSI_DD_MAGIC 0x64644632 /* ddF2 */
>> #define FSI_DD_STRNO 0x1 /* Structure version number */
>> @@ -34,6 +35,7 @@ struct fsidd { /* FSI Main structure */
>> wait_queue_head_t link_wq; /* Wait queue for link changes */
>> unsigned long state; /* State driver is in */
>> struct device dev; /* Anchor point in /sys/kernel */
>> + struct fsimaster pri_master; /* Primary FSI master */
>> };
>>
>> #define to_fsidd_prim(a) container_of(a, struct fsidd, pri_master)
>> diff --git a/drivers/fsi/fsimaster.c b/drivers/fsi/fsimaster.c
>> new file mode 100644
>> index 0000000..b5d16db
>> --- /dev/null
>> +++ b/drivers/fsi/fsimaster.c
>> @@ -0,0 +1,242 @@
>> +/*
>> + * FSI Master Control
>> + *
>> + * Copyright 2016 IBM Corp.
>> + *
>> + * Christopher Bostic <cbostic@us.ibm.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * as published by the Free Software Foundation; either version
>> + * 2 of the License, or (at your option) any later version.
>> + */
>> +
>> +#include <linux/err.h>
>> +#include <linux/delay.h>
>> +#include <linux/ktime.h>
>> +#include <linux/io.h>
>> +#include "fsi.h"
>> +#include "fsiinit.h"
>> +#include "fsimaster.h"
>> +#include "fsicfam.h"
>> +
>> +static int hpinfo_alloc(struct fsimaster *master)
>> +{
>> + return 0;
>> +}
>> +
>> +static inline unsigned int fsimid(struct fsimaster *master)
>> +{
>> + return master->myid;
>> +}
>> +
>> +static void primaster_exit(struct fsimaster *master)
>> +{
>> + if (master->dcr_alloc) {
>> + master->base = NULL;
>> + master->dcr_alloc = false;
>> + }
>> +}
>> +
>> +/*
>> + * Read/write functions to access primary FSI master registers
>> + * Note that this master is virtual as we don't yet have any
>> + * real FSI masters implemented in hardware
>
> "virtual"? What's the purpose of this code?
For implementations without a real hardware FSI master such as soft
FSI there is a 'virtual' master in memory where registers are just u32
variables in a data structure. Will add comments to make this clear.
>
>> + */
>> +static u32 virt_master_readreg(struct fsi_mreg *mbase, int regnm)
>> +{
>> + u32 *base = (u32 *)mbase;
>> +
>> + return *(base + regnm);
>> +}
>> +
>> +static void virt_master_readreg2(struct fsi_mreg *mbase, int regnm, u64 *dest)
>> +{
>> + u32 *base = (u32 *)mbase;
>> +
>> + memcpy(dest, base + regnm, sizeof(u64));
>> +}
>> +
>> +static void virt_master_readreg4(struct fsi_mreg *mbase, int regnm, u32 *dest)
>> +{
>> + u32 *base = (u32 *)mbase;
>> +
>> + memcpy(dest, base + regnm, 4 * sizeof(u32));
>> +}
>>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH linux v5 4/7] drivers/fsi: Add initial FSI link buildup
[not found] ` <CACPK8XfE0LpLnU64bw-8JA70wvAwbfO7L-fb6foyOLv-nMfNeg@mail.gmail.com>
@ 2016-09-21 18:44 ` Christopher Bostic
0 siblings, 0 replies; 19+ messages in thread
From: Christopher Bostic @ 2016-09-21 18:44 UTC (permalink / raw)
To: Joel Stanley, OpenBMC Maillist
On Wed, Sep 7, 2016 at 7:09 PM, Joel Stanley <joel@jms.id.au> wrote:
> On Thu, Aug 25, 2016 at 5:24 AM, <christopher.lee.bostic@gmail.com> wrote:
>> From: Chris Bostic <cbostic@us.ibm.com>
>>
>> Add function to allow the primary FSI master to begin a buildup of a link
>> when a target device is found. Buildup is the process of creating an
>> internal device tree representing the physical target device connections
>> on a given master. First a master must create a link structure and
>> initialize it when there is a target device present on the other end of the
>> link.
>>
>> Begin process of 'pinging' target device called a 'CFAM'. CFAM (Common
>> Field replaceable unit Access Macro) contains an FSI slave that is the
>> target of any FSI master communications. First the master pings by sending
>> a BREAK command to determine if anyone is listening. If CFAM is accessible
>> by reading its configuration space then the link buildup process begins.
>>
>> Signed-off-by: Chris Bostic <cbostic@us.ibm.com>
>> ---
>> drivers/fsi/Makefile | 2 +-
>> drivers/fsi/build.c | 114 +++++++++++++
>> drivers/fsi/fsi.h | 20 +++
>> drivers/fsi/fsi_private.h | 21 +++
>> drivers/fsi/fsiinit.c | 3 +
>> drivers/fsi/fsilink.h | 99 ++++++++++++
>> drivers/fsi/fsimaster.c | 218 +++++++++++++++++++++++++
>> drivers/fsi/fsimaster.h | 5 +
>> drivers/fsi/fsislave.h | 404 ++++++++++++++++++++++++++++++++++++++++++++++
>> drivers/fsi/ldm.c | 29 ++++
>> drivers/fsi/readwrite.c | 34 ++++
>> 11 files changed, 948 insertions(+), 1 deletion(-)
>> create mode 100644 drivers/fsi/build.c
>> create mode 100644 drivers/fsi/fsilink.h
>> create mode 100644 drivers/fsi/fsislave.h
>> create mode 100644 drivers/fsi/ldm.c
>> create mode 100644 drivers/fsi/readwrite.c
>>
>> diff --git a/drivers/fsi/Makefile b/drivers/fsi/Makefile
>> index 9800c15..2445cee 100644
>> --- a/drivers/fsi/Makefile
>> +++ b/drivers/fsi/Makefile
>> @@ -2,4 +2,4 @@
>> # Makefile for the FSI bus specific drivers.
>> #
>>
>> -obj-y += fsiinit.o fsimaster.o
>> +obj-y += fsiinit.o fsimaster.o build.o readwrite.o ldm.o
>> diff --git a/drivers/fsi/build.c b/drivers/fsi/build.c
>> new file mode 100644
>> index 0000000..c9a31c0
>> --- /dev/null
>> +++ b/drivers/fsi/build.c
>> @@ -0,0 +1,114 @@
>> +/*
>> + * FSI Link Build up
>> + *
>> + * Copyright 2016 IBM Corp.
>> + *
>> + * Christopher Bostic <cbostic@us.ibm.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * as published by the Free Software Foundation; either version
>> + * 2 of the License, or (at your option) any later version.
>> + */
>> +#include <linux/err.h>
>> +#include <linux/delay.h>
>> +#include <linux/slab.h>
>> +#include <linux/io.h>
>> +#include "fsi.h"
>> +#include "fsi_private.h"
>> +#include "fsimaster.h"
>> +#include "fsicfam.h"
>> +#include "fsilink.h"
>> +
>> +static void link_release(struct device *devp)
>> +{
>> +}
>> +
>> +/*
>> + * Create a FSI link struct and assign it to the FSI tree
>> + */
>> +static struct fsilink *link_add(struct fsimaster *master, int no)
>> +{
>> + int rc = 0;
>> + struct fsilink *link = NULL;
>> + int id = 0;
>> +
>> + id = fsi_mtype_2break_id(master->type);
>> +
>> + link = kmalloc(sizeof(struct fsilink), GFP_KERNEL);
>> + if (!link)
>> + return link;
>> +
>> + dev_set_name(&link->fsidev.dev, "link-%d", no);
>> + link->id3_addr = (FSI_MAX_CASCADE - 1) * FSI_CFAM_SIZE;
>> + link->master = master;
>> + link->linkno = no;
>> + link->fsidev.map.va = link->id3_addr;
>> + link->fsidev.map.cmtype = master->type;
>> + link->fsidev.id.engine_type = FSI_ENGID_LINK;
>> + link->fsidev.map.kb = fsimaster_linksz(master) / FSI_ENGINE_SIZE;
>> + link->fsidev.irq_start = no * (FSI_MAX_CASCADE * FSI_MAX_ENGINES);
>> + link->fsidev.irq_range = FSI_MAX_CASCADE * FSI_MAX_ENGINES;
>> + if (!master->fsidev)
>> + link->fsidev.dev.parent = 0;
>> + else
>> + link->fsidev.dev.parent = &master->fsidev->dev;
>> + link->fsidev.dev.release = link_release;
>> +
>> + /* stub */
>> +
>> + return link ? : ERR_PTR(rc);
>> +}
>> +
>> +static void linkbuild2(struct fsimaster *master, struct fsilink *link)
>> +{
>> +}
>> +
>> +/*
>> + * Return number of CFAMs discovered. If something fails during the build up
>> + * process return error reason
>> + */
>> +static int linkbuild1(struct fsimaster *master, int no)
>
> The naming needs to be fixed.
Will fix.
>
>> +{
>> + int i, rc = 0;
>> + struct fsilink *link = link_add(master, no);
>> +
>> + if (IS_ERR(link))
>> + return PTR_ERR(link);
>> +
>> + /* stub */
>> +
>> + linkbuild2(master, link);
>> + i = link->cascade;
>> + if (i == 0) {
>> +
>> + /* stub */
>> +
>> + rc = -EIO;
>> + } else {
>> +
>> + /* stub */
>> + }
>> +
>> + return rc;
>> +}
>> +
>> +/*
>> + * Build up a link. Returns number of CFAMs discovered.
>> + */
>> +int fsi_linkbuild(struct fsimaster *master, int no)
>> +{
>> + int rc;
>> + u64 menp;
>> +
>> + menp = fsimaster_read_menp(master);
>> + if (menp & mask64(no))
>> + return -EEXIST; /* Already running */
>> +
>> + fsimaster_enable_link(master, no);
>> + rc = linkbuild1(master, no);
>> + if (rc < 0)
>> + fsimaster_disable_link(master, no);
>> +
>> + return rc;
>> +}
>> diff --git a/drivers/fsi/fsi.h b/drivers/fsi/fsi.h
>> index f146396..b723208 100644
>> --- a/drivers/fsi/fsi.h
>> +++ b/drivers/fsi/fsi.h
>> @@ -15,15 +15,35 @@
>>
>> #include <linux/device.h>
>>
>> +/*
>> + * Engine ID's
>> + */
>> +#define FSI_ENGID_LINK 0xff /* Link Identifier */
>> +
>> +/* Engine ID as it appears in the CFAM configuration table */
>> +struct fsi_engine_id {
>> + u8 match_flags;
>> + u8 engine_type;
>> + u8 engine_version;
>> + u8 engine_vendor;
>> +};
>> +
>> +/* Location information for a FSI device */
>> struct fsimap {
>> u8 link; /* Master link # */
>> u8 cfam; /* CFAM # on link */
>> + u8 eng; /* Engine # on CFAM */
>> + u8 cmtype; /* Type of master upstream */
>> u32 offset; /* Address offset into CFAM */
>> u32 va; /* Virtual address */
>> + u16 kb; /* Size of dev engine space */
>> + u16 kb_off; /* CFAM config table offset data */
>> };
>>
>> struct fsidevice {
>> + struct fsi_engine_id id; /* Engine type/version */
>> u32 irq_start; /* IRQ Number */
>> + u16 irq_range; /* Number of IRQs */
>> struct fsidevice *parent; /* Parent of this device */
>> struct device dev; /* LDM entry for bus */
>> struct fsimap map; /* Address & location info */
>> diff --git a/drivers/fsi/fsi_private.h b/drivers/fsi/fsi_private.h
>> index be327ef..afa2553 100644
>> --- a/drivers/fsi/fsi_private.h
>> +++ b/drivers/fsi/fsi_private.h
>> @@ -44,10 +44,22 @@
>> #define FSI_PRIM 0 /* Generic Primary FSI master */
>> #define FSI_MBIT_MASK 0x3 /* FSI master bits in pa */
>> #define FSI_ENG_MASK 0x00007FFF /* The engine mask in MATRB */
>> +
>> /* FSI Events */
>> +#define FSI_EVT_LBUSLOST 1 /* Local bus loss */
>> +#define FSI_EVT_LBUSRECV 2 /* Local bus gained */
>> +#define FSI_EVT_IRQLOOP 3 /* IRQ loop detected */
>> +#define FSI_EVT_LINKCHG 4 /* Link state change */
>> +#define FSI_EVT_UNPLUG 5 /* Device unplugged */
>> #define FSI_EVT_PLUG 6 /* Device plugged */
>> +#define FSI_EVT_CFAMADD 7 /* New CFAM found */
>> +#define FSI_EVT_CFAMDELETE 8 /* Removing a CFAM */
>> +#define FSI_EVT_CFAMDEAD 9 /* CFAM no longer functions */
>> #define FSI_LINK_BUILD 10 /* In build up phase */
>> #define FSI_LINK_PROBE 11 /* In probing phase */
>> +#define FSI_LINK_RUNNING 12 /* Link up and running */
>> +#define FSI_LINK_DEAD 13 /* Link defective */
>> +#define FSI_LINK_WAITFOR 14 /* Wait for buildup */
>>
>> /*
>> * Return the link number where this device is attached
>> @@ -76,6 +88,15 @@ static inline int fsi_mtype_2break_id(u8 mtype)
>>
>> /*
>> * Build a mask where bit index 'x' is set (numbering from left to right.
>> + * Bit 0 is MSB and bit 63 is LSM.
>> + */
>> +static inline u64 mask64(int x)
>> +{
>> + return 1 << (BITS_PER_LONG_LONG - x - 1);
>> +}
>> +
>
> I've seen this function before. Can we share it?
>
As per previous comments in patch v5 0002 you suggested pulling in the
arch/powerpc functions.
Will remove the local definitions of mask64 and mask32
>> +/*
>> + * Build a mask where bit index 'x' is set (numbering from left to right.
>> * Bit 0 is MSB and bit 31 is LSM.
>> */
>> static inline unsigned long mask32(int x)
>> diff --git a/drivers/fsi/fsiinit.c b/drivers/fsi/fsiinit.c
>> index c589294..eaa3582 100644
>> --- a/drivers/fsi/fsiinit.c
>> +++ b/drivers/fsi/fsiinit.c
>> @@ -14,8 +14,11 @@
>> #include <linux/init.h>
>> #include <linux/module.h>
>> #include <linux/kdev_t.h>
>> +#include <linux/io.h>
>> +#include <linux/slab.h>
>> #include "fsiinit.h"
>> #include "fsimaster.h"
>> +#include "fsi_private.h"
>>
>> MODULE_AUTHOR("Christopher Bostic cbostic@us.ibm.com");
>> MODULE_DESCRIPTION("FSI master device driver");
>> diff --git a/drivers/fsi/fsilink.h b/drivers/fsi/fsilink.h
>> new file mode 100644
>> index 0000000..f923650
>> --- /dev/null
>> +++ b/drivers/fsi/fsilink.h
>> @@ -0,0 +1,99 @@
>> +/*
>> + * FSI link structure definitions and defines
>> + *
>> + * Copyright 2016 IBM Corp.
>> + *
>> + * Christopher Bostic <cbostic@us.ibm.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * as published by the Free Software Foundation; either version
>> + * 2 of the License, or (at your option) any later version.
>> + */
>> +#ifndef DRIVERS_FSILINK_H
>> +#define DRIVERS_FSILINK_H
>> +
>> +#include <linux/types.h>
>> +#include <linux/kobject.h>
>> +#include <linux/device.h>
>> +#include "fsi.h"
>> +#include "fsi_private.h"
>> +
>> +/*
>> + * Extended FSI error counting and thresholding. Count the FSI errors with
>> + * time they occurred.
>> + */
>> +#define FSI_MAX_PE 6 /* Max # of FSI port errors */
>> +#define FSI_MAX_ME 11 /* Max # of FSI master errors */
>> +#define FSI_MAX_SE 10 /* Max # of FSI slave V3 errors */
>> +#define FSI_MAX_SEV2 6 /* Max # of FSI slave V2 errors */
>> +
>> +struct fsi_ecnt { /* Structure for counting errors */
>> + unsigned short cnt; /* Counter */
>> + struct timeval seen_1st; /* First occurrence */
> first
Changing
>
>> + struct timeval seen_last; /* Last occurrence */
>> +};
>> +
>> +struct fsi_eport { /* Port error statistics */
>> + unsigned short pec[FSI_MAX_PE]; /* Port errors counter per type */
>> + unsigned short pcrc_cnt; /* Recovered CRC counter port */
>> +};
>> +
>> +struct fsi_eslv { /* Slave error statistics */
>> + unsigned short sec[FSI_MAX_SE]; /* Slave errors counter per type */
>> + unsigned short scrc_cnt; /* Recovered CRC counter slave */
>> +};
>> +
>> +struct fsi_emaster { /* Master error statistics */
>> + unsigned short mec[FSI_MAX_ME]; /* Master errors counter per type */
>> + unsigned short mcrc_cnt; /* Recovered CRC counter master */
>> +};
>
> Could all of these statistics go in the one struct?
>
Do you suggest a new stats struct that contains all of these?
>> +
>> +struct fsi_elink { /* Link error statistics */
>> + struct fsi_emaster master; /* Master errors */
>> + struct fsi_eport port; /* Port errors */
>> + struct fsi_eslv slv[FSI_MAX_CASCADE]; /* Slave errors */
>> + struct fsi_ecnt breaked; /* BREAK command sent */
>> +};
>> +
>> +enum fsilink_state { /* Bit mask for error states */
>> + fsilink_lost = 1, /* Link already schedule for removal */
>> + fsilink_up = 2, /* Link up & running */
>> + fsilink_going = 3 /* Link removal in progress */
>> +};
>> +
>> +struct fsilink { /* Information per link */
>> + u8 speedset; /* Link speed set (0 or 1) */
>> + u8 cascade; /* Length of cascade */
>> + u8 top_cfam; /* # CFAM found on initial scan */
>> + u8 linkno; /* Number of this link */
>> + unsigned long state; /* Bit mask for error states */
>> + struct fsicfam *cfams[FSI_MAX_CASCADE]; /* CFAMs per link */
>> + struct fsidevice fsidev;
>> + u32 id3_addr; /* CFAM id3 page */
>> + struct fsimaster *master; /* Ptr to controlling fsi master */
>> + struct fsi_elink error; /* Errors on this link */
>> +};
>> +
>> +#define FSILINK_ATTR(_name, _mode, _show, _store) \
>> +struct device_attribute fsilink_attr_##_name = { \
>> + .attr = { \
>> + .name = __stringify(_name), \
>> + .mode = _mode, \
>> + }, \
>> + .show = _show, \
>> + .store = _store \
>> +}
>> +
>> +/*
>> + * Pointer conversion from fsidevice member to fsilink.
>> + */
>> +#define to_fsilink(x) container_of((x), struct fsilink, fsidev)
>> +
>> +unsigned char fsilink_get_top_cfam(struct fsilink *);
>> +unsigned char fsilink_get_linkno(struct fsilink *);
>> +unsigned long fsilink_get_state(struct fsilink *);
>> +struct fsicfam *fsilink_get_cfam(struct fsilink *, int);
>> +struct device *fsilink_get_device(struct fsilink *);
>> +
>> +#endif /* DRIVERS_FSILINK_H */
>> diff --git a/drivers/fsi/fsimaster.c b/drivers/fsi/fsimaster.c
>> index 8054051..427231f 100644
>> --- a/drivers/fsi/fsimaster.c
>> +++ b/drivers/fsi/fsimaster.c
>> @@ -17,9 +17,11 @@
>> #include <linux/io.h>
>> #include <linux/bitops.h>
>> #include "fsi.h"
>> +#include "fsi_private.h"
>> #include "fsiinit.h"
>> #include "fsimaster.h"
>> #include "fsicfam.h"
>> +#include "fsislave.h"
>>
>> static int hpinfo_alloc(struct fsimaster *master)
>> {
>> @@ -150,6 +152,9 @@ static int fsimaster_init(struct fsimaster *master)
>> return rc;
>> }
>>
>> +/*
>> + * Retrieve the first master in the chain
>> + */
>
> The comment should be added when you add the function.
>
Will fix.
>> struct fsimaster *fsimaster_get_top_master(struct fsimaster *master)
>> {
>> struct fsimaster *parent = NULL;
>> @@ -163,10 +168,195 @@ struct fsimaster *fsimaster_get_top_master(struct fsimaster *master)
>> }
>>
>> /*
>> + * Get the address space size of a link/CFAM
>> + */
>> +
>> +u32 fsimaster_cfamsz(struct fsimaster *master)
>> +{
>> + return master->cfam_size;
>> +}
>> +
>> +u32 fsimaster_linksz(struct fsimaster *master)
>> +{
>> + return FSI_MAX_CASCADE * fsimaster_cfamsz(master);
>> +}
>> +
>> +/*
>> + * Find physical address given master and link #
>> + */
>> +u32 fsimaster_link2pa(struct fsimaster *master, int link)
>> +{
>> + u32 offset = link * fsimaster_linksz(master);
>> +
>> + return master->membase + offset;
>> +}
>> +
>> +/*
>> + * Find physical address given master, link # and CFAM #
>> + */
>> +u32 fsimaster_cfam2pa(struct fsimaster *master, int link, int cfam)
>> +{
>> + u32 offset = link * fsimaster_linksz(master) +
>> + cfam * fsimaster_cfamsz(master);
>> +
>> + return master->membase + offset;
>> +}
>> +
>> +int fsim_pa2irq(struct fsimaster *master, u32 pa)
>> +{
>> + return 0;
>> +}
>> +
>> +int fsi_pa2irq(u32 pa)
>> +{
>> + return 0;
>> +}
>> +
>> +/*
>> + * Master control register accessors
>> + */
>> +
>> +/*
>> + * Read/write mode register: MMODE
>> + */
>> +u32 fsimaster_read_mmode_nl(struct fsimaster *master)
>> +{
>> + return master->read_reg(master->base, FSI_N_MMODE);
>> +}
>> +
>> +u32 fsimaster_read_mmode(struct fsimaster *master)
>> +{
>> + return 0;
>> +}
>> +
>> +void fsimaster_write_mmode(struct fsimaster *master, u32 value)
>> +{
>> +}
>> +
>> +/*
>> + * Read/write enable port register: MENP
>> + */
>> +u64 fsimaster_read_menp_nl(struct fsimaster *master)
>> +{
>> + return 0;
>> +}
>> +
>> +u64 fsimaster_read_menp(struct fsimaster *master)
>> +{
>> + return 0;
>> +}
>> +
>> +void fsimaster_write_menp(struct fsimaster *master, u64 *menp, int on_off)
>> +{
>> +}
>> +
>> +void fsimaster_disable_link(struct fsimaster *master, int link)
>> +{
>> +}
>> +
>> +void fsimaster_enable_link(struct fsimaster *master, int link)
>> +{
>> +}
>> +
>> +/*
>> + * Send out a BREAK command and see if anything response. Part of the scan
>> + * process
>> + */
>> +static int ping_cfam(struct fsimaster *master, struct fsi_hotplug *hp,
>> + const int count)
>> +{
>> + int i = 0, rc = -EIO;
>> + u32 value, pa;
>> + int id = fsi_mtype_2break_id(master->type);
>> +
>> + pa = fsimaster_cfam2pa(master, hp->linkno, id);
>> +
>> + fsimaster_enable_link(master, hp->linkno);
>> + if (fsi_sendbreak(master, pa, hp->linkno))
>> + goto out;
>> +
>> + while (i++ < count) {
>> + rc = fsi_readw_int(master, pa + FSI_SLAVE0_OFFSET + FSI_SMODE,
>> + &value);
>> + if (rc == 0)
>> + break;
>> +
>> + udelay(FSI_CFAM_PING_DELAY);
>> + }
>> +out:
>> + fsimaster_disable_link(master, hp->linkno);
>> +
>> + return rc;
>> +}
>> +
>> +/*
>> + * Probe for CFAMs
>> + */
>> +static int probe_link(struct fsimaster *master, struct fsi_hotplug *hp)
>> +{
>> + int rc = 0;
>> + struct fsidd *dd = to_fsidd_prim(fsimaster_get_top_master(master));
>> +
>> + hp->tries++;
>> + rc = ping_cfam(master, hp, FSI_MAX_CASCADE - 1);
>> + if (rc == 0) {
>> + atomic_set(&hp->state, FSI_LINK_BUILD);
>> + set_bit(FSI_LINK_BUILD, &dd->state);
>> + set_bit(hp->linkno, &master->hotp.building);
>> + clear_bit(hp->linkno, &master->hotp.probing);
>> + rc = 1;
>> + } else if (hp->tries > FSI_MAX_PING_ATTEMPTS) {
>> + atomic_set(&hp->state, FSI_EVT_CFAMDEAD);
>> + clear_bit(hp->linkno, &master->hotp.probing);
>> + }
>> +
>> + return rc;
>> +}
>> +
>> +/*
>> * Work queue function to probe links
>> */
>> static void probe_wq(struct work_struct *work)
>> {
>> + struct fsimaster *master = to_fsimaster_probe(work);
>> + struct fsidd *dd = to_fsidd_prim(fsimaster_get_top_master(master));
>> + int i, cnt = 0;
>> +
>> + for (i = 0; i < master->maxlinks; ++i) {
>> + if (test_bit(i, &master->hotp.probing))
>> + cnt += probe_link(master, master->hotp.plug[i]);
>> + }
>> + if (cnt)
>> + queue_work(dd->hotp_wq, &master->hotp.buildwork);
>> +}
>> +
>> +/*
>> + * Called from worker in process/task context
>> + */
>> +static int build(struct fsimaster *master, struct fsi_hotplug *hp)
>> +{
>> + int rc;
>> +
>> + rc = fsi_linkbuild(master, hp->linkno);
>> + atomic_set(&hp->state, rc ? FSI_LINK_RUNNING : FSI_LINK_DEAD);
>> + if (test_and_clear_bit(FSI_LINK_WAITFOR, &hp->wait_state))
>> + complete_all(&hp->done);
>> +
>> + return rc;
>> +}
>> +
>> +static int remove(struct fsimaster *master, struct fsi_hotplug *hp)
>> +{
>> + return 0;
>> +}
>> +
>> +/*
>> + * Actual link build function. Called in process context.
>> + */
>> +static void build_link(struct fsimaster *master, struct fsi_hotplug *hp)
>> +{
>> + hp->error_code = (hp->cmd == FSI_EVT_CFAMADD) ? build(master, hp)
>> + : remove(master, hp);
>> }
>>
>> /*
>> @@ -174,6 +364,34 @@ static void probe_wq(struct work_struct *work)
>> */
>> static void build_wq(struct work_struct *work)
>> {
>> + struct fsimaster *master = to_fsimaster_build(work);
>> + struct fsidd *dd = to_fsidd_prim(fsimaster_get_top_master(master));
>> + int i;
>> +
>> + set_bit(FSI_LINK_BUILD, &dd->state);
>> +again:
>> + for (i = 0; i < master->maxlinks; ++i) {
>> + if (test_and_clear_bit(i, &master->hotp.building))
>> + build_link(master, master->hotp.plug[i]);
>> + }
>> +
>> + /* stub */
>> +
>> + /*
>> + * Make sure all bits were cleared before leaving.
>> + * This worker runs in process context. While running, an FSI error
>> + * interrupt can occur and schedule a link for removal.
>> + * If we are past this new bit in our loop above, the link is not
>> + * removed. Iterate on non zero.
>> + */
>> + if (master->hotp.building)
>> + goto again;
>> +
>> + /*
>> + * If the same described above happens here, we are toast again.
>> + * Another perodic check is done on plugmgr()
>> + */
>> + clear_bit(FSI_LINK_BUILD, &dd->state);
>> }
>>
>> static int fsimaster_reset(struct fsimaster *master)
>> diff --git a/drivers/fsi/fsimaster.h b/drivers/fsi/fsimaster.h
>> index 61e8c8a..0d47dc6 100644
>> --- a/drivers/fsi/fsimaster.h
>> +++ b/drivers/fsi/fsimaster.h
>> @@ -20,6 +20,7 @@
>> #define FSI_MAX_PING_ATTEMPTS 12
>> #define FSI_PLUG_CHECK_TIME 100
>> #define FSI_DFLT_IPOLL_CHECK 800
>> +#define FSI_CFAM_PING_DELAY 20 /* in microseconds */
>>
>> /* FSI master register numbers */
>> #define FSI_N_MMODE 0 /* 0x0 R/W: mode register */
>> @@ -524,6 +525,7 @@ struct fsi_hotplug { /* Hot plug information */
>> struct completion done; /* Link build done */
>> u16 tries; /* # of tries before probing */
>> u8 linkno; /* Link # */
>> + u8 cmd; /* State add/delete */
>> atomic_t state; /* State of this entry */
>> int error_code; /* Error code */
>> unsigned long wait_state; /* Wait state */
>> @@ -673,4 +675,7 @@ void fsimaster_engput(struct fsidevice *);
>> void fsi_rst_error2(struct fsimaster *, struct fsidevice *, int, int, int, int);
>> int port_reset(struct fsimaster *, int);
>>
>> +int fsi_writew_int(struct fsimaster *, u32, u32);
>> +int fsi_readw_int(struct fsimaster *, u32, u32*);
>> +
>> #endif /* DRIVERS_FSIMASTER_H */
>> diff --git a/drivers/fsi/fsislave.h b/drivers/fsi/fsislave.h
>> new file mode 100644
>> index 0000000..f2095d3
>> --- /dev/null
>> +++ b/drivers/fsi/fsislave.h
>> @@ -0,0 +1,404 @@
>> +/*
>> + * FSI slave structure definitions and defines
>> + *
>> + * Copyright 2016 IBM Corp.
>> + *
>> + * Christopher Bostic <cbostic@us.ibm.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * as published by the Free Software Foundation; either version
>> + * 2 of the License, or (at your option) any later version.
>> + */
>> +#ifndef DRIVERS_FSISLAVE_H
>> +#define DRIVERS_FSISLAVE_H
>> +
>> +/*
>> + * Define read address for peek engine referring to
>> + * side/series/node-id/frame-id
>> + */
>> +#define FSI_PEEK_IDADDR 0xc
>> +
>> +#define FSI_SLV_CFAM_OFFSET 0x800
>> +
>> +/*
>> + * Defines for address locations of certain register in FSI Slave. All register
>> + * names start with FSI_S for slave register. Some registers have the
>> + * same address but different meanings for read and write access.
>> + */
>> +#define FSI_SMODE 0x0 /* R/W: Slave mode register */
>> +#define FSI_SDMA 0x4 /* R/W: DMA control register */
>> +#define FSI_SISC 0x8 /* Read: read Interrupt condition register */
>> +#define FSI_SCISC 0x8 /* Write: Clear Interrupt condition register */
>> +#define FSI_SISM 0xC /* R/W: Interrupt mask register */
>> +#define FSI_SISS 0x10 /* Read: Interrupt status register */
>> +#define FSI_SSISM 0x10 /* Write: Set interrupt mask */
>> +#define FSI_SSTAT 0x14 /* Read: Read slave status register */
>> +#define FSI_SCISM 0x14 /* Write: Clear interrupt mask */
>> +#define FSI_SI1M 0x18 /* R/W: Interrupt 1 mask register */
>> +#define FSI_SI1S 0x1C /* Read: Read Interrupt 1 status register */
>> +#define FSI_SSI1M 0x1C /* Write: Set Interrupt 1 mask register */
>> +#define FSI_SIC 0x20 /* Read: Read engine interrupt condition reg */
>> +#define FSI_SCI1M 0x20 /* Write: Clear Interrupt 1 mask register */
>> +#define FSI_SI2M 0x24 /* R/W: Interrupt 2 mask register */
>> +#define FSI_SI2S 0x28 /* Read: Read Interrupt 2 status register */
>> +#define FSI_SSI2M 0x28 /* Write: Set Interrupt 2 mask register */
>> +#define FSI_SCMDT 0x2C /* Read: Command trace register */
>> +#define FSI_SCI2M 0x2C /* Write: Clear Interrupt 2 mask register */
>> +#define FSI_SDATAT 0x30 /* Read: Data trace register */
>> +#define FSI_SLBUS 0x30 /* Write: local bus address commands */
>> +#define FSI_SLASTD 0x34 /* Read: Last data send register */
>> +#define FSI_SRES 0x34 /* Write: Reset command register */
>> +#define FSI_SMBL 0x38 /* R/W: Mailbox register left port */
>> +#define FSI_SOML 0x3C /* Read: Mailbox old data register left port */
>> +#define FSI_SSMBL 0x3C /* Write: Set Mailbox bits register left port */
>> +#define FSI_SNML 0x40 /* Read: Mailbox new data register left port */
>> +#define FSI_SCMBL 0x40 /* Write: Clear mailbox bits left port */
>> +#define FSI_SMBR 0x44 /* R/W: Mailbox register right port */
>> +#define FSI_SOMR 0x48 /* Read: Mailbox old data register right port */
>> +#define FSI_SSMBR 0x48 /* Write: Set Mailbox bits register right port*/
>> +#define FSI_SNMR 0x4c /* Read: Mailbox new data register right port */
>> +#define FSI_SCMBR 0x4c /* Write: Clear mailbox bits right port */
>> +
>> +/* Same as above except Word offsets into the FSI slave engine */
>> +#define FSI_N_SISC 0x2 /* Read: read Interrupt condition register */
>> +#define FSI_N_SSTAT 0x5 /* Read: Slave Status register */
>> +#define FSI_N_SCMDT 0xB /* Read: Command trace register */
>> +#define FSI_N_SDATAT 0xC /* Read: Data trace register */
>> +#define FSI_N_SLASTD 0xD /* Read: Last data send register */
>> +
>> +/* Next registers are only valid for FSI slave version 3 */
>> +#define FSI_SRSIC 0x50 /* Read slave remote slave IRQ condition */
>> +#define FSI_SCRSIC 0x50 /* Write: Clear Slave remote slave IRQ cond */
>> +#define FSI_SRSIM 0x54 /* R/W: Slave remote slave IRQ mask */
>> +#define FSI_SRSIS 0x58 /* Read: Slave remote slave IRQ status */
>> +
>> +/* Next registers are only valid for FSI slave version 4 */
>> +/* cmFSI */
>> +#define FSI_ScRSIC0 0x50 /* Read / Write: to clear cmFSI remote */
>> +/* slave IRQ condition ports 0-3 */
>> +#define FSI_ScRSIC4 0x54 /* Read / Write: to clear cmFSI remote */
>> +/* slave IRQ condition ports 4-7 */
>> +#define FSI_ScRSIM0 0x58 /* R/W: cmFSI remote slave IRQ mask */
>> +/* ports 0-3 */
>> +#define FSI_ScRSIM4 0x5C /* R/W: cmFSI remote slave IRQ mask */
>> +/* ports 4-7 */
>> +#define FSI_ScRSIS0 0x60 /* Read: cmFSI remote slave IRQ status */
>> +/* ports 0-3 */
>> +#define FSI_ScRSIS4 0x64 /* Read: cMFSI remote slave IRQ status */
>> +/* ports 4-7 */
>> +/* hFSI */
>> +#define FSI_SRSIC0 0x68 /* Read / Write: to clear hFSI remote */
>> +/* slave IRQ condition ports 0-3 */
>> +#define FSI_SRSIC4 0x6C /* Read / Write: to clear hFSI remote */
>> +/* slave IRQ condition ports 4-7 */
>> +#define FSI_SRSIM0 0x70 /* R/W: hFSI remote slave IRQ mask */
>> +/* ports 0-3 */
>> +#define FSI_SRSIM4 0x74 /* R/W: hFSI remote slave IRQ mask */
>> +/* ports 4-7 */
>> +#define FSI_SRSIS0 0x78 /* Read: hFSI remote slave IRQ status */
>> +/* ports 0-3 */
>> +#define FSI_SRSIS4 0x7C /* Read: hFSI remote slave IRQ status */
>> +/* ports 4-7 */
>> +
>> +#define FSI_SRSIM_SID3_SHIFT 6
>> +
>> +/* Slave ID 3 on interrupt level 1 for all sub/hub links */
>> +#define SRSIM_ID3_IRPT1_MASK 0x02020202
>> +#define SRSIM_MAGIC SRSIM_ID3_IRPT1_MASK
>> +
>> +struct fsi_sreg { /* FSI slave register definition */
>> + u32 smode; /* 0x0: Mode register */
>> + u32 sdma; /* 0x4: DMA control register */
>> + u32 sisc; /* 0x8: Slave interrupt condition register */
>> + u32 sism; /* 0xc: Slave interrupt mask register */
>> + u32 siss; /* 0x10: Slave interrupt status register */
>> + u32 sstat; /* 0x14: Slave status register */
>> + u32 si1m; /* 0x18: interrupt 1 mask register */
>> + u32 si1s; /* 0x1c: interrupt 1 status register */
>> + u32 sic; /* 0x20: engine interrupt condition register */
>> + u32 si2m; /* 0x24: interrupt 2 mask register */
>> + u32 si2s; /* 0x28: interrupt 2 status register */
>> + u32 scmdt; /* 0x2c: read command trace register */
>> + u32 sdatat; /* 0x30: read data trace register */
>> + u32 slastd; /* 0x34: read last FSI data register */
>> + u32 smbl; /* 0x38: mail box to left port register */
>> + u32 soml; /* 0x3c: old mail left port register */
>> + u32 snml; /* 0x40: new mail left port register */
>> + u32 smbr; /* 0x44: mail box to right port register */
>> + u32 somr; /* 0x48: old mail right port register */
>> + u32 snmr; /* 0x4c: new mail right port register */
>> + u32 srsic0; /* 0x50: slave remote slave IRQ cond. 0-3 */
>> + u32 srsic4; /* 0x54: slave remote slave IRQ cond. 4-7 */
>> + u32 srsim0; /* 0x58: slave remote slave IRQ mask 0-3 */
>> + u32 srsim4; /* 0x5C: slave remote slave IRQ mask 4-7 */
>> + u32 srsis0; /* 0x60: slave remote slave IRQ stat 0-3 */
>> + u32 srsis4; /* 0x64: slave remote slave IRQ stat 4-7 */
>> +};
>> +
>> +/*
>> + * FSI slave mode register
>> + */
>> +#define FSI_SMODE_WSC 0x80000000 /* Warm start completed */
>> +#define FSI_SMODE_EAP 0x40000000 /* Enable auxiliary port */
>> +#define FSI_SMODE_ECRC 0x20000000 /* Enable CRC checking by hw */
>> +#define FSI_SMODE_SID_SHIFT 24 /* Slave identifier shift */
>> +#define FSI_SMODE_SID_MASK 3 /* Slave identifier mask */
>> +#define FSI_SMODE_ED_SHIFT 20 /* Echo delay cycles shift */
>> +#define FSI_SMODE_ED_MASK 0xf /* Echo delay cycles mask */
>> +#define FSI_SMODE_SD_SHIFT 16 /* Send delay cycles shift */
>> +#define FSI_SMODE_SD_MASK 0xf /* Send delay cycles mask */
>> +#define FSI_SMODE_LBCRR_SHIFT 8 /* Local bus clk rate shift */
>> +#define FSI_SMODE_LBCRR_MASK 0xf /* Local bus clk rate mask */
>> +#define FSI_SMODE_BDL_SHIFT 4 /* Briefing data left shift */
>> +#define FSI_SMODE_BDL_MASK 0xf /* Briefing data mask */
>> +#define FSI_SMODE_BDR_SHIFT 0 /* Briefing data right shift */
>> +#define FSI_SMODE_BDR_MASK 0xf /* Briefing data mask */
>> +#define FSI_SMODE_RSV_MASK 0xe3ff0fff /* Mask for used bit clr rsvd */
>> +
>> +/* FSI slave local bus echo delay */
>> +static inline u32 fsi_smode_echodly(int x)
>> +{
>> + return (x & FSI_SMODE_ED_MASK) << FSI_SMODE_ED_SHIFT;
>> +}
>> +
>> +/* FSI slave local bus send delay */
>> +static inline u32 fsi_smode_senddly(int x)
>> +{
>> + return (x & FSI_SMODE_SD_MASK) << FSI_SMODE_SD_SHIFT;
>> +}
>> +
>> +/* FSI slave local bus clock rate ratio */
>> +static inline int fsi_smode_extlbcrr(u32 x)
>> +{
>> + return (x >> FSI_SMODE_LBCRR_SHIFT) & FSI_SMODE_LBCRR_MASK;
>> +}
>> +
>> +/* FSI slave local bus clock rate ratio */
>> +static inline u32 fsi_smode_lbcrr(int x)
>> +{
>> + return (x & FSI_SMODE_LBCRR_MASK) << FSI_SMODE_LBCRR_SHIFT;
>> +}
>> +
>> +/* FSI slave identifier setting */
>> +static inline u32 fsi_smode_sid(int x)
>> +{
>> + return (x & FSI_SMODE_SID_MASK) << FSI_SMODE_SID_SHIFT;
>> +}
>> +
>> +/* FSI slave briefing data right port */
>> +static inline u32 fsi_smode_bdr(int x)
>> +{
>> + return (x & FSI_SMODE_BDR_MASK) << FSI_SMODE_BDR_SHIFT;
>> +}
>> +
>> +static inline int fsi_smode_extbdr(u32 x)
>> +{
>> + return (x >> FSI_SMODE_BDR_SHIFT) & FSI_SMODE_BDR_MASK;
>> +}
>> +
>> +/* FSI slave briefing data left port */
>> +static inline u32 fsi_smode_bdl(int x)
>> +{
>> + return (x & FSI_SMODE_BDL_MASK) << FSI_SMODE_BDL_SHIFT;
>> +}
>> +
>> +static inline int fsi_smode_extbdl(u32 x)
>> +{
>> + return (x >> FSI_SMODE_BDL_SHIFT) & FSI_SMODE_BDL_MASK;
>> +}
>> +
>> +/* FSI slave echo delay */
>> +static inline u32 fsi_smode_ed(int x)
>> +{
>> + return (x & FSI_SMODE_ED_MASK) << FSI_SMODE_ED_SHIFT;
>> +}
>> +
>> +static inline int fsi_smode_exted(u32 x)
>> +{
>> + return (x >> FSI_SMODE_ED_SHIFT) & FSI_SMODE_ED_MASK;
>> +}
>> +
>> +/* FSI slave send delay */
>> +static inline u32 fsi_smode_sd(int x)
>> +{
>> + return (x & FSI_SMODE_SD_MASK) << FSI_SMODE_SD_SHIFT;
>> +}
>> +
>> +static inline int fsi_smode_extsd(u32 x)
>> +{
>> + return (x >> FSI_SMODE_SD_SHIFT) & FSI_SMODE_SD_MASK;
>> +}
>> +
>> +/*
>> + * FSI slave interrupt register: interrupt conditions, status and mask
>> + */
>> +#define FSI_SSI_CRCE 0x80000000 /* FSI CRC error */
>> +#define FSI_SSI_PROTE 0x40000000 /* FSI protocol error */
>> +#define FSI_SSI_LBPE 0x20000000 /* FSI local bus parity error */
>> +#define FSI_SSI_LBPROTE 0x10000000 /* FSI local bus protocol err */
>> +#define FSI_SSI_LBAE 0x08000000 /* FSI local bus access error */
>> +#define FSI_SSI_LBOE 0x04000000 /* FSI local bus owner error */
>> +#define FSI_SSI_LBOC 0x02000000 /* FSI local bus owner change */
>> +#define FSI_SSI_HPE 0x01000000 /* Hot plug event */
>> +#define FSI_SSI_MRL 0x00800000 /* Mail received left port */
>> +#define FSI_SSI_MDL 0x00400000 /* Mail send left port */
>> +#define FSI_SSI_WSL 0x00200000 /* Warm start flag left port */
>> +#define FSI_SSI_LBRL 0x00100000 /* Local bus requ left port */
>> +#define FSI_SSI_MRR 0x00080000 /* Mail received right port */
>> +#define FSI_SSI_MDR 0x00040000 /* Mail delivered right port */
>> +#define FSI_SSI_WSR 0x00020000 /* Warm start flag right port */
>> +#define FSI_SSI_LBRR 0x00010000 /* Local bus req right port */
>> +#define FSI_SSI_CMEL 0x00008000 /* Clocks monitor event left */
>> +#define FSI_SSI_CMER 0x00004000 /* Clocks monitor event right */
>> +#define FSI_SSI_OPB_FNC 0x00001000 /* OPB Fenced (cMFSI & hMFSI) */
>> +#define FSI_SSI_OBP_PA 0x00000800 /* OPB Parity (cMFSI) */
>> +#define FSI_SSI_OBP_PR 0x00000400 /* OPB Protocol (cMFSI) */
>> +#define FSI_SSI_OBP_TO 0x00000200 /* OPB Timeout (cMFSI) */
>> +#define FSI_SSI_OBP_EA 0x00000100 /* OPB ErrorAck (cMFSI) */
>> +#define FSI_SSI_OBP_IA 0x00002000 /* OPB Invalid Address (cMFSI)*/
>> +#define FSI_SSI_CMFSI_AME 0x00000080 /* CMFSI any-master-error */
>> +#define FSI_SSI_CMFSI_APE 0x00000040 /* CMFSI any-port-error */
>> +#define FSI_SSI_CMFSI_HPE 0x00000020 /* CMFSI Hot plug event */
>> +#define FSI_SSI_CMFSI_CRPA 0x00000010 /* CMFSI Contr reg parity err */
>> +#define FSI_SSI_ANY_IRQ 0xffffc000 /* Valid bits */
>> +#define FSI_SSI_ANY_IRQ3 (FSI_SSI_CMFSI_AME | FSI_SSI_CMFSI_APE \
>> + | FSI_SSI_CMFSI_HPE | FSI_SSI_CMFSI_CRPA)
>> + /* Valid bits (cMFSI) */
>> +#define FSI_SSI_ANY_ERROR 0xfc000000 /* Valid error bits */
>> +#define FSI_SSI_ANY_ERROR3 (FSI_SSI_OBP_PA \
>> + | FSI_SSI_OBP_PR | FSI_SSI_OBP_TO \
>> + | FSI_SSI_OBP_EA | FSI_SSI_OBP_IA)
>> + /* Valid error bits (cMFSI) */
>> +#define FSI_SSI_ERR_MASK 0x3f /* Any error bits mask */
>> +#define FSI_SSI_ERR_SHFT 26 /* Any error bits shift */
>> +#define FSI_SISC_CRCE 0 /* Slave CRC error bit */
>> +#define FSI_SISC_PE 1 /* Slave protocol error bit */
>> +#define FSI_SISC_LBPE 2 /* Slave lcl bus parity err */
>> +#define FSI_SISC_LBPROTOE 3 /* Slave lcl bus prot err */
>> +#define FSI_SISC_LBAE 4 /* Slave access error bit */
>> +#define FSI_SISC_LBOE 5 /* Slave lcl bus owner err */
>> +#define FSI_SISC_OPBPA 20 /* Slave OPB parity error */
>> +#define FSI_SISC_OPBPR 21 /* Slave OPB protocol error */
>> +#define FSI_SISC_OPBTO 22 /* Slave OPB timeout error */
>> +#define FSI_SISC_OPBEA 23 /* Slave OPB ack error */
>> +#define FSI_SISC_CM_ERRS 0x000000f0 /* CMP8 sourced errors */
>> +#define FSI_SISC_HM_ERRS 0x0000000f /* HMP8 sourced errors */
>> +
>> +/* FSI slave error interrupt */
>> +static inline int fsi_sisc_iserror(u32 x)
>> +{
>> + return x & (FSI_SSI_ANY_ERROR3 | FSI_SSI_ANY_ERROR);
>> +}
>> +
>> +/*
>> + * FSI slave interrupt mask register: interrupt conditions, status and mask
>> + */
>> +#define FSI_SSI_ENG0 0x80000000 /* FSI slave */
>> +#define FSI_SSI_ENG_MBX 0x400 /* FSI IOU Mailbox */
>> +#define FSI_SSI_ENG_ANY 0x7fffffff /* FSI engine 1..31 */
>> +#define FSI_SSI_ENG_NOLBUS (FSI_SSI_ENG0 | FSI_SSI_ENG_MBX)
>> + /* Engines without local bus */
>> +/*
>> + * FSI slave status register SSTAT
>> + */
>> +#define FSI_SSTAT_AE 0x80000000 /* Any error bit */
>> +#define FSI_SSTAT_IDD 0x40000000 /* CFAM ID dirty at PON lvl) */
>> +#define FSI_SSTAT_LSW 0x40000000 /* Left side warm start flag */
>> +#define FSI_SSTAT_RSW 0x10000000 /* Rt side warm start flag */
>> +#define FSI_SSTAT_MDL 0x08000000 /* Mail delivered left side */
>> +#define FSI_SSTAT_MDR 0x04000000 /* Mail delivered right side */
>> +#define FSI_SSTAT_MRL 0x02000000 /* Mail received left side */
>> +#define FSI_SSTAT_MRR 0x01000000 /* Mail received right side */
>> +#define FSI_SSTAT_BDL_SHIFT 20 /* Brief data left side shft */
>> +#define FSI_SSTAT_BDL_MASK 0xf /* Brief data left side mask */
>> +#define FSI_SSTAT_BDR_SHIFT 16 /* Brief data rt side shift */
>> +#define FSI_SSTAT_BDR_MASK 0xf /* Brief data rt side mask */
>> +#define FSI_SSTAT_LSLBR 0x8000 /* Left side local bus req */
>> +#define FSI_SSTAT_RSLBR 0x4000 /* Right side local bus req */
>> +#define FSI_SSTAT_TSLBR 0x2000 /* This side local bus req */
>> +#define FSI_SSTAT_BLBA 0x1000 /* Block C-side lcl bus acc */
>> +#define FSI_SSTAT_LBO_SHIFT 10 /* Local bus owner shift */
>> +#define FSI_SSTAT_LBO_MASK 3 /* Local bus owner mask */
>> +#define FSI_SSTAT_TSF_SHIFT 8 /* This side A=01 B=10 C=11 */
>> +#define FSI_SSTAT_TSF_MASK 3 /* This side flag mask */
>> +#define FSI_SSTAT_CAL 0x00000080 /* Clocks active left port */
>> +#define FSI_SSTAT_CAR 0x00000040 /* Clocks active right port */
>> +#define FSI_SSTAT_APIL 0x00000020 /* Aux port input level */
>> +#define FSI_SSTAT_APRL 0x00000010 /* Aux port reference level */
>> +#define FSI_SSTAT_CRC_SHIFT 0 /* CRC error counter */
>> +#define FSI_SSTAT_CRC_MASK 0xf /* CRC mask */
>> +#define FSI_SSTAT_SIDE_NONE 0 /* Unknown Side */
>> +#define FSI_SSTAT_SIDE_A 1 /* A-Side */
>> +#define FSI_SSTAT_SIDE_B 2 /* B-Side */
>> +#define FSI_SSTAT_SIDE_C 3 /* C-Side */
>> +
>> +/* FSI status local bus request */
>> +static inline int fsi_sstat_tsf(u32 x)
>> +{
>> + return (x >> FSI_SSTAT_TSF_SHIFT) & FSI_SSTAT_TSF_MASK;
>> +}
>> +
>> +/* FSI status get local bus owner */
>> +static inline int fsi_sstat_lbo(u32 x)
>> +{
>> + return (x >> FSI_SSTAT_LBO_SHIFT) & FSI_SSTAT_LBO_MASK;
>> +}
>> +
>> +/* FSI status get right side briefing data */
>> +static inline int fsi_sstat_bdr(u32 x)
>> +{
>> + return (x >> FSI_SSTAT_BDR_SHIFT) & FSI_SSTAT_BDR_MASK;
>> +}
>> +
>> +/* FSI status get left side briefing data */
>> +static inline int fsi_sstat_bdl(u32 x)
>> +{
>> + return (x >> FSI_SSTAT_BDL_SHIFT) & FSI_SSTAT_BDL_MASK;
>> +}
>> +
>> +/* FSI status get CRC counter */
>> +static inline int fsi_sstat_crc(u32 x)
>> +{
>> + return (x >> FSI_SSTAT_CRC_SHIFT) & FSI_SSTAT_CRC_MASK;
>> +}
>> +
>> +/*
>> + * FSI slave local bus access register SLBUS
>> + */
>> +#define FSI_SLBUS_FLBO 0x80000000 /* Force local bus ownership */
>> +#define FSI_SLBUS_RLBA 0x40000000 /* Request local bus access */
>> +#define FSI_SLBUS_RLBO_SHIFT 28 /* Release local bus shift */
>> +#define FSI_SLBUS_RLBO_MASK 3 /* Release local bus mask */
>> +#define FSI_SLBUS_RLBR 0x08000000 /* Reset local bus req */
>> +#define FSI_SLBUS_BLBA_SHIFT 16 /* Block local bus acc shift */
>> +#define FSI_SLBUS_BLBA_MASK 0xff /* Block local bus acc mask */
>> +#define FSI_SLBUS_BLBA 0xff /* Block local bus acc */
>> +#define FSI_SLBUS_UBLBA 0xec /* Unblock local bus access */
>> +#define FSI_SLBUS_RESERVE_MASK 0xf8ff0000 /* Mask off reserved bits */
>> +
>> +/* Release local bus */
>> +static inline u32 fsi_slbus_rlbo(int side)
>> +{
>> + return (side & FSI_SLBUS_RLBO_MASK) << FSI_SLBUS_RLBO_SHIFT;
>> +}
>> +
>> +/* Block local bus access */
>> +static inline u32 fsi_slbus_blba(int side)
>> +{
>> + return (side & FSI_SLBUS_BLBA_MASK) << FSI_SLBUS_BLBA_SHIFT;
>> +}
>> +
>> +/* FSI Slave Error Reset Register SRES */
>> +#define FSI_SRES_RFS 0x80000000 /* Reset FSI slave */
>> +#define FSI_SRES_REFS 0x40000000 /* Reset Errors FSI slave */
>> +#define FSI_SRES_RLBE 0x20000000 /* Reset Local bus engs slave */
>> +#define FSI_SRES_RESERVE_MASK 0x1fffffff /* Mask off reserved bits */
>> +
>> +int slave_readreg(struct fsimaster *, void *, u32 *, u32);
>> +int slave_writereg(struct fsimaster *, void *, u32, u32);
>> +int slave_irqclear(struct fsimaster *, void *, u32, u32);
>> +int p8_cfam_fixup(struct fsicfam *, int);
>> +u32 xmp8_srsim_mask(int);
>> +
>> +#endif /* DRIVERS_FSISLAVE_H */
>> diff --git a/drivers/fsi/ldm.c b/drivers/fsi/ldm.c
>> new file mode 100644
>> index 0000000..4a2f90b
>> --- /dev/null
>> +++ b/drivers/fsi/ldm.c
>> @@ -0,0 +1,29 @@
>> +/*
>> + * FSI interface to the LDM
>> + *
>> + * Copyright 2016 IBM Corp.
>> + *
>> + * Christopher Bostic <cbostic@us.ibm.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * as published by the Free Software Foundation; either version
>> + * 2 of the License, or (at your option) any later version.
>> + */
>> +#include "fsi.h"
>> +#include "fsi_private.h"
>> +
>> +/*
>> + * Register a FSI device with the Linux device model
>> + */
>> +int fsidev_register_nolock(struct fsidevice *fsidev,
>> + struct device_attribute **ap)
>> +{
>> + return 0;
>> +}
>> +
>> +int fsidev_register(struct fsidevice *fsidev, struct device_attribute **ap)
>> +{
>> + return 0;
>> +}
>> +EXPORT_SYMBOL(fsidev_register);
>> diff --git a/drivers/fsi/readwrite.c b/drivers/fsi/readwrite.c
>> new file mode 100644
>> index 0000000..33d972c
>> --- /dev/null
>> +++ b/drivers/fsi/readwrite.c
>> @@ -0,0 +1,34 @@
>> +/*
>> + * FSI I/O accesses
>> + *
>> + * Copyright 2016 IBM Corp.
>> + *
>> + * Christopher Bostic <cbostic@us.ibm.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * as published by the Free Software Foundation; either version
>> + * 2 of the License, or (at your option) any later version.
>> + */
>> +#include "fsi.h"
>> +#include "fsi_private.h"
>> +#include "fsimaster.h"
>> +
>> +int fsi_readw_int(struct fsimaster *master, u32 pa, u32 *value)
>> +{
>> + return 0;
>> +}
>> +
>> +int fsi_writew_int(struct fsimaster *master, u32 pa, u32 value)
>> +{
>> + return 0;
>> +}
>> +
>> +/*
>> + * Send out a BREAK command on a given link - Resets the logic of any slaves
>> + * present
>> + */
>> +int fsi_sendbreak(struct fsimaster *master, u32 cfam_base, int linkno)
>> +{
>> + return 0;
>> +}
>> --
>> 1.8.2.2
>>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH linux v5 0/7] Introducing the FSI device driver
2016-09-08 0:10 ` Joel Stanley
@ 2016-09-21 18:49 ` Christopher Bostic
2016-09-21 18:52 ` Christopher Bostic
1 sibling, 0 replies; 19+ messages in thread
From: Christopher Bostic @ 2016-09-21 18:49 UTC (permalink / raw)
To: Joel Stanley; +Cc: OpenBMC Maillist, Chris Bostic, Jeremy Kerr
On Wed, Sep 7, 2016 at 7:10 PM, Joel Stanley <joel@jms.id.au> wrote:
> Hi Chris,
>
> On Fri, Sep 2, 2016 at 2:35 PM, Joel Stanley <joel@jms.id.au> wrote:
>> Hi Chris,
>>
>> On Thu, Aug 25, 2016 at 5:24 AM, <christopher.lee.bostic@gmail.com> wrote:
>>> From: Chris Bostic <cbostic@us.ibm.com>
>>>
>>> Introduction of the IBM 'Flexible Support Interface' (FSI) bus device
>>> driver. FSI is a high fan out serial bus consisting of a clock and a serial
>>> data line capable of running at speeds up to 166 MHz.
>>
>
> I've taken a look at the patches. There doesn't seem to be much
> improvement over the last version.
Not sure I follow what you mean by improvement. There is more
function added with this last set. In terms of incorporating Jeremy's
changes I will attempt to follow his suggestions but I'm a little
unclear if you are expecting those to be done verbatim as per his
example. The patches are rather small and so to incorporate ~ 5
KLOCs would require an enormous patch set or series of sets.
I've been working on the next set and will get that to you soon. I
don't, however, want to send another set without much improvement so
let me know how I can do this.
>
>> I was wondering if you have had a look at Jeremy's implementation yet?
>> If so, are there any ideas you have incorporated into your series?
>
> I recommend you consider these questions and get back to me.
>
> Cheers,
>
> Joel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH linux v5 0/7] Introducing the FSI device driver
2016-09-08 0:10 ` Joel Stanley
2016-09-21 18:49 ` Christopher Bostic
@ 2016-09-21 18:52 ` Christopher Bostic
1 sibling, 0 replies; 19+ messages in thread
From: Christopher Bostic @ 2016-09-21 18:52 UTC (permalink / raw)
To: Joel Stanley; +Cc: OpenBMC Maillist, Chris Bostic, Jeremy Kerr
On Wed, Sep 7, 2016 at 7:10 PM, Joel Stanley <joel@jms.id.au> wrote:
> Hi Chris,
>
> On Fri, Sep 2, 2016 at 2:35 PM, Joel Stanley <joel@jms.id.au> wrote:
>> Hi Chris,
>>
>> On Thu, Aug 25, 2016 at 5:24 AM, <christopher.lee.bostic@gmail.com> wrote:
>>> From: Chris Bostic <cbostic@us.ibm.com>
>>>
>>> Introduction of the IBM 'Flexible Support Interface' (FSI) bus device
>>> driver. FSI is a high fan out serial bus consisting of a clock and a serial
>>> data line capable of running at speeds up to 166 MHz.
>>
>
> I've taken a look at the patches. There doesn't seem to be much
> improvement over the last version.
In terms of patch ordering, starting with the generic bus registration
etc as per Jeremy's example I understand and will be reordering in
this way in the next set I submit.
>
>> I was wondering if you have had a look at Jeremy's implementation yet?
>> If so, are there any ideas you have incorporated into your series?
>
> I recommend you consider these questions and get back to me.
>
> Cheers,
>
> Joel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH linux v5 2/7] drivers/fsi: Add FSI Master Functionality and Initialization
2016-09-08 0:09 ` Joel Stanley
2016-09-21 18:38 ` Christopher Bostic
@ 2016-09-21 21:15 ` Christopher Bostic
1 sibling, 0 replies; 19+ messages in thread
From: Christopher Bostic @ 2016-09-21 21:15 UTC (permalink / raw)
To: Joel Stanley; +Cc: OpenBMC Maillist, Chris Bostic, zahrens
>> +++ b/drivers/fsi/fsi.h
>> @@ -0,0 +1,32 @@
>> +/*
>> + * FSI device driver structure definitions and defines
>> + *
>> + * Copyright 2016 IBM Corp.
>> + *
>> + * Christopher Bostic <cbostic@us.ibm.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * as published by the Free Software Foundation; either version
>> + * 2 of the License, or (at your option) any later version.
>> + */
>> +#ifndef DRIVERS_FSI_H
>> +#define DRIVERS_FSI_H
>> +
>> +#include <linux/device.h>
>> +
>> +struct fsimap {
>> + u8 link; /* Master link # */
>> + u8 cfam; /* CFAM # on link */
>> + u32 offset; /* Address offset into CFAM */
>> + u32 va; /* Virtual address */
>> +};
>> +
>> +struct fsidevice {
>> + u32 irq_start; /* IRQ Number */
>> + struct fsidevice *parent; /* Parent of this device */
>> + struct device dev; /* LDM entry for bus */
>> + struct fsimap map; /* Address & location info */
>> +};
>> +
>> +#endif /* DRIVERS_FSI_H */
>> diff --git a/drivers/fsi/fsi_private.h b/drivers/fsi/fsi_private.h
>> new file mode 100644
>> index 0000000..be327ef
>> --- /dev/null
>> +++ b/drivers/fsi/fsi_private.h
>> @@ -0,0 +1,97 @@
>> +/*
>> + * FSI device driver structure definitions and defines
>> + *
>> + * Copyright 2016 IBM Corp.
>> + *
>> + * Christopher Bostic <cbostic@us.ibm.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * as published by the Free Software Foundation; either version
>> + * 2 of the License, or (at your option) any later version.
>> + */
>> +#ifndef DRIVERS_FSI_PRIVATE_H
>> +#define DRIVERS_FSI_PRIVATE_H
>> +
>> +#include "fsi.h"
>> +
>> +#define FSIDD_NAME "fsi" /* FSI device driver name */
>> +
>> +/*
>> + * Universal FSI constants - Applicable for any FSI device
>> + */
>> +#define FSI_MAX_LINKS 64 /* FSI Master # of links */
>> +#define FSI_MAX_CASCADE 4 /* # of CFAMS in cascade */
>> +#define FSI_MAX_MASTERS 1 /* # of masters in system */
>> +#define FSI_LINK_ENG_MASK 0xE0007FFF /* Used for minor num calcs */
>> +#define FSI_MAX_DEPTH 3 /* Max # of links in path */
>> +#define FSI_LINK_SHIFT 23 /* Bits to shift */
>> +#define FSI_LINK_SIZE (1 << FSI_LINK_SHIFT) /* 8 MB */
>> +#define FSI_CFAM_SHIFT 21 /* Bits to shift */
>> +#define FSI_CFAM_SIZE (1 << FSI_CFAM_SHIFT) /* 2 MB */
>> +#define FSI_ENGINE_SHIFT 10 /* Bits to shift */
>> +#define FSI_ENGINE_SIZE (1 << FSI_ENGINE_SHIFT) /* 1 KB */
>> +#define FSI_LINK_MASK 0x1f800000 /* Bits for link */
>> +#define FSI_CFAM_MASK 0x00600000 /* Bits for cfam */
>> +#define FSI_ENGINE_MASK 0x000ffc00 /* Bits for engine */
>> +#define FSI_PEEK_OFFSET FSI_ENGINE_SIZE
>> +#define FSI_SLAVE0_OFFSET (2 * FSI_ENGINE_SIZE)
>> +#define FSI_SLV_NO_ERROR 100 /* Slave has no error data */
>> +#define FSI_BREAK 0xc0de0000 /* BREAK command */
>> +#define FSI_TERM 0xecc00000 /* TERM command */
>> +#define FSI_BREAK_TIME 180 /* # Seconds to allow BREAKs */
>> +#define FSI_BREAK_CNT 3 /* limit for BREAK attempts */
>> +#define FSI_PRIM 0 /* Generic Primary FSI master */
>> +#define FSI_MBIT_MASK 0x3 /* FSI master bits in pa */
>> +#define FSI_ENG_MASK 0x00007FFF /* The engine mask in MATRB */
>> +/* FSI Events */
>> +#define FSI_EVT_PLUG 6 /* Device plugged */
>> +#define FSI_LINK_BUILD 10 /* In build up phase */
>> +#define FSI_LINK_PROBE 11 /* In probing phase */
>> +
>> +/*
>> + * Return the link number where this device is attached
>> + */
>> +static inline int fsi_my_link(struct fsidevice *fdev)
>> +{
>> + return fdev->map.link;
>> +}
>> +
>> +/*
>> + * Return CFAM number on link where this device is attached
>> + */
>> +static inline int fsi_my_cfam(struct fsidevice *fdev)
>> +{
>> + return fdev->map.cfam;
>> +}
>> +
>> +/*
>> + * Determine the link address to send the break command to
>> + * This is master dependent
>> + */
>> +static inline int fsi_mtype_2break_id(u8 mtype)
>> +{
>> + return FSI_MAX_CASCADE - 1;
>> +}
>> +
>> +/*
>> + * Build a mask where bit index 'x' is set (numbering from left to right.
>> + * Bit 0 is MSB and bit 31 is LSM.
>> + */
>> +static inline unsigned long mask32(int x)
>> +{
>> + return 1 << (BITS_PER_LONG - x - 1);
>
> Is this masking in IBM bit ordering?
>
> We should pull the macros (or at least copy them) from arch/powerpc so
> we can use them here.
>
>> +}
>> +
>> +/*
>> + * Various function prototypes
>> + */
>> +int slv_install(void);
>> +void slv_uninstall(void);
>> +
>> +void fsi_exit_fileio(dev_t);
>> +
>> +int fsibus_init(void);
>> +void fsibus_exit(void);
>> +
>> +#endif /* DRIVERS_FSI_PRIVATE_H */
>> diff --git a/drivers/fsi/fsicfam.h b/drivers/fsi/fsicfam.h
>> new file mode 100644
>> index 0000000..dde7036
>> --- /dev/null
>> +++ b/drivers/fsi/fsicfam.h
>> @@ -0,0 +1,46 @@
>> +/*
>> + * FSI CFAM structure definitions and defines
>> + *
>> + * Copyright 2016 IBM Corp.
>> + *
>> + * Christopher Bostic <cbostic@us.ibm.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * as published by the Free Software Foundation; either version
>> + * 2 of the License, or (at your option) any later version.
>> + */
>> +#ifndef DRIVERS_FSICFAM_H
>> +#define DRIVERS_FSICFAM_H
>> +
>> +#include "fsi.h"
>> +#include "fsi_private.h"
>> +
>> +#define FSI_MAX_ENGINES 32 /* Max # of engines per CFAM */
>> +
>> +struct fsicfam { /* CFAM internal structure */
>> + struct fsidevice *engines[FSI_MAX_ENGINES]; /* CFAM engine data */
>> + u32 cfgtab[FSI_MAX_ENGINES]; /* Configuration word */
>> + u16 chipid; /* CFAM chip type (IOU, CFAM-S, etc) */
>> + u8 id; /* CFAM Id */
>> + bool has_submaster; /* CFAM with cascaded or hub masters */
>> + bool has_mux; /* CFAM with multiplexer */
>> + u8 ec_maj; /* Major EC Level */
>> + u8 ec_min; /* Minor EC Level or version number */
>> + u16 pages; /* # Mapped pages */
>> + u8 no_eng; /* Number of engines[] */
>> + struct fsidevice fsidev; /* LDM entry */
>> + struct fsidevice hpdone; /* Dummy engine to signal completion */
>> + unsigned long eng_build; /* True during engine activate */
>> + struct fsimaster *master; /* pointer to parent master */
>> +};
>> +
>> +#define to_fsicfam(x) container_of((x), struct fsicfam, fsidev)
>
> Make this a function.
>
Creating a macro for container_of( ) ops seems to be common practice
for include/linux/ headers. I do plan on moving this to
include/linux in the next patch set in any case.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH linux v5 2/7] drivers/fsi: Add FSI Master Functionality and Initialization
2016-09-21 18:38 ` Christopher Bostic
@ 2016-09-21 22:59 ` Brad Bishop
0 siblings, 0 replies; 19+ messages in thread
From: Brad Bishop @ 2016-09-21 22:59 UTC (permalink / raw)
To: Christopher Bostic; +Cc: Joel Stanley, OpenBMC Maillist
> On Sep 21, 2016, at 2:38 PM, Christopher Bostic <christopher.lee.bostic@gmail.com> wrote:
>
> On Wed, Sep 7, 2016 at 7:09 PM, Joel Stanley <joel@jms.id.au> wrote:
>> On Thu, Aug 25, 2016 at 5:24 AM, <christopher.lee.bostic@gmail.com> wrote:
>>> From: Chris Bostic <cbostic@us.ibm.com>
>>>
>>> Define the FSI master control register set and its accessors.
>>> Initialize the primary FSI master.
>>>
>>> Signed-off-by: Chris Bostic <cbostic@us.ibm.com>
>>> ---
>>
>> I recall reading this patch in the past. No changelog?
>
> Had the changes specific to this patch in 0001, will move those to 0002.
>
>>
>>> drivers/fsi/Makefile | 2 +-
>>> drivers/fsi/fsi.h | 32 +++
>>> drivers/fsi/fsi_private.h | 97 +++++++
>>> drivers/fsi/fsicfam.h | 46 ++++
>>> drivers/fsi/fsiinit.c | 22 ++
>>> drivers/fsi/fsiinit.h | 2 +
>>> drivers/fsi/fsimaster.c | 242 +++++++++++++++++
>>> drivers/fsi/fsimaster.h | 655 ++++++++++++++++++++++++++++++++++++++++++++++
>>> 8 files changed, 1097 insertions(+), 1 deletion(-)
>>> create mode 100644 drivers/fsi/fsi.h
>>> create mode 100644 drivers/fsi/fsi_private.h
>>> create mode 100644 drivers/fsi/fsicfam.h
>>> create mode 100644 drivers/fsi/fsimaster.c
>>> create mode 100644 drivers/fsi/fsimaster.h
>>>
>>> diff --git a/drivers/fsi/Makefile b/drivers/fsi/Makefile
>>> index f547c08..9800c15 100644
>>> --- a/drivers/fsi/Makefile
>>> +++ b/drivers/fsi/Ma
>
>
>
>>> + * Determine the link address to send the break command to
>>> + * This is master dependent
>>> + */
>>> +static inline int fsi_mtype_2break_id(u8 mtype)
>>> +{
>>> + return FSI_MAX_CASCADE - 1;
>>> +}
>>> +
>>> +/*
>>> + * Build a mask where bit index 'x' is set (numbering from left to right.
>>> + * Bit 0 is MSB and bit 31 is LSM.
>>> + */
>>> +static inline unsigned long mask32(int x)
>>> +{
>>> + return 1 << (BITS_PER_LONG - x - 1);
>>
>> Is this masking in IBM bit ordering?
>>
>> We should pull the macros (or at least copy them) from arch/powerpc so
>> we can use them here.
>
> Will do, should be easy
>
>>
>>> +}
>>> +
>>> +/*
>>> + * Various function prototypes
>>> + */
>>> +int slv_install(void);
>>> +void slv_uninstall(void);
>>> +
>>> +void fsi_exit_fileio(dev_t);
>>> +
>>> +int fsibus_init(void);
>>> +void fsibus_exit(void);
>>> +
>>> +#endif /* DRIVERS_FSI_PRIVATE_H */
>>> diff --git a/drivers/fsi/fsicfam.h b/drivers/fsi/fsicfam.h
>>> new file mode 100644
>>> index 0000000..dde7036
>>> --- /dev/null
>>> +++ b/drivers/fsi/fsicfam.h
>>> @@ -0,0 +1,46 @@
>>> +/*
>>> + * FSI CFAM structure definitions and defines
>>> + *
>>> + * Copyright 2016 IBM Corp.
>>> + *
>>> + * Christopher Bostic <cbostic@us.ibm.com>
>>> + *
>>> + * This program is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU General Public License
>>> + * as published by the Free Software Foundation; either version
>>> + * 2 of the License, or (at your option) any later version.
>>> + */
>>> +#ifndef DRIVERS_FSICFAM_H
>>> +#define DRIVERS_FSICFAM_H
>>> +
>>> +#include "fsi.h"
>>> +#include "fsi_private.h"
>>> +
>>> +#define FSI_MAX_ENGINES 32 /* Max # of engines per CFAM */
>>> +
>>> +struct fsicfam { /* CFAM internal structure */
>>> + struct fsidevice *engines[FSI_MAX_ENGINES]; /* CFAM engine data */
>>> + u32 cfgtab[FSI_MAX_ENGINES]; /* Configuration word */
>>> + u16 chipid; /* CFAM chip type (IOU, CFAM-S, etc) */
>>> + u8 id; /* CFAM Id */
>>> + bool has_submaster; /* CFAM with cascaded or hub masters */
>>> + bool has_mux; /* CFAM with multiplexer */
>>> + u8 ec_maj; /* Major EC Level */
>>> + u8 ec_min; /* Minor EC Level or version number */
>>> + u16 pages; /* # Mapped pages */
>>> + u8 no_eng; /* Number of engines[] */
>>> + struct fsidevice fsidev; /* LDM entry */
>>> + struct fsidevice hpdone; /* Dummy engine to signal completion */
>>> + unsigned long eng_build; /* True during engine activate */
>>> + struct fsimaster *master; /* pointer to parent master */
>>> +};
>>> +
>>> +#define to_fsicfam(x) container_of((x), struct fsicfam, fsidev)
>>
>> Make this a function.
>
> Will change.
>
>
>>
>>> +
>>> +/*
>>> + * CFAM specific function prototypes.
>>> + */
>>> +int fsi_cfamirq_request(int, struct fsicfam *);
>>> +void fsi_cfamirq_free(struct fsicfam *);
>>> +
>>> +#endif /* DRIVERS_FSICFAM_H */
>>> diff --git a/drivers/fsi/fsiinit.c b/drivers/fsi/fsiinit.c
>>> index 767c0c3..c589294 100644
>>> --- a/drivers/fsi/fsiinit.c
>>> +++ b/drivers/fsi/fsiinit.c
>>> @@ -13,7 +13,9 @@
>>>
>>> #include <linux/init.h>
>>> #include <linux/module.h>
>>> +#include <linux/kdev_t.h>
>>> #include "fsiinit.h"
>>> +#include "fsimaster.h"
>>>
>>> MODULE_AUTHOR("Christopher Bostic cbostic@us.ibm.com");
>>> MODULE_DESCRIPTION("FSI master device driver");
>>> @@ -26,6 +28,7 @@ MODULE_DESCRIPTION("FSI master device driver");
>>> struct fsidd fsidd = { /* FSI device driver structure definition */
>>> .magic = FSI_DD_MAGIC,
>>> .strno = FSI_DD_STRNO,
>>> + .major = MKDEV(FSIDD_MAJOR, 0),
>>> };
>>>
>>> static int fsi_start(void)
>>> @@ -33,6 +36,25 @@ static int fsi_start(void)
>>> int rc = 0;
>>>
>>> dev_dbg(&fsidd.dev, "FSI DD v:%d installation ok\n", FSIDD_VERNO);
>>> +
>>> + init_waitqueue_head(&fsidd.error_wq);
>>> + init_waitqueue_head(&fsidd.lbus_wq);
>>> + init_waitqueue_head(&fsidd.irq_wq);
>>> + init_waitqueue_head(&fsidd.link_wq);
>>> +
>>> + /*
>>> + * Initialize the the master
>>> + */
>>> + if (!fsimaster_build_init(&fsidd.pri_master, FSI_PRIM, 0)) {
>>> + rc = PTR_ERR(0);
>>
>> ???
I think the ??? means what is up with PTR_ERR(0) ? Maybe just save the rc from the previous line?
>>
>>> + goto err;
>>> + }
>>> + fsimaster_start(&fsidd.pri_master);
>>> + dev_dbg(&fsidd.dev, "FSI DD v%d installation ok\n", FSIDD_VERNO);
>>> + return rc;
>>> +
>>> +err:
>>> + dev_dbg(&fsidd.dev, "FSI DD v:%d installation failed\n", FSIDD_VERNO);
>>> return rc;
>>
>> Your formatting is broken.
>
> How is it broken? Not sure what '???' means.
Agree…I don’t see anything broken here.
>
>>
>>> }
>>>
>>> diff --git a/drivers/fsi/fsiinit.h b/drivers/fsi/fsiinit.h
>>> index 93662533..10ddfc0 100644
>>> --- a/drivers/fsi/fsiinit.h
>>> +++ b/drivers/fsi/fsiinit.h
>>> @@ -19,6 +19,7 @@
>>> #include <linux/device.h>
>>> #include <linux/workqueue.h>
>>> #include <linux/hrtimer.h>
>>> +#include "fsimaster.h"
>>>
>>> #define FSI_DD_MAGIC 0x64644632 /* ddF2 */
>>> #define FSI_DD_STRNO 0x1 /* Structure version number */
>>> @@ -34,6 +35,7 @@ struct fsidd { /* FSI Main structure */
>>> wait_queue_head_t link_wq; /* Wait queue for link changes */
>>> unsigned long state; /* State driver is in */
>>> struct device dev; /* Anchor point in /sys/kernel */
>>> + struct fsimaster pri_master; /* Primary FSI master */
>>> };
>>>
>>> #define to_fsidd_prim(a) container_of(a, struct fsidd, pri_master)
>>> diff --git a/drivers/fsi/fsimaster.c b/drivers/fsi/fsimaster.c
>>> new file mode 100644
>>> index 0000000..b5d16db
>>> --- /dev/null
>>> +++ b/drivers/fsi/fsimaster.c
>>> @@ -0,0 +1,242 @@
>>> +/*
>>> + * FSI Master Control
>>> + *
>>> + * Copyright 2016 IBM Corp.
>>> + *
>>> + * Christopher Bostic <cbostic@us.ibm.com>
>>> + *
>>> + * This program is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU General Public License
>>> + * as published by the Free Software Foundation; either version
>>> + * 2 of the License, or (at your option) any later version.
>>> + */
>>> +
>>> +#include <linux/err.h>
>>> +#include <linux/delay.h>
>>> +#include <linux/ktime.h>
>>> +#include <linux/io.h>
>>> +#include "fsi.h"
>>> +#include "fsiinit.h"
>>> +#include "fsimaster.h"
>>> +#include "fsicfam.h"
>>> +
>>> +static int hpinfo_alloc(struct fsimaster *master)
>>> +{
>>> + return 0;
>>> +}
>>> +
>>> +static inline unsigned int fsimid(struct fsimaster *master)
>>> +{
>>> + return master->myid;
>>> +}
>>> +
>>> +static void primaster_exit(struct fsimaster *master)
>>> +{
>>> + if (master->dcr_alloc) {
>>> + master->base = NULL;
>>> + master->dcr_alloc = false;
>>> + }
>>> +}
>>> +
>>> +/*
>>> + * Read/write functions to access primary FSI master registers
>>> + * Note that this master is virtual as we don't yet have any
>>> + * real FSI masters implemented in hardware
>>
>> "virtual"? What's the purpose of this code?
>
> For implementations without a real hardware FSI master such as soft
> FSI there is a 'virtual' master in memory where registers are just u32
> variables in a data structure. Will add comments to make this clear.
>
>>
>>> + */
>>> +static u32 virt_master_readreg(struct fsi_mreg *mbase, int regnm)
>>> +{
>>> + u32 *base = (u32 *)mbase;
>>> +
>>> + return *(base + regnm);
>>> +}
>>> +
>>> +static void virt_master_readreg2(struct fsi_mreg *mbase, int regnm, u64 *dest)
>>> +{
>>> + u32 *base = (u32 *)mbase;
>>> +
>>> + memcpy(dest, base + regnm, sizeof(u64));
>>> +}
>>> +
>>> +static void virt_master_readreg4(struct fsi_mreg *mbase, int regnm, u32 *dest)
>>> +{
>>> + u32 *base = (u32 *)mbase;
>>> +
>>> + memcpy(dest, base + regnm, 4 * sizeof(u32));
>>> +}
>>>
> _______________________________________________
> openbmc mailing list
> openbmc@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/openbmc
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2016-09-21 23:06 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-24 19:54 [PATCH linux v5 0/7] Introducing the FSI device driver christopher.lee.bostic
2016-08-24 19:54 ` [PATCH linux v5 1/7] drivers/fsi: Initial stubs for " christopher.lee.bostic
2016-08-24 19:54 ` [PATCH linux v5 2/7] drivers/fsi: Add FSI Master Functionality and Initialization christopher.lee.bostic
2016-09-08 0:09 ` Joel Stanley
2016-09-21 18:38 ` Christopher Bostic
2016-09-21 22:59 ` Brad Bishop
2016-09-21 21:15 ` Christopher Bostic
2016-08-24 19:54 ` [PATCH linux v5 3/7] drivers/fsi: Add FSI master target device scanning function christopher.lee.bostic
2016-08-24 19:54 ` [PATCH linux v5 4/7] drivers/fsi: Add initial FSI link buildup christopher.lee.bostic
[not found] ` <CACPK8XfE0LpLnU64bw-8JA70wvAwbfO7L-fb6foyOLv-nMfNeg@mail.gmail.com>
2016-09-21 18:44 ` Christopher Bostic
2016-08-24 19:54 ` [PATCH linux v5 5/7] drivers/fsi: Add FSI bus type and hook into LDM christopher.lee.bostic
[not found] ` <CACPK8XcKuNAdrCiDuXpj5QgM+_U_+7hGKZd0ueZEGPcuurL=1g@mail.gmail.com>
2016-09-21 18:16 ` Christopher Bostic
2016-08-24 19:54 ` [PATCH linux v5 6/7] drivers/fsi: Add FSI Bus Support for Clients christopher.lee.bostic
2016-08-24 19:54 ` [PATCH linux v5 7/7] drivers/fsi: Add CFAM scanning function christopher.lee.bostic
2016-09-02 5:05 ` [PATCH linux v5 0/7] Introducing the FSI device driver Joel Stanley
2016-09-08 0:10 ` Joel Stanley
2016-09-21 18:49 ` Christopher Bostic
2016-09-21 18:52 ` Christopher Bostic
2016-09-21 17:42 ` Christopher Bostic
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.