Newer
Older
/*
* Driver for (BCM4706)? GBit MAC core on BCMA bus.
*
* Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com>
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#include "bgmac.h"
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/mii.h>
#include <linux/phy_fixed.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/bcm47xx_nvram.h>
static const struct bcma_device_id bgmac_bcma_tbl[] = {
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
};
MODULE_DEVICE_TABLE(bcma, bgmac_bcma_tbl);
static inline bool bgmac_is_bcm4707_family(struct bgmac *bgmac)
{
switch (bgmac->core->bus->chipinfo.id) {
case BCMA_CHIP_ID_BCM4707:
case BCMA_CHIP_ID_BCM47094:
case BCMA_CHIP_ID_BCM53018:
return true;
default:
return false;
}
}
41
42
43
44
45
46
47
48
49
50
51
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
static bool bgmac_wait_value(struct bcma_device *core, u16 reg, u32 mask,
u32 value, int timeout)
{
u32 val;
int i;
for (i = 0; i < timeout / 10; i++) {
val = bcma_read32(core, reg);
if ((val & mask) == value)
return true;
udelay(10);
}
pr_err("Timeout waiting for reg 0x%X\n", reg);
return false;
}
/**************************************************
* DMA
**************************************************/
static void bgmac_dma_tx_reset(struct bgmac *bgmac, struct bgmac_dma_ring *ring)
{
u32 val;
int i;
if (!ring->mmio_base)
return;
/* Suspend DMA TX ring first.
* bgmac_wait_value doesn't support waiting for any of few values, so
* implement whole loop here.
*/
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL,
BGMAC_DMA_TX_SUSPEND);
for (i = 0; i < 10000 / 10; i++) {
val = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_STATUS);
val &= BGMAC_DMA_TX_STAT;
if (val == BGMAC_DMA_TX_STAT_DISABLED ||
val == BGMAC_DMA_TX_STAT_IDLEWAIT ||
val == BGMAC_DMA_TX_STAT_STOPPED) {
i = 0;
break;
}
udelay(10);
}
if (i)
bgmac_err(bgmac, "Timeout suspending DMA TX ring 0x%X (BGMAC_DMA_TX_STAT: 0x%08X)\n",
ring->mmio_base, val);
/* Remove SUSPEND bit */
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL, 0);
if (!bgmac_wait_value(bgmac->core,
ring->mmio_base + BGMAC_DMA_TX_STATUS,
BGMAC_DMA_TX_STAT, BGMAC_DMA_TX_STAT_DISABLED,
10000)) {
bgmac_warn(bgmac, "DMA TX ring 0x%X wasn't disabled on time, waiting additional 300us\n",
ring->mmio_base);
udelay(300);
val = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_STATUS);
if ((val & BGMAC_DMA_TX_STAT) != BGMAC_DMA_TX_STAT_DISABLED)
bgmac_err(bgmac, "Reset of DMA TX ring 0x%X failed\n",
ring->mmio_base);
}
}
static void bgmac_dma_tx_enable(struct bgmac *bgmac,
struct bgmac_dma_ring *ring)
{
u32 ctl;
ctl = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL);
if (bgmac->core->id.rev >= 4) {
ctl &= ~BGMAC_DMA_TX_BL_MASK;
ctl |= BGMAC_DMA_TX_BL_128 << BGMAC_DMA_TX_BL_SHIFT;
ctl &= ~BGMAC_DMA_TX_MR_MASK;
ctl |= BGMAC_DMA_TX_MR_2 << BGMAC_DMA_TX_MR_SHIFT;
ctl &= ~BGMAC_DMA_TX_PC_MASK;
ctl |= BGMAC_DMA_TX_PC_16 << BGMAC_DMA_TX_PC_SHIFT;
ctl &= ~BGMAC_DMA_TX_PT_MASK;
ctl |= BGMAC_DMA_TX_PT_8 << BGMAC_DMA_TX_PT_SHIFT;
}
ctl |= BGMAC_DMA_TX_ENABLE;
ctl |= BGMAC_DMA_TX_PARITY_DISABLE;
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL, ctl);
}
static void
bgmac_dma_tx_add_buf(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
int i, int len, u32 ctl0)
{
struct bgmac_slot_info *slot;
struct bgmac_dma_desc *dma_desc;
u32 ctl1;
ctl0 |= BGMAC_DESC_CTL0_EOT;
ctl1 = len & BGMAC_DESC_CTL1_LEN;
slot = &ring->slots[i];
dma_desc = &ring->cpu_base[i];
dma_desc->addr_low = cpu_to_le32(lower_32_bits(slot->dma_addr));
dma_desc->addr_high = cpu_to_le32(upper_32_bits(slot->dma_addr));
dma_desc->ctl0 = cpu_to_le32(ctl0);
dma_desc->ctl1 = cpu_to_le32(ctl1);
}
static netdev_tx_t bgmac_dma_tx_add(struct bgmac *bgmac,
struct bgmac_dma_ring *ring,
struct sk_buff *skb)
{
struct device *dma_dev = bgmac->core->dma_dev;
struct net_device *net_dev = bgmac->net_dev;
int index = ring->end % BGMAC_TX_RING_SLOTS;
struct bgmac_slot_info *slot = &ring->slots[index];
int nr_frags;
u32 flags;
int i;
if (skb->len > BGMAC_DESC_CTL1_LEN) {
bgmac_err(bgmac, "Too long skb (%d)\n", skb->len);
if (skb->ip_summed == CHECKSUM_PARTIAL)
skb_checksum_help(skb);
nr_frags = skb_shinfo(skb)->nr_frags;
/* ring->end - ring->start will return the number of valid slots,
* even when ring->end overflows
*/
if (ring->end - ring->start + nr_frags + 1 >= BGMAC_TX_RING_SLOTS) {
bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n");
netif_stop_queue(net_dev);
return NETDEV_TX_BUSY;
}
slot->dma_addr = dma_map_single(dma_dev, skb->data, skb_headlen(skb),
if (unlikely(dma_mapping_error(dma_dev, slot->dma_addr)))
goto err_dma_head;
flags = BGMAC_DESC_CTL0_SOF;
if (!nr_frags)
flags |= BGMAC_DESC_CTL0_EOF | BGMAC_DESC_CTL0_IOC;
bgmac_dma_tx_add_buf(bgmac, ring, index, skb_headlen(skb), flags);
flags = 0;
for (i = 0; i < nr_frags; i++) {
struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
int len = skb_frag_size(frag);
index = (index + 1) % BGMAC_TX_RING_SLOTS;
slot = &ring->slots[index];
slot->dma_addr = skb_frag_dma_map(dma_dev, frag, 0,
len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(dma_dev, slot->dma_addr)))
goto err_dma;
if (i == nr_frags - 1)
flags |= BGMAC_DESC_CTL0_EOF | BGMAC_DESC_CTL0_IOC;
bgmac_dma_tx_add_buf(bgmac, ring, index, len, flags);
}
slot->skb = skb;
netdev_sent_queue(net_dev, skb->len);
wmb();
/* Increase ring->end to point empty slot. We tell hardware the first
* slot it should *not* read.
*/
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX,
ring->index_base +
(ring->end % BGMAC_TX_RING_SLOTS) *
sizeof(struct bgmac_dma_desc));
if (ring->end - ring->start >= BGMAC_TX_RING_SLOTS - 8)
netif_stop_queue(net_dev);
return NETDEV_TX_OK;
err_dma:
dma_unmap_single(dma_dev, slot->dma_addr, skb_headlen(skb),
DMA_TO_DEVICE);
while (i > 0) {
int index = (ring->end + i) % BGMAC_TX_RING_SLOTS;
struct bgmac_slot_info *slot = &ring->slots[index];
u32 ctl1 = le32_to_cpu(ring->cpu_base[index].ctl1);
int len = ctl1 & BGMAC_DESC_CTL1_LEN;
dma_unmap_page(dma_dev, slot->dma_addr, len, DMA_TO_DEVICE);
}
err_dma_head:
bgmac_err(bgmac, "Mapping error of skb on ring 0x%X\n",
ring->mmio_base);
err_drop:
net_dev->stats.tx_dropped++;
net_dev->stats.tx_errors++;
return NETDEV_TX_OK;
}
/* Free transmitted packets */
static void bgmac_dma_tx_free(struct bgmac *bgmac, struct bgmac_dma_ring *ring)
{
struct device *dma_dev = bgmac->core->dma_dev;
int empty_slot;
bool freed = false;
unsigned bytes_compl = 0, pkts_compl = 0;
/* The last slot that hardware didn't consume yet */
empty_slot = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_STATUS);
empty_slot &= BGMAC_DMA_TX_STATDPTR;
empty_slot -= ring->index_base;
empty_slot &= BGMAC_DMA_TX_STATDPTR;
empty_slot /= sizeof(struct bgmac_dma_desc);
while (ring->start != ring->end) {
int slot_idx = ring->start % BGMAC_TX_RING_SLOTS;
struct bgmac_slot_info *slot = &ring->slots[slot_idx];
u32 ctl1;
int len;
if (slot_idx == empty_slot)
break;
ctl1 = le32_to_cpu(ring->cpu_base[slot_idx].ctl1);
len = ctl1 & BGMAC_DESC_CTL1_LEN;
/* Unmap no longer used buffer */
dma_unmap_single(dma_dev, slot->dma_addr, len,
DMA_TO_DEVICE);
else
dma_unmap_page(dma_dev, slot->dma_addr, len,
DMA_TO_DEVICE);
bgmac->net_dev->stats.tx_bytes += slot->skb->len;
bgmac->net_dev->stats.tx_packets++;
bytes_compl += slot->skb->len;
pkts_compl++;
/* Free memory! :) */
dev_kfree_skb(slot->skb);
slot->skb = NULL;
}
if (!pkts_compl)
return;
netdev_completed_queue(bgmac->net_dev, pkts_compl, bytes_compl);
if (netif_queue_stopped(bgmac->net_dev))
netif_wake_queue(bgmac->net_dev);
}
static void bgmac_dma_rx_reset(struct bgmac *bgmac, struct bgmac_dma_ring *ring)
{
if (!ring->mmio_base)
return;
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL, 0);
if (!bgmac_wait_value(bgmac->core,
ring->mmio_base + BGMAC_DMA_RX_STATUS,
BGMAC_DMA_RX_STAT, BGMAC_DMA_RX_STAT_DISABLED,
10000))
bgmac_err(bgmac, "Reset of ring 0x%X RX failed\n",
ring->mmio_base);
}
static void bgmac_dma_rx_enable(struct bgmac *bgmac,
struct bgmac_dma_ring *ring)
{
u32 ctl;
ctl = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL);
if (bgmac->core->id.rev >= 4) {
ctl &= ~BGMAC_DMA_RX_BL_MASK;
ctl |= BGMAC_DMA_RX_BL_128 << BGMAC_DMA_RX_BL_SHIFT;
ctl &= ~BGMAC_DMA_RX_PC_MASK;
ctl |= BGMAC_DMA_RX_PC_8 << BGMAC_DMA_RX_PC_SHIFT;
ctl &= ~BGMAC_DMA_RX_PT_MASK;
ctl |= BGMAC_DMA_RX_PT_1 << BGMAC_DMA_RX_PT_SHIFT;
}
ctl &= BGMAC_DMA_RX_ADDREXT_MASK;
ctl |= BGMAC_DMA_RX_ENABLE;
ctl |= BGMAC_DMA_RX_PARITY_DISABLE;
ctl |= BGMAC_DMA_RX_OVERFLOW_CONT;
ctl |= BGMAC_RX_FRAME_OFFSET << BGMAC_DMA_RX_FRAME_OFFSET_SHIFT;
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL, ctl);
}
static int bgmac_dma_rx_skb_for_slot(struct bgmac *bgmac,
struct bgmac_slot_info *slot)
{
struct device *dma_dev = bgmac->core->dma_dev;
dma_addr_t dma_addr;
buf = netdev_alloc_frag(BGMAC_RX_ALLOC_SIZE);
if (!buf)
return -ENOMEM;
/* Poison - if everything goes fine, hardware will overwrite it */
rx = buf + BGMAC_RX_BUF_OFFSET;
rx->len = cpu_to_le16(0xdead);
rx->flags = cpu_to_le16(0xbeef);
/* Map skb for the DMA */
dma_addr = dma_map_single(dma_dev, buf + BGMAC_RX_BUF_OFFSET,
BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
if (dma_mapping_error(dma_dev, dma_addr)) {
bgmac_err(bgmac, "DMA mapping error\n");
put_page(virt_to_head_page(buf));
/* Update the slot */
slot->dma_addr = dma_addr;
static void bgmac_dma_rx_update_index(struct bgmac *bgmac,
struct bgmac_dma_ring *ring)
{
dma_wmb();
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX,
ring->index_base +
ring->end * sizeof(struct bgmac_dma_desc));
}
static void bgmac_dma_rx_setup_desc(struct bgmac *bgmac,
struct bgmac_dma_ring *ring, int desc_idx)
{
struct bgmac_dma_desc *dma_desc = ring->cpu_base + desc_idx;
u32 ctl0 = 0, ctl1 = 0;
ctl0 |= BGMAC_DESC_CTL0_EOT;
ctl1 |= BGMAC_RX_BUF_SIZE & BGMAC_DESC_CTL1_LEN;
/* Is there any BGMAC device that requires extension? */
/* ctl1 |= (addrext << B43_DMA64_DCTL1_ADDREXT_SHIFT) &
* B43_DMA64_DCTL1_ADDREXT_MASK;
*/
dma_desc->addr_low = cpu_to_le32(lower_32_bits(ring->slots[desc_idx].dma_addr));
dma_desc->addr_high = cpu_to_le32(upper_32_bits(ring->slots[desc_idx].dma_addr));
dma_desc->ctl0 = cpu_to_le32(ctl0);
dma_desc->ctl1 = cpu_to_le32(ctl1);
static void bgmac_dma_rx_poison_buf(struct device *dma_dev,
struct bgmac_slot_info *slot)
{
struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
dma_sync_single_for_cpu(dma_dev, slot->dma_addr, BGMAC_RX_BUF_SIZE,
DMA_FROM_DEVICE);
rx->len = cpu_to_le16(0xdead);
rx->flags = cpu_to_le16(0xbeef);
dma_sync_single_for_device(dma_dev, slot->dma_addr, BGMAC_RX_BUF_SIZE,
DMA_FROM_DEVICE);
}
static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
int weight)
{
u32 end_slot;
int handled = 0;
end_slot = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_STATUS);
end_slot &= BGMAC_DMA_RX_STATDPTR;
end_slot -= ring->index_base;
end_slot &= BGMAC_DMA_RX_STATDPTR;
end_slot /= sizeof(struct bgmac_dma_desc);
struct device *dma_dev = bgmac->core->dma_dev;
struct bgmac_slot_info *slot = &ring->slots[ring->start];
struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
struct sk_buff *skb;
void *buf = slot->buf;
dma_addr_t dma_addr = slot->dma_addr;
do {
/* Prepare new skb as replacement */
if (bgmac_dma_rx_skb_for_slot(bgmac, slot)) {
bgmac_dma_rx_poison_buf(dma_dev, slot);
break;
}
/* Unmap buffer to make it accessible to the CPU */
dma_unmap_single(dma_dev, dma_addr,
BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
/* Get info from the header */
len = le16_to_cpu(rx->len);
flags = le16_to_cpu(rx->flags);
/* Check for poison and drop or pass the packet */
if (len == 0xdead && flags == 0xbeef) {
bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n",
ring->start);
put_page(virt_to_head_page(buf));
bgmac->net_dev->stats.rx_errors++;
break;
}
if (len > BGMAC_RX_ALLOC_SIZE) {
bgmac_err(bgmac, "Found oversized packet at slot %d, DMA issue!\n",
ring->start);
put_page(virt_to_head_page(buf));
bgmac->net_dev->stats.rx_length_errors++;
bgmac->net_dev->stats.rx_errors++;
skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
if (unlikely(!skb)) {
bgmac_err(bgmac, "build_skb failed\n");
put_page(virt_to_head_page(buf));
bgmac->net_dev->stats.rx_errors++;
skb_put(skb, BGMAC_RX_FRAME_OFFSET +
BGMAC_RX_BUF_OFFSET + len);
skb_pull(skb, BGMAC_RX_FRAME_OFFSET +
BGMAC_RX_BUF_OFFSET);
skb_checksum_none_assert(skb);
skb->protocol = eth_type_trans(skb, bgmac->net_dev);
bgmac->net_dev->stats.rx_bytes += len;
bgmac->net_dev->stats.rx_packets++;
napi_gro_receive(&bgmac->napi, skb);
handled++;
} while (0);
bgmac_dma_rx_setup_desc(bgmac, ring, ring->start);
if (++ring->start >= BGMAC_RX_RING_SLOTS)
ring->start = 0;
if (handled >= weight) /* Should never be greater */
break;
}
bgmac_dma_rx_update_index(bgmac, ring);
return handled;
}
/* Does ring support unaligned addressing? */
static bool bgmac_dma_unaligned(struct bgmac *bgmac,
struct bgmac_dma_ring *ring,
enum bgmac_dma_ring_type ring_type)
{
switch (ring_type) {
case BGMAC_DMA_RING_TX:
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGLO,
0xff0);
if (bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGLO))
return true;
break;
case BGMAC_DMA_RING_RX:
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO,
0xff0);
if (bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO))
return true;
break;
}
return false;
}
static void bgmac_dma_tx_ring_free(struct bgmac *bgmac,
struct bgmac_dma_ring *ring)
{
struct device *dma_dev = bgmac->core->dma_dev;
struct bgmac_dma_desc *dma_desc = ring->cpu_base;
struct bgmac_slot_info *slot;
int i;
int len = dma_desc[i].ctl1 & BGMAC_DESC_CTL1_LEN;
dev_kfree_skb(slot->skb);
if (!slot->dma_addr)
continue;
if (slot->skb)
dma_unmap_single(dma_dev, slot->dma_addr,
len, DMA_TO_DEVICE);
else
dma_unmap_page(dma_dev, slot->dma_addr,
len, DMA_TO_DEVICE);
}
static void bgmac_dma_rx_ring_free(struct bgmac *bgmac,
struct bgmac_dma_ring *ring)
{
struct device *dma_dev = bgmac->core->dma_dev;
struct bgmac_slot_info *slot;
int i;
dma_unmap_single(dma_dev, slot->dma_addr,
BGMAC_RX_BUF_SIZE,
DMA_FROM_DEVICE);
put_page(virt_to_head_page(slot->buf));
static void bgmac_dma_ring_desc_free(struct bgmac *bgmac,
struct bgmac_dma_ring *ring,
int num_slots)
{
struct device *dma_dev = bgmac->core->dma_dev;
int size;
if (!ring->cpu_base)
return;
/* Free ring of descriptors */
size = num_slots * sizeof(struct bgmac_dma_desc);
dma_free_coherent(dma_dev, size, ring->cpu_base,
ring->dma_base);
}
static void bgmac_dma_cleanup(struct bgmac *bgmac)
for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
bgmac_dma_tx_ring_free(bgmac, &bgmac->tx_ring[i]);
for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
bgmac_dma_rx_ring_free(bgmac, &bgmac->rx_ring[i]);
}
static void bgmac_dma_free(struct bgmac *bgmac)
{
int i;
for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i],
BGMAC_TX_RING_SLOTS);
for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i],
BGMAC_RX_RING_SLOTS);
}
static int bgmac_dma_alloc(struct bgmac *bgmac)
{
struct device *dma_dev = bgmac->core->dma_dev;
struct bgmac_dma_ring *ring;
static const u16 ring_base[] = { BGMAC_DMA_BASE0, BGMAC_DMA_BASE1,
BGMAC_DMA_BASE2, BGMAC_DMA_BASE3, };
int size; /* ring size: different for Tx and Rx */
int err;
int i;
BUILD_BUG_ON(BGMAC_MAX_TX_RINGS > ARRAY_SIZE(ring_base));
BUILD_BUG_ON(BGMAC_MAX_RX_RINGS > ARRAY_SIZE(ring_base));
if (!(bcma_aread32(bgmac->core, BCMA_IOST) & BCMA_IOST_DMA64)) {
bgmac_err(bgmac, "Core does not report 64-bit DMA\n");
return -ENOTSUPP;
}
for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
ring = &bgmac->tx_ring[i];
ring->mmio_base = ring_base[i];
/* Alloc ring of descriptors */
size = BGMAC_TX_RING_SLOTS * sizeof(struct bgmac_dma_desc);
ring->cpu_base = dma_zalloc_coherent(dma_dev, size,
&ring->dma_base,
GFP_KERNEL);
if (!ring->cpu_base) {
bgmac_err(bgmac, "Allocation of TX ring 0x%X failed\n",
ring->mmio_base);
goto err_dma_free;
}
ring->unaligned = bgmac_dma_unaligned(bgmac, ring,
BGMAC_DMA_RING_TX);
if (ring->unaligned)
ring->index_base = lower_32_bits(ring->dma_base);
else
ring->index_base = 0;
/* No need to alloc TX slots yet */
}
for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
ring = &bgmac->rx_ring[i];
ring->mmio_base = ring_base[i];
/* Alloc ring of descriptors */
size = BGMAC_RX_RING_SLOTS * sizeof(struct bgmac_dma_desc);
ring->cpu_base = dma_zalloc_coherent(dma_dev, size,
&ring->dma_base,
GFP_KERNEL);
if (!ring->cpu_base) {
bgmac_err(bgmac, "Allocation of RX ring 0x%X failed\n",
ring->mmio_base);
err = -ENOMEM;
goto err_dma_free;
}
ring->unaligned = bgmac_dma_unaligned(bgmac, ring,
BGMAC_DMA_RING_RX);
if (ring->unaligned)
ring->index_base = lower_32_bits(ring->dma_base);
else
ring->index_base = 0;
}
return 0;
err_dma_free:
bgmac_dma_free(bgmac);
return -ENOMEM;
}
static int bgmac_dma_init(struct bgmac *bgmac)
{
struct bgmac_dma_ring *ring;
for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
ring = &bgmac->tx_ring[i];
if (!ring->unaligned)
bgmac_dma_tx_enable(bgmac, ring);
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGLO,
lower_32_bits(ring->dma_base));
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGHI,
upper_32_bits(ring->dma_base));
if (ring->unaligned)
bgmac_dma_tx_enable(bgmac, ring);
ring->start = 0;
ring->end = 0; /* Points the slot that should *not* be read */
}
for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
ring = &bgmac->rx_ring[i];
if (!ring->unaligned)
bgmac_dma_rx_enable(bgmac, ring);
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO,
lower_32_bits(ring->dma_base));
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGHI,
upper_32_bits(ring->dma_base));
if (ring->unaligned)
bgmac_dma_rx_enable(bgmac, ring);
err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]);
if (err)
goto error;
bgmac_dma_rx_setup_desc(bgmac, ring, j);
return 0;
error:
bgmac_dma_cleanup(bgmac);
return err;
}
/**************************************************
* PHY ops
**************************************************/
static u16 bgmac_phy_read(struct bgmac *bgmac, u8 phyaddr, u8 reg)
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
{
struct bcma_device *core;
u16 phy_access_addr;
u16 phy_ctl_addr;
u32 tmp;
BUILD_BUG_ON(BGMAC_PA_DATA_MASK != BCMA_GMAC_CMN_PA_DATA_MASK);
BUILD_BUG_ON(BGMAC_PA_ADDR_MASK != BCMA_GMAC_CMN_PA_ADDR_MASK);
BUILD_BUG_ON(BGMAC_PA_ADDR_SHIFT != BCMA_GMAC_CMN_PA_ADDR_SHIFT);
BUILD_BUG_ON(BGMAC_PA_REG_MASK != BCMA_GMAC_CMN_PA_REG_MASK);
BUILD_BUG_ON(BGMAC_PA_REG_SHIFT != BCMA_GMAC_CMN_PA_REG_SHIFT);
BUILD_BUG_ON(BGMAC_PA_WRITE != BCMA_GMAC_CMN_PA_WRITE);
BUILD_BUG_ON(BGMAC_PA_START != BCMA_GMAC_CMN_PA_START);
BUILD_BUG_ON(BGMAC_PC_EPA_MASK != BCMA_GMAC_CMN_PC_EPA_MASK);
BUILD_BUG_ON(BGMAC_PC_MCT_MASK != BCMA_GMAC_CMN_PC_MCT_MASK);
BUILD_BUG_ON(BGMAC_PC_MCT_SHIFT != BCMA_GMAC_CMN_PC_MCT_SHIFT);
BUILD_BUG_ON(BGMAC_PC_MTE != BCMA_GMAC_CMN_PC_MTE);
if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
core = bgmac->core->bus->drv_gmac_cmn.core;
phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
} else {
core = bgmac->core;
phy_access_addr = BGMAC_PHY_ACCESS;
phy_ctl_addr = BGMAC_PHY_CNTL;
}
tmp = bcma_read32(core, phy_ctl_addr);
tmp &= ~BGMAC_PC_EPA_MASK;
tmp |= phyaddr;
bcma_write32(core, phy_ctl_addr, tmp);
tmp = BGMAC_PA_START;
tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
tmp |= reg << BGMAC_PA_REG_SHIFT;
bcma_write32(core, phy_access_addr, tmp);
if (!bgmac_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000)) {
bgmac_err(bgmac, "Reading PHY %d register 0x%X failed\n",
phyaddr, reg);
return 0xffff;
}
return bcma_read32(core, phy_access_addr) & BGMAC_PA_DATA_MASK;
}
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphywr */
static int bgmac_phy_write(struct bgmac *bgmac, u8 phyaddr, u8 reg, u16 value)
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
{
struct bcma_device *core;
u16 phy_access_addr;
u16 phy_ctl_addr;
u32 tmp;
if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
core = bgmac->core->bus->drv_gmac_cmn.core;
phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
} else {
core = bgmac->core;
phy_access_addr = BGMAC_PHY_ACCESS;
phy_ctl_addr = BGMAC_PHY_CNTL;
}
tmp = bcma_read32(core, phy_ctl_addr);
tmp &= ~BGMAC_PC_EPA_MASK;
tmp |= phyaddr;
bcma_write32(core, phy_ctl_addr, tmp);
bgmac_write(bgmac, BGMAC_INT_STATUS, BGMAC_IS_MDIO);
if (bgmac_read(bgmac, BGMAC_INT_STATUS) & BGMAC_IS_MDIO)
bgmac_warn(bgmac, "Error setting MDIO int\n");
tmp = BGMAC_PA_START;
tmp |= BGMAC_PA_WRITE;
tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
tmp |= reg << BGMAC_PA_REG_SHIFT;
tmp |= value;
bcma_write32(core, phy_access_addr, tmp);
if (!bgmac_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000)) {
bgmac_err(bgmac, "Writing to PHY %d register 0x%X failed\n",
phyaddr, reg);
return -ETIMEDOUT;
}
return 0;
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
}
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyinit */
static void bgmac_phy_init(struct bgmac *bgmac)
{
struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo;
struct bcma_drv_cc *cc = &bgmac->core->bus->drv_cc;
u8 i;
if (ci->id == BCMA_CHIP_ID_BCM5356) {
for (i = 0; i < 5; i++) {
bgmac_phy_write(bgmac, i, 0x1f, 0x008b);
bgmac_phy_write(bgmac, i, 0x15, 0x0100);
bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
bgmac_phy_write(bgmac, i, 0x12, 0x2aaa);
bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
}
}
if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg != 10) ||
(ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg != 10) ||
(ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg != 9)) {
bcma_chipco_chipctl_maskset(cc, 2, ~0xc0000000, 0);
bcma_chipco_chipctl_maskset(cc, 4, ~0x80000000, 0);
for (i = 0; i < 5; i++) {
bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
bgmac_phy_write(bgmac, i, 0x16, 0x5284);
bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
bgmac_phy_write(bgmac, i, 0x17, 0x0010);
bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
bgmac_phy_write(bgmac, i, 0x16, 0x5296);
bgmac_phy_write(bgmac, i, 0x17, 0x1073);
bgmac_phy_write(bgmac, i, 0x17, 0x9073);
bgmac_phy_write(bgmac, i, 0x16, 0x52b6);
bgmac_phy_write(bgmac, i, 0x17, 0x9273);
bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
}
}
}
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyreset */
static void bgmac_phy_reset(struct bgmac *bgmac)
{
if (bgmac->phyaddr == BGMAC_PHY_NOREGS)
return;
bgmac_phy_write(bgmac, bgmac->phyaddr, MII_BMCR, BMCR_RESET);
if (bgmac_phy_read(bgmac, bgmac->phyaddr, MII_BMCR) & BMCR_RESET)
bgmac_err(bgmac, "PHY reset failed\n");
bgmac_phy_init(bgmac);
}
/**************************************************
* Chip ops
**************************************************/
/* TODO: can we just drop @force? Can we don't reset MAC at all if there is
* nothing to change? Try if after stabilizng driver.
*/
static void bgmac_cmdcfg_maskset(struct bgmac *bgmac, u32 mask, u32 set,
bool force)
{
u32 cmdcfg = bgmac_read(bgmac, BGMAC_CMDCFG);
u32 new_val = (cmdcfg & mask) | set;
bgmac_set(bgmac, BGMAC_CMDCFG, BGMAC_CMDCFG_SR(bgmac->core->id.rev));
udelay(2);
if (new_val != cmdcfg || force)
bgmac_write(bgmac, BGMAC_CMDCFG, new_val);
bgmac_mask(bgmac, BGMAC_CMDCFG, ~BGMAC_CMDCFG_SR(bgmac->core->id.rev));
static void bgmac_write_mac_address(struct bgmac *bgmac, u8 *addr)
{
u32 tmp;
tmp = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
bgmac_write(bgmac, BGMAC_MACADDR_HIGH, tmp);
tmp = (addr[4] << 8) | addr[5];
bgmac_write(bgmac, BGMAC_MACADDR_LOW, tmp);
}
static void bgmac_set_rx_mode(struct net_device *net_dev)
{
struct bgmac *bgmac = netdev_priv(net_dev);
if (net_dev->flags & IFF_PROMISC)
bgmac_cmdcfg_maskset(bgmac, ~0, BGMAC_CMDCFG_PROM, true);
bgmac_cmdcfg_maskset(bgmac, ~BGMAC_CMDCFG_PROM, 0, true);
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
#if 0 /* We don't use that regs yet */
static void bgmac_chip_stats_update(struct bgmac *bgmac)
{
int i;
if (bgmac->core->id.id != BCMA_CORE_4706_MAC_GBIT) {
for (i = 0; i < BGMAC_NUM_MIB_TX_REGS; i++)
bgmac->mib_tx_regs[i] =
bgmac_read(bgmac,
BGMAC_TX_GOOD_OCTETS + (i * 4));
for (i = 0; i < BGMAC_NUM_MIB_RX_REGS; i++)
bgmac->mib_rx_regs[i] =
bgmac_read(bgmac,
BGMAC_RX_GOOD_OCTETS + (i * 4));
}
/* TODO: what else? how to handle BCM4706? Specs are needed */
}
#endif
static void bgmac_clear_mib(struct bgmac *bgmac)
{
int i;
if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT)
return;
bgmac_set(bgmac, BGMAC_DEV_CTL, BGMAC_DC_MROR);
for (i = 0; i < BGMAC_NUM_MIB_TX_REGS; i++)
bgmac_read(bgmac, BGMAC_TX_GOOD_OCTETS + (i * 4));
for (i = 0; i < BGMAC_NUM_MIB_RX_REGS; i++)
bgmac_read(bgmac, BGMAC_RX_GOOD_OCTETS + (i * 4));
}
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_speed */
static void bgmac_mac_speed(struct bgmac *bgmac)
{
u32 mask = ~(BGMAC_CMDCFG_ES_MASK | BGMAC_CMDCFG_HD);
u32 set = 0;
switch (bgmac->mac_speed) {
case SPEED_10:
break;
case SPEED_100:
break;
case SPEED_1000:
set |= BGMAC_CMDCFG_ES_1000;
case SPEED_2500:
set |= BGMAC_CMDCFG_ES_2500;
break;
default:
bgmac_err(bgmac, "Unsupported speed: %d\n", bgmac->mac_speed);