aboutsummaryrefslogtreecommitdiff
path: root/src/vendorcode/cavium/include/bdk/libbdk-hal/device/bdk-device.h
blob: 3ca3f00710165a729f6c98da56fc350259be180c (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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/***********************license start***********************************
* Copyright (c) 2003-2017  Cavium Inc. (support@cavium.com). All rights
* reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*
*   * Neither the name of Cavium Inc. nor the names of
*     its contributors may be used to endorse or promote products
*     derived from this software without specific prior written
*     permission.
*
* This Software, including technical data, may be subject to U.S. export
* control laws, including the U.S. Export Administration Act and its
* associated regulations, and may be subject to export or import
* regulations in other countries.
*
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
* AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
* WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT
* TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
* REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
* DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
* OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
* PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT,
* QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK
* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
***********************license end**************************************/

/**
 * @file
 *
 * bdk_device_t represents devices connected using ECAMs. This
 * are discover by scanning the ECAMs and instantiating devices
 * for what is found.
 *
 *  The discovery process for a device is: Scan all ECAMs:
 *      1) Device found on an ECAM that doesn't have a bdk_device_t
 *      2) bdk_device_t created, put in
 *          BDK_DEVICE_STATE_NOT_PROBED state
 *  For all devices in state BDK_DEVICE_STATE_NOT_PROBED:
 *      1) Lookup driver probe() function. If not found, skip
 *      2) Call probe() 3) Based on probe(), transition to
 *          either BDK_DEVICE_STATE_PROBED or
 *          BDK_DEVICE_STATE_PROBE_FAIL
 *  For all devices in state BDK_DEVICE_STATE_PROBED:
 *      1) Lookup driver init() function. If not found, skip
 *      2) Call init() 3) Based on init(), transition to either
 *          BDK_DEVICE_STATE_READY or BDK_DEVICE_STATE_INIT_FAIL
 *  In general all devices should transition to
 *  BDK_DEVICE_STATE_PROBED before any init() functions are
 *  called. This can be used for synchronization. For example,
 *  the FPA should be functional after a probe() so PKI/PKO can
 *  succeed when calling alloc in init().
 *
 * @defgroup device ECAM Attached Devices
 * @addtogroup device
 * @{
 */

/**
 * Possible states of a device
 */
typedef enum
{
    BDK_DEVICE_STATE_NOT_PROBED,    /* Device is known and offline. We haven't probed it */
    BDK_DEVICE_STATE_PROBE_FAIL,    /* Device failed probing and is offline */
    BDK_DEVICE_STATE_PROBED,        /* Device succeeded probing, about to go online */
    BDK_DEVICE_STATE_INIT_FAIL,     /* Device init call failed, offline */
    BDK_DEVICE_STATE_READY,         /* Device init call success, online */
} bdk_device_state_t;

/**
 * The structure of a ECAM BAR entry inside if a device
 */
typedef struct
{
    uint64_t address;   /* Base physical address */
    uint32_t size2;     /* Size in bytes as 2^size */
    uint32_t flags;     /* Type flags for the BAR */
} bdk_device_bar_t;

/**
 * Defines the BDK's representation of a ECAM connected device
 */
typedef struct
{
    char name[16];                  /* Name of the device */
    bdk_device_bar_t    bar[4];     /* Device BARs, first for better alignment */
    bdk_device_state_t  state : 8;  /* Current state of bdk_device_t */
    bdk_node_t          node : 3;   /* Node the device is on */
    uint8_t             ecam : 5;   /* ECAM for the device */
    uint8_t             bus;        /* ECAM bus number (0-255) */
    uint8_t             dev : 5;    /* ECAM device (0-31) */
    uint8_t             func : 3;   /* ECAM deivce function (0-7) */
    uint32_t            id;         /* ECAM device ID */
    uint16_t            instance;   /* Cavium internal instance number */
} bdk_device_t;
#define BDK_NO_DEVICE_INSTANCE 0xffffu

/**
 * Defines the main entry points for a device driver. Full
 * definition is in bdk-device.h
 */
struct bdk_driver_s;

/**
 * Called to register a new driver with the bdk-device system. Drivers are probed
 * and initialized as device are found for them. If devices have already been
 * added before the driver was registered, the driver will be probed and
 * initialized before this function returns.
 *
 * @param driver Driver functions
 *
 * @return Zero on success, negative on failure
 */
extern int bdk_device_add_driver(struct bdk_driver_s *driver);

/**
 * Called by the ECAM code whan a new device is detected in the system
 *
 * @param node   Node the ECAM is on
 * @param ecam   ECAM the device is on
 * @param bus    Bus number for the device
 * @param dev    Device number
 * @param func   Function number
 *
 * @return Zero on success, negative on failure
 */
extern int bdk_device_add(bdk_node_t node, int ecam, int bus, int dev, int func);

/**
 * Rename a device. Called by driver to give devices friendly names
 *
 * @param device Device to rename
 * @param format Printf style format string
 */
extern void bdk_device_rename(bdk_device_t *device, const char *format, ...) __attribute__ ((format(printf, 2, 3)));

/**
 * Called by the ECAM code once all devices have been added
 *
 * @return Zero on success, negative on failure
 */
extern int bdk_device_init(void);

/**
 * Lookup a device by ECAM ID and internal instance number. This can be used by
 * one device to find a handle to an associated device. For example, PKI would
 * use this function to get a handle to the FPA.
 *
 * @param node     Node to lookup for
 * @param id       ECAM ID
 * @param instance Cavium internal instance number
 *
 * @return Device pointer, or NULL if the device isn't found
 */
extern const bdk_device_t *bdk_device_lookup(bdk_node_t node, uint32_t id, int instance);

/**
 * Read from a device BAR
 *
 * @param device Device to read from
 * @param bar    Which BAR to read from (0-3)
 * @param size   Size of the read
 * @param offset Offset into the BAR
 *
 * @return Value read
 */
extern uint64_t bdk_bar_read(const bdk_device_t *device, int bar, int size, uint64_t offset);

/**
 * Write to a device BAR
 *
 * @param device Device to write to
 * @param bar    Which BAR to read from (0-3)
 * @param size   Size of the write
 * @param offset Offset into the BAR
 * @param value  Value to write
 */
extern void bdk_bar_write(const bdk_device_t *device, int bar, int size, uint64_t offset, uint64_t value);

/**
 * This macro makes it easy to define a variable of the correct
 * type for a BAR.
 */
#define BDK_BAR_DEFINE(name, REG) typedef_##REG name

/**
 * This macro makes it easy to define a variable and initialize it
 * with a BAR.
 */
#define BDK_BAR_INIT(name, device, REG) typedef_##REG name = {.u = bdk_bar_read(device, device_bar_##REG, sizeof(typedef_##REG), REG)}

/**
 * Macro to read a BAR
 */
#define BDK_BAR_READ(device, REG) bdk_bar_read(device, device_bar_##REG, sizeof(typedef_##REG), REG)

/**
 * Macro to write a BAR
 */
#define BDK_BAR_WRITE(device, REG, value) bdk_bar_write(device, device_bar_##REG, sizeof(typedef_##REG), REG, value)

/**
 * Macro to make a read, modify, and write sequence easy. The "code_block"
 * should be replaced with a C code block or a comma separated list of
 * "name.s.field = value", without the quotes.
 */
#define BDK_BAR_MODIFY(name, device, REG, code_block) do { \
        uint64_t _tmp_address = REG; \
        typedef_##REG name = {.u = bdk_bar_read(device, device_bar_##REG, sizeof(typedef_##REG), _tmp_address)}; \
        code_block; \
        bdk_bar_write(device, device_bar_##REG, sizeof(typedef_##REG), _tmp_address, name.u); \
    } while (0)

/**
 * This macro spins on a field waiting for it to reach a value. It
 * is common in code to need to wait for a specific field in a
 * REG to match a specific value. Conceptually this macro
 * expands to:
 *
 * 1) read REG
 * 2) Check if ("type".s."field" "op" "value")
 * 3) If #2 isn't true loop to #1 unless too much time has passed.
 */
#define BDK_BAR_WAIT_FOR_FIELD(device, REG, field, op, value, timeout_usec) \
    ({int result;                                                       \
    do {                                                                \
        uint64_t done = bdk_clock_get_count(BDK_CLOCK_TIME) + (uint64_t)timeout_usec * \
                        bdk_clock_get_rate(bdk_numa_local(), BDK_CLOCK_TIME) / 1000000;   \
        typedef_##REG c;                                                \
        uint64_t _tmp_address = REG;                                    \
        while (1)                                                       \
        {                                                               \
            c.u = bdk_bar_read(device, device_bar_##REG, sizeof(typedef_##REG), _tmp_address); \
            if ((c.s.field) op (value)) {                               \
                result = 0;                                             \
                break;                                                  \
            } else if (bdk_clock_get_count(BDK_CLOCK_TIME) > done) {    \
                result = -1;                                            \
                break;                                                  \
            } else                                                      \
                bdk_thread_yield();                                     \
        }                                                               \
    } while (0);                                                        \
    result;})

/** @} */