blob: 3308859733a7b0fee4daf9787579a5e041037471 [file] [log] [blame]
#ifndef __CB_BDK_DEVICE_H__
#define __CB_BDK_DEVICE_H__
/***********************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; \
} \
} \
} while (0); \
result;})
/** @} */
#endif /* !__CB_BDK_DEVICE_H__ */