Skip to content

Commit 7fd94d8

Browse files
IoanaCiorneidavem330
authored andcommitted
staging: dpaa2-switch: add .ndo_start_xmit() callback
Implement the .ndo_start_xmit() callback for the switch port interfaces. For each of the switch ports, gather the corresponding queue destination ID (QDID) necessary for Tx enqueueing. We'll reserve 64 bytes for software annotations, where we keep a skb backpointer used on the Tx confirmation side for releasing the allocated memory. At the moment, we only support linear skbs. Also, add support for the Tx confirmation path which for the most part shares the code path with the normal Rx queue. Signed-off-by: Ioana Ciornei <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0b1b713 commit 7fd94d8

File tree

5 files changed

+245
-16
lines changed

5 files changed

+245
-16
lines changed

drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
#define DPSW_CMDID_IF_ENABLE DPSW_CMD_ID(0x03D)
4848
#define DPSW_CMDID_IF_DISABLE DPSW_CMD_ID(0x03E)
4949

50+
#define DPSW_CMDID_IF_GET_ATTR DPSW_CMD_ID(0x042)
51+
5052
#define DPSW_CMDID_IF_SET_MAX_FRAME_LENGTH DPSW_CMD_ID(0x044)
5153

5254
#define DPSW_CMDID_IF_GET_LINK_STATE DPSW_CMD_ID(0x046)
@@ -246,6 +248,28 @@ struct dpsw_cmd_if {
246248
__le16 if_id;
247249
};
248250

251+
#define DPSW_ADMIT_UNTAGGED_SHIFT 0
252+
#define DPSW_ADMIT_UNTAGGED_SIZE 4
253+
#define DPSW_ENABLED_SHIFT 5
254+
#define DPSW_ENABLED_SIZE 1
255+
#define DPSW_ACCEPT_ALL_VLAN_SHIFT 6
256+
#define DPSW_ACCEPT_ALL_VLAN_SIZE 1
257+
258+
struct dpsw_rsp_if_get_attr {
259+
/* cmd word 0 */
260+
/* from LSB: admit_untagged:4 enabled:1 accept_all_vlan:1 */
261+
u8 conf;
262+
u8 pad1;
263+
u8 num_tcs;
264+
u8 pad2;
265+
__le16 qdid;
266+
/* cmd word 1 */
267+
__le32 options;
268+
__le32 pad3;
269+
/* cmd word 2 */
270+
__le32 rate;
271+
};
272+
249273
struct dpsw_cmd_if_set_max_frame_length {
250274
__le16 if_id;
251275
__le16 frame_length;

drivers/staging/fsl-dpaa2/ethsw/dpsw.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,47 @@ int dpsw_if_disable(struct fsl_mc_io *mc_io,
642642
return mc_send_command(mc_io, &cmd);
643643
}
644644

645+
/**
646+
* dpsw_if_get_attributes() - Function obtains attributes of interface
647+
* @mc_io: Pointer to MC portal's I/O object
648+
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
649+
* @token: Token of DPSW object
650+
* @if_id: Interface Identifier
651+
* @attr: Returned interface attributes
652+
*
653+
* Return: Completion status. '0' on Success; Error code otherwise.
654+
*/
655+
int dpsw_if_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
656+
u16 if_id, struct dpsw_if_attr *attr)
657+
{
658+
struct dpsw_rsp_if_get_attr *rsp_params;
659+
struct fsl_mc_command cmd = { 0 };
660+
struct dpsw_cmd_if *cmd_params;
661+
int err;
662+
663+
cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_ATTR, cmd_flags,
664+
token);
665+
cmd_params = (struct dpsw_cmd_if *)cmd.params;
666+
cmd_params->if_id = cpu_to_le16(if_id);
667+
668+
err = mc_send_command(mc_io, &cmd);
669+
if (err)
670+
return err;
671+
672+
rsp_params = (struct dpsw_rsp_if_get_attr *)cmd.params;
673+
attr->num_tcs = rsp_params->num_tcs;
674+
attr->rate = le32_to_cpu(rsp_params->rate);
675+
attr->options = le32_to_cpu(rsp_params->options);
676+
attr->qdid = le16_to_cpu(rsp_params->qdid);
677+
attr->enabled = dpsw_get_field(rsp_params->conf, ENABLED);
678+
attr->accept_all_vlan = dpsw_get_field(rsp_params->conf,
679+
ACCEPT_ALL_VLAN);
680+
attr->admit_untagged = dpsw_get_field(rsp_params->conf,
681+
ADMIT_UNTAGGED);
682+
683+
return 0;
684+
}
685+
645686
/**
646687
* dpsw_if_set_max_frame_length() - Set Maximum Receive frame length.
647688
* @mc_io: Pointer to MC portal's I/O object

drivers/staging/fsl-dpaa2/ethsw/dpsw.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,34 @@ int dpsw_if_disable(struct fsl_mc_io *mc_io,
430430
u16 token,
431431
u16 if_id);
432432

433+
/**
434+
* struct dpsw_if_attr - Structure representing DPSW interface attributes
435+
* @num_tcs: Number of traffic classes
436+
* @rate: Transmit rate in bits per second
437+
* @options: Interface configuration options (bitmap)
438+
* @enabled: Indicates if interface is enabled
439+
* @accept_all_vlan: The device discards/accepts incoming frames
440+
* for VLANs that do not include this interface
441+
* @admit_untagged: When set to 'DPSW_ADMIT_ONLY_VLAN_TAGGED', the device
442+
* discards untagged frames or priority-tagged frames received on
443+
* this interface;
444+
* When set to 'DPSW_ADMIT_ALL', untagged frames or priority-
445+
* tagged frames received on this interface are accepted
446+
* @qdid: control frames transmit qdid
447+
*/
448+
struct dpsw_if_attr {
449+
u8 num_tcs;
450+
u32 rate;
451+
u32 options;
452+
int enabled;
453+
int accept_all_vlan;
454+
enum dpsw_accepted_frames admit_untagged;
455+
u16 qdid;
456+
};
457+
458+
int dpsw_if_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
459+
u16 if_id, struct dpsw_if_attr *attr);
460+
433461
int dpsw_if_set_max_frame_length(struct fsl_mc_io *mc_io,
434462
u32 cmd_flags,
435463
u16 token,

drivers/staging/fsl-dpaa2/ethsw/ethsw.c

Lines changed: 138 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -434,10 +434,13 @@ static int dpaa2_switch_port_carrier_state_sync(struct net_device *netdev)
434434
WARN_ONCE(state.up > 1, "Garbage read into link_state");
435435

436436
if (state.up != port_priv->link_state) {
437-
if (state.up)
437+
if (state.up) {
438438
netif_carrier_on(netdev);
439-
else
439+
netif_tx_start_all_queues(netdev);
440+
} else {
440441
netif_carrier_off(netdev);
442+
netif_tx_stop_all_queues(netdev);
443+
}
441444
port_priv->link_state = state.up;
442445
}
443446

@@ -491,9 +494,6 @@ static int dpaa2_switch_port_open(struct net_device *netdev)
491494
struct ethsw_core *ethsw = port_priv->ethsw_data;
492495
int err;
493496

494-
/* No need to allow Tx as control interface is disabled */
495-
netif_tx_stop_all_queues(netdev);
496-
497497
/* Explicitly set carrier off, otherwise
498498
* netif_carrier_ok() will return true and cause 'ip link show'
499499
* to report the LOWER_UP flag, even though the link
@@ -547,15 +547,6 @@ static int dpaa2_switch_port_stop(struct net_device *netdev)
547547
return 0;
548548
}
549549

550-
static netdev_tx_t dpaa2_switch_port_dropframe(struct sk_buff *skb,
551-
struct net_device *netdev)
552-
{
553-
/* we don't support I/O for now, drop the frame */
554-
dev_kfree_skb_any(skb);
555-
556-
return NETDEV_TX_OK;
557-
}
558-
559550
static int dpaa2_switch_port_parent_id(struct net_device *dev,
560551
struct netdev_phys_item_id *ppid)
561552
{
@@ -772,6 +763,115 @@ static void dpaa2_switch_free_fd(const struct ethsw_core *ethsw,
772763
dev_kfree_skb(skb);
773764
}
774765

766+
static int dpaa2_switch_build_single_fd(struct ethsw_core *ethsw,
767+
struct sk_buff *skb,
768+
struct dpaa2_fd *fd)
769+
{
770+
struct device *dev = ethsw->dev;
771+
struct sk_buff **skbh;
772+
dma_addr_t addr;
773+
u8 *buff_start;
774+
void *hwa;
775+
776+
buff_start = PTR_ALIGN(skb->data - DPAA2_SWITCH_TX_DATA_OFFSET -
777+
DPAA2_SWITCH_TX_BUF_ALIGN,
778+
DPAA2_SWITCH_TX_BUF_ALIGN);
779+
780+
/* Clear FAS to have consistent values for TX confirmation. It is
781+
* located in the first 8 bytes of the buffer's hardware annotation
782+
* area
783+
*/
784+
hwa = buff_start + DPAA2_SWITCH_SWA_SIZE;
785+
memset(hwa, 0, 8);
786+
787+
/* Store a backpointer to the skb at the beginning of the buffer
788+
* (in the private data area) such that we can release it
789+
* on Tx confirm
790+
*/
791+
skbh = (struct sk_buff **)buff_start;
792+
*skbh = skb;
793+
794+
addr = dma_map_single(dev, buff_start,
795+
skb_tail_pointer(skb) - buff_start,
796+
DMA_TO_DEVICE);
797+
if (unlikely(dma_mapping_error(dev, addr)))
798+
return -ENOMEM;
799+
800+
/* Setup the FD fields */
801+
memset(fd, 0, sizeof(*fd));
802+
803+
dpaa2_fd_set_addr(fd, addr);
804+
dpaa2_fd_set_offset(fd, (u16)(skb->data - buff_start));
805+
dpaa2_fd_set_len(fd, skb->len);
806+
dpaa2_fd_set_format(fd, dpaa2_fd_single);
807+
808+
return 0;
809+
}
810+
811+
static netdev_tx_t dpaa2_switch_port_tx(struct sk_buff *skb,
812+
struct net_device *net_dev)
813+
{
814+
struct ethsw_port_priv *port_priv = netdev_priv(net_dev);
815+
struct ethsw_core *ethsw = port_priv->ethsw_data;
816+
int retries = DPAA2_SWITCH_SWP_BUSY_RETRIES;
817+
struct dpaa2_fd fd;
818+
int err;
819+
820+
if (unlikely(skb_headroom(skb) < DPAA2_SWITCH_NEEDED_HEADROOM)) {
821+
struct sk_buff *ns;
822+
823+
ns = skb_realloc_headroom(skb, DPAA2_SWITCH_NEEDED_HEADROOM);
824+
if (unlikely(!ns)) {
825+
net_err_ratelimited("%s: Error reallocating skb headroom\n", net_dev->name);
826+
goto err_free_skb;
827+
}
828+
dev_consume_skb_any(skb);
829+
skb = ns;
830+
}
831+
832+
/* We'll be holding a back-reference to the skb until Tx confirmation */
833+
skb = skb_unshare(skb, GFP_ATOMIC);
834+
if (unlikely(!skb)) {
835+
/* skb_unshare() has already freed the skb */
836+
net_err_ratelimited("%s: Error copying the socket buffer\n", net_dev->name);
837+
goto err_exit;
838+
}
839+
840+
/* At this stage, we do not support non-linear skbs so just try to
841+
* linearize the skb and if that's not working, just drop the packet.
842+
*/
843+
err = skb_linearize(skb);
844+
if (err) {
845+
net_err_ratelimited("%s: skb_linearize error (%d)!\n", net_dev->name, err);
846+
goto err_free_skb;
847+
}
848+
849+
err = dpaa2_switch_build_single_fd(ethsw, skb, &fd);
850+
if (unlikely(err)) {
851+
net_err_ratelimited("%s: ethsw_build_*_fd() %d\n", net_dev->name, err);
852+
goto err_free_skb;
853+
}
854+
855+
do {
856+
err = dpaa2_io_service_enqueue_qd(NULL,
857+
port_priv->tx_qdid,
858+
8, 0, &fd);
859+
retries--;
860+
} while (err == -EBUSY && retries);
861+
862+
if (unlikely(err < 0)) {
863+
dpaa2_switch_free_fd(ethsw, &fd);
864+
goto err_exit;
865+
}
866+
867+
return NETDEV_TX_OK;
868+
869+
err_free_skb:
870+
dev_kfree_skb(skb);
871+
err_exit:
872+
return NETDEV_TX_OK;
873+
}
874+
775875
static const struct net_device_ops dpaa2_switch_port_ops = {
776876
.ndo_open = dpaa2_switch_port_open,
777877
.ndo_stop = dpaa2_switch_port_stop,
@@ -783,7 +883,7 @@ static const struct net_device_ops dpaa2_switch_port_ops = {
783883
.ndo_get_offload_stats = dpaa2_switch_port_get_offload_stats,
784884
.ndo_fdb_dump = dpaa2_switch_port_fdb_dump,
785885

786-
.ndo_start_xmit = dpaa2_switch_port_dropframe,
886+
.ndo_start_xmit = dpaa2_switch_port_tx,
787887
.ndo_get_port_parent_id = dpaa2_switch_port_parent_id,
788888
.ndo_get_phys_port_name = dpaa2_switch_port_get_phys_name,
789889
};
@@ -1436,6 +1536,12 @@ static struct sk_buff *dpaa2_switch_build_linear_skb(struct ethsw_core *ethsw,
14361536
return skb;
14371537
}
14381538

1539+
static void dpaa2_switch_tx_conf(struct dpaa2_switch_fq *fq,
1540+
const struct dpaa2_fd *fd)
1541+
{
1542+
dpaa2_switch_free_fd(fq->ethsw, fd);
1543+
}
1544+
14391545
static void dpaa2_switch_rx(struct dpaa2_switch_fq *fq,
14401546
const struct dpaa2_fd *fd)
14411547
{
@@ -1813,7 +1919,10 @@ static int dpaa2_switch_store_consume(struct dpaa2_switch_fq *fq)
18131919
continue;
18141920
}
18151921

1816-
dpaa2_switch_rx(fq, dpaa2_dq_fd(dq));
1922+
if (fq->type == DPSW_QUEUE_RX)
1923+
dpaa2_switch_rx(fq, dpaa2_dq_fd(dq));
1924+
else
1925+
dpaa2_switch_tx_conf(fq, dpaa2_dq_fd(dq));
18171926
cleaned++;
18181927

18191928
} while (!is_last);
@@ -2111,8 +2220,19 @@ static int dpaa2_switch_port_init(struct ethsw_port_priv *port_priv, u16 port)
21112220
.flags = BRIDGE_VLAN_INFO_UNTAGGED | BRIDGE_VLAN_INFO_PVID,
21122221
};
21132222
struct net_device *netdev = port_priv->netdev;
2223+
struct ethsw_core *ethsw = port_priv->ethsw_data;
2224+
struct dpsw_if_attr dpsw_if_attr;
21142225
int err;
21152226

2227+
/* Get the Tx queue for this specific port */
2228+
err = dpsw_if_get_attributes(ethsw->mc_io, 0, ethsw->dpsw_handle,
2229+
port_priv->idx, &dpsw_if_attr);
2230+
if (err) {
2231+
netdev_err(netdev, "dpsw_if_get_attributes err %d\n", err);
2232+
return err;
2233+
}
2234+
port_priv->tx_qdid = dpsw_if_attr.qdid;
2235+
21162236
/* We need to add VLAN 1 as the PVID on this port until it is under a
21172237
* bridge since the DPAA2 switch is not able to handle the traffic in a
21182238
* VLAN unaware fashion
@@ -2230,6 +2350,8 @@ static int dpaa2_switch_probe_port(struct ethsw_core *ethsw,
22302350
port_netdev->netdev_ops = &dpaa2_switch_port_ops;
22312351
port_netdev->ethtool_ops = &dpaa2_switch_port_ethtool_ops;
22322352

2353+
port_netdev->needed_headroom = DPAA2_SWITCH_NEEDED_HEADROOM;
2354+
22332355
/* Set MTU limits */
22342356
port_netdev->min_mtu = ETH_MIN_MTU;
22352357
port_netdev->max_mtu = ETHSW_MAX_FRAME_LENGTH;

drivers/staging/fsl-dpaa2/ethsw/ethsw.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,19 @@
6666
*/
6767
#define DPAA2_SWITCH_SWP_BUSY_RETRIES 1000
6868

69+
/* Hardware annotation buffer size */
70+
#define DPAA2_SWITCH_HWA_SIZE 64
71+
/* Software annotation buffer size */
72+
#define DPAA2_SWITCH_SWA_SIZE 64
73+
74+
#define DPAA2_SWITCH_TX_BUF_ALIGN 64
75+
76+
#define DPAA2_SWITCH_TX_DATA_OFFSET \
77+
(DPAA2_SWITCH_HWA_SIZE + DPAA2_SWITCH_SWA_SIZE)
78+
79+
#define DPAA2_SWITCH_NEEDED_HEADROOM \
80+
(DPAA2_SWITCH_TX_DATA_OFFSET + DPAA2_SWITCH_TX_BUF_ALIGN)
81+
6982
extern const struct ethtool_ops dpaa2_switch_port_ethtool_ops;
7083

7184
struct ethsw_core;
@@ -91,6 +104,7 @@ struct ethsw_port_priv {
91104
u8 vlans[VLAN_VID_MASK + 1];
92105
u16 pvid;
93106
struct net_device *bridge_dev;
107+
u16 tx_qdid;
94108
};
95109

96110
/* Switch data */

0 commit comments

Comments
 (0)