]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - include/linux/ntb.h
Merge tag 'armsoc-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux.git] / include / linux / ntb.h
index 56a92e3ae3ae5f0785c74eabcb56ae90a4a10b93..8c13538aeffea34614b1ac5f32e5837ce6ef2c03 100644 (file)
 
 #include <linux/completion.h>
 #include <linux/device.h>
+#include <linux/interrupt.h>
 
 struct ntb_client;
 struct ntb_dev;
+struct ntb_msi;
 struct pci_dev;
 
 /**
@@ -205,7 +207,7 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
 }
 
 /**
- * struct ntb_ctx_ops - ntb device operations
+ * struct ntb_dev_ops - ntb device operations
  * @port_number:       See ntb_port_number().
  * @peer_port_count:   See ntb_peer_port_count().
  * @peer_port_number:  See ntb_peer_port_number().
@@ -404,7 +406,7 @@ struct ntb_client {
 #define drv_ntb_client(__drv) container_of((__drv), struct ntb_client, drv)
 
 /**
- * struct ntb_device - ntb device
+ * struct ntb_dev - ntb device
  * @dev:               Linux device object.
  * @pdev:              PCI device entry of the ntb.
  * @topo:              Detected topology of the ntb.
@@ -426,6 +428,10 @@ struct ntb_dev {
        spinlock_t                      ctx_lock;
        /* block unregister until device is fully released */
        struct completion               released;
+
+#ifdef CONFIG_NTB_MSI
+       struct ntb_msi *msi;
+#endif
 };
 #define dev_ntb(__dev) container_of((__dev), struct ntb_dev, dev)
 
@@ -616,7 +622,6 @@ static inline int ntb_port_number(struct ntb_dev *ntb)
 
        return ntb->ops->port_number(ntb);
 }
-
 /**
  * ntb_peer_port_count() - get the number of peer device ports
  * @ntb:       NTB device context.
@@ -653,6 +658,58 @@ static inline int ntb_peer_port_number(struct ntb_dev *ntb, int pidx)
        return ntb->ops->peer_port_number(ntb, pidx);
 }
 
+/**
+ * ntb_logical_port_number() - get the logical port number of the local port
+ * @ntb:       NTB device context.
+ *
+ * The Logical Port Number is defined to be a unique number for each
+ * port starting from zero through to the number of ports minus one.
+ * This is in contrast to the Port Number where each port can be assigned
+ * any unique physical number by the hardware.
+ *
+ * The logical port number is useful for calculating the resource indexes
+ * used by peers.
+ *
+ * Return: the logical port number or negative value indicating an error
+ */
+static inline int ntb_logical_port_number(struct ntb_dev *ntb)
+{
+       int lport = ntb_port_number(ntb);
+       int pidx;
+
+       if (lport < 0)
+               return lport;
+
+       for (pidx = 0; pidx < ntb_peer_port_count(ntb); pidx++)
+               if (lport <= ntb_peer_port_number(ntb, pidx))
+                       return pidx;
+
+       return pidx;
+}
+
+/**
+ * ntb_peer_logical_port_number() - get the logical peer port by given index
+ * @ntb:       NTB device context.
+ * @pidx:      Peer port index.
+ *
+ * The Logical Port Number is defined to be a unique number for each
+ * port starting from zero through to the number of ports minus one.
+ * This is in contrast to the Port Number where each port can be assigned
+ * any unique physical number by the hardware.
+ *
+ * The logical port number is useful for calculating the resource indexes
+ * used by peers.
+ *
+ * Return: the peer's logical port number or negative value indicating an error
+ */
+static inline int ntb_peer_logical_port_number(struct ntb_dev *ntb, int pidx)
+{
+       if (ntb_peer_port_number(ntb, pidx) < ntb_port_number(ntb))
+               return pidx;
+       else
+               return pidx + 1;
+}
+
 /**
  * ntb_peer_port_idx() - get the peer device port index by given port number
  * @ntb:       NTB device context.
@@ -1506,4 +1563,141 @@ static inline int ntb_peer_msg_write(struct ntb_dev *ntb, int pidx, int midx,
        return ntb->ops->peer_msg_write(ntb, pidx, midx, msg);
 }
 
+/**
+ * ntb_peer_resource_idx() - get a resource index for a given peer idx
+ * @ntb:       NTB device context.
+ * @pidx:      Peer port index.
+ *
+ * When constructing a graph of peers, each remote peer must use a different
+ * resource index (mw, doorbell, etc) to communicate with each other
+ * peer.
+ *
+ * In a two peer system, this function should always return 0 such that
+ * resource 0 points to the remote peer on both ports.
+ *
+ * In a 5 peer system, this function will return the following matrix
+ *
+ * pidx \ port    0    1    2    3    4
+ * 0              0    0    1    2    3
+ * 1              0    1    1    2    3
+ * 2              0    1    2    2    3
+ * 3              0    1    2    3    3
+ *
+ * For example, if this function is used to program peer's memory
+ * windows, port 0 will program MW 0 on all it's peers to point to itself.
+ * port 1 will program MW 0 in port 0 to point to itself and MW 1 on all
+ * other ports. etc.
+ *
+ * For the legacy two host case, ntb_port_number() and ntb_peer_port_number()
+ * both return zero and therefore this function will always return zero.
+ * So MW 0 on each host would be programmed to point to the other host.
+ *
+ * Return: the resource index to use for that peer.
+ */
+static inline int ntb_peer_resource_idx(struct ntb_dev *ntb, int pidx)
+{
+       int local_port, peer_port;
+
+       if (pidx >= ntb_peer_port_count(ntb))
+               return -EINVAL;
+
+       local_port = ntb_logical_port_number(ntb);
+       peer_port = ntb_peer_logical_port_number(ntb, pidx);
+
+       if (peer_port < local_port)
+               return local_port - 1;
+       else
+               return local_port;
+}
+
+/**
+ * ntb_peer_highest_mw_idx() - get a memory window index for a given peer idx
+ *     using the highest index memory windows first
+ *
+ * @ntb:       NTB device context.
+ * @pidx:      Peer port index.
+ *
+ * Like ntb_peer_resource_idx(), except it returns indexes starting with
+ * last memory window index.
+ *
+ * Return: the resource index to use for that peer.
+ */
+static inline int ntb_peer_highest_mw_idx(struct ntb_dev *ntb, int pidx)
+{
+       int ret;
+
+       ret = ntb_peer_resource_idx(ntb, pidx);
+       if (ret < 0)
+               return ret;
+
+       return ntb_mw_count(ntb, pidx) - ret - 1;
+}
+
+struct ntb_msi_desc {
+       u32 addr_offset;
+       u32 data;
+};
+
+#ifdef CONFIG_NTB_MSI
+
+int ntb_msi_init(struct ntb_dev *ntb, void (*desc_changed)(void *ctx));
+int ntb_msi_setup_mws(struct ntb_dev *ntb);
+void ntb_msi_clear_mws(struct ntb_dev *ntb);
+int ntbm_msi_request_threaded_irq(struct ntb_dev *ntb, irq_handler_t handler,
+                                 irq_handler_t thread_fn,
+                                 const char *name, void *dev_id,
+                                 struct ntb_msi_desc *msi_desc);
+void ntbm_msi_free_irq(struct ntb_dev *ntb, unsigned int irq, void *dev_id);
+int ntb_msi_peer_trigger(struct ntb_dev *ntb, int peer,
+                        struct ntb_msi_desc *desc);
+int ntb_msi_peer_addr(struct ntb_dev *ntb, int peer,
+                     struct ntb_msi_desc *desc,
+                     phys_addr_t *msi_addr);
+
+#else /* not CONFIG_NTB_MSI */
+
+static inline int ntb_msi_init(struct ntb_dev *ntb,
+                              void (*desc_changed)(void *ctx))
+{
+       return -EOPNOTSUPP;
+}
+static inline int ntb_msi_setup_mws(struct ntb_dev *ntb)
+{
+       return -EOPNOTSUPP;
+}
+static inline void ntb_msi_clear_mws(struct ntb_dev *ntb) {}
+static inline int ntbm_msi_request_threaded_irq(struct ntb_dev *ntb,
+                                               irq_handler_t handler,
+                                               irq_handler_t thread_fn,
+                                               const char *name, void *dev_id,
+                                               struct ntb_msi_desc *msi_desc)
+{
+       return -EOPNOTSUPP;
+}
+static inline void ntbm_msi_free_irq(struct ntb_dev *ntb, unsigned int irq,
+                                    void *dev_id) {}
+static inline int ntb_msi_peer_trigger(struct ntb_dev *ntb, int peer,
+                                      struct ntb_msi_desc *desc)
+{
+       return -EOPNOTSUPP;
+}
+static inline int ntb_msi_peer_addr(struct ntb_dev *ntb, int peer,
+                                   struct ntb_msi_desc *desc,
+                                   phys_addr_t *msi_addr)
+{
+       return -EOPNOTSUPP;
+
+}
+
+#endif /* CONFIG_NTB_MSI */
+
+static inline int ntbm_msi_request_irq(struct ntb_dev *ntb,
+                                      irq_handler_t handler,
+                                      const char *name, void *dev_id,
+                                      struct ntb_msi_desc *msi_desc)
+{
+       return ntbm_msi_request_threaded_irq(ntb, handler, NULL, name,
+                                            dev_id, msi_desc);
+}
+
 #endif