1 #ifndef __CB_BDK_DEVICE_H__ 2 #define __CB_BDK_DEVICE_H__ 3 4 /***********************license start*********************************** 5 * Copyright (c) 2003-2017 Cavium Inc. ([email protected]). All rights 6 * reserved. 7 * 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions are 11 * met: 12 * 13 * * Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * * Redistributions in binary form must reproduce the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer in the documentation and/or other materials provided 19 * with the distribution. 20 * 21 * * Neither the name of Cavium Inc. nor the names of 22 * its contributors may be used to endorse or promote products 23 * derived from this software without specific prior written 24 * permission. 25 * 26 * This Software, including technical data, may be subject to U.S. export 27 * control laws, including the U.S. Export Administration Act and its 28 * associated regulations, and may be subject to export or import 29 * regulations in other countries. 30 * 31 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 32 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 33 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT 34 * TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY 35 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT 36 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES 37 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR 38 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, 39 * QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK 40 * ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 41 ***********************license end**************************************/ 42 43 /** 44 * @file 45 * 46 * bdk_device_t represents devices connected using ECAMs. This 47 * are discover by scanning the ECAMs and instantiating devices 48 * for what is found. 49 * 50 * The discovery process for a device is: Scan all ECAMs: 51 * 1) Device found on an ECAM that doesn't have a bdk_device_t 52 * 2) bdk_device_t created, put in 53 * BDK_DEVICE_STATE_NOT_PROBED state 54 * For all devices in state BDK_DEVICE_STATE_NOT_PROBED: 55 * 1) Lookup driver probe() function. If not found, skip 56 * 2) Call probe() 3) Based on probe(), transition to 57 * either BDK_DEVICE_STATE_PROBED or 58 * BDK_DEVICE_STATE_PROBE_FAIL 59 * For all devices in state BDK_DEVICE_STATE_PROBED: 60 * 1) Lookup driver init() function. If not found, skip 61 * 2) Call init() 3) Based on init(), transition to either 62 * BDK_DEVICE_STATE_READY or BDK_DEVICE_STATE_INIT_FAIL 63 * In general all devices should transition to 64 * BDK_DEVICE_STATE_PROBED before any init() functions are 65 * called. This can be used for synchronization. For example, 66 * the FPA should be functional after a probe() so PKI/PKO can 67 * succeed when calling alloc in init(). 68 * 69 * @defgroup device ECAM Attached Devices 70 * @addtogroup device 71 * @{ 72 */ 73 74 /** 75 * Possible states of a device 76 */ 77 typedef enum 78 { 79 BDK_DEVICE_STATE_NOT_PROBED, /* Device is known and offline. We haven't probed it */ 80 BDK_DEVICE_STATE_PROBE_FAIL, /* Device failed probing and is offline */ 81 BDK_DEVICE_STATE_PROBED, /* Device succeeded probing, about to go online */ 82 BDK_DEVICE_STATE_INIT_FAIL, /* Device init call failed, offline */ 83 BDK_DEVICE_STATE_READY, /* Device init call success, online */ 84 } bdk_device_state_t; 85 86 /** 87 * The structure of a ECAM BAR entry inside if a device 88 */ 89 typedef struct 90 { 91 uint64_t address; /* Base physical address */ 92 uint32_t size2; /* Size in bytes as 2^size */ 93 uint32_t flags; /* Type flags for the BAR */ 94 } bdk_device_bar_t; 95 96 /** 97 * Defines the BDK's representation of a ECAM connected device 98 */ 99 typedef struct 100 { 101 char name[16]; /* Name of the device */ 102 bdk_device_bar_t bar[4]; /* Device BARs, first for better alignment */ 103 bdk_device_state_t state : 8; /* Current state of bdk_device_t */ 104 bdk_node_t node : 3; /* Node the device is on */ 105 uint8_t ecam : 5; /* ECAM for the device */ 106 uint8_t bus; /* ECAM bus number (0-255) */ 107 uint8_t dev : 5; /* ECAM device (0-31) */ 108 uint8_t func : 3; /* ECAM deivce function (0-7) */ 109 uint32_t id; /* ECAM device ID */ 110 uint16_t instance; /* Cavium internal instance number */ 111 } bdk_device_t; 112 #define BDK_NO_DEVICE_INSTANCE 0xffffu 113 114 /** 115 * Defines the main entry points for a device driver. Full 116 * definition is in bdk-device.h 117 */ 118 struct bdk_driver_s; 119 120 /** 121 * Called to register a new driver with the bdk-device system. Drivers are probed 122 * and initialized as device are found for them. If devices have already been 123 * added before the driver was registered, the driver will be probed and 124 * initialized before this function returns. 125 * 126 * @param driver Driver functions 127 * 128 * @return Zero on success, negative on failure 129 */ 130 extern int bdk_device_add_driver(struct bdk_driver_s *driver); 131 132 /** 133 * Called by the ECAM code whan a new device is detected in the system 134 * 135 * @param node Node the ECAM is on 136 * @param ecam ECAM the device is on 137 * @param bus Bus number for the device 138 * @param dev Device number 139 * @param func Function number 140 * 141 * @return Zero on success, negative on failure 142 */ 143 extern int bdk_device_add(bdk_node_t node, int ecam, int bus, int dev, int func); 144 145 /** 146 * Rename a device. Called by driver to give devices friendly names 147 * 148 * @param device Device to rename 149 * @param format Printf style format string 150 */ 151 extern void bdk_device_rename(bdk_device_t *device, const char *format, ...) __attribute__ ((format(printf, 2, 3))); 152 153 /** 154 * Called by the ECAM code once all devices have been added 155 * 156 * @return Zero on success, negative on failure 157 */ 158 extern int bdk_device_init(void); 159 160 /** 161 * Lookup a device by ECAM ID and internal instance number. This can be used by 162 * one device to find a handle to an associated device. For example, PKI would 163 * use this function to get a handle to the FPA. 164 * 165 * @param node Node to lookup for 166 * @param id ECAM ID 167 * @param instance Cavium internal instance number 168 * 169 * @return Device pointer, or NULL if the device isn't found 170 */ 171 extern const bdk_device_t *bdk_device_lookup(bdk_node_t node, uint32_t id, int instance); 172 173 /** 174 * Read from a device BAR 175 * 176 * @param device Device to read from 177 * @param bar Which BAR to read from (0-3) 178 * @param size Size of the read 179 * @param offset Offset into the BAR 180 * 181 * @return Value read 182 */ 183 extern uint64_t bdk_bar_read(const bdk_device_t *device, int bar, int size, uint64_t offset); 184 185 /** 186 * Write to a device BAR 187 * 188 * @param device Device to write to 189 * @param bar Which BAR to read from (0-3) 190 * @param size Size of the write 191 * @param offset Offset into the BAR 192 * @param value Value to write 193 */ 194 extern void bdk_bar_write(const bdk_device_t *device, int bar, int size, uint64_t offset, uint64_t value); 195 196 /** 197 * This macro makes it easy to define a variable of the correct 198 * type for a BAR. 199 */ 200 #define BDK_BAR_DEFINE(name, REG) typedef_##REG name 201 202 /** 203 * This macro makes it easy to define a variable and initialize it 204 * with a BAR. 205 */ 206 #define BDK_BAR_INIT(name, device, REG) typedef_##REG name = {.u = bdk_bar_read(device, device_bar_##REG, sizeof(typedef_##REG), REG)} 207 208 /** 209 * Macro to read a BAR 210 */ 211 #define BDK_BAR_READ(device, REG) bdk_bar_read(device, device_bar_##REG, sizeof(typedef_##REG), REG) 212 213 /** 214 * Macro to write a BAR 215 */ 216 #define BDK_BAR_WRITE(device, REG, value) bdk_bar_write(device, device_bar_##REG, sizeof(typedef_##REG), REG, value) 217 218 /** 219 * Macro to make a read, modify, and write sequence easy. The "code_block" 220 * should be replaced with a C code block or a comma separated list of 221 * "name.s.field = value", without the quotes. 222 */ 223 #define BDK_BAR_MODIFY(name, device, REG, code_block) do { \ 224 uint64_t _tmp_address = REG; \ 225 typedef_##REG name = {.u = bdk_bar_read(device, device_bar_##REG, sizeof(typedef_##REG), _tmp_address)}; \ 226 code_block; \ 227 bdk_bar_write(device, device_bar_##REG, sizeof(typedef_##REG), _tmp_address, name.u); \ 228 } while (0) 229 230 /** 231 * This macro spins on a field waiting for it to reach a value. It 232 * is common in code to need to wait for a specific field in a 233 * REG to match a specific value. Conceptually this macro 234 * expands to: 235 * 236 * 1) read REG 237 * 2) Check if ("type".s."field" "op" "value") 238 * 3) If #2 isn't true loop to #1 unless too much time has passed. 239 */ 240 #define BDK_BAR_WAIT_FOR_FIELD(device, REG, field, op, value, timeout_usec) \ 241 ({int result; \ 242 do { \ 243 uint64_t done = bdk_clock_get_count(BDK_CLOCK_TIME) + (uint64_t)timeout_usec * \ 244 bdk_clock_get_rate(bdk_numa_local(), BDK_CLOCK_TIME) / 1000000; \ 245 typedef_##REG c; \ 246 uint64_t _tmp_address = REG; \ 247 while (1) \ 248 { \ 249 c.u = bdk_bar_read(device, device_bar_##REG, sizeof(typedef_##REG), _tmp_address); \ 250 if ((c.s.field) op (value)) { \ 251 result = 0; \ 252 break; \ 253 } else if (bdk_clock_get_count(BDK_CLOCK_TIME) > done) { \ 254 result = -1; \ 255 break; \ 256 } \ 257 } \ 258 } while (0); \ 259 result;}) 260 261 /** @} */ 262 263 #endif /* !__CB_BDK_DEVICE_H__ */ 264