summaryrefslogtreecommitdiff
path: root/drivers/edgetpu/edgetpu-mcp.h
blob: 4530d7950817f494834a0a438874e7adffc3a3b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * EdgeTPU multi-chip package management.
 *
 * Copyright (C) 2020 Google, Inc.
 */
#ifndef __EDGETPU_MCP_H__
#define __EDGETPU_MCP_H__

#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/types.h>

#include "edgetpu-config.h"
#include "edgetpu-internal.h"

struct edgetpu_mcp {
	/* constant fields after initialization */

	u8 id;		/* the MCP ID matches etdev->mcp_id */
	u8 pkgtype;	/* package type, definition is chip-dependent */
	u8 total_num;	/* total number of etdevs expected by this MCP */
	u64 serial_num; /* serial number of the package */

	/* fields need to be locked before accessing */

	struct mutex lock;
	u8 cur_num;	/* current number of etdevs registered */
	/*
	 * Array of etdevs in this MCP, its length is @total_num.
	 *
	 * @etdevs[i] equals NULL means the etdev with mcp_die_index = i is not
	 * added yet.
	 *
	 * @etdevs[i] equals -ENODEV if that device is added but marked as
	 * failed by edgetpu_mcp_probe_fail().
	 *
	 * One should check with !IS_ERR_OR_NULL(etdevs[i]) before accessing.
	 */
	struct edgetpu_dev **etdevs;
};

#ifdef EDGETPU_HAS_MCP

/*
 * Registers @etdev to the MCP manager.
 *
 * @etdev->mcp_pkg_type, @etdev->mcp_id, and @etdev->mcp_die_index must be set
 * before this call.
 *
 * Returns 0 on success, or -errno on error.
 */
int edgetpu_mcp_add_etdev(struct edgetpu_dev *etdev);

/*
 * Init @mcp if all the dies in the mcp have been probed.
 *
 * After trying to probe each etdev on PCI, the mcp list is fully populated
 * with the corresponding etdevs. At this time the mcp list consists of
 * successfully probed *etdev and -ENODEV for etdevs that failed probe.
 * The mcp can then be initialized.
 *
 * Returns 0 on success, or -errno on error.
 */
int edgetpu_mcp_init_if_last(struct edgetpu_dev *etdev);

/*
 * Reverts edgetpu_mcp_add_etdev().
 *
 * @etdev->mcp_id and @etdev->mcp_die_index must be the same when called
 * edgetpu_mcp_add_etdev().
 */
void edgetpu_mcp_remove_etdev(struct edgetpu_dev *etdev);

/*
 * Marks etdev that failed to probe, set MCP entry to -ENODEV.
 */
void edgetpu_mcp_probe_fail(struct edgetpu_dev *etdev);

/*
 * Invokes @callback with each (currently) registered MCP.
 *
 * If @stop_on_err is true, this function stops when @callback returned non-zero
 * value. And that value is also returned by this function.
 * If @stop_on_err is false, @callback will be called exactly the number of
 * registered MCPs times, and this function will always return 0.
 *
 * @data can be any value, it will be directly passed to @callback.
 *
 * @callback is expected to return 0 on success, -errno otherwise.
 *
 * Don't call this or other edgetpu_mcp_* functions recursively to prevent dead
 * locking.
 *
 * It's @callback's responsibility to hold edgetpu_mcp's lock when access
 * non-constant fields of edgetpu_mcp.
 */
int edgetpu_mcp_each(bool stop_on_err, void *data,
		     int (*callback)(struct edgetpu_mcp *, void *));

/*
 * Invoke @callback on each device for the specified @mcp.
 *
 * @data can be any value, it will be directly passed to @callback.
 */
void edgetpu_mcp_foreach_etdev(struct edgetpu_mcp *mcp,
			       void (*callback)(struct edgetpu_dev *, void *),
			       void *data);

/*
 * Returns the MCP object @etdev belongs to.
 *
 * Returns NULL when such object is not found.
 *
 * Note: The returned pointer will be released when the last etdev is removed.
 * Don't use the returned pointer after edgetpu_mcp_remove_etdev() is called.
 */
struct edgetpu_mcp *edgetpu_mcp_of_etdev(struct edgetpu_dev *etdev);

/* Returns the next available MCP ID. */
int edgetpu_mcp_next_id(void);

/* To allocate / release structures for MCP management */
void edgetpu_mcp_init(void);
void edgetpu_mcp_exit(void);

#else /* !EDGETPU_HAS_MCP */

static inline struct edgetpu_mcp *
edgetpu_mcp_of_etdev(struct edgetpu_dev *etdev)
{
	return NULL;
}

static inline void edgetpu_mcp_init(void)
{
}

static inline void edgetpu_mcp_exit(void)
{
}

#endif /* EDGETPU_HAS_MCP */

#endif /* __EDGETPU_MCP_H__ */