diff options
Diffstat (limited to 'drivers/net/enic/base')
-rw-r--r-- | drivers/net/enic/base/vnic_dev.c | 105 | ||||
-rw-r--r-- | drivers/net/enic/base/vnic_dev.h | 8 | ||||
-rw-r--r-- | drivers/net/enic/base/vnic_devcmd.h | 72 |
3 files changed, 176 insertions, 9 deletions
diff --git a/drivers/net/enic/base/vnic_dev.c b/drivers/net/enic/base/vnic_dev.c index 16e8814a..fd303fec 100644 --- a/drivers/net/enic/base/vnic_dev.c +++ b/drivers/net/enic/base/vnic_dev.c @@ -57,6 +57,9 @@ struct vnic_dev { void (*free_consistent)(void *priv, size_t size, void *vaddr, dma_addr_t dma_handle); + struct vnic_counter_counts *flow_counters; + dma_addr_t flow_counters_pa; + u8 flow_counters_dma_active; }; #define VNIC_MAX_RES_HDR_SIZE \ @@ -64,6 +67,8 @@ struct vnic_dev { sizeof(struct vnic_resource) * RES_TYPE_MAX) #define VNIC_RES_STRIDE 128 +#define VNIC_MAX_FLOW_COUNTERS 2048 + void *vnic_dev_priv(struct vnic_dev *vdev) { return vdev->priv; @@ -611,6 +616,35 @@ int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats) return vnic_dev_cmd(vdev, CMD_STATS_DUMP, &a0, &a1, wait); } +/* + * Configure counter DMA + */ +int vnic_dev_counter_dma_cfg(struct vnic_dev *vdev, u32 period, + u32 num_counters) +{ + u64 args[3]; + int wait = 1000; + int err; + + if (num_counters > VNIC_MAX_FLOW_COUNTERS) + return -ENOMEM; + if (period > 0 && (period < VNIC_COUNTER_DMA_MIN_PERIOD || + num_counters == 0)) + return -EINVAL; + + args[0] = num_counters; + args[1] = vdev->flow_counters_pa; + args[2] = period; + err = vnic_dev_cmd_args(vdev, CMD_COUNTER_DMA_CONFIG, args, 3, wait); + + /* record if DMAs need to be stopped on close */ + if (!err) + vdev->flow_counters_dma_active = (num_counters != 0 && + period != 0); + + return err; +} + int vnic_dev_close(struct vnic_dev *vdev) { u64 a0 = 0, a1 = 0; @@ -939,6 +973,24 @@ int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev) return vdev->stats == NULL ? -ENOMEM : 0; } +/* + * Initialize for up to VNIC_MAX_FLOW_COUNTERS + */ +int vnic_dev_alloc_counter_mem(struct vnic_dev *vdev) +{ + char name[NAME_MAX]; + static u32 instance; + + snprintf((char *)name, sizeof(name), "vnic_flow_ctrs-%u", instance++); + vdev->flow_counters = vdev->alloc_consistent(vdev->priv, + sizeof(struct vnic_counter_counts) + * VNIC_MAX_FLOW_COUNTERS, + &vdev->flow_counters_pa, + (u8 *)name); + vdev->flow_counters_dma_active = 0; + return vdev->flow_counters == NULL ? -ENOMEM : 0; +} + void vnic_dev_unregister(struct vnic_dev *vdev) { if (vdev) { @@ -951,6 +1003,16 @@ void vnic_dev_unregister(struct vnic_dev *vdev) vdev->free_consistent(vdev->priv, sizeof(struct vnic_stats), vdev->stats, vdev->stats_pa); + if (vdev->flow_counters) { + /* turn off counter DMAs before freeing memory */ + if (vdev->flow_counters_dma_active) + vnic_dev_counter_dma_cfg(vdev, 0, 0); + + vdev->free_consistent(vdev->priv, + sizeof(struct vnic_counter_counts) + * VNIC_MAX_FLOW_COUNTERS, + vdev->flow_counters, vdev->flow_counters_pa); + } if (vdev->fw_info) vdev->free_consistent(vdev->priv, sizeof(struct vnic_devcmd_fw_info), @@ -1094,3 +1156,46 @@ int vnic_dev_capable_vxlan(struct vnic_dev *vdev) (a1 & (FEATURE_VXLAN_IPV6 | FEATURE_VXLAN_MULTI_WQ)) == (FEATURE_VXLAN_IPV6 | FEATURE_VXLAN_MULTI_WQ); } + +bool vnic_dev_counter_alloc(struct vnic_dev *vdev, uint32_t *idx) +{ + u64 a0 = 0; + u64 a1 = 0; + int wait = 1000; + + if (vnic_dev_cmd(vdev, CMD_COUNTER_ALLOC, &a0, &a1, wait)) + return false; + *idx = (uint32_t)a0; + return true; +} + +bool vnic_dev_counter_free(struct vnic_dev *vdev, uint32_t idx) +{ + u64 a0 = idx; + u64 a1 = 0; + int wait = 1000; + + return vnic_dev_cmd(vdev, CMD_COUNTER_FREE, &a0, &a1, + wait) == 0; +} + +bool vnic_dev_counter_query(struct vnic_dev *vdev, uint32_t idx, + bool reset, uint64_t *packets, uint64_t *bytes) +{ + u64 a0 = idx; + u64 a1 = reset ? 1 : 0; + int wait = 1000; + + if (reset) { + /* query/reset returns updated counters */ + if (vnic_dev_cmd(vdev, CMD_COUNTER_QUERY, &a0, &a1, wait)) + return false; + *packets = a0; + *bytes = a1; + } else { + /* Get values DMA'd from the adapter */ + *packets = vdev->flow_counters[idx].vcc_packets; + *bytes = vdev->flow_counters[idx].vcc_bytes; + } + return true; +} diff --git a/drivers/net/enic/base/vnic_dev.h b/drivers/net/enic/base/vnic_dev.h index 270a47bd..de2645c4 100644 --- a/drivers/net/enic/base/vnic_dev.h +++ b/drivers/net/enic/base/vnic_dev.h @@ -118,6 +118,8 @@ int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, size_t size, void *value); int vnic_dev_stats_clear(struct vnic_dev *vdev); int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats); +int vnic_dev_counter_dma_cfg(struct vnic_dev *vdev, u32 period, + u32 num_counters); int vnic_dev_hang_notify(struct vnic_dev *vdev); int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, int broadcast, int promisc, int allmulti); @@ -170,6 +172,7 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, unsigned int num_bars); struct rte_pci_device *vnic_dev_get_pdev(struct vnic_dev *vdev); int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev); +int vnic_dev_alloc_counter_mem(struct vnic_dev *vdev); int vnic_dev_cmd_init(struct vnic_dev *vdev, int fallback); int vnic_dev_get_size(void); int vnic_dev_int13(struct vnic_dev *vdev, u64 arg, u32 op); @@ -187,4 +190,9 @@ int vnic_dev_overlay_offload_ctrl(struct vnic_dev *vdev, int vnic_dev_overlay_offload_cfg(struct vnic_dev *vdev, u8 overlay, u16 vxlan_udp_port_number); int vnic_dev_capable_vxlan(struct vnic_dev *vdev); +bool vnic_dev_counter_alloc(struct vnic_dev *vdev, uint32_t *idx); +bool vnic_dev_counter_free(struct vnic_dev *vdev, uint32_t idx); +bool vnic_dev_counter_query(struct vnic_dev *vdev, uint32_t idx, + bool reset, uint64_t *packets, uint64_t *bytes); + #endif /* _VNIC_DEV_H_ */ diff --git a/drivers/net/enic/base/vnic_devcmd.h b/drivers/net/enic/base/vnic_devcmd.h index a22d8a76..3aad2dbd 100644 --- a/drivers/net/enic/base/vnic_devcmd.h +++ b/drivers/net/enic/base/vnic_devcmd.h @@ -598,6 +598,48 @@ enum vnic_devcmd_cmd { * a3 = bitmask of supported actions */ CMD_ADD_ADV_FILTER = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ENET, 77), + + /* + * Allocate a counter for use with CMD_ADD_FILTER + * out:(u32) a0 = counter index + */ + CMD_COUNTER_ALLOC = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ENET, 85), + + /* + * Free a counter + * in: (u32) a0 = counter_id + */ + CMD_COUNTER_FREE = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 86), + + /* + * Read a counter + * in: (u32) a0 = counter_id + * (u32) a1 = clear counter if non-zero + * out:(u64) a0 = packet count + * (u64) a1 = byte count + */ + CMD_COUNTER_QUERY = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ENET, 87), + + /* + * Configure periodic counter DMA. This will trigger an immediate + * DMA of the counters (unless period == 0), and then schedule a DMA + * of the counters every <period> seconds until disdabled. + * Each new COUNTER_DMA_CONFIG will override all previous commands on + * this vnic. + * Setting a2 (period) = 0 will disable periodic DMAs + * If a0 (num_counters) != 0, an immediate DMA will always be done, + * irrespective of the value in a2. + * in: (u32) a0 = number of counters to DMA + * (u64) a1 = host target DMA address + * (u32) a2 = DMA period in milliseconds (0 to disable) + */ + CMD_COUNTER_DMA_CONFIG = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 88), +#define VNIC_COUNTER_DMA_MIN_PERIOD 500 + + /* + * Clear all counters on a vnic + */ + CMD_COUNTER_CLEAR_ALL = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ENET, 89), }; /* Modes for exchanging advanced filter capabilities. The modes supported by @@ -863,9 +905,11 @@ struct filter_action { #define FILTER_ACTION_RQ_STEERING_FLAG (1 << 0) #define FILTER_ACTION_FILTER_ID_FLAG (1 << 1) #define FILTER_ACTION_DROP_FLAG (1 << 2) +#define FILTER_ACTION_COUNTER_FLAG (1 << 3) #define FILTER_ACTION_V2_ALL (FILTER_ACTION_RQ_STEERING_FLAG \ + | FILTER_ACTION_FILTER_ID_FLAG \ | FILTER_ACTION_DROP_FLAG \ - | FILTER_ACTION_FILTER_ID_FLAG) + | FILTER_ACTION_COUNTER_FLAG) /* Version 2 of filter action must be a strict extension of struct filter_action * where the first fields exactly match in size and meaning. @@ -875,7 +919,8 @@ struct filter_action_v2 { u32 rq_idx; u32 flags; /* use FILTER_ACTION_XXX_FLAG defines */ u16 filter_id; - u_int8_t reserved[32]; /* for future expansion */ + u32 counter_index; + uint8_t reserved[28]; /* for future expansion */ } __attribute__((packed)); /* Specifies the filter type. */ @@ -941,9 +986,9 @@ enum { }; struct filter_tlv { - u_int32_t type; - u_int32_t length; - u_int32_t val[0]; + uint32_t type; + uint32_t length; + uint32_t val[0]; }; /* Data for CMD_ADD_FILTER is 2 TLV and filter + action structs */ @@ -957,10 +1002,10 @@ struct filter_tlv { * drivers should use this instead of "sizeof (struct filter_v2)" when * computing length for TLV. */ -static inline u_int32_t +static inline uint32_t vnic_filter_size(struct filter_v2 *fp) { - u_int32_t size; + uint32_t size; switch (fp->type) { case FILTER_USNIC_ID: @@ -999,10 +1044,10 @@ enum { * drivers should use this instead of "sizeof (struct filter_action_v2)" * when computing length for TLV. */ -static inline u_int32_t +static inline uint32_t vnic_action_size(struct filter_action_v2 *fap) { - u_int32_t size; + uint32_t size; switch (fap->type) { case FILTER_ACTION_RQ_STEERING: @@ -1122,4 +1167,13 @@ typedef enum { GRPINTR_UPD_VECT, } grpintr_subcmd_t; +/* + * Structure for counter DMA + * (DMAed by CMD_COUNTER_DMA_CONFIG) + */ +struct vnic_counter_counts { + u64 vcc_packets; + u64 vcc_bytes; +}; + #endif /* _VNIC_DEVCMD_H_ */ |