-/* $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
*
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);
+}
-/* $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
*
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_ */