Freescale Ethernet combined driver
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
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
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
@@ -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
@@ -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);
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
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. Thevirt_to_xxxmacros don't work on those addresses. You need to use thedma_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
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. Thevirt_to_xxxmacros don't work on those addresses. You need to use thedma_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
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. Thevirt_to_xxxmacros don't work on those addresses. You need to use thedma_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
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. Thevirt_to_xxxmacros don't work on those addresses. You need to use thedma_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
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. Thevirt_to_xxxmacros don't work on those addresses. You need to use thedma_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 ppc32NOT_CACHE_COHERENTprcoessors and stash the dma_addr_t/void * for later use. The other way is to kmalloc anddma_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
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. Thevirt_to_xxxmacros don't work on those addresses. You need to use thedma_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 ppc32NOT_CACHE_COHERENTprcoessors and stash the dma_addr_t/void * for later use. The other way is to kmalloc anddma_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
@@ -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 *dfor (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
@@ -271,6 +271,7 @@ static void restart(struct net_device *dstruct 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 *dFW (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);
Hi
Fix compile on 8xx FEC.
Brown bag time.
Regards
Pantelis
drivers/net/fs_enet/fs_enet.h +2 -2
@@ -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
@@ -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))
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