Add a framework for hardware locks.
authorpatrick <patrick@openbsd.org>
Wed, 17 May 2023 23:25:45 +0000 (23:25 +0000)
committerpatrick <patrick@openbsd.org>
Wed, 17 May 2023 23:25:45 +0000 (23:25 +0000)
ok kettenis@ drahn@

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

index 3bcb6f3..90f541f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ofw_misc.c,v 1.42 2023/04/26 21:37:46 patrick Exp $   */
+/*     $OpenBSD: ofw_misc.c,v 1.43 2023/05/17 23:25:45 patrick Exp $   */
 /*
  * Copyright (c) 2017-2021 Mark Kettenis
  *
@@ -1344,3 +1344,108 @@ mbox_recv(struct mbox_channel *mc, void *data, size_t len)
 
        return ENXIO;
 }
+
+/* hwlock support */
+
+LIST_HEAD(, hwlock_device) hwlock_devices =
+       LIST_HEAD_INITIALIZER(hwlock_devices);
+
+void
+hwlock_register(struct hwlock_device *hd)
+{
+       hd->hd_cells = OF_getpropint(hd->hd_node, "#hwlock-cells", 0);
+       hd->hd_phandle = OF_getpropint(hd->hd_node, "phandle", 0);
+       if (hd->hd_phandle == 0)
+               return;
+
+       LIST_INSERT_HEAD(&hwlock_devices, hd, hd_list);
+}
+
+int
+hwlock_lock_cells(uint32_t *cells, int lock)
+{
+       struct hwlock_device *hd;
+       uint32_t phandle = cells[0];
+
+       LIST_FOREACH(hd, &hwlock_devices, hd_list) {
+               if (hd->hd_phandle == phandle)
+                       break;
+       }
+
+       if (hd && hd->hd_lock)
+               return hd->hd_lock(hd->hd_cookie, &cells[1], lock);
+
+       return ENXIO;
+}
+
+uint32_t *
+hwlock_next_hwlock(uint32_t *cells)
+{
+       uint32_t phandle = cells[0];
+       int node, ncells;
+
+       node = OF_getnodebyphandle(phandle);
+       if (node == 0)
+               return NULL;
+
+       ncells = OF_getpropint(node, "#hwlock-cells", 0);
+       return cells + ncells + 1;
+}
+
+int
+hwlock_do_lock_idx(int node, int idx, int lock)
+{
+       uint32_t *hwlocks;
+       uint32_t *hwlock;
+       int rv = -1;
+       int len;
+
+       len = OF_getproplen(node, "hwlocks");
+       if (len <= 0)
+               return -1;
+
+       hwlocks = malloc(len, M_TEMP, M_WAITOK);
+       OF_getpropintarray(node, "hwlocks", hwlocks, len);
+
+       hwlock = hwlocks;
+       while (hwlock && hwlock < hwlocks + (len / sizeof(uint32_t))) {
+               if (idx <= 0)
+                       rv = hwlock_lock_cells(hwlock, lock);
+               if (idx == 0)
+                       break;
+               hwlock = hwlock_next_hwlock(hwlock);
+               idx--;
+       }
+
+       free(hwlocks, M_TEMP, len);
+       return rv;
+}
+
+int
+hwlock_lock_idx(int node, int idx)
+{
+       return hwlock_do_lock_idx(node, idx, 1);
+}
+
+int
+hwlock_lock_idx_timeout(int node, int idx, int ms)
+{
+       int i, ret = ENXIO;
+
+       for (i = 0; i <= ms; i++) {
+               ret = hwlock_do_lock_idx(node, idx, 1);
+               if (ret == EAGAIN) {
+                       delay(1000);
+                       continue;
+               }
+               break;
+       }
+
+       return ret;
+}
+
+int
+hwlock_unlock_idx(int node, int idx)
+{
+       return hwlock_do_lock_idx(node, idx, 0);
+}
index 6a21576..ae4a814 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ofw_misc.h,v 1.29 2023/04/03 01:40:32 dlg Exp $       */
+/*     $OpenBSD: ofw_misc.h,v 1.30 2023/05/17 23:25:45 patrick Exp $   */
 /*
  * Copyright (c) 2017-2021 Mark Kettenis
  *
@@ -313,4 +313,22 @@ 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);
 
+/* hwlock support */
+
+struct hwlock_device {
+       int     hd_node;
+       void    *hd_cookie;
+       int     (*hd_lock)(void *, uint32_t *, int);
+
+       LIST_ENTRY(hwlock_device) hd_list;
+       uint32_t hd_phandle;
+       uint32_t hd_cells;
+};
+
+void   hwlock_register(struct hwlock_device *);
+
+int    hwlock_lock_idx(int, int);
+int    hwlock_lock_idx_timeout(int, int, int);
+int    hwlock_unlock_idx(int, int);
+
 #endif /* _DEV_OFW_MISC_H_ */