Skip to content

Commit c5e12ac

Browse files
vladimirolteandavem330
authored andcommitted
net: mscc: ocelot: serialize access to the injection/extraction groups
As explained by Horatiu Vultur in commit 603ead9 ("net: sparx5: Add spinlock for frame transmission from CPU") which is for a similar hardware design, multiple CPUs can simultaneously perform injection or extraction. There are only 2 register groups for injection and 2 for extraction, and the driver only uses one of each. So we'd better serialize access using spin locks, otherwise frame corruption is possible. Note that unlike in sparx5, FDMA in ocelot does not have this issue because struct ocelot_fdma_tx_ring already contains an xmit_lock. I guess this is mostly a problem for NXP LS1028A, as that is dual core. I don't think VSC7514 is. So I'm blaming the commit where LS1028A (aka the felix DSA driver) started using register-based packet injection and extraction. Fixes: 0a6f17c ("net: dsa: tag_ocelot_8021q: add support for PTP timestamping") Signed-off-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e1b9e80 commit c5e12ac

File tree

4 files changed

+76
-0
lines changed

4 files changed

+76
-0
lines changed

drivers/net/dsa/ocelot/felix.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,9 @@ static int felix_tag_8021q_setup(struct dsa_switch *ds)
528528
* so we need to be careful that there are no extra frames to be
529529
* dequeued over MMIO, since we would never know to discard them.
530530
*/
531+
ocelot_lock_xtr_grp_bh(ocelot, 0);
531532
ocelot_drain_cpu_queue(ocelot, 0);
533+
ocelot_unlock_xtr_grp_bh(ocelot, 0);
532534

533535
return 0;
534536
}
@@ -1518,6 +1520,8 @@ static void felix_port_deferred_xmit(struct kthread_work *work)
15181520
int port = xmit_work->dp->index;
15191521
int retries = 10;
15201522

1523+
ocelot_lock_inj_grp(ocelot, 0);
1524+
15211525
do {
15221526
if (ocelot_can_inject(ocelot, 0))
15231527
break;
@@ -1526,6 +1530,7 @@ static void felix_port_deferred_xmit(struct kthread_work *work)
15261530
} while (--retries);
15271531

15281532
if (!retries) {
1533+
ocelot_unlock_inj_grp(ocelot, 0);
15291534
dev_err(ocelot->dev, "port %d failed to inject skb\n",
15301535
port);
15311536
ocelot_port_purge_txtstamp_skb(ocelot, port, skb);
@@ -1535,6 +1540,8 @@ static void felix_port_deferred_xmit(struct kthread_work *work)
15351540

15361541
ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb);
15371542

1543+
ocelot_unlock_inj_grp(ocelot, 0);
1544+
15381545
consume_skb(skb);
15391546
kfree(xmit_work);
15401547
}
@@ -1694,6 +1701,8 @@ static bool felix_check_xtr_pkt(struct ocelot *ocelot)
16941701
if (!felix->info->quirk_no_xtr_irq)
16951702
return false;
16961703

1704+
ocelot_lock_xtr_grp(ocelot, grp);
1705+
16971706
while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp)) {
16981707
struct sk_buff *skb;
16991708
unsigned int type;
@@ -1730,6 +1739,8 @@ static bool felix_check_xtr_pkt(struct ocelot *ocelot)
17301739
ocelot_drain_cpu_queue(ocelot, 0);
17311740
}
17321741

1742+
ocelot_unlock_xtr_grp(ocelot, grp);
1743+
17331744
return true;
17341745
}
17351746

drivers/net/ethernet/mscc/ocelot.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,48 @@ void ocelot_ptp_rx_timestamp(struct ocelot *ocelot, struct sk_buff *skb,
10991099
}
11001100
EXPORT_SYMBOL(ocelot_ptp_rx_timestamp);
11011101

1102+
void ocelot_lock_inj_grp(struct ocelot *ocelot, int grp)
1103+
__acquires(&ocelot->inj_lock)
1104+
{
1105+
spin_lock(&ocelot->inj_lock);
1106+
}
1107+
EXPORT_SYMBOL_GPL(ocelot_lock_inj_grp);
1108+
1109+
void ocelot_unlock_inj_grp(struct ocelot *ocelot, int grp)
1110+
__releases(&ocelot->inj_lock)
1111+
{
1112+
spin_unlock(&ocelot->inj_lock);
1113+
}
1114+
EXPORT_SYMBOL_GPL(ocelot_unlock_inj_grp);
1115+
1116+
void ocelot_lock_xtr_grp(struct ocelot *ocelot, int grp)
1117+
__acquires(&ocelot->inj_lock)
1118+
{
1119+
spin_lock(&ocelot->inj_lock);
1120+
}
1121+
EXPORT_SYMBOL_GPL(ocelot_lock_xtr_grp);
1122+
1123+
void ocelot_unlock_xtr_grp(struct ocelot *ocelot, int grp)
1124+
__releases(&ocelot->inj_lock)
1125+
{
1126+
spin_unlock(&ocelot->inj_lock);
1127+
}
1128+
EXPORT_SYMBOL_GPL(ocelot_unlock_xtr_grp);
1129+
1130+
void ocelot_lock_xtr_grp_bh(struct ocelot *ocelot, int grp)
1131+
__acquires(&ocelot->xtr_lock)
1132+
{
1133+
spin_lock_bh(&ocelot->xtr_lock);
1134+
}
1135+
EXPORT_SYMBOL_GPL(ocelot_lock_xtr_grp_bh);
1136+
1137+
void ocelot_unlock_xtr_grp_bh(struct ocelot *ocelot, int grp)
1138+
__releases(&ocelot->xtr_lock)
1139+
{
1140+
spin_unlock_bh(&ocelot->xtr_lock);
1141+
}
1142+
EXPORT_SYMBOL_GPL(ocelot_unlock_xtr_grp_bh);
1143+
11021144
int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp, struct sk_buff **nskb)
11031145
{
11041146
u64 timestamp, src_port, len;
@@ -1109,6 +1151,8 @@ int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp, struct sk_buff **nskb)
11091151
u32 val, *buf;
11101152
int err;
11111153

1154+
lockdep_assert_held(&ocelot->xtr_lock);
1155+
11121156
err = ocelot_xtr_poll_xfh(ocelot, grp, xfh);
11131157
if (err)
11141158
return err;
@@ -1184,6 +1228,8 @@ bool ocelot_can_inject(struct ocelot *ocelot, int grp)
11841228
{
11851229
u32 val = ocelot_read(ocelot, QS_INJ_STATUS);
11861230

1231+
lockdep_assert_held(&ocelot->inj_lock);
1232+
11871233
if (!(val & QS_INJ_STATUS_FIFO_RDY(BIT(grp))))
11881234
return false;
11891235
if (val & QS_INJ_STATUS_WMARK_REACHED(BIT(grp)))
@@ -1236,6 +1282,8 @@ void ocelot_port_inject_frame(struct ocelot *ocelot, int port, int grp,
12361282
u32 ifh[OCELOT_TAG_LEN / 4];
12371283
unsigned int i, count, last;
12381284

1285+
lockdep_assert_held(&ocelot->inj_lock);
1286+
12391287
ocelot_write_rix(ocelot, QS_INJ_CTRL_GAP_SIZE(1) |
12401288
QS_INJ_CTRL_SOF, QS_INJ_CTRL, grp);
12411289

@@ -1272,6 +1320,8 @@ EXPORT_SYMBOL(ocelot_port_inject_frame);
12721320

12731321
void ocelot_drain_cpu_queue(struct ocelot *ocelot, int grp)
12741322
{
1323+
lockdep_assert_held(&ocelot->xtr_lock);
1324+
12751325
while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp))
12761326
ocelot_read_rix(ocelot, QS_XTR_RD, grp);
12771327
}
@@ -2954,6 +3004,8 @@ int ocelot_init(struct ocelot *ocelot)
29543004
mutex_init(&ocelot->fwd_domain_lock);
29553005
spin_lock_init(&ocelot->ptp_clock_lock);
29563006
spin_lock_init(&ocelot->ts_id_lock);
3007+
spin_lock_init(&ocelot->inj_lock);
3008+
spin_lock_init(&ocelot->xtr_lock);
29573009

29583010
ocelot->owq = alloc_ordered_workqueue("ocelot-owq", 0);
29593011
if (!ocelot->owq)

drivers/net/ethernet/mscc/ocelot_vsc7514.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
5151
struct ocelot *ocelot = arg;
5252
int grp = 0, err;
5353

54+
ocelot_lock_xtr_grp(ocelot, grp);
55+
5456
while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp)) {
5557
struct sk_buff *skb;
5658

@@ -69,6 +71,8 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
6971
if (err < 0)
7072
ocelot_drain_cpu_queue(ocelot, 0);
7173

74+
ocelot_unlock_xtr_grp(ocelot, grp);
75+
7276
return IRQ_HANDLED;
7377
}
7478

include/soc/mscc/ocelot.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,9 @@ struct ocelot {
813813
const u32 *const *map;
814814
struct list_head stats_regions;
815815

816+
spinlock_t inj_lock;
817+
spinlock_t xtr_lock;
818+
816819
u32 pool_size[OCELOT_SB_NUM][OCELOT_SB_POOL_NUM];
817820
int packet_buffer_size;
818821
int num_frame_refs;
@@ -966,6 +969,12 @@ void __ocelot_target_write_ix(struct ocelot *ocelot, enum ocelot_target target,
966969
u32 val, u32 reg, u32 offset);
967970

968971
/* Packet I/O */
972+
void ocelot_lock_inj_grp(struct ocelot *ocelot, int grp);
973+
void ocelot_unlock_inj_grp(struct ocelot *ocelot, int grp);
974+
void ocelot_lock_xtr_grp(struct ocelot *ocelot, int grp);
975+
void ocelot_unlock_xtr_grp(struct ocelot *ocelot, int grp);
976+
void ocelot_lock_xtr_grp_bh(struct ocelot *ocelot, int grp);
977+
void ocelot_unlock_xtr_grp_bh(struct ocelot *ocelot, int grp);
969978
bool ocelot_can_inject(struct ocelot *ocelot, int grp);
970979
void ocelot_port_inject_frame(struct ocelot *ocelot, int port, int grp,
971980
u32 rew_op, struct sk_buff *skb);

0 commit comments

Comments
 (0)