* Re: [PATCH v6 net-next 04/19] ionic: Add port management commands
From: Jakub Kicinski @ 2019-08-29 22:46 UTC (permalink / raw)
To: Shannon Nelson; +Cc: netdev, davem
In-Reply-To: <20190829182720.68419-5-snelson@pensando.io>
On Thu, 29 Aug 2019 11:27:05 -0700, Shannon Nelson wrote:
> The port management commands apply to the physical port
> associated with the PCI device, which might be shared among
> several logical interfaces.
>
> Signed-off-by: Shannon Nelson <snelson@pensando.io>
> ---
> drivers/net/ethernet/pensando/ionic/ionic.h | 4 +
> .../ethernet/pensando/ionic/ionic_bus_pci.c | 16 ++++
> .../net/ethernet/pensando/ionic/ionic_dev.c | 92 +++++++++++++++++++
> .../net/ethernet/pensando/ionic/ionic_dev.h | 13 +++
> .../net/ethernet/pensando/ionic/ionic_main.c | 86 +++++++++++++++++
> 5 files changed, 211 insertions(+)
>
> diff --git a/drivers/net/ethernet/pensando/ionic/ionic.h b/drivers/net/ethernet/pensando/ionic/ionic.h
> index 89ad9c590736..4960effd2bcc 100644
> --- a/drivers/net/ethernet/pensando/ionic/ionic.h
> +++ b/drivers/net/ethernet/pensando/ionic/ionic.h
> @@ -42,4 +42,8 @@ int ionic_identify(struct ionic *ionic);
> int ionic_init(struct ionic *ionic);
> int ionic_reset(struct ionic *ionic);
>
> +int ionic_port_identify(struct ionic *ionic);
> +int ionic_port_init(struct ionic *ionic);
> +int ionic_port_reset(struct ionic *ionic);
> +
> #endif /* _IONIC_H_ */
> diff --git a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
> index 286b4b450a73..804dd43e92a6 100644
> --- a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
> +++ b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
> @@ -138,12 +138,27 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
> goto err_out_teardown;
> }
>
> + /* Configure the ports */
> + err = ionic_port_identify(ionic);
> + if (err) {
> + dev_err(dev, "Cannot identify port: %d, aborting\n", err);
> + goto err_out_reset;
> + }
> +
> + err = ionic_port_init(ionic);
> + if (err) {
> + dev_err(dev, "Cannot init port: %d, aborting\n", err);
> + goto err_out_reset;
> + }
> +
> err = ionic_devlink_register(ionic);
> if (err)
> dev_err(dev, "Cannot register devlink: %d\n", err);
>
> return 0;
>
> +err_out_reset:
> + ionic_reset(ionic);
> err_out_teardown:
> ionic_dev_teardown(ionic);
> err_out_unmap_bars:
> @@ -170,6 +185,7 @@ static void ionic_remove(struct pci_dev *pdev)
> return;
>
> ionic_devlink_unregister(ionic);
> + ionic_port_reset(ionic);
> ionic_reset(ionic);
> ionic_dev_teardown(ionic);
> ionic_unmap_bars(ionic);
> diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c
> index 0bf1bd6bd7b1..3137776e9191 100644
> --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c
> +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c
> @@ -134,3 +134,95 @@ void ionic_dev_cmd_reset(struct ionic_dev *idev)
>
> ionic_dev_cmd_go(idev, &cmd);
> }
> +
> +/* Port commands */
> +void ionic_dev_cmd_port_identify(struct ionic_dev *idev)
> +{
> + union ionic_dev_cmd cmd = {
> + .port_init.opcode = IONIC_CMD_PORT_IDENTIFY,
> + .port_init.index = 0,
> + };
> +
> + ionic_dev_cmd_go(idev, &cmd);
> +}
> +
> +void ionic_dev_cmd_port_init(struct ionic_dev *idev)
> +{
> + union ionic_dev_cmd cmd = {
> + .port_init.opcode = IONIC_CMD_PORT_INIT,
> + .port_init.index = 0,
> + .port_init.info_pa = cpu_to_le64(idev->port_info_pa),
> + };
> +
> + ionic_dev_cmd_go(idev, &cmd);
> +}
> +
> +void ionic_dev_cmd_port_reset(struct ionic_dev *idev)
> +{
> + union ionic_dev_cmd cmd = {
> + .port_reset.opcode = IONIC_CMD_PORT_RESET,
> + .port_reset.index = 0,
> + };
> +
> + ionic_dev_cmd_go(idev, &cmd);
> +}
> +
> +void ionic_dev_cmd_port_state(struct ionic_dev *idev, u8 state)
> +{
> + union ionic_dev_cmd cmd = {
> + .port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
> + .port_setattr.index = 0,
> + .port_setattr.attr = IONIC_PORT_ATTR_STATE,
> + .port_setattr.state = state,
> + };
> +
> + ionic_dev_cmd_go(idev, &cmd);
> +}
> +
> +void ionic_dev_cmd_port_speed(struct ionic_dev *idev, u32 speed)
> +{
> + union ionic_dev_cmd cmd = {
> + .port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
> + .port_setattr.index = 0,
> + .port_setattr.attr = IONIC_PORT_ATTR_SPEED,
> + .port_setattr.speed = cpu_to_le32(speed),
> + };
> +
> + ionic_dev_cmd_go(idev, &cmd);
> +}
> +
> +void ionic_dev_cmd_port_autoneg(struct ionic_dev *idev, u8 an_enable)
> +{
> + union ionic_dev_cmd cmd = {
> + .port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
> + .port_setattr.index = 0,
> + .port_setattr.attr = IONIC_PORT_ATTR_AUTONEG,
> + .port_setattr.an_enable = an_enable,
> + };
> +
> + ionic_dev_cmd_go(idev, &cmd);
> +}
> +
> +void ionic_dev_cmd_port_fec(struct ionic_dev *idev, u8 fec_type)
> +{
> + union ionic_dev_cmd cmd = {
> + .port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
> + .port_setattr.index = 0,
> + .port_setattr.attr = IONIC_PORT_ATTR_FEC,
> + .port_setattr.fec_type = fec_type,
> + };
> +
> + ionic_dev_cmd_go(idev, &cmd);
> +}
> +
> +void ionic_dev_cmd_port_pause(struct ionic_dev *idev, u8 pause_type)
> +{
> + union ionic_dev_cmd cmd = {
> + .port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
> + .port_setattr.index = 0,
> + .port_setattr.attr = IONIC_PORT_ATTR_PAUSE,
> + .port_setattr.pause_type = pause_type,
> + };
> +
> + ionic_dev_cmd_go(idev, &cmd);
> +}
Hm. So you haven't moved those?
> diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h
> index 7050545a83aa..81b6910aabc1 100644
> --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h
> +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h
> @@ -117,6 +117,10 @@ struct ionic_dev {
> struct ionic_intr __iomem *intr_ctrl;
> u64 __iomem *intr_status;
>
> + u32 port_info_sz;
> + struct ionic_port_info *port_info;
> + dma_addr_t port_info_pa;
> +
> struct ionic_devinfo dev_info;
> };
>
> @@ -135,4 +139,13 @@ void ionic_dev_cmd_identify(struct ionic_dev *idev, u8 ver);
> void ionic_dev_cmd_init(struct ionic_dev *idev);
> void ionic_dev_cmd_reset(struct ionic_dev *idev);
>
> +void ionic_dev_cmd_port_identify(struct ionic_dev *idev);
> +void ionic_dev_cmd_port_init(struct ionic_dev *idev);
> +void ionic_dev_cmd_port_reset(struct ionic_dev *idev);
> +void ionic_dev_cmd_port_state(struct ionic_dev *idev, u8 state);
> +void ionic_dev_cmd_port_speed(struct ionic_dev *idev, u32 speed);
> +void ionic_dev_cmd_port_autoneg(struct ionic_dev *idev, u8 an_enable);
> +void ionic_dev_cmd_port_fec(struct ionic_dev *idev, u8 fec_type);
> +void ionic_dev_cmd_port_pause(struct ionic_dev *idev, u8 pause_type);
> +
> #endif /* _IONIC_DEV_H_ */
> diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c
> index 5c311b9241ee..96de2789587d 100644
> --- a/drivers/net/ethernet/pensando/ionic/ionic_main.c
> +++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c
> @@ -317,6 +317,92 @@ int ionic_reset(struct ionic *ionic)
> return err;
> }
>
> +int ionic_port_identify(struct ionic *ionic)
> +{
> + struct ionic_identity *ident = &ionic->ident;
> + struct ionic_dev *idev = &ionic->idev;
> + size_t sz;
> + int err;
> +
> + mutex_lock(&ionic->dev_cmd_lock);
> +
> + ionic_dev_cmd_port_identify(idev);
> + err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
> + if (!err) {
> + sz = min(sizeof(ident->port), sizeof(idev->dev_cmd_regs->data));
> + memcpy_fromio(&ident->port, &idev->dev_cmd_regs->data, sz);
> + }
> +
> + mutex_unlock(&ionic->dev_cmd_lock);
> +
> + return err;
> +}
> +
> +int ionic_port_init(struct ionic *ionic)
> +{
> + struct ionic_identity *ident = &ionic->ident;
> + struct ionic_dev *idev = &ionic->idev;
> + size_t sz;
> + int err;
> +
> + if (idev->port_info)
> + return 0;
> +
> + idev->port_info_sz = ALIGN(sizeof(*idev->port_info), PAGE_SIZE);
> + idev->port_info = dma_alloc_coherent(ionic->dev, idev->port_info_sz,
> + &idev->port_info_pa,
> + GFP_KERNEL);
> + if (!idev->port_info) {
> + dev_err(ionic->dev, "Failed to allocate port info, aborting\n");
> + return -ENOMEM;
> + }
> +
> + sz = min(sizeof(ident->port.config), sizeof(idev->dev_cmd_regs->data));
> +
> + mutex_lock(&ionic->dev_cmd_lock);
> +
> + memcpy_toio(&idev->dev_cmd_regs->data, &ident->port.config, sz);
> + ionic_dev_cmd_port_init(idev);
> + err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
> +
> + ionic_dev_cmd_port_state(&ionic->idev, IONIC_PORT_ADMIN_STATE_UP);
> + (void)ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
> +
> + mutex_unlock(&ionic->dev_cmd_lock);
> + if (err) {
> + dev_err(ionic->dev, "Failed to init port\n");
> + dma_free_coherent(ionic->dev, idev->port_info_sz,
> + idev->port_info, idev->port_info_pa);
idev->port_info = NULL;
> + }
> +
> + return err;
> +}
> +
> +int ionic_port_reset(struct ionic *ionic)
> +{
> + struct ionic_dev *idev = &ionic->idev;
> + int err;
> +
> + if (!idev->port_info)
> + return 0;
> +
> + mutex_lock(&ionic->dev_cmd_lock);
> + ionic_dev_cmd_port_reset(idev);
> + err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
> + mutex_unlock(&ionic->dev_cmd_lock);
> +
> + dma_free_coherent(ionic->dev, idev->port_info_sz,
> + idev->port_info, idev->port_info_pa);
> +
> + idev->port_info = NULL;
> + idev->port_info_pa = 0;
> +
> + if (err)
> + dev_err(ionic->dev, "Failed to reset port\n");
> +
> + return err;
> +}
> +
> static int __init ionic_init_module(void)
> {
> pr_info("%s %s, ver %s\n",
^ permalink raw reply
* Re: [PATCH v6 net-next 07/19] ionic: Add basic adminq support
From: Jakub Kicinski @ 2019-08-29 22:52 UTC (permalink / raw)
To: Shannon Nelson; +Cc: netdev, davem
In-Reply-To: <20190829182720.68419-8-snelson@pensando.io>
On Thu, 29 Aug 2019 11:27:08 -0700, Shannon Nelson wrote:
> +static void ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq)
> +{
> + struct ionic_dev *idev = &lif->ionic->idev;
> + struct device *dev = lif->ionic->dev;
> +
> + if (!qcq)
> + return;
> +
> + ionic_debugfs_del_qcq(qcq);
> +
> + if (!(qcq->flags & IONIC_QCQ_F_INITED))
> + return;
> +
> + if (qcq->flags & IONIC_QCQ_F_INTR) {
> + ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
> + IONIC_INTR_MASK_SET);
> + synchronize_irq(qcq->intr.vector);
> + devm_free_irq(dev, qcq->intr.vector, &qcq->napi);
Doesn't free_irq() basically imply synchronize_irq()?
> + netif_napi_del(&qcq->napi);
> + }
> +
> + qcq->flags &= ~IONIC_QCQ_F_INITED;
^ permalink raw reply
* Re: [PATCH bpf-next 05/13] bpf: adding map batch processing support
From: Brian Vazquez @ 2019-08-29 23:01 UTC (permalink / raw)
To: Yonghong Song
Cc: bpf, netdev, Alexei Starovoitov, Daniel Borkmann, kernel-team
In-Reply-To: <20190829064507.2750795-1-yhs@fb.com>
Hi Yonghong!
Thanks for sending this series of patches and starting the discussion.
On Wed, Aug 28, 2019 at 11:45 PM Yonghong Song <yhs@fb.com> wrote:
>
> Brian Vazquez has proposed BPF_MAP_DUMP command to look up more than one
> map entries per syscall.
> https://lore.kernel.org/bpf/CABCgpaU3xxX6CMMxD+1knApivtc2jLBHysDXw-0E9bQEL0qC3A@mail.gmail.com/T/#t
>
> During discussion, we found more use cases can be supported in a similar
> map operation batching framework. For example, batched map lookup and delete,
> which can be really helpful for bcc.
> https://github.com/iovisor/bcc/blob/master/tools/tcptop.py#L233-L243
> https://github.com/iovisor/bcc/blob/master/tools/slabratetop.py#L129-L138
>
> Also, in bcc, we have API to delete all entries in a map.
> https://github.com/iovisor/bcc/blob/master/src/cc/api/BPFTable.h#L257-L264
>
> For map update, batched operations also useful as sometimes applications need
> to populate initial maps with more than one entry. For example, the below
> example is from kernel/samples/bpf/xdp_redirect_cpu_user.c:
> https://github.com/torvalds/linux/blob/master/samples/bpf/xdp_redirect_cpu_user.c#L543-L550
>
> This patch addresses all the above use cases. To make uapi stable, it also
> covers other potential use cases. Four bpf syscall subcommands are introduced:
> BPF_MAP_LOOKUP_BATCH
> BPF_MAP_LOOKUP_AND_DELETE_BATCH
> BPF_MAP_UPDATE_BATCH
> BPF_MAP_DELETE_BATCH
>
> The UAPI attribute structure looks like:
> struct { /* struct used by BPF_MAP_*_BATCH commands */
> __aligned_u64 start_key; /* input: storing start key,
> * if NULL, starting from the beginning.
> */
> __aligned_u64 next_start_key; /* output: storing next batch start_key,
> * if NULL, no next key.
> */
> __aligned_u64 keys; /* input/output: key buffer */
> __aligned_u64 values; /* input/output: value buffer */
> __u32 count; /* input: # of keys/values in
> * or fits in keys[]/values[].
> * output: how many successful
> * lookup/lookup_and_delete
> * /delete/update operations.
> */
> __u32 map_fd;
> __u64 elem_flags; /* BPF_MAP_{UPDATE,LOOKUP}_ELEM flags */
> __u64 flags; /* flags for batch operation */
> } batch;
>
> The 'start_key' and 'next_start_key' are used to BPF_MAP_LOOKUP_BATCH,
> BPF_MAP_LOOKUP_AND_DELETE_BATCH and BPF_MAP_DELETE_BATCH
> to start the operation on 'start_key' and also set the
> next batch start key in 'next_start_key'.
>
> If 'count' is greater than 0 and the return code is 0,
> . the 'count' may be updated to be smaller if there is less
> elements than 'count' for the operation. In such cases,
> 'next_start_key' will be set to NULL.
> . the 'count' remains the same. 'next_start_key' could be NULL
> or could point to next start_key for batch processing.
>
> If 'count' is greater than 0 and the return code is an error
> other than -EFAULT, the kernel will try to overwrite 'count'
> to contain the number of successful element-level (lookup,
> lookup_and_delete, update and delete) operations. The following
> attributes can be checked:
> . if 'count' value is modified, the new value will be
> the number of successful element-level operations.
> . if 'count' value is modified, the keys[]/values[] will
> contain correct results for new 'count' number of
> operations for lookup[_and_delete] and update.
>
> The implementation in this patch mimics what user space
> did, e.g., for lookup_and_delete,
> while(bpf_get_next_key(map, keyp, next_keyp) == 0) {
> bpf_map_delete_elem(map, keyp);
> bpf_map_lookup_elem(map, next_keyp, &value, flags);
> keyp, next_keyp = next_keyp, keyp;
> }
> The similar loop is implemented in the kernel, and
> each operation, bpf_get_next_key(), bpf_map_delete_elem()
> and bpf_map_lookup_elem(), uses existing kernel functions
> each of which has its own rcu_read_lock region, bpf_prog_active
> protection, etc.
> Therefore, it is totally possible that after bpf_get_next_key(),
> the bpf_map_delete_elem() or bpf_map_lookup_elem() may fail
> as the key may be deleted concurrently by kernel or
> other user space processes/threads.
> By default, the current implementation permits the loop
> to continue, just like typical user space handling. But
> a flag, BPF_F_ENFORCE_ENOENT, can be specified, so kernel
> will return an error if bpf_map_delete_elem() or
> bpf_map_lookup_elem() failed.
>
> The high-level algorithm for BPF_MAP_LOOKUP_BATCH and
> BPF_MAP_LOOKUP_AND_DELETE_BATCH:
> if (start_key == NULL and next_start_key == NULL) {
> lookup up to 'count' keys in keys[] and fill
> corresponding values[], and delete those
> keys if BPF_MAP_LOOKUP_AND_DELETE_BATCH.
> } else if (start_key == NULL && next_start_key != NULL) {
> lookup up to 'count' keys from the beginning
> of the map and fill keys[]/values[], delete
> those keys if BPF_MAP_LOOKUP_AND_DELETE_BATCH.
> Set 'next_start_key' for next batch operation.
> } else if (start_key != NULL && next_start_key != NULL) {
> lookup to 'count' keys from 'start_key', inclusive,
> and fill keys[]/values[], delete those keys if
> BPF_MAP_LOOKUP_AND_DELETE_BATCH.
> Set 'next_start_key' for next batch operation.
> }
>
> The high-level algorithm for BPF_MAP_UPDATE_BATCH:
> if (count != 0) {
> do 'count' number of updates on keys[]/values[].
> }
>
> The high-level algorithm for BPF_MAP_DELETE_BATCH:
> if (count == 0) {
> if (start_key == NULL) {
> delete all elements from map.
> } else {
> delete all elements from start_key to the end of map.
> }
> } else {
> if (start_key == NULL and next_start_key == NULL) {
> delete 'count' number of keys in keys[].
> } else if (start_key == NULL and next_start_key != NULL) {
> delete 'count' number of keys from the
> beginning of the map and set 'next_start_key'
> properly.
> } else if (start_key != NULL and next_start_keeey != NULL) {
> delete 'count' number of keys from 'start_key',
> and set 'next_start_key' properly.
> }
> }
>
> Signed-off-by: Yonghong Song <yhs@fb.com>
> ---
> include/uapi/linux/bpf.h | 27 +++
> kernel/bpf/syscall.c | 448 +++++++++++++++++++++++++++++++++++++++
> 2 files changed, 475 insertions(+)
>
> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> index 5d2fb183ee2d..576688f13e8c 100644
> --- a/include/uapi/linux/bpf.h
> +++ b/include/uapi/linux/bpf.h
> @@ -107,6 +107,10 @@ enum bpf_cmd {
> BPF_MAP_LOOKUP_AND_DELETE_ELEM,
> BPF_MAP_FREEZE,
> BPF_BTF_GET_NEXT_ID,
> + BPF_MAP_LOOKUP_BATCH,
> + BPF_MAP_LOOKUP_AND_DELETE_BATCH,
> + BPF_MAP_UPDATE_BATCH,
> + BPF_MAP_DELETE_BATCH,
> };
>
> enum bpf_map_type {
> @@ -347,6 +351,9 @@ enum bpf_attach_type {
> /* flags for BPF_PROG_QUERY */
> #define BPF_F_QUERY_EFFECTIVE (1U << 0)
>
> +/* flags for BPF_MAP_*_BATCH */
> +#define BPF_F_ENFORCE_ENOENT (1U << 0)
> +
> enum bpf_stack_build_id_status {
> /* user space need an empty entry to identify end of a trace */
> BPF_STACK_BUILD_ID_EMPTY = 0,
> @@ -396,6 +403,26 @@ union bpf_attr {
> __u64 flags;
> };
>
> + struct { /* struct used by BPF_MAP_*_BATCH commands */
> + __aligned_u64 start_key; /* input: storing start key,
> + * if NULL, starting from the beginning.
> + */
> + __aligned_u64 next_start_key; /* output: storing next batch start_key,
> + * if NULL, no next key.
> + */
> + __aligned_u64 keys; /* input/output: key buffer */
> + __aligned_u64 values; /* input/output: value buffer */
> + __u32 count; /* input: # of keys/values in
> + * or fits in keys[]/values[].
> + * output: how many successful
> + * lookup/lookup_and_delete
> + * update/delete operations.
> + */
> + __u32 map_fd;
> + __u64 elem_flags; /* BPF_MAP_*_ELEM flags */
> + __u64 flags; /* flags for batch operation */
> + } batch;
> +
> struct { /* anonymous struct used by BPF_PROG_LOAD command */
> __u32 prog_type; /* one of enum bpf_prog_type */
> __u32 insn_cnt;
> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index 06308f0206e5..8746b55405f9 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c
> @@ -33,6 +33,17 @@
>
> #define BPF_OBJ_FLAG_MASK (BPF_F_RDONLY | BPF_F_WRONLY)
>
> +#define BPF_MAP_BATCH_SWAP_KEYS(key1, key2, buf1, buf2) \
> + do { \
> + if (key1 == (buf1)) { \
> + key1 = buf2; \
> + key2 = buf1; \
> + } else { \
> + key1 = buf1; \
> + key2 = buf2; \
> + } \
> + } while (0) \
> +
> DEFINE_PER_CPU(int, bpf_prog_active);
> static DEFINE_IDR(prog_idr);
> static DEFINE_SPINLOCK(prog_idr_lock);
> @@ -1183,6 +1194,431 @@ static int map_lookup_and_delete_elem(union bpf_attr *attr)
> return err;
> }
>
> +static void __map_batch_get_attrs(const union bpf_attr *attr,
> + void __user **skey, void __user **nskey,
> + void __user **keys, void __user **values,
> + u32 *max_count, u64 *elem_flags, u64 *flags)
> +{
> + *skey = u64_to_user_ptr(attr->batch.start_key);
> + *nskey = u64_to_user_ptr(attr->batch.next_start_key);
> + *keys = u64_to_user_ptr(attr->batch.keys);
> + *values = u64_to_user_ptr(attr->batch.values);
> + *max_count = attr->batch.count;
> + *elem_flags = attr->batch.elem_flags;
> + *flags = attr->batch.flags;
> +}
> +
> +static int
> +__map_lookup_delete_batch_key_in_keys(struct bpf_map *map, void *key, void *value,
> + u32 max_count, u32 key_size, u32 value_size,
> + u64 elem_flags, void __user *keys,
> + void __user *values,
> + union bpf_attr __user *uattr,
> + bool ignore_enoent)
> +{
> + u32 count, missed = 0;
> + int ret = 0, err;
> +
> + for (count = 0; count < max_count; count++) {
> + if (copy_from_user(key, keys + count * key_size, key_size)) {
> + ret = -EFAULT;
> + break;
> + }
> +
> + ret = bpf_map_copy_value(map, key, value, elem_flags);
> + if (ret) {
> + if (ret != -ENOENT || !ignore_enoent)
> + break;
> +
> + missed++;
> + continue;
> + }
> +
> +
> + if (copy_to_user(values + count * value_size, value, value_size)) {
> + ret = -EFAULT;
> + break;
> + }
> +
> + ret = bpf_map_delete_elem(map, key);
> + if (ret) {
> + if (ret != -ENOENT || !ignore_enoent)
> + break;
> +
> + missed++;
> + }
> + }
> +
> + count -= missed;
> + if ((!ret && missed) || (ret && ret != -EFAULT)) {
> + err = put_user(count, &uattr->batch.count);
> + ret = err ? : ret;
> + }
> +
> + return ret;
> +}
> +
> +static int map_lookup_and_delete_batch(struct bpf_map *map,
> + const union bpf_attr *attr,
> + union bpf_attr __user *uattr,
> + bool do_delete)
> +{
> + u32 max_count, count = 0, key_size, roundup_key_size, value_size;
> + bool ignore_enoent, nextkey_is_null, copied;
> + void *buf = NULL, *key, *value, *next_key;
> + void __user *skey, *nskey, *keys, *values;
> + u64 elem_flags, flags, zero = 0;
> + int err, ret = 0;
> +
> + if (map->map_type == BPF_MAP_TYPE_QUEUE ||
> + map->map_type == BPF_MAP_TYPE_STACK)
> + return -ENOTSUPP;
> +
> + __map_batch_get_attrs(attr, &skey, &nskey, &keys, &values, &max_count,
> + &elem_flags, &flags);
> +
> + if (elem_flags & ~BPF_F_LOCK || flags & ~BPF_F_ENFORCE_ENOENT)
> + return -EINVAL;
> +
> + if (!max_count)
> + return 0;
> +
> + /* The following max_count/skey/nskey combinations are supported:
> + * max_count != 0 && !skey && !nskey: loop/delete max_count elements in keys[]/values[].
> + * max_count != 0 && !skey && nskey: loop/delete max_count elements starting from map start.
> + * max_count != 0 && skey && nskey: loop/delete max_count elements starting from skey.
> + */
> + if (skey && !nskey)
> + return -EINVAL;
> +
> + /* allocate space for two keys and one value. */
> + key_size = map->key_size;
> + roundup_key_size = round_up(map->key_size, 8);
> + value_size = bpf_map_value_size(map);
> + buf = kmalloc(roundup_key_size * 2 + value_size, GFP_USER | __GFP_NOWARN);
> + if (!buf)
> + return -ENOMEM;
> +
> + key = buf;
> + next_key = buf + roundup_key_size;
> + value = buf + roundup_key_size * 2;
> + ignore_enoent = !(flags & BPF_F_ENFORCE_ENOENT);
> +
> + if (!skey && !nskey) {
> + /* handle cases where keys in keys[] */
> + ret = __map_lookup_delete_batch_key_in_keys(map, key, value, max_count,
> + key_size, value_size,
> + elem_flags, keys, values,
> + uattr, ignore_enoent);
> + goto out;
> + }
> +
> + /* Get the first key. */
> + if (!skey) {
> + ret = bpf_map_get_next_key(map, NULL, key);
> + if (ret) {
> + nextkey_is_null = true;
> + goto after_loop;
> + }
> + } else if (copy_from_user(key, skey, key_size)) {
> + ret = -EFAULT;
> + goto out;
> + }
> +
> + /* Copy the first key/value pair */
> + ret = bpf_map_copy_value(map, key, value, elem_flags);
> + if (ret) {
> + if (skey)
> + goto out;
> +
> + nextkey_is_null = true;
> + goto after_loop;
> + }
> +
> + if (copy_to_user(keys, key, key_size) ||
> + copy_to_user(values, value, value_size)) {
> + ret = -EFAULT;
> + goto out;
> + }
> +
> + /* We will always try to get next_key first
> + * and then delete the current key.
> + */
> + ret = bpf_map_get_next_key(map, key, next_key);
One of the issues I see in this implementation is that is still
relying on the existing functions and has the same consistency
problems that my attempt had.
The problem happens when you are trying to do batch lookup on a
hashmap and when executing bpf_map_get_next_key(map, key, next_key)
the key is removed, then that call will return the first key and you'd
start iterating the map from the beginning again and retrieve
duplicate information.
Note that sometimes you can also start from the same bucket when the
key is updated while dumping it because it can be inserted on the head
of the bucket so you could potentially revisit elements that you had
already visited.
From previous discussion my understanding was that what we wanted was
to pursue 'atomic' compounded operations first and after that, try to
batch them. Although I don't think there's an easy way of batching and
being consistent at the same time.
^ permalink raw reply
* Re: linux-next: Tree for Aug 29 (mlx5)
From: Saeed Mahameed @ 2019-08-29 23:04 UTC (permalink / raw)
To: sfr@canb.auug.org.au, Eran Ben Elisha, linux-next@vger.kernel.org,
rdunlap@infradead.org, haiyangz
Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
Leon Romanovsky
In-Reply-To: <DM6PR21MB13379A89D3A57DCFD6E0D419CAA20@DM6PR21MB1337.namprd21.prod.outlook.com>
On Thu, 2019-08-29 at 21:48 +0000, Haiyang Zhang wrote:
> > -----Original Message-----
> > From: Saeed Mahameed <saeedm@mellanox.com>
> > Sent: Thursday, August 29, 2019 2:32 PM
> > To: sfr@canb.auug.org.au; Eran Ben Elisha <eranbe@mellanox.com>;
> > linux-
> > next@vger.kernel.org; rdunlap@infradead.org; Haiyang Zhang
> > <haiyangz@microsoft.com>
> > Cc: linux-kernel@vger.kernel.org; netdev@vger.kernel.org; Leon
> > Romanovsky <leonro@mellanox.com>
> > Subject: Re: linux-next: Tree for Aug 29 (mlx5)
> >
> > On Thu, 2019-08-29 at 12:55 -0700, Randy Dunlap wrote:
> > > On 8/29/19 12:54 PM, Randy Dunlap wrote:
> > > > On 8/29/19 4:08 AM, Stephen Rothwell wrote:
> > > > > Hi all,
> > > > >
> > > > > Changes since 20190828:
> > > > >
> > > >
> > > > on x86_64:
> > > > when CONFIG_PCI_HYPERV=m
> > >
> > > and CONFIG_PCI_HYPERV_INTERFACE=m
> > >
> >
> > Haiyang and Eran, I think CONFIG_PCI_HYPERV_INTERFACE was never
> > supposed to be a module ? it supposed to provide an always
> > available
> > interface to drivers ..
> >
> > Anyway, maybe we need to imply CONFIG_PCI_HYPERV_INTERFACE in mlx5.
>
> The symbolic dependency by driver mlx5e, automatically triggers
> loading of
> pci_hyperv_interface module. And this module can be loaded in any
> platforms.
>
This only works when both are modules.
> Currently, mlx5e driver has #if
> IS_ENABLED(CONFIG_PCI_HYPERV_INTERFACE)
> around the code using the interface.
>
> I agree --
> Adding "select PCI_HYPERV_INTERFACE" for mlx5e will clean up these
> #if's.
>
No, not "select", "imply".
if one wants PCI_HYPERV_INTERFACE off, imply will keep it off for you.
> Thanks,
> - Haiyang
^ permalink raw reply
* Re: [PATCH v6 net-next 12/19] ionic: Add Rx filter and rx_mode ndo support
From: Jakub Kicinski @ 2019-08-29 23:06 UTC (permalink / raw)
To: Shannon Nelson; +Cc: netdev, davem
In-Reply-To: <20190829182720.68419-13-snelson@pensando.io>
On Thu, 29 Aug 2019 11:27:13 -0700, Shannon Nelson wrote:
> @@ -588,8 +866,26 @@ static int ionic_set_features(struct net_device *netdev,
>
> static int ionic_set_mac_address(struct net_device *netdev, void *sa)
> {
> - netdev_info(netdev, "%s: stubbed\n", __func__);
> - return 0;
> + struct sockaddr *addr = sa;
> + u8 *mac;
> +
> + mac = (u8 *)addr->sa_data;
> + if (ether_addr_equal(netdev->dev_addr, mac))
> + return 0;
> +
> + if (!is_valid_ether_addr(mac))
> + return -EADDRNOTAVAIL;
> +
> + if (!is_zero_ether_addr(netdev->dev_addr)) {
> + netdev_info(netdev, "deleting mac addr %pM\n",
> + netdev->dev_addr);
> + ionic_addr_del(netdev, netdev->dev_addr);
> + }
> +
> + memcpy(netdev->dev_addr, mac, netdev->addr_len);
> + netdev_info(netdev, "updating mac addr %pM\n", mac);
> +
> + return ionic_addr_add(netdev, mac);
> }
Please use the eth_prepare_mac_addr_change() and
eth_commit_mac_addr_change() helpers.
^ permalink raw reply
* Re: [PATCH v6 net-next 14/19] ionic: Add initial ethtool support
From: Jakub Kicinski @ 2019-08-29 23:10 UTC (permalink / raw)
To: Shannon Nelson; +Cc: netdev, davem
In-Reply-To: <20190829182720.68419-15-snelson@pensando.io>
On Thu, 29 Aug 2019 11:27:15 -0700, Shannon Nelson wrote:
> +static int ionic_get_module_eeprom(struct net_device *netdev,
> + struct ethtool_eeprom *ee,
> + u8 *data)
> +{
> + struct ionic_lif *lif = netdev_priv(netdev);
> + struct ionic_dev *idev = &lif->ionic->idev;
> + struct ionic_xcvr_status *xcvr;
> + char tbuf[sizeof(xcvr->sprom)];
> + int count = 10;
> + u32 len;
> +
> + /* The NIC keeps the module prom up-to-date in the DMA space
> + * so we can simply copy the module bytes into the data buffer.
> + */
> + xcvr = &idev->port_info->status.xcvr;
> + len = min_t(u32, sizeof(xcvr->sprom), ee->len);
> +
> + do {
> + memcpy(data, xcvr->sprom, len);
> + memcpy(tbuf, xcvr->sprom, len);
> +
> + /* Let's make sure we got a consistent copy */
> + if (!memcmp(data, tbuf, len))
> + break;
> +
> + } while (--count);
Should this return an error if the image was never consistent?
> +
> + return 0;
> +}
^ permalink raw reply
* Re: [PATCH bpf-next 00/13] bpf: adding map batch processing support
From: Brian Vazquez @ 2019-08-29 23:13 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Yonghong Song, Alexei Starovoitov, bpf, netdev, Daniel Borkmann,
kernel-team
In-Reply-To: <20190829113932.5c058194@cakuba.netronome.com>
On Thu, Aug 29, 2019 at 11:40 AM Jakub Kicinski
<jakub.kicinski@netronome.com> wrote:
>
> On Wed, 28 Aug 2019 23:45:02 -0700, Yonghong Song wrote:
> > Brian Vazquez has proposed BPF_MAP_DUMP command to look up more than one
> > map entries per syscall.
> > https://lore.kernel.org/bpf/CABCgpaU3xxX6CMMxD+1knApivtc2jLBHysDXw-0E9bQEL0qC3A@mail.gmail.com/T/#t
> >
> > During discussion, we found more use cases can be supported in a similar
> > map operation batching framework. For example, batched map lookup and delete,
> > which can be really helpful for bcc.
> > https://github.com/iovisor/bcc/blob/master/tools/tcptop.py#L233-L243
> > https://github.com/iovisor/bcc/blob/master/tools/slabratetop.py#L129-L138
> >
> > Also, in bcc, we have API to delete all entries in a map.
> > https://github.com/iovisor/bcc/blob/master/src/cc/api/BPFTable.h#L257-L264
> >
> > For map update, batched operations also useful as sometimes applications need
> > to populate initial maps with more than one entry. For example, the below
> > example is from kernel/samples/bpf/xdp_redirect_cpu_user.c:
> > https://github.com/torvalds/linux/blob/master/samples/bpf/xdp_redirect_cpu_user.c#L543-L550
> >
> > This patch addresses all the above use cases. To make uapi stable, it also
> > covers other potential use cases. Four bpf syscall subcommands are introduced:
> > BPF_MAP_LOOKUP_BATCH
> > BPF_MAP_LOOKUP_AND_DELETE_BATCH
> > BPF_MAP_UPDATE_BATCH
> > BPF_MAP_DELETE_BATCH
> >
> > In userspace, application can iterate through the whole map one batch
> > as a time, e.g., bpf_map_lookup_batch() in the below:
> > p_key = NULL;
> > p_next_key = &key;
> > while (true) {
> > err = bpf_map_lookup_batch(fd, p_key, &p_next_key, keys, values,
> > &batch_size, elem_flags, flags);
> > if (err) ...
> > if (p_next_key) break; // done
> > if (!p_key) p_key = p_next_key;
> > }
> > Please look at individual patches for details of new syscall subcommands
> > and examples of user codes.
> >
> > The testing is also done in a qemu VM environment:
> > measure_lookup: max_entries 1000000, batch 10, time 342ms
> > measure_lookup: max_entries 1000000, batch 1000, time 295ms
> > measure_lookup: max_entries 1000000, batch 1000000, time 270ms
> > measure_lookup: max_entries 1000000, no batching, time 1346ms
> > measure_lookup_delete: max_entries 1000000, batch 10, time 433ms
> > measure_lookup_delete: max_entries 1000000, batch 1000, time 363ms
> > measure_lookup_delete: max_entries 1000000, batch 1000000, time 357ms
> > measure_lookup_delete: max_entries 1000000, not batch, time 1894ms
> > measure_delete: max_entries 1000000, batch, time 220ms
> > measure_delete: max_entries 1000000, not batch, time 1289ms
> > For a 1M entry hash table, batch size of 10 can reduce cpu time
> > by 70%. Please see patch "tools/bpf: measure map batching perf"
> > for details of test codes.
>
> Hi Yonghong!
>
> great to see this, we have been looking at implementing some way to
> speed up map walks as well.
>
> The direction we were looking in, after previous discussions [1],
> however, was to provide a BPF program which can run the logic entirely
> within the kernel.
>
> We have a rough PoC on the FW side (we can offload the program which
> walks the map, which is pretty neat), but the kernel verifier side
> hasn't really progressed. It will soon.
>
> The rough idea is that the user space provides two programs, "filter"
> and "dumper":
>
> bpftool map exec id XYZ filter pinned /some/prog \
> dumper pinned /some/other_prog
>
> Both programs get this context:
>
> struct map_op_ctx {
> u64 key;
> u64 value;
> }
>
> We need a per-map implementation of the exec side, but roughly maps
> would do:
>
> LIST_HEAD(deleted);
>
> for entry in map {
> struct map_op_ctx {
> .key = entry->key,
> .value = entry->value,
> };
>
> act = BPF_PROG_RUN(filter, &map_op_ctx);
> if (act & ~ACT_BITS)
> return -EINVAL;
>
> if (act & DELETE) {
> map_unlink(entry);
> list_add(entry, &deleted);
> }
> if (act & STOP)
> break;
> }
>
> synchronize_rcu();
>
> for entry in deleted {
> struct map_op_ctx {
> .key = entry->key,
> .value = entry->value,
> };
>
> BPF_PROG_RUN(dumper, &map_op_ctx);
> map_free(entry);
> }
>
Hi Jakub,
how would that approach support percpu maps?
I'm thinking of a scenario where you want to do some calculations on
percpu maps and you are interested on the info on all the cpus not
just the one that is running the bpf program. Currently on a pcpu map
the bpf_map_lookup_elem helper only returns the pointer to the data of
the executing cpu.
> The filter program can't perform any map operations other than lookup,
> otherwise we won't be able to guarantee that we'll walk the entire map
> (if the filter program deletes some entries in a unfortunate order).
>
> If user space just wants a pure dump it can simply load a program which
> dumps the entries into a perf ring.
>
> I'm bringing this up because that mechanism should cover what is
> achieved with this patch set and much more.
>
> In particular for networking workloads where old flows have to be
> pruned from the map periodically it's far more efficient to communicate
> to user space only the flows which timed out (the delete batching from
> this set won't help at all).
>
> With a 2M entry map and this patch set we still won't be able to prune
> once a second on one core.
>
> [1]
> https://lore.kernel.org/netdev/20190813130921.10704-4-quentin.monnet@netronome.com/
^ permalink raw reply
* RE: linux-next: Tree for Aug 29 (mlx5)
From: Haiyang Zhang @ 2019-08-29 23:15 UTC (permalink / raw)
To: Saeed Mahameed, sfr@canb.auug.org.au, Eran Ben Elisha,
linux-next@vger.kernel.org, rdunlap@infradead.org
Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
Leon Romanovsky
In-Reply-To: <82c4fad3fc394693a596597df0d73cc5235f7025.camel@mellanox.com>
> -----Original Message-----
> From: Saeed Mahameed <saeedm@mellanox.com>
> Sent: Thursday, August 29, 2019 4:04 PM
> To: sfr@canb.auug.org.au; Eran Ben Elisha <eranbe@mellanox.com>; linux-
> next@vger.kernel.org; rdunlap@infradead.org; Haiyang Zhang
> <haiyangz@microsoft.com>
> Cc: linux-kernel@vger.kernel.org; netdev@vger.kernel.org; Leon
> Romanovsky <leonro@mellanox.com>
> Subject: Re: linux-next: Tree for Aug 29 (mlx5)
>
> On Thu, 2019-08-29 at 21:48 +0000, Haiyang Zhang wrote:
> > > -----Original Message-----
> > > From: Saeed Mahameed <saeedm@mellanox.com>
> > > Sent: Thursday, August 29, 2019 2:32 PM
> > > To: sfr@canb.auug.org.au; Eran Ben Elisha <eranbe@mellanox.com>;
> > > linux-
> > > next@vger.kernel.org; rdunlap@infradead.org; Haiyang Zhang
> > > <haiyangz@microsoft.com>
> > > Cc: linux-kernel@vger.kernel.org; netdev@vger.kernel.org; Leon
> > > Romanovsky <leonro@mellanox.com>
> > > Subject: Re: linux-next: Tree for Aug 29 (mlx5)
> > >
> > > On Thu, 2019-08-29 at 12:55 -0700, Randy Dunlap wrote:
> > > > On 8/29/19 12:54 PM, Randy Dunlap wrote:
> > > > > On 8/29/19 4:08 AM, Stephen Rothwell wrote:
> > > > > > Hi all,
> > > > > >
> > > > > > Changes since 20190828:
> > > > > >
> > > > >
> > > > > on x86_64:
> > > > > when CONFIG_PCI_HYPERV=m
> > > >
> > > > and CONFIG_PCI_HYPERV_INTERFACE=m
> > > >
> > >
> > > Haiyang and Eran, I think CONFIG_PCI_HYPERV_INTERFACE was never
> > > supposed to be a module ? it supposed to provide an always available
> > > interface to drivers ..
> > >
> > > Anyway, maybe we need to imply CONFIG_PCI_HYPERV_INTERFACE in
> mlx5.
> >
> > The symbolic dependency by driver mlx5e, automatically triggers
> > loading of pci_hyperv_interface module. And this module can be loaded
> > in any platforms.
> >
>
> This only works when both are modules.
>
>
> > Currently, mlx5e driver has #if
> > IS_ENABLED(CONFIG_PCI_HYPERV_INTERFACE)
> > around the code using the interface.
> >
> > I agree --
> > Adding "select PCI_HYPERV_INTERFACE" for mlx5e will clean up these
> > #if's.
> >
>
> No, not "select", "imply".
>
> if one wants PCI_HYPERV_INTERFACE off, imply will keep it off for you.
This looks good.
- Haiyang
^ permalink raw reply
* Re: [PATCH v6 net-next 15/19] ionic: Add Tx and Rx handling
From: Jakub Kicinski @ 2019-08-29 23:18 UTC (permalink / raw)
To: Shannon Nelson; +Cc: netdev, davem
In-Reply-To: <20190829182720.68419-16-snelson@pensando.io>
On Thu, 29 Aug 2019 11:27:16 -0700, Shannon Nelson wrote:
> +netdev_tx_t ionic_start_xmit(struct sk_buff *skb, struct net_device *netdev)
> +{
> + u16 queue_index = skb_get_queue_mapping(skb);
> + struct ionic_lif *lif = netdev_priv(netdev);
> + struct ionic_queue *q;
> + int ndescs;
> + int err;
> +
> + if (unlikely(!test_bit(IONIC_LIF_UP, lif->state))) {
> + dev_kfree_skb(skb);
> + return NETDEV_TX_OK;
> + }
> +
> + if (likely(lif_to_txqcq(lif, queue_index)))
> + q = lif_to_txq(lif, queue_index);
> + else
> + q = lif_to_txq(lif, 0);
> +
> + ndescs = ionic_tx_descs_needed(q, skb);
> + if (ndescs < 0)
> + goto err_out_drop;
> +
> + if (!ionic_q_has_space(q, ndescs)) {
You should stop the queue in advance, whenever you can't ensure that a
max size frame can be placed on the ring. Requeuing is very expensive
so modern drivers should try to never return NETDEV_TX_BUSY
> + netif_stop_subqueue(netdev, queue_index);
> + q->stop++;
> +
> + /* Might race with ionic_tx_clean, check again */
> + smp_rmb();
> + if (ionic_q_has_space(q, ndescs)) {
> + netif_wake_subqueue(netdev, queue_index);
> + q->wake++;
> + } else {
> + return NETDEV_TX_BUSY;
> + }
> + }
> +
> + if (skb_is_gso(skb))
> + err = ionic_tx_tso(q, skb);
> + else
> + err = ionic_tx(q, skb);
> +
> + if (err)
> + goto err_out_drop;
> +
> + return NETDEV_TX_OK;
> +
> +err_out_drop:
> + netif_stop_subqueue(netdev, queue_index);
This stopping of the queue is suspicious, if ionic_tx() fails there's
no guarantee the queue will ever be woken up, no?
> + q->stop++;
> + q->drop++;
> + dev_kfree_skb(skb);
> + return NETDEV_TX_OK;
> +}
^ permalink raw reply
* Re: [v1] iproute2: police: support 64bit rate and peakrate in tc utility
From: Stephen Hemminger @ 2019-08-29 23:21 UTC (permalink / raw)
To: David Dai; +Cc: jhs, xiyou.wangcong, jiri, netdev, linux-kernel, zdai
In-Reply-To: <1567032776-1118-1-git-send-email-zdai@linux.vnet.ibm.com>
On Wed, 28 Aug 2019 17:52:56 -0500
David Dai <zdai@linux.vnet.ibm.com> wrote:
> For high speed adapter like Mellanox CX-5 card, it can reach upto
> 100 Gbits per second bandwidth. Currently htb already supports 64bit rate
> in tc utility. However police action rate and peakrate are still limited
> to 32bit value (upto 32 Gbits per second). Taking advantage of the 2 new
> attributes TCA_POLICE_RATE64 and TCA_POLICE_PEAKRATE64 from kernel,
> tc can use them to break the 32bit limit, and still keep the backward
> binary compatibility.
>
> Tested-by: David Dai <zdai@linux.vnet.ibm.com>
> Signed-off-by: David Dai <zdai@linux.vnet.ibm.com>
This needs to go to iproute2-next not iproute2
^ permalink raw reply
* Re: [iproute2, master 2/2] devlink: Add a new time-stamp format for health reporter's dump
From: Stephen Hemminger @ 2019-08-29 23:27 UTC (permalink / raw)
To: Aya Levin; +Cc: netdev, Jiri Pirko, Moshe Shemesh
In-Reply-To: <1566471942-28529-3-git-send-email-ayal@mellanox.com>
On Thu, 22 Aug 2019 14:05:42 +0300
Aya Levin <ayal@mellanox.com> wrote:
> diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
> index fc195cbd66f4..3f8532711315 100644
> --- a/include/uapi/linux/devlink.h
> +++ b/include/uapi/linux/devlink.h
> @@ -348,6 +348,8 @@ enum devlink_attr {
> DEVLINK_ATTR_PORT_PCI_PF_NUMBER, /* u16 */
> DEVLINK_ATTR_PORT_PCI_VF_NUMBER, /* u16 */
>
> + DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TSPEC,
> +
> /* add new attributes above here, update the policy in devlink.c */
>
> __DEVLINK_ATTR_MAX,
> --
Since this is not upstream, this patch needs to go to iproute2-next.
Which means if you want the other bug fix, send it again against master.
^ permalink raw reply
* Re: [PATCH v6 net-next 15/19] ionic: Add Tx and Rx handling
From: Jakub Kicinski @ 2019-08-29 23:33 UTC (permalink / raw)
To: Shannon Nelson; +Cc: netdev, davem
In-Reply-To: <20190829182720.68419-16-snelson@pensando.io>
On Thu, 29 Aug 2019 11:27:16 -0700, Shannon Nelson wrote:
> +static int ionic_tx_tso(struct ionic_queue *q, struct sk_buff *skb)
> +{
> + struct ionic_tx_stats *stats = q_to_tx_stats(q);
> + struct ionic_desc_info *abort = q->head;
> + struct device *dev = q->lif->ionic->dev;
> + struct ionic_desc_info *rewind = abort;
> + struct ionic_txq_sg_elem *elem;
> + struct ionic_txq_desc *desc;
> + unsigned int frag_left = 0;
> + unsigned int offset = 0;
> + unsigned int len_left;
> + dma_addr_t desc_addr;
> + unsigned int hdrlen;
> + unsigned int nfrags;
> + unsigned int seglen;
> + u64 total_bytes = 0;
> + u64 total_pkts = 0;
> + unsigned int left;
> + unsigned int len;
> + unsigned int mss;
> + skb_frag_t *frag;
> + bool start, done;
> + bool outer_csum;
> + bool has_vlan;
> + u16 desc_len;
> + u8 desc_nsge;
> + u16 vlan_tci;
> + bool encap;
> + int err;
> +
> + mss = skb_shinfo(skb)->gso_size;
> + nfrags = skb_shinfo(skb)->nr_frags;
> + len_left = skb->len - skb_headlen(skb);
> + outer_csum = (skb_shinfo(skb)->gso_type & SKB_GSO_GRE_CSUM) ||
> + (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM);
> + has_vlan = !!skb_vlan_tag_present(skb);
> + vlan_tci = skb_vlan_tag_get(skb);
> + encap = skb->encapsulation;
> +
> + /* Preload inner-most TCP csum field with IP pseudo hdr
> + * calculated with IP length set to zero. HW will later
> + * add in length to each TCP segment resulting from the TSO.
> + */
> +
> + if (encap)
> + err = ionic_tx_tcp_inner_pseudo_csum(skb);
> + else
> + err = ionic_tx_tcp_pseudo_csum(skb);
> + if (err)
> + return err;
> +
> + if (encap)
> + hdrlen = skb_inner_transport_header(skb) - skb->data +
> + inner_tcp_hdrlen(skb);
> + else
> + hdrlen = skb_transport_offset(skb) + tcp_hdrlen(skb);
> +
> + seglen = hdrlen + mss;
> + left = skb_headlen(skb);
> +
> + desc = ionic_tx_tso_next(q, &elem);
> + start = true;
> +
> + /* Chop skb->data up into desc segments */
> +
> + while (left > 0) {
> + len = min(seglen, left);
> + frag_left = seglen - len;
> + desc_addr = ionic_tx_map_single(q, skb->data + offset, len);
> + if (dma_mapping_error(dev, desc_addr))
> + goto err_out_abort;
> + desc_len = len;
> + desc_nsge = 0;
> + left -= len;
> + offset += len;
> + if (nfrags > 0 && frag_left > 0)
> + continue;
> + done = (nfrags == 0 && left == 0);
> + ionic_tx_tso_post(q, desc, skb,
> + desc_addr, desc_nsge, desc_len,
> + hdrlen, mss,
> + outer_csum,
> + vlan_tci, has_vlan,
> + start, done);
> + total_pkts++;
> + total_bytes += start ? len : len + hdrlen;
> + desc = ionic_tx_tso_next(q, &elem);
> + start = false;
> + seglen = mss;
> + }
> +
> + /* Chop skb frags into desc segments */
> +
> + for (frag = skb_shinfo(skb)->frags; len_left; frag++) {
> + offset = 0;
> + left = skb_frag_size(frag);
> + len_left -= left;
> + nfrags--;
> + stats->frags++;
> +
> + while (left > 0) {
> + if (frag_left > 0) {
> + len = min(frag_left, left);
> + frag_left -= len;
> + elem->addr =
> + cpu_to_le64(ionic_tx_map_frag(q, frag,
> + offset, len));
> + if (dma_mapping_error(dev, elem->addr))
> + goto err_out_abort;
> + elem->len = cpu_to_le16(len);
> + elem++;
> + desc_nsge++;
> + left -= len;
> + offset += len;
> + if (nfrags > 0 && frag_left > 0)
> + continue;
> + done = (nfrags == 0 && left == 0);
> + ionic_tx_tso_post(q, desc, skb, desc_addr,
> + desc_nsge, desc_len,
> + hdrlen, mss, outer_csum,
> + vlan_tci, has_vlan,
> + start, done);
> + total_pkts++;
> + total_bytes += start ? len : len + hdrlen;
> + desc = ionic_tx_tso_next(q, &elem);
> + start = false;
> + } else {
> + len = min(mss, left);
> + frag_left = mss - len;
> + desc_addr = ionic_tx_map_frag(q, frag,
> + offset, len);
> + if (dma_mapping_error(dev, desc_addr))
> + goto err_out_abort;
> + desc_len = len;
> + desc_nsge = 0;
> + left -= len;
> + offset += len;
> + if (nfrags > 0 && frag_left > 0)
> + continue;
> + done = (nfrags == 0 && left == 0);
> + ionic_tx_tso_post(q, desc, skb, desc_addr,
> + desc_nsge, desc_len,
> + hdrlen, mss, outer_csum,
> + vlan_tci, has_vlan,
> + start, done);
> + total_pkts++;
> + total_bytes += start ? len : len + hdrlen;
> + desc = ionic_tx_tso_next(q, &elem);
> + start = false;
> + }
> + }
> + }
> +
> + stats->pkts += total_pkts;
> + stats->bytes += total_bytes;
> + stats->tso++;
> +
> + return 0;
> +
> +err_out_abort:
> + while (rewind->desc != q->head->desc) {
> + ionic_tx_clean(q, rewind, NULL, NULL);
> + rewind = rewind->next;
> + }
> + q->head = abort;
> +
> + return -ENOMEM;
> +}
There's definitely a function for helping drivers which can't do full
TSO slice up the packet, but I can't find it now 😫😫
Eric would definitely know.
Did you have a look? Would it be useful here?
^ permalink raw reply
* Re: [PATCH] ipv6: Not to probe neighbourless routes
From: David Miller @ 2019-08-29 23:37 UTC (permalink / raw)
To: lkp
Cc: wang.yi59, kbuild-all, kuznet, yoshfuji, netdev, linux-kernel,
xue.zhihong, wang.liang82, cheng.lin130
In-Reply-To: <201908300657.DY647BSw%lkp@intel.com>
So yeah, this is one instance where the kbuild test robot's report is
making more rather than less work for us.
We identified the build problem within hours of this patch being
posted and the updated version was posted more than 24 hours ago.
The kbuild robot should really have a way to either:
1) Report build problems faster, humans find the obvious cases like
this one within a day or less.
2) Notice that a new version of the patch was posted or that a human
responded to the patch pointing out the build problem.
Otherwise we get postings like this which is just more noise to
delete.
Thanks.
^ permalink raw reply
* Re: [PATCH bpf-next 02/13] bpf: refactor map_update_elem()
From: Song Liu @ 2019-08-29 23:37 UTC (permalink / raw)
To: Yonghong Song
Cc: bpf, Networking, Alexei Starovoitov, Brian Vazquez,
Daniel Borkmann, Kernel Team
In-Reply-To: <20190829064504.2750444-1-yhs@fb.com>
> On Aug 28, 2019, at 11:45 PM, Yonghong Song <yhs@fb.com> wrote:
>
> Refactor function map_update_elem() by creating a
> helper function bpf_map_update_elem() which will be
> used later by batched map update operation.
>
> Also reuse function bpf_map_value_size()
> in map_update_elem().
>
> Signed-off-by: Yonghong Song <yhs@fb.com>
Acked-by: Song Liu <songliubraving@fb.com>
^ permalink raw reply
* Re: [PATCH v6 net-next 16/19] ionic: Add netdev-event handling
From: Jakub Kicinski @ 2019-08-29 23:37 UTC (permalink / raw)
To: Shannon Nelson; +Cc: netdev, davem
In-Reply-To: <20190829182720.68419-17-snelson@pensando.io>
On Thu, 29 Aug 2019 11:27:17 -0700, Shannon Nelson wrote:
> When the netdev gets a new name from userland, pass that name
> down to the NIC for internal tracking.
>
> Signed-off-by: Shannon Nelson <snelson@pensando.io>
There is a precedent in ACPI for telling the FW what OS is running but
how is the interface name useful for the firmware I can't really tell.
^ permalink raw reply
* Re: [PATCH bpf-next 03/13] bpf: refactor map_delete_elem()
From: Song Liu @ 2019-08-29 23:39 UTC (permalink / raw)
To: Yonghong Song
Cc: bpf, netdev@vger.kernel.org, Alexei Starovoitov, Brian Vazquez,
Daniel Borkmann, Kernel Team
In-Reply-To: <20190829064505.2750541-1-yhs@fb.com>
> On Aug 28, 2019, at 11:45 PM, Yonghong Song <yhs@fb.com> wrote:
>
> Refactor function map_delete_elem() with a new helper
> bpf_map_delete_elem(), which will be used later
> for batched lookup_and_delete and delete operations.
>
> Signed-off-by: Yonghong Song <yhs@fb.com>
Acked-by: Song Liu <songliubraving@fb.com>
^ permalink raw reply
* Re: [PATCH bpf-next 04/13] bpf: refactor map_get_next_key()
From: Song Liu @ 2019-08-29 23:39 UTC (permalink / raw)
To: Yonghong Song
Cc: bpf, netdev@vger.kernel.org, Alexei Starovoitov, Brian Vazquez,
Daniel Borkmann, Kernel Team
In-Reply-To: <20190829064506.2750717-1-yhs@fb.com>
> On Aug 28, 2019, at 11:45 PM, Yonghong Song <yhs@fb.com> wrote:
>
> Refactor function map_get_next_key() with a new helper
> bpf_map_get_next_key(), which will be used later
> for batched map lookup/lookup_and_delete/delete operations.
>
> Signed-off-by: Yonghong Song <yhs@fb.com>
Acked-by: Song Liu <songliubraving@fb.com>
^ permalink raw reply
* [PATCH mlx5-next 0/5] Mellanox, mlx5 next updates 2019-09-29
From: Saeed Mahameed @ 2019-08-29 23:42 UTC (permalink / raw)
To: Saeed Mahameed, Leon Romanovsky
Cc: netdev@vger.kernel.org, linux-rdma@vger.kernel.org
Hi All,
This series includes misc updates for mlx5-next shared branch required
for upcoming software steering feature.
1) Alex adds HW bits and definitions required for SW steering
2) Ariel moves device memory management to mlx5_core (From mlx5_ib)
3) Maor, Cleanups and fixups for eswitch mode and RoCE
4) Mar, Set only stag for match untagged packets
In case of no objection this series will be applied to mlx5-next branch
and sent later as pull request to both rdma-next and net-next branches.
Thanks,
Saeed.
---
Alex Vesker (1):
net/mlx5: Add HW bits and definitions required for SW steering
Ariel Levkovich (1):
net/mlx5: Move device memory management to mlx5_core
Maor Gottlieb (2):
net/mlx5: Avoid disabling RoCE when uninitialized
net/mlx5: Add stub for mlx5_eswitch_mode
Mark Bloch (1):
net/mlx5: Set only stag for match untagged packets
drivers/infiniband/hw/mlx5/cmd.c | 130 ----------
drivers/infiniband/hw/mlx5/cmd.h | 4 -
drivers/infiniband/hw/mlx5/main.c | 102 +++-----
drivers/infiniband/hw/mlx5/mlx5_ib.h | 2 -
.../net/ethernet/mellanox/mlx5/core/Makefile | 2 +-
.../net/ethernet/mellanox/mlx5/core/en_tc.c | 5 +-
.../net/ethernet/mellanox/mlx5/core/lib/dm.c | 223 +++++++++++++++++
.../net/ethernet/mellanox/mlx5/core/main.c | 5 +
.../ethernet/mellanox/mlx5/core/mlx5_core.h | 3 +
.../net/ethernet/mellanox/mlx5/core/rdma.c | 8 +-
include/linux/mlx5/device.h | 7 +
include/linux/mlx5/driver.h | 14 ++
include/linux/mlx5/eswitch.h | 8 +-
include/linux/mlx5/mlx5_ifc.h | 235 +++++++++++++++---
14 files changed, 497 insertions(+), 251 deletions(-)
create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c
--
2.21.0
^ permalink raw reply
* [PATCH mlx5-next 1/5] net/mlx5: Move device memory management to mlx5_core
From: Saeed Mahameed @ 2019-08-29 23:42 UTC (permalink / raw)
To: Saeed Mahameed, Leon Romanovsky
Cc: netdev@vger.kernel.org, linux-rdma@vger.kernel.org,
Ariel Levkovich, Mark Bloch
In-Reply-To: <20190829234151.9958-1-saeedm@mellanox.com>
From: Ariel Levkovich <lariel@mellanox.com>
Move the device memory allocation and deallocation commands
SW ICM memory to mlx5_core to expose this API for all
mlx5_core users.
This comes as preparation for supporting SW steering in kernel
where it will be required to allocate and register device
memory for direct rule insertion.
In addition, an API to register this device memory for future
remote access operations is introduced using the create_mkey
commands.
Signed-off-by: Ariel Levkovich <lariel@mellanox.com>
Reviewed-by: Mark Bloch <markb@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
drivers/infiniband/hw/mlx5/cmd.c | 130 ----------
drivers/infiniband/hw/mlx5/cmd.h | 4 -
drivers/infiniband/hw/mlx5/main.c | 102 +++-----
drivers/infiniband/hw/mlx5/mlx5_ib.h | 2 -
.../net/ethernet/mellanox/mlx5/core/Makefile | 2 +-
.../net/ethernet/mellanox/mlx5/core/lib/dm.c | 223 ++++++++++++++++++
.../net/ethernet/mellanox/mlx5/core/main.c | 5 +
.../ethernet/mellanox/mlx5/core/mlx5_core.h | 3 +
include/linux/mlx5/driver.h | 14 ++
9 files changed, 276 insertions(+), 209 deletions(-)
create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c
diff --git a/drivers/infiniband/hw/mlx5/cmd.c b/drivers/infiniband/hw/mlx5/cmd.c
index 6c8645033102..4937947400cd 100644
--- a/drivers/infiniband/hw/mlx5/cmd.c
+++ b/drivers/infiniband/hw/mlx5/cmd.c
@@ -186,136 +186,6 @@ int mlx5_cmd_dealloc_memic(struct mlx5_dm *dm, phys_addr_t addr, u64 length)
return err;
}
-int mlx5_cmd_alloc_sw_icm(struct mlx5_dm *dm, int type, u64 length,
- u16 uid, phys_addr_t *addr, u32 *obj_id)
-{
- struct mlx5_core_dev *dev = dm->dev;
- u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
- u32 in[MLX5_ST_SZ_DW(create_sw_icm_in)] = {};
- unsigned long *block_map;
- u64 icm_start_addr;
- u32 log_icm_size;
- u32 num_blocks;
- u32 max_blocks;
- u64 block_idx;
- void *sw_icm;
- int ret;
-
- MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
- MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
- MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_SW_ICM);
- MLX5_SET(general_obj_in_cmd_hdr, in, uid, uid);
-
- switch (type) {
- case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM:
- icm_start_addr = MLX5_CAP64_DEV_MEM(dev,
- steering_sw_icm_start_address);
- log_icm_size = MLX5_CAP_DEV_MEM(dev, log_steering_sw_icm_size);
- block_map = dm->steering_sw_icm_alloc_blocks;
- break;
- case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM:
- icm_start_addr = MLX5_CAP64_DEV_MEM(dev,
- header_modify_sw_icm_start_address);
- log_icm_size = MLX5_CAP_DEV_MEM(dev,
- log_header_modify_sw_icm_size);
- block_map = dm->header_modify_sw_icm_alloc_blocks;
- break;
- default:
- return -EINVAL;
- }
-
- num_blocks = (length + MLX5_SW_ICM_BLOCK_SIZE(dev) - 1) >>
- MLX5_LOG_SW_ICM_BLOCK_SIZE(dev);
- max_blocks = BIT(log_icm_size - MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
- spin_lock(&dm->lock);
- block_idx = bitmap_find_next_zero_area(block_map,
- max_blocks,
- 0,
- num_blocks, 0);
-
- if (block_idx < max_blocks)
- bitmap_set(block_map,
- block_idx, num_blocks);
-
- spin_unlock(&dm->lock);
-
- if (block_idx >= max_blocks)
- return -ENOMEM;
-
- sw_icm = MLX5_ADDR_OF(create_sw_icm_in, in, sw_icm);
- icm_start_addr += block_idx << MLX5_LOG_SW_ICM_BLOCK_SIZE(dev);
- MLX5_SET64(sw_icm, sw_icm, sw_icm_start_addr,
- icm_start_addr);
- MLX5_SET(sw_icm, sw_icm, log_sw_icm_size, ilog2(length));
-
- ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
- if (ret) {
- spin_lock(&dm->lock);
- bitmap_clear(block_map,
- block_idx, num_blocks);
- spin_unlock(&dm->lock);
-
- return ret;
- }
-
- *addr = icm_start_addr;
- *obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
-
- return 0;
-}
-
-int mlx5_cmd_dealloc_sw_icm(struct mlx5_dm *dm, int type, u64 length,
- u16 uid, phys_addr_t addr, u32 obj_id)
-{
- struct mlx5_core_dev *dev = dm->dev;
- u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
- u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
- unsigned long *block_map;
- u32 num_blocks;
- u64 start_idx;
- int err;
-
- num_blocks = (length + MLX5_SW_ICM_BLOCK_SIZE(dev) - 1) >>
- MLX5_LOG_SW_ICM_BLOCK_SIZE(dev);
-
- switch (type) {
- case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM:
- start_idx =
- (addr - MLX5_CAP64_DEV_MEM(
- dev, steering_sw_icm_start_address)) >>
- MLX5_LOG_SW_ICM_BLOCK_SIZE(dev);
- block_map = dm->steering_sw_icm_alloc_blocks;
- break;
- case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM:
- start_idx =
- (addr -
- MLX5_CAP64_DEV_MEM(
- dev, header_modify_sw_icm_start_address)) >>
- MLX5_LOG_SW_ICM_BLOCK_SIZE(dev);
- block_map = dm->header_modify_sw_icm_alloc_blocks;
- break;
- default:
- return -EINVAL;
- }
-
- MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
- MLX5_CMD_OP_DESTROY_GENERAL_OBJECT);
- MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_SW_ICM);
- MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, obj_id);
- MLX5_SET(general_obj_in_cmd_hdr, in, uid, uid);
-
- err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
- if (err)
- return err;
-
- spin_lock(&dm->lock);
- bitmap_clear(block_map,
- start_idx, num_blocks);
- spin_unlock(&dm->lock);
-
- return 0;
-}
-
int mlx5_cmd_query_ext_ppcnt_counters(struct mlx5_core_dev *dev, void *out)
{
u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {};
diff --git a/drivers/infiniband/hw/mlx5/cmd.h b/drivers/infiniband/hw/mlx5/cmd.h
index 0572dcba6eae..169cab4915e3 100644
--- a/drivers/infiniband/hw/mlx5/cmd.h
+++ b/drivers/infiniband/hw/mlx5/cmd.h
@@ -65,8 +65,4 @@ int mlx5_cmd_alloc_q_counter(struct mlx5_core_dev *dev, u16 *counter_id,
u16 uid);
int mlx5_cmd_mad_ifc(struct mlx5_core_dev *dev, const void *inb, void *outb,
u16 opmod, u8 port);
-int mlx5_cmd_alloc_sw_icm(struct mlx5_dm *dm, int type, u64 length,
- u16 uid, phys_addr_t *addr, u32 *obj_id);
-int mlx5_cmd_dealloc_sw_icm(struct mlx5_dm *dm, int type, u64 length,
- u16 uid, phys_addr_t addr, u32 obj_id);
#endif /* MLX5_IB_CMD_H */
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index c2a5780cb394..42fdbbea06f0 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -2280,6 +2280,7 @@ static inline int check_dm_type_support(struct mlx5_ib_dev *dev,
return -EOPNOTSUPP;
break;
case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM:
+ case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM:
if (!capable(CAP_SYS_RAWIO) ||
!capable(CAP_NET_RAW))
return -EPERM;
@@ -2344,20 +2345,20 @@ static int handle_alloc_dm_sw_icm(struct ib_ucontext *ctx,
struct uverbs_attr_bundle *attrs,
int type)
{
- struct mlx5_dm *dm_db = &to_mdev(ctx->device)->dm;
+ struct mlx5_core_dev *dev = to_mdev(ctx->device)->mdev;
u64 act_size;
int err;
/* Allocation size must a multiple of the basic block size
* and a power of 2.
*/
- act_size = round_up(attr->length, MLX5_SW_ICM_BLOCK_SIZE(dm_db->dev));
+ act_size = round_up(attr->length, MLX5_SW_ICM_BLOCK_SIZE(dev));
act_size = roundup_pow_of_two(act_size);
dm->size = act_size;
- err = mlx5_cmd_alloc_sw_icm(dm_db, type, act_size,
- to_mucontext(ctx)->devx_uid, &dm->dev_addr,
- &dm->icm_dm.obj_id);
+ err = mlx5_dm_sw_icm_alloc(dev, type, act_size,
+ to_mucontext(ctx)->devx_uid, &dm->dev_addr,
+ &dm->icm_dm.obj_id);
if (err)
return err;
@@ -2365,9 +2366,9 @@ static int handle_alloc_dm_sw_icm(struct ib_ucontext *ctx,
MLX5_IB_ATTR_ALLOC_DM_RESP_START_OFFSET,
&dm->dev_addr, sizeof(dm->dev_addr));
if (err)
- mlx5_cmd_dealloc_sw_icm(dm_db, type, dm->size,
- to_mucontext(ctx)->devx_uid,
- dm->dev_addr, dm->icm_dm.obj_id);
+ mlx5_dm_sw_icm_dealloc(dev, type, dm->size,
+ to_mucontext(ctx)->devx_uid, dm->dev_addr,
+ dm->icm_dm.obj_id);
return err;
}
@@ -2407,8 +2408,14 @@ struct ib_dm *mlx5_ib_alloc_dm(struct ib_device *ibdev,
attrs);
break;
case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM:
+ err = handle_alloc_dm_sw_icm(context, dm,
+ attr, attrs,
+ MLX5_SW_ICM_TYPE_STEERING);
+ break;
case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM:
- err = handle_alloc_dm_sw_icm(context, dm, attr, attrs, type);
+ err = handle_alloc_dm_sw_icm(context, dm,
+ attr, attrs,
+ MLX5_SW_ICM_TYPE_HEADER_MODIFY);
break;
default:
err = -EOPNOTSUPP;
@@ -2428,6 +2435,7 @@ int mlx5_ib_dealloc_dm(struct ib_dm *ibdm, struct uverbs_attr_bundle *attrs)
{
struct mlx5_ib_ucontext *ctx = rdma_udata_to_drv_context(
&attrs->driver_udata, struct mlx5_ib_ucontext, ibucontext);
+ struct mlx5_core_dev *dev = to_mdev(ibdm->device)->mdev;
struct mlx5_dm *dm_db = &to_mdev(ibdm->device)->dm;
struct mlx5_ib_dm *dm = to_mdm(ibdm);
u32 page_idx;
@@ -2439,19 +2447,23 @@ int mlx5_ib_dealloc_dm(struct ib_dm *ibdm, struct uverbs_attr_bundle *attrs)
if (ret)
return ret;
- page_idx = (dm->dev_addr -
- pci_resource_start(dm_db->dev->pdev, 0) -
- MLX5_CAP64_DEV_MEM(dm_db->dev,
- memic_bar_start_addr)) >>
- PAGE_SHIFT;
+ page_idx = (dm->dev_addr - pci_resource_start(dev->pdev, 0) -
+ MLX5_CAP64_DEV_MEM(dev, memic_bar_start_addr)) >>
+ PAGE_SHIFT;
bitmap_clear(ctx->dm_pages, page_idx,
DIV_ROUND_UP(dm->size, PAGE_SIZE));
break;
case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM:
+ ret = mlx5_dm_sw_icm_dealloc(dev, MLX5_SW_ICM_TYPE_STEERING,
+ dm->size, ctx->devx_uid, dm->dev_addr,
+ dm->icm_dm.obj_id);
+ if (ret)
+ return ret;
+ break;
case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM:
- ret = mlx5_cmd_dealloc_sw_icm(dm_db, dm->type, dm->size,
- ctx->devx_uid, dm->dev_addr,
- dm->icm_dm.obj_id);
+ ret = mlx5_dm_sw_icm_dealloc(dev, MLX5_SW_ICM_TYPE_HEADER_MODIFY,
+ dm->size, ctx->devx_uid, dm->dev_addr,
+ dm->icm_dm.obj_id);
if (ret)
return ret;
break;
@@ -6097,8 +6109,6 @@ static struct ib_counters *mlx5_ib_create_counters(struct ib_device *device,
static void mlx5_ib_stage_init_cleanup(struct mlx5_ib_dev *dev)
{
- struct mlx5_core_dev *mdev = dev->mdev;
-
mlx5_ib_cleanup_multiport_master(dev);
if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) {
srcu_barrier(&dev->mr_srcu);
@@ -6106,29 +6116,11 @@ static void mlx5_ib_stage_init_cleanup(struct mlx5_ib_dev *dev)
}
WARN_ON(!bitmap_empty(dev->dm.memic_alloc_pages, MLX5_MAX_MEMIC_PAGES));
-
- WARN_ON(dev->dm.steering_sw_icm_alloc_blocks &&
- !bitmap_empty(
- dev->dm.steering_sw_icm_alloc_blocks,
- BIT(MLX5_CAP_DEV_MEM(mdev, log_steering_sw_icm_size) -
- MLX5_LOG_SW_ICM_BLOCK_SIZE(mdev))));
-
- kfree(dev->dm.steering_sw_icm_alloc_blocks);
-
- WARN_ON(dev->dm.header_modify_sw_icm_alloc_blocks &&
- !bitmap_empty(dev->dm.header_modify_sw_icm_alloc_blocks,
- BIT(MLX5_CAP_DEV_MEM(
- mdev, log_header_modify_sw_icm_size) -
- MLX5_LOG_SW_ICM_BLOCK_SIZE(mdev))));
-
- kfree(dev->dm.header_modify_sw_icm_alloc_blocks);
}
static int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev)
{
struct mlx5_core_dev *mdev = dev->mdev;
- u64 header_modify_icm_blocks = 0;
- u64 steering_icm_blocks = 0;
int err;
int i;
@@ -6173,51 +6165,17 @@ static int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev)
INIT_LIST_HEAD(&dev->qp_list);
spin_lock_init(&dev->reset_flow_resource_lock);
- if (MLX5_CAP_GEN_64(mdev, general_obj_types) &
- MLX5_GENERAL_OBJ_TYPES_CAP_SW_ICM) {
- if (MLX5_CAP64_DEV_MEM(mdev, steering_sw_icm_start_address)) {
- steering_icm_blocks =
- BIT(MLX5_CAP_DEV_MEM(mdev,
- log_steering_sw_icm_size) -
- MLX5_LOG_SW_ICM_BLOCK_SIZE(mdev));
-
- dev->dm.steering_sw_icm_alloc_blocks =
- kcalloc(BITS_TO_LONGS(steering_icm_blocks),
- sizeof(unsigned long), GFP_KERNEL);
- if (!dev->dm.steering_sw_icm_alloc_blocks)
- goto err_mp;
- }
-
- if (MLX5_CAP64_DEV_MEM(mdev,
- header_modify_sw_icm_start_address)) {
- header_modify_icm_blocks = BIT(
- MLX5_CAP_DEV_MEM(
- mdev, log_header_modify_sw_icm_size) -
- MLX5_LOG_SW_ICM_BLOCK_SIZE(mdev));
-
- dev->dm.header_modify_sw_icm_alloc_blocks =
- kcalloc(BITS_TO_LONGS(header_modify_icm_blocks),
- sizeof(unsigned long), GFP_KERNEL);
- if (!dev->dm.header_modify_sw_icm_alloc_blocks)
- goto err_dm;
- }
- }
-
spin_lock_init(&dev->dm.lock);
dev->dm.dev = mdev;
if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) {
err = init_srcu_struct(&dev->mr_srcu);
if (err)
- goto err_dm;
+ goto err_mp;
}
return 0;
-err_dm:
- kfree(dev->dm.steering_sw_icm_alloc_blocks);
- kfree(dev->dm.header_modify_sw_icm_alloc_blocks);
-
err_mp:
mlx5_ib_cleanup_multiport_master(dev);
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
index c482f19958b3..afd69ba33b2b 100644
--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h
+++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h
@@ -880,8 +880,6 @@ struct mlx5_dm {
*/
spinlock_t lock;
DECLARE_BITMAP(memic_alloc_pages, MLX5_MAX_MEMIC_PAGES);
- unsigned long *steering_sw_icm_alloc_blocks;
- unsigned long *header_modify_sw_icm_alloc_blocks;
};
struct mlx5_read_counters_attr {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
index 57d2cc666fe3..4eb52e8500c3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
@@ -15,7 +15,7 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
health.o mcg.o cq.o alloc.o qp.o port.o mr.o pd.o \
transobj.o vport.o sriov.o fs_cmd.o fs_core.o pci_irq.o \
fs_counters.o rl.o lag.o dev.o events.o wq.o lib/gid.o \
- lib/devcom.o lib/pci_vsc.o diag/fs_tracepoint.o \
+ lib/devcom.o lib/pci_vsc.o lib/dm.o diag/fs_tracepoint.o \
diag/fw_tracer.o diag/crdump.o devlink.o
#
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c
new file mode 100644
index 000000000000..e065c2f68f5a
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+// Copyright (c) 2019 Mellanox Technologies
+
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/device.h>
+
+#include "mlx5_core.h"
+#include "lib/mlx5.h"
+
+struct mlx5_dm {
+ /* protect access to icm bitmask */
+ spinlock_t lock;
+ unsigned long *steering_sw_icm_alloc_blocks;
+ unsigned long *header_modify_sw_icm_alloc_blocks;
+};
+
+struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev)
+{
+ u64 header_modify_icm_blocks = 0;
+ u64 steering_icm_blocks = 0;
+ struct mlx5_dm *dm;
+
+ if (!(MLX5_CAP_GEN_64(dev, general_obj_types) & MLX5_GENERAL_OBJ_TYPES_CAP_SW_ICM))
+ return 0;
+
+ dm = kzalloc(sizeof(*dm), GFP_KERNEL);
+ if (!dm)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock_init(&dm->lock);
+
+ if (MLX5_CAP64_DEV_MEM(dev, steering_sw_icm_start_address)) {
+ steering_icm_blocks =
+ BIT(MLX5_CAP_DEV_MEM(dev, log_steering_sw_icm_size) -
+ MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
+
+ dm->steering_sw_icm_alloc_blocks =
+ kcalloc(BITS_TO_LONGS(steering_icm_blocks),
+ sizeof(unsigned long), GFP_KERNEL);
+ if (!dm->steering_sw_icm_alloc_blocks)
+ goto err_steering;
+ }
+
+ if (MLX5_CAP64_DEV_MEM(dev, header_modify_sw_icm_start_address)) {
+ header_modify_icm_blocks =
+ BIT(MLX5_CAP_DEV_MEM(dev, log_header_modify_sw_icm_size) -
+ MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
+
+ dm->header_modify_sw_icm_alloc_blocks =
+ kcalloc(BITS_TO_LONGS(header_modify_icm_blocks),
+ sizeof(unsigned long), GFP_KERNEL);
+ if (!dm->header_modify_sw_icm_alloc_blocks)
+ goto err_modify_hdr;
+ }
+
+ return dm;
+
+err_modify_hdr:
+ kfree(dm->steering_sw_icm_alloc_blocks);
+
+err_steering:
+ kfree(dm);
+
+ return ERR_PTR(-ENOMEM);
+}
+
+void mlx5_dm_cleanup(struct mlx5_core_dev *dev)
+{
+ struct mlx5_dm *dm = dev->dm;
+
+ if (!dev->dm)
+ return;
+
+ if (dm->steering_sw_icm_alloc_blocks) {
+ WARN_ON(!bitmap_empty(dm->steering_sw_icm_alloc_blocks,
+ BIT(MLX5_CAP_DEV_MEM(dev, log_steering_sw_icm_size) -
+ MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))));
+ kfree(dm->steering_sw_icm_alloc_blocks);
+ }
+
+ if (dm->header_modify_sw_icm_alloc_blocks) {
+ WARN_ON(!bitmap_empty(dm->header_modify_sw_icm_alloc_blocks,
+ BIT(MLX5_CAP_DEV_MEM(dev,
+ log_header_modify_sw_icm_size) -
+ MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))));
+ kfree(dm->header_modify_sw_icm_alloc_blocks);
+ }
+
+ kfree(dm);
+}
+
+int mlx5_dm_sw_icm_alloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type,
+ u64 length, u16 uid, phys_addr_t *addr, u32 *obj_id)
+{
+ u32 num_blocks = DIV_ROUND_UP_ULL(length, MLX5_SW_ICM_BLOCK_SIZE(dev));
+ u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
+ u32 in[MLX5_ST_SZ_DW(create_sw_icm_in)] = {};
+ struct mlx5_dm *dm = dev->dm;
+ unsigned long *block_map;
+ u64 icm_start_addr;
+ u32 log_icm_size;
+ u32 max_blocks;
+ u64 block_idx;
+ void *sw_icm;
+ int ret;
+
+ if (!dev->dm)
+ return -EOPNOTSUPP;
+
+ if (!length || (length & (length - 1)) ||
+ length & (MLX5_SW_ICM_BLOCK_SIZE(dev) - 1))
+ return -EINVAL;
+
+ MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
+ MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
+ MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_SW_ICM);
+ MLX5_SET(general_obj_in_cmd_hdr, in, uid, uid);
+
+ switch (type) {
+ case MLX5_SW_ICM_TYPE_STEERING:
+ icm_start_addr = MLX5_CAP64_DEV_MEM(dev, steering_sw_icm_start_address);
+ log_icm_size = MLX5_CAP_DEV_MEM(dev, log_steering_sw_icm_size);
+ block_map = dm->steering_sw_icm_alloc_blocks;
+ break;
+ case MLX5_SW_ICM_TYPE_HEADER_MODIFY:
+ icm_start_addr = MLX5_CAP64_DEV_MEM(dev, header_modify_sw_icm_start_address);
+ log_icm_size = MLX5_CAP_DEV_MEM(dev,
+ log_header_modify_sw_icm_size);
+ block_map = dm->header_modify_sw_icm_alloc_blocks;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (!block_map)
+ return -EOPNOTSUPP;
+
+ max_blocks = BIT(log_icm_size - MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
+ spin_lock(&dm->lock);
+ block_idx = bitmap_find_next_zero_area(block_map,
+ max_blocks,
+ 0,
+ num_blocks, 0);
+
+ if (block_idx < max_blocks)
+ bitmap_set(block_map,
+ block_idx, num_blocks);
+
+ spin_unlock(&dm->lock);
+
+ if (block_idx >= max_blocks)
+ return -ENOMEM;
+
+ sw_icm = MLX5_ADDR_OF(create_sw_icm_in, in, sw_icm);
+ icm_start_addr += block_idx << MLX5_LOG_SW_ICM_BLOCK_SIZE(dev);
+ MLX5_SET64(sw_icm, sw_icm, sw_icm_start_addr,
+ icm_start_addr);
+ MLX5_SET(sw_icm, sw_icm, log_sw_icm_size, ilog2(length));
+
+ ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+ if (ret) {
+ spin_lock(&dm->lock);
+ bitmap_clear(block_map,
+ block_idx, num_blocks);
+ spin_unlock(&dm->lock);
+
+ return ret;
+ }
+
+ *addr = icm_start_addr;
+ *obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx5_dm_sw_icm_alloc);
+
+int mlx5_dm_sw_icm_dealloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type,
+ u64 length, u16 uid, phys_addr_t addr, u32 obj_id)
+{
+ u32 num_blocks = DIV_ROUND_UP_ULL(length, MLX5_SW_ICM_BLOCK_SIZE(dev));
+ u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
+ u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
+ struct mlx5_dm *dm = dev->dm;
+ unsigned long *block_map;
+ u64 icm_start_addr;
+ u64 start_idx;
+ int err;
+
+ if (!dev->dm)
+ return -EOPNOTSUPP;
+
+ switch (type) {
+ case MLX5_SW_ICM_TYPE_STEERING:
+ icm_start_addr = MLX5_CAP64_DEV_MEM(dev, steering_sw_icm_start_address);
+ block_map = dm->steering_sw_icm_alloc_blocks;
+ break;
+ case MLX5_SW_ICM_TYPE_HEADER_MODIFY:
+ icm_start_addr = MLX5_CAP64_DEV_MEM(dev, header_modify_sw_icm_start_address);
+ block_map = dm->header_modify_sw_icm_alloc_blocks;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
+ MLX5_CMD_OP_DESTROY_GENERAL_OBJECT);
+ MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_SW_ICM);
+ MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, obj_id);
+ MLX5_SET(general_obj_in_cmd_hdr, in, uid, uid);
+
+ err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+ if (err)
+ return err;
+
+ start_idx = (addr - icm_start_addr) >> MLX5_LOG_SW_ICM_BLOCK_SIZE(dev);
+ spin_lock(&dm->lock);
+ bitmap_clear(block_map,
+ start_idx, num_blocks);
+ spin_unlock(&dm->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx5_dm_sw_icm_dealloc);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 7f70ecb1db6d..c1679d11d71f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -879,6 +879,10 @@ static int mlx5_init_once(struct mlx5_core_dev *dev)
goto err_eswitch_cleanup;
}
+ dev->dm = mlx5_dm_create(dev);
+ if (IS_ERR(dev->dm))
+ mlx5_core_warn(dev, "Failed to init device memory%d\n", err);
+
dev->tracer = mlx5_fw_tracer_create(dev);
return 0;
@@ -912,6 +916,7 @@ static int mlx5_init_once(struct mlx5_core_dev *dev)
static void mlx5_cleanup_once(struct mlx5_core_dev *dev)
{
mlx5_fw_tracer_destroy(dev->tracer);
+ mlx5_dm_cleanup(dev);
mlx5_fpga_cleanup(dev);
mlx5_eswitch_cleanup(dev->priv.eswitch);
mlx5_sriov_cleanup(dev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index 471bbc48bc1f..bbcf4ee40ad5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -198,6 +198,9 @@ int mlx5_set_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size);
int mlx5_query_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 *arm, u8 *mode);
int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode);
+struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev);
+void mlx5_dm_cleanup(struct mlx5_core_dev *dev);
+
#define MLX5_PPS_CAP(mdev) (MLX5_CAP_GEN((mdev), pps) && \
MLX5_CAP_GEN((mdev), pps_modify) && \
MLX5_CAP_MCAM_FEATURE((mdev), mtpps_fs) && \
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index 0acd28f2e62c..72bc6ce44b55 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -622,6 +622,11 @@ struct mlx5e_resources {
struct mlx5_sq_bfreg bfreg;
};
+enum mlx5_sw_icm_type {
+ MLX5_SW_ICM_TYPE_STEERING,
+ MLX5_SW_ICM_TYPE_HEADER_MODIFY,
+};
+
#define MLX5_MAX_RESERVED_GIDS 8
struct mlx5_rsvd_gids {
@@ -653,10 +658,14 @@ struct mlx5_clock {
struct mlx5_pps pps_info;
};
+struct mlx5_dm;
struct mlx5_fw_tracer;
struct mlx5_vxlan;
struct mlx5_geneve;
+#define MLX5_LOG_SW_ICM_BLOCK_SIZE(dev) (MLX5_CAP_DEV_MEM(dev, log_sw_icm_alloc_granularity))
+#define MLX5_SW_ICM_BLOCK_SIZE(dev) (1 << MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))
+
struct mlx5_core_dev {
struct device *device;
enum mlx5_coredev_type coredev_type;
@@ -690,6 +699,7 @@ struct mlx5_core_dev {
atomic_t num_qps;
u32 issi;
struct mlx5e_resources mlx5e_res;
+ struct mlx5_dm *dm;
struct mlx5_vxlan *vxlan;
struct mlx5_geneve *geneve;
struct {
@@ -1072,6 +1082,10 @@ int mlx5_lag_query_cong_counters(struct mlx5_core_dev *dev,
size_t *offsets);
struct mlx5_uars_page *mlx5_get_uars_page(struct mlx5_core_dev *mdev);
void mlx5_put_uars_page(struct mlx5_core_dev *mdev, struct mlx5_uars_page *up);
+int mlx5_dm_sw_icm_alloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type,
+ u64 length, u16 uid, phys_addr_t *addr, u32 *obj_id);
+int mlx5_dm_sw_icm_dealloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type,
+ u64 length, u16 uid, phys_addr_t addr, u32 obj_id);
#ifdef CONFIG_MLX5_CORE_IPOIB
struct net_device *mlx5_rdma_netdev_alloc(struct mlx5_core_dev *mdev,
--
2.21.0
^ permalink raw reply related
* [PATCH mlx5-next 2/5] net/mlx5: Add HW bits and definitions required for SW steering
From: Saeed Mahameed @ 2019-08-29 23:42 UTC (permalink / raw)
To: Saeed Mahameed, Leon Romanovsky
Cc: netdev@vger.kernel.org, linux-rdma@vger.kernel.org, Alex Vesker,
Yevgeny Klitenik, Mark Bloch
In-Reply-To: <20190829234151.9958-1-saeedm@mellanox.com>
From: Alex Vesker <valex@mellanox.com>
Add the required Software Steering hardware definitions and
bits to mlx5_ifc.
Signed-off-by: Alex Vesker <valex@mellanox.com>
Signed-off-by: Yevgeny Klitenik <kliten@mellanox.com>
Reviewed-by: Mark Bloch <markb@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
include/linux/mlx5/device.h | 7 +
include/linux/mlx5/mlx5_ifc.h | 235 ++++++++++++++++++++++++++++------
2 files changed, 205 insertions(+), 37 deletions(-)
diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h
index ce9839c8bc1a..5767d7fab5f3 100644
--- a/include/linux/mlx5/device.h
+++ b/include/linux/mlx5/device.h
@@ -1162,6 +1162,9 @@ enum mlx5_qcam_feature_groups {
#define MLX5_CAP_FLOWTABLE(mdev, cap) \
MLX5_GET(flow_table_nic_cap, mdev->caps.hca_cur[MLX5_CAP_FLOW_TABLE], cap)
+#define MLX5_CAP64_FLOWTABLE(mdev, cap) \
+ MLX5_GET64(flow_table_nic_cap, (mdev)->caps.hca_cur[MLX5_CAP_FLOW_TABLE], cap)
+
#define MLX5_CAP_FLOWTABLE_MAX(mdev, cap) \
MLX5_GET(flow_table_nic_cap, mdev->caps.hca_max[MLX5_CAP_FLOW_TABLE], cap)
@@ -1225,6 +1228,10 @@ enum mlx5_qcam_feature_groups {
MLX5_GET(e_switch_cap, \
mdev->caps.hca_cur[MLX5_CAP_ESWITCH], cap)
+#define MLX5_CAP64_ESW_FLOWTABLE(mdev, cap) \
+ MLX5_GET64(flow_table_eswitch_cap, \
+ (mdev)->caps.hca_cur[MLX5_CAP_ESWITCH_FLOW_TABLE], cap)
+
#define MLX5_CAP_ESW_MAX(mdev, cap) \
MLX5_GET(e_switch_cap, \
mdev->caps.hca_max[MLX5_CAP_ESWITCH], cap)
diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
index 4e278114d8b3..76e945dbc7ed 100644
--- a/include/linux/mlx5/mlx5_ifc.h
+++ b/include/linux/mlx5/mlx5_ifc.h
@@ -282,6 +282,7 @@ enum {
MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT = 0x940,
MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT = 0x941,
MLX5_CMD_OP_QUERY_MODIFY_HEADER_CONTEXT = 0x942,
+ MLX5_CMD_OP_SYNC_STEERING = 0xb00,
MLX5_CMD_OP_FPGA_CREATE_QP = 0x960,
MLX5_CMD_OP_FPGA_MODIFY_QP = 0x961,
MLX5_CMD_OP_FPGA_QUERY_QP = 0x962,
@@ -485,7 +486,11 @@ union mlx5_ifc_gre_key_bits {
};
struct mlx5_ifc_fte_match_set_misc_bits {
- u8 reserved_at_0[0x8];
+ u8 gre_c_present[0x1];
+ u8 reserved_auto1[0x1];
+ u8 gre_k_present[0x1];
+ u8 gre_s_present[0x1];
+ u8 source_vhca_port[0x4];
u8 source_sqn[0x18];
u8 source_eswitch_owner_vhca_id[0x10];
@@ -565,12 +570,38 @@ struct mlx5_ifc_fte_match_set_misc2_bits {
u8 metadata_reg_a[0x20];
- u8 reserved_at_1a0[0x60];
+ u8 metadata_reg_b[0x20];
+
+ u8 reserved_at_1c0[0x40];
};
struct mlx5_ifc_fte_match_set_misc3_bits {
- u8 reserved_at_0[0x120];
+ u8 inner_tcp_seq_num[0x20];
+
+ u8 outer_tcp_seq_num[0x20];
+
+ u8 inner_tcp_ack_num[0x20];
+
+ u8 outer_tcp_ack_num[0x20];
+
+ u8 reserved_at_80[0x8];
+ u8 outer_vxlan_gpe_vni[0x18];
+
+ u8 outer_vxlan_gpe_next_protocol[0x8];
+ u8 outer_vxlan_gpe_flags[0x8];
+ u8 reserved_at_b0[0x10];
+
+ u8 icmp_header_data[0x20];
+
+ u8 icmpv6_header_data[0x20];
+
+ u8 icmp_type[0x8];
+ u8 icmp_code[0x8];
+ u8 icmpv6_type[0x8];
+ u8 icmpv6_code[0x8];
+
u8 geneve_tlv_option_0_data[0x20];
+
u8 reserved_at_140[0xc0];
};
@@ -666,7 +697,15 @@ struct mlx5_ifc_flow_table_nic_cap_bits {
struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_nic_transmit_sniffer;
- u8 reserved_at_e00[0x7200];
+ u8 reserved_at_e00[0x1200];
+
+ u8 sw_steering_nic_rx_action_drop_icm_address[0x40];
+
+ u8 sw_steering_nic_tx_action_drop_icm_address[0x40];
+
+ u8 sw_steering_nic_tx_action_allow_icm_address[0x40];
+
+ u8 reserved_at_20c0[0x5f40];
};
enum {
@@ -698,7 +737,17 @@ struct mlx5_ifc_flow_table_eswitch_cap_bits {
struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_esw_acl_egress;
- u8 reserved_at_800[0x7800];
+ u8 reserved_at_800[0x1000];
+
+ u8 sw_steering_fdb_action_drop_icm_address_rx[0x40];
+
+ u8 sw_steering_fdb_action_drop_icm_address_tx[0x40];
+
+ u8 sw_steering_uplink_icm_address_rx[0x40];
+
+ u8 sw_steering_uplink_icm_address_tx[0x40];
+
+ u8 reserved_at_1900[0x6700];
};
enum {
@@ -849,6 +898,25 @@ struct mlx5_ifc_roce_cap_bits {
u8 reserved_at_100[0x700];
};
+struct mlx5_ifc_sync_steering_in_bits {
+ u8 opcode[0x10];
+ u8 uid[0x10];
+
+ u8 reserved_at_20[0x10];
+ u8 op_mod[0x10];
+
+ u8 reserved_at_40[0xc0];
+};
+
+struct mlx5_ifc_sync_steering_out_bits {
+ u8 status[0x8];
+ u8 reserved_at_8[0x18];
+
+ u8 syndrome[0x20];
+
+ u8 reserved_at_40[0x40];
+};
+
struct mlx5_ifc_device_mem_cap_bits {
u8 memic[0x1];
u8 reserved_at_1[0x1f];
@@ -1041,6 +1109,12 @@ enum {
MLX5_CAP_UMR_FENCE_NONE = 0x2,
};
+enum {
+ MLX5_FLEX_PARSER_VXLAN_GPE_ENABLED = 1 << 7,
+ MLX5_FLEX_PARSER_ICMP_V4_ENABLED = 1 << 8,
+ MLX5_FLEX_PARSER_ICMP_V6_ENABLED = 1 << 9,
+};
+
enum {
MLX5_UCTX_CAP_RAW_TX = 1UL << 0,
MLX5_UCTX_CAP_INTERNAL_DEV_RES = 1UL << 1,
@@ -1414,7 +1488,14 @@ struct mlx5_ifc_cmd_hca_cap_bits {
u8 reserved_at_6c0[0x4];
u8 flex_parser_id_geneve_tlv_option_0[0x4];
- u8 reserved_at_6c8[0x28];
+ u8 flex_parser_id_icmp_dw1[0x4];
+ u8 flex_parser_id_icmp_dw0[0x4];
+ u8 flex_parser_id_icmpv6_dw1[0x4];
+ u8 flex_parser_id_icmpv6_dw0[0x4];
+ u8 flex_parser_id_outer_first_mpls_over_gre[0x4];
+ u8 flex_parser_id_outer_first_mpls_over_udp_label[0x4];
+
+ u8 reserved_at_6e0[0x10];
u8 sf_base_id[0x10];
u8 reserved_at_700[0x80];
@@ -2652,6 +2733,7 @@ union mlx5_ifc_hca_cap_union_bits {
struct mlx5_ifc_debug_cap_bits debug_cap;
struct mlx5_ifc_fpga_cap_bits fpga_cap;
struct mlx5_ifc_tls_cap_bits tls_cap;
+ struct mlx5_ifc_device_mem_cap_bits device_mem_cap;
u8 reserved_at_0[0x8000];
};
@@ -3255,7 +3337,11 @@ struct mlx5_ifc_esw_vport_context_bits {
u8 cvlan_pcp[0x3];
u8 cvlan_id[0xc];
- u8 reserved_at_60[0x7a0];
+ u8 reserved_at_60[0x720];
+
+ u8 sw_steering_vport_icm_address_rx[0x40];
+
+ u8 sw_steering_vport_icm_address_tx[0x40];
};
enum {
@@ -4941,23 +5027,98 @@ struct mlx5_ifc_query_hca_cap_in_bits {
u8 reserved_at_20[0x10];
u8 op_mod[0x10];
- u8 reserved_at_40[0x40];
+ u8 other_function[0x1];
+ u8 reserved_at_41[0xf];
+ u8 function_id[0x10];
+
+ u8 reserved_at_60[0x20];
};
-struct mlx5_ifc_query_flow_table_out_bits {
+struct mlx5_ifc_other_hca_cap_bits {
+ u8 roce[0x1];
+ u8 reserved_0[0x27f];
+};
+
+struct mlx5_ifc_query_other_hca_cap_out_bits {
u8 status[0x8];
- u8 reserved_at_8[0x18];
+ u8 reserved_0[0x18];
u8 syndrome[0x20];
- u8 reserved_at_40[0x80];
+ u8 reserved_1[0x40];
- u8 reserved_at_c0[0x8];
+ struct mlx5_ifc_other_hca_cap_bits other_capability;
+};
+
+struct mlx5_ifc_query_other_hca_cap_in_bits {
+ u8 opcode[0x10];
+ u8 reserved_0[0x10];
+
+ u8 reserved_1[0x10];
+ u8 op_mod[0x10];
+
+ u8 reserved_2[0x10];
+ u8 function_id[0x10];
+
+ u8 reserved_3[0x20];
+};
+
+struct mlx5_ifc_modify_other_hca_cap_out_bits {
+ u8 status[0x8];
+ u8 reserved_0[0x18];
+
+ u8 syndrome[0x20];
+
+ u8 reserved_1[0x40];
+};
+
+struct mlx5_ifc_modify_other_hca_cap_in_bits {
+ u8 opcode[0x10];
+ u8 reserved_0[0x10];
+
+ u8 reserved_1[0x10];
+ u8 op_mod[0x10];
+
+ u8 reserved_2[0x10];
+ u8 function_id[0x10];
+ u8 field_select[0x20];
+
+ struct mlx5_ifc_other_hca_cap_bits other_capability;
+};
+
+struct mlx5_ifc_flow_table_context_bits {
+ u8 reformat_en[0x1];
+ u8 decap_en[0x1];
+ u8 sw_owner[0x1];
+ u8 termination_table[0x1];
+ u8 table_miss_action[0x4];
u8 level[0x8];
- u8 reserved_at_d0[0x8];
+ u8 reserved_at_10[0x8];
u8 log_size[0x8];
- u8 reserved_at_e0[0x120];
+ u8 reserved_at_20[0x8];
+ u8 table_miss_id[0x18];
+
+ u8 reserved_at_40[0x8];
+ u8 lag_master_next_table_id[0x18];
+
+ u8 reserved_at_60[0x60];
+
+ u8 sw_owner_icm_root_1[0x40];
+
+ u8 sw_owner_icm_root_0[0x40];
+
+};
+
+struct mlx5_ifc_query_flow_table_out_bits {
+ u8 status[0x8];
+ u8 reserved_at_8[0x18];
+
+ u8 syndrome[0x20];
+
+ u8 reserved_at_40[0x80];
+
+ struct mlx5_ifc_flow_table_context_bits flow_table_context;
};
struct mlx5_ifc_query_flow_table_in_bits {
@@ -5227,7 +5388,7 @@ struct mlx5_ifc_alloc_packet_reformat_context_out_bits {
u8 reserved_at_60[0x20];
};
-enum {
+enum mlx5_reformat_ctx_type {
MLX5_REFORMAT_TYPE_L2_TO_VXLAN = 0x0,
MLX5_REFORMAT_TYPE_L2_TO_NVGRE = 0x1,
MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL = 0x2,
@@ -5323,7 +5484,16 @@ enum {
MLX5_ACTION_IN_FIELD_OUT_DIPV4 = 0x16,
MLX5_ACTION_IN_FIELD_OUT_FIRST_VID = 0x17,
MLX5_ACTION_IN_FIELD_OUT_IPV6_HOPLIMIT = 0x47,
+ MLX5_ACTION_IN_FIELD_METADATA_REG_A = 0x49,
+ MLX5_ACTION_IN_FIELD_METADATA_REG_B = 0x50,
MLX5_ACTION_IN_FIELD_METADATA_REG_C_0 = 0x51,
+ MLX5_ACTION_IN_FIELD_METADATA_REG_C_1 = 0x52,
+ MLX5_ACTION_IN_FIELD_METADATA_REG_C_2 = 0x53,
+ MLX5_ACTION_IN_FIELD_METADATA_REG_C_3 = 0x54,
+ MLX5_ACTION_IN_FIELD_METADATA_REG_C_4 = 0x55,
+ MLX5_ACTION_IN_FIELD_METADATA_REG_C_5 = 0x56,
+ MLX5_ACTION_IN_FIELD_OUT_TCP_SEQ_NUM = 0x59,
+ MLX5_ACTION_IN_FIELD_OUT_TCP_ACK_NUM = 0x5B,
};
struct mlx5_ifc_alloc_modify_header_context_out_bits {
@@ -7369,35 +7539,26 @@ struct mlx5_ifc_create_mkey_in_bits {
u8 klm_pas_mtt[0][0x20];
};
+enum {
+ MLX5_FLOW_TABLE_TYPE_NIC_RX = 0x0,
+ MLX5_FLOW_TABLE_TYPE_NIC_TX = 0x1,
+ MLX5_FLOW_TABLE_TYPE_ESW_EGRESS_ACL = 0x2,
+ MLX5_FLOW_TABLE_TYPE_ESW_INGRESS_ACL = 0x3,
+ MLX5_FLOW_TABLE_TYPE_FDB = 0X4,
+ MLX5_FLOW_TABLE_TYPE_SNIFFER_RX = 0X5,
+ MLX5_FLOW_TABLE_TYPE_SNIFFER_TX = 0X6,
+};
+
struct mlx5_ifc_create_flow_table_out_bits {
u8 status[0x8];
- u8 reserved_at_8[0x18];
+ u8 icm_address_63_40[0x18];
u8 syndrome[0x20];
- u8 reserved_at_40[0x8];
+ u8 icm_address_39_32[0x8];
u8 table_id[0x18];
- u8 reserved_at_60[0x20];
-};
-
-struct mlx5_ifc_flow_table_context_bits {
- u8 reformat_en[0x1];
- u8 decap_en[0x1];
- u8 reserved_at_2[0x1];
- u8 termination_table[0x1];
- u8 table_miss_action[0x4];
- u8 level[0x8];
- u8 reserved_at_10[0x8];
- u8 log_size[0x8];
-
- u8 reserved_at_20[0x8];
- u8 table_miss_id[0x18];
-
- u8 reserved_at_40[0x8];
- u8 lag_master_next_table_id[0x18];
-
- u8 reserved_at_60[0xe0];
+ u8 icm_address_31_0[0x20];
};
struct mlx5_ifc_create_flow_table_in_bits {
--
2.21.0
^ permalink raw reply related
* [PATCH mlx5-next 3/5] net/mlx5: Avoid disabling RoCE when uninitialized
From: Saeed Mahameed @ 2019-08-29 23:42 UTC (permalink / raw)
To: Saeed Mahameed, Leon Romanovsky
Cc: netdev@vger.kernel.org, linux-rdma@vger.kernel.org, Maor Gottlieb,
Mark Bloch
In-Reply-To: <20190829234151.9958-1-saeedm@mellanox.com>
From: Maor Gottlieb <maorg@mellanox.com>
Move the check if RoCE steering is initialized to the
disable RoCE function, it will ensure that we disable
RoCE only if we succeeded in enabling it before.
Fixes: 80f09dfc237f ("net/mlx5: Eswitch, enable RoCE loopback traffic")
Signed-off-by: Maor Gottlieb <maorg@mellanox.com>
Reviewed-by: Mark Bloch <markb@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx5/core/rdma.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/rdma.c b/drivers/net/ethernet/mellanox/mlx5/core/rdma.c
index 18af6981e0be..0fc7de4aa572 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/rdma.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/rdma.c
@@ -14,9 +14,6 @@ static void mlx5_rdma_disable_roce_steering(struct mlx5_core_dev *dev)
{
struct mlx5_core_roce *roce = &dev->priv.roce;
- if (!roce->ft)
- return;
-
mlx5_del_flow_rules(roce->allow_rule);
mlx5_destroy_flow_group(roce->fg);
mlx5_destroy_flow_table(roce->ft);
@@ -145,6 +142,11 @@ static int mlx5_rdma_add_roce_addr(struct mlx5_core_dev *dev)
void mlx5_rdma_disable_roce(struct mlx5_core_dev *dev)
{
+ struct mlx5_core_roce *roce = &dev->priv.roce;
+
+ if (!roce->ft)
+ return;
+
mlx5_rdma_disable_roce_steering(dev);
mlx5_rdma_del_roce_addr(dev);
mlx5_nic_vport_disable_roce(dev);
--
2.21.0
^ permalink raw reply related
* [PATCH mlx5-next 4/5] net/mlx5: Add stub for mlx5_eswitch_mode
From: Saeed Mahameed @ 2019-08-29 23:42 UTC (permalink / raw)
To: Saeed Mahameed, Leon Romanovsky
Cc: netdev@vger.kernel.org, linux-rdma@vger.kernel.org, Maor Gottlieb,
Mark Bloch
In-Reply-To: <20190829234151.9958-1-saeedm@mellanox.com>
From: Maor Gottlieb <maorg@mellanox.com>
Return MLX5_ESWITCH_NONE when CONFIG_MLX5_ESWITCH
is not selected.
Signed-off-by: Maor Gottlieb <maorg@mellanox.com>
Reviewed-by: Mark Bloch <markb@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
include/linux/mlx5/eswitch.h | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/include/linux/mlx5/eswitch.h b/include/linux/mlx5/eswitch.h
index 46b5ba029802..825920d3ca40 100644
--- a/include/linux/mlx5/eswitch.h
+++ b/include/linux/mlx5/eswitch.h
@@ -61,7 +61,6 @@ void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw,
struct mlx5_eswitch_rep *mlx5_eswitch_vport_rep(struct mlx5_eswitch *esw,
u16 vport_num);
void *mlx5_eswitch_uplink_get_proto_dev(struct mlx5_eswitch *esw, u8 rep_type);
-u8 mlx5_eswitch_mode(struct mlx5_eswitch *esw);
struct mlx5_flow_handle *
mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *esw,
u16 vport_num, u32 sqn);
@@ -75,7 +74,14 @@ mlx5_eswitch_get_encap_mode(const struct mlx5_core_dev *dev);
bool mlx5_eswitch_vport_match_metadata_enabled(const struct mlx5_eswitch *esw);
u32 mlx5_eswitch_get_vport_metadata_for_match(const struct mlx5_eswitch *esw,
u16 vport_num);
+u8 mlx5_eswitch_mode(struct mlx5_eswitch *esw);
#else /* CONFIG_MLX5_ESWITCH */
+
+static inline u8 mlx5_eswitch_mode(struct mlx5_eswitch *esw)
+{
+ return MLX5_ESWITCH_NONE;
+}
+
static inline enum devlink_eswitch_encap_mode
mlx5_eswitch_get_encap_mode(const struct mlx5_core_dev *dev)
{
--
2.21.0
^ permalink raw reply related
* [PATCH mlx5-next 5/5] net/mlx5: Set only stag for match untagged packets
From: Saeed Mahameed @ 2019-08-29 23:42 UTC (permalink / raw)
To: Saeed Mahameed, Leon Romanovsky
Cc: netdev@vger.kernel.org, linux-rdma@vger.kernel.org, Mark Bloch
In-Reply-To: <20190829234151.9958-1-saeedm@mellanox.com>
From: Mark Bloch <markb@mellanox.com>
cvlan_tag enabled in match criteria and disabled in
match value means both S & C tags don't exist (untagged of both).
Signed-off-by: Mark Bloch <markb@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index cc096f6011d9..9e9b41ab392b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -1593,7 +1593,10 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
*match_level = MLX5_MATCH_L2;
}
} else if (*match_level != MLX5_MATCH_NONE) {
- MLX5_SET(fte_match_set_lyr_2_4, headers_c, svlan_tag, 1);
+ /* cvlan_tag enabled in match criteria and
+ * disabled in match value means both S & C tags
+ * don't exist (untagged of both)
+ */
MLX5_SET(fte_match_set_lyr_2_4, headers_c, cvlan_tag, 1);
*match_level = MLX5_MATCH_L2;
}
--
2.21.0
^ permalink raw reply related
* Re: pull-request: mac80211 2019-08-29
From: David Miller @ 2019-08-29 23:44 UTC (permalink / raw)
To: johannes; +Cc: netdev, linux-wireless
In-Reply-To: <20190829150011.10512-1-johannes@sipsolutions.net>
From: Johannes Berg <johannes@sipsolutions.net>
Date: Thu, 29 Aug 2019 17:00:10 +0200
> We have just three more fixes now, and one of those is a driver fix
> because Kalle is on vacation and I'm covering for him in the meantime.
>
> Please pull and let me know if there's any problem.
Ok, pulled, thanks.
^ permalink raw reply
* Re: [PATCH net-next v3 1/3] dpaa2-eth: Remove support for changing link settings
From: David Miller @ 2019-08-29 23:54 UTC (permalink / raw)
To: ruxandra.radulescu; +Cc: netdev, andrew, ioana.ciornei
In-Reply-To: <1567001295-31801-1-git-send-email-ruxandra.radulescu@nxp.com>
From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
Date: Wed, 28 Aug 2019 17:08:13 +0300
> We only support fixed-link for now, so there is no point in
> offering users the option to change link settings via ethtool.
>
> Functionally there is no change, since firmware prevents us from
> changing link parameters anyway.
>
> Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
> Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Applied.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox