[PATCH v2 01/14] thunderbolt: Add initial cactus ridge NHI support
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
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