diff options
author | David J. Choi <david.choi@micrel.com> | 2010-07-13 13:09:19 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-07-13 13:13:49 -0400 |
commit | 28bd620c7a1244e59459d6293ca11f162e0a67b9 (patch) | |
tree | a0ff06027d762346eb81aae4a835c56df0938133 /drivers/net/ks8842.c | |
parent | 242647bcf8464860f173f3d4d4ab3490d3558518 (diff) |
drivers/net: Add Micrel KS8841/42 support to ks8842 driver
Body of the explanation:
-support 16bit and 32bit bus width.
-add device reset for ks8842/8841 Micrel device.
-set 100Mbps as a default for Micrel device.
-set MAC address in both MAC/Switch layer with different sequence for Micrel
device, as mentioned in data sheet.
-use private data to set options both 16/32bit bus width and Micrel device/
Timberdale(FPGA).
-update Kconfig in order to put more information about ks8842 device.
Signed-off-by: David J. Choi <david.choi@micrel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ks8842.c')
-rw-r--r-- | drivers/net/ks8842.c | 174 |
1 files changed, 129 insertions, 45 deletions
diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c index 0be92613acf0..ee69dea69be8 100644 --- a/drivers/net/ks8842.c +++ b/drivers/net/ks8842.c | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | /* Supports: | 19 | /* Supports: |
20 | * The Micrel KS8842 behind the timberdale FPGA | 20 | * The Micrel KS8842 behind the timberdale FPGA |
21 | * The genuine Micrel KS8841/42 device with ISA 16/32bit bus interface | ||
21 | */ | 22 | */ |
22 | 23 | ||
23 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 24 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
@@ -114,9 +115,14 @@ | |||
114 | #define REG_P1CR4 0x02 | 115 | #define REG_P1CR4 0x02 |
115 | #define REG_P1SR 0x04 | 116 | #define REG_P1SR 0x04 |
116 | 117 | ||
118 | /* flags passed by platform_device for configuration */ | ||
119 | #define MICREL_KS884X 0x01 /* 0=Timeberdale(FPGA), 1=Micrel */ | ||
120 | #define KS884X_16BIT 0x02 /* 1=16bit, 0=32bit */ | ||
121 | |||
117 | struct ks8842_adapter { | 122 | struct ks8842_adapter { |
118 | void __iomem *hw_addr; | 123 | void __iomem *hw_addr; |
119 | int irq; | 124 | int irq; |
125 | unsigned long conf_flags; /* copy of platform_device config */ | ||
120 | struct tasklet_struct tasklet; | 126 | struct tasklet_struct tasklet; |
121 | spinlock_t lock; /* spinlock to be interrupt safe */ | 127 | spinlock_t lock; /* spinlock to be interrupt safe */ |
122 | struct work_struct timeout_work; | 128 | struct work_struct timeout_work; |
@@ -192,15 +198,21 @@ static inline u32 ks8842_read32(struct ks8842_adapter *adapter, u16 bank, | |||
192 | 198 | ||
193 | static void ks8842_reset(struct ks8842_adapter *adapter) | 199 | static void ks8842_reset(struct ks8842_adapter *adapter) |
194 | { | 200 | { |
195 | /* The KS8842 goes haywire when doing softare reset | 201 | if (adapter->conf_flags & MICREL_KS884X) { |
196 | * a work around in the timberdale IP is implemented to | 202 | ks8842_write16(adapter, 3, 1, REG_GRR); |
197 | * do a hardware reset instead | 203 | msleep(10); |
198 | ks8842_write16(adapter, 3, 1, REG_GRR); | 204 | iowrite16(0, adapter->hw_addr + REG_GRR); |
199 | msleep(10); | 205 | } else { |
200 | iowrite16(0, adapter->hw_addr + REG_GRR); | 206 | /* The KS8842 goes haywire when doing softare reset |
201 | */ | 207 | * a work around in the timberdale IP is implemented to |
202 | iowrite32(0x1, adapter->hw_addr + REG_TIMB_RST); | 208 | * do a hardware reset instead |
203 | msleep(20); | 209 | ks8842_write16(adapter, 3, 1, REG_GRR); |
210 | msleep(10); | ||
211 | iowrite16(0, adapter->hw_addr + REG_GRR); | ||
212 | */ | ||
213 | iowrite32(0x1, adapter->hw_addr + REG_TIMB_RST); | ||
214 | msleep(20); | ||
215 | } | ||
204 | } | 216 | } |
205 | 217 | ||
206 | static void ks8842_update_link_status(struct net_device *netdev, | 218 | static void ks8842_update_link_status(struct net_device *netdev, |
@@ -269,8 +281,10 @@ static void ks8842_reset_hw(struct ks8842_adapter *adapter) | |||
269 | 281 | ||
270 | /* restart port auto-negotiation */ | 282 | /* restart port auto-negotiation */ |
271 | ks8842_enable_bits(adapter, 49, 1 << 13, REG_P1CR4); | 283 | ks8842_enable_bits(adapter, 49, 1 << 13, REG_P1CR4); |
272 | /* only advertise 10Mbps */ | 284 | |
273 | ks8842_clear_bits(adapter, 49, 3 << 2, REG_P1CR4); | 285 | if (!(adapter->conf_flags & MICREL_KS884X)) |
286 | /* only advertise 10Mbps */ | ||
287 | ks8842_clear_bits(adapter, 49, 3 << 2, REG_P1CR4); | ||
274 | 288 | ||
275 | /* Enable the transmitter */ | 289 | /* Enable the transmitter */ |
276 | ks8842_enable_tx(adapter); | 290 | ks8842_enable_tx(adapter); |
@@ -296,13 +310,28 @@ static void ks8842_read_mac_addr(struct ks8842_adapter *adapter, u8 *dest) | |||
296 | for (i = 0; i < ETH_ALEN; i++) | 310 | for (i = 0; i < ETH_ALEN; i++) |
297 | dest[ETH_ALEN - i - 1] = ks8842_read8(adapter, 2, REG_MARL + i); | 311 | dest[ETH_ALEN - i - 1] = ks8842_read8(adapter, 2, REG_MARL + i); |
298 | 312 | ||
299 | /* make sure the switch port uses the same MAC as the QMU */ | 313 | if (adapter->conf_flags & MICREL_KS884X) { |
300 | mac = ks8842_read16(adapter, 2, REG_MARL); | 314 | /* |
301 | ks8842_write16(adapter, 39, mac, REG_MACAR1); | 315 | the sequence of saving mac addr between MAC and Switch is |
302 | mac = ks8842_read16(adapter, 2, REG_MARM); | 316 | different. |
303 | ks8842_write16(adapter, 39, mac, REG_MACAR2); | 317 | */ |
304 | mac = ks8842_read16(adapter, 2, REG_MARH); | 318 | |
305 | ks8842_write16(adapter, 39, mac, REG_MACAR3); | 319 | mac = ks8842_read16(adapter, 2, REG_MARL); |
320 | ks8842_write16(adapter, 39, mac, REG_MACAR3); | ||
321 | mac = ks8842_read16(adapter, 2, REG_MARM); | ||
322 | ks8842_write16(adapter, 39, mac, REG_MACAR2); | ||
323 | mac = ks8842_read16(adapter, 2, REG_MARH); | ||
324 | ks8842_write16(adapter, 39, mac, REG_MACAR1); | ||
325 | } else { | ||
326 | |||
327 | /* make sure the switch port uses the same MAC as the QMU */ | ||
328 | mac = ks8842_read16(adapter, 2, REG_MARL); | ||
329 | ks8842_write16(adapter, 39, mac, REG_MACAR1); | ||
330 | mac = ks8842_read16(adapter, 2, REG_MARM); | ||
331 | ks8842_write16(adapter, 39, mac, REG_MACAR2); | ||
332 | mac = ks8842_read16(adapter, 2, REG_MARH); | ||
333 | ks8842_write16(adapter, 39, mac, REG_MACAR3); | ||
334 | } | ||
306 | } | 335 | } |
307 | 336 | ||
308 | static void ks8842_write_mac_addr(struct ks8842_adapter *adapter, u8 *mac) | 337 | static void ks8842_write_mac_addr(struct ks8842_adapter *adapter, u8 *mac) |
@@ -313,8 +342,25 @@ static void ks8842_write_mac_addr(struct ks8842_adapter *adapter, u8 *mac) | |||
313 | spin_lock_irqsave(&adapter->lock, flags); | 342 | spin_lock_irqsave(&adapter->lock, flags); |
314 | for (i = 0; i < ETH_ALEN; i++) { | 343 | for (i = 0; i < ETH_ALEN; i++) { |
315 | ks8842_write8(adapter, 2, mac[ETH_ALEN - i - 1], REG_MARL + i); | 344 | ks8842_write8(adapter, 2, mac[ETH_ALEN - i - 1], REG_MARL + i); |
316 | ks8842_write8(adapter, 39, mac[ETH_ALEN - i - 1], | 345 | if (!(adapter->conf_flags & MICREL_KS884X)) |
317 | REG_MACAR1 + i); | 346 | ks8842_write8(adapter, 39, mac[ETH_ALEN - i - 1], |
347 | REG_MACAR1 + i); | ||
348 | } | ||
349 | |||
350 | if (adapter->conf_flags & MICREL_KS884X) { | ||
351 | /* | ||
352 | the sequence of saving mac addr between MAC and Switch is | ||
353 | different. | ||
354 | */ | ||
355 | |||
356 | u16 mac; | ||
357 | |||
358 | mac = ks8842_read16(adapter, 2, REG_MARL); | ||
359 | ks8842_write16(adapter, 39, mac, REG_MACAR3); | ||
360 | mac = ks8842_read16(adapter, 2, REG_MARM); | ||
361 | ks8842_write16(adapter, 39, mac, REG_MACAR2); | ||
362 | mac = ks8842_read16(adapter, 2, REG_MARH); | ||
363 | ks8842_write16(adapter, 39, mac, REG_MACAR1); | ||
318 | } | 364 | } |
319 | spin_unlock_irqrestore(&adapter->lock, flags); | 365 | spin_unlock_irqrestore(&adapter->lock, flags); |
320 | } | 366 | } |
@@ -328,8 +374,6 @@ static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev) | |||
328 | { | 374 | { |
329 | struct ks8842_adapter *adapter = netdev_priv(netdev); | 375 | struct ks8842_adapter *adapter = netdev_priv(netdev); |
330 | int len = skb->len; | 376 | int len = skb->len; |
331 | u32 *ptr = (u32 *)skb->data; | ||
332 | u32 ctrl; | ||
333 | 377 | ||
334 | netdev_dbg(netdev, "%s: len %u head %p data %p tail %p end %p\n", | 378 | netdev_dbg(netdev, "%s: len %u head %p data %p tail %p end %p\n", |
335 | __func__, skb->len, skb->head, skb->data, | 379 | __func__, skb->len, skb->head, skb->data, |
@@ -339,17 +383,34 @@ static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev) | |||
339 | if (ks8842_tx_fifo_space(adapter) < len + 8) | 383 | if (ks8842_tx_fifo_space(adapter) < len + 8) |
340 | return NETDEV_TX_BUSY; | 384 | return NETDEV_TX_BUSY; |
341 | 385 | ||
342 | /* the control word, enable IRQ, port 1 and the length */ | 386 | if (adapter->conf_flags & KS884X_16BIT) { |
343 | ctrl = 0x8000 | 0x100 | (len << 16); | 387 | u16 *ptr16 = (u16 *)skb->data; |
344 | ks8842_write32(adapter, 17, ctrl, REG_QMU_DATA_LO); | 388 | ks8842_write16(adapter, 17, 0x8000 | 0x100, REG_QMU_DATA_LO); |
389 | ks8842_write16(adapter, 17, (u16)len, REG_QMU_DATA_HI); | ||
390 | netdev->stats.tx_bytes += len; | ||
391 | |||
392 | /* copy buffer */ | ||
393 | while (len > 0) { | ||
394 | iowrite16(*ptr16++, adapter->hw_addr + REG_QMU_DATA_LO); | ||
395 | iowrite16(*ptr16++, adapter->hw_addr + REG_QMU_DATA_HI); | ||
396 | len -= sizeof(u32); | ||
397 | } | ||
398 | } else { | ||
399 | |||
400 | u32 *ptr = (u32 *)skb->data; | ||
401 | u32 ctrl; | ||
402 | /* the control word, enable IRQ, port 1 and the length */ | ||
403 | ctrl = 0x8000 | 0x100 | (len << 16); | ||
404 | ks8842_write32(adapter, 17, ctrl, REG_QMU_DATA_LO); | ||
345 | 405 | ||
346 | netdev->stats.tx_bytes += len; | 406 | netdev->stats.tx_bytes += len; |
347 | 407 | ||
348 | /* copy buffer */ | 408 | /* copy buffer */ |
349 | while (len > 0) { | 409 | while (len > 0) { |
350 | iowrite32(*ptr, adapter->hw_addr + REG_QMU_DATA_LO); | 410 | iowrite32(*ptr, adapter->hw_addr + REG_QMU_DATA_LO); |
351 | len -= sizeof(u32); | 411 | len -= sizeof(u32); |
352 | ptr++; | 412 | ptr++; |
413 | } | ||
353 | } | 414 | } |
354 | 415 | ||
355 | /* enqueue packet */ | 416 | /* enqueue packet */ |
@@ -363,12 +424,23 @@ static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev) | |||
363 | static void ks8842_rx_frame(struct net_device *netdev, | 424 | static void ks8842_rx_frame(struct net_device *netdev, |
364 | struct ks8842_adapter *adapter) | 425 | struct ks8842_adapter *adapter) |
365 | { | 426 | { |
366 | u32 status = ks8842_read32(adapter, 17, REG_QMU_DATA_LO); | 427 | u16 status16; |
367 | int len = (status >> 16) & 0x7ff; | 428 | u32 status; |
429 | int len; | ||
368 | 430 | ||
369 | status &= 0xffff; | 431 | if (adapter->conf_flags & KS884X_16BIT) { |
370 | 432 | status16 = ks8842_read16(adapter, 17, REG_QMU_DATA_LO); | |
371 | netdev_dbg(netdev, "%s - rx_data: status: %x\n", __func__, status); | 433 | len = (int)ks8842_read16(adapter, 17, REG_QMU_DATA_HI); |
434 | len &= 0xffff; | ||
435 | netdev_dbg(netdev, "%s - rx_data: status: %x\n", | ||
436 | __func__, status16); | ||
437 | } else { | ||
438 | status = ks8842_read32(adapter, 17, REG_QMU_DATA_LO); | ||
439 | len = (status >> 16) & 0x7ff; | ||
440 | status &= 0xffff; | ||
441 | netdev_dbg(netdev, "%s - rx_data: status: %x\n", | ||
442 | __func__, status); | ||
443 | } | ||
372 | 444 | ||
373 | /* check the status */ | 445 | /* check the status */ |
374 | if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) { | 446 | if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) { |
@@ -376,22 +448,32 @@ static void ks8842_rx_frame(struct net_device *netdev, | |||
376 | 448 | ||
377 | netdev_dbg(netdev, "%s, got package, len: %d\n", __func__, len); | 449 | netdev_dbg(netdev, "%s, got package, len: %d\n", __func__, len); |
378 | if (skb) { | 450 | if (skb) { |
379 | u32 *data; | ||
380 | 451 | ||
381 | netdev->stats.rx_packets++; | 452 | netdev->stats.rx_packets++; |
382 | netdev->stats.rx_bytes += len; | 453 | netdev->stats.rx_bytes += len; |
383 | if (status & RXSR_MULTICAST) | 454 | if (status & RXSR_MULTICAST) |
384 | netdev->stats.multicast++; | 455 | netdev->stats.multicast++; |
385 | 456 | ||
386 | data = (u32 *)skb_put(skb, len); | 457 | if (adapter->conf_flags & KS884X_16BIT) { |
387 | 458 | u16 *data16 = (u16 *)skb_put(skb, len); | |
388 | ks8842_select_bank(adapter, 17); | 459 | ks8842_select_bank(adapter, 17); |
389 | while (len > 0) { | 460 | while (len > 0) { |
390 | *data++ = ioread32(adapter->hw_addr + | 461 | *data16++ = ioread16(adapter->hw_addr + |
391 | REG_QMU_DATA_LO); | 462 | REG_QMU_DATA_LO); |
392 | len -= sizeof(u32); | 463 | *data16++ = ioread16(adapter->hw_addr + |
464 | REG_QMU_DATA_HI); | ||
465 | len -= sizeof(u32); | ||
466 | } | ||
467 | } else { | ||
468 | u32 *data = (u32 *)skb_put(skb, len); | ||
469 | |||
470 | ks8842_select_bank(adapter, 17); | ||
471 | while (len > 0) { | ||
472 | *data++ = ioread32(adapter->hw_addr + | ||
473 | REG_QMU_DATA_LO); | ||
474 | len -= sizeof(u32); | ||
475 | } | ||
393 | } | 476 | } |
394 | |||
395 | skb->protocol = eth_type_trans(skb, netdev); | 477 | skb->protocol = eth_type_trans(skb, netdev); |
396 | netif_rx(skb); | 478 | netif_rx(skb); |
397 | } else | 479 | } else |
@@ -669,6 +751,8 @@ static int __devinit ks8842_probe(struct platform_device *pdev) | |||
669 | adapter->netdev = netdev; | 751 | adapter->netdev = netdev; |
670 | INIT_WORK(&adapter->timeout_work, ks8842_tx_timeout_work); | 752 | INIT_WORK(&adapter->timeout_work, ks8842_tx_timeout_work); |
671 | adapter->hw_addr = ioremap(iomem->start, resource_size(iomem)); | 753 | adapter->hw_addr = ioremap(iomem->start, resource_size(iomem)); |
754 | adapter->conf_flags = iomem->flags; | ||
755 | |||
672 | if (!adapter->hw_addr) | 756 | if (!adapter->hw_addr) |
673 | goto err_ioremap; | 757 | goto err_ioremap; |
674 | 758 | ||