asix_common.c 13.7 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 19 20 21 22
 * 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
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

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

int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
		  u16 size, void *data)
27
{
28 29 30 31 32 33 34 35
	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;
36 37
}

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

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

C
Christian Riesch 已提交
54
int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
55
{
56
	int offset = 0;
57

58 59 60 61
	while (offset + sizeof(u32) < skb->len) {
		struct sk_buff *ax_skb;
		u16 size;
		u32 header = get_unaligned_le32(skb->data + offset);
62

63
		offset += sizeof(u32);
64

65
		/* get the packet length */
66 67 68 69
		size = (u16) (header & 0x7ff);
		if (size != ((~header >> 16) & 0x07ff)) {
			netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n");
			return 0;
70 71
		}

72
		if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) ||
73
		    (size + offset > skb->len)) {
74 75
			netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
				   size);
76 77
			return 0;
		}
78 79
		ax_skb = netdev_alloc_skb_ip_align(dev->net, size);
		if (!ax_skb)
80 81
			return 0;

82 83 84
		skb_put(ax_skb, size);
		memcpy(ax_skb->data, skb->data + offset, size);
		usbnet_skb_return(dev, ax_skb);
85

86
		offset += (size + 1) & 0xfffe;
87 88
	}

89
	if (skb->len != offset) {
90 91
		netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n",
			   skb->len);
92 93 94 95 96
		return 0;
	}
	return 1;
}

C
Christian Riesch 已提交
97 98
struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
			      gfp_t flags)
99 100 101 102 103 104 105
{
	int padlen;
	int headroom = skb_headroom(skb);
	int tailroom = skb_tailroom(skb);
	u32 packet_len;
	u32 padbytes = 0xffff0000;

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

E
Eric Dumazet 已提交
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
	/* 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) {
126
			skb->data = memmove(skb->head + 4, skb->data, skb->len);
127
			skb_set_tail_pointer(skb, skb->len);
128 129 130
		}
	} else {
		struct sk_buff *skb2;
E
Eric Dumazet 已提交
131

132 133 134 135 136 137 138
		skb2 = skb_copy_expand(skb, 4, padlen, flags);
		dev_kfree_skb_any(skb);
		skb = skb2;
		if (!skb)
			return NULL;
	}

E
Eric Dumazet 已提交
139
	packet_len = ((skb->len ^ 0x0000ffff) << 16) + skb->len;
140
	skb_push(skb, 4);
141
	cpu_to_le32s(&packet_len);
142
	skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len));
143

144
	if (padlen) {
145
		cpu_to_le32s(&padbytes);
146
		memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
147 148 149 150 151
		skb_put(skb, sizeof(padbytes));
	}
	return skb;
}

C
Christian Riesch 已提交
152
int asix_set_sw_mii(struct usbnet *dev)
153 154 155 156
{
	int ret;
	ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
	if (ret < 0)
157
		netdev_err(dev->net, "Failed to enable software MII access\n");
158 159 160
	return ret;
}

C
Christian Riesch 已提交
161
int asix_set_hw_mii(struct usbnet *dev)
162 163 164 165
{
	int ret;
	ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
	if (ret < 0)
166
		netdev_err(dev->net, "Failed to enable hardware MII access\n");
167 168 169
	return ret;
}

170
int asix_read_phy_addr(struct usbnet *dev, int internal)
171
{
172
	int offset = (internal ? 1 : 0);
A
Al Viro 已提交
173 174
	u8 buf[2];
	int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf);
175

176
	netdev_dbg(dev->net, "asix_get_phy_addr()\n");
177

A
Al Viro 已提交
178
	if (ret < 0) {
179
		netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret);
A
Al Viro 已提交
180
		goto out;
181
	}
182 183
	netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n",
		   *((__le16 *)buf));
184
	ret = buf[offset];
A
Al Viro 已提交
185 186

out:
187 188 189
	return ret;
}

190 191 192 193 194 195 196
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 已提交
197
int asix_sw_reset(struct usbnet *dev, u8 flags)
198 199 200 201 202
{
	int ret;

        ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL);
	if (ret < 0)
203
		netdev_err(dev->net, "Failed to send software reset: %02x\n", ret);
204 205 206

	return ret;
}
207

C
Christian Riesch 已提交
208
u16 asix_read_rx_ctl(struct usbnet *dev)
209
{
A
Al Viro 已提交
210 211
	__le16 v;
	int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v);
212

A
Al Viro 已提交
213
	if (ret < 0) {
214
		netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret);
A
Al Viro 已提交
215
		goto out;
216
	}
A
Al Viro 已提交
217 218
	ret = le16_to_cpu(v);
out:
219 220 221
	return ret;
}

C
Christian Riesch 已提交
222
int asix_write_rx_ctl(struct usbnet *dev, u16 mode)
223 224 225
{
	int ret;

226
	netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode);
227 228
	ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
	if (ret < 0)
229 230
		netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n",
			   mode, ret);
231 232 233 234

	return ret;
}

C
Christian Riesch 已提交
235
u16 asix_read_medium_status(struct usbnet *dev)
236
{
A
Al Viro 已提交
237 238
	__le16 v;
	int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v);
239

A
Al Viro 已提交
240
	if (ret < 0) {
241 242
		netdev_err(dev->net, "Error reading Medium Status register: %02x\n",
			   ret);
243
		return ret;	/* TODO: callers not checking for error ret */
244
	}
245 246 247

	return le16_to_cpu(v);

248 249
}

C
Christian Riesch 已提交
250
int asix_write_medium_mode(struct usbnet *dev, u16 mode)
251
{
252
	int ret;
253

254
	netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode);
255 256
	ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
	if (ret < 0)
257 258
		netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n",
			   mode, ret);
259

260 261
	return ret;
}
262

C
Christian Riesch 已提交
263
int asix_write_gpio(struct usbnet *dev, u16 value, int sleep)
264 265
{
	int ret;
266

267
	netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value);
268 269
	ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL);
	if (ret < 0)
270 271
		netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n",
			   value, ret);
272

273 274 275 276
	if (sleep)
		msleep(sleep);

	return ret;
277 278
}

279 280 281
/*
 * AX88772 & AX88178 have a 16-bit RX_CTL value
 */
C
Christian Riesch 已提交
282
void asix_set_multicast(struct net_device *net)
283 284
{
	struct usbnet *dev = netdev_priv(net);
285
	struct asix_data *data = (struct asix_data *)&dev->data;
286
	u16 rx_ctl = AX_DEFAULT_RX_CTL;
287 288

	if (net->flags & IFF_PROMISC) {
289
		rx_ctl |= AX_RX_CTL_PRO;
290
	} else if (net->flags & IFF_ALLMULTI ||
291
		   netdev_mc_count(net) > AX_MAX_MCAST) {
292
		rx_ctl |= AX_RX_CTL_AMALL;
293
	} else if (netdev_mc_empty(net)) {
294 295 296 297 298 299
		/* 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 */
300
		struct netdev_hw_addr *ha;
301 302 303 304 305
		u32 crc_bits;

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

		/* Build the multicast hash filter. */
306 307
		netdev_for_each_mc_addr(ha, net) {
			crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
308 309 310 311
			data->multi_filter[crc_bits >> 3] |=
			    1 << (crc_bits & 7);
		}

312
		asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
313 314
				   AX_MCAST_FILTER_SIZE, data->multi_filter);

315
		rx_ctl |= AX_RX_CTL_AM;
316 317
	}

318
	asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
319 320
}

C
Christian Riesch 已提交
321
int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
322 323
{
	struct usbnet *dev = netdev_priv(netdev);
A
Al Viro 已提交
324
	__le16 res;
325

326
	mutex_lock(&dev->phy_mutex);
327 328
	asix_set_sw_mii(dev);
	asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
A
Al Viro 已提交
329
				(__u16)loc, 2, &res);
330
	asix_set_hw_mii(dev);
331
	mutex_unlock(&dev->phy_mutex);
332

333 334
	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));
335

A
Al Viro 已提交
336
	return le16_to_cpu(res);
337 338
}

C
Christian Riesch 已提交
339
void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
340 341
{
	struct usbnet *dev = netdev_priv(netdev);
A
Al Viro 已提交
342
	__le16 res = cpu_to_le16(val);
343

344 345
	netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
		   phy_id, loc, val);
346
	mutex_lock(&dev->phy_mutex);
347
	asix_set_sw_mii(dev);
A
Al Viro 已提交
348
	asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res);
349
	asix_set_hw_mii(dev);
350
	mutex_unlock(&dev->phy_mutex);
351 352
}

C
Christian Riesch 已提交
353
void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
354 355 356 357
{
	struct usbnet *dev = netdev_priv(net);
	u8 opt;

358
	if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) {
359 360 361 362 363 364
		wolinfo->supported = 0;
		wolinfo->wolopts = 0;
		return;
	}
	wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
	wolinfo->wolopts = 0;
365 366 367 368
	if (opt & AX_MONITOR_LINK)
		wolinfo->wolopts |= WAKE_PHY;
	if (opt & AX_MONITOR_MAGIC)
		wolinfo->wolopts |= WAKE_MAGIC;
369 370
}

C
Christian Riesch 已提交
371
int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
372 373 374 375 376 377 378 379 380
{
	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;

381
	if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE,
A
Al Viro 已提交
382
			      opt, 0, 0, NULL) < 0)
383 384 385 386 387
		return -EINVAL;

	return 0;
}

C
Christian Riesch 已提交
388
int asix_get_eeprom_len(struct net_device *net)
389
{
390
	return AX_EEPROM_LEN;
391 392
}

C
Christian Riesch 已提交
393 394
int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
		    u8 *data)
395 396
{
	struct usbnet *dev = netdev_priv(net);
397 398
	u16 *eeprom_buff;
	int first_word, last_word;
399 400
	int i;

401
	if (eeprom->len == 0)
402 403 404 405
		return -EINVAL;

	eeprom->magic = AX_EEPROM_MAGIC;

406 407 408 409 410 411 412 413
	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;

414
	/* ax8817x returns 2 bytes from eeprom on read */
415 416 417 418 419 420
	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;
		}
421
	}
422 423 424

	memcpy(data, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
	kfree(eeprom_buff);
425 426 427
	return 0;
}

428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 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
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 已提交
509
void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
510 511 512
{
	/* Inherit standard device info */
	usbnet_get_drvinfo(net, info);
513
	strncpy (info->driver, DRIVER_NAME, sizeof info->driver);
514
	strncpy (info->version, DRIVER_VERSION, sizeof info->version);
515
	info->eedump_len = AX_EEPROM_LEN;
516 517
}

C
Christian Riesch 已提交
518
int asix_set_mac_address(struct net_device *net, void *p)
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
{
	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;
}