diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/Kconfig | 2 | ||||
-rw-r--r-- | drivers/net/ll_temac.h | 14 | ||||
-rw-r--r-- | drivers/net/ll_temac_main.c | 137 |
3 files changed, 38 insertions, 115 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index dbd26f99215..49c372a5e0b 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2435,8 +2435,8 @@ config MV643XX_ETH config XILINX_LL_TEMAC tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver" - depends on PPC || MICROBLAZE select PHYLIB + depends on PPC_DCR_NATIVE help This driver supports the Xilinx 10/100/1000 LocalLink TEMAC core used in Xilinx Spartan and Virtex FPGAs diff --git a/drivers/net/ll_temac.h b/drivers/net/ll_temac.h index c03358434ac..1af66a1e691 100644 --- a/drivers/net/ll_temac.h +++ b/drivers/net/ll_temac.h @@ -5,11 +5,8 @@ #include <linux/netdevice.h> #include <linux/of.h> #include <linux/spinlock.h> - -#ifdef CONFIG_PPC_DCR #include <asm/dcr.h> #include <asm/dcr-regs.h> -#endif /* packet size info */ #define XTE_HDR_SIZE 14 /* size of Ethernet header */ @@ -293,6 +290,9 @@ This option defaults to enabled (set) */ #define TX_CONTROL_CALC_CSUM_MASK 1 +#define XTE_ALIGN 32 +#define BUFFER_ALIGN(adr) ((XTE_ALIGN - ((u32) adr)) % XTE_ALIGN) + #define MULTICAST_CAM_TABLE_NUM 4 /* TX/RX CURDESC_PTR points to first descriptor */ @@ -335,15 +335,9 @@ struct temac_local { struct mii_bus *mii_bus; /* MII bus reference */ int mdio_irqs[PHY_MAX_ADDR]; /* IRQs table for MDIO bus */ - /* IO registers, dma functions and IRQs */ + /* IO registers and IRQs */ void __iomem *regs; - void __iomem *sdma_regs; -#ifdef CONFIG_PPC_DCR dcr_host_t sdma_dcrs; -#endif - u32 (*dma_in)(struct temac_local *, int); - void (*dma_out)(struct temac_local *, int, u32); - int tx_irq; int rx_irq; int emac_num; diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index b6edb2fd0a8..30474d6b15c 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -20,6 +20,9 @@ * or rx, so this should be okay. * * TODO: + * - Fix driver to work on more than just Virtex5. Right now the driver + * assumes that the locallink DMA registers are accessed via DCR + * instructions. * - Factor out locallink DMA code into separate driver * - Fix multicast assignment. * - Fix support for hardware checksumming. @@ -112,86 +115,17 @@ void temac_indirect_out32(struct temac_local *lp, int reg, u32 value) temac_iow(lp, XTE_CTL0_OFFSET, CNTLREG_WRITE_ENABLE_MASK | reg); } -/** - * temac_dma_in32 - Memory mapped DMA read, this function expects a - * register input that is based on DCR word addresses which - * are then converted to memory mapped byte addresses - */ static u32 temac_dma_in32(struct temac_local *lp, int reg) { - return in_be32((u32 *)(lp->sdma_regs + (reg << 2))); -} - -/** - * temac_dma_out32 - Memory mapped DMA read, this function expects a - * register input that is based on DCR word addresses which - * are then converted to memory mapped byte addresses - */ -static void temac_dma_out32(struct temac_local *lp, int reg, u32 value) -{ - out_be32((u32 *)(lp->sdma_regs + (reg << 2)), value); -} - -/* DMA register access functions can be DCR based or memory mapped. - * The PowerPC 440 is DCR based, the PowerPC 405 and MicroBlaze are both - * memory mapped. - */ -#ifdef CONFIG_PPC_DCR - -/** - * temac_dma_dcr_in32 - DCR based DMA read - */ -static u32 temac_dma_dcr_in(struct temac_local *lp, int reg) -{ return dcr_read(lp->sdma_dcrs, reg); } -/** - * temac_dma_dcr_out32 - DCR based DMA write - */ -static void temac_dma_dcr_out(struct temac_local *lp, int reg, u32 value) +static void temac_dma_out32(struct temac_local *lp, int reg, u32 value) { dcr_write(lp->sdma_dcrs, reg, value); } /** - * temac_dcr_setup - If the DMA is DCR based, then setup the address and - * I/O functions - */ -static int temac_dcr_setup(struct temac_local *lp, struct of_device *op, - struct device_node *np) -{ - unsigned int dcrs; - - /* setup the dcr address mapping if it's in the device tree */ - - dcrs = dcr_resource_start(np, 0); - if (dcrs != 0) { - lp->sdma_dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0)); - lp->dma_in = temac_dma_dcr_in; - lp->dma_out = temac_dma_dcr_out; - dev_dbg(&op->dev, "DCR base: %x\n", dcrs); - return 0; - } - /* no DCR in the device tree, indicate a failure */ - return -1; -} - -#else - -/* - * temac_dcr_setup - This is a stub for when DCR is not supported, - * such as with MicroBlaze - */ -static int temac_dcr_setup(struct temac_local *lp, struct of_device *op, - struct device_node *np) -{ - return -1; -} - -#endif - -/** * temac_dma_bd_init - Setup buffer descriptor rings */ static int temac_dma_bd_init(struct net_device *ndev) @@ -221,14 +155,14 @@ static int temac_dma_bd_init(struct net_device *ndev) lp->rx_bd_v[i].next = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * ((i + 1) % RX_BD_NUM); - skb = netdev_alloc_skb_ip_align(ndev, - XTE_MAX_JUMBO_FRAME_SIZE); - + skb = alloc_skb(XTE_MAX_JUMBO_FRAME_SIZE + + XTE_ALIGN, GFP_ATOMIC); if (skb == 0) { dev_err(&ndev->dev, "alloc_skb error %d\n", i); return -1; } lp->rx_skb[i] = skb; + skb_reserve(skb, BUFFER_ALIGN(skb->data)); /* returns physical address of skb->data */ lp->rx_bd_v[i].phys = dma_map_single(ndev->dev.parent, skb->data, @@ -238,23 +172,23 @@ static int temac_dma_bd_init(struct net_device *ndev) lp->rx_bd_v[i].app0 = STS_CTRL_APP0_IRQONEND; } - lp->dma_out(lp, TX_CHNL_CTRL, 0x10220400 | + temac_dma_out32(lp, TX_CHNL_CTRL, 0x10220400 | CHNL_CTRL_IRQ_EN | CHNL_CTRL_IRQ_DLY_EN | CHNL_CTRL_IRQ_COAL_EN); /* 0x10220483 */ /* 0x00100483 */ - lp->dma_out(lp, RX_CHNL_CTRL, 0xff010000 | + temac_dma_out32(lp, RX_CHNL_CTRL, 0xff010000 | CHNL_CTRL_IRQ_EN | CHNL_CTRL_IRQ_DLY_EN | CHNL_CTRL_IRQ_COAL_EN | CHNL_CTRL_IRQ_IOE); /* 0xff010283 */ - lp->dma_out(lp, RX_CURDESC_PTR, lp->rx_bd_p); - lp->dma_out(lp, RX_TAILDESC_PTR, + temac_dma_out32(lp, RX_CURDESC_PTR, lp->rx_bd_p); + temac_dma_out32(lp, RX_TAILDESC_PTR, lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1))); - lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p); + temac_dma_out32(lp, TX_CURDESC_PTR, lp->tx_bd_p); return 0; } @@ -492,9 +426,9 @@ static void temac_device_reset(struct net_device *ndev) temac_indirect_out32(lp, XTE_RXC1_OFFSET, val & ~XTE_RXC1_RXEN_MASK); /* Reset Local Link (DMA) */ - lp->dma_out(lp, DMA_CONTROL_REG, DMA_CONTROL_RST); + temac_dma_out32(lp, DMA_CONTROL_REG, DMA_CONTROL_RST); timeout = 1000; - while (lp->dma_in(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) { + while (temac_dma_in32(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) { udelay(1); if (--timeout == 0) { dev_err(&ndev->dev, @@ -502,7 +436,7 @@ static void temac_device_reset(struct net_device *ndev) break; } } - lp->dma_out(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE); + temac_dma_out32(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE); temac_dma_bd_init(ndev); @@ -663,7 +597,7 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) lp->tx_bd_tail = 0; /* Kick off the transfer */ - lp->dma_out(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */ + temac_dma_out32(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */ return NETDEV_TX_OK; } @@ -705,15 +639,16 @@ static void ll_temac_recv(struct net_device *ndev) ndev->stats.rx_packets++; ndev->stats.rx_bytes += length; - new_skb = netdev_alloc_skb_ip_align(ndev, - XTE_MAX_JUMBO_FRAME_SIZE); - + new_skb = alloc_skb(XTE_MAX_JUMBO_FRAME_SIZE + XTE_ALIGN, + GFP_ATOMIC); if (new_skb == 0) { dev_err(&ndev->dev, "no memory for new sk_buff\n"); spin_unlock_irqrestore(&lp->rx_lock, flags); return; } + skb_reserve(new_skb, BUFFER_ALIGN(new_skb->data)); + cur_p->app0 = STS_CTRL_APP0_IRQONEND; cur_p->phys = dma_map_single(ndev->dev.parent, new_skb->data, XTE_MAX_JUMBO_FRAME_SIZE, @@ -728,7 +663,7 @@ static void ll_temac_recv(struct net_device *ndev) cur_p = &lp->rx_bd_v[lp->rx_bd_ci]; bdstat = cur_p->app0; } - lp->dma_out(lp, RX_TAILDESC_PTR, tail_p); + temac_dma_out32(lp, RX_TAILDESC_PTR, tail_p); spin_unlock_irqrestore(&lp->rx_lock, flags); } @@ -739,8 +674,8 @@ static irqreturn_t ll_temac_tx_irq(int irq, void *_ndev) struct temac_local *lp = netdev_priv(ndev); unsigned int status; - status = lp->dma_in(lp, TX_IRQ_REG); - lp->dma_out(lp, TX_IRQ_REG, status); + status = temac_dma_in32(lp, TX_IRQ_REG); + temac_dma_out32(lp, TX_IRQ_REG, status); if (status & (IRQ_COAL | IRQ_DLY)) temac_start_xmit_done(lp->ndev); @@ -757,8 +692,8 @@ static irqreturn_t ll_temac_rx_irq(int irq, void *_ndev) unsigned int status; /* Read and clear the status registers */ - status = lp->dma_in(lp, RX_IRQ_REG); - lp->dma_out(lp, RX_IRQ_REG, status); + status = temac_dma_in32(lp, RX_IRQ_REG); + temac_dma_out32(lp, RX_IRQ_REG, status); if (status & (IRQ_COAL | IRQ_DLY)) ll_temac_recv(lp->ndev); @@ -859,7 +794,7 @@ static ssize_t temac_show_llink_regs(struct device *dev, int i, len = 0; for (i = 0; i < 0x11; i++) - len += sprintf(buf + len, "%.8x%s", lp->dma_in(lp, i), + len += sprintf(buf + len, "%.8x%s", temac_dma_in32(lp, i), (i % 8) == 7 ? "\n" : " "); len += sprintf(buf + len, "\n"); @@ -885,6 +820,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match) struct net_device *ndev; const void *addr; int size, rc = 0; + unsigned int dcrs; /* Init network device structure */ ndev = alloc_etherdev(sizeof(*lp)); @@ -934,20 +870,13 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match) goto nodev; } - /* Setup the DMA register accesses, could be DCR or memory mapped */ - if (temac_dcr_setup(lp, op, np)) { - - /* no DCR in the device tree, try non-DCR */ - lp->sdma_regs = of_iomap(np, 0); - if (lp->sdma_regs) { - lp->dma_in = temac_dma_in32; - lp->dma_out = temac_dma_out32; - dev_dbg(&op->dev, "MEM base: %p\n", lp->sdma_regs); - } else { - dev_err(&op->dev, "unable to map DMA registers\n"); - goto nodev; - } + dcrs = dcr_resource_start(np, 0); + if (dcrs == 0) { + dev_err(&op->dev, "could not get DMA register address\n"); + goto nodev; } + lp->sdma_dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0)); + dev_dbg(&op->dev, "DCR base: %x\n", dcrs); lp->rx_irq = irq_of_parse_and_map(np, 0); lp->tx_irq = irq_of_parse_and_map(np, 1); |