ksz_common.c 11.3 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
2 3 4
/*
 * Microchip switch driver main logic
 *
5
 * Copyright (C) 2017-2019 Microchip Technology Inc.
6 7 8 9
 */

#include <linux/delay.h>
#include <linux/export.h>
10
#include <linux/gpio/consumer.h>
11 12 13 14 15 16
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_data/microchip-ksz.h>
#include <linux/phy.h>
#include <linux/etherdevice.h>
#include <linux/if_bridge.h>
17
#include <linux/of_net.h>
18 19 20 21 22
#include <net/dsa.h>
#include <net/switchdev.h>

#include "ksz_priv.h"

23 24 25 26 27 28 29 30 31 32
void ksz_port_cleanup(struct ksz_device *dev, int port)
{
	/* Common code for port cleanup. */
	mutex_lock(&dev->dev_mutex);
	dev->on_ports &= ~(1 << port);
	dev->live_ports &= ~(1 << port);
	mutex_unlock(&dev->dev_mutex);
}
EXPORT_SYMBOL_GPL(ksz_port_cleanup);

33
void ksz_update_port_member(struct ksz_device *dev, int port)
34
{
35
	struct ksz_port *p;
36 37
	int i;

38 39 40 41 42 43 44 45 46 47 48
	for (i = 0; i < dev->port_cnt; i++) {
		if (i == port || i == dev->cpu_port)
			continue;
		p = &dev->ports[i];
		if (!(dev->member & (1 << i)))
			continue;

		/* Port is a member of the bridge and is forwarding. */
		if (p->stp_state == BR_STATE_FORWARDING &&
		    p->member != dev->member)
			dev->dev_ops->cfg_port_member(dev, i, dev->member);
49 50
	}
}
51
EXPORT_SYMBOL_GPL(ksz_update_port_member);
52

53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
static void port_r_cnt(struct ksz_device *dev, int port)
{
	struct ksz_port_mib *mib = &dev->ports[port].mib;
	u64 *dropped;

	/* Some ports may not have MIB counters before SWITCH_COUNTER_NUM. */
	while (mib->cnt_ptr < dev->reg_mib_cnt) {
		dev->dev_ops->r_mib_cnt(dev, port, mib->cnt_ptr,
					&mib->counters[mib->cnt_ptr]);
		++mib->cnt_ptr;
	}

	/* last one in storage */
	dropped = &mib->counters[dev->mib_cnt];

	/* Some ports may not have MIB counters after SWITCH_COUNTER_NUM. */
	while (mib->cnt_ptr < dev->mib_cnt) {
		dev->dev_ops->r_mib_pkt(dev, port, mib->cnt_ptr,
					dropped, &mib->counters[mib->cnt_ptr]);
		++mib->cnt_ptr;
	}
	mib->cnt_ptr = 0;
}

static void ksz_mib_read_work(struct work_struct *work)
{
	struct ksz_device *dev = container_of(work, struct ksz_device,
					      mib_read);
	struct ksz_port_mib *mib;
	struct ksz_port *p;
	int i;

	for (i = 0; i < dev->mib_port_cnt; i++) {
		p = &dev->ports[i];
		mib = &p->mib;
		mutex_lock(&mib->cnt_mutex);

		/* Only read MIB counters when the port is told to do.
		 * If not, read only dropped counters when link is not up.
		 */
		if (!p->read) {
			const struct dsa_port *dp = dsa_to_port(dev->ds, i);

			if (!netif_carrier_ok(dp->slave))
				mib->cnt_ptr = dev->reg_mib_cnt;
		}
		port_r_cnt(dev, i);
		p->read = false;
		mutex_unlock(&mib->cnt_mutex);
	}
}

static void mib_monitor(struct timer_list *t)
{
	struct ksz_device *dev = from_timer(dev, t, mib_read_timer);

	mod_timer(&dev->mib_read_timer, jiffies + dev->mib_read_interval);
	schedule_work(&dev->mib_read);
}

void ksz_init_mib_timer(struct ksz_device *dev)
{
	int i;

	/* Read MIB counters every 30 seconds to avoid overflow. */
	dev->mib_read_interval = msecs_to_jiffies(30000);

	INIT_WORK(&dev->mib_read, ksz_mib_read_work);
	timer_setup(&dev->mib_read_timer, mib_monitor, 0);

	for (i = 0; i < dev->mib_port_cnt; i++)
		dev->dev_ops->port_init_cnt(dev, i);

	/* Start the timer 2 seconds later. */
	dev->mib_read_timer.expires = jiffies + msecs_to_jiffies(2000);
	add_timer(&dev->mib_read_timer);
}
EXPORT_SYMBOL_GPL(ksz_init_mib_timer);

132
int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg)
133 134
{
	struct ksz_device *dev = ds->priv;
135
	u16 val = 0xffff;
136

137
	dev->dev_ops->r_phy(dev, addr, reg, &val);
138 139 140

	return val;
}
141
EXPORT_SYMBOL_GPL(ksz_phy_read16);
142

143
int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val)
144 145 146
{
	struct ksz_device *dev = ds->priv;

147
	dev->dev_ops->w_phy(dev, addr, reg, val);
148 149 150

	return 0;
}
151
EXPORT_SYMBOL_GPL(ksz_phy_write16);
152

153 154 155 156 157 158 159 160 161 162 163
void ksz_adjust_link(struct dsa_switch *ds, int port,
		     struct phy_device *phydev)
{
	struct ksz_device *dev = ds->priv;
	struct ksz_port *p = &dev->ports[port];

	/* Read all MIB counters when the link is going down. */
	if (!phydev->link) {
		p->read = true;
		schedule_work(&dev->mib_read);
	}
164 165 166 167 168 169 170
	mutex_lock(&dev->dev_mutex);
	if (!phydev->link)
		dev->live_ports &= ~(1 << port);
	else
		/* Remember which port is connected and active. */
		dev->live_ports |= (1 << port) & dev->on_ports;
	mutex_unlock(&dev->dev_mutex);
171 172 173
}
EXPORT_SYMBOL_GPL(ksz_adjust_link);

174
int ksz_sset_count(struct dsa_switch *ds, int port, int sset)
175 176 177
{
	struct ksz_device *dev = ds->priv;

178 179 180
	if (sset != ETH_SS_STATS)
		return 0;

181
	return dev->mib_cnt;
182
}
183
EXPORT_SYMBOL_GPL(ksz_sset_count);
184

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf)
{
	const struct dsa_port *dp = dsa_to_port(ds, port);
	struct ksz_device *dev = ds->priv;
	struct ksz_port_mib *mib;

	mib = &dev->ports[port].mib;
	mutex_lock(&mib->cnt_mutex);

	/* Only read dropped counters if no link. */
	if (!netif_carrier_ok(dp->slave))
		mib->cnt_ptr = dev->reg_mib_cnt;
	port_r_cnt(dev, port);
	memcpy(buf, mib->counters, dev->mib_cnt * sizeof(u64));
	mutex_unlock(&mib->cnt_mutex);
}
EXPORT_SYMBOL_GPL(ksz_get_ethtool_stats);

203 204
int ksz_port_bridge_join(struct dsa_switch *ds, int port,
			 struct net_device *br)
205 206 207
{
	struct ksz_device *dev = ds->priv;

208
	mutex_lock(&dev->dev_mutex);
209
	dev->br_member |= (1 << port);
210
	mutex_unlock(&dev->dev_mutex);
211

212 213 214
	/* port_stp_state_set() will be called after to put the port in
	 * appropriate state so there is no need to do anything.
	 */
215

216
	return 0;
217
}
218
EXPORT_SYMBOL_GPL(ksz_port_bridge_join);
219

220 221
void ksz_port_bridge_leave(struct dsa_switch *ds, int port,
			   struct net_device *br)
222 223 224
{
	struct ksz_device *dev = ds->priv;

225
	mutex_lock(&dev->dev_mutex);
226 227
	dev->br_member &= ~(1 << port);
	dev->member &= ~(1 << port);
228
	mutex_unlock(&dev->dev_mutex);
229

230 231 232
	/* port_stp_state_set() will be called after to put the port in
	 * forwarding state so there is no need to do anything.
	 */
233
}
234
EXPORT_SYMBOL_GPL(ksz_port_bridge_leave);
235

236
void ksz_port_fast_age(struct dsa_switch *ds, int port)
237 238 239
{
	struct ksz_device *dev = ds->priv;

240
	dev->dev_ops->flush_dyn_mac_table(dev, port);
241
}
242
EXPORT_SYMBOL_GPL(ksz_port_fast_age);
243

244 245
int ksz_port_vlan_prepare(struct dsa_switch *ds, int port,
			  const struct switchdev_obj_port_vlan *vlan)
246 247 248 249 250
{
	/* nothing needed */

	return 0;
}
251
EXPORT_SYMBOL_GPL(ksz_port_vlan_prepare);
252

253 254
int ksz_port_fdb_dump(struct dsa_switch *ds, int port, dsa_fdb_dump_cb_t *cb,
		      void *data)
255 256
{
	struct ksz_device *dev = ds->priv;
257
	int ret = 0;
258 259 260 261 262
	u16 i = 0;
	u16 entries = 0;
	u8 timestamp = 0;
	u8 fid;
	u8 member;
263 264 265
	struct alu_struct alu;

	do {
266 267 268 269 270
		alu.is_static = false;
		ret = dev->dev_ops->r_dyn_mac_table(dev, i, alu.mac, &fid,
						    &member, &timestamp,
						    &entries);
		if (!ret && (member & BIT(port))) {
271
			ret = cb(alu.mac, alu.fid, alu.is_static, data);
272
			if (ret)
273
				break;
274
		}
275 276 277 278
		i++;
	} while (i < entries);
	if (i >= entries)
		ret = 0;
279 280 281

	return ret;
}
282
EXPORT_SYMBOL_GPL(ksz_port_fdb_dump);
283

284 285
int ksz_port_mdb_prepare(struct dsa_switch *ds, int port,
			 const struct switchdev_obj_port_mdb *mdb)
286 287 288 289
{
	/* nothing to do */
	return 0;
}
290
EXPORT_SYMBOL_GPL(ksz_port_mdb_prepare);
291

292 293
void ksz_port_mdb_add(struct dsa_switch *ds, int port,
		      const struct switchdev_obj_port_mdb *mdb)
294 295
{
	struct ksz_device *dev = ds->priv;
296
	struct alu_struct alu;
297
	int index;
298
	int empty = 0;
299

300
	alu.port_forward = 0;
301
	for (index = 0; index < dev->num_statics; index++) {
302 303 304 305
		if (!dev->dev_ops->r_sta_mac_table(dev, index, &alu)) {
			/* Found one already in static MAC table. */
			if (!memcmp(alu.mac, mdb->addr, ETH_ALEN) &&
			    alu.fid == mdb->vid)
306
				break;
307 308 309
		/* Remember the first empty entry. */
		} else if (!empty) {
			empty = index + 1;
310 311 312 313
		}
	}

	/* no available entry */
314 315
	if (index == dev->num_statics && !empty)
		return;
316 317

	/* add entry */
318 319 320 321 322 323 324 325 326
	if (index == dev->num_statics) {
		index = empty - 1;
		memset(&alu, 0, sizeof(alu));
		memcpy(alu.mac, mdb->addr, ETH_ALEN);
		alu.is_static = true;
	}
	alu.port_forward |= BIT(port);
	if (mdb->vid) {
		alu.is_use_fid = true;
327

328 329 330 331
		/* Need a way to map VID to FID. */
		alu.fid = mdb->vid;
	}
	dev->dev_ops->w_sta_mac_table(dev, index, &alu);
332
}
333
EXPORT_SYMBOL_GPL(ksz_port_mdb_add);
334

335 336
int ksz_port_mdb_del(struct dsa_switch *ds, int port,
		     const struct switchdev_obj_port_mdb *mdb)
337 338
{
	struct ksz_device *dev = ds->priv;
339
	struct alu_struct alu;
340 341 342 343
	int index;
	int ret = 0;

	for (index = 0; index < dev->num_statics; index++) {
344 345 346 347
		if (!dev->dev_ops->r_sta_mac_table(dev, index, &alu)) {
			/* Found one already in static MAC table. */
			if (!memcmp(alu.mac, mdb->addr, ETH_ALEN) &&
			    alu.fid == mdb->vid)
348 349 350 351 352
				break;
		}
	}

	/* no available entry */
353
	if (index == dev->num_statics)
354 355 356
		goto exit;

	/* clear port */
357 358 359 360
	alu.port_forward &= ~BIT(port);
	if (!alu.port_forward)
		alu.is_static = false;
	dev->dev_ops->w_sta_mac_table(dev, index, &alu);
361 362 363 364

exit:
	return ret;
}
365
EXPORT_SYMBOL_GPL(ksz_port_mdb_del);
366

367
int ksz_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy)
368 369 370
{
	struct ksz_device *dev = ds->priv;

371 372
	/* setup slave port */
	dev->dev_ops->port_setup(dev, port, false);
373
	dev->dev_ops->phy_setup(dev, port, phy);
374

375 376 377
	/* port_stp_state_set() will be called after to enable the port so
	 * there is no need to do anything.
	 */
378 379 380

	return 0;
}
381
EXPORT_SYMBOL_GPL(ksz_enable_port);
382

383
void ksz_disable_port(struct dsa_switch *ds, int port)
384 385 386
{
	struct ksz_device *dev = ds->priv;

387 388
	dev->on_ports &= ~(1 << port);
	dev->live_ports &= ~(1 << port);
389

390 391 392
	/* port_stp_state_set() will be called after to disable the port so
	 * there is no need to do anything.
	 */
393
}
394
EXPORT_SYMBOL_GPL(ksz_disable_port);
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421

struct ksz_device *ksz_switch_alloc(struct device *base,
				    const struct ksz_io_ops *ops,
				    void *priv)
{
	struct dsa_switch *ds;
	struct ksz_device *swdev;

	ds = dsa_switch_alloc(base, DSA_MAX_PORTS);
	if (!ds)
		return NULL;

	swdev = devm_kzalloc(base, sizeof(*swdev), GFP_KERNEL);
	if (!swdev)
		return NULL;

	ds->priv = swdev;
	swdev->dev = base;

	swdev->ds = ds;
	swdev->priv = priv;
	swdev->ops = ops;

	return swdev;
}
EXPORT_SYMBOL(ksz_switch_alloc);

422 423
int ksz_switch_register(struct ksz_device *dev,
			const struct ksz_dev_ops *ops)
424 425 426 427 428 429
{
	int ret;

	if (dev->pdata)
		dev->chip_id = dev->pdata->chip_id;

430 431 432 433 434 435 436 437 438 439 440
	dev->reset_gpio = devm_gpiod_get_optional(dev->dev, "reset",
						  GPIOD_OUT_LOW);
	if (IS_ERR(dev->reset_gpio))
		return PTR_ERR(dev->reset_gpio);

	if (dev->reset_gpio) {
		gpiod_set_value(dev->reset_gpio, 1);
		mdelay(10);
		gpiod_set_value(dev->reset_gpio, 0);
	}

441
	mutex_init(&dev->dev_mutex);
442 443 444 445 446
	mutex_init(&dev->reg_mutex);
	mutex_init(&dev->stats_mutex);
	mutex_init(&dev->alu_mutex);
	mutex_init(&dev->vlan_mutex);

447 448 449
	dev->dev_ops = ops;

	if (dev->dev_ops->detect(dev))
450 451
		return -EINVAL;

452
	ret = dev->dev_ops->init(dev);
453 454 455
	if (ret)
		return ret;

456 457 458
	/* Host port interface will be self detected, or specifically set in
	 * device tree.
	 */
459 460 461 462 463 464 465 466 467 468 469 470 471
	if (dev->dev->of_node) {
		ret = of_get_phy_mode(dev->dev->of_node);
		if (ret >= 0)
			dev->interface = ret;
	}

	ret = dsa_register_switch(dev->ds);
	if (ret) {
		dev->dev_ops->exit(dev);
		return ret;
	}

	return 0;
472 473 474 475 476
}
EXPORT_SYMBOL(ksz_switch_register);

void ksz_switch_remove(struct ksz_device *dev)
{
477 478 479 480 481 482
	/* timer started */
	if (dev->mib_read_timer.expires) {
		del_timer_sync(&dev->mib_read_timer);
		flush_work(&dev->mib_read);
	}

483
	dev->dev_ops->exit(dev);
484
	dsa_unregister_switch(dev->ds);
485 486 487 488

	if (dev->reset_gpio)
		gpiod_set_value(dev->reset_gpio, 1);

489 490 491 492 493 494
}
EXPORT_SYMBOL(ksz_switch_remove);

MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>");
MODULE_DESCRIPTION("Microchip KSZ Series Switch DSA Driver");
MODULE_LICENSE("GPL");