summaryrefslogtreecommitdiffstats
path: root/drivers/thunderbolt/nhi.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/thunderbolt/nhi.h')
-rw-r--r--drivers/thunderbolt/nhi.h114
1 files changed, 114 insertions, 0 deletions
diff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h
new file mode 100644
index 000000000000..317242939b31
--- /dev/null
+++ b/drivers/thunderbolt/nhi.h
@@ -0,0 +1,114 @@
+/*
+ * Thunderbolt Cactus Ridge driver - NHI driver
+ *
+ * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
+ */
+
+#ifndef DSL3510_H_
+#define DSL3510_H_
+
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+/**
+ * struct tb_nhi - thunderbolt native host interface
+ */
+struct tb_nhi {
+ struct mutex lock; /*
+ * Must be held during ring creation/destruction.
+ * Is acquired by interrupt_work when dispatching
+ * interrupts to individual rings.
+ **/
+ struct pci_dev *pdev;
+ void __iomem *iobase;
+ struct tb_ring **tx_rings;
+ struct tb_ring **rx_rings;
+ struct work_struct interrupt_work;
+ u32 hop_count; /* Number of rings (end point hops) supported by NHI. */
+};
+
+/**
+ * struct tb_ring - thunderbolt TX or RX ring associated with a NHI
+ */
+struct tb_ring {
+ struct mutex lock; /* must be acquired after nhi->lock */
+ struct tb_nhi *nhi;
+ int size;
+ int hop;
+ int head; /* write next descriptor here */
+ int tail; /* complete next descriptor here */
+ struct ring_desc *descriptors;
+ dma_addr_t descriptors_dma;
+ struct list_head queue;
+ struct list_head in_flight;
+ struct work_struct work;
+ bool is_tx:1; /* rx otherwise */
+ bool running:1;
+};
+
+struct ring_frame;
+typedef void (*ring_cb)(struct tb_ring*, struct ring_frame*, bool canceled);
+
+/**
+ * struct ring_frame - for use with ring_rx/ring_tx
+ */
+struct ring_frame {
+ dma_addr_t buffer_phy;
+ ring_cb callback;
+ struct list_head list;
+ u32 size:12; /* TX: in, RX: out*/
+ u32 flags:12; /* RX: out */
+ u32 eof:4; /* TX:in, RX: out */
+ u32 sof:4; /* TX:in, RX: out */
+};
+
+#define TB_FRAME_SIZE 0x100 /* minimum size for ring_rx */
+
+struct tb_ring *ring_alloc_tx(struct tb_nhi *nhi, int hop, int size);
+struct tb_ring *ring_alloc_rx(struct tb_nhi *nhi, int hop, int size);
+void ring_start(struct tb_ring *ring);
+void ring_stop(struct tb_ring *ring);
+void ring_free(struct tb_ring *ring);
+
+int __ring_enqueue(struct tb_ring *ring, struct ring_frame *frame);
+
+/**
+ * ring_rx() - enqueue a frame on an RX ring
+ *
+ * frame->buffer, frame->buffer_phy and frame->callback have to be set. The
+ * buffer must contain at least TB_FRAME_SIZE bytes.
+ *
+ * frame->callback will be invoked with frame->size, frame->flags, frame->eof,
+ * frame->sof set once the frame has been received.
+ *
+ * If ring_stop is called after the packet has been enqueued frame->callback
+ * will be called with canceled set to true.
+ *
+ * Return: Returns ESHUTDOWN if ring_stop has been called. Zero otherwise.
+ */
+static inline int ring_rx(struct tb_ring *ring, struct ring_frame *frame)
+{
+ WARN_ON(ring->is_tx);
+ return __ring_enqueue(ring, frame);
+}
+
+/**
+ * ring_tx() - enqueue a frame on an TX ring
+ *
+ * frame->buffer, frame->buffer_phy, frame->callback, frame->size, frame->eof
+ * and frame->sof have to be set.
+ *
+ * frame->callback will be invoked with once the frame has been transmitted.
+ *
+ * If ring_stop is called after the packet has been enqueued frame->callback
+ * will be called with canceled set to true.
+ *
+ * Return: Returns ESHUTDOWN if ring_stop has been called. Zero otherwise.
+ */
+static inline int ring_tx(struct tb_ring *ring, struct ring_frame *frame)
+{
+ WARN_ON(!ring->is_tx);
+ return __ring_enqueue(ring, frame);
+}
+
+#endif