diff options
Diffstat (limited to 'drivers/net/ll_temac_main.c')
| -rw-r--r-- | drivers/net/ll_temac_main.c | 137 | 
1 files changed, 104 insertions, 33 deletions
diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index 30474d6b15c..b6edb2fd0a8 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -20,9 +20,6 @@   *   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. @@ -115,17 +112,86 @@ 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 dcr_read(lp->sdma_dcrs, 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) +{  	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) @@ -155,14 +221,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 = alloc_skb(XTE_MAX_JUMBO_FRAME_SIZE -				+ XTE_ALIGN, GFP_ATOMIC); +		skb = netdev_alloc_skb_ip_align(ndev, +						XTE_MAX_JUMBO_FRAME_SIZE); +  		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, @@ -172,23 +238,23 @@ static int temac_dma_bd_init(struct net_device *ndev)  		lp->rx_bd_v[i].app0 = STS_CTRL_APP0_IRQONEND;  	} -	temac_dma_out32(lp, TX_CHNL_CTRL, 0x10220400 | +	lp->dma_out(lp, TX_CHNL_CTRL, 0x10220400 |  					  CHNL_CTRL_IRQ_EN |  					  CHNL_CTRL_IRQ_DLY_EN |  					  CHNL_CTRL_IRQ_COAL_EN);  	/* 0x10220483 */  	/* 0x00100483 */ -	temac_dma_out32(lp, RX_CHNL_CTRL, 0xff010000 | +	lp->dma_out(lp, RX_CHNL_CTRL, 0xff010000 |  					  CHNL_CTRL_IRQ_EN |  					  CHNL_CTRL_IRQ_DLY_EN |  					  CHNL_CTRL_IRQ_COAL_EN |  					  CHNL_CTRL_IRQ_IOE);  	/* 0xff010283 */ -	temac_dma_out32(lp, RX_CURDESC_PTR,  lp->rx_bd_p); -	temac_dma_out32(lp, RX_TAILDESC_PTR, +	lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p); +	lp->dma_out(lp, RX_TAILDESC_PTR,  		       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1))); -	temac_dma_out32(lp, TX_CURDESC_PTR, lp->tx_bd_p); +	lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);  	return 0;  } @@ -426,9 +492,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) */ -	temac_dma_out32(lp, DMA_CONTROL_REG, DMA_CONTROL_RST); +	lp->dma_out(lp, DMA_CONTROL_REG, DMA_CONTROL_RST);  	timeout = 1000; -	while (temac_dma_in32(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) { +	while (lp->dma_in(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) {  		udelay(1);  		if (--timeout == 0) {  			dev_err(&ndev->dev, @@ -436,7 +502,7 @@ static void temac_device_reset(struct net_device *ndev)  			break;  		}  	} -	temac_dma_out32(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE); +	lp->dma_out(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE);  	temac_dma_bd_init(ndev); @@ -597,7 +663,7 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)  		lp->tx_bd_tail = 0;  	/* Kick off the transfer */ -	temac_dma_out32(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */ +	lp->dma_out(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */  	return NETDEV_TX_OK;  } @@ -639,16 +705,15 @@ static void ll_temac_recv(struct net_device *ndev)  		ndev->stats.rx_packets++;  		ndev->stats.rx_bytes += length; -		new_skb = alloc_skb(XTE_MAX_JUMBO_FRAME_SIZE + XTE_ALIGN, -				GFP_ATOMIC); +		new_skb = netdev_alloc_skb_ip_align(ndev, +						XTE_MAX_JUMBO_FRAME_SIZE); +  		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, @@ -663,7 +728,7 @@ static void ll_temac_recv(struct net_device *ndev)  		cur_p = &lp->rx_bd_v[lp->rx_bd_ci];  		bdstat = cur_p->app0;  	} -	temac_dma_out32(lp, RX_TAILDESC_PTR, tail_p); +	lp->dma_out(lp, RX_TAILDESC_PTR, tail_p);  	spin_unlock_irqrestore(&lp->rx_lock, flags);  } @@ -674,8 +739,8 @@ static irqreturn_t ll_temac_tx_irq(int irq, void *_ndev)  	struct temac_local *lp = netdev_priv(ndev);  	unsigned int status; -	status = temac_dma_in32(lp, TX_IRQ_REG); -	temac_dma_out32(lp, TX_IRQ_REG, status); +	status = lp->dma_in(lp, TX_IRQ_REG); +	lp->dma_out(lp, TX_IRQ_REG, status);  	if (status & (IRQ_COAL | IRQ_DLY))  		temac_start_xmit_done(lp->ndev); @@ -692,8 +757,8 @@ static irqreturn_t ll_temac_rx_irq(int irq, void *_ndev)  	unsigned int status;  	/* Read and clear the status registers */ -	status = temac_dma_in32(lp, RX_IRQ_REG); -	temac_dma_out32(lp, RX_IRQ_REG, status); +	status = lp->dma_in(lp, RX_IRQ_REG); +	lp->dma_out(lp, RX_IRQ_REG, status);  	if (status & (IRQ_COAL | IRQ_DLY))  		ll_temac_recv(lp->ndev); @@ -794,7 +859,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", temac_dma_in32(lp, i), +		len += sprintf(buf + len, "%.8x%s", lp->dma_in(lp, i),  			       (i % 8) == 7 ? "\n" : " ");  	len += sprintf(buf + len, "\n"); @@ -820,7 +885,6 @@ 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)); @@ -870,13 +934,20 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)  		goto nodev;  	} -	dcrs = dcr_resource_start(np, 0); -	if (dcrs == 0) { -		dev_err(&op->dev, "could not get DMA register address\n"); -		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; +		}  	} -	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);  |