| /* net/core/xdp.c |
| * |
| * Copyright (c) 2017 Jesper Dangaard Brouer, Red Hat Inc. |
| * Released under terms in GPL version 2. See COPYING. |
| */ |
| #include <linux/types.h> |
| #include <linux/mm.h> |
| |
| #include <net/xdp.h> |
| |
| #define REG_STATE_NEW 0x0 |
| #define REG_STATE_REGISTERED 0x1 |
| #define REG_STATE_UNREGISTERED 0x2 |
| #define REG_STATE_UNUSED 0x3 |
| |
| void xdp_rxq_info_unreg(struct xdp_rxq_info *xdp_rxq) |
| { |
| /* Simplify driver cleanup code paths, allow unreg "unused" */ |
| if (xdp_rxq->reg_state == REG_STATE_UNUSED) |
| return; |
| |
| WARN(!(xdp_rxq->reg_state == REG_STATE_REGISTERED), "Driver BUG"); |
| |
| xdp_rxq->reg_state = REG_STATE_UNREGISTERED; |
| xdp_rxq->dev = NULL; |
| } |
| EXPORT_SYMBOL_GPL(xdp_rxq_info_unreg); |
| |
| static void xdp_rxq_info_init(struct xdp_rxq_info *xdp_rxq) |
| { |
| memset(xdp_rxq, 0, sizeof(*xdp_rxq)); |
| } |
| |
| /* Returns 0 on success, negative on failure */ |
| int xdp_rxq_info_reg(struct xdp_rxq_info *xdp_rxq, |
| struct net_device *dev, u32 queue_index) |
| { |
| if (xdp_rxq->reg_state == REG_STATE_UNUSED) { |
| WARN(1, "Driver promised not to register this"); |
| return -EINVAL; |
| } |
| |
| if (xdp_rxq->reg_state == REG_STATE_REGISTERED) { |
| WARN(1, "Missing unregister, handled but fix driver"); |
| xdp_rxq_info_unreg(xdp_rxq); |
| } |
| |
| if (!dev) { |
| WARN(1, "Missing net_device from driver"); |
| return -ENODEV; |
| } |
| |
| /* State either UNREGISTERED or NEW */ |
| xdp_rxq_info_init(xdp_rxq); |
| xdp_rxq->dev = dev; |
| xdp_rxq->queue_index = queue_index; |
| |
| xdp_rxq->reg_state = REG_STATE_REGISTERED; |
| return 0; |
| } |
| EXPORT_SYMBOL_GPL(xdp_rxq_info_reg); |
| |
| void xdp_rxq_info_unused(struct xdp_rxq_info *xdp_rxq) |
| { |
| xdp_rxq->reg_state = REG_STATE_UNUSED; |
| } |
| EXPORT_SYMBOL_GPL(xdp_rxq_info_unused); |
| |
| bool xdp_rxq_info_is_reg(struct xdp_rxq_info *xdp_rxq) |
| { |
| return (xdp_rxq->reg_state == REG_STATE_REGISTERED); |
| } |
| EXPORT_SYMBOL_GPL(xdp_rxq_info_is_reg); |