Commit 328de467 authored by Oleksij Rempel's avatar Oleksij Rempel Committed by David S. Miller

net: dsa: microchip: add multi queue support for KSZ88X3 variants

KSZ88X3 switches support up to 4 queues. Rework ksz8795_set_prio_queue()
to support KSZ8795 and KSZ88X3 families of switches.

Per default, configure KSZ88X3 to use one queue, since it need special
handling due to priority related errata. Errata handling is implemented
in a separate patch.
Signed-off-by: default avatarOleksij Rempel <o.rempel@pengutronix.de>
Acked-by: default avatarArun Ramadoss <arun.ramadoss@microchip.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 768cf841
...@@ -127,37 +127,56 @@ int ksz8_change_mtu(struct ksz_device *dev, int port, int mtu) ...@@ -127,37 +127,56 @@ int ksz8_change_mtu(struct ksz_device *dev, int port, int mtu)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static void ksz8795_set_prio_queue(struct ksz_device *dev, int port, int queue) static int ksz8_port_queue_split(struct ksz_device *dev, int port, int queues)
{ {
u8 hi, lo; u8 mask_4q, mask_2q;
u8 reg_4q, reg_2q;
u8 data_4q = 0;
u8 data_2q = 0;
int ret;
/* Number of queues can only be 1, 2, or 4. */ if (ksz_is_ksz88x3(dev)) {
switch (queue) { mask_4q = KSZ8873_PORT_4QUEUE_SPLIT_EN;
case 4: mask_2q = KSZ8873_PORT_2QUEUE_SPLIT_EN;
case 3: reg_4q = REG_PORT_CTRL_0;
queue = PORT_QUEUE_SPLIT_4; reg_2q = REG_PORT_CTRL_2;
break;
case 2: /* KSZ8795 family switches have Weighted Fair Queueing (WFQ)
queue = PORT_QUEUE_SPLIT_2; * enabled by default. Enable it for KSZ8873 family switches
break; * too. Default value for KSZ8873 family is strict priority,
default: * which should be enabled by using TC_SETUP_QDISC_ETS, not
queue = PORT_QUEUE_SPLIT_1; * by default.
*/
ret = ksz_rmw8(dev, REG_SW_CTRL_3, WEIGHTED_FAIR_QUEUE_ENABLE,
WEIGHTED_FAIR_QUEUE_ENABLE);
if (ret)
return ret;
} else {
mask_4q = KSZ8795_PORT_4QUEUE_SPLIT_EN;
mask_2q = KSZ8795_PORT_2QUEUE_SPLIT_EN;
reg_4q = REG_PORT_CTRL_13;
reg_2q = REG_PORT_CTRL_0;
/* TODO: this is legacy from initial KSZ8795 driver, should be
* moved to appropriate place in the future.
*/
ret = ksz_rmw8(dev, REG_SW_CTRL_19,
SW_OUT_RATE_LIMIT_QUEUE_BASED,
SW_OUT_RATE_LIMIT_QUEUE_BASED);
if (ret)
return ret;
} }
ksz_pread8(dev, port, REG_PORT_CTRL_0, &lo);
ksz_pread8(dev, port, P_DROP_TAG_CTRL, &hi); if (queues == 4)
lo &= ~PORT_QUEUE_SPLIT_L; data_4q = mask_4q;
if (queue & PORT_QUEUE_SPLIT_2) else if (queues == 2)
lo |= PORT_QUEUE_SPLIT_L; data_2q = mask_2q;
hi &= ~PORT_QUEUE_SPLIT_H;
if (queue & PORT_QUEUE_SPLIT_4) ret = ksz_prmw8(dev, port, reg_4q, mask_4q, data_4q);
hi |= PORT_QUEUE_SPLIT_H; if (ret)
ksz_pwrite8(dev, port, REG_PORT_CTRL_0, lo); return ret;
ksz_pwrite8(dev, port, P_DROP_TAG_CTRL, hi);
return ksz_prmw8(dev, port, reg_2q, mask_2q, data_2q);
/* Default is port based for egress rate limit. */
if (queue != PORT_QUEUE_SPLIT_1)
ksz_cfg(dev, REG_SW_CTRL_19, SW_OUT_RATE_LIMIT_QUEUE_BASED,
true);
} }
void ksz8_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt) void ksz8_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt)
...@@ -1513,6 +1532,7 @@ void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port) ...@@ -1513,6 +1532,7 @@ void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
{ {
struct dsa_switch *ds = dev->ds; struct dsa_switch *ds = dev->ds;
const u32 *masks; const u32 *masks;
int queues;
u8 member; u8 member;
masks = dev->info->masks; masks = dev->info->masks;
...@@ -1520,8 +1540,15 @@ void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port) ...@@ -1520,8 +1540,15 @@ void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
/* enable broadcast storm limit */ /* enable broadcast storm limit */
ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true); ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true);
if (!ksz_is_ksz88x3(dev)) /* For KSZ88x3 enable only one queue by default, otherwise we won't
ksz8795_set_prio_queue(dev, port, 4); * be able to get rid of PCP prios on Port 2.
*/
if (ksz_is_ksz88x3(dev))
queues = 1;
else
queues = dev->info->num_tx_queues;
ksz8_port_queue_split(dev, port, queues);
/* disable DiffServ priority */ /* disable DiffServ priority */
ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_DIFFSERV_ENABLE, false); ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_DIFFSERV_ENABLE, false);
......
...@@ -124,7 +124,8 @@ ...@@ -124,7 +124,8 @@
#define PORT_BASED_PRIO_3 3 #define PORT_BASED_PRIO_3 3
#define PORT_INSERT_TAG BIT(2) #define PORT_INSERT_TAG BIT(2)
#define PORT_REMOVE_TAG BIT(1) #define PORT_REMOVE_TAG BIT(1)
#define PORT_QUEUE_SPLIT_L BIT(0) #define KSZ8795_PORT_2QUEUE_SPLIT_EN BIT(0)
#define KSZ8873_PORT_4QUEUE_SPLIT_EN BIT(0)
#define REG_PORT_1_CTRL_1 0x11 #define REG_PORT_1_CTRL_1 0x11
#define REG_PORT_2_CTRL_1 0x21 #define REG_PORT_2_CTRL_1 0x21
...@@ -143,6 +144,7 @@ ...@@ -143,6 +144,7 @@
#define REG_PORT_4_CTRL_2 0x42 #define REG_PORT_4_CTRL_2 0x42
#define REG_PORT_5_CTRL_2 0x52 #define REG_PORT_5_CTRL_2 0x52
#define KSZ8873_PORT_2QUEUE_SPLIT_EN BIT(7)
#define PORT_INGRESS_FILTER BIT(6) #define PORT_INGRESS_FILTER BIT(6)
#define PORT_DISCARD_NON_VID BIT(5) #define PORT_DISCARD_NON_VID BIT(5)
#define PORT_FORCE_FLOW_CTRL BIT(4) #define PORT_FORCE_FLOW_CTRL BIT(4)
...@@ -463,10 +465,7 @@ ...@@ -463,10 +465,7 @@
#define REG_PORT_4_CTRL_13 0xE1 #define REG_PORT_4_CTRL_13 0xE1
#define REG_PORT_5_CTRL_13 0xF1 #define REG_PORT_5_CTRL_13 0xF1
#define PORT_QUEUE_SPLIT_H BIT(1) #define KSZ8795_PORT_4QUEUE_SPLIT_EN BIT(1)
#define PORT_QUEUE_SPLIT_1 0
#define PORT_QUEUE_SPLIT_2 1
#define PORT_QUEUE_SPLIT_4 2
#define PORT_DROP_TAG BIT(0) #define PORT_DROP_TAG BIT(0)
#define REG_PORT_1_CTRL_14 0xB2 #define REG_PORT_1_CTRL_14 0xB2
......
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