asix_common.c 14.8 KB
Newer Older
1 2
/*
 * ASIX AX8817X based USB 2.0 Ethernet Devices
3
 * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com>
4
 * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
5
 * Copyright (C) 2006 James Painter <jamie.painter@iname.com>
6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright (c) 2002-2003 TiVo Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 21
 */

C
Christian Riesch 已提交
22 23 24 25
#include "asix.h"

int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
		  u16 size, void *data)
26
{
27 28 29 30 31 32 33 34
	int ret;
	ret = usbnet_read_cmd(dev, cmd,
			       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			       value, index, data, size);

	if (ret != size && ret >= 0)
		return -EINVAL;
	return ret;
35 36
}

C
Christian Riesch 已提交
37 38
int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
		   u16 size, void *data)
39
{
40 41 42
	return usbnet_write_cmd(dev, cmd,
				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
				value, index, data, size);
43 44
}

C
Christian Riesch 已提交
45 46
void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
			  u16 size, void *data)
47
{
48 49 50
	usbnet_write_cmd_async(dev, cmd,
			       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			       value, index, data, size);
51 52
}

53 54
int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
			   struct asix_rx_fixup_info *rx)
55
{
56
	int offset = 0;
57

58 59 60
	while (offset + sizeof(u16) <= skb->len) {
		u16 remaining = 0;
		unsigned char *data;
61

62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
		if (!rx->size) {
			if ((skb->len - offset == sizeof(u16)) ||
			    rx->split_head) {
				if(!rx->split_head) {
					rx->header = get_unaligned_le16(
							skb->data + offset);
					rx->split_head = true;
					offset += sizeof(u16);
					break;
				} else {
					rx->header |= (get_unaligned_le16(
							skb->data + offset)
							<< 16);
					rx->split_head = false;
					offset += sizeof(u16);
				}
			} else {
				rx->header = get_unaligned_le32(skb->data +
								offset);
				offset += sizeof(u32);
			}
83

84 85 86 87 88 89 90 91 92 93 94 95
			/* get the packet length */
			rx->size = (u16) (rx->header & 0x7ff);
			if (rx->size != ((~rx->header >> 16) & 0x7ff)) {
				netdev_err(dev->net, "asix_rx_fixup() Bad Header Length 0x%x, offset %d\n",
					   rx->header, offset);
				rx->size = 0;
				return 0;
			}
			rx->ax_skb = netdev_alloc_skb_ip_align(dev->net,
							       rx->size);
			if (!rx->ax_skb)
				return 0;
96 97
		}

98
		if (rx->size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) {
99
			netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
100 101
				   rx->size);
			kfree_skb(rx->ax_skb);
102 103 104
			rx->ax_skb = NULL;
			rx->size = 0U;

105 106 107
			return 0;
		}

108 109 110 111
		if (rx->size > skb->len - offset) {
			remaining = rx->size - (skb->len - offset);
			rx->size = skb->len - offset;
		}
112

113 114 115 116 117 118 119
		data = skb_put(rx->ax_skb, rx->size);
		memcpy(data, skb->data + offset, rx->size);
		if (!remaining)
			usbnet_skb_return(dev, rx->ax_skb);

		offset += (rx->size + 1) & 0xfffe;
		rx->size = remaining;
120 121
	}

122
	if (skb->len != offset) {
123 124
		netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d, %d\n",
			   skb->len, offset);
125 126
		return 0;
	}
127

128 129 130
	return 1;
}

131 132 133 134 135 136 137 138
int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb)
{
	struct asix_common_private *dp = dev->driver_priv;
	struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;

	return asix_rx_fixup_internal(dev, skb, rx);
}

C
Christian Riesch 已提交
139 140
struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
			      gfp_t flags)
141 142 143 144 145 146 147
{
	int padlen;
	int headroom = skb_headroom(skb);
	int tailroom = skb_tailroom(skb);
	u32 packet_len;
	u32 padbytes = 0xffff0000;

148
	padlen = ((skb->len + 4) & (dev->maxpacket - 1)) ? 0 : 4;
149

E
Eric Dumazet 已提交
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
	/* We need to push 4 bytes in front of frame (packet_len)
	 * and maybe add 4 bytes after the end (if padlen is 4)
	 *
	 * Avoid skb_copy_expand() expensive call, using following rules :
	 * - We are allowed to push 4 bytes in headroom if skb_header_cloned()
	 *   is false (and if we have 4 bytes of headroom)
	 * - We are allowed to put 4 bytes at tail if skb_cloned()
	 *   is false (and if we have 4 bytes of tailroom)
	 *
	 * TCP packets for example are cloned, but skb_header_release()
	 * was called in tcp stack, allowing us to use headroom for our needs.
	 */
	if (!skb_header_cloned(skb) &&
	    !(padlen && skb_cloned(skb)) &&
	    headroom + tailroom >= 4 + padlen) {
		/* following should not happen, but better be safe */
		if (headroom < 4 ||
		    tailroom < padlen) {
168
			skb->data = memmove(skb->head + 4, skb->data, skb->len);
169
			skb_set_tail_pointer(skb, skb->len);
170 171 172
		}
	} else {
		struct sk_buff *skb2;
E
Eric Dumazet 已提交
173

174 175 176 177 178 179 180
		skb2 = skb_copy_expand(skb, 4, padlen, flags);
		dev_kfree_skb_any(skb);
		skb = skb2;
		if (!skb)
			return NULL;
	}

E
Eric Dumazet 已提交
181
	packet_len = ((skb->len ^ 0x0000ffff) << 16) + skb->len;
182
	skb_push(skb, 4);
183
	cpu_to_le32s(&packet_len);
184
	skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len));
185

186
	if (padlen) {
187
		cpu_to_le32s(&padbytes);
188
		memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
189 190
		skb_put(skb, sizeof(padbytes));
	}
191 192

	usbnet_set_skb_tx_stats(skb, 1);
193 194 195
	return skb;
}

C
Christian Riesch 已提交
196
int asix_set_sw_mii(struct usbnet *dev)
197 198 199 200
{
	int ret;
	ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
	if (ret < 0)
201
		netdev_err(dev->net, "Failed to enable software MII access\n");
202 203 204
	return ret;
}

C
Christian Riesch 已提交
205
int asix_set_hw_mii(struct usbnet *dev)
206 207 208 209
{
	int ret;
	ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
	if (ret < 0)
210
		netdev_err(dev->net, "Failed to enable hardware MII access\n");
211 212 213
	return ret;
}

214
int asix_read_phy_addr(struct usbnet *dev, int internal)
215
{
216
	int offset = (internal ? 1 : 0);
A
Al Viro 已提交
217 218
	u8 buf[2];
	int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf);
219

220
	netdev_dbg(dev->net, "asix_get_phy_addr()\n");
221

A
Al Viro 已提交
222
	if (ret < 0) {
223
		netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret);
A
Al Viro 已提交
224
		goto out;
225
	}
226 227
	netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n",
		   *((__le16 *)buf));
228
	ret = buf[offset];
A
Al Viro 已提交
229 230

out:
231 232 233
	return ret;
}

234 235 236 237 238 239 240
int asix_get_phy_addr(struct usbnet *dev)
{
	/* return the address of the internal phy */
	return asix_read_phy_addr(dev, 1);
}


C
Christian Riesch 已提交
241
int asix_sw_reset(struct usbnet *dev, u8 flags)
242 243 244 245 246
{
	int ret;

        ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL);
	if (ret < 0)
247
		netdev_err(dev->net, "Failed to send software reset: %02x\n", ret);
248 249 250

	return ret;
}
251

C
Christian Riesch 已提交
252
u16 asix_read_rx_ctl(struct usbnet *dev)
253
{
A
Al Viro 已提交
254 255
	__le16 v;
	int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v);
256

A
Al Viro 已提交
257
	if (ret < 0) {
258
		netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret);
A
Al Viro 已提交
259
		goto out;
260
	}
A
Al Viro 已提交
261 262
	ret = le16_to_cpu(v);
out:
263 264 265
	return ret;
}

C
Christian Riesch 已提交
266
int asix_write_rx_ctl(struct usbnet *dev, u16 mode)
267 268 269
{
	int ret;

270
	netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode);
271 272
	ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
	if (ret < 0)
273 274
		netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n",
			   mode, ret);
275 276 277 278

	return ret;
}

C
Christian Riesch 已提交
279
u16 asix_read_medium_status(struct usbnet *dev)
280
{
A
Al Viro 已提交
281 282
	__le16 v;
	int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v);
283

A
Al Viro 已提交
284
	if (ret < 0) {
285 286
		netdev_err(dev->net, "Error reading Medium Status register: %02x\n",
			   ret);
287
		return ret;	/* TODO: callers not checking for error ret */
288
	}
289 290 291

	return le16_to_cpu(v);

292 293
}

C
Christian Riesch 已提交
294
int asix_write_medium_mode(struct usbnet *dev, u16 mode)
295
{
296
	int ret;
297

298
	netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode);
299 300
	ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
	if (ret < 0)
301 302
		netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n",
			   mode, ret);
303

304 305
	return ret;
}
306

C
Christian Riesch 已提交
307
int asix_write_gpio(struct usbnet *dev, u16 value, int sleep)
308 309
{
	int ret;
310

311
	netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value);
312 313
	ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL);
	if (ret < 0)
314 315
		netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n",
			   value, ret);
316

317 318 319 320
	if (sleep)
		msleep(sleep);

	return ret;
321 322
}

323 324 325
/*
 * AX88772 & AX88178 have a 16-bit RX_CTL value
 */
C
Christian Riesch 已提交
326
void asix_set_multicast(struct net_device *net)
327 328
{
	struct usbnet *dev = netdev_priv(net);
329
	struct asix_data *data = (struct asix_data *)&dev->data;
330
	u16 rx_ctl = AX_DEFAULT_RX_CTL;
331 332

	if (net->flags & IFF_PROMISC) {
333
		rx_ctl |= AX_RX_CTL_PRO;
334
	} else if (net->flags & IFF_ALLMULTI ||
335
		   netdev_mc_count(net) > AX_MAX_MCAST) {
336
		rx_ctl |= AX_RX_CTL_AMALL;
337
	} else if (netdev_mc_empty(net)) {
338 339 340 341 342 343
		/* just broadcast and directed */
	} else {
		/* We use the 20 byte dev->data
		 * for our 8 byte filter buffer
		 * to avoid allocating memory that
		 * is tricky to free later */
344
		struct netdev_hw_addr *ha;
345 346 347 348 349
		u32 crc_bits;

		memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);

		/* Build the multicast hash filter. */
350 351
		netdev_for_each_mc_addr(ha, net) {
			crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
352 353 354 355
			data->multi_filter[crc_bits >> 3] |=
			    1 << (crc_bits & 7);
		}

356
		asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
357 358
				   AX_MCAST_FILTER_SIZE, data->multi_filter);

359
		rx_ctl |= AX_RX_CTL_AM;
360 361
	}

362
	asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
363 364
}

C
Christian Riesch 已提交
365
int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
366 367
{
	struct usbnet *dev = netdev_priv(netdev);
A
Al Viro 已提交
368
	__le16 res;
369

370
	mutex_lock(&dev->phy_mutex);
371 372
	asix_set_sw_mii(dev);
	asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
A
Al Viro 已提交
373
				(__u16)loc, 2, &res);
374
	asix_set_hw_mii(dev);
375
	mutex_unlock(&dev->phy_mutex);
376

377 378
	netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
		   phy_id, loc, le16_to_cpu(res));
379

A
Al Viro 已提交
380
	return le16_to_cpu(res);
381 382
}

C
Christian Riesch 已提交
383
void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
384 385
{
	struct usbnet *dev = netdev_priv(netdev);
A
Al Viro 已提交
386
	__le16 res = cpu_to_le16(val);
387

388 389
	netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
		   phy_id, loc, val);
390
	mutex_lock(&dev->phy_mutex);
391
	asix_set_sw_mii(dev);
A
Al Viro 已提交
392
	asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res);
393
	asix_set_hw_mii(dev);
394
	mutex_unlock(&dev->phy_mutex);
395 396
}

C
Christian Riesch 已提交
397
void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
398 399 400 401
{
	struct usbnet *dev = netdev_priv(net);
	u8 opt;

402
	if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) {
403 404 405 406 407 408
		wolinfo->supported = 0;
		wolinfo->wolopts = 0;
		return;
	}
	wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
	wolinfo->wolopts = 0;
409 410 411 412
	if (opt & AX_MONITOR_LINK)
		wolinfo->wolopts |= WAKE_PHY;
	if (opt & AX_MONITOR_MAGIC)
		wolinfo->wolopts |= WAKE_MAGIC;
413 414
}

C
Christian Riesch 已提交
415
int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
416 417 418 419 420 421 422 423 424
{
	struct usbnet *dev = netdev_priv(net);
	u8 opt = 0;

	if (wolinfo->wolopts & WAKE_PHY)
		opt |= AX_MONITOR_LINK;
	if (wolinfo->wolopts & WAKE_MAGIC)
		opt |= AX_MONITOR_MAGIC;

425
	if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE,
A
Al Viro 已提交
426
			      opt, 0, 0, NULL) < 0)
427 428 429 430 431
		return -EINVAL;

	return 0;
}

C
Christian Riesch 已提交
432
int asix_get_eeprom_len(struct net_device *net)
433
{
434
	return AX_EEPROM_LEN;
435 436
}

C
Christian Riesch 已提交
437 438
int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
		    u8 *data)
439 440
{
	struct usbnet *dev = netdev_priv(net);
441 442
	u16 *eeprom_buff;
	int first_word, last_word;
443 444
	int i;

445
	if (eeprom->len == 0)
446 447 448 449
		return -EINVAL;

	eeprom->magic = AX_EEPROM_MAGIC;

450 451 452 453 454 455 456 457
	first_word = eeprom->offset >> 1;
	last_word = (eeprom->offset + eeprom->len - 1) >> 1;

	eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1),
			      GFP_KERNEL);
	if (!eeprom_buff)
		return -ENOMEM;

458
	/* ax8817x returns 2 bytes from eeprom on read */
459 460 461 462 463 464
	for (i = first_word; i <= last_word; i++) {
		if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, i, 0, 2,
				  &(eeprom_buff[i - first_word])) < 0) {
			kfree(eeprom_buff);
			return -EIO;
		}
465
	}
466 467 468

	memcpy(data, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
	kfree(eeprom_buff);
469 470 471
	return 0;
}

472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
		    u8 *data)
{
	struct usbnet *dev = netdev_priv(net);
	u16 *eeprom_buff;
	int first_word, last_word;
	int i;
	int ret;

	netdev_dbg(net, "write EEPROM len %d, offset %d, magic 0x%x\n",
		   eeprom->len, eeprom->offset, eeprom->magic);

	if (eeprom->len == 0)
		return -EINVAL;

	if (eeprom->magic != AX_EEPROM_MAGIC)
		return -EINVAL;

	first_word = eeprom->offset >> 1;
	last_word = (eeprom->offset + eeprom->len - 1) >> 1;

	eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1),
			      GFP_KERNEL);
	if (!eeprom_buff)
		return -ENOMEM;

	/* align data to 16 bit boundaries, read the missing data from
	   the EEPROM */
	if (eeprom->offset & 1) {
		ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, first_word, 0, 2,
				    &(eeprom_buff[0]));
		if (ret < 0) {
			netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", first_word);
			goto free;
		}
	}

	if ((eeprom->offset + eeprom->len) & 1) {
		ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, last_word, 0, 2,
				    &(eeprom_buff[last_word - first_word]));
		if (ret < 0) {
			netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", last_word);
			goto free;
		}
	}

	memcpy((u8 *)eeprom_buff + (eeprom->offset & 1), data, eeprom->len);

	/* write data to EEPROM */
	ret = asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0x0000, 0, 0, NULL);
	if (ret < 0) {
		netdev_err(net, "Failed to enable EEPROM write\n");
		goto free;
	}
	msleep(20);

	for (i = first_word; i <= last_word; i++) {
		netdev_dbg(net, "write to EEPROM at offset 0x%02x, data 0x%04x\n",
			   i, eeprom_buff[i - first_word]);
		ret = asix_write_cmd(dev, AX_CMD_WRITE_EEPROM, i,
				     eeprom_buff[i - first_word], 0, NULL);
		if (ret < 0) {
			netdev_err(net, "Failed to write EEPROM at offset 0x%02x.\n",
				   i);
			goto free;
		}
		msleep(20);
	}

	ret = asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0x0000, 0, 0, NULL);
	if (ret < 0) {
		netdev_err(net, "Failed to disable EEPROM write\n");
		goto free;
	}

	ret = 0;
free:
	kfree(eeprom_buff);
	return ret;
}

C
Christian Riesch 已提交
553
void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
554 555 556
{
	/* Inherit standard device info */
	usbnet_get_drvinfo(net, info);
557 558
	strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
	strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
559
	info->eedump_len = AX_EEPROM_LEN;
560 561
}

C
Christian Riesch 已提交
562
int asix_set_mac_address(struct net_device *net, void *p)
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
{
	struct usbnet *dev = netdev_priv(net);
	struct asix_data *data = (struct asix_data *)&dev->data;
	struct sockaddr *addr = p;

	if (netif_running(net))
		return -EBUSY;
	if (!is_valid_ether_addr(addr->sa_data))
		return -EADDRNOTAVAIL;

	memcpy(net->dev_addr, addr->sa_data, ETH_ALEN);

	/* We use the 20 byte dev->data
	 * for our 6 byte mac buffer
	 * to avoid allocating memory that
	 * is tricky to free later */
	memcpy(data->mac_addr, addr->sa_data, ETH_ALEN);
	asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
							data->mac_addr);

	return 0;
}