[PATCH v2 01/14] thunderbolt: Add initial cactus ridge NHI support

2014-04-10 Thread Andreas Noever
Thunderbolt hotplug is supposed to be handled by the firmware. But Apple
decided to implement thunderbolt at the operating system level. The
firmare only initializes thunderbolt devices that are present at boot
time. This driver enables hotplug of thunderbolt of non-chained
thunderbolt devices on Apple systems with a cactus ridge 4C (2 ports)
controller (MacBookPro10,1).

This first patch adds the Kconfig file as well the parts of the driver
which talk directly to the hardware (that is pci device setup, interrupt
handling and RX/TX ring management).

Signed-off-by: Andreas Noever 
---
 drivers/Kconfig|   2 +
 drivers/Makefile   |   1 +
 drivers/thunderbolt/Kconfig|  12 +
 drivers/thunderbolt/Makefile   |   3 +
 drivers/thunderbolt/nhi.c  | 625 +
 drivers/thunderbolt/nhi.h  | 114 
 drivers/thunderbolt/nhi_regs.h | 101 +++
 7 files changed, 858 insertions(+)
 create mode 100644 drivers/thunderbolt/Kconfig
 create mode 100644 drivers/thunderbolt/Makefile
 create mode 100644 drivers/thunderbolt/nhi.c
 create mode 100644 drivers/thunderbolt/nhi.h
 create mode 100644 drivers/thunderbolt/nhi_regs.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 0a0a90f..07e3a73 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -174,4 +174,6 @@ source "drivers/powercap/Kconfig"
 
 source "drivers/mcb/Kconfig"
 
+source "drivers/thunderbolt/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index e3ced91..8d328e4 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -157,3 +157,4 @@ obj-$(CONFIG_NTB)   += ntb/
 obj-$(CONFIG_FMC)  += fmc/
 obj-$(CONFIG_POWERCAP) += powercap/
 obj-$(CONFIG_MCB)  += mcb/
+obj-$(CONFIG_THUNDERBOLT)  += thunderbolt/
diff --git a/drivers/thunderbolt/Kconfig b/drivers/thunderbolt/Kconfig
new file mode 100644
index 000..3a25529
--- /dev/null
+++ b/drivers/thunderbolt/Kconfig
@@ -0,0 +1,12 @@
+menuconfig THUNDERBOLT
+   tristate "Thunderbolt support for Apple devices"
+   default no
+   help
+ Cactus Ridge Thunderbolt Controller driver
+ This driver is required if you want to hotplug Thunderbolt devices on
+ Apple hardware.
+
+ Device chaining is currently not supported.
+
+ To compile this driver a module, choose M here. The module will be
+ called thunderbolt.
diff --git a/drivers/thunderbolt/Makefile b/drivers/thunderbolt/Makefile
new file mode 100644
index 000..d473ab9
--- /dev/null
+++ b/drivers/thunderbolt/Makefile
@@ -0,0 +1,3 @@
+obj-${CONFIG_THUNDERBOLT} := thunderbolt.o
+thunderbolt-objs := nhi.o
+
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
new file mode 100644
index 000..1c6adc7
--- /dev/null
+++ b/drivers/thunderbolt/nhi.c
@@ -0,0 +1,625 @@
+/*
+ * Thunderbolt Cactus Ridge driver - NHI driver
+ *
+ * The NHI (native host interface) is the pci device that allows us to send and
+ * receive frames from the thunderbolt bus.
+ *
+ * Copyright (c) 2014 Andreas Noever 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "nhi.h"
+#include "nhi_regs.h"
+
+#define RING_TYPE(ring) ((ring)->is_tx ? "TX ring" : "RX ring")
+
+
+static int ring_interrupt_index(struct tb_ring *ring)
+{
+   int bit = ring->hop;
+   if (!ring->is_tx)
+   bit += ring->nhi->hop_count;
+   return bit;
+}
+
+/**
+ * ring_interrupt_active() - activate/deactivate interrupts for a single ring
+ *
+ * ring->nhi->lock must be held.
+ */
+static void ring_interrupt_active(struct tb_ring *ring, bool active)
+{
+   int reg = REG_RING_INTERRUPT_BASE + ring_interrupt_index(ring) / 32;
+   int bit = ring_interrupt_index(ring) & 31;
+   int mask = 1 << bit;
+   u32 old, new;
+   old = ioread32(ring->nhi->iobase + reg);
+   if (active)
+   new = old | mask;
+   else
+   new = old & ~mask;
+
+   dev_info(>nhi->pdev->dev,
+"%s interrupt at register %#x bit %d (%#x -> %#x)\n",
+active ? "enabling" : "disabling", reg, bit, old, new);
+
+   if (new == old)
+   dev_WARN(>nhi->pdev->dev,
+"interrupt for %s %d is already %s\n",
+RING_TYPE(ring), ring->hop,
+active ? "enabled" : "disabled");
+   iowrite32(new, ring->nhi->iobase + reg);
+}
+
+/**
+ * nhi_disable_interrupts() - disable interrupts for all rings
+ *
+ * Use only during init and shutdown.
+ */
+static void nhi_disable_interrupts(struct tb_nhi *nhi)
+{
+   int i = 0;
+   /* disable interrupts */
+   for (i = 0; i < RING_INTERRUPT_REG_COUNT(nhi); i++)
+   iowrite32(0, nhi->iobase + REG_RING_INTERRUPT_BASE + 4 * i);
+
+   /* clear interrupt status bits */
+   for (i = 0; i < RING_NOTIFY_REG_COUNT(nhi); i++)
+   

[PATCH v2 01/14] thunderbolt: Add initial cactus ridge NHI support

2014-04-10 Thread Andreas Noever
Thunderbolt hotplug is supposed to be handled by the firmware. But Apple
decided to implement thunderbolt at the operating system level. The
firmare only initializes thunderbolt devices that are present at boot
time. This driver enables hotplug of thunderbolt of non-chained
thunderbolt devices on Apple systems with a cactus ridge 4C (2 ports)
controller (MacBookPro10,1).

This first patch adds the Kconfig file as well the parts of the driver
which talk directly to the hardware (that is pci device setup, interrupt
handling and RX/TX ring management).

Signed-off-by: Andreas Noever andreas.noe...@gmail.com
---
 drivers/Kconfig|   2 +
 drivers/Makefile   |   1 +
 drivers/thunderbolt/Kconfig|  12 +
 drivers/thunderbolt/Makefile   |   3 +
 drivers/thunderbolt/nhi.c  | 625 +
 drivers/thunderbolt/nhi.h  | 114 
 drivers/thunderbolt/nhi_regs.h | 101 +++
 7 files changed, 858 insertions(+)
 create mode 100644 drivers/thunderbolt/Kconfig
 create mode 100644 drivers/thunderbolt/Makefile
 create mode 100644 drivers/thunderbolt/nhi.c
 create mode 100644 drivers/thunderbolt/nhi.h
 create mode 100644 drivers/thunderbolt/nhi_regs.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 0a0a90f..07e3a73 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -174,4 +174,6 @@ source drivers/powercap/Kconfig
 
 source drivers/mcb/Kconfig
 
+source drivers/thunderbolt/Kconfig
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index e3ced91..8d328e4 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -157,3 +157,4 @@ obj-$(CONFIG_NTB)   += ntb/
 obj-$(CONFIG_FMC)  += fmc/
 obj-$(CONFIG_POWERCAP) += powercap/
 obj-$(CONFIG_MCB)  += mcb/
+obj-$(CONFIG_THUNDERBOLT)  += thunderbolt/
diff --git a/drivers/thunderbolt/Kconfig b/drivers/thunderbolt/Kconfig
new file mode 100644
index 000..3a25529
--- /dev/null
+++ b/drivers/thunderbolt/Kconfig
@@ -0,0 +1,12 @@
+menuconfig THUNDERBOLT
+   tristate Thunderbolt support for Apple devices
+   default no
+   help
+ Cactus Ridge Thunderbolt Controller driver
+ This driver is required if you want to hotplug Thunderbolt devices on
+ Apple hardware.
+
+ Device chaining is currently not supported.
+
+ To compile this driver a module, choose M here. The module will be
+ called thunderbolt.
diff --git a/drivers/thunderbolt/Makefile b/drivers/thunderbolt/Makefile
new file mode 100644
index 000..d473ab9
--- /dev/null
+++ b/drivers/thunderbolt/Makefile
@@ -0,0 +1,3 @@
+obj-${CONFIG_THUNDERBOLT} := thunderbolt.o
+thunderbolt-objs := nhi.o
+
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
new file mode 100644
index 000..1c6adc7
--- /dev/null
+++ b/drivers/thunderbolt/nhi.c
@@ -0,0 +1,625 @@
+/*
+ * Thunderbolt Cactus Ridge driver - NHI driver
+ *
+ * The NHI (native host interface) is the pci device that allows us to send and
+ * receive frames from the thunderbolt bus.
+ *
+ * Copyright (c) 2014 Andreas Noever andreas.noe...@gmail.com
+ */
+
+#include linux/slab.h
+#include linux/errno.h
+#include linux/pci.h
+#include linux/interrupt.h
+#include linux/module.h
+#include linux/dmi.h
+
+#include nhi.h
+#include nhi_regs.h
+
+#define RING_TYPE(ring) ((ring)-is_tx ? TX ring : RX ring)
+
+
+static int ring_interrupt_index(struct tb_ring *ring)
+{
+   int bit = ring-hop;
+   if (!ring-is_tx)
+   bit += ring-nhi-hop_count;
+   return bit;
+}
+
+/**
+ * ring_interrupt_active() - activate/deactivate interrupts for a single ring
+ *
+ * ring-nhi-lock must be held.
+ */
+static void ring_interrupt_active(struct tb_ring *ring, bool active)
+{
+   int reg = REG_RING_INTERRUPT_BASE + ring_interrupt_index(ring) / 32;
+   int bit = ring_interrupt_index(ring)  31;
+   int mask = 1  bit;
+   u32 old, new;
+   old = ioread32(ring-nhi-iobase + reg);
+   if (active)
+   new = old | mask;
+   else
+   new = old  ~mask;
+
+   dev_info(ring-nhi-pdev-dev,
+%s interrupt at register %#x bit %d (%#x - %#x)\n,
+active ? enabling : disabling, reg, bit, old, new);
+
+   if (new == old)
+   dev_WARN(ring-nhi-pdev-dev,
+interrupt for %s %d is already %s\n,
+RING_TYPE(ring), ring-hop,
+active ? enabled : disabled);
+   iowrite32(new, ring-nhi-iobase + reg);
+}
+
+/**
+ * nhi_disable_interrupts() - disable interrupts for all rings
+ *
+ * Use only during init and shutdown.
+ */
+static void nhi_disable_interrupts(struct tb_nhi *nhi)
+{
+   int i = 0;
+   /* disable interrupts */
+   for (i = 0; i  RING_INTERRUPT_REG_COUNT(nhi); i++)
+   iowrite32(0, nhi-iobase + REG_RING_INTERRUPT_BASE + 4 * i);
+
+   /* clear interrupt status