Skip to contentSkip to conversation

Freescale Ethernet combined driver

PATCH In review Pantelis Antoniou 3 participants 12 messages May 9, 2005 – May 13, 2005 Network drivers

lore
Share & tools
lore
#0 lore raw

PATCH 3/4 Freescale Ethernet combined driver

Hi

The following patch is a combined FCC/FEC ethernet driver for the Freescale line of PowerQUICCs.

FECs on 8xx and FCCs on 82xx are supported.

This part of the patch contains the mac drivers
for FEC & FCC.

Regards

Pantelis

drivers/net/fs_enet/mac-fcc.c new file +508 -0
@@ -0,0 +1,508 @@
+/*
+ * FCC driver for Motorola MPC8xx.
+ *
+ * Copyright (c) 2003 Intracom S.A. 
+ *  by Pantelis Antoniou <[email protected]>
+ *
+ * Released under the GPL
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/bitops.h>
+#include <linux/fs.h>
+
+#include <asm/immap_cpm2.h>
+#include <asm/mpc8260.h>
+#include <asm/cpm2.h>
+
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "fs_enet.h"
+
+/*************************************************/
+
+/* FCC access macros */
+
+/* be safe version */
+#if 1
+#define __fcc_out32(addr, x)	out_be32((unsigned *)addr, x)
+#define __fcc_out16(addr, x)	out_be16((unsigned short *)addr, x)
+#define __fcc_out8(addr, x)	out_8((unsigned char *)addr, x)
+#define __fcc_in32(addr)	in_be32((unsigned *)addr)
+#define __fcc_in16(addr)	in_be16((unsigned short *)addr)
+#define __fcc_in8(addr)		in_8((unsigned char *)addr)
+#else
+#define __fcc_out32(addr, x)	__raw_writel(x, addr)
+#define __fcc_out16(addr, x)	__raw_writew(x, addr)
+#define __fcc_out8(addr, x)	__raw_writeb(x, addr)
+#define __fcc_in32(addr)	__raw_readl(addr)
+#define __fcc_in16(addr)	__raw_readw(addr)
+#define __fcc_in8(addr)		__raw_readb(addr)
+#endif
+
+/* parameter space */
+
+/* write, read, set bits, clear bits */
+#define W32(_p, _m, _v)	__fcc_out32(&(_p)->_m, (_v))
+#define R32(_p, _m)	__fcc_in32(&(_p)->_m)
+#define S32(_p, _m, _v)	W32(_p, _m, R32(_p, _m) | (_v))
+#define C32(_p, _m, _v)	W32(_p, _m, R32(_p, _m) & ~(_v))
+
+#define W16(_p, _m, _v)	__fcc_out16(&(_p)->_m, (_v))
+#define R16(_p, _m)	__fcc_in16(&(_p)->_m)
+#define S16(_p, _m, _v)	W16(_p, _m, R16(_p, _m) | (_v))
+#define C16(_p, _m, _v)	W16(_p, _m, R16(_p, _m) & ~(_v))
+
+#define W8(_p, _m, _v)	__fcc_out8(&(_p)->_m, (_v))
+#define R8(_p, _m)	__fcc_in8(&(_p)->_m)
+#define S8(_p, _m, _v)	W8(_p, _m, R8(_p, _m) | (_v))
+#define C8(_p, _m, _v)	W8(_p, _m, R8(_p, _m) & ~(_v))
+
+/*************************************************/
+
+#define FCC_MAX_MULTICAST_ADDRS	64
+
+#define mk_mii_read(REG)	(0x60020000 | ((REG & 0x1f) << 18))
+#define mk_mii_write(REG, VAL)	(0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff))
+#define mk_mii_end		0
+
+#define MAX_CR_CMD_LOOPS	10000
+
+static inline int fcc_cr_cmd(struct fs_enet_private *fep, __u32 mcn, __u32 op)
+{
+	cpm2_map_t *immap = (cpm2_map_t *)CPM_MAP_ADDR;
+	cpm_cpm2_t *cpmp = &immap->im_cpm;
+	__u32 pg, sbc, v;
+
+	pg = CPM_CR_FCC1_PAGE + fep->fcc.idx;
+	sbc = CPM_CR_FCC1_SBLOCK + fep->fcc.idx;
+	v = mk_cr_cmd(pg, sbc, mcn, op);
+	W32(cpmp, cp_cpcr, v | CPM_CR_FLG);
+	while ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) != 0)
+		;
+
+	return 0;
+}
+
+#define FCC_NAPI_RX_EVENT_MSK	(FCC_ENET_RXF | FCC_ENET_RXB)
+#define FCC_RX_EVENT		(FCC_ENET_RXF)
+#define FCC_TX_EVENT		(FCC_ENET_TXB)
+#define FCC_ERR_EVENT_MSK	(FCC_ENET_TXE | FCC_ENET_BSY)
+
+static int setup_data(struct net_device *dev)
+{
+	cpm2_map_t *immap = (cpm2_map_t *)CPM_MAP_ADDR;
+	struct fs_enet_private *fep = netdev_priv(dev);
+	const struct fs_platform_info *fpi = fep->fpi;
+
+	fep->fcc.idx = fs_get_fcc_index(fpi->fs_no);
+	if ((unsigned int)fep->fcc.idx >= 3)	/* max 3 FCCs */
+		return -EINVAL;
+
+	fep->fcc.fccp = &immap->im_fcc[fep->fcc.idx];
+	fep->fcc.ep = &immap->im_dprambase[PROFF_FCC1 + fep->fcc.idx * 0x100];
+	fep->fcc.fcccp = &immap->im_fcc_c[fep->fcc.idx];
+
+	fep->ev_napi_rx = FCC_NAPI_RX_EVENT_MSK;
+	fep->ev_rx = FCC_RX_EVENT;
+	fep->ev_tx = FCC_TX_EVENT;
+	fep->ev_err = FCC_ERR_EVENT_MSK;
+
+	return 0;
+}
+
+static void cleanup_data(struct net_device *dev)
+{
+	/* nothing */
+}
+
+static void set_promiscuous_mode(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+
+	S32(fccp, fcc_fpsmr, FCC_PSMR_PRO);
+}
+
+static void set_multicast_start(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_enet_t *ep = fep->fcc.ep;
+
+	W32(ep, fen_gaddrh, 0);
+	W32(ep, fen_gaddrl, 0);
+}
+
+static void set_multicast_one(struct net_device *dev, const __u8 *mac)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_enet_t *ep = fep->fcc.ep;
+	__u16 taddrh, taddrm, taddrl;
+
+	taddrh = ((__u16)mac[5] << 8) | mac[4];
+	taddrm = ((__u16)mac[3] << 8) | mac[2];
+	taddrl = ((__u16)mac[1] << 8) | mac[0];
+
+	W16(ep, fen_taddrh, taddrh);
+	W16(ep, fen_taddrm, taddrm);
+	W16(ep, fen_taddrl, taddrl);
+	fcc_cr_cmd(fep, 0x0C, CPM_CR_SET_GADDR);
+}
+
+static void set_multicast_finish(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+	fcc_enet_t *ep = fep->fcc.ep;
+
+	/* clear promiscuous always */
+	C32(fccp, fcc_fpsmr, FCC_PSMR_PRO);
+
+	/* if all multi or too many multicasts; just enable all */
+	if ((dev->flags & IFF_ALLMULTI) != 0 ||
+	    dev->mc_count > FCC_MAX_MULTICAST_ADDRS) {
+
+		W32(ep, fen_gaddrh, 0xffffffff);
+		W32(ep, fen_gaddrl, 0xffffffff);
+	}
+
+	/* read back */
+	fep->fcc.gaddrh = R32(ep, fen_gaddrh);
+	fep->fcc.gaddrl = R32(ep, fen_gaddrl);
+}
+
+static void set_mac_address(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_enet_t *ep = fep->fcc.ep;
+	__u16 paddrh, paddrm, paddrl;
+	const unsigned char *mac = dev->dev_addr;
+
+	paddrh = ((__u16)mac[5] << 8) | mac[4];
+	paddrm = ((__u16)mac[3] << 8) | mac[2];
+	paddrl = ((__u16)mac[1] << 8) | mac[0];
+
+	W16(ep, fen_paddrh, paddrh);
+	W16(ep, fen_paddrm, paddrm);
+	W16(ep, fen_paddrl, paddrl);
+}
+
+static void restart(struct net_device *dev, int duplex, int speed)
+{
+	cpm2_map_t *immap = (cpm2_map_t *)CPM_MAP_ADDR;
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+	fcc_enet_t *ep = fep->fcc.ep;
+	__u16 paddrh, paddrm, paddrl;
+	__u16 mem_addr;
+	const unsigned char *mac;
+	int i;
+
+	C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT);
+
+	/* clear everything (slow & steady does it) */
+	for (i = 0; i < sizeof(*ep); i++)
+		__fcc_out8((char *)ep + i, 0);
+
+	/* point to bds */
+	W32(ep, fen_genfcc.fcc_rbase, iopa((__u32)fep->rx_bd_base));
+	W32(ep, fen_genfcc.fcc_tbase, iopa((__u32)fep->tx_bd_base));
+
+	/* Set maximum bytes per receive buffer.
+	 * It must be a multiple of 32.
+	 */
+	W16(ep, fen_genfcc.fcc_mrblr, PKT_MAXBLR_SIZE);
+
+	W32(ep, fen_genfcc.fcc_rstate, (CPMFCR_GBL | CPMFCR_EB) << 24);
+	W32(ep, fen_genfcc.fcc_tstate, (CPMFCR_GBL | CPMFCR_EB) << 24);
+
+	/* Allocate space in the reserved FCC area of DPRAM for the
+	 * internal buffers.  No one uses this space (yet), so we
+	 * can do this.  Later, we will add resource management for
+	 * this area.
+	 */
+	mem_addr = CPM_FCC_SPECIAL_BASE + fep->fcc.idx * 128;
+	W16(ep, fen_genfcc.fcc_riptr, (mem_addr & 0xffff));
+	W16(ep, fen_genfcc.fcc_tiptr, ((mem_addr + 32) & 0xffff));
+	W16(ep, fen_padptr, mem_addr + 64);
+	for (i = 64; i < 128; i++)
+		__fcc_out8(immap->im_dprambase + mem_addr + i, 0x88);
+
+	W32(ep, fen_genfcc.fcc_rbptr, 0);
+	W32(ep, fen_genfcc.fcc_tbptr, 0);
+	W32(ep, fen_genfcc.fcc_rcrc, 0);
+	W32(ep, fen_genfcc.fcc_tcrc, 0);
+	W32(ep, fen_genfcc.fcc_res1, 0);
+	W32(ep, fen_genfcc.fcc_res2, 0);
+
+	/* no CAM */
+	W32(ep, fen_camptr, 0);
+
+	/* Set CRC preset and mask */
+	W32(ep, fen_cmask, 0xdebb20e3);
+	W32(ep, fen_cpres, 0xffffffff);
+
+	W32(ep, fen_crcec, 0);		/* CRC Error counter       */
+	W32(ep, fen_alec, 0);		/* alignment error counter */
+	W32(ep, fen_disfc, 0);		/* discard frame counter   */
+	W16(ep, fen_retlim, 15);	/* Retry limit threshold   */
+	W16(ep, fen_pper, 0);		/* Normal persistence      */
+
+	/* set group address */
+	W32(ep, fen_gaddrh, fep->fcc.gaddrh);
+	W32(ep, fen_gaddrl, fep->fcc.gaddrh);
+
+	/* Clear hash filter tables */
+	W32(ep, fen_iaddrh, 0);
+	W32(ep, fen_iaddrl, 0);
+
+	/* Clear the Out-of-sequence TxBD  */
+	W16(ep, fen_tfcstat, 0);
+	W16(ep ,fen_tfclen, 0);
+	W32(ep, fen_tfcptr, 0);
+
+	W16(ep, fen_mflr, PKT_MAXBUF_SIZE);   /* maximum frame length register */
+	W16(ep, fen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */
+
+	/* set address */
+	mac = dev->dev_addr;
+	paddrh = ((__u16)mac[5] << 8) | mac[4];
+	paddrm = ((__u16)mac[3] << 8) | mac[2];
+	paddrl = ((__u16)mac[1] << 8) | mac[0];
+
+	W16(ep, fen_paddrh, paddrh);
+	W16(ep, fen_paddrm, paddrm);
+	W16(ep, fen_paddrl, paddrl);
+
+	W16(ep, fen_taddrh, 0);
+	W16(ep, fen_taddrm, 0);
+	W16(ep, fen_taddrl, 0);
+
+	W16(ep, fen_maxd1, 1520);	/* maximum DMA1 length */
+	W16(ep, fen_maxd2, 1520);	/* maximum DMA2 length */
+
+	/* Clear stat counters, in case we ever enable RMON */
+	W32(ep, fen_octc, 0);
+	W32(ep, fen_colc, 0);
+	W32(ep, fen_broc, 0);
+	W32(ep, fen_mulc, 0);
+	W32(ep, fen_uspc, 0);
+	W32(ep, fen_frgc, 0);
+	W32(ep, fen_ospc, 0);
+	W32(ep, fen_jbrc, 0);
+	W32(ep, fen_p64c, 0);
+	W32(ep, fen_p65c, 0);
+	W32(ep, fen_p128c, 0);
+	W32(ep, fen_p256c, 0);
+	W32(ep, fen_p512c, 0);
+	W32(ep, fen_p1024c, 0);
+
+	W16(ep, fen_rfthr, 0);	/* Suggested by manual */
+	W16(ep, fen_rfcnt, 0);
+	W16(ep, fen_cftype, 0);
+
+	fs_init_bds(dev);
+
+	fcc_cr_cmd(fep, 0x0c, CPM_CR_INIT_TRX);
+
+	W16(ep, fen_genfcc.fcc_mrblr, PKT_MAXBLR_SIZE);
+
+	/* clear events */
+	W16(fccp, fcc_fcce, 0xffff);
+
+	/* Enable interrupts we wish to service */
+	W16(fccp, fcc_fccm, FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB);
+
+	/* Set GFMR to enable Ethernet operating mode */
+	W32(fccp, fcc_gfmr, FCC_GFMR_TCI | FCC_GFMR_MODE_ENET);
+
+	/* set sync/delimiters */
+	W16(fccp, fcc_fdsr, 0xd555);
+
+	W32(fccp, fcc_fpsmr, FCC_PSMR_ENCRC | FCC_PSMR_RMII);
+
+	/* adjust to duplex mode */
+	if (duplex)
+		S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB);
+	else
+		C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB);
+
+	S32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT);
+}
+
+static void stop(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+
+	/* stop ethernet */
+	C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT);
+
+	/* clear events */
+	W16(fccp, fcc_fcce, 0xffff);
+
+	/* clear interrupt mask */
+	W16(fccp, fcc_fccm, 0);
+
+	fs_cleanup_bds(dev);
+}
+
+static void pre_request_irq(struct net_device *dev, int irq)
+{
+	/* nothing */
+}
+
+static void post_free_irq(struct net_device *dev, int irq)
+{
+	/* nothing */
+}
+
+static void napi_clear_rx_event(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+
+	W16(fccp, fcc_fcce, FCC_NAPI_RX_EVENT_MSK);
+}
+
+static void napi_enable_rx(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+
+	S16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK);
+}
+
+static void napi_disable_rx(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+
+	C16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK);
+}
+
+static void rx_bd_done(struct net_device *dev)
+{
+	/* nothing */
+}
+
+static void tx_kickstart(struct net_device *dev)
+{
+	/* nothing */
+}
+
+static __u32 get_int_events(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+
+	return (__u32)R16(fccp, fcc_fcce);
+}
+
+static void clear_int_events(struct net_device *dev, __u32 int_events)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+
+	W16(fccp, fcc_fcce, int_events & 0xffff);
+}
+
+static void ev_error(struct net_device *dev, __u32 int_events)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	(void)fep;
+	printk(KERN_WARNING DRV_MODULE_NAME
+	       ": %s FS_ENET ERROR(s) 0x%x\n", dev->name, int_events);
+}
+
+int get_regs(struct net_device *dev, void *p, int *sizep)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+
+	if (*sizep < sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t))
+		return -EINVAL;
+
+	memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t));
+	p = (char *)p + sizeof(fcc_t);
+
+	memcpy_fromio(p, fep->fcc.fcccp, sizeof(fcc_c_t));
+	p = (char *)p + sizeof(fcc_c_t);
+
+	memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t));
+
+	return 0;
+}
+
+int get_regs_len(struct net_device *dev)
+{
+	return sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t);
+}
+
+/* Some transmit errors cause the transmitter to shut
+ * down.  We now issue a restart transmit.  Since the
+ * errors close the BD and update the pointers, the restart
+ * _should_ pick up without having to reset any of our
+ * pointers either.  Also, To workaround 8260 device erratum 
+ * CPM37, we must disable and then re-enable the transmitter
+ * following a Late Collision, Underrun, or Retry Limit error.
+ */
+void tx_restart(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+
+	C32(fccp, fcc_gfmr, FCC_GFMR_ENT);
+	udelay(10);
+	S32(fccp, fcc_gfmr, FCC_GFMR_ENT);
+
+	fcc_cr_cmd(fep, 0x0C, CPM_CR_RESTART_TX);
+}
+
+/*************************************************************************/
+
+const struct fs_ops fs_fcc_ops = {
+	.setup_data		= setup_data,
+	.cleanup_data		= cleanup_data,
+	.set_promiscuous_mode	= set_promiscuous_mode,
+	.set_multicast_start	= set_multicast_start,
+	.set_multicast_one	= set_multicast_one,
+	.set_multicast_finish	= set_multicast_finish,
+	.set_mac_address	= set_mac_address,
+	.restart		= restart,
+	.stop			= stop,
+	.pre_request_irq	= pre_request_irq,
+	.post_free_irq		= post_free_irq,
+	.napi_clear_rx_event	= napi_clear_rx_event,
+	.napi_enable_rx		= napi_enable_rx,
+	.napi_disable_rx	= napi_disable_rx,
+	.rx_bd_done		= rx_bd_done,
+	.tx_kickstart		= tx_kickstart,
+	.get_int_events		= get_int_events,
+	.clear_int_events	= clear_int_events,
+	.ev_error		= ev_error,
+	.get_regs		= get_regs,
+	.get_regs_len		= get_regs_len,
+	.tx_restart		= tx_restart,
+};
drivers/net/fs_enet/mac-fec.c new file +633 -0

633 lines not on this page · raw message

#1 lore raw
Quoted 9 lines · Pantelis Antoniou

Hi

The following patch is a combined FCC/FEC ethernet driver for the Freescale line of PowerQUICCs.

FECs on 8xx and FCCs on 82xx are supported.

This part of the patch contains the mac drivers
for FEC & FCC.

As mentioned on IRC, this needs to be scrubbed of all iopa() usage in favor of standard DMA API calls.

-Matt

#2 lore raw
Quoted 9 lines · Matt Porter
Quoted 7 lines · Pantelis Antoniou

Hi

The following patch is a combined FCC/FEC ethernet driver for the Freescale line of PowerQUICCs.

FECs on 8xx and FCCs on 82xx are supported.

Quoted 10 lines
Quoted 2 lines

This part of the patch contains the mac drivers
for FEC & FCC.

As mentioned on IRC, this needs to be scrubbed of all iopa() usage in favor of standard DMA API calls.

-Matt

This patch replace iopa use with virt_to_phys.

Regards

Pantelis

drivers/net/fs_enet/mac-fcc.c +2 -2
Index: linux-2.6.11.7-fs_enet/drivers/net/fs_enet/mac-fcc.c
===================================================================
@@ -226,8 +226,8 @@ static void restart(struct net_device *d
 		__fcc_out8((char *)ep + i, 0);
 
 	/* point to bds */
-	W32(ep, fen_genfcc.fcc_rbase, iopa((__u32)fep->rx_bd_base));
-	W32(ep, fen_genfcc.fcc_tbase, iopa((__u32)fep->tx_bd_base));
+	W32(ep, fen_genfcc.fcc_rbase, virt_to_phys(fep->rx_bd_base));
+	W32(ep, fen_genfcc.fcc_tbase, virt_to_phys(fep->tx_bd_base));
 
 	/* Set maximum bytes per receive buffer.
 	 * It must be a multiple of 32.
drivers/net/fs_enet/mac-fec.c +2 -2
Index: linux-2.6.11.7-fs_enet/drivers/net/fs_enet/mac-fec.c
===================================================================
@@ -306,8 +306,8 @@ static void restart(struct net_device *d
 	/*
 	 * Set receive and transmit descriptor base. 
 	 */
-	FW(fecp, r_des_start, iopa((__u32)fep->rx_bd_base));
-	FW(fecp, x_des_start, iopa((__u32)fep->tx_bd_base));
+	FW(fecp, r_des_start, virt_to_phys(fep->rx_bd_base));
+	FW(fecp, x_des_start, virt_to_phys(fep->tx_bd_base));
 
 	fs_init_bds(dev);
 
#3 lore raw
Quoted 1 line · Pantelis Antoniou

This patch replace iopa use with virt_to_phys.

Not gonna work .....

When you map uncached on 8xx you get a new vmalloc() space. The virt_to_xxx macros don't work on those addresses. You need to use the dma_consistent() function, stash the real physical address it returns and then use it where appropriate.

drivers/net/fs_enet/mac-fcc.c static void restart(struct net_device *d · line 230

Quoted 2 lines
drivers/net/fs_enet/mac-fcc.c +2 -0
+	W32(ep, fen_genfcc.fcc_rbase, virt_to_phys(fep->rx_bd_base));
+	W32(ep, fen_genfcc.fcc_tbase, virt_to_phys(fep->tx_bd_base));

I thought you were getting rid of these weirdo macros and write normal code for data structure access? Please .....

Thanks.

	-- Dan
#4 lore raw
Quoted 6 lines · Dan Malek
Quoted 1 line · Pantelis Antoniou

This patch replace iopa use with virt_to_phys.

Quoted 8 lines

Not gonna work .....

When you map uncached on 8xx you get a new vmalloc() space. The virt_to_xxx macros don't work on those addresses. You need to use the dma_consistent() function, stash the real physical address it returns and then use it where appropriate.

Hmm. Correct. The dma_consistent() function will do some cache flushing, but we don't really care about that anyway.

Oh well. Patch will be forthcoming...

Quoted 7 lines

drivers/net/fs_enet/mac-fcc.c static void restart(struct net_device *d · line 230

Quoted 2 lines
drivers/net/fs_enet/mac-fcc.c +2 -0
+    W32(ep, fen_genfcc.fcc_rbase, virt_to_phys(fep->rx_bd_base));
+    W32(ep, fen_genfcc.fcc_tbase, virt_to_phys(fep->tx_bd_base));

I thought you were getting rid of these weirdo macros and write normal code for data structure access? Please .....

This is going to be difficult since the /net/drivers maintainer insists on using them. I used to have direct data structure accesses so it won't be difficult to change.

But we must have a consunsus.

Quoted 7 lines

Thanks.

    -- Dan

Regards

Pantelis

#5 lore raw
In reply to Dan Malek
Quoted 5 lines · Dan Malek
Quoted 1 line · Pantelis Antoniou

This patch replace iopa use with virt_to_phys.

Quoted 7 lines

Not gonna work .....

When you map uncached on 8xx you get a new vmalloc() space. The virt_to_xxx macros don't work on those addresses. You need to use the dma_consistent() function, stash the real physical address it returns and then use it where appropriate.

That and the use of virt_to_* and friends is deprecated by the DMA API. You'll never get that upstream even if it were a case where it did work. That's a good thing to know for anybody doing other drivers...

-Matt

#6 lore raw
Quoted 16 lines · Matt Porter
Quoted 5 lines · Dan Malek
Quoted 1 line · Pantelis Antoniou

This patch replace iopa use with virt_to_phys.

Quoted 7 lines

Not gonna work .....

When you map uncached on 8xx you get a new vmalloc() space. The virt_to_xxx macros don't work on those addresses. You need to use the dma_consistent() function, stash the real physical address it returns and then use it where appropriate.

Quoted 8 lines

That and the use of virt_to_* and friends is deprecated by the DMA API. You'll never get that upstream even if it were a case where it did work. That's a good thing to know for anybody doing other drivers...

-Matt

OK then.

What's the recommended function to call to go from a virtual -> physical address, but without doing a cache flush/invalidate?

Regards

Pantelis

#7 lore raw
Quoted 26 lines · Pantelis Antoniou
Quoted 16 lines · Matt Porter
Quoted 5 lines · Dan Malek
Quoted 1 line · Pantelis Antoniou

This patch replace iopa use with virt_to_phys.

Quoted 7 lines

Not gonna work .....

When you map uncached on 8xx you get a new vmalloc() space. The virt_to_xxx macros don't work on those addresses. You need to use the dma_consistent() function, stash the real physical address it returns and then use it where appropriate.

Quoted 8 lines

That and the use of virt_to_* and friends is deprecated by the DMA API. You'll never get that upstream even if it were a case where it did work. That's a good thing to know for anybody doing other drivers...

-Matt

Quoted 5 lines

OK then.

What's the recommended function to call to go from a virtual -> physical address, but without doing a cache flush/invalidate?

There is no generic function to do that in a driver since no mainstream drivers in the kernel need to do it. Generally you can rework the driver such that you cache the DMA address as Dan suggested already. I don't know your exact usage, however, you can allocate memory with dma_alloc_noncoherent() that is cached on ppc32 NOT_CACHE_COHERENT prcoessors and stash the dma_addr_t/void * for later use. The other way is to kmalloc and dma_map_single() (stashing the same way) which is basically the same thing.

Do you have a case where this doesn't work?

-Matt

#8 lore raw
Quoted 48 lines · Matt Porter
Quoted 29 lines · Pantelis Antoniou
Quoted 18 lines · Matt Porter
Quoted 6 lines · Dan Malek
Quoted 1 line · Pantelis Antoniou

This patch replace iopa use with virt_to_phys.

Quoted 7 lines

Not gonna work .....

When you map uncached on 8xx you get a new vmalloc() space. The virt_to_xxx macros don't work on those addresses. You need to use the dma_consistent() function, stash the real physical address it returns and then use it where appropriate.

Quoted 8 lines

That and the use of virt_to_* and friends is deprecated by the DMA API. You'll never get that upstream even if it were a case where it did work. That's a good thing to know for anybody doing other drivers...

-Matt

Quoted 5 lines

OK then.

What's the recommended function to call to go from a virtual -> physical address, but without doing a cache flush/invalidate?

There is no generic function to do that in a driver since no mainstream drivers in the kernel need to do it. Generally you can rework the driver such that you cache the DMA address as Dan suggested already. I don't know your exact usage, however, you can allocate memory with dma_alloc_noncoherent() that is cached on ppc32 NOT_CACHE_COHERENT prcoessors and stash the dma_addr_t/void * for later use. The other way is to kmalloc and dma_map_single() (stashing the same way) which is basically the same thing.

Quoted 2 lines

Do you have a case where this doesn't work?

No that will do just fine.

I just want to know the recommended way to do it.

Quoted 3 lines

-Matt

Regards

Pantelis

#9 lore raw
In reply to Matt Porter
Quoted 48 lines · Matt Porter
Quoted 29 lines · Pantelis Antoniou
Quoted 18 lines · Matt Porter
Quoted 6 lines · Dan Malek
Quoted 1 line · Pantelis Antoniou

This patch replace iopa use with virt_to_phys.

Quoted 7 lines

Not gonna work .....

When you map uncached on 8xx you get a new vmalloc() space. The virt_to_xxx macros don't work on those addresses. You need to use the dma_consistent() function, stash the real physical address it returns and then use it where appropriate.

Quoted 8 lines

That and the use of virt_to_* and friends is deprecated by the DMA API. You'll never get that upstream even if it were a case where it did work. That's a good thing to know for anybody doing other drivers...

-Matt

Quoted 5 lines

OK then.

What's the recommended function to call to go from a virtual -> physical address, but without doing a cache flush/invalidate?

There is no generic function to do that in a driver since no mainstream drivers in the kernel need to do it. Generally you can rework the driver such that you cache the DMA address as Dan suggested already. I don't know your exact usage, however, you can allocate memory with dma_alloc_noncoherent() that is cached on ppc32 NOT_CACHE_COHERENT prcoessors and stash the dma_addr_t/void * for later use. The other way is to kmalloc and dma_map_single() (stashing the same way) which is basically the same thing.

Quoted 5 lines

Do you have a case where this doesn't work?

-Matt

Here is the final (I hope) fix.

This patch kills iopa/virt_to_phys usage by using the returned physical address from the DMA API.

Comments?

Regards

Pantelis

drivers/net/fs_enet/mac-fcc.c +8 -2
Index: linux-2.6.11.7-fs_enet/drivers/net/fs_enet/mac-fcc.c
===================================================================
@@ -212,8 +212,10 @@ static void restart(struct net_device *d
 {
 	cpm2_map_t *immap = (cpm2_map_t *)CPM_MAP_ADDR;
 	struct fs_enet_private *fep = netdev_priv(dev);
+	const struct fs_platform_info *fpi = fep->fpi;
 	fcc_t *fccp = fep->fcc.fccp;
 	fcc_enet_t *ep = fep->fcc.ep;
+	dma_addr_t rx_bd_base_phys, tx_bd_base_phys;
 	__u16 paddrh, paddrm, paddrl;
 	__u16 mem_addr;
 	const unsigned char *mac;
@@ -225,9 +227,13 @@ static void restart(struct net_device *d
 	for (i = 0; i < sizeof(*ep); i++)
 		__fcc_out8((char *)ep + i, 0);
 
+	/* get physical address */
+	rx_bd_base_phys = fep->ring_mem_addr;
+	tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring;
+
 	/* point to bds */
-	W32(ep, fen_genfcc.fcc_rbase, iopa((__u32)fep->rx_bd_base));
-	W32(ep, fen_genfcc.fcc_tbase, iopa((__u32)fep->tx_bd_base));
+	W32(ep, fen_genfcc.fcc_rbase, rx_bd_base_phys);
+	W32(ep, fen_genfcc.fcc_tbase, tx_bd_base_phys);
 
 	/* Set maximum bytes per receive buffer.
 	 * It must be a multiple of 32.
drivers/net/fs_enet/mac-fec.c +7 -2
Index: linux-2.6.11.7-fs_enet/drivers/net/fs_enet/mac-fec.c
===================================================================
@@ -271,6 +271,7 @@ static void restart(struct net_device *d
 	struct fs_enet_private *fep = netdev_priv(dev);
 	fec_t *fecp = fep->fec.fecp;
 	const struct fs_platform_info *fpi = fep->fpi;
+	dma_addr_t rx_bd_base_phys, tx_bd_base_phys;
 	int r;
 	__u32 addrhi, addrlo;
 
@@ -303,11 +304,15 @@ static void restart(struct net_device *d
 	FW(fecp, r_buff_size, PKT_MAXBLR_SIZE);
 	FW(fecp, r_hash, PKT_MAXBUF_SIZE);
 
+	/* get physical address */
+	rx_bd_base_phys = fep->ring_mem_addr;
+	tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring;
+
 	/*
 	 * Set receive and transmit descriptor base. 
 	 */
-	FW(fecp, r_des_start, iopa((__u32)fep->rx_bd_base));
-	FW(fecp, x_des_start, iopa((__u32)fep->tx_bd_base));
+	FW(fecp, r_des_start, rx_bd_base_phys);
+	FW(fecp, x_des_start, tx_bd_base_phys);
 
 	fs_init_bds(dev);
 
#10 lore raw

Hi

Fix compile on 8xx FEC.

Brown bag time.

Regards

Pantelis

drivers/net/fs_enet/fs_enet.h +2 -2
Index: linux-2.6.11.7-fs_enet/drivers/net/fs_enet/fs_enet.h
===================================================================
@@ -108,7 +108,7 @@ struct fs_enet_mii_bus {
 	union {
 		struct {
 			unsigned int mii_speed;
-			void *fsp;
+			void *fecp;
 		} fec;
 
 		struct {
@@ -172,7 +172,7 @@ struct fs_enet_private {
 	union {
 		struct {
 			int idx;		/* FEC1 = 0, FEC2 = 1  */
-			void *fsp;		/* hw registers        */
+			void *fecp;		/* hw registers        */
 			__u32 hthi, htlo;	/* state for multicast */
 		} fec;
 
drivers/net/fs_enet/mac-fec.c +2 -2
Index: linux-2.6.11.7-fs_enet/drivers/net/fs_enet/mac-fec.c
===================================================================
@@ -60,10 +60,10 @@
 #endif
 
 /* write */
-#define FW(_fecp, _reg, _v) __fs_out32(&(_fecp)->fs_ ## _reg, (_v))
+#define FW(_fecp, _reg, _v) __fs_out32(&(_fecp)->fec_ ## _reg, (_v))
 
 /* read */
-#define FR(_fecp, _reg)	__fs_in32(&(_fecp)->fs_ ## _reg)
+#define FR(_fecp, _reg)	__fs_in32(&(_fecp)->fec_ ## _reg)
 
 /* set bits */
 #define FS(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) | (_v))
#11 lore raw
In reply to Pantelis Antoniou
Quoted 3 lines · Pantelis Antoniou

What's the recommended function to call to go from a virtual -> physical address, but without doing a cache flush/invalidate?

It doesn't have anything to do with cache flush/invalidate, it has to do with the way the memory is mapped to a different VM space. You do not (and in some cases can't) perform invalidate/flush on uncached addresses.

What we need to do is fix up the CPM allocation functions, so when it does the dma_alloc_consistent (or whatever the name is today) it keeps both the physical and virtual addresses. When we call cpm_hostalloc(), it has to return both the physical and virtual addresses, and the driver must take note of them. I had this in the drivers at one time in 2.4, I don't know where it went ......

The drivers themselves must do the dma_consistent_alloc on large buffers, and also keep track of both physical and virtual addresses. Again, this was done once before ....

Thanks.

	-- Dan