summaryrefslogtreecommitdiffstats
path: root/libpdbg
diff options
context:
space:
mode:
authorJoel Stanley <joel@jms.id.au>2016-12-12 20:01:40 +1100
committerAlistair Popple <alistair@popple.id.au>2017-02-18 09:28:43 +1100
commit6df751700763f9fa6649b15fc5859b11dec0e99e (patch)
tree5c4d4cd9b20069e7bacded6a4e839187f711d1cf /libpdbg
parent4b1c617f2a469e7033b3376a1b591f26c5010787 (diff)
downloadpdbg-6df751700763f9fa6649b15fc5859b11dec0e99e.tar.gz
pdbg-6df751700763f9fa6649b15fc5859b11dec0e99e.zip
libdbg: Introduce kernel FSI driver backend
Creatively named 'kernel', this uses the SoftFSI aka OpenFSI aka fsi kernel driver. This backend triggers a probe of all attached FSI devices by the kernel. This assumes a single slave appears in sysfs, and uses the 'raw' device to perform reads and writes directly to the CFAM address space and SCOM space. Signed-off-by: Joel Stanley <joel@jms.id.au>
Diffstat (limited to 'libpdbg')
-rw-r--r--libpdbg/kernel.c184
-rw-r--r--libpdbg/operations.h2
2 files changed, 186 insertions, 0 deletions
diff --git a/libpdbg/kernel.c b/libpdbg/kernel.c
new file mode 100644
index 0000000..2694ba0
--- /dev/null
+++ b/libpdbg/kernel.c
@@ -0,0 +1,184 @@
+/* Copyright 2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <assert.h>
+#include <errno.h>
+#include <err.h>
+#include <inttypes.h>
+
+#include "bitutils.h"
+#include "operations.h"
+#include "target.h"
+
+#define FSI_SCAN_PATH "/sys/devices/platform/fsi-master/scan"
+#define FSI_CFAM_PATH "/sys/devices/platform/fsi-master/slave@00:00/raw"
+#define FSI_SCOM_PATH "/sys/devices/platform/fsi-master/slave@00:00/"
+
+int fsi_fd;
+int scom_fd;
+
+static int kernel_putscom(struct target *target, uint64_t addr, uint64_t value)
+{
+ int rc;
+
+ rc = lseek(scom_fd, addr, SEEK_SET);
+ if (rc < 0) {
+ warn("Failed to seek %s", FSI_SCOM_PATH);
+ return errno;
+ }
+
+ rc = write(scom_fd, &value, sizeof(value));
+ if (rc < 0) {
+ warn("Failed to write to 0x%016llx", addr);
+ return errno;
+ }
+
+ return 0;
+
+}
+
+static int kernel_getscom(struct target *target, uint64_t addr, uint64_t *value)
+{
+ int rc;
+
+ rc = lseek(fsi_fd, addr, SEEK_SET);
+ if (rc < 0) {
+ warn("Failed to seek %s", FSI_SCOM_PATH);
+ return errno;
+ }
+
+ rc = read(fsi_fd, value, sizeof(*value));
+ if (rc < 0) {
+ warn("Failed to read from 0x%016llx", addr);
+ return errno;
+ }
+
+ return 0;
+
+}
+
+static int kernel_fsi_getcfam(struct target *target, uint64_t addr64, uint64_t *value)
+{
+ int rc;
+ uint32_t addr = (addr64 & 0x1fff00) | ((addr64 & 0xff) << 2);
+
+ rc = lseek(fsi_fd, addr, SEEK_SET);
+ if (rc < 0) {
+ warn("Failed to seek %s", FSI_CFAM_PATH);
+ return errno;
+ }
+
+ rc = read(fsi_fd, value, 4);
+ if (rc < 0) {
+ warn("Failed to read from 0x%08x (%016llx)", (uint32_t)addr, addr64);
+ return errno;
+ }
+
+ return 0;
+}
+
+static int kernel_fsi_putcfam(struct target *target, uint64_t addr64, uint64_t data)
+{
+ int rc;
+ uint32_t addr = (addr64 & 0x1fff00) | ((addr64 & 0xff) << 2);
+
+ rc = lseek(fsi_fd, addr, SEEK_SET);
+ if (rc < 0) {
+ warn("Failed to seek %s", FSI_CFAM_PATH);
+ return errno;
+ }
+
+ rc = write(fsi_fd, &data, 4);
+ if (rc < 0) {
+ warn("Failed to write to 0x%08x (%016llx)", addr, addr64);
+ return errno;
+ }
+
+ return 0;
+}
+
+static void kernel_fsi_destroy(struct target *target)
+{
+ close(fsi_fd);
+}
+
+static void kernel_fsi_scan_devices(void)
+{
+ const char one = '1';
+ int rc, fd;
+
+ fd = open(FSI_SCAN_PATH, O_WRONLY | O_SYNC);
+ if (fd < 0)
+ err(errno, "Unable to open %s", FSI_SCAN_PATH);
+
+ rc = write(fd, &one, sizeof(one));
+ if (rc < 0)
+ err(errno, "Unable to write to %s", FSI_SCAN_PATH);
+
+ close(fd);
+}
+
+int kernel_fsi_target_init(struct target *target, const char *name,
+ struct target *next)
+{
+ uint64_t value;
+
+ if (!fsi_fd) {
+ int tries = 5;
+
+ while (tries) {
+ /* Open first raw device */
+ fsi_fd = open(FSI_CFAM_PATH, O_RDWR | O_SYNC);
+ if (fsi_fd >= 0)
+ goto found;
+ tries--;
+
+ /* Scan */
+ kernel_fsi_scan_devices();
+ sleep(1);
+ }
+ if (fsi_fd < 0)
+ err(errno, "Unable to open %s", FSI_CFAM_PATH);
+
+ }
+found:
+ /* No cascaded devices after this one. */
+ assert(next == NULL);
+ target_init(target, name, 0, kernel_fsi_getcfam, kernel_fsi_putcfam,
+ kernel_fsi_destroy, next);
+
+ /* Read chip id */
+ CHECK_ERR(read_target(target, 0xc09, &value));
+ target->chip_type = get_chip_type(value);
+
+ return 0;
+}
+
+int kernel_fsi2pib_target_init(struct target *target, const char *name,
+ uint64_t base, struct target *next)
+{
+ target_init(target, name, base, kernel_getscom, kernel_putscom, NULL,
+ next);
+
+ return 0;
+
+}
diff --git a/libpdbg/operations.h b/libpdbg/operations.h
index a3e66c6..76a1ca8 100644
--- a/libpdbg/operations.h
+++ b/libpdbg/operations.h
@@ -74,7 +74,9 @@ int fsi_target_init(struct target *target, const char *name, enum fsi_system_typ
int fsi_target_probe(struct target *targets, int max_target_count);
int i2c_target_init(struct target *target, const char *name, struct target *next,
const char *bus, int addr);
+int kernel_fsi_target_init(struct target *target, const char *name, struct target *next);
int fsi2pib_target_init(struct target *target, const char *name, uint64_t base, struct target *next);
+int kernel_fsi2pib_target_init(struct target *target, const char *name, uint64_t base, struct target *next);
int opb_target_init(struct target *target, const char *name, uint64_t base, struct target *next);
enum chip_type get_chip_type(uint64_t chip_id);
int thread_target_init(struct target *thread, const char *name, uint64_t thread_id, struct target *next);
OpenPOWER on IntegriCloud