Commit 4110b282 authored by David S. Miller's avatar David S. Miller

Merge branch 'switchdev-transaction-item-queue'

Jiri Pirko says:

====================
switchdev: transaction item queue and cleanup
====================
Acked-by: default avatarScott Feldman <sfeldma@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents aee2f545 f623ab7f
...@@ -369,3 +369,22 @@ The driver can monitor for updates to arp_tbl using the netevent notifier ...@@ -369,3 +369,22 @@ The driver can monitor for updates to arp_tbl using the netevent notifier
NETEVENT_NEIGH_UPDATE. The device can be programmed with resolved nexthops NETEVENT_NEIGH_UPDATE. The device can be programmed with resolved nexthops
for the routes as arp_tbl updates. The driver implements ndo_neigh_destroy for the routes as arp_tbl updates. The driver implements ndo_neigh_destroy
to know when arp_tbl neighbor entries are purged from the port. to know when arp_tbl neighbor entries are purged from the port.
Transaction item queue
^^^^^^^^^^^^^^^^^^^^^^
For switchdev ops attr_set and obj_add, there is a 2 phase transaction model
used. First phase is to "prepare" anything needed, including various checks,
memory allocation, etc. The goal is to handle the stuff that is not unlikely
to fail here. The second phase is to "commit" the actual changes.
Switchdev provides an inftrastructure for sharing items (for example memory
allocations) between the two phases.
The object created by a driver in "prepare" phase and it is queued up by:
switchdev_trans_item_enqueue()
During the "commit" phase, the driver gets the object by:
switchdev_trans_item_dequeue()
If a transaction is aborted during "prepare" phase, switchdev code will handle
cleanup of the queued-up objects.
...@@ -228,7 +228,6 @@ struct rocker_port { ...@@ -228,7 +228,6 @@ struct rocker_port {
struct napi_struct napi_rx; struct napi_struct napi_rx;
struct rocker_dma_ring_info tx_ring; struct rocker_dma_ring_info tx_ring;
struct rocker_dma_ring_info rx_ring; struct rocker_dma_ring_info rx_ring;
struct list_head trans_mem;
}; };
struct rocker { struct rocker {
...@@ -343,74 +342,63 @@ static bool rocker_port_is_ovsed(const struct rocker_port *rocker_port) ...@@ -343,74 +342,63 @@ static bool rocker_port_is_ovsed(const struct rocker_port *rocker_port)
#define ROCKER_OP_FLAG_REFRESH BIT(3) #define ROCKER_OP_FLAG_REFRESH BIT(3)
static void *__rocker_port_mem_alloc(struct rocker_port *rocker_port, static void *__rocker_port_mem_alloc(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
size_t size) size_t size)
{ {
struct list_head *elem = NULL; struct switchdev_trans_item *elem = NULL;
gfp_t gfp_flags = (flags & ROCKER_OP_FLAG_NOWAIT) ? gfp_t gfp_flags = (flags & ROCKER_OP_FLAG_NOWAIT) ?
GFP_ATOMIC : GFP_KERNEL; GFP_ATOMIC : GFP_KERNEL;
/* If in transaction prepare phase, allocate the memory /* If in transaction prepare phase, allocate the memory
* and enqueue it on a per-port list. If in transaction * and enqueue it on a transaction. If in transaction
* commit phase, dequeue the memory from the per-port list * commit phase, dequeue the memory from the transaction
* rather than re-allocating the memory. The idea is the * rather than re-allocating the memory. The idea is the
* driver code paths for prepare and commit are identical * driver code paths for prepare and commit are identical
* so the memory allocated in the prepare phase is the * so the memory allocated in the prepare phase is the
* memory used in the commit phase. * memory used in the commit phase.
*/ */
switch (trans) { if (!trans) {
case SWITCHDEV_TRANS_PREPARE: elem = kzalloc(size + sizeof(*elem), gfp_flags);
} else if (switchdev_trans_ph_prepare(trans)) {
elem = kzalloc(size + sizeof(*elem), gfp_flags); elem = kzalloc(size + sizeof(*elem), gfp_flags);
if (!elem) if (!elem)
return NULL; return NULL;
list_add_tail(elem, &rocker_port->trans_mem); switchdev_trans_item_enqueue(trans, elem, kfree, elem);
break; } else {
case SWITCHDEV_TRANS_COMMIT: elem = switchdev_trans_item_dequeue(trans);
BUG_ON(list_empty(&rocker_port->trans_mem));
elem = rocker_port->trans_mem.next;
list_del_init(elem);
break;
case SWITCHDEV_TRANS_NONE:
elem = kzalloc(size + sizeof(*elem), gfp_flags);
if (elem)
INIT_LIST_HEAD(elem);
break;
default:
break;
} }
return elem ? elem + 1 : NULL; return elem ? elem + 1 : NULL;
} }
static void *rocker_port_kzalloc(struct rocker_port *rocker_port, static void *rocker_port_kzalloc(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
size_t size) size_t size)
{ {
return __rocker_port_mem_alloc(rocker_port, trans, flags, size); return __rocker_port_mem_alloc(rocker_port, trans, flags, size);
} }
static void *rocker_port_kcalloc(struct rocker_port *rocker_port, static void *rocker_port_kcalloc(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
size_t n, size_t size) size_t n, size_t size)
{ {
return __rocker_port_mem_alloc(rocker_port, trans, flags, 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) static void rocker_port_kfree(struct switchdev_trans *trans, const void *mem)
{ {
struct list_head *elem; struct switchdev_trans_item *elem;
/* Frees are ignored if in transaction prepare phase. The /* Frees are ignored if in transaction prepare phase. The
* memory remains on the per-port list until freed in the * memory remains on the per-port list until freed in the
* commit phase. * commit phase.
*/ */
if (trans == SWITCHDEV_TRANS_PREPARE) if (switchdev_trans_ph_prepare(trans))
return; return;
elem = (struct list_head *)mem - 1; elem = (struct switchdev_trans_item *) mem - 1;
BUG_ON(!list_empty(elem));
kfree(elem); kfree(elem);
} }
...@@ -433,7 +421,7 @@ static void rocker_wait_init(struct rocker_wait *wait) ...@@ -433,7 +421,7 @@ static void rocker_wait_init(struct rocker_wait *wait)
} }
static struct rocker_wait *rocker_wait_create(struct rocker_port *rocker_port, static struct rocker_wait *rocker_wait_create(struct rocker_port *rocker_port,
enum switchdev_trans trans, struct switchdev_trans *trans,
int flags) int flags)
{ {
struct rocker_wait *wait; struct rocker_wait *wait;
...@@ -445,7 +433,7 @@ static struct rocker_wait *rocker_wait_create(struct rocker_port *rocker_port, ...@@ -445,7 +433,7 @@ static struct rocker_wait *rocker_wait_create(struct rocker_port *rocker_port,
return wait; return wait;
} }
static void rocker_wait_destroy(enum switchdev_trans trans, static void rocker_wait_destroy(struct switchdev_trans *trans,
struct rocker_wait *wait) struct rocker_wait *wait)
{ {
rocker_port_kfree(trans, wait); rocker_port_kfree(trans, wait);
...@@ -1411,7 +1399,7 @@ static irqreturn_t rocker_cmd_irq_handler(int irq, void *dev_id) ...@@ -1411,7 +1399,7 @@ static irqreturn_t rocker_cmd_irq_handler(int irq, void *dev_id)
wait = rocker_desc_cookie_ptr_get(desc_info); wait = rocker_desc_cookie_ptr_get(desc_info);
if (wait->nowait) { if (wait->nowait) {
rocker_desc_gen_clear(desc_info); rocker_desc_gen_clear(desc_info);
rocker_wait_destroy(SWITCHDEV_TRANS_NONE, wait); rocker_wait_destroy(NULL, wait);
} else { } else {
rocker_wait_wake_up(wait); rocker_wait_wake_up(wait);
} }
...@@ -1466,7 +1454,7 @@ static int rocker_event_link_change(const struct rocker *rocker, ...@@ -1466,7 +1454,7 @@ static int rocker_event_link_change(const struct rocker *rocker,
} }
static int rocker_port_fdb(struct rocker_port *rocker_port, static int rocker_port_fdb(struct rocker_port *rocker_port,
enum switchdev_trans trans, struct switchdev_trans *trans,
const unsigned char *addr, const unsigned char *addr,
__be16 vlan_id, int flags); __be16 vlan_id, int flags);
...@@ -1499,8 +1487,7 @@ static int rocker_event_mac_vlan_seen(const struct rocker *rocker, ...@@ -1499,8 +1487,7 @@ static int rocker_event_mac_vlan_seen(const struct rocker *rocker,
rocker_port->stp_state != BR_STATE_FORWARDING) rocker_port->stp_state != BR_STATE_FORWARDING)
return 0; return 0;
return rocker_port_fdb(rocker_port, SWITCHDEV_TRANS_NONE, return rocker_port_fdb(rocker_port, NULL, addr, vlan_id, flags);
addr, vlan_id, flags);
} }
static int rocker_event_process(const struct rocker *rocker, static int rocker_event_process(const struct rocker *rocker,
...@@ -1585,7 +1572,7 @@ typedef int (*rocker_cmd_proc_cb_t)(const struct rocker_port *rocker_port, ...@@ -1585,7 +1572,7 @@ typedef int (*rocker_cmd_proc_cb_t)(const struct rocker_port *rocker_port,
void *priv); void *priv);
static int rocker_cmd_exec(struct rocker_port *rocker_port, static int rocker_cmd_exec(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
rocker_cmd_prep_cb_t prepare, void *prepare_priv, rocker_cmd_prep_cb_t prepare, void *prepare_priv,
rocker_cmd_proc_cb_t process, void *process_priv) rocker_cmd_proc_cb_t process, void *process_priv)
{ {
...@@ -1618,7 +1605,7 @@ static int rocker_cmd_exec(struct rocker_port *rocker_port, ...@@ -1618,7 +1605,7 @@ static int rocker_cmd_exec(struct rocker_port *rocker_port,
rocker_desc_cookie_ptr_set(desc_info, wait); rocker_desc_cookie_ptr_set(desc_info, wait);
if (trans != SWITCHDEV_TRANS_PREPARE) if (!switchdev_trans_ph_prepare(trans))
rocker_desc_head_set(rocker, &rocker->cmd_ring, desc_info); rocker_desc_head_set(rocker, &rocker->cmd_ring, desc_info);
spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags); spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags);
...@@ -1626,7 +1613,7 @@ static int rocker_cmd_exec(struct rocker_port *rocker_port, ...@@ -1626,7 +1613,7 @@ static int rocker_cmd_exec(struct rocker_port *rocker_port,
if (nowait) if (nowait)
return 0; return 0;
if (trans != SWITCHDEV_TRANS_PREPARE) if (!switchdev_trans_ph_prepare(trans))
if (!rocker_wait_event_timeout(wait, HZ / 10)) if (!rocker_wait_event_timeout(wait, HZ / 10))
return -EIO; return -EIO;
...@@ -1878,7 +1865,7 @@ rocker_cmd_set_port_learning_prep(const struct rocker_port *rocker_port, ...@@ -1878,7 +1865,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, static int rocker_cmd_get_port_settings_ethtool(struct rocker_port *rocker_port,
struct ethtool_cmd *ecmd) struct ethtool_cmd *ecmd)
{ {
return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0, return rocker_cmd_exec(rocker_port, NULL, 0,
rocker_cmd_get_port_settings_prep, NULL, rocker_cmd_get_port_settings_prep, NULL,
rocker_cmd_get_port_settings_ethtool_proc, rocker_cmd_get_port_settings_ethtool_proc,
ecmd); ecmd);
...@@ -1887,7 +1874,7 @@ static int rocker_cmd_get_port_settings_ethtool(struct rocker_port *rocker_port, ...@@ -1887,7 +1874,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, static int rocker_cmd_get_port_settings_macaddr(struct rocker_port *rocker_port,
unsigned char *macaddr) unsigned char *macaddr)
{ {
return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0, return rocker_cmd_exec(rocker_port, NULL, 0,
rocker_cmd_get_port_settings_prep, NULL, rocker_cmd_get_port_settings_prep, NULL,
rocker_cmd_get_port_settings_macaddr_proc, rocker_cmd_get_port_settings_macaddr_proc,
macaddr); macaddr);
...@@ -1896,7 +1883,7 @@ static int rocker_cmd_get_port_settings_macaddr(struct rocker_port *rocker_port, ...@@ -1896,7 +1883,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, static int rocker_cmd_set_port_settings_ethtool(struct rocker_port *rocker_port,
struct ethtool_cmd *ecmd) struct ethtool_cmd *ecmd)
{ {
return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0, return rocker_cmd_exec(rocker_port, NULL, 0,
rocker_cmd_set_port_settings_ethtool_prep, rocker_cmd_set_port_settings_ethtool_prep,
ecmd, NULL, NULL); ecmd, NULL, NULL);
} }
...@@ -1904,7 +1891,7 @@ static int rocker_cmd_set_port_settings_ethtool(struct rocker_port *rocker_port, ...@@ -1904,7 +1891,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, static int rocker_cmd_set_port_settings_macaddr(struct rocker_port *rocker_port,
unsigned char *macaddr) unsigned char *macaddr)
{ {
return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0, return rocker_cmd_exec(rocker_port, NULL, 0,
rocker_cmd_set_port_settings_macaddr_prep, rocker_cmd_set_port_settings_macaddr_prep,
macaddr, NULL, NULL); macaddr, NULL, NULL);
} }
...@@ -1912,13 +1899,13 @@ static int rocker_cmd_set_port_settings_macaddr(struct rocker_port *rocker_port, ...@@ -1912,13 +1899,13 @@ static int rocker_cmd_set_port_settings_macaddr(struct rocker_port *rocker_port,
static int rocker_cmd_set_port_settings_mtu(struct rocker_port *rocker_port, static int rocker_cmd_set_port_settings_mtu(struct rocker_port *rocker_port,
int mtu) int mtu)
{ {
return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0, return rocker_cmd_exec(rocker_port, NULL, 0,
rocker_cmd_set_port_settings_mtu_prep, rocker_cmd_set_port_settings_mtu_prep,
&mtu, NULL, NULL); &mtu, NULL, NULL);
} }
static int rocker_port_set_learning(struct rocker_port *rocker_port, static int rocker_port_set_learning(struct rocker_port *rocker_port,
enum switchdev_trans trans) struct switchdev_trans *trans)
{ {
return rocker_cmd_exec(rocker_port, trans, 0, return rocker_cmd_exec(rocker_port, trans, 0,
rocker_cmd_set_port_learning_prep, rocker_cmd_set_port_learning_prep,
...@@ -2436,7 +2423,7 @@ rocker_flow_tbl_find(const struct rocker *rocker, ...@@ -2436,7 +2423,7 @@ rocker_flow_tbl_find(const struct rocker *rocker,
} }
static int rocker_flow_tbl_add(struct rocker_port *rocker_port, static int rocker_flow_tbl_add(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
struct rocker_flow_tbl_entry *match) struct rocker_flow_tbl_entry *match)
{ {
struct rocker *rocker = rocker_port->rocker; struct rocker *rocker = rocker_port->rocker;
...@@ -2452,7 +2439,7 @@ static int rocker_flow_tbl_add(struct rocker_port *rocker_port, ...@@ -2452,7 +2439,7 @@ static int rocker_flow_tbl_add(struct rocker_port *rocker_port,
if (found) { if (found) {
match->cookie = found->cookie; match->cookie = found->cookie;
if (trans != SWITCHDEV_TRANS_PREPARE) if (!switchdev_trans_ph_prepare(trans))
hash_del(&found->entry); hash_del(&found->entry);
rocker_port_kfree(trans, found); rocker_port_kfree(trans, found);
found = match; found = match;
...@@ -2463,7 +2450,7 @@ static int rocker_flow_tbl_add(struct rocker_port *rocker_port, ...@@ -2463,7 +2450,7 @@ static int rocker_flow_tbl_add(struct rocker_port *rocker_port,
found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD; found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD;
} }
if (trans != SWITCHDEV_TRANS_PREPARE) if (!switchdev_trans_ph_prepare(trans))
hash_add(rocker->flow_tbl, &found->entry, found->key_crc32); hash_add(rocker->flow_tbl, &found->entry, found->key_crc32);
spin_unlock_irqrestore(&rocker->flow_tbl_lock, lock_flags); spin_unlock_irqrestore(&rocker->flow_tbl_lock, lock_flags);
...@@ -2473,7 +2460,7 @@ static int rocker_flow_tbl_add(struct rocker_port *rocker_port, ...@@ -2473,7 +2460,7 @@ static int rocker_flow_tbl_add(struct rocker_port *rocker_port,
} }
static int rocker_flow_tbl_del(struct rocker_port *rocker_port, static int rocker_flow_tbl_del(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
struct rocker_flow_tbl_entry *match) struct rocker_flow_tbl_entry *match)
{ {
struct rocker *rocker = rocker_port->rocker; struct rocker *rocker = rocker_port->rocker;
...@@ -2489,7 +2476,7 @@ static int rocker_flow_tbl_del(struct rocker_port *rocker_port, ...@@ -2489,7 +2476,7 @@ static int rocker_flow_tbl_del(struct rocker_port *rocker_port,
found = rocker_flow_tbl_find(rocker, match); found = rocker_flow_tbl_find(rocker, match);
if (found) { if (found) {
if (trans != SWITCHDEV_TRANS_PREPARE) if (!switchdev_trans_ph_prepare(trans))
hash_del(&found->entry); hash_del(&found->entry);
found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL; found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL;
} }
...@@ -2509,7 +2496,7 @@ static int rocker_flow_tbl_del(struct rocker_port *rocker_port, ...@@ -2509,7 +2496,7 @@ static int rocker_flow_tbl_del(struct rocker_port *rocker_port,
} }
static int rocker_flow_tbl_do(struct rocker_port *rocker_port, static int rocker_flow_tbl_do(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
struct rocker_flow_tbl_entry *entry) struct rocker_flow_tbl_entry *entry)
{ {
if (flags & ROCKER_OP_FLAG_REMOVE) if (flags & ROCKER_OP_FLAG_REMOVE)
...@@ -2519,7 +2506,7 @@ static int rocker_flow_tbl_do(struct rocker_port *rocker_port, ...@@ -2519,7 +2506,7 @@ static int rocker_flow_tbl_do(struct rocker_port *rocker_port,
} }
static int rocker_flow_tbl_ig_port(struct rocker_port *rocker_port, static int rocker_flow_tbl_ig_port(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
u32 in_pport, u32 in_pport_mask, u32 in_pport, u32 in_pport_mask,
enum rocker_of_dpa_table_id goto_tbl) enum rocker_of_dpa_table_id goto_tbl)
{ {
...@@ -2539,7 +2526,7 @@ static int rocker_flow_tbl_ig_port(struct rocker_port *rocker_port, ...@@ -2539,7 +2526,7 @@ static int rocker_flow_tbl_ig_port(struct rocker_port *rocker_port,
} }
static int rocker_flow_tbl_vlan(struct rocker_port *rocker_port, static int rocker_flow_tbl_vlan(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
u32 in_pport, __be16 vlan_id, u32 in_pport, __be16 vlan_id,
__be16 vlan_id_mask, __be16 vlan_id_mask,
enum rocker_of_dpa_table_id goto_tbl, enum rocker_of_dpa_table_id goto_tbl,
...@@ -2565,7 +2552,7 @@ static int rocker_flow_tbl_vlan(struct rocker_port *rocker_port, ...@@ -2565,7 +2552,7 @@ static int rocker_flow_tbl_vlan(struct rocker_port *rocker_port,
} }
static int rocker_flow_tbl_term_mac(struct rocker_port *rocker_port, static int rocker_flow_tbl_term_mac(struct rocker_port *rocker_port,
enum switchdev_trans trans, struct switchdev_trans *trans,
u32 in_pport, u32 in_pport_mask, u32 in_pport, u32 in_pport_mask,
__be16 eth_type, const u8 *eth_dst, __be16 eth_type, const u8 *eth_dst,
const u8 *eth_dst_mask, __be16 vlan_id, const u8 *eth_dst_mask, __be16 vlan_id,
...@@ -2602,7 +2589,7 @@ static int rocker_flow_tbl_term_mac(struct rocker_port *rocker_port, ...@@ -2602,7 +2589,7 @@ static int rocker_flow_tbl_term_mac(struct rocker_port *rocker_port,
} }
static int rocker_flow_tbl_bridge(struct rocker_port *rocker_port, static int rocker_flow_tbl_bridge(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
const u8 *eth_dst, const u8 *eth_dst_mask, const u8 *eth_dst, const u8 *eth_dst_mask,
__be16 vlan_id, u32 tunnel_id, __be16 vlan_id, u32 tunnel_id,
enum rocker_of_dpa_table_id goto_tbl, enum rocker_of_dpa_table_id goto_tbl,
...@@ -2656,7 +2643,7 @@ static int rocker_flow_tbl_bridge(struct rocker_port *rocker_port, ...@@ -2656,7 +2643,7 @@ static int rocker_flow_tbl_bridge(struct rocker_port *rocker_port,
} }
static int rocker_flow_tbl_ucast4_routing(struct rocker_port *rocker_port, static int rocker_flow_tbl_ucast4_routing(struct rocker_port *rocker_port,
enum switchdev_trans trans, struct switchdev_trans *trans,
__be16 eth_type, __be32 dst, __be16 eth_type, __be32 dst,
__be32 dst_mask, u32 priority, __be32 dst_mask, u32 priority,
enum rocker_of_dpa_table_id goto_tbl, enum rocker_of_dpa_table_id goto_tbl,
...@@ -2682,7 +2669,7 @@ static int rocker_flow_tbl_ucast4_routing(struct rocker_port *rocker_port, ...@@ -2682,7 +2669,7 @@ static int rocker_flow_tbl_ucast4_routing(struct rocker_port *rocker_port,
} }
static int rocker_flow_tbl_acl(struct rocker_port *rocker_port, static int rocker_flow_tbl_acl(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
u32 in_pport, u32 in_pport_mask, u32 in_pport, u32 in_pport_mask,
const u8 *eth_src, const u8 *eth_src_mask, const u8 *eth_src, const u8 *eth_src_mask,
const u8 *eth_dst, const u8 *eth_dst_mask, const u8 *eth_dst, const u8 *eth_dst_mask,
...@@ -2747,7 +2734,7 @@ rocker_group_tbl_find(const struct rocker *rocker, ...@@ -2747,7 +2734,7 @@ rocker_group_tbl_find(const struct rocker *rocker,
return NULL; return NULL;
} }
static void rocker_group_tbl_entry_free(enum switchdev_trans trans, static void rocker_group_tbl_entry_free(struct switchdev_trans *trans,
struct rocker_group_tbl_entry *entry) struct rocker_group_tbl_entry *entry)
{ {
switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) { switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) {
...@@ -2762,7 +2749,7 @@ static void rocker_group_tbl_entry_free(enum switchdev_trans trans, ...@@ -2762,7 +2749,7 @@ static void rocker_group_tbl_entry_free(enum switchdev_trans trans,
} }
static int rocker_group_tbl_add(struct rocker_port *rocker_port, static int rocker_group_tbl_add(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
struct rocker_group_tbl_entry *match) struct rocker_group_tbl_entry *match)
{ {
struct rocker *rocker = rocker_port->rocker; struct rocker *rocker = rocker_port->rocker;
...@@ -2774,7 +2761,7 @@ static int rocker_group_tbl_add(struct rocker_port *rocker_port, ...@@ -2774,7 +2761,7 @@ static int rocker_group_tbl_add(struct rocker_port *rocker_port,
found = rocker_group_tbl_find(rocker, match); found = rocker_group_tbl_find(rocker, match);
if (found) { if (found) {
if (trans != SWITCHDEV_TRANS_PREPARE) if (!switchdev_trans_ph_prepare(trans))
hash_del(&found->entry); hash_del(&found->entry);
rocker_group_tbl_entry_free(trans, found); rocker_group_tbl_entry_free(trans, found);
found = match; found = match;
...@@ -2784,7 +2771,7 @@ static int rocker_group_tbl_add(struct rocker_port *rocker_port, ...@@ -2784,7 +2771,7 @@ static int rocker_group_tbl_add(struct rocker_port *rocker_port,
found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD; found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD;
} }
if (trans != SWITCHDEV_TRANS_PREPARE) if (!switchdev_trans_ph_prepare(trans))
hash_add(rocker->group_tbl, &found->entry, found->group_id); hash_add(rocker->group_tbl, &found->entry, found->group_id);
spin_unlock_irqrestore(&rocker->group_tbl_lock, lock_flags); spin_unlock_irqrestore(&rocker->group_tbl_lock, lock_flags);
...@@ -2794,7 +2781,7 @@ static int rocker_group_tbl_add(struct rocker_port *rocker_port, ...@@ -2794,7 +2781,7 @@ static int rocker_group_tbl_add(struct rocker_port *rocker_port,
} }
static int rocker_group_tbl_del(struct rocker_port *rocker_port, static int rocker_group_tbl_del(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
struct rocker_group_tbl_entry *match) struct rocker_group_tbl_entry *match)
{ {
struct rocker *rocker = rocker_port->rocker; struct rocker *rocker = rocker_port->rocker;
...@@ -2807,7 +2794,7 @@ static int rocker_group_tbl_del(struct rocker_port *rocker_port, ...@@ -2807,7 +2794,7 @@ static int rocker_group_tbl_del(struct rocker_port *rocker_port,
found = rocker_group_tbl_find(rocker, match); found = rocker_group_tbl_find(rocker, match);
if (found) { if (found) {
if (trans != SWITCHDEV_TRANS_PREPARE) if (!switchdev_trans_ph_prepare(trans))
hash_del(&found->entry); hash_del(&found->entry);
found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL; found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL;
} }
...@@ -2827,7 +2814,7 @@ static int rocker_group_tbl_del(struct rocker_port *rocker_port, ...@@ -2827,7 +2814,7 @@ static int rocker_group_tbl_del(struct rocker_port *rocker_port,
} }
static int rocker_group_tbl_do(struct rocker_port *rocker_port, static int rocker_group_tbl_do(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
struct rocker_group_tbl_entry *entry) struct rocker_group_tbl_entry *entry)
{ {
if (flags & ROCKER_OP_FLAG_REMOVE) if (flags & ROCKER_OP_FLAG_REMOVE)
...@@ -2837,7 +2824,7 @@ static int rocker_group_tbl_do(struct rocker_port *rocker_port, ...@@ -2837,7 +2824,7 @@ static int rocker_group_tbl_do(struct rocker_port *rocker_port,
} }
static int rocker_group_l2_interface(struct rocker_port *rocker_port, static int rocker_group_l2_interface(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
__be16 vlan_id, u32 out_pport, __be16 vlan_id, u32 out_pport,
int pop_vlan) int pop_vlan)
{ {
...@@ -2854,7 +2841,7 @@ static int rocker_group_l2_interface(struct rocker_port *rocker_port, ...@@ -2854,7 +2841,7 @@ static int rocker_group_l2_interface(struct rocker_port *rocker_port,
} }
static int rocker_group_l2_fan_out(struct rocker_port *rocker_port, static int rocker_group_l2_fan_out(struct rocker_port *rocker_port,
enum switchdev_trans trans, struct switchdev_trans *trans,
int flags, u8 group_count, int flags, u8 group_count,
const u32 *group_ids, u32 group_id) const u32 *group_ids, u32 group_id)
{ {
...@@ -2879,7 +2866,7 @@ static int rocker_group_l2_fan_out(struct rocker_port *rocker_port, ...@@ -2879,7 +2866,7 @@ static int rocker_group_l2_fan_out(struct rocker_port *rocker_port,
} }
static int rocker_group_l2_flood(struct rocker_port *rocker_port, static int rocker_group_l2_flood(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
__be16 vlan_id, u8 group_count, __be16 vlan_id, u8 group_count,
const u32 *group_ids, u32 group_id) const u32 *group_ids, u32 group_id)
{ {
...@@ -2889,7 +2876,7 @@ static int rocker_group_l2_flood(struct rocker_port *rocker_port, ...@@ -2889,7 +2876,7 @@ static int rocker_group_l2_flood(struct rocker_port *rocker_port,
} }
static int rocker_group_l3_unicast(struct rocker_port *rocker_port, static int rocker_group_l3_unicast(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
u32 index, const u8 *src_mac, const u8 *dst_mac, u32 index, const u8 *src_mac, const u8 *dst_mac,
__be16 vlan_id, bool ttl_check, u32 pport) __be16 vlan_id, bool ttl_check, u32 pport)
{ {
...@@ -2925,22 +2912,22 @@ rocker_neigh_tbl_find(const struct rocker *rocker, __be32 ip_addr) ...@@ -2925,22 +2912,22 @@ rocker_neigh_tbl_find(const struct rocker *rocker, __be32 ip_addr)
} }
static void _rocker_neigh_add(struct rocker *rocker, static void _rocker_neigh_add(struct rocker *rocker,
enum switchdev_trans trans, struct switchdev_trans *trans,
struct rocker_neigh_tbl_entry *entry) struct rocker_neigh_tbl_entry *entry)
{ {
if (trans != SWITCHDEV_TRANS_COMMIT) if (!switchdev_trans_ph_commit(trans))
entry->index = rocker->neigh_tbl_next_index++; entry->index = rocker->neigh_tbl_next_index++;
if (trans == SWITCHDEV_TRANS_PREPARE) if (switchdev_trans_ph_prepare(trans))
return; return;
entry->ref_count++; entry->ref_count++;
hash_add(rocker->neigh_tbl, &entry->entry, hash_add(rocker->neigh_tbl, &entry->entry,
be32_to_cpu(entry->ip_addr)); be32_to_cpu(entry->ip_addr));
} }
static void _rocker_neigh_del(enum switchdev_trans trans, static void _rocker_neigh_del(struct switchdev_trans *trans,
struct rocker_neigh_tbl_entry *entry) struct rocker_neigh_tbl_entry *entry)
{ {
if (trans == SWITCHDEV_TRANS_PREPARE) if (switchdev_trans_ph_prepare(trans))
return; return;
if (--entry->ref_count == 0) { if (--entry->ref_count == 0) {
hash_del(&entry->entry); hash_del(&entry->entry);
...@@ -2949,19 +2936,19 @@ static void _rocker_neigh_del(enum switchdev_trans trans, ...@@ -2949,19 +2936,19 @@ static void _rocker_neigh_del(enum switchdev_trans trans,
} }
static void _rocker_neigh_update(struct rocker_neigh_tbl_entry *entry, static void _rocker_neigh_update(struct rocker_neigh_tbl_entry *entry,
enum switchdev_trans trans, struct switchdev_trans *trans,
const u8 *eth_dst, bool ttl_check) const u8 *eth_dst, bool ttl_check)
{ {
if (eth_dst) { if (eth_dst) {
ether_addr_copy(entry->eth_dst, eth_dst); ether_addr_copy(entry->eth_dst, eth_dst);
entry->ttl_check = ttl_check; entry->ttl_check = ttl_check;
} else if (trans != SWITCHDEV_TRANS_PREPARE) { } else if (!switchdev_trans_ph_prepare(trans)) {
entry->ref_count++; entry->ref_count++;
} }
} }
static int rocker_port_ipv4_neigh(struct rocker_port *rocker_port, static int rocker_port_ipv4_neigh(struct rocker_port *rocker_port,
enum switchdev_trans trans, struct switchdev_trans *trans,
int flags, __be32 ip_addr, const u8 *eth_dst) int flags, __be32 ip_addr, const u8 *eth_dst)
{ {
struct rocker *rocker = rocker_port->rocker; struct rocker *rocker = rocker_port->rocker;
...@@ -3053,7 +3040,8 @@ static int rocker_port_ipv4_neigh(struct rocker_port *rocker_port, ...@@ -3053,7 +3040,8 @@ static int rocker_port_ipv4_neigh(struct rocker_port *rocker_port,
} }
static int rocker_port_ipv4_resolve(struct rocker_port *rocker_port, static int rocker_port_ipv4_resolve(struct rocker_port *rocker_port,
enum switchdev_trans trans, __be32 ip_addr) struct switchdev_trans *trans,
__be32 ip_addr)
{ {
struct net_device *dev = rocker_port->dev; struct net_device *dev = rocker_port->dev;
struct neighbour *n = __ipv4_neigh_lookup(dev, (__force u32)ip_addr); struct neighbour *n = __ipv4_neigh_lookup(dev, (__force u32)ip_addr);
...@@ -3081,7 +3069,7 @@ static int rocker_port_ipv4_resolve(struct rocker_port *rocker_port, ...@@ -3081,7 +3069,7 @@ static int rocker_port_ipv4_resolve(struct rocker_port *rocker_port,
} }
static int rocker_port_ipv4_nh(struct rocker_port *rocker_port, static int rocker_port_ipv4_nh(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
__be32 ip_addr, u32 *index) __be32 ip_addr, u32 *index)
{ {
struct rocker *rocker = rocker_port->rocker; struct rocker *rocker = rocker_port->rocker;
...@@ -3140,7 +3128,7 @@ static int rocker_port_ipv4_nh(struct rocker_port *rocker_port, ...@@ -3140,7 +3128,7 @@ static int rocker_port_ipv4_nh(struct rocker_port *rocker_port,
} }
static int rocker_port_vlan_flood_group(struct rocker_port *rocker_port, static int rocker_port_vlan_flood_group(struct rocker_port *rocker_port,
enum switchdev_trans trans, struct switchdev_trans *trans,
int flags, __be16 vlan_id) int flags, __be16 vlan_id)
{ {
struct rocker_port *p; struct rocker_port *p;
...@@ -3189,7 +3177,7 @@ static int rocker_port_vlan_flood_group(struct rocker_port *rocker_port, ...@@ -3189,7 +3177,7 @@ static int rocker_port_vlan_flood_group(struct rocker_port *rocker_port,
} }
static int rocker_port_vlan_l2_groups(struct rocker_port *rocker_port, static int rocker_port_vlan_l2_groups(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
__be16 vlan_id, bool pop_vlan) __be16 vlan_id, bool pop_vlan)
{ {
const struct rocker *rocker = rocker_port->rocker; const struct rocker *rocker = rocker_port->rocker;
...@@ -3295,7 +3283,7 @@ static struct rocker_ctrl { ...@@ -3295,7 +3283,7 @@ static struct rocker_ctrl {
}; };
static int rocker_port_ctrl_vlan_acl(struct rocker_port *rocker_port, static int rocker_port_ctrl_vlan_acl(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
const struct rocker_ctrl *ctrl, __be16 vlan_id) const struct rocker_ctrl *ctrl, __be16 vlan_id)
{ {
u32 in_pport = rocker_port->pport; u32 in_pport = rocker_port->pport;
...@@ -3328,7 +3316,8 @@ static int rocker_port_ctrl_vlan_acl(struct rocker_port *rocker_port, ...@@ -3328,7 +3316,8 @@ static int rocker_port_ctrl_vlan_acl(struct rocker_port *rocker_port,
} }
static int rocker_port_ctrl_vlan_bridge(struct rocker_port *rocker_port, static int rocker_port_ctrl_vlan_bridge(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans,
int flags,
const struct rocker_ctrl *ctrl, const struct rocker_ctrl *ctrl,
__be16 vlan_id) __be16 vlan_id)
{ {
...@@ -3353,7 +3342,7 @@ static int rocker_port_ctrl_vlan_bridge(struct rocker_port *rocker_port, ...@@ -3353,7 +3342,7 @@ static int rocker_port_ctrl_vlan_bridge(struct rocker_port *rocker_port,
} }
static int rocker_port_ctrl_vlan_term(struct rocker_port *rocker_port, static int rocker_port_ctrl_vlan_term(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
const struct rocker_ctrl *ctrl, __be16 vlan_id) const struct rocker_ctrl *ctrl, __be16 vlan_id)
{ {
u32 in_pport_mask = 0xffffffff; u32 in_pport_mask = 0xffffffff;
...@@ -3377,7 +3366,7 @@ static int rocker_port_ctrl_vlan_term(struct rocker_port *rocker_port, ...@@ -3377,7 +3366,7 @@ static int rocker_port_ctrl_vlan_term(struct rocker_port *rocker_port,
} }
static int rocker_port_ctrl_vlan(struct rocker_port *rocker_port, static int rocker_port_ctrl_vlan(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
const struct rocker_ctrl *ctrl, __be16 vlan_id) const struct rocker_ctrl *ctrl, __be16 vlan_id)
{ {
if (ctrl->acl) if (ctrl->acl)
...@@ -3395,7 +3384,7 @@ static int rocker_port_ctrl_vlan(struct rocker_port *rocker_port, ...@@ -3395,7 +3384,7 @@ static int rocker_port_ctrl_vlan(struct rocker_port *rocker_port,
} }
static int rocker_port_ctrl_vlan_add(struct rocker_port *rocker_port, static int rocker_port_ctrl_vlan_add(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
__be16 vlan_id) __be16 vlan_id)
{ {
int err = 0; int err = 0;
...@@ -3414,7 +3403,7 @@ static int rocker_port_ctrl_vlan_add(struct rocker_port *rocker_port, ...@@ -3414,7 +3403,7 @@ static int rocker_port_ctrl_vlan_add(struct rocker_port *rocker_port,
} }
static int rocker_port_ctrl(struct rocker_port *rocker_port, static int rocker_port_ctrl(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
const struct rocker_ctrl *ctrl) const struct rocker_ctrl *ctrl)
{ {
u16 vid; u16 vid;
...@@ -3433,7 +3422,7 @@ static int rocker_port_ctrl(struct rocker_port *rocker_port, ...@@ -3433,7 +3422,7 @@ static int rocker_port_ctrl(struct rocker_port *rocker_port,
} }
static int rocker_port_vlan(struct rocker_port *rocker_port, static int rocker_port_vlan(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, u16 vid) struct switchdev_trans *trans, int flags, u16 vid)
{ {
enum rocker_of_dpa_table_id goto_tbl = enum rocker_of_dpa_table_id goto_tbl =
ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC; ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
...@@ -3490,14 +3479,14 @@ static int rocker_port_vlan(struct rocker_port *rocker_port, ...@@ -3490,14 +3479,14 @@ static int rocker_port_vlan(struct rocker_port *rocker_port,
"Error (%d) port VLAN table\n", err); "Error (%d) port VLAN table\n", err);
err_out: err_out:
if (trans == SWITCHDEV_TRANS_PREPARE) if (switchdev_trans_ph_prepare(trans))
change_bit(ntohs(internal_vlan_id), rocker_port->vlan_bitmap); change_bit(ntohs(internal_vlan_id), rocker_port->vlan_bitmap);
return err; return err;
} }
static int rocker_port_ig_tbl(struct rocker_port *rocker_port, static int rocker_port_ig_tbl(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags) struct switchdev_trans *trans, int flags)
{ {
enum rocker_of_dpa_table_id goto_tbl; enum rocker_of_dpa_table_id goto_tbl;
u32 in_pport; u32 in_pport;
...@@ -3525,7 +3514,7 @@ static int rocker_port_ig_tbl(struct rocker_port *rocker_port, ...@@ -3525,7 +3514,7 @@ static int rocker_port_ig_tbl(struct rocker_port *rocker_port,
struct rocker_fdb_learn_work { struct rocker_fdb_learn_work {
struct work_struct work; struct work_struct work;
struct rocker_port *rocker_port; struct rocker_port *rocker_port;
enum switchdev_trans trans; struct switchdev_trans *trans;
int flags; int flags;
u8 addr[ETH_ALEN]; u8 addr[ETH_ALEN];
u16 vid; u16 vid;
...@@ -3553,7 +3542,7 @@ static void rocker_port_fdb_learn_work(struct work_struct *work) ...@@ -3553,7 +3542,7 @@ static void rocker_port_fdb_learn_work(struct work_struct *work)
} }
static int rocker_port_fdb_learn(struct rocker_port *rocker_port, static int rocker_port_fdb_learn(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
const u8 *addr, __be16 vlan_id) const u8 *addr, __be16 vlan_id)
{ {
struct rocker_fdb_learn_work *lw; struct rocker_fdb_learn_work *lw;
...@@ -3595,7 +3584,7 @@ static int rocker_port_fdb_learn(struct rocker_port *rocker_port, ...@@ -3595,7 +3584,7 @@ static int rocker_port_fdb_learn(struct rocker_port *rocker_port,
ether_addr_copy(lw->addr, addr); ether_addr_copy(lw->addr, addr);
lw->vid = rocker_port_vlan_to_vid(rocker_port, vlan_id); lw->vid = rocker_port_vlan_to_vid(rocker_port, vlan_id);
if (trans == SWITCHDEV_TRANS_PREPARE) if (switchdev_trans_ph_prepare(trans))
rocker_port_kfree(trans, lw); rocker_port_kfree(trans, lw);
else else
schedule_work(&lw->work); schedule_work(&lw->work);
...@@ -3617,7 +3606,7 @@ rocker_fdb_tbl_find(const struct rocker *rocker, ...@@ -3617,7 +3606,7 @@ rocker_fdb_tbl_find(const struct rocker *rocker,
} }
static int rocker_port_fdb(struct rocker_port *rocker_port, static int rocker_port_fdb(struct rocker_port *rocker_port,
enum switchdev_trans trans, struct switchdev_trans *trans,
const unsigned char *addr, const unsigned char *addr,
__be16 vlan_id, int flags) __be16 vlan_id, int flags)
{ {
...@@ -3646,11 +3635,11 @@ static int rocker_port_fdb(struct rocker_port *rocker_port, ...@@ -3646,11 +3635,11 @@ static int rocker_port_fdb(struct rocker_port *rocker_port,
found->touched = jiffies; found->touched = jiffies;
if (removing) { if (removing) {
rocker_port_kfree(trans, fdb); rocker_port_kfree(trans, fdb);
if (trans != SWITCHDEV_TRANS_PREPARE) if (!switchdev_trans_ph_prepare(trans))
hash_del(&found->entry); hash_del(&found->entry);
} }
} else if (!removing) { } else if (!removing) {
if (trans != SWITCHDEV_TRANS_PREPARE) if (!switchdev_trans_ph_prepare(trans))
hash_add(rocker->fdb_tbl, &fdb->entry, hash_add(rocker->fdb_tbl, &fdb->entry,
fdb->key_crc32); fdb->key_crc32);
} }
...@@ -3670,7 +3659,7 @@ static int rocker_port_fdb(struct rocker_port *rocker_port, ...@@ -3670,7 +3659,7 @@ static int rocker_port_fdb(struct rocker_port *rocker_port,
} }
static int rocker_port_fdb_flush(struct rocker_port *rocker_port, static int rocker_port_fdb_flush(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags) struct switchdev_trans *trans, int flags)
{ {
struct rocker *rocker = rocker_port->rocker; struct rocker *rocker = rocker_port->rocker;
struct rocker_fdb_tbl_entry *found; struct rocker_fdb_tbl_entry *found;
...@@ -3697,7 +3686,7 @@ static int rocker_port_fdb_flush(struct rocker_port *rocker_port, ...@@ -3697,7 +3686,7 @@ static int rocker_port_fdb_flush(struct rocker_port *rocker_port,
found->key.vlan_id); found->key.vlan_id);
if (err) if (err)
goto err_out; goto err_out;
if (trans != SWITCHDEV_TRANS_PREPARE) if (!switchdev_trans_ph_prepare(trans))
hash_del(&found->entry); hash_del(&found->entry);
} }
...@@ -3728,7 +3717,7 @@ static void rocker_fdb_cleanup(unsigned long data) ...@@ -3728,7 +3717,7 @@ static void rocker_fdb_cleanup(unsigned long data)
rocker_port = entry->key.rocker_port; rocker_port = entry->key.rocker_port;
expires = entry->touched + rocker_port->ageing_time; expires = entry->touched + rocker_port->ageing_time;
if (time_before_eq(expires, jiffies)) { if (time_before_eq(expires, jiffies)) {
rocker_port_fdb_learn(rocker_port, SWITCHDEV_TRANS_NONE, rocker_port_fdb_learn(rocker_port, NULL,
flags, entry->key.addr, flags, entry->key.addr,
entry->key.vlan_id); entry->key.vlan_id);
hash_del(&entry->entry); hash_del(&entry->entry);
...@@ -3743,7 +3732,7 @@ static void rocker_fdb_cleanup(unsigned long data) ...@@ -3743,7 +3732,7 @@ static void rocker_fdb_cleanup(unsigned long data)
} }
static int rocker_port_router_mac(struct rocker_port *rocker_port, static int rocker_port_router_mac(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
__be16 vlan_id) __be16 vlan_id)
{ {
u32 in_pport_mask = 0xffffffff; u32 in_pport_mask = 0xffffffff;
...@@ -3776,7 +3765,7 @@ static int rocker_port_router_mac(struct rocker_port *rocker_port, ...@@ -3776,7 +3765,7 @@ static int rocker_port_router_mac(struct rocker_port *rocker_port,
} }
static int rocker_port_fwding(struct rocker_port *rocker_port, static int rocker_port_fwding(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags) struct switchdev_trans *trans, int flags)
{ {
bool pop_vlan; bool pop_vlan;
u32 out_pport; u32 out_pport;
...@@ -3815,16 +3804,16 @@ static int rocker_port_fwding(struct rocker_port *rocker_port, ...@@ -3815,16 +3804,16 @@ static int rocker_port_fwding(struct rocker_port *rocker_port,
} }
static int rocker_port_stp_update(struct rocker_port *rocker_port, static int rocker_port_stp_update(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags, struct switchdev_trans *trans, int flags,
u8 state) u8 state)
{ {
bool want[ROCKER_CTRL_MAX] = { 0, }; bool want[ROCKER_CTRL_MAX] = { 0, };
bool prev_ctrls[ROCKER_CTRL_MAX]; bool prev_ctrls[ROCKER_CTRL_MAX];
u8 prev_state; u8 uninitialized_var(prev_state);
int err; int err;
int i; int i;
if (trans == SWITCHDEV_TRANS_PREPARE) { if (switchdev_trans_ph_prepare(trans)) {
memcpy(prev_ctrls, rocker_port->ctrls, sizeof(prev_ctrls)); memcpy(prev_ctrls, rocker_port->ctrls, sizeof(prev_ctrls));
prev_state = rocker_port->stp_state; prev_state = rocker_port->stp_state;
} }
...@@ -3876,7 +3865,7 @@ static int rocker_port_stp_update(struct rocker_port *rocker_port, ...@@ -3876,7 +3865,7 @@ static int rocker_port_stp_update(struct rocker_port *rocker_port,
err = rocker_port_fwding(rocker_port, trans, flags); err = rocker_port_fwding(rocker_port, trans, flags);
err_out: err_out:
if (trans == SWITCHDEV_TRANS_PREPARE) { if (switchdev_trans_ph_prepare(trans)) {
memcpy(rocker_port->ctrls, prev_ctrls, sizeof(prev_ctrls)); memcpy(rocker_port->ctrls, prev_ctrls, sizeof(prev_ctrls));
rocker_port->stp_state = prev_state; rocker_port->stp_state = prev_state;
} }
...@@ -3885,7 +3874,7 @@ static int rocker_port_stp_update(struct rocker_port *rocker_port, ...@@ -3885,7 +3874,7 @@ static int rocker_port_stp_update(struct rocker_port *rocker_port,
} }
static int rocker_port_fwd_enable(struct rocker_port *rocker_port, static int rocker_port_fwd_enable(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags) struct switchdev_trans *trans, int flags)
{ {
if (rocker_port_is_bridged(rocker_port)) if (rocker_port_is_bridged(rocker_port))
/* bridge STP will enable port */ /* bridge STP will enable port */
...@@ -3897,7 +3886,7 @@ static int rocker_port_fwd_enable(struct rocker_port *rocker_port, ...@@ -3897,7 +3886,7 @@ static int rocker_port_fwd_enable(struct rocker_port *rocker_port,
} }
static int rocker_port_fwd_disable(struct rocker_port *rocker_port, static int rocker_port_fwd_disable(struct rocker_port *rocker_port,
enum switchdev_trans trans, int flags) struct switchdev_trans *trans, int flags)
{ {
if (rocker_port_is_bridged(rocker_port)) if (rocker_port_is_bridged(rocker_port))
/* bridge STP will disable port */ /* bridge STP will disable port */
...@@ -3995,7 +3984,7 @@ rocker_port_internal_vlan_id_put(const struct rocker_port *rocker_port, ...@@ -3995,7 +3984,7 @@ rocker_port_internal_vlan_id_put(const struct rocker_port *rocker_port,
} }
static int rocker_port_fib_ipv4(struct rocker_port *rocker_port, static int rocker_port_fib_ipv4(struct rocker_port *rocker_port,
enum switchdev_trans trans, __be32 dst, struct switchdev_trans *trans, __be32 dst,
int dst_len, const struct fib_info *fi, int dst_len, const struct fib_info *fi,
u32 tb_id, int flags) u32 tb_id, int flags)
{ {
...@@ -4069,7 +4058,7 @@ static int rocker_port_open(struct net_device *dev) ...@@ -4069,7 +4058,7 @@ static int rocker_port_open(struct net_device *dev)
goto err_request_rx_irq; goto err_request_rx_irq;
} }
err = rocker_port_fwd_enable(rocker_port, SWITCHDEV_TRANS_NONE, 0); err = rocker_port_fwd_enable(rocker_port, NULL, 0);
if (err) if (err)
goto err_fwd_enable; goto err_fwd_enable;
...@@ -4097,7 +4086,7 @@ static int rocker_port_stop(struct net_device *dev) ...@@ -4097,7 +4086,7 @@ static int rocker_port_stop(struct net_device *dev)
rocker_port_set_enable(rocker_port, false); rocker_port_set_enable(rocker_port, false);
napi_disable(&rocker_port->napi_rx); napi_disable(&rocker_port->napi_rx);
napi_disable(&rocker_port->napi_tx); napi_disable(&rocker_port->napi_tx);
rocker_port_fwd_disable(rocker_port, SWITCHDEV_TRANS_NONE, rocker_port_fwd_disable(rocker_port, NULL,
ROCKER_OP_FLAG_NOWAIT); ROCKER_OP_FLAG_NOWAIT);
free_irq(rocker_msix_rx_vector(rocker_port), rocker_port); free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);
free_irq(rocker_msix_tx_vector(rocker_port), rocker_port); free_irq(rocker_msix_tx_vector(rocker_port), rocker_port);
...@@ -4283,7 +4272,7 @@ static int rocker_port_get_phys_port_name(struct net_device *dev, ...@@ -4283,7 +4272,7 @@ static int rocker_port_get_phys_port_name(struct net_device *dev,
struct port_name name = { .buf = buf, .len = len }; struct port_name name = { .buf = buf, .len = len };
int err; int err;
err = rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0, err = rocker_cmd_exec(rocker_port, NULL, 0,
rocker_cmd_get_port_settings_prep, NULL, rocker_cmd_get_port_settings_prep, NULL,
rocker_cmd_get_port_settings_phys_name_proc, rocker_cmd_get_port_settings_phys_name_proc,
&name); &name);
...@@ -4308,7 +4297,7 @@ static void rocker_port_neigh_destroy(struct neighbour *n) ...@@ -4308,7 +4297,7 @@ static void rocker_port_neigh_destroy(struct neighbour *n)
int flags = ROCKER_OP_FLAG_REMOVE | ROCKER_OP_FLAG_NOWAIT; int flags = ROCKER_OP_FLAG_REMOVE | ROCKER_OP_FLAG_NOWAIT;
__be32 ip_addr = *(__be32 *)n->primary_key; __be32 ip_addr = *(__be32 *)n->primary_key;
rocker_port_ipv4_neigh(rocker_port, SWITCHDEV_TRANS_NONE, rocker_port_ipv4_neigh(rocker_port, NULL,
flags, ip_addr, n->ha); flags, ip_addr, n->ha);
} }
...@@ -4354,18 +4343,8 @@ static int rocker_port_attr_get(struct net_device *dev, ...@@ -4354,18 +4343,8 @@ static int rocker_port_attr_get(struct net_device *dev,
return 0; return 0;
} }
static void rocker_port_trans_abort(const struct rocker_port *rocker_port)
{
struct list_head *mem, *tmp;
list_for_each_safe(mem, tmp, &rocker_port->trans_mem) {
list_del(mem);
kfree(mem);
}
}
static int rocker_port_brport_flags_set(struct rocker_port *rocker_port, static int rocker_port_brport_flags_set(struct rocker_port *rocker_port,
enum switchdev_trans trans, struct switchdev_trans *trans,
unsigned long brport_flags) unsigned long brport_flags)
{ {
unsigned long orig_flags; unsigned long orig_flags;
...@@ -4376,37 +4355,27 @@ static int rocker_port_brport_flags_set(struct rocker_port *rocker_port, ...@@ -4376,37 +4355,27 @@ static int rocker_port_brport_flags_set(struct rocker_port *rocker_port,
if ((orig_flags ^ rocker_port->brport_flags) & BR_LEARNING) if ((orig_flags ^ rocker_port->brport_flags) & BR_LEARNING)
err = rocker_port_set_learning(rocker_port, trans); err = rocker_port_set_learning(rocker_port, trans);
if (trans == SWITCHDEV_TRANS_PREPARE) if (switchdev_trans_ph_prepare(trans))
rocker_port->brport_flags = orig_flags; rocker_port->brport_flags = orig_flags;
return err; return err;
} }
static int rocker_port_attr_set(struct net_device *dev, static int rocker_port_attr_set(struct net_device *dev,
struct switchdev_attr *attr) struct switchdev_attr *attr,
struct switchdev_trans *trans)
{ {
struct rocker_port *rocker_port = netdev_priv(dev); struct rocker_port *rocker_port = netdev_priv(dev);
int err = 0; int err = 0;
switch (attr->trans) {
case SWITCHDEV_TRANS_PREPARE:
BUG_ON(!list_empty(&rocker_port->trans_mem));
break;
case SWITCHDEV_TRANS_ABORT:
rocker_port_trans_abort(rocker_port);
return 0;
default:
break;
}
switch (attr->id) { switch (attr->id) {
case SWITCHDEV_ATTR_PORT_STP_STATE: case SWITCHDEV_ATTR_PORT_STP_STATE:
err = rocker_port_stp_update(rocker_port, attr->trans, err = rocker_port_stp_update(rocker_port, trans,
ROCKER_OP_FLAG_NOWAIT, ROCKER_OP_FLAG_NOWAIT,
attr->u.stp_state); attr->u.stp_state);
break; break;
case SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS: case SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS:
err = rocker_port_brport_flags_set(rocker_port, attr->trans, err = rocker_port_brport_flags_set(rocker_port, trans,
attr->u.brport_flags); attr->u.brport_flags);
break; break;
default: default:
...@@ -4418,7 +4387,8 @@ static int rocker_port_attr_set(struct net_device *dev, ...@@ -4418,7 +4387,8 @@ static int rocker_port_attr_set(struct net_device *dev,
} }
static int rocker_port_vlan_add(struct rocker_port *rocker_port, static int rocker_port_vlan_add(struct rocker_port *rocker_port,
enum switchdev_trans trans, u16 vid, u16 flags) struct switchdev_trans *trans,
u16 vid, u16 flags)
{ {
int err; int err;
...@@ -4437,7 +4407,7 @@ static int rocker_port_vlan_add(struct rocker_port *rocker_port, ...@@ -4437,7 +4407,7 @@ static int rocker_port_vlan_add(struct rocker_port *rocker_port,
} }
static int rocker_port_vlans_add(struct rocker_port *rocker_port, static int rocker_port_vlans_add(struct rocker_port *rocker_port,
enum switchdev_trans trans, struct switchdev_trans *trans,
const struct switchdev_obj_vlan *vlan) const struct switchdev_obj_vlan *vlan)
{ {
u16 vid; u16 vid;
...@@ -4454,7 +4424,7 @@ static int rocker_port_vlans_add(struct rocker_port *rocker_port, ...@@ -4454,7 +4424,7 @@ static int rocker_port_vlans_add(struct rocker_port *rocker_port,
} }
static int rocker_port_fdb_add(struct rocker_port *rocker_port, static int rocker_port_fdb_add(struct rocker_port *rocker_port,
enum switchdev_trans trans, struct switchdev_trans *trans,
const struct switchdev_obj_fdb *fdb) const struct switchdev_obj_fdb *fdb)
{ {
__be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, fdb->vid, NULL); __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, fdb->vid, NULL);
...@@ -4467,36 +4437,26 @@ static int rocker_port_fdb_add(struct rocker_port *rocker_port, ...@@ -4467,36 +4437,26 @@ static int rocker_port_fdb_add(struct rocker_port *rocker_port,
} }
static int rocker_port_obj_add(struct net_device *dev, static int rocker_port_obj_add(struct net_device *dev,
struct switchdev_obj *obj) struct switchdev_obj *obj,
struct switchdev_trans *trans)
{ {
struct rocker_port *rocker_port = netdev_priv(dev); struct rocker_port *rocker_port = netdev_priv(dev);
const struct switchdev_obj_ipv4_fib *fib4; const struct switchdev_obj_ipv4_fib *fib4;
int err = 0; int err = 0;
switch (obj->trans) {
case SWITCHDEV_TRANS_PREPARE:
BUG_ON(!list_empty(&rocker_port->trans_mem));
break;
case SWITCHDEV_TRANS_ABORT:
rocker_port_trans_abort(rocker_port);
return 0;
default:
break;
}
switch (obj->id) { switch (obj->id) {
case SWITCHDEV_OBJ_PORT_VLAN: case SWITCHDEV_OBJ_PORT_VLAN:
err = rocker_port_vlans_add(rocker_port, obj->trans, err = rocker_port_vlans_add(rocker_port, trans,
&obj->u.vlan); &obj->u.vlan);
break; break;
case SWITCHDEV_OBJ_IPV4_FIB: case SWITCHDEV_OBJ_IPV4_FIB:
fib4 = &obj->u.ipv4_fib; fib4 = &obj->u.ipv4_fib;
err = rocker_port_fib_ipv4(rocker_port, obj->trans, err = rocker_port_fib_ipv4(rocker_port, trans,
htonl(fib4->dst), fib4->dst_len, htonl(fib4->dst), fib4->dst_len,
fib4->fi, fib4->tb_id, 0); fib4->fi, fib4->tb_id, 0);
break; break;
case SWITCHDEV_OBJ_PORT_FDB: case SWITCHDEV_OBJ_PORT_FDB:
err = rocker_port_fdb_add(rocker_port, obj->trans, &obj->u.fdb); err = rocker_port_fdb_add(rocker_port, trans, &obj->u.fdb);
break; break;
default: default:
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
...@@ -4511,12 +4471,12 @@ static int rocker_port_vlan_del(struct rocker_port *rocker_port, ...@@ -4511,12 +4471,12 @@ static int rocker_port_vlan_del(struct rocker_port *rocker_port,
{ {
int err; int err;
err = rocker_port_router_mac(rocker_port, SWITCHDEV_TRANS_NONE, err = rocker_port_router_mac(rocker_port, NULL,
ROCKER_OP_FLAG_REMOVE, htons(vid)); ROCKER_OP_FLAG_REMOVE, htons(vid));
if (err) if (err)
return err; return err;
return rocker_port_vlan(rocker_port, SWITCHDEV_TRANS_NONE, return rocker_port_vlan(rocker_port, NULL,
ROCKER_OP_FLAG_REMOVE, vid); ROCKER_OP_FLAG_REMOVE, vid);
} }
...@@ -4536,7 +4496,7 @@ static int rocker_port_vlans_del(struct rocker_port *rocker_port, ...@@ -4536,7 +4496,7 @@ static int rocker_port_vlans_del(struct rocker_port *rocker_port,
} }
static int rocker_port_fdb_del(struct rocker_port *rocker_port, static int rocker_port_fdb_del(struct rocker_port *rocker_port,
enum switchdev_trans trans, struct switchdev_trans *trans,
const struct switchdev_obj_fdb *fdb) const struct switchdev_obj_fdb *fdb)
{ {
__be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, fdb->vid, NULL); __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, fdb->vid, NULL);
...@@ -4561,13 +4521,13 @@ static int rocker_port_obj_del(struct net_device *dev, ...@@ -4561,13 +4521,13 @@ static int rocker_port_obj_del(struct net_device *dev,
break; break;
case SWITCHDEV_OBJ_IPV4_FIB: case SWITCHDEV_OBJ_IPV4_FIB:
fib4 = &obj->u.ipv4_fib; fib4 = &obj->u.ipv4_fib;
err = rocker_port_fib_ipv4(rocker_port, SWITCHDEV_TRANS_NONE, err = rocker_port_fib_ipv4(rocker_port, NULL,
htonl(fib4->dst), fib4->dst_len, htonl(fib4->dst), fib4->dst_len,
fib4->fi, fib4->tb_id, fib4->fi, fib4->tb_id,
ROCKER_OP_FLAG_REMOVE); ROCKER_OP_FLAG_REMOVE);
break; break;
case SWITCHDEV_OBJ_PORT_FDB: case SWITCHDEV_OBJ_PORT_FDB:
err = rocker_port_fdb_del(rocker_port, obj->trans, &obj->u.fdb); err = rocker_port_fdb_del(rocker_port, NULL, &obj->u.fdb);
break; break;
default: default:
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
...@@ -4781,7 +4741,7 @@ rocker_cmd_get_port_stats_ethtool_proc(const struct rocker_port *rocker_port, ...@@ -4781,7 +4741,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, static int rocker_cmd_get_port_stats_ethtool(struct rocker_port *rocker_port,
void *priv) void *priv)
{ {
return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0, return rocker_cmd_exec(rocker_port, NULL, 0,
rocker_cmd_get_port_stats_prep, NULL, rocker_cmd_get_port_stats_prep, NULL,
rocker_cmd_get_port_stats_ethtool_proc, rocker_cmd_get_port_stats_ethtool_proc,
priv); priv);
...@@ -4973,8 +4933,7 @@ static void rocker_remove_ports(const struct rocker *rocker) ...@@ -4973,8 +4933,7 @@ static void rocker_remove_ports(const struct rocker *rocker)
rocker_port = rocker->ports[i]; rocker_port = rocker->ports[i];
if (!rocker_port) if (!rocker_port)
continue; continue;
rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE, rocker_port_ig_tbl(rocker_port, NULL, ROCKER_OP_FLAG_REMOVE);
ROCKER_OP_FLAG_REMOVE);
unregister_netdev(rocker_port->dev); unregister_netdev(rocker_port->dev);
free_netdev(rocker_port->dev); free_netdev(rocker_port->dev);
} }
...@@ -5013,7 +4972,6 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) ...@@ -5013,7 +4972,6 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
rocker_port->pport = port_number + 1; rocker_port->pport = port_number + 1;
rocker_port->brport_flags = BR_LEARNING | BR_LEARNING_SYNC; rocker_port->brport_flags = BR_LEARNING | BR_LEARNING_SYNC;
rocker_port->ageing_time = BR_DEFAULT_AGEING_TIME; rocker_port->ageing_time = BR_DEFAULT_AGEING_TIME;
INIT_LIST_HEAD(&rocker_port->trans_mem);
rocker_port_dev_addr_init(rocker_port); rocker_port_dev_addr_init(rocker_port);
dev->netdev_ops = &rocker_port_netdev_ops; dev->netdev_ops = &rocker_port_netdev_ops;
...@@ -5036,9 +4994,9 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) ...@@ -5036,9 +4994,9 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
switchdev_port_fwd_mark_set(rocker_port->dev, NULL, false); switchdev_port_fwd_mark_set(rocker_port->dev, NULL, false);
rocker_port_set_learning(rocker_port, SWITCHDEV_TRANS_NONE); rocker_port_set_learning(rocker_port, NULL);
err = rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE, 0); err = rocker_port_ig_tbl(rocker_port, NULL, 0);
if (err) { if (err) {
netdev_err(rocker_port->dev, "install ig port table failed\n"); netdev_err(rocker_port->dev, "install ig port table failed\n");
goto err_port_ig_tbl; goto err_port_ig_tbl;
...@@ -5047,8 +5005,7 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) ...@@ -5047,8 +5005,7 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
rocker_port->internal_vlan_id = rocker_port->internal_vlan_id =
rocker_port_internal_vlan_id_get(rocker_port, dev->ifindex); rocker_port_internal_vlan_id_get(rocker_port, dev->ifindex);
err = rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE, err = rocker_port_vlan_add(rocker_port, NULL, untagged_vid, 0);
untagged_vid, 0);
if (err) { if (err) {
netdev_err(rocker_port->dev, "install untagged VLAN failed\n"); netdev_err(rocker_port->dev, "install untagged VLAN failed\n");
goto err_untagged_vlan; goto err_untagged_vlan;
...@@ -5057,8 +5014,7 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) ...@@ -5057,8 +5014,7 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
return 0; return 0;
err_untagged_vlan: err_untagged_vlan:
rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE, rocker_port_ig_tbl(rocker_port, NULL, ROCKER_OP_FLAG_REMOVE);
ROCKER_OP_FLAG_REMOVE);
err_port_ig_tbl: err_port_ig_tbl:
rocker->ports[port_number] = NULL; rocker->ports[port_number] = NULL;
unregister_netdev(dev); unregister_netdev(dev);
...@@ -5325,8 +5281,7 @@ static int rocker_port_bridge_join(struct rocker_port *rocker_port, ...@@ -5325,8 +5281,7 @@ static int rocker_port_bridge_join(struct rocker_port *rocker_port,
rocker_port->bridge_dev = bridge; rocker_port->bridge_dev = bridge;
switchdev_port_fwd_mark_set(rocker_port->dev, bridge, true); switchdev_port_fwd_mark_set(rocker_port->dev, bridge, true);
return rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE, return rocker_port_vlan_add(rocker_port, NULL, untagged_vid, 0);
untagged_vid, 0);
} }
static int rocker_port_bridge_leave(struct rocker_port *rocker_port) static int rocker_port_bridge_leave(struct rocker_port *rocker_port)
...@@ -5348,14 +5303,12 @@ static int rocker_port_bridge_leave(struct rocker_port *rocker_port) ...@@ -5348,14 +5303,12 @@ static int rocker_port_bridge_leave(struct rocker_port *rocker_port)
false); false);
rocker_port->bridge_dev = NULL; rocker_port->bridge_dev = NULL;
err = rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE, err = rocker_port_vlan_add(rocker_port, NULL, untagged_vid, 0);
untagged_vid, 0);
if (err) if (err)
return err; return err;
if (rocker_port->dev->flags & IFF_UP) if (rocker_port->dev->flags & IFF_UP)
err = rocker_port_fwd_enable(rocker_port, err = rocker_port_fwd_enable(rocker_port, NULL, 0);
SWITCHDEV_TRANS_NONE, 0);
return err; return err;
} }
...@@ -5368,10 +5321,10 @@ static int rocker_port_ovs_changed(struct rocker_port *rocker_port, ...@@ -5368,10 +5321,10 @@ static int rocker_port_ovs_changed(struct rocker_port *rocker_port,
rocker_port->bridge_dev = master; rocker_port->bridge_dev = master;
err = rocker_port_fwd_disable(rocker_port, SWITCHDEV_TRANS_NONE, 0); err = rocker_port_fwd_disable(rocker_port, NULL, 0);
if (err) if (err)
return err; return err;
err = rocker_port_fwd_enable(rocker_port, SWITCHDEV_TRANS_NONE, 0); err = rocker_port_fwd_enable(rocker_port, NULL, 0);
return err; return err;
} }
...@@ -5449,8 +5402,7 @@ static int rocker_neigh_update(struct net_device *dev, struct neighbour *n) ...@@ -5449,8 +5402,7 @@ static int rocker_neigh_update(struct net_device *dev, struct neighbour *n)
ROCKER_OP_FLAG_NOWAIT; ROCKER_OP_FLAG_NOWAIT;
__be32 ip_addr = *(__be32 *)n->primary_key; __be32 ip_addr = *(__be32 *)n->primary_key;
return rocker_port_ipv4_neigh(rocker_port, SWITCHDEV_TRANS_NONE, return rocker_port_ipv4_neigh(rocker_port, NULL, flags, ip_addr, n->ha);
flags, ip_addr, n->ha);
} }
static int rocker_netevent_event(struct notifier_block *unused, static int rocker_netevent_event(struct notifier_block *unused,
......
/* /*
* include/net/switchdev.h - Switch device API * include/net/switchdev.h - Switch device API
* Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us> * Copyright (c) 2014-2015 Jiri Pirko <jiri@resnulli.us>
* Copyright (c) 2014-2015 Scott Feldman <sfeldma@gmail.com> * Copyright (c) 2014-2015 Scott Feldman <sfeldma@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -13,16 +13,31 @@ ...@@ -13,16 +13,31 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/list.h>
#define SWITCHDEV_F_NO_RECURSE BIT(0) #define SWITCHDEV_F_NO_RECURSE BIT(0)
enum switchdev_trans { struct switchdev_trans_item {
SWITCHDEV_TRANS_NONE, struct list_head list;
SWITCHDEV_TRANS_PREPARE, void *data;
SWITCHDEV_TRANS_ABORT, void (*destructor)(const void *data);
SWITCHDEV_TRANS_COMMIT,
}; };
struct switchdev_trans {
struct list_head item_list;
bool ph_prepare;
};
static inline bool switchdev_trans_ph_prepare(struct switchdev_trans *trans)
{
return trans && trans->ph_prepare;
}
static inline bool switchdev_trans_ph_commit(struct switchdev_trans *trans)
{
return trans && !trans->ph_prepare;
}
enum switchdev_attr_id { enum switchdev_attr_id {
SWITCHDEV_ATTR_UNDEFINED, SWITCHDEV_ATTR_UNDEFINED,
SWITCHDEV_ATTR_PORT_PARENT_ID, SWITCHDEV_ATTR_PORT_PARENT_ID,
...@@ -32,7 +47,6 @@ enum switchdev_attr_id { ...@@ -32,7 +47,6 @@ enum switchdev_attr_id {
struct switchdev_attr { struct switchdev_attr {
enum switchdev_attr_id id; enum switchdev_attr_id id;
enum switchdev_trans trans;
u32 flags; u32 flags;
union { union {
struct netdev_phys_item_id ppid; /* PORT_PARENT_ID */ struct netdev_phys_item_id ppid; /* PORT_PARENT_ID */
...@@ -52,7 +66,6 @@ enum switchdev_obj_id { ...@@ -52,7 +66,6 @@ enum switchdev_obj_id {
struct switchdev_obj { struct switchdev_obj {
enum switchdev_obj_id id; enum switchdev_obj_id id;
enum switchdev_trans trans;
int (*cb)(struct net_device *dev, struct switchdev_obj *obj); int (*cb)(struct net_device *dev, struct switchdev_obj *obj);
union { union {
struct switchdev_obj_vlan { /* PORT_VLAN */ struct switchdev_obj_vlan { /* PORT_VLAN */
...@@ -77,6 +90,11 @@ struct switchdev_obj { ...@@ -77,6 +90,11 @@ struct switchdev_obj {
} u; } u;
}; };
void switchdev_trans_item_enqueue(struct switchdev_trans *trans,
void *data, void (*destructor)(void const *),
struct switchdev_trans_item *tritem);
void *switchdev_trans_item_dequeue(struct switchdev_trans *trans);
/** /**
* struct switchdev_ops - switchdev operations * struct switchdev_ops - switchdev operations
* *
...@@ -94,9 +112,11 @@ struct switchdev_ops { ...@@ -94,9 +112,11 @@ struct switchdev_ops {
int (*switchdev_port_attr_get)(struct net_device *dev, int (*switchdev_port_attr_get)(struct net_device *dev,
struct switchdev_attr *attr); struct switchdev_attr *attr);
int (*switchdev_port_attr_set)(struct net_device *dev, int (*switchdev_port_attr_set)(struct net_device *dev,
struct switchdev_attr *attr); struct switchdev_attr *attr,
struct switchdev_trans *trans);
int (*switchdev_port_obj_add)(struct net_device *dev, int (*switchdev_port_obj_add)(struct net_device *dev,
struct switchdev_obj *obj); struct switchdev_obj *obj,
struct switchdev_trans *trans);
int (*switchdev_port_obj_del)(struct net_device *dev, int (*switchdev_port_obj_del)(struct net_device *dev,
struct switchdev_obj *obj); struct switchdev_obj *obj);
int (*switchdev_port_obj_dump)(struct net_device *dev, int (*switchdev_port_obj_dump)(struct net_device *dev,
......
...@@ -242,7 +242,8 @@ static int dsa_bridge_check_vlan_range(struct dsa_switch *ds, ...@@ -242,7 +242,8 @@ static int dsa_bridge_check_vlan_range(struct dsa_switch *ds,
} }
static int dsa_slave_port_vlan_add(struct net_device *dev, static int dsa_slave_port_vlan_add(struct net_device *dev,
struct switchdev_obj *obj) struct switchdev_obj *obj,
struct switchdev_trans *trans)
{ {
struct switchdev_obj_vlan *vlan = &obj->u.vlan; struct switchdev_obj_vlan *vlan = &obj->u.vlan;
struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_slave_priv *p = netdev_priv(dev);
...@@ -250,8 +251,7 @@ static int dsa_slave_port_vlan_add(struct net_device *dev, ...@@ -250,8 +251,7 @@ static int dsa_slave_port_vlan_add(struct net_device *dev,
u16 vid; u16 vid;
int err; int err;
switch (obj->trans) { if (switchdev_trans_ph_prepare(trans)) {
case SWITCHDEV_TRANS_PREPARE:
if (!ds->drv->port_vlan_add || !ds->drv->port_pvid_set) if (!ds->drv->port_vlan_add || !ds->drv->port_pvid_set)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -263,8 +263,7 @@ static int dsa_slave_port_vlan_add(struct net_device *dev, ...@@ -263,8 +263,7 @@ static int dsa_slave_port_vlan_add(struct net_device *dev,
vlan->vid_end); vlan->vid_end);
if (err) if (err)
return err; return err;
break; } else {
case SWITCHDEV_TRANS_COMMIT:
for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) { for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
err = ds->drv->port_vlan_add(ds, p->port, vid, err = ds->drv->port_vlan_add(ds, p->port, vid,
vlan->flags & vlan->flags &
...@@ -274,9 +273,6 @@ static int dsa_slave_port_vlan_add(struct net_device *dev, ...@@ -274,9 +273,6 @@ static int dsa_slave_port_vlan_add(struct net_device *dev,
if (err) if (err)
return err; return err;
} }
break;
default:
return -EOPNOTSUPP;
} }
return 0; return 0;
...@@ -347,16 +343,17 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev, ...@@ -347,16 +343,17 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev,
} }
static int dsa_slave_port_fdb_add(struct net_device *dev, static int dsa_slave_port_fdb_add(struct net_device *dev,
struct switchdev_obj *obj) struct switchdev_obj *obj,
struct switchdev_trans *trans)
{ {
struct switchdev_obj_fdb *fdb = &obj->u.fdb; struct switchdev_obj_fdb *fdb = &obj->u.fdb;
struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_slave_priv *p = netdev_priv(dev);
struct dsa_switch *ds = p->parent; struct dsa_switch *ds = p->parent;
int ret = -EOPNOTSUPP; int ret = -EOPNOTSUPP;
if (obj->trans == SWITCHDEV_TRANS_PREPARE) if (switchdev_trans_ph_prepare(trans))
ret = ds->drv->port_fdb_add ? 0 : -EOPNOTSUPP; ret = ds->drv->port_fdb_add ? 0 : -EOPNOTSUPP;
else if (obj->trans == SWITCHDEV_TRANS_COMMIT) else
ret = ds->drv->port_fdb_add(ds, p->port, fdb->addr, fdb->vid); ret = ds->drv->port_fdb_add(ds, p->port, fdb->addr, fdb->vid);
return ret; return ret;
...@@ -456,13 +453,14 @@ static int dsa_slave_stp_update(struct net_device *dev, u8 state) ...@@ -456,13 +453,14 @@ static int dsa_slave_stp_update(struct net_device *dev, u8 state)
} }
static int dsa_slave_port_attr_set(struct net_device *dev, static int dsa_slave_port_attr_set(struct net_device *dev,
struct switchdev_attr *attr) struct switchdev_attr *attr,
struct switchdev_trans *trans)
{ {
int ret = 0; int ret = 0;
switch (attr->id) { switch (attr->id) {
case SWITCHDEV_ATTR_PORT_STP_STATE: case SWITCHDEV_ATTR_PORT_STP_STATE:
if (attr->trans == SWITCHDEV_TRANS_COMMIT) if (switchdev_trans_ph_commit(trans))
ret = dsa_slave_stp_update(dev, attr->u.stp_state); ret = dsa_slave_stp_update(dev, attr->u.stp_state);
break; break;
default: default:
...@@ -474,7 +472,8 @@ static int dsa_slave_port_attr_set(struct net_device *dev, ...@@ -474,7 +472,8 @@ static int dsa_slave_port_attr_set(struct net_device *dev,
} }
static int dsa_slave_port_obj_add(struct net_device *dev, static int dsa_slave_port_obj_add(struct net_device *dev,
struct switchdev_obj *obj) struct switchdev_obj *obj,
struct switchdev_trans *trans)
{ {
int err; int err;
...@@ -485,10 +484,10 @@ static int dsa_slave_port_obj_add(struct net_device *dev, ...@@ -485,10 +484,10 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
switch (obj->id) { switch (obj->id) {
case SWITCHDEV_OBJ_PORT_FDB: case SWITCHDEV_OBJ_PORT_FDB:
err = dsa_slave_port_fdb_add(dev, obj); err = dsa_slave_port_fdb_add(dev, obj, trans);
break; break;
case SWITCHDEV_OBJ_PORT_VLAN: case SWITCHDEV_OBJ_PORT_VLAN:
err = dsa_slave_port_vlan_add(dev, obj); err = dsa_slave_port_vlan_add(dev, obj, trans);
break; break;
default: default:
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
......
/* /*
* net/switchdev/switchdev.c - Switch device API * net/switchdev/switchdev.c - Switch device API
* Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us> * Copyright (c) 2014-2015 Jiri Pirko <jiri@resnulli.us>
* Copyright (c) 2014-2015 Scott Feldman <sfeldma@gmail.com> * Copyright (c) 2014-2015 Scott Feldman <sfeldma@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -16,9 +16,82 @@ ...@@ -16,9 +16,82 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_bridge.h> #include <linux/if_bridge.h>
#include <linux/list.h>
#include <net/ip_fib.h> #include <net/ip_fib.h>
#include <net/switchdev.h> #include <net/switchdev.h>
/**
* switchdev_trans_item_enqueue - Enqueue data item to transaction queue
*
* @trans: transaction
* @data: pointer to data being queued
* @destructor: data destructor
* @tritem: transaction item being queued
*
* Enqeueue data item to transaction queue. tritem is typically placed in
* cointainter pointed at by data pointer. Destructor is called on
* transaction abort and after successful commit phase in case
* the caller did not dequeue the item before.
*/
void switchdev_trans_item_enqueue(struct switchdev_trans *trans,
void *data, void (*destructor)(void const *),
struct switchdev_trans_item *tritem)
{
tritem->data = data;
tritem->destructor = destructor;
list_add_tail(&tritem->list, &trans->item_list);
}
EXPORT_SYMBOL_GPL(switchdev_trans_item_enqueue);
static struct switchdev_trans_item *
__switchdev_trans_item_dequeue(struct switchdev_trans *trans)
{
struct switchdev_trans_item *tritem;
if (list_empty(&trans->item_list))
return NULL;
tritem = list_first_entry(&trans->item_list,
struct switchdev_trans_item, list);
list_del(&tritem->list);
return tritem;
}
/**
* switchdev_trans_item_dequeue - Dequeue data item from transaction queue
*
* @trans: transaction
*/
void *switchdev_trans_item_dequeue(struct switchdev_trans *trans)
{
struct switchdev_trans_item *tritem;
tritem = __switchdev_trans_item_dequeue(trans);
BUG_ON(!tritem);
return tritem->data;
}
EXPORT_SYMBOL_GPL(switchdev_trans_item_dequeue);
static void switchdev_trans_init(struct switchdev_trans *trans)
{
INIT_LIST_HEAD(&trans->item_list);
}
static void switchdev_trans_items_destroy(struct switchdev_trans *trans)
{
struct switchdev_trans_item *tritem;
while ((tritem = __switchdev_trans_item_dequeue(trans)))
tritem->destructor(tritem->data);
}
static void switchdev_trans_items_warn_destroy(struct net_device *dev,
struct switchdev_trans *trans)
{
WARN(!list_empty(&trans->item_list), "%s: transaction item queue is not empty.\n",
dev->name);
switchdev_trans_items_destroy(trans);
}
/** /**
* switchdev_port_attr_get - Get port attribute * switchdev_port_attr_get - Get port attribute
* *
...@@ -62,7 +135,8 @@ int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr) ...@@ -62,7 +135,8 @@ int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr)
EXPORT_SYMBOL_GPL(switchdev_port_attr_get); EXPORT_SYMBOL_GPL(switchdev_port_attr_get);
static int __switchdev_port_attr_set(struct net_device *dev, static int __switchdev_port_attr_set(struct net_device *dev,
struct switchdev_attr *attr) struct switchdev_attr *attr,
struct switchdev_trans *trans)
{ {
const struct switchdev_ops *ops = dev->switchdev_ops; const struct switchdev_ops *ops = dev->switchdev_ops;
struct net_device *lower_dev; struct net_device *lower_dev;
...@@ -70,7 +144,7 @@ static int __switchdev_port_attr_set(struct net_device *dev, ...@@ -70,7 +144,7 @@ static int __switchdev_port_attr_set(struct net_device *dev,
int err = -EOPNOTSUPP; int err = -EOPNOTSUPP;
if (ops && ops->switchdev_port_attr_set) if (ops && ops->switchdev_port_attr_set)
return ops->switchdev_port_attr_set(dev, attr); return ops->switchdev_port_attr_set(dev, attr, trans);
if (attr->flags & SWITCHDEV_F_NO_RECURSE) if (attr->flags & SWITCHDEV_F_NO_RECURSE)
return err; return err;
...@@ -81,7 +155,7 @@ static int __switchdev_port_attr_set(struct net_device *dev, ...@@ -81,7 +155,7 @@ static int __switchdev_port_attr_set(struct net_device *dev,
*/ */
netdev_for_each_lower_dev(dev, lower_dev, iter) { netdev_for_each_lower_dev(dev, lower_dev, iter) {
err = __switchdev_port_attr_set(lower_dev, attr); err = __switchdev_port_attr_set(lower_dev, attr, trans);
if (err) if (err)
break; break;
} }
...@@ -144,6 +218,7 @@ static int switchdev_port_attr_set_defer(struct net_device *dev, ...@@ -144,6 +218,7 @@ static int switchdev_port_attr_set_defer(struct net_device *dev,
*/ */
int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr)
{ {
struct switchdev_trans trans;
int err; int err;
if (!rtnl_is_locked()) { if (!rtnl_is_locked()) {
...@@ -156,6 +231,8 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) ...@@ -156,6 +231,8 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr)
return switchdev_port_attr_set_defer(dev, attr); return switchdev_port_attr_set_defer(dev, attr);
} }
switchdev_trans_init(&trans);
/* Phase I: prepare for attr set. Driver/device should fail /* Phase I: prepare for attr set. Driver/device should fail
* here if there are going to be issues in the commit phase, * here if there are going to be issues in the commit phase,
* such as lack of resources or support. The driver/device * such as lack of resources or support. The driver/device
...@@ -163,18 +240,16 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) ...@@ -163,18 +240,16 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr)
* but should not commit the attr. * but should not commit the attr.
*/ */
attr->trans = SWITCHDEV_TRANS_PREPARE; trans.ph_prepare = true;
err = __switchdev_port_attr_set(dev, attr); err = __switchdev_port_attr_set(dev, attr, &trans);
if (err) { if (err) {
/* Prepare phase failed: abort the transaction. Any /* Prepare phase failed: abort the transaction. Any
* resources reserved in the prepare phase are * resources reserved in the prepare phase are
* released. * released.
*/ */
if (err != -EOPNOTSUPP) { if (err != -EOPNOTSUPP)
attr->trans = SWITCHDEV_TRANS_ABORT; switchdev_trans_items_destroy(&trans);
__switchdev_port_attr_set(dev, attr);
}
return err; return err;
} }
...@@ -184,17 +259,19 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) ...@@ -184,17 +259,19 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr)
* because the driver said everythings was OK in phase I. * because the driver said everythings was OK in phase I.
*/ */
attr->trans = SWITCHDEV_TRANS_COMMIT; trans.ph_prepare = false;
err = __switchdev_port_attr_set(dev, attr); err = __switchdev_port_attr_set(dev, attr, &trans);
WARN(err, "%s: Commit of attribute (id=%d) failed.\n", WARN(err, "%s: Commit of attribute (id=%d) failed.\n",
dev->name, attr->id); dev->name, attr->id);
switchdev_trans_items_warn_destroy(dev, &trans);
return err; return err;
} }
EXPORT_SYMBOL_GPL(switchdev_port_attr_set); EXPORT_SYMBOL_GPL(switchdev_port_attr_set);
static int __switchdev_port_obj_add(struct net_device *dev, static int __switchdev_port_obj_add(struct net_device *dev,
struct switchdev_obj *obj) struct switchdev_obj *obj,
struct switchdev_trans *trans)
{ {
const struct switchdev_ops *ops = dev->switchdev_ops; const struct switchdev_ops *ops = dev->switchdev_ops;
struct net_device *lower_dev; struct net_device *lower_dev;
...@@ -202,7 +279,7 @@ static int __switchdev_port_obj_add(struct net_device *dev, ...@@ -202,7 +279,7 @@ static int __switchdev_port_obj_add(struct net_device *dev,
int err = -EOPNOTSUPP; int err = -EOPNOTSUPP;
if (ops && ops->switchdev_port_obj_add) if (ops && ops->switchdev_port_obj_add)
return ops->switchdev_port_obj_add(dev, obj); return ops->switchdev_port_obj_add(dev, obj, trans);
/* Switch device port(s) may be stacked under /* Switch device port(s) may be stacked under
* bond/team/vlan dev, so recurse down to add object on * bond/team/vlan dev, so recurse down to add object on
...@@ -210,7 +287,7 @@ static int __switchdev_port_obj_add(struct net_device *dev, ...@@ -210,7 +287,7 @@ static int __switchdev_port_obj_add(struct net_device *dev,
*/ */
netdev_for_each_lower_dev(dev, lower_dev, iter) { netdev_for_each_lower_dev(dev, lower_dev, iter) {
err = __switchdev_port_obj_add(lower_dev, obj); err = __switchdev_port_obj_add(lower_dev, obj, trans);
if (err) if (err)
break; break;
} }
...@@ -232,10 +309,13 @@ static int __switchdev_port_obj_add(struct net_device *dev, ...@@ -232,10 +309,13 @@ static int __switchdev_port_obj_add(struct net_device *dev,
*/ */
int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj)
{ {
struct switchdev_trans trans;
int err; int err;
ASSERT_RTNL(); ASSERT_RTNL();
switchdev_trans_init(&trans);
/* Phase I: prepare for obj add. Driver/device should fail /* Phase I: prepare for obj add. Driver/device should fail
* here if there are going to be issues in the commit phase, * here if there are going to be issues in the commit phase,
* such as lack of resources or support. The driver/device * such as lack of resources or support. The driver/device
...@@ -243,18 +323,16 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) ...@@ -243,18 +323,16 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj)
* but should not commit the obj. * but should not commit the obj.
*/ */
obj->trans = SWITCHDEV_TRANS_PREPARE; trans.ph_prepare = true;
err = __switchdev_port_obj_add(dev, obj); err = __switchdev_port_obj_add(dev, obj, &trans);
if (err) { if (err) {
/* Prepare phase failed: abort the transaction. Any /* Prepare phase failed: abort the transaction. Any
* resources reserved in the prepare phase are * resources reserved in the prepare phase are
* released. * released.
*/ */
if (err != -EOPNOTSUPP) { if (err != -EOPNOTSUPP)
obj->trans = SWITCHDEV_TRANS_ABORT; switchdev_trans_items_destroy(&trans);
__switchdev_port_obj_add(dev, obj);
}
return err; return err;
} }
...@@ -264,9 +342,10 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) ...@@ -264,9 +342,10 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj)
* because the driver said everythings was OK in phase I. * because the driver said everythings was OK in phase I.
*/ */
obj->trans = SWITCHDEV_TRANS_COMMIT; trans.ph_prepare = false;
err = __switchdev_port_obj_add(dev, obj); err = __switchdev_port_obj_add(dev, obj, &trans);
WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, obj->id); WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, obj->id);
switchdev_trans_items_warn_destroy(dev, &trans);
return err; return err;
} }
......
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