X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=drivers%2Fnet%2Fcpsw.c;h=30f1137c735a079637889a53fbf5b00d6a91459a;hb=772cc6d9f70d9c77e4ea748caf707c070c6619a3;hp=db04795dfc97c55db137d5af2a92bd31364ce43b;hpb=1199c377cf14c240b903e351ab02b3b2cd3800c6;p=karo-tx-uboot.git diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index db04795dfc..30f1137c73 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -20,10 +20,10 @@ #include #include #include -#include #include #include #include +#include #define BITMASK(bits) (BIT(bits) - 1) #define PHY_REG_MASK 0x1f @@ -89,8 +89,8 @@ struct cpsw_mdio_regs { #define USERACCESS_GO BIT(31) #define USERACCESS_WRITE BIT(30) #define USERACCESS_ACK BIT(29) -#define USERACCESS_READ (0) -#define USERACCESS_DATA (0xffff) +#define USERACCESS_READ 0 +#define USERACCESS_DATA 0xffff } user[0]; }; @@ -188,19 +188,22 @@ struct cpdma_desc { u32 hw_buffer; u32 hw_len; u32 hw_mode; - /* software fields */ - u32 sw_buffer; - u32 sw_len; +} __attribute__((aligned(CONFIG_SYS_CACHELINE_SIZE))); + +struct cpsw_desc { + void *sw_buffer; + struct cpsw_desc *next; + struct cpdma_desc *dma_desc; }; struct cpdma_chan { - struct cpdma_desc *head, *tail; + struct cpsw_desc *head, *tail; void *hdp, *cp, *rxfree; }; -#define desc_write(desc, fld, val) __raw_writel((u32)(val), &(desc)->fld) -#define desc_read(desc, fld) __raw_readl(&(desc)->fld) -#define desc_read_ptr(desc, fld) ((void *)__raw_readl(&(desc)->fld)) +#define desc_write(desc, fld, val) __raw_writel((u32)(val), &(desc)->dma_desc->fld) +#define desc_read(desc, fld) __raw_readl(&(desc)->dma_desc->fld) +#define desc_read_ptr(desc, fld) ((void *)__raw_readl(&(desc)->dma_desc->fld)) #define chan_write(chan, fld, val) __raw_writel((u32)(val), (chan)->fld) #define chan_read(chan, fld) __raw_readl((chan)->fld) @@ -208,11 +211,11 @@ struct cpdma_chan { #define for_each_slave(slave, priv) \ for (slave = (priv)->slaves; slave != (priv)->slaves + \ - (priv)->data.slaves; slave++) + (priv)->data->slaves; slave++) struct cpsw_priv { struct eth_device *dev; - struct cpsw_platform_data data; + struct cpsw_platform_data *data; int host_port; struct cpsw_regs *regs; @@ -220,8 +223,8 @@ struct cpsw_priv { struct cpsw_host_regs *host_port_regs; void *ale_regs; - struct cpdma_desc *descs; - struct cpdma_desc *desc_free; + struct cpsw_desc descs[NUM_DESCS]; + struct cpsw_desc *desc_free; struct cpdma_chan rx_chan, tx_chan; struct cpsw_slave *slaves; @@ -317,7 +320,7 @@ static int cpsw_ale_match_addr(struct cpsw_priv *priv, u8* addr) u32 ale_entry[ALE_ENTRY_WORDS]; int type, idx; - for (idx = 0; idx < priv->data.ale_entries; idx++) { + for (idx = 0; idx < priv->data->ale_entries; idx++) { u8 entry_addr[6]; cpsw_ale_read(priv, idx, ale_entry); @@ -336,7 +339,7 @@ static int cpsw_ale_match_free(struct cpsw_priv *priv) u32 ale_entry[ALE_ENTRY_WORDS]; int type, idx; - for (idx = 0; idx < priv->data.ale_entries; idx++) { + for (idx = 0; idx < priv->data->ale_entries; idx++) { cpsw_ale_read(priv, idx, ale_entry); type = cpsw_ale_get_entry_type(ale_entry); if (type == ALE_TYPE_FREE) @@ -350,7 +353,7 @@ static int cpsw_ale_find_ageable(struct cpsw_priv *priv) u32 ale_entry[ALE_ENTRY_WORDS]; int type, idx; - for (idx = 0; idx < priv->data.ale_entries; idx++) { + for (idx = 0; idx < priv->data->ale_entries; idx++) { cpsw_ale_read(priv, idx, ale_entry); type = cpsw_ale_get_entry_type(ale_entry); if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR) @@ -449,17 +452,17 @@ static struct cpsw_mdio_regs *mdio_regs; /* wait until hardware is ready for another user access */ static inline u32 wait_for_user_access(void) { - u32 reg = 0; int timeout = MDIO_TIMEOUT; + u32 reg; - while (timeout-- && - ((reg = __raw_readl(&mdio_regs->user[0].access)) & USERACCESS_GO)) - udelay(10); - - if (timeout == -1) { - printf("wait_for_user_access Timeout\n"); - return -ETIMEDOUT; + while ((reg = __raw_readl(&mdio_regs->user[0].access)) & USERACCESS_GO) { + udelay(1000); + if (--timeout <= 0) { + printf("TIMEOUT waiting for USERACCESS_GO\n"); + break; + } } + return reg; } @@ -468,12 +471,13 @@ static inline void wait_for_idle(void) { int timeout = MDIO_TIMEOUT; - while (timeout-- && - ((__raw_readl(&mdio_regs->control) & CONTROL_IDLE) == 0)) - udelay(10); - - if (timeout == -1) - printf("wait_for_idle Timeout\n"); + while ((__raw_readl(&mdio_regs->control) & CONTROL_IDLE) == 0) { + if (--timeout <= 0) { + printf("TIMEOUT waiting for state machine idle\n"); + break; + } + udelay(1000); + } } static int cpsw_mdio_read(struct mii_dev *bus, int phy_id, @@ -485,11 +489,16 @@ static int cpsw_mdio_read(struct mii_dev *bus, int phy_id, if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK) return -EINVAL; - wait_for_user_access(); + if (wait_for_user_access() & USERACCESS_GO) + /* promote error from previous access */ + return -ETIME; + reg = (USERACCESS_GO | USERACCESS_READ | (phy_reg << 21) | (phy_id << 16)); __raw_writel(reg, &mdio_regs->user[0].access); reg = wait_for_user_access(); + if (reg & USERACCESS_GO) + return -ETIME; data = (reg & USERACCESS_ACK) ? (reg & USERACCESS_DATA) : -1; return data; @@ -503,11 +512,15 @@ static int cpsw_mdio_write(struct mii_dev *bus, int phy_id, int dev_addr, if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK) return -EINVAL; - wait_for_user_access(); + if (wait_for_user_access() & USERACCESS_GO) + /* promote error from previous access */ + return -ETIME; + reg = (USERACCESS_GO | USERACCESS_WRITE | (phy_reg << 21) | (phy_id << 16) | (data & USERACCESS_DATA)); __raw_writel(reg, &mdio_regs->user[0].access); - wait_for_user_access(); + if (wait_for_user_access() & USERACCESS_GO) + return -ETIME; return 0; } @@ -541,9 +554,12 @@ static void cpsw_mdio_init(char *name, u32 mdio_base, u32 div) /* Set a self-clearing bit in a register, and wait for it to clear */ static inline void setbit_and_wait_for_clear32(void *addr) { + int loops = 0; + __raw_writel(CLEAR_BIT, addr); while (__raw_readl(addr) & CLEAR_BIT) - ; + loops++; + debug("%s: reset finished after %u loops\n", __func__, loops); } #define mac_hi(mac) (((mac)[0] << 0) | ((mac)[1] << 8) | \ @@ -557,24 +573,32 @@ static void cpsw_set_slave_mac(struct cpsw_slave *slave, __raw_writel(mac_lo(priv->dev->enetaddr), &slave->regs->sa_lo); } +#define NUM_TRIES 50 static void cpsw_slave_update_link(struct cpsw_slave *slave, struct cpsw_priv *priv, int *link) { struct phy_device *phy = priv->phydev; u32 mac_control = 0; - - phy_startup(phy); - *link = phy->link; - - if (*link) { /* link up */ - mac_control = priv->data.mac_control; - if (phy->speed == 1000) - mac_control |= GIGABITEN; - if (phy->duplex == DUPLEX_FULL) - mac_control |= FULLDUPLEXEN; - if (phy->speed == 100) - mac_control |= MIIEN; - } + int retries = NUM_TRIES; + + do { + phy_startup(phy); + *link = phy->link; + + if (*link) { /* link up */ + mac_control = priv->data->mac_control; + if (phy->speed == 1000) + mac_control |= GIGABITEN; + if (phy->duplex == DUPLEX_FULL) + mac_control |= FULLDUPLEXEN; + if (phy->speed == 100) + mac_control |= MIIEN; + } else { + udelay(10000); + } + } while (!*link && retries-- > 0); + debug("%s: mac_control: %08x -> %08x after %u loops\n", __func__, + slave->mac_control, mac_control, NUM_TRIES - retries); if (mac_control == slave->mac_control) return; @@ -602,7 +626,7 @@ static int cpsw_update_link(struct cpsw_priv *priv) return link; } -static inline u32 cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num) +static inline u32 cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num) { if (priv->host_port == 0) return slave_num + 1; @@ -614,6 +638,7 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv) { u32 slave_port; + debug("%s\n", __func__); setbit_and_wait_for_clear32(&slave->sliver->soft_reset); /* setup priority mapping */ @@ -633,19 +658,33 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv) cpsw_ale_add_mcast(priv, NetBcastAddr, 1 << slave_port); } -static struct cpdma_desc *cpdma_desc_alloc(struct cpsw_priv *priv) +static void cpdma_desc_get(struct cpsw_desc *desc) +{ + invalidate_dcache_range((u32)desc->dma_desc, (u32)(&desc->dma_desc[1])); +} + +static void cpdma_desc_put(struct cpsw_desc *desc) +{ + flush_dcache_range((u32)desc->dma_desc, (u32)(&desc->dma_desc[1])); +} + +static struct cpsw_desc *cpdma_desc_alloc(struct cpsw_priv *priv) { - struct cpdma_desc *desc = priv->desc_free; + struct cpsw_desc *desc = priv->desc_free; - if (desc) - priv->desc_free = desc_read_ptr(desc, hw_next); + if (desc) { + cpdma_desc_get(desc); + priv->desc_free = desc->next; + } return desc; } -static void cpdma_desc_free(struct cpsw_priv *priv, struct cpdma_desc *desc) +static void cpdma_desc_free(struct cpsw_priv *priv, struct cpsw_desc *desc) { if (desc) { - desc_write(desc, hw_next, priv->desc_free); + desc_write(desc, hw_next, priv->desc_free->dma_desc); + cpdma_desc_put(desc); + desc->next = priv->desc_free; priv->desc_free = desc; } } @@ -653,76 +692,89 @@ static void cpdma_desc_free(struct cpsw_priv *priv, struct cpdma_desc *desc) static int cpdma_submit(struct cpsw_priv *priv, struct cpdma_chan *chan, void *buffer, int len) { - struct cpdma_desc *desc, *prev; + struct cpsw_desc *desc, *prev; u32 mode; + if (!buffer) { + printf("ERROR: %s() NULL buffer\n", __func__); + return -EINVAL; + } + + flush_dcache_range((u32)buffer, (u32)buffer + len); + desc = cpdma_desc_alloc(priv); if (!desc) return -ENOMEM; + debug("%s@%d: %cX desc %p DMA %p\n", __func__, __LINE__, + chan == &priv->rx_chan ? 'R' : 'T', desc, desc->dma_desc); if (len < PKT_MIN) len = PKT_MIN; mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP; + desc->next = NULL; desc_write(desc, hw_next, 0); desc_write(desc, hw_buffer, buffer); desc_write(desc, hw_len, len); desc_write(desc, hw_mode, mode | len); - desc_write(desc, sw_buffer, buffer); - desc_write(desc, sw_len, len); + desc->sw_buffer = buffer; + + cpdma_desc_put(desc); if (!chan->head) { /* simple case - first packet enqueued */ chan->head = desc; chan->tail = desc; - chan_write(chan, hdp, desc); + chan_write(chan, hdp, desc->dma_desc); goto done; } /* not the first packet - enqueue at the tail */ prev = chan->tail; - desc_write(prev, hw_next, desc); + + prev->next = desc; + cpdma_desc_get(prev); + desc_write(prev, hw_next, desc->dma_desc); + cpdma_desc_put(prev); + chan->tail = desc; /* next check if EOQ has been triggered already */ if (desc_read(prev, hw_mode) & CPDMA_DESC_EOQ) - chan_write(chan, hdp, desc); + chan_write(chan, hdp, desc->dma_desc); done: if (chan->rxfree) chan_write(chan, rxfree, 1); + debug("%s@%d\n", __func__, __LINE__); return 0; } static int cpdma_process(struct cpsw_priv *priv, struct cpdma_chan *chan, void **buffer, int *len) { - struct cpdma_desc *desc = chan->head; + struct cpsw_desc *desc = chan->head; u32 status; if (!desc) return -ENOENT; + cpdma_desc_get(desc); + status = desc_read(desc, hw_mode); + if (status & CPDMA_DESC_OWNER) + return -EBUSY; if (len) *len = status & 0x7ff; if (buffer) - *buffer = desc_read_ptr(desc, sw_buffer); + *buffer = desc->sw_buffer; + debug("%s@%d: buffer=%p\n", __func__, __LINE__, desc->sw_buffer); - if (status & CPDMA_DESC_OWNER) { - if (chan_read(chan, hdp) == 0) { - if (desc_read(desc, hw_mode) & CPDMA_DESC_OWNER) - chan_write(chan, hdp, desc); - } - - return -EBUSY; - } - - chan->head = desc_read_ptr(desc, hw_next); - chan_write(chan, cp, desc); + chan->head = desc->next; + chan_write(chan, cp, desc->dma_desc); cpdma_desc_free(priv, desc); return 0; @@ -734,6 +786,7 @@ static int cpsw_init(struct eth_device *dev, bd_t *bis) struct cpsw_slave *slave; int i, ret; + debug("%s\n", __func__); /* soft reset the controller and initialize priv */ setbit_and_wait_for_clear32(&priv->regs->soft_reset); @@ -765,60 +818,55 @@ static int cpsw_init(struct eth_device *dev, bd_t *bis) /* init descriptor pool */ for (i = 0; i < NUM_DESCS; i++) { + struct cpsw_desc *next_desc = (i < (NUM_DESCS - 1)) ? + &priv->descs[i + 1] : NULL; + + priv->descs[i].next = next_desc; desc_write(&priv->descs[i], hw_next, - (i == (NUM_DESCS - 1)) ? 0 : &priv->descs[i+1]); + next_desc ? next_desc->dma_desc : 0); + cpdma_desc_put(&priv->descs[i]); } priv->desc_free = &priv->descs[0]; /* initialize channels */ - if (priv->data.version == CPSW_CTRL_VERSION_2) { + if (priv->data->version == CPSW_CTRL_VERSION_2) { memset(&priv->rx_chan, 0, sizeof(struct cpdma_chan)); - priv->rx_chan.hdp = priv->dma_regs + CPDMA_RXHDP_VER2; - priv->rx_chan.cp = priv->dma_regs + CPDMA_RXCP_VER2; - priv->rx_chan.rxfree = priv->dma_regs + CPDMA_RXFREE; + priv->rx_chan.hdp = priv->dma_regs + CPDMA_RXHDP_VER2; + priv->rx_chan.cp = priv->dma_regs + CPDMA_RXCP_VER2; + priv->rx_chan.rxfree = priv->dma_regs + CPDMA_RXFREE; memset(&priv->tx_chan, 0, sizeof(struct cpdma_chan)); - priv->tx_chan.hdp = priv->dma_regs + CPDMA_TXHDP_VER2; - priv->tx_chan.cp = priv->dma_regs + CPDMA_TXCP_VER2; + priv->tx_chan.hdp = priv->dma_regs + CPDMA_TXHDP_VER2; + priv->tx_chan.cp = priv->dma_regs + CPDMA_TXCP_VER2; } else { memset(&priv->rx_chan, 0, sizeof(struct cpdma_chan)); - priv->rx_chan.hdp = priv->dma_regs + CPDMA_RXHDP_VER1; - priv->rx_chan.cp = priv->dma_regs + CPDMA_RXCP_VER1; - priv->rx_chan.rxfree = priv->dma_regs + CPDMA_RXFREE; + priv->rx_chan.hdp = priv->dma_regs + CPDMA_RXHDP_VER1; + priv->rx_chan.cp = priv->dma_regs + CPDMA_RXCP_VER1; + priv->rx_chan.rxfree = priv->dma_regs + CPDMA_RXFREE; memset(&priv->tx_chan, 0, sizeof(struct cpdma_chan)); - priv->tx_chan.hdp = priv->dma_regs + CPDMA_TXHDP_VER1; - priv->tx_chan.cp = priv->dma_regs + CPDMA_TXCP_VER1; + priv->tx_chan.hdp = priv->dma_regs + CPDMA_TXHDP_VER1; + priv->tx_chan.cp = priv->dma_regs + CPDMA_TXCP_VER1; } /* clear dma state */ setbit_and_wait_for_clear32(priv->dma_regs + CPDMA_SOFTRESET); - if (priv->data.version == CPSW_CTRL_VERSION_2) { - for (i = 0; i < priv->data.channels; i++) { - __raw_writel(0, priv->dma_regs + CPDMA_RXHDP_VER2 + 4 - * i); - __raw_writel(0, priv->dma_regs + CPDMA_RXFREE + 4 - * i); - __raw_writel(0, priv->dma_regs + CPDMA_RXCP_VER2 + 4 - * i); - __raw_writel(0, priv->dma_regs + CPDMA_TXHDP_VER2 + 4 - * i); - __raw_writel(0, priv->dma_regs + CPDMA_TXCP_VER2 + 4 - * i); + if (priv->data->version == CPSW_CTRL_VERSION_2) { + for (i = 0; i < priv->data->channels; i++) { + __raw_writel(0, priv->dma_regs + CPDMA_RXHDP_VER2 + 4 * i); + __raw_writel(0, priv->dma_regs + CPDMA_RXFREE + 4 * i); + __raw_writel(0, priv->dma_regs + CPDMA_RXCP_VER2 + 4 * i); + __raw_writel(0, priv->dma_regs + CPDMA_TXHDP_VER2 + 4 * i); + __raw_writel(0, priv->dma_regs + CPDMA_TXCP_VER2 + 4 * i); } } else { - for (i = 0; i < priv->data.channels; i++) { - __raw_writel(0, priv->dma_regs + CPDMA_RXHDP_VER1 + 4 - * i); - __raw_writel(0, priv->dma_regs + CPDMA_RXFREE + 4 - * i); - __raw_writel(0, priv->dma_regs + CPDMA_RXCP_VER1 + 4 - * i); - __raw_writel(0, priv->dma_regs + CPDMA_TXHDP_VER1 + 4 - * i); - __raw_writel(0, priv->dma_regs + CPDMA_TXCP_VER1 + 4 - * i); + for (i = 0; i < priv->data->channels; i++) { + __raw_writel(0, priv->dma_regs + CPDMA_RXHDP_VER1 + 4 * i); + __raw_writel(0, priv->dma_regs + CPDMA_RXFREE + 4 * i); + __raw_writel(0, priv->dma_regs + CPDMA_RXCP_VER1 + 4 * i); + __raw_writel(0, priv->dma_regs + CPDMA_TXHDP_VER1 + 4 * i); + __raw_writel(0, priv->dma_regs + CPDMA_TXCP_VER1 + 4 * i); } } @@ -836,7 +884,7 @@ static int cpsw_init(struct eth_device *dev, bd_t *bis) } } - return 0; + return ret; } static void cpsw_halt(struct eth_device *dev) @@ -852,31 +900,27 @@ static void cpsw_halt(struct eth_device *dev) /* clear dma state */ setbit_and_wait_for_clear32(priv->dma_regs + CPDMA_SOFTRESET); - priv->data.control(0); + debug("%s\n", __func__); + priv->data->control(0); } static int cpsw_send(struct eth_device *dev, void *packet, int length) { - struct cpsw_priv *priv = dev->priv; + struct cpsw_priv *priv = dev->priv; void *buffer; int len; - int timeout = CPDMA_TIMEOUT; - if (!cpsw_update_link(priv)) - return -EIO; + debug("%s@%d: sending packet %p..%p\n", __func__, __LINE__, + packet, packet + length - 1); - flush_dcache_range((unsigned long)packet, - (unsigned long)packet + length); + if (!priv->data->mac_control && !cpsw_update_link(priv)) { + printf("%s: Cannot send packet; link is down\n", __func__); + return -EIO; + } /* first reap completed packets */ - while (timeout-- && - (cpdma_process(priv, &priv->tx_chan, &buffer, &len) >= 0)) - ; - - if (timeout == -1) { - printf("cpdma_process timeout\n"); - return -ETIMEDOUT; - } + while (cpdma_process(priv, &priv->tx_chan, &buffer, &len) == 0) + /* NOP */; return cpdma_submit(priv, &priv->tx_chan, packet, length); } @@ -887,13 +931,14 @@ static int cpsw_recv(struct eth_device *dev) void *buffer; int len; - cpsw_update_link(priv); - - while (cpdma_process(priv, &priv->rx_chan, &buffer, &len) >= 0) { - invalidate_dcache_range((unsigned long)buffer, - (unsigned long)buffer + PKTSIZE_ALIGN); - NetReceive(buffer, len); - cpdma_submit(priv, &priv->rx_chan, buffer, PKTSIZE); + while (cpdma_process(priv, &priv->rx_chan, &buffer, &len) == 0) { + if (buffer) { + NetReceive(buffer, len); + cpdma_submit(priv, &priv->rx_chan, buffer, PKTSIZE); + } else { + printf("NULL buffer returned from cpdma_process\n"); + return -EIO; + } } return 0; @@ -903,7 +948,10 @@ static void cpsw_slave_setup(struct cpsw_slave *slave, int slave_num, struct cpsw_priv *priv) { void *regs = priv->regs; - struct cpsw_slave_data *data = priv->data.slave_data + slave_num; + struct cpsw_slave_data *data = priv->data->slave_data + slave_num; + + debug("%s@%d: slave[%d] %p\n", __func__, __LINE__, + slave_num, slave); slave->slave_num = slave_num; slave->data = data; slave->regs = regs + data->slave_reg_ofs; @@ -920,10 +968,27 @@ static int cpsw_phy_init(struct eth_device *dev, struct cpsw_slave *slave) SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full); - phydev = phy_connect(priv->bus, - CONFIG_PHY_ADDR, - dev, - slave->data->phy_if); + if (slave->data->phy_id < 0) { + u32 phy_addr; + + for (phy_addr = 0; phy_addr < 32; phy_addr++) { + debug("Trying to connect to PHY @ addr %02x\n", + phy_addr); + phydev = phy_connect(priv->bus, phy_addr, + dev, slave->data->phy_if); + if (phydev) + break; + } + } else { + phydev = phy_connect(priv->bus, + slave->data->phy_id, + dev, + slave->data->phy_if); + } + if (!phydev) { + printf("Failed to connect to PHY\n"); + return -EINVAL; + } phydev->supported &= supported; phydev->advertising = phydev->supported; @@ -931,7 +996,7 @@ static int cpsw_phy_init(struct eth_device *dev, struct cpsw_slave *slave) priv->phydev = phydev; phy_config(phydev); - return 1; + return 0; } int cpsw_register(struct cpsw_platform_data *data) @@ -940,6 +1005,10 @@ int cpsw_register(struct cpsw_platform_data *data) struct cpsw_slave *slave; void *regs = (void *)data->cpsw_base; struct eth_device *dev; + int i; + int idx = 0; + + debug("%s@%d\n", __func__, __LINE__); dev = calloc(sizeof(*dev), 1); if (!dev) @@ -951,25 +1020,39 @@ int cpsw_register(struct cpsw_platform_data *data) return -ENOMEM; } - priv->data = *data; + priv->data = data; priv->dev = dev; - priv->slaves = malloc(sizeof(struct cpsw_slave) * data->slaves); + priv->slaves = calloc(sizeof(struct cpsw_slave), data->slaves); if (!priv->slaves) { free(dev); free(priv); return -ENOMEM; } - priv->descs = (void *)CPDMA_RAM_ADDR; + for (i = 0; i < NUM_DESCS; i++) { + priv->descs[i].dma_desc = memalign(CONFIG_SYS_CACHELINE_SIZE, + sizeof(struct cpsw_desc) * NUM_DESCS); + if (!priv->descs[i].dma_desc) { + while (--i >= 0) { + free(priv->descs[i].dma_desc); + } + free(priv->slaves); + free(priv); + free(dev); + return -ENOMEM; + } + debug("DMA desc[%d] allocated @ %p desc_size %u\n", + i, priv->descs[i].dma_desc, + sizeof(*priv->descs[i].dma_desc)); + } + priv->host_port = data->host_port_num; priv->regs = regs; priv->host_port_regs = regs + data->host_port_reg_ofs; priv->dma_regs = regs + data->cpdma_reg_ofs; priv->ale_regs = regs + data->ale_reg_ofs; - int idx = 0; - for_each_slave(slave, priv) { cpsw_slave_setup(slave, idx, priv); idx = idx + 1;