Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: mscc: ocelot: serialize access to the injection/extraction groups

As explained by Horatiu Vultur in commit 603ead96582d ("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: 0a6f17c6ae21 ("net: dsa: tag_ocelot_8021q: add support for PTP timestamping")
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Vladimir Oltean and committed by
David S. Miller
c5e12ac3 e1b9e802

+76
+11
drivers/net/dsa/ocelot/felix.c
··· 528 528 * so we need to be careful that there are no extra frames to be 529 529 * dequeued over MMIO, since we would never know to discard them. 530 530 */ 531 + ocelot_lock_xtr_grp_bh(ocelot, 0); 531 532 ocelot_drain_cpu_queue(ocelot, 0); 533 + ocelot_unlock_xtr_grp_bh(ocelot, 0); 532 534 533 535 return 0; 534 536 } ··· 1520 1518 int port = xmit_work->dp->index; 1521 1519 int retries = 10; 1522 1520 1521 + ocelot_lock_inj_grp(ocelot, 0); 1522 + 1523 1523 do { 1524 1524 if (ocelot_can_inject(ocelot, 0)) 1525 1525 break; ··· 1530 1526 } while (--retries); 1531 1527 1532 1528 if (!retries) { 1529 + ocelot_unlock_inj_grp(ocelot, 0); 1533 1530 dev_err(ocelot->dev, "port %d failed to inject skb\n", 1534 1531 port); 1535 1532 ocelot_port_purge_txtstamp_skb(ocelot, port, skb); ··· 1539 1534 } 1540 1535 1541 1536 ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb); 1537 + 1538 + ocelot_unlock_inj_grp(ocelot, 0); 1542 1539 1543 1540 consume_skb(skb); 1544 1541 kfree(xmit_work); ··· 1701 1694 if (!felix->info->quirk_no_xtr_irq) 1702 1695 return false; 1703 1696 1697 + ocelot_lock_xtr_grp(ocelot, grp); 1698 + 1704 1699 while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp)) { 1705 1700 struct sk_buff *skb; 1706 1701 unsigned int type; ··· 1738 1729 ERR_PTR(err)); 1739 1730 ocelot_drain_cpu_queue(ocelot, 0); 1740 1731 } 1732 + 1733 + ocelot_unlock_xtr_grp(ocelot, grp); 1741 1734 1742 1735 return true; 1743 1736 }
+52
drivers/net/ethernet/mscc/ocelot.c
··· 1099 1099 } 1100 1100 EXPORT_SYMBOL(ocelot_ptp_rx_timestamp); 1101 1101 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 + 1102 1144 int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp, struct sk_buff **nskb) 1103 1145 { 1104 1146 u64 timestamp, src_port, len; ··· 1150 1108 int sz, buf_len; 1151 1109 u32 val, *buf; 1152 1110 int err; 1111 + 1112 + lockdep_assert_held(&ocelot->xtr_lock); 1153 1113 1154 1114 err = ocelot_xtr_poll_xfh(ocelot, grp, xfh); 1155 1115 if (err) ··· 1228 1184 { 1229 1185 u32 val = ocelot_read(ocelot, QS_INJ_STATUS); 1230 1186 1187 + lockdep_assert_held(&ocelot->inj_lock); 1188 + 1231 1189 if (!(val & QS_INJ_STATUS_FIFO_RDY(BIT(grp)))) 1232 1190 return false; 1233 1191 if (val & QS_INJ_STATUS_WMARK_REACHED(BIT(grp))) ··· 1282 1236 u32 ifh[OCELOT_TAG_LEN / 4]; 1283 1237 unsigned int i, count, last; 1284 1238 1239 + lockdep_assert_held(&ocelot->inj_lock); 1240 + 1285 1241 ocelot_write_rix(ocelot, QS_INJ_CTRL_GAP_SIZE(1) | 1286 1242 QS_INJ_CTRL_SOF, QS_INJ_CTRL, grp); 1287 1243 ··· 1320 1272 1321 1273 void ocelot_drain_cpu_queue(struct ocelot *ocelot, int grp) 1322 1274 { 1275 + lockdep_assert_held(&ocelot->xtr_lock); 1276 + 1323 1277 while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp)) 1324 1278 ocelot_read_rix(ocelot, QS_XTR_RD, grp); 1325 1279 } ··· 3004 2954 mutex_init(&ocelot->fwd_domain_lock); 3005 2955 spin_lock_init(&ocelot->ptp_clock_lock); 3006 2956 spin_lock_init(&ocelot->ts_id_lock); 2957 + spin_lock_init(&ocelot->inj_lock); 2958 + spin_lock_init(&ocelot->xtr_lock); 3007 2959 3008 2960 ocelot->owq = alloc_ordered_workqueue("ocelot-owq", 0); 3009 2961 if (!ocelot->owq)
+4
drivers/net/ethernet/mscc/ocelot_vsc7514.c
··· 51 51 struct ocelot *ocelot = arg; 52 52 int grp = 0, err; 53 53 54 + ocelot_lock_xtr_grp(ocelot, grp); 55 + 54 56 while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp)) { 55 57 struct sk_buff *skb; 56 58 ··· 70 68 out: 71 69 if (err < 0) 72 70 ocelot_drain_cpu_queue(ocelot, 0); 71 + 72 + ocelot_unlock_xtr_grp(ocelot, grp); 73 73 74 74 return IRQ_HANDLED; 75 75 }
+9
include/soc/mscc/ocelot.h
··· 813 813 const u32 *const *map; 814 814 struct list_head stats_regions; 815 815 816 + spinlock_t inj_lock; 817 + spinlock_t xtr_lock; 818 + 816 819 u32 pool_size[OCELOT_SB_NUM][OCELOT_SB_POOL_NUM]; 817 820 int packet_buffer_size; 818 821 int num_frame_refs; ··· 969 966 u32 val, u32 reg, u32 offset); 970 967 971 968 /* Packet I/O */ 969 + void ocelot_lock_inj_grp(struct ocelot *ocelot, int grp); 970 + void ocelot_unlock_inj_grp(struct ocelot *ocelot, int grp); 971 + void ocelot_lock_xtr_grp(struct ocelot *ocelot, int grp); 972 + void ocelot_unlock_xtr_grp(struct ocelot *ocelot, int grp); 973 + void ocelot_lock_xtr_grp_bh(struct ocelot *ocelot, int grp); 974 + void ocelot_unlock_xtr_grp_bh(struct ocelot *ocelot, int grp); 972 975 bool ocelot_can_inject(struct ocelot *ocelot, int grp); 973 976 void ocelot_port_inject_frame(struct ocelot *ocelot, int port, int grp, 974 977 u32 rew_op, struct sk_buff *skb);