Commit 4d367963 authored by David S. Miller's avatar David S. Miller

Merge branch 'rocker-no-wait'

Scott Feldman says:

====================
rocker: revert back to support for nowait processes

One of the items removed from the rocker driver in the Spring Cleanup patch
series was the ability to mark processing in the driver as "no wait" for
those contexts where we cannot sleep.  Turns out, we have "no wait"
contexts where we want to program the device and we don't want to defer the
processing to a process context.  So re-add the ROCKER_OP_FLAG_NOWAIT flag
to mark such processes, and propagate flags to mem allocator and to the
device cmd executor.  With NOWAIT, mem allocs are GFP_ATOMIC and device
cmds are queued to the device, but the driver will not wait (sleep) for the
response back from the device.

My bad for removing NOWAIT support in the first place; I thought we could
swing non-sleep contexts to process context using a work queue, for
example, but there is push-back to keep processing in original context.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4d81db41 f66feaa9
......@@ -326,10 +326,18 @@ static bool rocker_port_is_bridged(const struct rocker_port *rocker_port)
return !!rocker_port->bridge_dev;
}
#define ROCKER_OP_FLAG_REMOVE BIT(0)
#define ROCKER_OP_FLAG_NOWAIT BIT(1)
#define ROCKER_OP_FLAG_LEARNED BIT(2)
#define ROCKER_OP_FLAG_REFRESH BIT(3)
static void *__rocker_port_mem_alloc(struct rocker_port *rocker_port,
enum switchdev_trans trans, size_t size)
enum switchdev_trans trans, int flags,
size_t size)
{
struct list_head *elem = NULL;
gfp_t gfp_flags = (flags & ROCKER_OP_FLAG_NOWAIT) ?
GFP_ATOMIC : GFP_KERNEL;
/* If in transaction prepare phase, allocate the memory
* and enqueue it on a per-port list. If in transaction
......@@ -342,7 +350,7 @@ static void *__rocker_port_mem_alloc(struct rocker_port *rocker_port,
switch (trans) {
case SWITCHDEV_TRANS_PREPARE:
elem = kzalloc(size + sizeof(*elem), GFP_KERNEL);
elem = kzalloc(size + sizeof(*elem), gfp_flags);
if (!elem)
return NULL;
list_add_tail(elem, &rocker_port->trans_mem);
......@@ -353,7 +361,7 @@ static void *__rocker_port_mem_alloc(struct rocker_port *rocker_port,
list_del_init(elem);
break;
case SWITCHDEV_TRANS_NONE:
elem = kzalloc(size + sizeof(*elem), GFP_KERNEL);
elem = kzalloc(size + sizeof(*elem), gfp_flags);
if (elem)
INIT_LIST_HEAD(elem);
break;
......@@ -365,16 +373,17 @@ static void *__rocker_port_mem_alloc(struct rocker_port *rocker_port,
}
static void *rocker_port_kzalloc(struct rocker_port *rocker_port,
enum switchdev_trans trans, size_t size)
enum switchdev_trans trans, int flags,
size_t size)
{
return __rocker_port_mem_alloc(rocker_port, trans, size);
return __rocker_port_mem_alloc(rocker_port, trans, flags, size);
}
static void *rocker_port_kcalloc(struct rocker_port *rocker_port,
enum switchdev_trans trans, size_t n,
size_t size)
enum switchdev_trans trans, int flags,
size_t n, size_t size)
{
return __rocker_port_mem_alloc(rocker_port, trans, n * size);
return __rocker_port_mem_alloc(rocker_port, trans, flags, n * size);
}
static void rocker_port_kfree(enum switchdev_trans trans, const void *mem)
......@@ -397,11 +406,13 @@ static void rocker_port_kfree(enum switchdev_trans trans, const void *mem)
struct rocker_wait {
wait_queue_head_t wait;
bool done;
bool nowait;
};
static void rocker_wait_reset(struct rocker_wait *wait)
{
wait->done = false;
wait->nowait = false;
}
static void rocker_wait_init(struct rocker_wait *wait)
......@@ -411,11 +422,12 @@ static void rocker_wait_init(struct rocker_wait *wait)
}
static struct rocker_wait *rocker_wait_create(struct rocker_port *rocker_port,
enum switchdev_trans trans)
enum switchdev_trans trans,
int flags)
{
struct rocker_wait *wait;
wait = rocker_port_kzalloc(rocker_port, trans, sizeof(*wait));
wait = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*wait));
if (!wait)
return NULL;
rocker_wait_init(wait);
......@@ -1386,7 +1398,12 @@ static irqreturn_t rocker_cmd_irq_handler(int irq, void *dev_id)
spin_lock(&rocker->cmd_ring_lock);
while ((desc_info = rocker_desc_tail_get(&rocker->cmd_ring))) {
wait = rocker_desc_cookie_ptr_get(desc_info);
rocker_wait_wake_up(wait);
if (wait->nowait) {
rocker_desc_gen_clear(desc_info);
rocker_wait_destroy(SWITCHDEV_TRANS_NONE, wait);
} else {
rocker_wait_wake_up(wait);
}
credits++;
}
spin_unlock(&rocker->cmd_ring_lock);
......@@ -1437,45 +1454,19 @@ static int rocker_event_link_change(const struct rocker *rocker,
return 0;
}
#define ROCKER_OP_FLAG_REMOVE BIT(0)
#define ROCKER_OP_FLAG_LEARNED BIT(1)
#define ROCKER_OP_FLAG_REFRESH BIT(2)
static int rocker_port_fdb(struct rocker_port *rocker_port,
enum switchdev_trans trans,
const unsigned char *addr,
__be16 vlan_id, int flags);
struct rocker_mac_vlan_seen_work {
struct work_struct work;
struct rocker_port *rocker_port;
int flags;
unsigned char addr[ETH_ALEN];
__be16 vlan_id;
};
static void rocker_event_mac_vlan_seen_work(struct work_struct *work)
{
const struct rocker_mac_vlan_seen_work *sw =
container_of(work, struct rocker_mac_vlan_seen_work, work);
rtnl_lock();
rocker_port_fdb(sw->rocker_port, SWITCHDEV_TRANS_NONE,
sw->addr, sw->vlan_id, sw->flags);
rtnl_unlock();
kfree(work);
}
static int rocker_event_mac_vlan_seen(const struct rocker *rocker,
const struct rocker_tlv *info)
{
struct rocker_mac_vlan_seen_work *sw;
const struct rocker_tlv *attrs[ROCKER_TLV_EVENT_MAC_VLAN_MAX + 1];
unsigned int port_number;
struct rocker_port *rocker_port;
const unsigned char *addr;
int flags = ROCKER_OP_FLAG_LEARNED;
int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_LEARNED;
__be16 vlan_id;
rocker_tlv_parse_nested(attrs, ROCKER_TLV_EVENT_MAC_VLAN_MAX, info);
......@@ -1497,20 +1488,8 @@ static int rocker_event_mac_vlan_seen(const struct rocker *rocker,
rocker_port->stp_state != BR_STATE_FORWARDING)
return 0;
sw = kmalloc(sizeof(*sw), GFP_ATOMIC);
if (!sw)
return -ENOMEM;
INIT_WORK(&sw->work, rocker_event_mac_vlan_seen_work);
sw->rocker_port = rocker_port;
sw->flags = flags;
ether_addr_copy(sw->addr, addr);
sw->vlan_id = vlan_id;
schedule_work(&sw->work);
return 0;
return rocker_port_fdb(rocker_port, SWITCHDEV_TRANS_NONE,
addr, vlan_id, flags);
}
static int rocker_event_process(const struct rocker *rocker,
......@@ -1595,32 +1574,34 @@ typedef int (*rocker_cmd_proc_cb_t)(const struct rocker_port *rocker_port,
void *priv);
static int rocker_cmd_exec(struct rocker_port *rocker_port,
enum switchdev_trans trans,
enum switchdev_trans trans, int flags,
rocker_cmd_prep_cb_t prepare, void *prepare_priv,
rocker_cmd_proc_cb_t process, void *process_priv)
{
struct rocker *rocker = rocker_port->rocker;
struct rocker_desc_info *desc_info;
struct rocker_wait *wait;
unsigned long flags;
bool nowait = !!(flags & ROCKER_OP_FLAG_NOWAIT);
unsigned long lock_flags;
int err;
wait = rocker_wait_create(rocker_port, trans);
wait = rocker_wait_create(rocker_port, trans, flags);
if (!wait)
return -ENOMEM;
wait->nowait = nowait;
spin_lock_irqsave(&rocker->cmd_ring_lock, flags);
spin_lock_irqsave(&rocker->cmd_ring_lock, lock_flags);
desc_info = rocker_desc_head_get(&rocker->cmd_ring);
if (!desc_info) {
spin_unlock_irqrestore(&rocker->cmd_ring_lock, flags);
spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags);
err = -EAGAIN;
goto out;
}
err = prepare(rocker_port, desc_info, prepare_priv);
if (err) {
spin_unlock_irqrestore(&rocker->cmd_ring_lock, flags);
spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags);
goto out;
}
......@@ -1629,7 +1610,10 @@ static int rocker_cmd_exec(struct rocker_port *rocker_port,
if (trans != SWITCHDEV_TRANS_PREPARE)
rocker_desc_head_set(rocker, &rocker->cmd_ring, desc_info);
spin_unlock_irqrestore(&rocker->cmd_ring_lock, flags);
spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags);
if (nowait)
return 0;
if (trans != SWITCHDEV_TRANS_PREPARE)
if (!rocker_wait_event_timeout(wait, HZ / 10))
......@@ -1859,7 +1843,7 @@ rocker_cmd_set_port_learning_prep(const struct rocker_port *rocker_port,
static int rocker_cmd_get_port_settings_ethtool(struct rocker_port *rocker_port,
struct ethtool_cmd *ecmd)
{
return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE,
return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
rocker_cmd_get_port_settings_prep, NULL,
rocker_cmd_get_port_settings_ethtool_proc,
ecmd);
......@@ -1868,7 +1852,7 @@ static int rocker_cmd_get_port_settings_ethtool(struct rocker_port *rocker_port,
static int rocker_cmd_get_port_settings_macaddr(struct rocker_port *rocker_port,
unsigned char *macaddr)
{
return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE,
return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
rocker_cmd_get_port_settings_prep, NULL,
rocker_cmd_get_port_settings_macaddr_proc,
macaddr);
......@@ -1877,7 +1861,7 @@ static int rocker_cmd_get_port_settings_macaddr(struct rocker_port *rocker_port,
static int rocker_cmd_set_port_settings_ethtool(struct rocker_port *rocker_port,
struct ethtool_cmd *ecmd)
{
return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE,
return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
rocker_cmd_set_port_settings_ethtool_prep,
ecmd, NULL, NULL);
}
......@@ -1885,7 +1869,7 @@ static int rocker_cmd_set_port_settings_ethtool(struct rocker_port *rocker_port,
static int rocker_cmd_set_port_settings_macaddr(struct rocker_port *rocker_port,
unsigned char *macaddr)
{
return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE,
return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
rocker_cmd_set_port_settings_macaddr_prep,
macaddr, NULL, NULL);
}
......@@ -1893,7 +1877,7 @@ static int rocker_cmd_set_port_settings_macaddr(struct rocker_port *rocker_port,
static int rocker_port_set_learning(struct rocker_port *rocker_port,
enum switchdev_trans trans)
{
return rocker_cmd_exec(rocker_port, trans,
return rocker_cmd_exec(rocker_port, trans, 0,
rocker_cmd_set_port_learning_prep,
NULL, NULL, NULL);
}
......@@ -2409,17 +2393,17 @@ rocker_flow_tbl_find(const struct rocker *rocker,
}
static int rocker_flow_tbl_add(struct rocker_port *rocker_port,
enum switchdev_trans trans,
enum switchdev_trans trans, int flags,
struct rocker_flow_tbl_entry *match)
{
struct rocker *rocker = rocker_port->rocker;
struct rocker_flow_tbl_entry *found;
size_t key_len = match->key_len ? match->key_len : sizeof(found->key);
unsigned long flags;
unsigned long lock_flags;
match->key_crc32 = crc32(~0, &match->key, key_len);
spin_lock_irqsave(&rocker->flow_tbl_lock, flags);
spin_lock_irqsave(&rocker->flow_tbl_lock, lock_flags);
found = rocker_flow_tbl_find(rocker, match);
......@@ -2439,25 +2423,25 @@ static int rocker_flow_tbl_add(struct rocker_port *rocker_port,
if (trans != SWITCHDEV_TRANS_PREPARE)
hash_add(rocker->flow_tbl, &found->entry, found->key_crc32);
spin_unlock_irqrestore(&rocker->flow_tbl_lock, flags);
spin_unlock_irqrestore(&rocker->flow_tbl_lock, lock_flags);
return rocker_cmd_exec(rocker_port, trans, rocker_cmd_flow_tbl_add,
found, NULL, NULL);
return rocker_cmd_exec(rocker_port, trans, flags,
rocker_cmd_flow_tbl_add, found, NULL, NULL);
}
static int rocker_flow_tbl_del(struct rocker_port *rocker_port,
enum switchdev_trans trans,
enum switchdev_trans trans, int flags,
struct rocker_flow_tbl_entry *match)
{
struct rocker *rocker = rocker_port->rocker;
struct rocker_flow_tbl_entry *found;
size_t key_len = match->key_len ? match->key_len : sizeof(found->key);
unsigned long flags;
unsigned long lock_flags;
int err = 0;
match->key_crc32 = crc32(~0, &match->key, key_len);
spin_lock_irqsave(&rocker->flow_tbl_lock, flags);
spin_lock_irqsave(&rocker->flow_tbl_lock, lock_flags);
found = rocker_flow_tbl_find(rocker, match);
......@@ -2467,12 +2451,12 @@ static int rocker_flow_tbl_del(struct rocker_port *rocker_port,
found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL;
}
spin_unlock_irqrestore(&rocker->flow_tbl_lock, flags);
spin_unlock_irqrestore(&rocker->flow_tbl_lock, lock_flags);
rocker_port_kfree(trans, match);
if (found) {
err = rocker_cmd_exec(rocker_port, trans,
err = rocker_cmd_exec(rocker_port, trans, flags,
rocker_cmd_flow_tbl_del,
found, NULL, NULL);
rocker_port_kfree(trans, found);
......@@ -2486,9 +2470,9 @@ static int rocker_flow_tbl_do(struct rocker_port *rocker_port,
struct rocker_flow_tbl_entry *entry)
{
if (flags & ROCKER_OP_FLAG_REMOVE)
return rocker_flow_tbl_del(rocker_port, trans, entry);
return rocker_flow_tbl_del(rocker_port, trans, flags, entry);
else
return rocker_flow_tbl_add(rocker_port, trans, entry);
return rocker_flow_tbl_add(rocker_port, trans, flags, entry);
}
static int rocker_flow_tbl_ig_port(struct rocker_port *rocker_port,
......@@ -2498,7 +2482,7 @@ static int rocker_flow_tbl_ig_port(struct rocker_port *rocker_port,
{
struct rocker_flow_tbl_entry *entry;
entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry));
entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
......@@ -2520,7 +2504,7 @@ static int rocker_flow_tbl_vlan(struct rocker_port *rocker_port,
{
struct rocker_flow_tbl_entry *entry;
entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry));
entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
......@@ -2547,7 +2531,7 @@ static int rocker_flow_tbl_term_mac(struct rocker_port *rocker_port,
{
struct rocker_flow_tbl_entry *entry;
entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry));
entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
......@@ -2587,7 +2571,7 @@ static int rocker_flow_tbl_bridge(struct rocker_port *rocker_port,
bool dflt = !eth_dst || (eth_dst && eth_dst_mask);
bool wild = false;
entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry));
entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
......@@ -2637,7 +2621,7 @@ static int rocker_flow_tbl_ucast4_routing(struct rocker_port *rocker_port,
{
struct rocker_flow_tbl_entry *entry;
entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry));
entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
......@@ -2667,7 +2651,7 @@ static int rocker_flow_tbl_acl(struct rocker_port *rocker_port,
u32 priority;
struct rocker_flow_tbl_entry *entry;
entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry));
entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
......@@ -2735,14 +2719,14 @@ static void rocker_group_tbl_entry_free(enum switchdev_trans trans,
}
static int rocker_group_tbl_add(struct rocker_port *rocker_port,
enum switchdev_trans trans,
enum switchdev_trans trans, int flags,
struct rocker_group_tbl_entry *match)
{
struct rocker *rocker = rocker_port->rocker;
struct rocker_group_tbl_entry *found;
unsigned long flags;
unsigned long lock_flags;
spin_lock_irqsave(&rocker->group_tbl_lock, flags);
spin_lock_irqsave(&rocker->group_tbl_lock, lock_flags);
found = rocker_group_tbl_find(rocker, match);
......@@ -2760,22 +2744,22 @@ static int rocker_group_tbl_add(struct rocker_port *rocker_port,
if (trans != SWITCHDEV_TRANS_PREPARE)
hash_add(rocker->group_tbl, &found->entry, found->group_id);
spin_unlock_irqrestore(&rocker->group_tbl_lock, flags);
spin_unlock_irqrestore(&rocker->group_tbl_lock, lock_flags);
return rocker_cmd_exec(rocker_port, trans, rocker_cmd_group_tbl_add,
found, NULL, NULL);
return rocker_cmd_exec(rocker_port, trans, flags,
rocker_cmd_group_tbl_add, found, NULL, NULL);
}
static int rocker_group_tbl_del(struct rocker_port *rocker_port,
enum switchdev_trans trans,
enum switchdev_trans trans, int flags,
struct rocker_group_tbl_entry *match)
{
struct rocker *rocker = rocker_port->rocker;
struct rocker_group_tbl_entry *found;
unsigned long flags;
unsigned long lock_flags;
int err = 0;
spin_lock_irqsave(&rocker->group_tbl_lock, flags);
spin_lock_irqsave(&rocker->group_tbl_lock, lock_flags);
found = rocker_group_tbl_find(rocker, match);
......@@ -2785,12 +2769,12 @@ static int rocker_group_tbl_del(struct rocker_port *rocker_port,
found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL;
}
spin_unlock_irqrestore(&rocker->group_tbl_lock, flags);
spin_unlock_irqrestore(&rocker->group_tbl_lock, lock_flags);
rocker_group_tbl_entry_free(trans, match);
if (found) {
err = rocker_cmd_exec(rocker_port, trans,
err = rocker_cmd_exec(rocker_port, trans, flags,
rocker_cmd_group_tbl_del,
found, NULL, NULL);
rocker_group_tbl_entry_free(trans, found);
......@@ -2804,9 +2788,9 @@ static int rocker_group_tbl_do(struct rocker_port *rocker_port,
struct rocker_group_tbl_entry *entry)
{
if (flags & ROCKER_OP_FLAG_REMOVE)
return rocker_group_tbl_del(rocker_port, trans, entry);
return rocker_group_tbl_del(rocker_port, trans, flags, entry);
else
return rocker_group_tbl_add(rocker_port, trans, entry);
return rocker_group_tbl_add(rocker_port, trans, flags, entry);
}
static int rocker_group_l2_interface(struct rocker_port *rocker_port,
......@@ -2816,7 +2800,7 @@ static int rocker_group_l2_interface(struct rocker_port *rocker_port,
{
struct rocker_group_tbl_entry *entry;
entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry));
entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
......@@ -2833,15 +2817,15 @@ static int rocker_group_l2_fan_out(struct rocker_port *rocker_port,
{
struct rocker_group_tbl_entry *entry;
entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry));
entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
entry->group_id = group_id;
entry->group_count = group_count;
entry->group_ids = rocker_port_kcalloc(rocker_port, trans, group_count,
sizeof(u32));
entry->group_ids = rocker_port_kcalloc(rocker_port, trans, flags,
group_count, sizeof(u32));
if (!entry->group_ids) {
rocker_port_kfree(trans, entry);
return -ENOMEM;
......@@ -2868,7 +2852,7 @@ static int rocker_group_l3_unicast(struct rocker_port *rocker_port,
{
struct rocker_group_tbl_entry *entry;
entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry));
entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
......@@ -2951,7 +2935,7 @@ static int rocker_port_ipv4_neigh(struct rocker_port *rocker_port,
bool removing;
int err = 0;
entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry));
entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
......@@ -3067,7 +3051,7 @@ static int rocker_port_ipv4_nh(struct rocker_port *rocker_port,
bool resolved = true;
int err = 0;
entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry));
entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
......@@ -3124,8 +3108,8 @@ static int rocker_port_vlan_flood_group(struct rocker_port *rocker_port,
int err = 0;
int i;
group_ids = rocker_port_kcalloc(rocker_port, trans, rocker->port_count,
sizeof(u32));
group_ids = rocker_port_kcalloc(rocker_port, trans, flags,
rocker->port_count, sizeof(u32));
if (!group_ids)
return -ENOMEM;
......@@ -3550,7 +3534,7 @@ static int rocker_port_fdb_learn(struct rocker_port *rocker_port,
if (!rocker_port_is_bridged(rocker_port))
return 0;
lw = rocker_port_kzalloc(rocker_port, trans, sizeof(*lw));
lw = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*lw));
if (!lw)
return -ENOMEM;
......@@ -3594,7 +3578,7 @@ static int rocker_port_fdb(struct rocker_port *rocker_port,
bool removing = (flags & ROCKER_OP_FLAG_REMOVE);
unsigned long lock_flags;
fdb = rocker_port_kzalloc(rocker_port, trans, sizeof(*fdb));
fdb = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*fdb));
if (!fdb)
return -ENOMEM;
......@@ -3632,12 +3616,11 @@ static int rocker_port_fdb(struct rocker_port *rocker_port,
}
static int rocker_port_fdb_flush(struct rocker_port *rocker_port,
enum switchdev_trans trans)
enum switchdev_trans trans, int flags)
{
struct rocker *rocker = rocker_port->rocker;
struct rocker_fdb_tbl_entry *found;
unsigned long lock_flags;
int flags = ROCKER_OP_FLAG_REMOVE;
struct hlist_node *tmp;
int bkt;
int err = 0;
......@@ -3646,6 +3629,8 @@ static int rocker_port_fdb_flush(struct rocker_port *rocker_port,
rocker_port->stp_state == BR_STATE_FORWARDING)
return 0;
flags |= ROCKER_OP_FLAG_REMOVE;
spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags);
hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, found, entry) {
......@@ -3702,13 +3687,12 @@ static int rocker_port_router_mac(struct rocker_port *rocker_port,
}
static int rocker_port_fwding(struct rocker_port *rocker_port,
enum switchdev_trans trans)
enum switchdev_trans trans, int flags)
{
bool pop_vlan;
u32 out_pport;
__be16 vlan_id;
u16 vid;
int flags = 0;
int err;
/* Port will be forwarding-enabled if its STP state is LEARNING
......@@ -3742,12 +3726,12 @@ static int rocker_port_fwding(struct rocker_port *rocker_port,
}
static int rocker_port_stp_update(struct rocker_port *rocker_port,
enum switchdev_trans trans, u8 state)
enum switchdev_trans trans, int flags,
u8 state)
{
bool want[ROCKER_CTRL_MAX] = { 0, };
bool prev_ctrls[ROCKER_CTRL_MAX];
u8 prev_state;
int flags;
int err;
int i;
......@@ -3783,8 +3767,9 @@ static int rocker_port_stp_update(struct rocker_port *rocker_port,
for (i = 0; i < ROCKER_CTRL_MAX; i++) {
if (want[i] != rocker_port->ctrls[i]) {
flags = (want[i] ? 0 : ROCKER_OP_FLAG_REMOVE);
err = rocker_port_ctrl(rocker_port, trans, flags,
int ctrl_flags = flags |
(want[i] ? 0 : ROCKER_OP_FLAG_REMOVE);
err = rocker_port_ctrl(rocker_port, trans, ctrl_flags,
&rocker_ctrls[i]);
if (err)
goto err_out;
......@@ -3792,11 +3777,11 @@ static int rocker_port_stp_update(struct rocker_port *rocker_port,
}
}
err = rocker_port_fdb_flush(rocker_port, trans);
err = rocker_port_fdb_flush(rocker_port, trans, flags);
if (err)
goto err_out;
err = rocker_port_fwding(rocker_port, trans);
err = rocker_port_fwding(rocker_port, trans, flags);
err_out:
if (trans == SWITCHDEV_TRANS_PREPARE) {
......@@ -3808,25 +3793,27 @@ static int rocker_port_stp_update(struct rocker_port *rocker_port,
}
static int rocker_port_fwd_enable(struct rocker_port *rocker_port,
enum switchdev_trans trans)
enum switchdev_trans trans, int flags)
{
if (rocker_port_is_bridged(rocker_port))
/* bridge STP will enable port */
return 0;
/* port is not bridged, so simulate going to FORWARDING state */
return rocker_port_stp_update(rocker_port, trans, BR_STATE_FORWARDING);
return rocker_port_stp_update(rocker_port, trans, flags,
BR_STATE_FORWARDING);
}
static int rocker_port_fwd_disable(struct rocker_port *rocker_port,
enum switchdev_trans trans)
enum switchdev_trans trans, int flags)
{
if (rocker_port_is_bridged(rocker_port))
/* bridge STP will disable port */
return 0;
/* port is not bridged, so simulate going to DISABLED state */
return rocker_port_stp_update(rocker_port, trans, BR_STATE_DISABLED);
return rocker_port_stp_update(rocker_port, trans, flags,
BR_STATE_DISABLED);
}
static struct rocker_internal_vlan_tbl_entry *
......@@ -3990,7 +3977,7 @@ static int rocker_port_open(struct net_device *dev)
goto err_request_rx_irq;
}
err = rocker_port_fwd_enable(rocker_port, SWITCHDEV_TRANS_NONE);
err = rocker_port_fwd_enable(rocker_port, SWITCHDEV_TRANS_NONE, 0);
if (err)
goto err_fwd_enable;
......@@ -4017,7 +4004,8 @@ static int rocker_port_stop(struct net_device *dev)
rocker_port_set_enable(rocker_port, false);
napi_disable(&rocker_port->napi_rx);
napi_disable(&rocker_port->napi_tx);
rocker_port_fwd_disable(rocker_port, SWITCHDEV_TRANS_NONE);
rocker_port_fwd_disable(rocker_port, SWITCHDEV_TRANS_NONE,
ROCKER_OP_FLAG_NOWAIT);
free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);
free_irq(rocker_msix_tx_vector(rocker_port), rocker_port);
rocker_port_dma_rings_fini(rocker_port);
......@@ -4171,7 +4159,7 @@ static int rocker_port_get_phys_port_name(struct net_device *dev,
struct port_name name = { .buf = buf, .len = len };
int err;
err = rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE,
err = rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
rocker_cmd_get_port_settings_prep, NULL,
rocker_cmd_get_port_settings_phys_name_proc,
&name);
......@@ -4266,6 +4254,7 @@ static int rocker_port_attr_set(struct net_device *dev,
switch (attr->id) {
case SWITCHDEV_ATTR_PORT_STP_STATE:
err = rocker_port_stp_update(rocker_port, attr->trans,
ROCKER_OP_FLAG_NOWAIT,
attr->u.stp_state);
break;
case SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS:
......@@ -4618,7 +4607,7 @@ rocker_cmd_get_port_stats_ethtool_proc(const struct rocker_port *rocker_port,
static int rocker_cmd_get_port_stats_ethtool(struct rocker_port *rocker_port,
void *priv)
{
return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE,
return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
rocker_cmd_get_port_stats_prep, NULL,
rocker_cmd_get_port_stats_ethtool_proc,
priv);
......@@ -5170,7 +5159,8 @@ static int rocker_port_bridge_leave(struct rocker_port *rocker_port)
return err;
if (rocker_port->dev->flags & IFF_UP)
err = rocker_port_fwd_enable(rocker_port, SWITCHDEV_TRANS_NONE);
err = rocker_port_fwd_enable(rocker_port,
SWITCHDEV_TRANS_NONE, 0);
return err;
}
......@@ -5229,7 +5219,8 @@ static struct notifier_block rocker_netdevice_nb __read_mostly = {
static int rocker_neigh_update(struct net_device *dev, struct neighbour *n)
{
struct rocker_port *rocker_port = netdev_priv(dev);
int flags = (n->nud_state & NUD_VALID) ? 0 : ROCKER_OP_FLAG_REMOVE;
int flags = (n->nud_state & NUD_VALID ? 0 : ROCKER_OP_FLAG_REMOVE) |
ROCKER_OP_FLAG_NOWAIT;
__be32 ip_addr = *(__be32 *)n->primary_key;
return rocker_port_ipv4_neigh(rocker_port, SWITCHDEV_TRANS_NONE,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment