Add a mailbox "framework" to handle mailboxes referenced in device trees
authorkettenis <kettenis@openbsd.org>
Sat, 18 Dec 2021 09:19:25 +0000 (09:19 +0000)
committerkettenis <kettenis@openbsd.org>
Sat, 18 Dec 2021 09:19:25 +0000 (09:19 +0000)
in a generic way.

ok visa@

sys/dev/ofw/ofw_misc.c
sys/dev/ofw/ofw_misc.h

index 1f562eb..abb9f49 100644 (file)
@@ -1,6 +1,6 @@
-/*     $OpenBSD: ofw_misc.c,v 1.33 2021/06/25 17:41:22 patrick Exp $   */
+/*     $OpenBSD: ofw_misc.c,v 1.34 2021/12/18 09:19:25 kettenis Exp $  */
 /*
- * Copyright (c) 2017 Mark Kettenis
+ * Copyright (c) 2017-2021 Mark Kettenis
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -1043,3 +1043,129 @@ iommu_reserve_region_pci(int node, uint32_t rid, bus_addr_t addr,
 
        return iommu_device_do_reserve(phandle, &sid, addr, size);
 }
+
+/*
+ * Mailbox support.
+ */
+
+struct mbox_channel {
+       struct mbox_device      *mc_md;
+       void                    *mc_cookie;
+};
+
+LIST_HEAD(, mbox_device) mbox_devices =
+       LIST_HEAD_INITIALIZER(mbox_devices);
+
+void
+mbox_register(struct mbox_device *md)
+{
+       md->md_cells = OF_getpropint(md->md_node, "#mbox-cells", 0);
+       md->md_phandle = OF_getpropint(md->md_node, "phandle", 0);
+       if (md->md_phandle == 0)
+               return;
+
+       LIST_INSERT_HEAD(&mbox_devices, md, md_list);
+}
+
+struct mbox_channel *
+mbox_channel_cells(uint32_t *cells, struct mbox_client *client)
+{
+       struct mbox_device *md;
+       struct mbox_channel *mc;
+       uint32_t phandle = cells[0];
+       void *cookie;
+
+       LIST_FOREACH(md, &mbox_devices, md_list) {
+               if (md->md_phandle == phandle)
+                       break;
+       }
+
+       if (md && md->md_channel) {
+               cookie = md->md_channel(md->md_cookie, &cells[1], client);
+               if (cookie) {
+                       mc = malloc(sizeof(*mc), M_DEVBUF, M_WAITOK);
+                       mc->mc_md = md;
+                       mc->mc_cookie = cookie;
+                       return mc;
+               }
+       }
+
+       return NULL;
+}
+
+uint32_t *
+mbox_next_mbox(uint32_t *cells)
+{
+       uint32_t phandle = cells[0];
+       int node, ncells;
+
+       node = OF_getnodebyphandle(phandle);
+       if (node == 0)
+               return NULL;
+
+       ncells = OF_getpropint(node, "#mbox-cells", 0);
+       return cells + ncells + 1;
+}
+
+struct mbox_channel *
+mbox_channel_idx(int node, int idx, struct mbox_client *client)
+{
+       struct mbox_channel *mc = NULL;
+       uint32_t *mboxes;
+       uint32_t *mbox;
+       int len;
+
+       len = OF_getproplen(node, "mboxes");
+       if (len <= 0)
+               return NULL;
+
+       mboxes = malloc(len, M_TEMP, M_WAITOK);
+       OF_getpropintarray(node, "mboxes", mboxes, len);
+
+       mbox = mboxes;
+       while (mbox && mbox < mboxes + (len / sizeof(uint32_t))) {
+               if (idx == 0) {
+                       mc = mbox_channel_cells(mbox, client);
+                       break;
+               }
+               mbox = mbox_next_mbox(mbox);
+               idx--;
+       }
+
+       free(mboxes, M_TEMP, len);
+       return mc;
+}
+
+struct mbox_channel *
+mbox_channel(int node, const char *name, struct mbox_client *client)
+{
+       int idx;
+
+       idx = OF_getindex(node, name, "mbox-names");
+       if (idx == -1)
+               return NULL;
+
+       return mbox_channel_idx(node, idx, client);
+}
+
+int
+mbox_send(struct mbox_channel *mc, const void *data, size_t len)
+{
+       struct mbox_device *md = mc->mc_md;
+
+       if (md->md_send)
+               return md->md_send(mc->mc_cookie, data, len);
+
+       return ENXIO;
+}
+
+int
+mbox_recv(struct mbox_channel *mc, void *data, size_t len)
+{
+       struct mbox_device *md = mc->mc_md;
+
+       if (md->md_recv)
+               return md->md_recv(mc->mc_cookie, data, len);
+
+       return ENXIO;
+}
index 03fb3a0..e294d30 100644 (file)
@@ -1,6 +1,6 @@
-/*     $OpenBSD: ofw_misc.h,v 1.21 2021/06/25 17:41:22 patrick Exp $   */
+/*     $OpenBSD: ofw_misc.h,v 1.22 2021/12/18 09:19:25 kettenis Exp $  */
 /*
- * Copyright (c) 2017 Mark Kettenis
+ * Copyright (c) 2017-2021 Mark Kettenis
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -254,4 +254,33 @@ bus_dma_tag_t iommu_device_map(int, bus_dma_tag_t);
 bus_dma_tag_t iommu_device_map_pci(int, uint32_t, bus_dma_tag_t);
 void   iommu_reserve_region_pci(int, uint32_t, bus_addr_t, bus_size_t);
 
+/* Mailbox support */
+
+struct mbox_client {
+       void    (*mc_rx_callback)(void *);
+       void    *mc_rx_arg;
+};
+
+struct mbox_channel;
+
+struct mbox_device {
+       int     md_node;
+       void    *md_cookie;
+       void    *(*md_channel)(void *, uint32_t *, struct mbox_client *);
+       int     (*md_recv)(void *, void *, size_t);
+       int     (*md_send)(void *, const void *, size_t);
+
+       LIST_ENTRY(mbox_device) md_list;
+       uint32_t md_phandle;
+       uint32_t md_cells;
+};
+
+void   mbox_register(struct mbox_device *);
+
+struct mbox_channel *mbox_channel(int, const char *, struct mbox_client *);
+struct mbox_channel *mbox_channel_idx(int, int, struct mbox_client *);
+
+int    mbox_send(struct mbox_channel *, const void *, size_t);
+int    mbox_recv(struct mbox_channel *, void *, size_t);
+
 #endif /* _DEV_OFW_MISC_H_ */