From: patrick Date: Wed, 17 May 2023 23:25:45 +0000 (+0000) Subject: Add a framework for hardware locks. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=949f008f01ce4510c6cf4a111524f59a568b1d46;p=openbsd Add a framework for hardware locks. ok kettenis@ drahn@ --- diff --git a/sys/dev/ofw/ofw_misc.c b/sys/dev/ofw/ofw_misc.c index 3bcb6f3b013..90f541fd5d7 100644 --- a/sys/dev/ofw/ofw_misc.c +++ b/sys/dev/ofw/ofw_misc.c @@ -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); +} diff --git a/sys/dev/ofw/ofw_misc.h b/sys/dev/ofw/ofw_misc.h index 6a21576b477..ae4a81463f8 100644 --- a/sys/dev/ofw/ofw_misc.h +++ b/sys/dev/ofw/ofw_misc.h @@ -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_ */