diff options
author | imp <imp@FreeBSD.org> | 2010-04-12 23:16:16 +0000 |
---|---|---|
committer | imp <imp@FreeBSD.org> | 2010-04-12 23:16:16 +0000 |
commit | 4db75e1a62c2f69f67a921c34d9be31dc951fe8d (patch) | |
tree | 0c8e1c9067a1556456275b0ec4337b5853bc5528 | |
parent | 3c756540edb731191bace768a61a742408d850c1 (diff) | |
download | FreeBSD-src-4db75e1a62c2f69f67a921c34d9be31dc951fe8d.zip FreeBSD-src-4db75e1a62c2f69f67a921c34d9be31dc951fe8d.tar.gz |
merge from head, part 10 of many
35 files changed, 1058 insertions, 875 deletions
diff --git a/sys/mips/atheros/if_arge.c b/sys/mips/atheros/if_arge.c index da8d181..4367bfb 100644 --- a/sys/mips/atheros/if_arge.c +++ b/sys/mips/atheros/if_arge.c @@ -171,7 +171,7 @@ extern uint32_t ar711_base_mac[ETHER_ADDR_LEN]; static struct mtx miibus_mtx; -MTX_SYSINIT(miibus_mtx, &miibus_mtx, "arge mii lock", MTX_SPIN); +MTX_SYSINIT(miibus_mtx, &miibus_mtx, "arge mii lock", MTX_DEF); /* diff --git a/sys/mips/cavium/dev/rgmii/octeon_rgmx.c b/sys/mips/cavium/dev/rgmii/octeon_rgmx.c index 53365cc..ada0946 100644 --- a/sys/mips/cavium/dev/rgmii/octeon_rgmx.c +++ b/sys/mips/cavium/dev/rgmii/octeon_rgmx.c @@ -136,7 +136,6 @@ struct rgmx_softc_dev { u_int idx; u_char ieee[6]; - char const * typestr; /* printable name of the interface. */ u_short txb_size; /* size of TX buffer, in bytes */ /* Transmission buffer management. */ @@ -182,7 +181,6 @@ static u_int get_rgmx_port_ordinal(u_int port); static void octeon_rgmx_set_mac(u_int port); static void octeon_rgmx_init_sc(struct rgmx_softc_dev *sc, device_t dev, u_int port, u_int num_devices); static int octeon_rgmx_init_ifnet(struct rgmx_softc_dev *sc); -static void octeon_rgmx_mark_ready(struct rgmx_softc_dev *sc); static void octeon_rgmx_stop(struct rgmx_softc_dev *sc); static void octeon_rgmx_config_speed(u_int port, u_int); #ifdef DEBUG_RGMX_DUMP @@ -211,6 +209,7 @@ static int octeon_rgmx_intr(void *arg); /* Standard driver entry points. These can be static. */ static void octeon_rgmx_init (void *); //static driver_intr_t rgmx_intr; +static void octeon_rgmx_config_cam (struct ifnet *); static int octeon_rgmx_ioctl (struct ifnet *, u_long, caddr_t); static void octeon_rgmx_output_start (struct ifnet *); static void octeon_rgmx_output_start_locked (struct ifnet *); @@ -349,8 +348,6 @@ static int octeon_rgmx_init_ifnet (struct rgmx_softc_dev *sc) ifmedia_set(&sc->media, bit2media[0]); ether_ifattach(sc->ifp, sc->ieee); - /* Print additional info when attached. */ - device_printf(sc->sc_dev, "type %s, full duplex\n", sc->typestr); return (0); } @@ -447,12 +444,6 @@ static int rgmii_attach (device_t dev) device_printf(dev, " ifinit failed for rgmx port %u\n", port); return (ENOSPC); } -/* - * Don't call octeon_rgmx_mark_ready() - * ifnet will call it indirectly via octeon_rgmx_init() - * - * octeon_rgmx_mark_ready(sc); - */ num_devices++; } } @@ -1024,10 +1015,9 @@ static u_int octeon_rgmx_pko_xmit_packet (struct rgmx_softc_dev *sc, void *out_b * 3 words or less are left. We write our 2nd word now and then put in a chain link * to new PKO cmd buf. */ - void *pko_cmd_buf = octeon_fpa_alloc(OCTEON_FPA_TX_CMDBUF_POOL); - uint64_t phys_cmd_buf; + uint64_t phys_cmd_buf = octeon_fpa_alloc_phys(OCTEON_FPA_TX_CMDBUF_POOL); - if (!pko_cmd_buf) { + if (!phys_cmd_buf) { /* * FPA pool for xmit-buffer-commands is empty. */ @@ -1035,7 +1025,6 @@ static u_int octeon_rgmx_pko_xmit_packet (struct rgmx_softc_dev *sc, void *out_b octeon_spinlock_unlock(&(sc->outq_ptr[queue].lock)); return (0); } - phys_cmd_buf = OCTEON_PTR2PHYS(pko_cmd_buf); xmit_cmd_ptr[1] = pko_pkt_word.word64; xmit_cmd_ptr[2] = phys_cmd_buf; @@ -1235,6 +1224,8 @@ static void octeon_rgmx_output_start_locked (struct ifnet *ifp) for (ii = 0; ii < len; ii++) printf(" %X", dc[ii]); printf("\n"); #endif + ETHER_BPF_MTAP(ifp, m); + IF_ENQUEUE(&sc->tx_pending_queue, m); /* @@ -1648,9 +1639,106 @@ static int octeon_rgmx_medchange (struct ifnet *ifp) static void octeon_rgmx_medstat (struct ifnet *ifp, struct ifmediareq *ifm) { - /* - * No support for Media Status callback - */ + struct rgmx_softc_dev *sc = ifp->if_softc; + octeon_rgmx_rxx_rx_inbnd_t link_status; + + octeon_rgmx_config_speed(sc->port, 1); + + RGMX_LOCK(sc); + + ifm->ifm_status = IFM_AVALID; + ifm->ifm_active = IFM_ETHER; + + /* + * Parse link status. + */ + link_status.word64 = sc->link_status; + + if (!link_status.bits.status) { + RGMX_UNLOCK(sc); + return; + } + + ifm->ifm_status |= IFM_ACTIVE; + + switch (link_status.bits.speed) { + case 0: + ifm->ifm_active |= IFM_10_T; + break; + case 1: + ifm->ifm_active |= IFM_100_TX; + break; + case 2: + ifm->ifm_active |= IFM_1000_T;; + break; + default: + /* Unknown! */ + break; + } + + /* + * Check duplex. + */ + if (link_status.bits.duplex == 1) + ifm->ifm_active |= IFM_FDX; + else + ifm->ifm_active |= IFM_HDX; + + RGMX_UNLOCK(sc); +} + +static void octeon_rgmx_config_cam(struct ifnet *ifp) +{ + struct rgmx_softc_dev *sc = ifp->if_softc; + u_int port = sc->port; + int index = INDEX(port); + int iface = INTERFACE(port); + u_int last_enabled; + uint64_t adr_ctl; + + last_enabled = octeon_rgmx_stop_port(port); + + adr_ctl = oct_read64(OCTEON_RGMX_RXX_ADR_CTL(index, iface)); + + /* + * Always accept broadcast traffic. + */ + if ((adr_ctl & OCTEON_RGMX_ADRCTL_ACCEPT_BROADCAST) == 0) + adr_ctl |= OCTEON_RGMX_ADRCTL_ACCEPT_BROADCAST; + + /* + * Accept all multicast in all multicast mode and in + * promiscuous mode. + * + * XXX Since we don't handle programming the CAM for + * multicast filtering, always accept all multicast. + */ + adr_ctl &= ~OCTEON_RGMX_ADRCTL_REJECT_ALL_MULTICAST; + adr_ctl |= OCTEON_RGMX_ADRCTL_ACCEPT_ALL_MULTICAST; + + /* + * In promiscuous mode, the CAM is shut off, so reject everything. + * Otherwise, filter using the CAM. + */ + if ((ifp->if_flags & IFF_PROMISC) != 0) { + adr_ctl &= ~OCTEON_RGMX_ADRCTL_CAM_MODE_ACCEPT_DMAC; + adr_ctl |= OCTEON_RGMX_ADRCTL_CAM_MODE_REJECT_DMAC; + } else { + adr_ctl &= ~OCTEON_RGMX_ADRCTL_CAM_MODE_REJECT_DMAC; + adr_ctl |= OCTEON_RGMX_ADRCTL_CAM_MODE_ACCEPT_DMAC; + } + + oct_write64(OCTEON_RGMX_RXX_ADR_CTL(index, iface), adr_ctl); + + /* + * If in promiscuous mode, disable the CAM. + */ + if ((ifp->if_flags & IFF_PROMISC) != 0) + oct_write64(OCTEON_RGMX_RXX_ADR_CAM_EN(index, iface), 0); + else + oct_write64(OCTEON_RGMX_RXX_ADR_CAM_EN(index, iface), 1); + + if (last_enabled) octeon_rgmx_start_port(port); } static int octeon_rgmx_ioctl (struct ifnet * ifp, u_long command, caddr_t data) @@ -1671,28 +1759,21 @@ static int octeon_rgmx_ioctl (struct ifnet * ifp, u_long command, caddr_t data) * "stopped", reflecting the UP flag. */ if (ifp->if_flags & IFF_UP) { - - /* * New state is IFF_UP * Restart or Start now, if driver is not running currently. */ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { - printf(" SIOCSTIFFLAGS UP/Not-running\n"); break; octeon_rgmx_init(sc); - } else { - printf(" SIOCSTIFFLAGS UP/Running\n"); break; } + octeon_rgmx_config_cam(ifp); } else { /* * New state is IFF_DOWN. * Stop & shut it down now, if driver is running currently. */ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { - printf(" SIOCSTIFFLAGS Down/Running\n"); break; octeon_rgmx_stop(sc); - } else { - printf(" SIOCSTIFFLAGS Down/Not-Running\n"); break; } } break; @@ -1734,17 +1815,9 @@ static int octeon_rgmx_ioctl (struct ifnet * ifp, u_long command, caddr_t data) return (error); } - - - -/* - * octeon_rgmx_mark_ready - * - * Initialize the rgmx driver for this instance - * Initialize device. - */ -static void octeon_rgmx_mark_ready (struct rgmx_softc_dev *sc) +static void octeon_rgmx_init (void *xsc) { + struct rgmx_softc_dev *sc = xsc; /* Enable interrupts. */ /* For RGMX they are already enabled earlier */ @@ -1763,21 +1836,9 @@ static void octeon_rgmx_mark_ready (struct rgmx_softc_dev *sc) /* Kick start the output */ /* Hopefully PKO is running and will pick up packets via the timer or receive loop */ -} - -static void octeon_rgmx_init (void *xsc) -{ - - /* - * Called mostly from ifnet interface ifp->if_init(); - * I think we can anchor most of our iniialization here and - * not do it in different places from driver_attach(). - */ - /* - * For now, we only mark the interface ready - */ - octeon_rgmx_mark_ready((struct rgmx_softc_dev *) xsc); + /* Set link status. */ + octeon_rgmx_config_speed(sc->port, 1); } @@ -1792,7 +1853,6 @@ static void octeon_rgmx_config_speed (u_int port, u_int report_link) uint64_t val64_tx_clk, val64_tx_slot, val64_tx_burst; u_int last_enabled; - sc = get_rgmx_softc(port); if (!sc) { printf(" config_speed didn't find sc int:%u port:%u", iface, port); @@ -1804,79 +1864,96 @@ static void octeon_rgmx_config_speed (u_int port, u_int report_link) */ link_status.word64 = oct_read64(OCTEON_RGMX_RXX_RX_INBND(index, iface)); + RGMX_LOCK(sc); + /* * Compre to prev known state. If same then nothing to do. */ if (link_status.word64 == sc->link_status) { + RGMX_UNLOCK(sc); return; } - - RGMX_LOCK(sc); - old_link_status.word64 = sc->link_status; - sc->link_status = link_status.word64; - - last_enabled = octeon_rgmx_stop_port(port); - - gmx_cfg.word64 = oct_read64(OCTEON_RGMX_PRTX_CFG(index, iface)); - - /* - * Duplex - */ - gmx_cfg.bits.duplex = 1; - - switch (link_status.bits.speed) { - case 0: /* 10Mbps */ - gmx_cfg.bits.speed = 0; - gmx_cfg.bits.slottime = 0; - val64_tx_clk = 50; val64_tx_slot = 0x40; val64_tx_burst = 0; - break; - case 1: /* 100Mbps */ - gmx_cfg.bits.speed = 0; - gmx_cfg.bits.slottime = 0; - val64_tx_clk = 5; val64_tx_slot = 0x40; val64_tx_burst = 0; - break; - - case 2: /* 1Gbps */ - gmx_cfg.bits.speed = 1; - gmx_cfg.bits.slottime = 1; - val64_tx_clk = 1; val64_tx_slot = 0x200; val64_tx_burst = 0x2000; - break; - - case 3: /* ?? */ - default: - gmx_cfg.bits.speed = 1; - gmx_cfg.bits.slottime = 1; - val64_tx_clk = 1; val64_tx_slot = 0x200; val64_tx_burst = 0x2000; - break; - } + /* + * Compare to previous state modulo link status. If only link + * status is different, we don't need to change media. + */ + if (old_link_status.bits.duplex != link_status.bits.duplex || + old_link_status.bits.speed != link_status.bits.speed) { + last_enabled = octeon_rgmx_stop_port(port); + + gmx_cfg.word64 = oct_read64(OCTEON_RGMX_PRTX_CFG(index, iface)); - oct_write64(OCTEON_RGMX_TXX_CLK(index, iface), val64_tx_clk); - oct_write64(OCTEON_RGMX_TXX_SLOT(index, iface), val64_tx_slot); - oct_write64(OCTEON_RGMX_TXX_BURST(index, iface), val64_tx_burst); + /* + * Duplex + * XXX Set based on link_status.bits.duplex? + */ + gmx_cfg.bits.duplex = 1; + + switch (link_status.bits.speed) { + case 0: /* 10Mbps */ + gmx_cfg.bits.speed = 0; + gmx_cfg.bits.slottime = 0; + val64_tx_clk = 50; val64_tx_slot = 0x40; val64_tx_burst = 0; + break; + + case 1: /* 100Mbps */ + gmx_cfg.bits.speed = 0; + gmx_cfg.bits.slottime = 0; + val64_tx_clk = 5; val64_tx_slot = 0x40; val64_tx_burst = 0; + break; + + case 2: /* 1Gbps */ + gmx_cfg.bits.speed = 1; + gmx_cfg.bits.slottime = 1; + val64_tx_clk = 1; val64_tx_slot = 0x200; val64_tx_burst = 0x2000; + break; + + case 3: /* ?? */ + default: + gmx_cfg.bits.speed = 1; + gmx_cfg.bits.slottime = 1; + val64_tx_clk = 1; val64_tx_slot = 0x200; val64_tx_burst = 0x2000; + break; + } - oct_write64(OCTEON_RGMX_PRTX_CFG(index, iface), gmx_cfg.word64); + oct_write64(OCTEON_RGMX_TXX_CLK(index, iface), val64_tx_clk); + oct_write64(OCTEON_RGMX_TXX_SLOT(index, iface), val64_tx_slot); + oct_write64(OCTEON_RGMX_TXX_BURST(index, iface), val64_tx_burst); + + oct_write64(OCTEON_RGMX_PRTX_CFG(index, iface), gmx_cfg.word64); + + if (last_enabled) octeon_rgmx_start_port(port); + } - if (last_enabled) octeon_rgmx_start_port(port); + /* + * Now check and possibly change link status. + */ + if (link_status.bits.status != old_link_status.bits.status) { + if (report_link) { + if (link_status.bits.status) { + if_link_state_change(sc->ifp, LINK_STATE_UP); + } else { + if_link_state_change(sc->ifp, LINK_STATE_DOWN); + } + } + } - if (link_status.bits.status != old_link_status.bits.status) { + if (report_link) { + sc->link_status = link_status.word64; + } else { + /* + * We can't update link status proper since we can't + * change it in the interface, so keep the old link + * status intact but note the current speed and duplex + * settings. + */ + link_status.bits.status = old_link_status.bits.status; + sc->link_status = link_status.word64; + } -//#define DEBUG_LINESTATUS - if (link_status.bits.status) { -#ifdef DEBUG_LINESTATUS - printf(" %u/%u: Interface is now alive\n", iface, port); -#endif - if (report_link) if_link_state_change(sc->ifp, LINK_STATE_UP); - } else { -#ifdef DEBUG_LINESTATUS - printf(" %u/%u: Interface went down\n", iface, port); -#endif - if (report_link) if_link_state_change(sc->ifp, LINK_STATE_DOWN); - } - } RGMX_UNLOCK(sc); - } @@ -2096,7 +2173,6 @@ static void octeon_config_rgmii_port (u_int port) gmx_cfg.bits.en = 1; oct_write64(OCTEON_RGMX_PRTX_CFG(index, iface), gmx_cfg.word64); - octeon_rgmx_config_speed(port, 0); oct_write64(OCTEON_RGMX_TXX_THRESH(index, iface), 32); @@ -2181,7 +2257,7 @@ static int octeon_has_4ports (void) u_int chipid; int retcode = 1; - chipid = octeon_get_chipid() & 0xffffff00; + chipid = octeon_get_chipid(); switch (chipid) { case OCTEON_CN31XX_CHIP: diff --git a/sys/mips/cavium/octeon_ebt3000_cf.c b/sys/mips/cavium/octeon_ebt3000_cf.c index 10fb313..4298b75 100644 --- a/sys/mips/cavium/octeon_ebt3000_cf.c +++ b/sys/mips/cavium/octeon_ebt3000_cf.c @@ -89,6 +89,7 @@ __FBSDID("$FreeBSD$"); /* Status Register */ #define STATUS_BSY 0x80 /* Drive is busy */ #define STATUS_RDY 0x40 /* Drive is ready */ +#define STATUS_DF 0x20 /* Device fault */ #define STATUS_DRQ 0x08 /* Data can be transferred */ /* Miscelaneous */ @@ -153,11 +154,11 @@ static int cf_attach(device_t); static int cf_attach_geom(void *, int); /* ATA methods */ -static void cf_cmd_identify(void); -static void cf_cmd_write(uint32_t, uint32_t, void *); -static void cf_cmd_read(uint32_t, uint32_t, void *); -static void cf_wait_busy(void); -static void cf_send_cmd(uint32_t, uint8_t); +static int cf_cmd_identify(void); +static int cf_cmd_write(uint32_t, uint32_t, void *); +static int cf_cmd_read(uint32_t, uint32_t, void *); +static int cf_wait_busy(void); +static int cf_send_cmd(uint32_t, uint8_t); static void cf_attach_geom_proxy(void *arg, int flag); /* Miscelenous */ @@ -183,6 +184,8 @@ static int cf_access (struct g_provider *pp, int r, int w, int e) * ------------------------------------------------------------------- */ static void cf_start (struct bio *bp) { + int error; + /* * Handle actual I/O requests. The request is passed down through * the bio struct. @@ -200,12 +203,19 @@ static void cf_start (struct bio *bp) if ((bp->bio_cmd & (BIO_READ | BIO_WRITE))) { if (bp->bio_cmd & BIO_READ) { - cf_cmd_read(bp->bio_length / drive_param.sector_size, - bp->bio_offset / drive_param.sector_size, bp->bio_data); - + error = cf_cmd_read(bp->bio_length / drive_param.sector_size, + bp->bio_offset / drive_param.sector_size, bp->bio_data); } else if (bp->bio_cmd & BIO_WRITE) { - cf_cmd_write(bp->bio_length / drive_param.sector_size, - bp->bio_offset/drive_param.sector_size, bp->bio_data); + error = cf_cmd_write(bp->bio_length / drive_param.sector_size, + bp->bio_offset/drive_param.sector_size, bp->bio_data); + } else { + printf("%s: unrecognized bio_cmd %x.\n", __func__, bp->bio_cmd); + error = ENOTSUP; + } + + if (error != 0) { + g_io_deliver(bp, error); + return; } bp->bio_resid = 0; @@ -227,12 +237,13 @@ static int cf_ioctl (struct g_provider *pp, u_long cmd, void *data, int fflag, s * * Read nr_sectors from the device starting from start_sector. */ -static void cf_cmd_read (uint32_t nr_sectors, uint32_t start_sector, void *buf) +static int cf_cmd_read (uint32_t nr_sectors, uint32_t start_sector, void *buf) { unsigned long lba; uint32_t count; uint16_t *ptr_16; uint8_t *ptr_8; + int error; //#define OCTEON_VISUAL_CF_0 1 #ifdef OCTEON_VISUAL_CF_0 @@ -244,8 +255,11 @@ static void cf_cmd_read (uint32_t nr_sectors, uint32_t start_sector, void *buf) while (nr_sectors--) { - - cf_send_cmd(lba, CMD_READ_SECTOR); + error = cf_send_cmd(lba, CMD_READ_SECTOR); + if (error != 0) { + printf("%s: cf_send_cmd(CMD_READ_SECTOR) failed: %d\n", __func__, error); + return (error); + } if (bus_width == 8) { volatile uint8_t *task_file = (volatile uint8_t*)base_addr; @@ -270,6 +284,7 @@ static void cf_cmd_read (uint32_t nr_sectors, uint32_t start_sector, void *buf) #ifdef OCTEON_VISUAL_CF_0 octeon_led_write_char(0, ' '); #endif + return (0); } @@ -279,12 +294,13 @@ static void cf_cmd_read (uint32_t nr_sectors, uint32_t start_sector, void *buf) * * Write nr_sectors to the device starting from start_sector. */ -static void cf_cmd_write (uint32_t nr_sectors, uint32_t start_sector, void *buf) +static int cf_cmd_write (uint32_t nr_sectors, uint32_t start_sector, void *buf) { uint32_t lba; uint32_t count; uint16_t *ptr_16; uint8_t *ptr_8; + int error; //#define OCTEON_VISUAL_CF_1 1 #ifdef OCTEON_VISUAL_CF_1 @@ -295,8 +311,11 @@ static void cf_cmd_write (uint32_t nr_sectors, uint32_t start_sector, void *buf) ptr_16 = (uint16_t*)buf; while (nr_sectors--) { - - cf_send_cmd(lba, CMD_WRITE_SECTOR); + error = cf_send_cmd(lba, CMD_WRITE_SECTOR); + if (error != 0) { + printf("%s: cf_send_cmd(CMD_WRITE_SECTOR) failed: %d\n", __func__, error); + return (error); + } if (bus_width == 8) { volatile uint8_t *task_file; @@ -324,6 +343,7 @@ static void cf_cmd_write (uint32_t nr_sectors, uint32_t start_sector, void *buf) #ifdef OCTEON_VISUAL_CF_1 octeon_led_write_char(1, ' '); #endif + return (0); } @@ -335,10 +355,11 @@ static void cf_cmd_write (uint32_t nr_sectors, uint32_t start_sector, void *buf) * it in the drive_param structure * */ -static void cf_cmd_identify (void) +static int cf_cmd_identify (void) { int count; uint8_t status; + int error; if (bus_width == 8) { volatile uint8_t *task_file; @@ -356,11 +377,11 @@ static void cf_cmd_identify (void) task_file[TF_DRV_HEAD] = 0; task_file[TF_COMMAND] = CMD_IDENTIFY; - cf_wait_busy(); - - for (count = 0; count < SECTOR_SIZE; count++) - drive_param.u.buf[count] = task_file[TF_DATA]; - + error = cf_wait_busy(); + if (error == 0) { + for (count = 0; count < SECTOR_SIZE; count++) + drive_param.u.buf[count] = task_file[TF_DATA]; + } } else { volatile uint16_t *task_file; @@ -374,17 +395,22 @@ static void cf_cmd_identify (void) task_file[TF_CYL_LSB/2] = 0; /* this includes TF_CYL_MSB */ task_file[TF_DRV_HEAD/2] = 0 | (CMD_IDENTIFY<<8); /* this includes TF_COMMAND */ - cf_wait_busy(); - - for (count = 0; count < SECTOR_SIZE; count+=2) { - uint16_t temp; - temp = task_file[TF_DATA]; - - /* endianess will be swapped below */ - drive_param.u.buf[count] = (temp & 0xff); - drive_param.u.buf[count+1] = (temp & 0xff00)>>8; + error = cf_wait_busy(); + if (error == 0) { + for (count = 0; count < SECTOR_SIZE; count+=2) { + uint16_t temp; + temp = task_file[TF_DATA]; + + /* endianess will be swapped below */ + drive_param.u.buf[count] = (temp & 0xff); + drive_param.u.buf[count+1] = (temp & 0xff00)>>8; + } } } + if (error != 0) { + printf("%s: identify failed: %d\n", __func__, error); + return (error); + } cf_swap_ascii(drive_param.u.driveid.model, drive_param.model); @@ -394,6 +420,7 @@ static void cf_cmd_identify (void) drive_param.sec_track = SWAP_SHORT (drive_param.u.driveid.cur_sectors); drive_param.nr_sectors = SWAP_LONG (drive_param.u.driveid.lba_capacity); + return (0); } @@ -404,7 +431,7 @@ static void cf_cmd_identify (void) * Send command to read/write one sector specified by lba. * */ -static void cf_send_cmd (uint32_t lba, uint8_t cmd) +static int cf_send_cmd (uint32_t lba, uint8_t cmd) { uint8_t status; @@ -439,7 +466,7 @@ static void cf_send_cmd (uint32_t lba, uint8_t cmd) } - cf_wait_busy(); + return (cf_wait_busy()); } /* ------------------------------------------------------------------- * @@ -448,12 +475,16 @@ static void cf_send_cmd (uint32_t lba, uint8_t cmd) * * Wait until the drive finishes a given command and data is * ready to be transferred. This is done by repeatedly checking - * the BSY and DRQ bits of the status register. When the controller - * is ready for data transfer, it clears the BSY bit and sets the - * DRQ bit. + * the BSY bit of the status register. When the controller is ready for + * data transfer, it clears the BSY bit and sets the DRQ bit. + * + * If the DF bit is ever set, we return error. * + * This code originally spun on DRQ. If that behavior turns out to be + * necessary, a flag can be added or this function can be called + * repeatedly as long as it is returning ENXIO. */ -static void cf_wait_busy (void) +static int cf_wait_busy (void) { uint8_t status; @@ -469,7 +500,11 @@ static void cf_wait_busy (void) task_file = (volatile uint8_t *)base_addr; status = task_file[TF_STATUS]; - while ((status & STATUS_BSY) == STATUS_BSY || (status & STATUS_DRQ) != STATUS_DRQ ) { + while ((status & STATUS_BSY) == STATUS_BSY) { + if ((status & STATUS_DF) != 0) { + printf("%s: device fault (status=%x)\n", __func__, status); + return (EIO); + } DELAY(WAIT_DELAY); status = task_file[TF_STATUS]; } @@ -478,15 +513,24 @@ static void cf_wait_busy (void) task_file = (volatile uint16_t *)base_addr; status = task_file[TF_STATUS/2]>>8; - while ((status & STATUS_BSY) == STATUS_BSY || (status & STATUS_DRQ) != STATUS_DRQ ) { + while ((status & STATUS_BSY) == STATUS_BSY) { + if ((status & STATUS_DF) != 0) { + printf("%s: device fault (status=%x)\n", __func__, status); + return (EIO); + } DELAY(WAIT_DELAY); status = (uint8_t)(task_file[TF_STATUS/2]>>8); } } + if ((status & STATUS_DRQ) == 0) { + printf("%s: device not ready (status=%x)\n", __func__, status); + return (ENXIO); + } #ifdef OCTEON_VISUAL_CF_2 octeon_led_write_char(2, ' '); #endif + return (0); } /* ------------------------------------------------------------------- * @@ -522,9 +566,7 @@ static int cf_probe (device_t dev) device_set_desc(dev, "Octeon Compact Flash Driver"); - cf_cmd_identify(); - - return (0); + return (cf_cmd_identify()); } /* ------------------------------------------------------------------- * @@ -543,7 +585,6 @@ static void cf_identify (driver_t *drv, device_t parent) int count = 0; octeon_mio_boot_reg_cfgx_t cfg; - if (!octeon_board_real()) return; diff --git a/sys/mips/cavium/octeon_machdep.c b/sys/mips/cavium/octeon_machdep.c index e3f2fbd..f55c7ea 100644 --- a/sys/mips/cavium/octeon_machdep.c +++ b/sys/mips/cavium/octeon_machdep.c @@ -730,8 +730,6 @@ platform_start(__register_t a0, __register_t a1, __register_t a2 __unused, { uint64_t platform_counter_freq; - boothowto |= RB_SINGLE; - /* Initialize pcpu stuff */ mips_pcpu0_init(); mips_timer_early_init(OCTEON_CLOCK_DEFAULT); @@ -873,8 +871,9 @@ int octeon_chip_rev_major = 0, octeon_chip_rev_minor = 0, octeon_chip_type = 0; static octeon_boot_descriptor_t *app_desc_ptr; static cvmx_bootinfo_t *cvmx_desc_ptr; -#define OCTEON_BOARD_TYPE_NONE 0 -#define OCTEON_BOARD_TYPE_SIM 1 +#define OCTEON_BOARD_TYPE_NONE 0 +#define OCTEON_BOARD_TYPE_SIM 1 +#define OCTEON_BOARD_TYPE_CN3010_EVB_HS5 11 #define OCTEON_CLOCK_MIN (100 * 1000 * 1000) #define OCTEON_CLOCK_MAX (800 * 1000 * 1000) @@ -886,11 +885,23 @@ static cvmx_bootinfo_t *cvmx_desc_ptr; int octeon_board_real(void) { - if ((octeon_board_type == OCTEON_BOARD_TYPE_NONE) || - (octeon_board_type == OCTEON_BOARD_TYPE_SIM) || - !octeon_board_rev_major) + switch (octeon_board_type) { + case OCTEON_BOARD_TYPE_NONE: + case OCTEON_BOARD_TYPE_SIM: return 0; - return 1; + case OCTEON_BOARD_TYPE_CN3010_EVB_HS5: + /* + * XXX + * The CAM-0100 identifies itself as type 11, revision 0.0, + * despite its being rather real. Disable the revision check + * for type 11. + */ + return 1; + default: + if (octeon_board_rev_major == 0) + return 0; + return 1; + } } static void diff --git a/sys/mips/cavium/octeon_pcmap_regs.h b/sys/mips/cavium/octeon_pcmap_regs.h index a80c3d4..16dff5b 100644 --- a/sys/mips/cavium/octeon_pcmap_regs.h +++ b/sys/mips/cavium/octeon_pcmap_regs.h @@ -90,350 +90,228 @@ extern struct pcpu *cpuid_to_pcpu[]; #define OCTEON_SYNCW __asm __volatile (".word 0x10f" : : ) #define OCTEON_SYNCWS __asm __volatile (".word 0x14f" : : ) -#if defined(__mips_n32) || defined(__mips_n64) +#if defined(__mips_n64) +#define oct_write64(a, v) (*(volatile uint64_t *)(a) = (uint64_t)(v)) +#define oct_write8_x8(a, v) (*(volatile uint8_t *)(a) = (uint8_t)(v)) -static inline void oct_write64 (uint64_t csr_addr, uint64_t val64) -{ - uint64_t *ptr = (uint64_t *) csr_addr; - *ptr = val64; +#define OCT_READ(n, t) \ +static inline t oct_read ## n(uintptr_t a) \ +{ \ + volatile t *p = (volatile t *)a; \ + return (*p); \ } -static inline void oct_write64_int64 (uint64_t csr_addr, int64_t val64i) -{ - int64_t *ptr = (int64_t *) csr_addr; - *ptr = val64i; -} +OCT_READ(8, uint8_t); +OCT_READ(16, uint16_t); +OCT_READ(32, uint32_t); +OCT_READ(64, uint64_t); -static inline void oct_write8_x8 (uint64_t csr_addr, uint8_t val8) +#elif defined(__mips_n32) || defined(__mips_o32) +#if defined(__mips_n32) +static inline void oct_write64 (uint64_t csr_addr, uint64_t val64) { - uint64_t *ptr = (uint64_t *) csr_addr; - *ptr = (uint64_t) val8; + __asm __volatile ( + ".set push\n" + ".set mips64\n" + "sd %0, 0(%1)\n" + ".set pop\n" + : + : "r"(val64), "r"(csr_addr)); } -static inline void oct_write8 (uint64_t csr_addr, uint8_t val8) +static inline void oct_write8_x8 (uint64_t csr_addr, uint8_t val8) { - oct_write64(csr_addr, (uint64_t) val8); -} + __asm __volatile ( + ".set push\n" + ".set mips64\n" + "sb %0, 0(%1)\n" + ".set pop\n" + : + : "r"(val8), "r"(csr_addr)); +} + +#define OCT_READ(n, t, insn) \ +static inline t oct_read ## n(uint64_t a) \ +{ \ + uint64_t tmp; \ + \ + __asm __volatile ( \ + ".set push\n" \ + ".set mips64\n" \ + insn "\t%0, 0(%1)\n" \ + ".set pop\n" \ + : "=r"(tmp) \ + : "r"(a)); \ + return ((t)tmp); \ +} + +OCT_READ(8, uint8_t, "lb"); +OCT_READ(16, uint16_t, "lh"); +OCT_READ(32, uint32_t, "lw"); +OCT_READ(64, uint64_t, "ld"); +#else -static inline void oct_write16 (uint64_t csr_addr, uint16_t val16) +/* + * XXX + * Add o32 variants that load the address into a register and the result out + * of a register properly, and simply disable interrupts before and after and + * hope that we don't need to refill or modify the TLB to access the address. + * I'd be a lot happier if csr_addr were a physical address and we mapped it + * into XKPHYS here so that we could guarantee that interrupts were the only + * kind of exception we needed to worry about. + * + * Also, some of this inline assembly is needlessly verbose. Oh, well. + */ +static inline void oct_write64 (uint64_t csr_addr, uint64_t val64) { - oct_write64(csr_addr, (uint64_t) val16); -} + uint32_t csr_addrh = csr_addr >> 32; + uint32_t csr_addrl = csr_addr; + uint32_t valh = val64 >> 32; + uint32_t vall = val64; + uint32_t tmp1; + uint32_t tmp2; + uint32_t tmp3; + register_t sr; -static inline void oct_write32 (uint64_t csr_addr, uint32_t val32) -{ - oct_write64(csr_addr, (uint64_t) val32); -} + sr = intr_disable(); -static inline uint8_t oct_read8 (uint64_t csr_addr) -{ - uint8_t *ptr = (uint8_t *) csr_addr; - return (*ptr); + __asm __volatile ( + ".set push\n" + ".set mips64\n" + ".set noreorder\n" + ".set noat\n" + "dsll %0, %3, 32\n" + "dsll %1, %5, 32\n" + "dsll %2, %4, 32\n" + "dsrl %2, %2, 32\n" + "or %0, %0, %2\n" + "dsll %2, %6, 32\n" + "dsrl %2, %2, 32\n" + "or %1, %1, %2\n" + "sd %0, 0(%1)\n" + ".set pop\n" + : "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3) + : "r" (valh), "r" (vall), "r" (csr_addrh), "r" (csr_addrl)); + + intr_restore(sr); } -static inline uint8_t oct_read16 (uint64_t csr_addr) +static inline void oct_write8_x8 (uint64_t csr_addr, uint8_t val8) { - uint16_t *ptr = (uint16_t *) csr_addr; - return (*ptr); -} + uint32_t csr_addrh = csr_addr >> 32; + uint32_t csr_addrl = csr_addr; + uint32_t tmp1; + uint32_t tmp2; + register_t sr; + sr = intr_disable(); -static inline uint32_t oct_read32 (uint64_t csr_addr) -{ - uint32_t *ptr = (uint32_t *) csr_addr; - return (*ptr); -} + __asm __volatile ( + ".set push\n" + ".set mips64\n" + ".set noreorder\n" + ".set noat\n" + "dsll %0, %3, 32\n" + "dsll %1, %4, 32\n" + "dsrl %1, %1, 32\n" + "or %0, %0, %1\n" + "sb %2, 0(%0)\n" + ".set pop\n" + : "=&r" (tmp1), "=&r" (tmp2) + : "r" (val8), "r" (csr_addrh), "r" (csr_addrl)); + + intr_restore(sr); +} + +#define OCT_READ(n, t, insn) \ +static inline t oct_read ## n(uint64_t csr_addr) \ +{ \ + uint32_t csr_addrh = csr_addr >> 32; \ + uint32_t csr_addrl = csr_addr; \ + uint32_t tmp1, tmp2; \ + register_t sr; \ + \ + sr = intr_disable(); \ + \ + __asm __volatile ( \ + ".set push\n" \ + ".set mips64\n" \ + ".set noreorder\n" \ + ".set noat\n" \ + "dsll %1, %2, 32\n" \ + "dsll %0, %3, 32\n" \ + "dsrl %0, %0, 32\n" \ + "or %1, %1, %0\n" \ + "lb %1, 0(%1)\n" \ + ".set pop\n" \ + : "=&r" (tmp1), "=&r" (tmp2) \ + : "r" (csr_addrh), "r" (csr_addrl)); \ + \ + intr_restore(sr); \ + \ + return ((t)tmp2); \ +} + +OCT_READ(8, uint8_t, "lb"); +OCT_READ(16, uint16_t, "lh"); +OCT_READ(32, uint32_t, "lw"); static inline uint64_t oct_read64 (uint64_t csr_addr) { - uint64_t *ptr = (uint64_t *) csr_addr; - return (*ptr); -} - -static inline int32_t oct_readint32 (uint64_t csr_addr) -{ - int32_t *ptr = (int32_t *) csr_addr; - return (*ptr); -} - - - -#else - - -/* ABI o32 */ - - -/* - * Read/write functions - */ -static inline void oct_write64 (uint64_t csr_addr, uint64_t val64) -{ - uint32_t csr_addrh = csr_addr >> 32; - uint32_t csr_addrl = csr_addr; - uint32_t valh = (uint64_t)val64 >> 32; - uint32_t vall = val64; - uint32_t tmp1; - uint32_t tmp2; - uint32_t tmp3; + uint32_t csr_addrh = csr_addr >> 32; + uint32_t csr_addrl = csr_addr; + uint32_t valh; + uint32_t vall; + register_t sr; - __asm __volatile ( - ".set mips64\n" - "dsll %0, %3, 32\n" - "dsll %1, %5, 32\n" - "dsll %2, %4, 32\n" - "dsrl %2, %2, 32\n" - "or %0, %0, %2\n" - "dsll %2, %6, 32\n" - "dsrl %2, %2, 32\n" - "or %1, %1, %2\n" - "sd %0, 0(%1)\n" - ".set mips0\n" - : "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3) - : "r" (valh), "r" (vall), - "r" (csr_addrh), "r" (csr_addrl) - ); -} - -static inline void oct_write64_int64 (uint64_t csr_addr, int64_t val64i) -{ - uint32_t csr_addrh = csr_addr >> 32; - uint32_t csr_addrl = csr_addr; - int32_t valh = (uint64_t)val64i >> 32; - int32_t vall = val64i; - uint32_t tmp1; - uint32_t tmp2; - uint32_t tmp3; + sr = intr_disable(); - __asm __volatile ( + __asm __volatile ( + ".set push\n" ".set mips64\n" - "dsll %0, %3, 32\n" - "dsll %1, %5, 32\n" - "dsll %2, %4, 32\n" - "dsrl %2, %2, 32\n" - "or %0, %0, %2\n" - "dsll %2, %6, 32\n" - "dsrl %2, %2, 32\n" - "or %1, %1, %2\n" - "sd %0, 0(%1)\n" - ".set mips0\n" - : "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3) - : "r" (valh), "r" (vall), - "r" (csr_addrh), "r" (csr_addrl) - ); + ".set noreorder\n" + ".set noat\n" + "dsll %0, %2, 32\n" + "dsll %1, %3, 32\n" + "dsrl %1, %1, 32\n" + "or %0, %0, %1\n" + "ld %1, 0(%0)\n" + "dsrl %0, %1, 32\n" + "dsll %1, %1, 32\n" + "dsrl %1, %1, 32\n" + ".set pop\n" + : "=&r" (valh), "=&r" (vall) + : "r" (csr_addrh), "r" (csr_addrl)); + + intr_restore(sr); + + return ((uint64_t)valh << 32) | vall; } +#endif +#endif -/* - * oct_write8_x8 - * - * 8 bit data write into IO Space. Written using an 8 bit bus io transaction - */ -static inline void oct_write8_x8 (uint64_t csr_addr, uint8_t val8) -{ - uint32_t csr_addrh = csr_addr>>32; - uint32_t csr_addrl = csr_addr; - uint32_t tmp1; - uint32_t tmp2; - - __asm __volatile ( - ".set mips64\n" - "dsll %0, %3, 32\n" - "dsll %1, %4, 32\n" - "dsrl %1, %1, 32\n" - "or %0, %0, %1\n" - "sb %2, 0(%0)\n" - ".set mips0\n" - : "=&r" (tmp1), "=&r" (tmp2) - : "r" (val8), "r" (csr_addrh), "r" (csr_addrl) ); -} +#define oct_write64_int64(a, v) (oct_write64(a, (int64_t)(v))) /* - * oct_write8 - * - * 8 bit data write into IO Space. Written using a 64 bit bus io transaction + * Most write bus transactions are actually 64-bit on Octeon. */ static inline void oct_write8 (uint64_t csr_addr, uint8_t val8) { -#if 1 oct_write64(csr_addr, (uint64_t) val8); -#else - - uint32_t csr_addrh = csr_addr>>32; - uint32_t csr_addrl = csr_addr; - uint32_t tmp1; - uint32_t tmp2; - - __asm __volatile ( - ".set mips64\n" - "dsll %0, %3, 32\n" - "dsll %1, %4, 32\n" - "dsrl %1, %1, 32\n" - "or %0, %0, %1\n" - "sb %2, 0(%0)\n" - ".set mips0\n" - : "=&r" (tmp1), "=&r" (tmp2) - : "r" (val8), "r" (csr_addrh), "r" (csr_addrl) ); -#endif } static inline void oct_write16 (uint64_t csr_addr, uint16_t val16) { -#if 1 oct_write64(csr_addr, (uint64_t) val16); - -#else - uint32_t csr_addrh = csr_addr>>32; - uint32_t csr_addrl = csr_addr; - uint32_t tmp1; - uint32_t tmp2; - - __asm __volatile ( - ".set mips64\n" - "dsll %0, %3, 32\n" - "dsll %1, %4, 32\n" - "dsrl %1, %1, 32\n" - "or %0, %0, %1\n" - "sh %2, 0(%0)\n" - ".set mips0\n" - : "=&r" (tmp1), "=&r" (tmp2) - : "r" (val16), "r" (csr_addrh), "r" (csr_addrl) ); -#endif } static inline void oct_write32 (uint64_t csr_addr, uint32_t val32) { -#if 1 oct_write64(csr_addr, (uint64_t) val32); -#else - - uint32_t csr_addrh = csr_addr>>32; - uint32_t csr_addrl = csr_addr; - uint32_t tmp1; - uint32_t tmp2; - - __asm __volatile ( - ".set mips64\n" - "dsll %0, %3, 32\n" - "dsll %1, %4, 32\n" - "dsrl %1, %1, 32\n" - "or %0, %0, %1\n" - "sw %2, 0(%0)\n" - ".set mips0\n" - : "=&r" (tmp1), "=&r" (tmp2) - : "r" (val32), "r" (csr_addrh), "r" (csr_addrl) ); -#endif -} - - - -static inline uint8_t oct_read8 (uint64_t csr_addr) -{ - uint32_t csr_addrh = csr_addr>>32; - uint32_t csr_addrl = csr_addr; - uint32_t tmp1, tmp2; - - __asm __volatile ( - ".set mips64\n" - "dsll %1, %2, 32\n" - "dsll %0, %3, 32\n" - "dsrl %0, %0, 32\n" - "or %1, %1, %0\n" - "lb %1, 0(%1)\n" - ".set mips0\n" - : "=&r" (tmp1), "=&r" (tmp2) - : "r" (csr_addrh), "r" (csr_addrl) ); - return ((uint8_t) tmp2); -} - -static inline uint8_t oct_read16 (uint64_t csr_addr) -{ - uint32_t csr_addrh = csr_addr>>32; - uint32_t csr_addrl = csr_addr; - uint32_t tmp1, tmp2; - - __asm __volatile ( - ".set mips64\n" - "dsll %1, %2, 32\n" - "dsll %0, %3, 32\n" - "dsrl %0, %0, 32\n" - "or %1, %1, %0\n" - "lh %1, 0(%1)\n" - ".set mips0\n" - : "=&r" (tmp1), "=&r" (tmp2) - : "r" (csr_addrh), "r" (csr_addrl) ); - return ((uint16_t) tmp2); -} - - -static inline uint32_t oct_read32 (uint64_t csr_addr) -{ - uint32_t csr_addrh = csr_addr>>32; - uint32_t csr_addrl = csr_addr; - uint32_t val32; - uint32_t tmp; - - __asm __volatile ( - ".set mips64\n" - "dsll %0, %2, 32\n" - "dsll %1, %3, 32\n" - "dsrl %1, %1, 32\n" - "or %0, %0, %1\n" - "lw %0, 0(%0)\n" - ".set mips0\n" - : "=&r" (val32), "=&r" (tmp) - : "r" (csr_addrh), "r" (csr_addrl) ); - return (val32); -} - - -static inline uint64_t oct_read64 (uint64_t csr_addr) -{ - uint32_t csr_addrh = csr_addr >> 32; - uint32_t csr_addrl = csr_addr; - uint32_t valh; - uint32_t vall; - - __asm __volatile ( - ".set mips64\n" - "dsll %0, %2, 32\n" - "dsll %1, %3, 32\n" - "dsrl %1, %1, 32\n" - "or %0, %0, %1\n" - "ld %1, 0(%0)\n" - "dsrl %0, %1, 32\n" - "dsll %1, %1, 32\n" - "dsrl %1, %1, 32\n" - ".set mips0\n" - : "=&r" (valh), "=&r" (vall) - : "r" (csr_addrh), "r" (csr_addrl) - ); - return ((uint64_t)valh << 32) | vall; } - -static inline int32_t oct_readint32 (uint64_t csr_addr) -{ - uint32_t csr_addrh = csr_addr>>32; - uint32_t csr_addrl = csr_addr; - int32_t val32; - uint32_t tmp; - - __asm __volatile ( - ".set mips64\n" - "dsll %0, %2, 32\n" - "dsll %1, %3, 32\n" - "dsrl %1, %1, 32\n" - "or %0, %0, %1\n" - "lw %0, 0(%0)\n" - : "=&r" (val32), "=&r" (tmp) - : "r" (csr_addrh), "r" (csr_addrl) ); - return (val32); -} - - -#endif - +#define oct_readint32(a) ((int32_t)oct_read32((a))) #define OCTEON_HW_BASE ((volatile uint64_t *) 0L) #define OCTEON_REG_OFFSET (-4 * 1024ll) /* local scratchpad reg base */ @@ -589,7 +467,7 @@ typedef enum { /* PTR_SIZE == sizeof(uint32_t) */ -#ifdef ISA_MIPS32 +#if defined(__mips_n32) || defined(__mips_o32) #define mipsx_addr_size uint32_t // u_int64 #define MIPSX_ADDR_SIZE_KSEGX_BIT_SHIFT 30 // 62 #define MIPSX_ADDR_SIZE_KSEGX_MASK_REMOVED 0x1fffffff // 0x1fffffff diff --git a/sys/mips/conf/AR71XX b/sys/mips/conf/AR71XX index 30126bf..4ee6aab 100644 --- a/sys/mips/conf/AR71XX +++ b/sys/mips/conf/AR71XX @@ -15,7 +15,7 @@ files "../atheros/files.ar71xx" hints "AR71XX.hints" makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols -makeoptions MODULES_OVERRIDE="" +#makeoptions MODULES_OVERRIDE="" options DDB options KDB @@ -67,10 +67,11 @@ device ath_rate_sample device mii device arge -# device usb -# options USB_EHCI_BIG_ENDIAN_DESC # handle big-endian byte order +device usb +options USB_EHCI_BIG_ENDIAN_DESC # handle big-endian byte order # options USB_DEBUG -# device ehci +device ohci +device ehci device spibus device ar71xx_spi diff --git a/sys/mips/conf/OCTEON1 b/sys/mips/conf/OCTEON1 index b326823..c8597dc 100644 --- a/sys/mips/conf/OCTEON1 +++ b/sys/mips/conf/OCTEON1 @@ -81,6 +81,8 @@ nodevice uart_ns8250 device rgmii #options VERBOSE_SYSINIT +device bpf +device random # # Use the following for Compact Flash file-system diff --git a/sys/mips/conf/OCTEON1-32 b/sys/mips/conf/OCTEON1-32 index 7962a06..870a141 100644 --- a/sys/mips/conf/OCTEON1-32 +++ b/sys/mips/conf/OCTEON1-32 @@ -70,6 +70,8 @@ nodevice uart_ns8250 device rgmii #options VERBOSE_SYSINIT +device bpf +device random # # Use the following for Compact Flash file-system diff --git a/sys/mips/include/bus.h b/sys/mips/include/bus.h index ccaeb34..2ab347b 100644 --- a/sys/mips/include/bus.h +++ b/sys/mips/include/bus.h @@ -713,6 +713,8 @@ void __bs_c(f,_bs_c_8) (void *t, bus_space_handle_t bsh1, \ #define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF #define BUS_SPACE_MAXSIZE 0xFFFFFFFF +#define BUS_SPACE_UNRESTRICTED (~0) + /* * declare generic bus space, it suits all needs in */ diff --git a/sys/mips/include/clock.h b/sys/mips/include/clock.h index 62b5112..7dbf4ab 100644 --- a/sys/mips/include/clock.h +++ b/sys/mips/include/clock.h @@ -34,6 +34,14 @@ void mips_timer_init_params(uint64_t, int); extern uint64_t counter_freq; extern int clocks_running; +/* + * The 'platform_timecounter' pointer may be used to register a + * platform-specific timecounter. + * + * A default timecounter based on the CP0 COUNT register is always registered. + */ +extern struct timecounter *platform_timecounter; + #endif #endif /* !_MACHINE_CLOCK_H_ */ diff --git a/sys/mips/include/cpu.h b/sys/mips/include/cpu.h index 5a1cb9d..1ec1cfc 100644 --- a/sys/mips/include/cpu.h +++ b/sys/mips/include/cpu.h @@ -50,22 +50,8 @@ #include <machine/psl.h> #include <machine/endian.h> -#define MIPS_CACHED_MEMORY_ADDR 0x80000000 -#define MIPS_UNCACHED_MEMORY_ADDR 0xa0000000 -#define MIPS_MAX_MEM_ADDR 0xbe000000 -#define MIPS_RESERVED_ADDR 0xbfc80000 - #define MIPS_KSEG0_LARGEST_PHYS 0x20000000 -#define MIPS_CACHED_TO_PHYS(x) ((uintptr_t)(x) & 0x1fffffff) -#define MIPS_PHYS_TO_CACHED(x) ((uintptr_t)(x) | MIPS_CACHED_MEMORY_ADDR) -#define MIPS_UNCACHED_TO_PHYS(x) ((uintptr_t)(x) & 0x1fffffff) -#define MIPS_PHYS_TO_UNCACHED(x) ((uintptr_t)(x) | MIPS_UNCACHED_MEMORY_ADDR) - #define MIPS_PHYS_MASK (0x1fffffff) -#define MIPS_PA_2_K1VA(x) (MIPS_KSEG1_START | ((x) & MIPS_PHYS_MASK)) - -#define MIPS_VA_TO_CINDEX(x) ((uintptr_t)(x) & 0xffffff | MIPS_CACHED_MEMORY_ADDR) -#define MIPS_CACHED_TO_UNCACHED(x) (MIPS_PHYS_TO_UNCACHED(MIPS_CACHED_TO_PHYS(x))) #define MIPS_PHYS_TO_KSEG0(x) ((uintptr_t)(x) | MIPS_KSEG0_START) #define MIPS_PHYS_TO_KSEG1(x) ((uintptr_t)(x) | MIPS_KSEG1_START) diff --git a/sys/mips/include/cpufunc.h b/sys/mips/include/cpufunc.h index d4ca0f1..f9100ea 100644 --- a/sys/mips/include/cpufunc.h +++ b/sys/mips/include/cpufunc.h @@ -283,6 +283,35 @@ breakpoint(void) __asm __volatile ("break"); } +#if defined(__GNUC__) && !defined(__mips_o32) +static inline uint64_t +mips3_ld(const volatile uint64_t *va) +{ + uint64_t rv; + +#if defined(_LP64) + rv = *va; +#else + __asm volatile("ld %0,0(%1)" : "=d"(rv) : "r"(va)); +#endif + + return (rv); +} + +static inline void +mips3_sd(volatile uint64_t *va, uint64_t v) +{ +#if defined(_LP64) + *va = v; +#else + __asm volatile("sd %0,0(%1)" :: "r"(v), "r"(va)); +#endif +} +#else +uint64_t mips3_ld(volatile uint64_t *va); +void mips3_sd(volatile uint64_t *, uint64_t); +#endif /* __GNUC__ */ + #endif /* _KERNEL */ #define readb(va) (*(volatile uint8_t *) (va)) diff --git a/sys/mips/include/cpuregs.h b/sys/mips/include/cpuregs.h index f1f2485..74e789c 100644 --- a/sys/mips/include/cpuregs.h +++ b/sys/mips/include/cpuregs.h @@ -89,12 +89,6 @@ #define MIPS_KSEG2_END MIPS_KSSEG_END #define MIPS_KSEG3_START 0xe0000000 #define MIPS_KSEG3_END 0xffffffff -#define MIPS_MAX_MEM_ADDR 0xbe000000 -#define MIPS_RESERVED_ADDR 0xbfc80000 - -/* Map virtual address to index in mips3 r4k virtually-indexed cache */ -#define MIPS3_VA_TO_CINDEX(x) \ - ((unsigned)(x) & 0xffffff | MIPS_KSEG0_START) #define MIPS_PHYS_TO_XKPHYS(cca,x) \ ((0x2ULL << 62) | ((unsigned long long)(cca) << 59) | (x)) @@ -583,6 +577,8 @@ #define MIPS_CONFIG1_TLBSZ_MASK 0x7E000000 /* bits 30..25 # tlb entries minus one */ #define MIPS_CONFIG1_TLBSZ_SHIFT 25 +#define MIPS_MAX_TLB_ENTRIES 64 + #define MIPS_CONFIG1_IS_MASK 0x01C00000 /* bits 24..22 icache sets per way */ #define MIPS_CONFIG1_IS_SHIFT 22 #define MIPS_CONFIG1_IL_MASK 0x00380000 /* bits 21..19 icache line size */ diff --git a/sys/mips/include/db_machdep.h b/sys/mips/include/db_machdep.h index ea97120..d7bf69a 100644 --- a/sys/mips/include/db_machdep.h +++ b/sys/mips/include/db_machdep.h @@ -92,7 +92,6 @@ db_addr_t next_instr_address(db_addr_t, boolean_t); #define DB_SMALL_VALUE_MIN (-0x400001) int db_inst_type(int); -void db_dump_tlb(int, int); db_addr_t branch_taken(int inst, db_addr_t pc); void stacktrace_subr(register_t pc, register_t sp, register_t ra, int (*)(const char *, ...)); int kdbpeek(int *); diff --git a/sys/mips/include/kdb.h b/sys/mips/include/kdb.h index cd8c618..6ca6654 100644 --- a/sys/mips/include/kdb.h +++ b/sys/mips/include/kdb.h @@ -32,6 +32,8 @@ #include <machine/frame.h> +#define KDB_STOPPEDPCB(pc) &stoppcbs[pc->pc_cpuid] + static __inline void kdb_cpu_clear_singlestep(void) { diff --git a/sys/mips/include/param.h b/sys/mips/include/param.h index 8edd48e..9d48702 100644 --- a/sys/mips/include/param.h +++ b/sys/mips/include/param.h @@ -128,14 +128,13 @@ #define MAXDUMPPGS 1 /* xxx: why is this only one? */ /* - * NOTE: In FreeBSD, Uarea's don't have a fixed address. - * Therefore, any code imported from OpenBSD which depends on - * UADDR, UVPN and KERNELSTACK requires porting. - * XXX: 3 stack pages? Not 4 which would be more efficient from a tlb - * XXX: point of view. + * The kernel stack needs to be aligned on a (PAGE_SIZE * 2) boundary. + * + * Although we allocate 3 pages for the kernel stack we end up using + * only the 2 pages that are aligned on a (PAGE_SIZE * 2) boundary. */ #define KSTACK_PAGES 3 /* kernel stack*/ -#define KSTACK_GUARD_PAGES 0 /* pages of kstack guard; 0 disables */ +#define KSTACK_GUARD_PAGES 1 /* pages of kstack guard; 0 disables */ #define UPAGES 2 diff --git a/sys/mips/include/pmap.h b/sys/mips/include/pmap.h index eedd4f3..51ff551 100644 --- a/sys/mips/include/pmap.h +++ b/sys/mips/include/pmap.h @@ -219,6 +219,11 @@ pmap_map_fpage(vm_paddr_t pa, struct fpage *fp, boolean_t check_unmaped); void pmap_unmap_fpage(vm_paddr_t pa, struct fpage *fp); +/* + * Function to save TLB contents so that they may be inspected in the debugger. + */ +extern void pmap_save_tlb(void); + #endif /* _KERNEL */ #endif /* !LOCORE */ diff --git a/sys/mips/include/smp.h b/sys/mips/include/smp.h index 346c863..1cb0596 100644 --- a/sys/mips/include/smp.h +++ b/sys/mips/include/smp.h @@ -17,6 +17,8 @@ #ifdef _KERNEL +#include <machine/pcb.h> + /* * Interprocessor interrupts for SMP. */ @@ -31,6 +33,8 @@ void ipi_selected(cpumask_t cpus, int ipi); void smp_init_secondary(u_int32_t cpuid); void mpentry(void); +extern struct pcb stoppcbs[]; + #endif /* !LOCORE */ #endif /* _KERNEL */ diff --git a/sys/mips/include/trap.h b/sys/mips/include/trap.h index 1c6be30..f382e70 100644 --- a/sys/mips/include/trap.h +++ b/sys/mips/include/trap.h @@ -111,11 +111,10 @@ void trapDump(char *msg); void MipsFPTrap(u_int, u_int, u_int); void MipsKernGenException(void); void MipsKernIntr(void); -void MipsKernTLBInvalidException(void); +void MipsTLBInvalidException(void); void MipsTLBMissException(void); void MipsUserGenException(void); void MipsUserIntr(void); -void MipsUserTLBInvalidException(void); u_int trap(struct trapframe *); diff --git a/sys/mips/mips/busdma_machdep.c b/sys/mips/mips/busdma_machdep.c index f2d41df..a6a7419 100644 --- a/sys/mips/mips/busdma_machdep.c +++ b/sys/mips/mips/busdma_machdep.c @@ -687,16 +687,21 @@ _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, pmap_t pmap, * Count the number of bounce pages * needed in order to complete this transfer */ - vaddr = trunc_page((vm_offset_t)buf); + vaddr = (vm_offset_t)buf; vendaddr = (vm_offset_t)buf + buflen; while (vaddr < vendaddr) { + bus_size_t sg_len; + KASSERT(kernel_pmap == pmap, ("pmap is not kernel pmap")); + sg_len = PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK); paddr = pmap_kextract(vaddr); if (((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) && - run_filter(dmat, paddr) != 0) + run_filter(dmat, paddr) != 0) { + sg_len = roundup2(sg_len, dmat->alignment); map->pagesneeded++; - vaddr += PAGE_SIZE; + } + vaddr += sg_len; } CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); } diff --git a/sys/mips/mips/db_trace.c b/sys/mips/mips/db_trace.c index 4eadc25..9417bcc 100644 --- a/sys/mips/mips/db_trace.c +++ b/sys/mips/mips/db_trace.c @@ -162,13 +162,16 @@ loop: subr = (uintptr_t)MipsUserGenException; else if (pcBetween(MipsKernIntr, MipsUserIntr)) subr = (uintptr_t)MipsKernIntr; - else if (pcBetween(MipsUserIntr, MipsKernTLBInvalidException)) + else if (pcBetween(MipsUserIntr, MipsTLBInvalidException)) subr = (uintptr_t)MipsUserIntr; - else if (pcBetween(MipsKernTLBInvalidException, - MipsUserTLBInvalidException)) - subr = (uintptr_t)MipsKernTLBInvalidException; - else if (pcBetween(MipsUserTLBInvalidException, MipsTLBMissException)) - subr = (uintptr_t)MipsUserTLBInvalidException; + else if (pcBetween(MipsTLBInvalidException, MipsTLBMissException)) + subr = (uintptr_t)MipsTLBInvalidException; + else if (pcBetween(fork_trampoline, savectx)) + subr = (uintptr_t)fork_trampoline; + else if (pcBetween(savectx, mips_cpu_throw)) + subr = (uintptr_t)savectx; + else if (pcBetween(mips_cpu_throw, cpu_switch)) + subr = (uintptr_t)cpu_throw; else if (pcBetween(cpu_switch, MipsSwitchFPState)) subr = (uintptr_t)cpu_switch; else if (pcBetween(_locore, _locoreEnd)) { @@ -412,10 +415,8 @@ db_trace_thread(struct thread *thr, int count) : "=r" (pc) : "r" (ra)); - } - - else { - ctx = thr->td_pcb; + } else { + ctx = kdb_thr_ctx(thr); sp = (register_t)ctx->pcb_context[PREG_SP]; pc = (register_t)ctx->pcb_context[PREG_PC]; ra = (register_t)ctx->pcb_context[PREG_RA]; diff --git a/sys/mips/mips/exception.S b/sys/mips/mips/exception.S index 02edcde..161e947 100644 --- a/sys/mips/mips/exception.S +++ b/sys/mips/mips/exception.S @@ -264,13 +264,13 @@ SlowFault: mfc0 a0, COP_0_STATUS_REG ;\ li a2, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX) ; \ or a0, a0, a2 ; \ - li a2, ~(MIPS_SR_INT_IE|MIPS_SR_EXL) ; \ + li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | SR_KSU_USER) ; \ and a0, a0, a2 ; \ mtc0 a0, COP_0_STATUS_REG #else #define CLEAR_STATUS \ mfc0 a0, COP_0_STATUS_REG ;\ - li a2, ~(MIPS_SR_INT_IE|MIPS_SR_EXL) ; \ + li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | SR_KSU_USER) ; \ and a0, a0, a2 ; \ mtc0 a0, COP_0_STATUS_REG #endif @@ -827,177 +827,168 @@ NNON_LEAF(MipsUserIntr, STAND_FRAME_SIZE, ra) .set at END(MipsUserIntr) -NLEAF(MipsKernTLBInvalidException) - .set noat - mfc0 k0, COP_0_BAD_VADDR # get the fault address - +NLEAF(MipsTLBInvalidException) + .set push + .set noat + .set noreorder + mfc0 k0, COP_0_BAD_VADDR li k1, VM_MAXUSER_ADDRESS sltu k1, k0, k1 - beqz k1, 1f - nop - GET_CPU_PCPU(k1) - lw k1, PC_SEGBASE(k1) # works for single cpu???? - beqz k1, _C_LABEL(MipsKernGenException) # seg tab is null + bnez k1, 1f nop + + /* badvaddr = kernel address */ + lui k1, %hi(_C_LABEL(kernel_segmap)) b 2f - nop + lw k1, %lo(_C_LABEL(kernel_segmap))(k1) + 1: - li k1, (VM_MAX_KERNEL_ADDRESS) - bgez k0, _C_LABEL(MipsKernGenException) # full trap processing - sltu k1, k1, k0 # check fault address against - bnez k1, _C_LABEL(MipsKernGenException) # kernel_segmap upper bound - lui k1, %hi(_C_LABEL(kernel_segmap)) # k1=hi of segbase - lw k1, %lo(_C_LABEL(kernel_segmap))(k1) # k1=segment tab base - beqz k1, _C_LABEL(MipsKernGenException) # seg tab is null + /* badvaddr = user address */ + GET_CPU_PCPU(k1) + lw k1, PC_SEGBASE(k1) + 2: - srl k0, 20 # k0=seg offset (almost) - andi k0, k0, 0xffc # k0=seg offset (mask 0x3) -#xxx mips64 unsafe? - addu k1, k0, k1 # k1=seg entry address - lw k1, 0(k1) # k1=seg entry - mfc0 k0, COP_0_BAD_VADDR # k0=bad address (again) - beq k1, zero, _C_LABEL(MipsKernGenException) # ==0 -- no page table - srl k0, k0, PGSHIFT-2 - andi k0, k0, 0xffc # compute offset from index - tlbp # Probe the invalid entry -#xxx mips64 unsafe? + beqz k1, 3f /* invalid page directory pointer */ + nop + + srl k0, SEGSHIFT - 2 + andi k0, 0xffc addu k1, k1, k0 - and k0, k0, 4 # check even/odd page - nop # required for QED 5230 - bne k0, zero, KernTLBIOdd + lw k1, 0(k1) + beqz k1, 3f /* invalid page table page pointer */ nop - mfc0 k0, COP_0_TLB_INDEX + mfc0 k0, COP_0_BAD_VADDR + srl k0, PGSHIFT - 2 + andi k0, 0xffc + addu k1, k1, k0 + + lw k0, 0(k1) + andi k0, PTE_V + beqz k0, 3f /* invalid page table entry */ nop - bltz k0, sys_stk_chk - sltiu k0, k0, VMWIRED_ENTRIES # index below wired entries? - bne k0, zero, sys_stk_chk - lw k0, 0(k1) # get PTE entry + andi k0, k1, 4 + bnez k0, odd_page + nop - _SLL k0, k0, WIRED_SHIFT # get rid of "wired" bit +even_page: + lw k0, 0(k1) + _SLL k0, k0, WIRED_SHIFT _SRL k0, k0, WIRED_SHIFT - _MTC0 k0, COP_0_TLB_LO0 # load PTE entry - and k0, k0, PTE_V # check for valid entry - nop # required for QED5230 - beq k0, zero, _C_LABEL(MipsKernGenException) # PTE invalid - lw k0, 4(k1) # get odd PTE entry + _MTC0 k0, COP_0_TLB_LO0 + + lw k0, 4(k1) _SLL k0, k0, WIRED_SHIFT _SRL k0, k0, WIRED_SHIFT - _MTC0 k0, COP_0_TLB_LO1 # load PTE entry - HAZARD_DELAY - tlbwi # write TLB - HAZARD_DELAY - eret + _MTC0 k0, COP_0_TLB_LO1 -KernTLBIOdd: - mfc0 k0, COP_0_TLB_INDEX + b tlb_insert_entry nop - bltz k0, sys_stk_chk - sltiu k0, k0, VMWIRED_ENTRIES # index below wired entries? - bne k0, zero, sys_stk_chk - lw k0, 0(k1) # get PTE entry - - _SLL k0, k0, WIRED_SHIFT # get rid of wired bit +odd_page: + lw k0, 0(k1) + _SLL k0, k0, WIRED_SHIFT _SRL k0, k0, WIRED_SHIFT - _MTC0 k0, COP_0_TLB_LO1 # save PTE entry - and k0, k0, PTE_V # check for valid entry - nop # required for QED5230 - beq k0, zero, _C_LABEL(MipsKernGenException) # PTE invalid - lw k0, -4(k1) # get even PTE entry + _MTC0 k0, COP_0_TLB_LO1 + + lw k0, -4(k1) _SLL k0, k0, WIRED_SHIFT _SRL k0, k0, WIRED_SHIFT - _MTC0 k0, COP_0_TLB_LO0 # save PTE entry + _MTC0 k0, COP_0_TLB_LO0 + +tlb_insert_entry: + tlbp HAZARD_DELAY - tlbwi # update TLB + mfc0 k0, COP_0_TLB_INDEX HAZARD_DELAY + bltz k0, tlb_insert_random + nop + tlbwi eret + ssnop - .set at -END(MipsKernTLBInvalidException) - - -NLEAF(MipsUserTLBInvalidException) - .set noat - mfc0 k0, COP_0_BAD_VADDR # get the fault address +tlb_insert_random: + tlbwr + eret + ssnop - li k1, VM_MAXUSER_ADDRESS - sltu k1, k0, k1 - beqz k1, _C_LABEL(MipsUserGenException) +3: + /* + * Branch to the comprehensive exception processing. + */ + mfc0 k1, COP_0_STATUS_REG + andi k1, k1, SR_KSU_USER + bnez k1, _C_LABEL(MipsUserGenException) nop + + /* + * Check for kernel stack overflow. + */ GET_CPU_PCPU(k1) - lw k1, PC_SEGBASE(k1) # works for single cpu???? - beqz k1, _C_LABEL(MipsUserGenException) # seg tab is null - nop -2: - srl k0, 20 # k0=seg offset (almost) - andi k0, k0, 0xffc # k0=seg offset (mask 0x3) -#xxx mips64 unsafe? - addu k1, k0, k1 # k1=seg entry address - lw k1, 0(k1) # k1=seg entry - mfc0 k0, COP_0_BAD_VADDR # k0=bad address (again) - beq k1, zero, _C_LABEL(MipsUserGenException) # ==0 -- no page table - srl k0, k0, PGSHIFT-2 - andi k0, k0, 0xffc # compute offset from index - tlbp # Probe the invalid entry -#xxx mips64 unsafe? - addu k1, k1, k0 - and k0, k0, 4 # check even/odd page - nop # required for QED 5230 - bne k0, zero, UserTLBIOdd + lw k0, PC_CURTHREAD(k1) + lw k0, TD_REALKSTACK(k0) + sltu k0, k0, sp + bnez k0, _C_LABEL(MipsKernGenException) nop - mfc0 k0, COP_0_TLB_INDEX - nop - bltz k0, _C_LABEL(MipsUserGenException) + /* + * Kernel stack overflow. + * + * Move to a valid stack before we call panic. We use the boot stack + * for this purpose. + */ + GET_CPU_PCPU(k1) + lw k1, PC_CPUID(k1) + sll k1, k1, PAGE_SHIFT + 1 - sltiu k0, k0, VMWIRED_ENTRIES # index below wired entries? - bne k0, zero, _C_LABEL(MipsUserGenException) - lw k0, 0(k1) # get PTE entry + PTR_LA k0, _C_LABEL(pcpu_space) + addiu k0, (NBPG * 2) + addu k0, k0, k1 - _SLL k0, k0, WIRED_SHIFT # get rid of "wired" bit - _SRL k0, k0, WIRED_SHIFT - _MTC0 k0, COP_0_TLB_LO0 # load PTE entry - and k0, k0, PTE_V # check for valid entry - nop # required for QED5230 - beq k0, zero, _C_LABEL(MipsUserGenException) # PTE invalid - lw k0, 4(k1) # get odd PTE entry - _SLL k0, k0, WIRED_SHIFT - _SRL k0, k0, WIRED_SHIFT - _MTC0 k0, COP_0_TLB_LO1 # load PTE entry - HAZARD_DELAY - tlbwi # write TLB - HAZARD_DELAY - eret + /* + * Stash the original value of 'sp' so we can update trapframe later. + * We assume that SAVE_CPU does not trash 'k1'. + */ + move k1, sp -UserTLBIOdd: - mfc0 k0, COP_0_TLB_INDEX - nop - bltz k0, _C_LABEL(MipsUserGenException) - sltiu k0, k0, VMWIRED_ENTRIES # index below wired entries? + move sp, k0 + subu sp, sp, KERN_EXC_FRAME_SIZE - bne k0, zero, _C_LABEL(MipsUserGenException) - lw k0, 0(k1) # get PTE entry + move k0, ra + move ra, zero + sw ra, CALLFRAME_RA(sp) /* stop the ddb backtrace right here */ + sw zero, CALLFRAME_SP(sp) + move ra, k0 - _SLL k0, k0, WIRED_SHIFT # get rid of wired bit - _SRL k0, k0, WIRED_SHIFT - _MTC0 k0, COP_0_TLB_LO1 # save PTE entry - and k0, k0, PTE_V # check for valid entry - nop # required for QED5230 - beq k0, zero, _C_LABEL(MipsUserGenException) # PTE invalid - lw k0, -4(k1) # get even PTE entry - _SLL k0, k0, WIRED_SHIFT - _SRL k0, k0, WIRED_SHIFT - _MTC0 k0, COP_0_TLB_LO0 # save PTE entry - HAZARD_DELAY - tlbwi # update TLB - HAZARD_DELAY - eret + SAVE_CPU - .set at -END(MipsUserTLBInvalidException) + /* + * Now restore the value of 'sp' at the time of the tlb exception in + * the trapframe. + */ + SAVE_REG(k1, SP, sp) + + /* + * Squelch any more overflow checks by setting the stack base to 0. + */ + GET_CPU_PCPU(k1) + lw k0, PC_CURTHREAD(k1) + sw zero, TD_REALKSTACK(k0) + + move a1, a0 + PANIC("kernel stack overflow - trapframe at %p") + + /* + * This nop is necessary so that the 'ra' remains within the bounds + * of this handler. Otherwise the ddb backtrace code will think that + * the panic() was called from MipsTLBMissException. + */ + nop + + .set pop +END(MipsTLBInvalidException) /*---------------------------------------------------------------------------- * @@ -1048,68 +1039,6 @@ NLEAF(MipsTLBMissException) tlbwr # write to tlb HAZARD_DELAY eret # return from exception - -sys_stk_chk: - GET_CPU_PCPU(k0) - lw k0, PC_CURTHREAD(k0) - lw k0, TD_REALKSTACK(k0) - sltu k0, sp, k0 # check for stack overflow - beqz k0, _C_LABEL(MipsKernGenException) # not stack overflow - nop - -# stack overflow - PTR_LA a0, _C_LABEL(_start) - CALLFRAME_SIZ - 8 # set sp to a valid place - sw sp, 24(a0) - move sp, a0 - PTR_LA a0, 1f - mfc0 a2, COP_0_STATUS_REG - mfc0 a3, COP_0_CAUSE_REG - _MFC0 a1, COP_0_EXC_PC - sw a2, 16(sp) - sw a3, 20(sp) - move a2, ra - PTR_LA k0, _C_LABEL(printf) - jalr k0 - mfc0 a3, COP_0_BAD_VADDR - - PTR_LA sp, _C_LABEL(_start) - CALLFRAME_SIZ # set sp to a valid place - -#if !defined(SMP) && defined(DDB) - PTR_LA a0, 2f - PTR_LA k0, _C_LABEL(trapDump) - jalr k0 - nop - - li a0, 0 - lw a1, _C_LABEL(num_tlbentries) - PTR_LA k0, _C_LABEL(db_dump_tlb) - jalr k0 - addu a1, -1 - -3: - b 3b - nop -#endif - - PANIC("kernel stack overflow") - - .data - .globl lastktlbmiss -lastktlbmiss: - .word 0 -lastktlbmisspc: - .word 0 -lastutlbmiss: - .word 0 -lastutlbmisspc: - .word 0 - -1: - .asciiz "ktlbmiss: PC %x RA %x ADR %x\nSR %x CR %x SP %x\n" -2: - .asciiz "stack ovf" - .text - .set at END(MipsTLBMissException) @@ -1253,7 +1182,7 @@ VECTOR(MipsCache, unknown) PTR_LA k0, _C_LABEL(MipsCacheException) li k1, MIPS_PHYS_MASK and k0, k1 - li k1, MIPS_UNCACHED_MEMORY_ADDR + li k1, MIPS_KSEG1_START or k0, k1 j k0 nop diff --git a/sys/mips/mips/mp_machdep.c b/sys/mips/mips/mp_machdep.c index d8520cc..f65db9b 100644 --- a/sys/mips/mips/mp_machdep.c +++ b/sys/mips/mips/mp_machdep.c @@ -50,6 +50,8 @@ __FBSDID("$FreeBSD$"); #include <machine/intr_machdep.h> #include <machine/cache.h> +struct pcb stoppcbs[MAXCPU]; + static void *dpcpu; static struct mtx ap_boot_mtx; @@ -88,10 +90,14 @@ ipi_selected(cpumask_t cpus, int ipi) static int mips_ipi_handler(void *arg) { + int cpu; cpumask_t cpumask; u_int ipi, ipi_bitmap; int bit; + cpu = PCPU_GET(cpuid); + cpumask = PCPU_GET(cpumask); + platform_ipi_clear(); /* quiesce the pending ipi interrupt */ ipi_bitmap = atomic_readandclear_int(PCPU_PTR(pending_ipis)); @@ -120,10 +126,17 @@ mips_ipi_handler(void *arg) * necessary to add it in the switch. */ CTR0(KTR_SMP, "IPI_STOP or IPI_STOP_HARD"); - cpumask = PCPU_GET(cpumask); + + savectx(&stoppcbs[cpu]); + pmap_save_tlb(); + + /* Indicate we are stopped */ atomic_set_int(&stopped_cpus, cpumask); + + /* Wait for restart */ while ((started_cpus & cpumask) == 0) cpu_spinwait(); + atomic_clear_int(&started_cpus, cpumask); atomic_clear_int(&stopped_cpus, cpumask); CTR0(KTR_SMP, "IPI_STOP (restart)"); diff --git a/sys/mips/mips/nexus.c b/sys/mips/mips/nexus.c index 7d3f190..6600980 100644 --- a/sys/mips/mips/nexus.c +++ b/sys/mips/mips/nexus.c @@ -73,7 +73,6 @@ struct nexus_device { #define DEVTONX(dev) ((struct nexus_device *)device_get_ivars(dev)) #define NUM_MIPS_IRQS 6 -#define MIPS_MEM_RID 0x20 static struct rman irq_rman; static struct rman mem_rman; diff --git a/sys/mips/mips/pm_machdep.c b/sys/mips/mips/pm_machdep.c index 712763b..03867b0 100644 --- a/sys/mips/mips/pm_machdep.c +++ b/sys/mips/mips/pm_machdep.c @@ -472,7 +472,7 @@ set_fpregs(struct thread *td, struct fpreg *fpregs) * code by the MIPS elf abi). */ void -exec_setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings) +exec_setregs(struct thread *td, struct image_params *imgp, u_long stack) { bzero((caddr_t)td->td_frame, sizeof(struct trapframe)); @@ -481,8 +481,8 @@ exec_setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings) * Make sp 64-bit aligned. */ td->td_frame->sp = ((register_t) stack) & ~(sizeof(__int64_t) - 1); - td->td_frame->pc = entry & ~3; - td->td_frame->t9 = entry & ~3; /* abicall req */ + td->td_frame->pc = imgp->entry_addr & ~3; + td->td_frame->t9 = imgp->entry_addr & ~3; /* abicall req */ #if 0 // td->td_frame->sr = SR_KSU_USER | SR_EXL | SR_INT_ENAB; //? td->td_frame->sr |= idle_mask & ALL_INT_MASK; @@ -511,7 +511,7 @@ exec_setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings) td->td_frame->a0 = (register_t) stack; td->td_frame->a1 = 0; td->td_frame->a2 = 0; - td->td_frame->a3 = (register_t)ps_strings; + td->td_frame->a3 = (register_t)imgp->ps_strings; td->td_md.md_flags &= ~MDTD_FPUSED; if (PCPU_GET(fpcurthread) == td) diff --git a/sys/mips/mips/pmap.c b/sys/mips/mips/pmap.c index 4a267dc..73f57e4 100644 --- a/sys/mips/mips/pmap.c +++ b/sys/mips/mips/pmap.c @@ -76,6 +76,7 @@ __FBSDID("$FreeBSD$"); #include <sys/msgbuf.h> #include <sys/vmmeter.h> #include <sys/mman.h> +#include <sys/smp.h> #include <vm/vm.h> #include <vm/vm_param.h> @@ -149,6 +150,8 @@ unsigned pmap_max_asid; /* max ASID supported by the system */ vm_offset_t kernel_vm_end; +static struct tlb tlbstash[MAXCPU][MIPS_MAX_TLB_ENTRIES]; + static void pmap_asid_alloc(pmap_t pmap); /* @@ -205,7 +208,7 @@ struct local_sysmaps { /* This structure is for large memory * above 512Meg. We can't (in 32 bit mode) - * just use the direct mapped MIPS_CACHED_TO_PHYS() + * just use the direct mapped MIPS_KSEG0_TO_PHYS() * macros since we can't see the memory and must * map it in when we need to access it. In 64 * bit mode this goes away. @@ -271,7 +274,7 @@ pmap_steal_memory(vm_size_t size) if (pa >= MIPS_KSEG0_LARGEST_PHYS) { panic("Out of memory below 512Meg?"); } - va = MIPS_PHYS_TO_CACHED(pa); + va = MIPS_PHYS_TO_KSEG0(pa); bzero((caddr_t)va, size); return va; } @@ -946,10 +949,21 @@ pmap_unmap_fpage(vm_paddr_t pa, struct fpage *fp) static int _pmap_unwire_pte_hold(pmap_t pmap, vm_page_t m) { + vm_offset_t pteva; /* * unmap the page table page */ + pteva = (vm_offset_t)pmap->pm_segtab[m->pindex]; + if (pteva >= VM_MIN_KERNEL_ADDRESS) { + pmap_kremove(pteva); + kmem_free(kernel_map, pteva, PAGE_SIZE); + } else { + KASSERT(MIPS_IS_KSEG0_ADDR(pteva), + ("_pmap_unwire_pte_hold: 0x%0lx is not in kseg0", + (long)pteva)); + } + pmap->pm_segtab[m->pindex] = 0; --pmap->pm_stats.resident_count; @@ -994,7 +1008,7 @@ pmap_unuse_pt(pmap_t pmap, vm_offset_t va, vm_page_t mpte) mpte = pmap->pm_ptphint; } else { pteva = *pmap_pde(pmap, va); - mpte = PHYS_TO_VM_PAGE(MIPS_CACHED_TO_PHYS(pteva)); + mpte = PHYS_TO_VM_PAGE(vtophys(pteva)); pmap->pm_ptphint = mpte; } } @@ -1026,6 +1040,8 @@ pmap_pinit0(pmap_t pmap) int pmap_pinit(pmap_t pmap) { + vm_offset_t ptdva; + vm_paddr_t ptdpa; vm_page_t ptdpg; int i; int req; @@ -1047,8 +1063,17 @@ pmap_pinit(pmap_t pmap) ptdpg->valid = VM_PAGE_BITS_ALL; - pmap->pm_segtab = (pd_entry_t *) - MIPS_PHYS_TO_CACHED(VM_PAGE_TO_PHYS(ptdpg)); + ptdpa = VM_PAGE_TO_PHYS(ptdpg); + if (ptdpa < MIPS_KSEG0_LARGEST_PHYS) { + ptdva = MIPS_PHYS_TO_KSEG0(ptdpa); + } else { + ptdva = kmem_alloc_nofault(kernel_map, PAGE_SIZE); + if (ptdva == 0) + panic("pmap_pinit: unable to allocate kva"); + pmap_kenter(ptdva, ptdpa); + } + + pmap->pm_segtab = (pd_entry_t *)ptdva; if ((ptdpg->flags & PG_ZERO) == 0) bzero(pmap->pm_segtab, PAGE_SIZE); @@ -1115,7 +1140,15 @@ _pmap_allocpte(pmap_t pmap, unsigned ptepindex, int flags) pmap->pm_stats.resident_count++; ptepa = VM_PAGE_TO_PHYS(m); - pteva = MIPS_PHYS_TO_CACHED(ptepa); + if (ptepa < MIPS_KSEG0_LARGEST_PHYS) { + pteva = MIPS_PHYS_TO_KSEG0(ptepa); + } else { + pteva = kmem_alloc_nofault(kernel_map, PAGE_SIZE); + if (pteva == 0) + panic("_pmap_allocpte: unable to allocate kva"); + pmap_kenter(pteva, ptepa); + } + pmap->pm_segtab[ptepindex] = (pd_entry_t)pteva; /* @@ -1169,7 +1202,7 @@ retry: (pmap->pm_ptphint->pindex == ptepindex)) { m = pmap->pm_ptphint; } else { - m = PHYS_TO_VM_PAGE(MIPS_CACHED_TO_PHYS(pteva)); + m = PHYS_TO_VM_PAGE(vtophys(pteva)); pmap->pm_ptphint = m; } m->wire_count++; @@ -1209,13 +1242,24 @@ retry: void pmap_release(pmap_t pmap) { + vm_offset_t ptdva; vm_page_t ptdpg; KASSERT(pmap->pm_stats.resident_count == 0, ("pmap_release: pmap resident count %ld != 0", pmap->pm_stats.resident_count)); - ptdpg = PHYS_TO_VM_PAGE(MIPS_CACHED_TO_PHYS(pmap->pm_segtab)); + ptdva = (vm_offset_t)pmap->pm_segtab; + ptdpg = PHYS_TO_VM_PAGE(vtophys(ptdva)); + + if (ptdva >= VM_MIN_KERNEL_ADDRESS) { + pmap_kremove(ptdva); + kmem_free(kernel_map, ptdva, PAGE_SIZE); + } else { + KASSERT(MIPS_IS_KSEG0_ADDR(ptdva), + ("pmap_release: 0x%0lx is not in kseg0", (long)ptdva)); + } + ptdpg->wire_count--; atomic_subtract_int(&cnt.v_wire_count, 1); vm_page_free_zero(ptdpg); @@ -1285,7 +1329,7 @@ pmap_growkernel(vm_offset_t addr) */ panic("Gak, can't handle a k-page table outside of lower 512Meg"); } - pte = (pt_entry_t *)MIPS_PHYS_TO_CACHED(ptppaddr); + pte = (pt_entry_t *)MIPS_PHYS_TO_KSEG0(ptppaddr); segtab_pde(kernel_segmap, kernel_vm_end) = (pd_entry_t)pte; /* @@ -2027,7 +2071,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, (pmap->pm_ptphint->pindex == ptepindex)) { mpte = pmap->pm_ptphint; } else { - mpte = PHYS_TO_VM_PAGE(MIPS_CACHED_TO_PHYS(pteva)); + mpte = PHYS_TO_VM_PAGE(vtophys(pteva)); pmap->pm_ptphint = mpte; } mpte->wire_count++; @@ -2117,7 +2161,7 @@ pmap_kenter_temporary(vm_paddr_t pa, int i) } else #endif if (pa < MIPS_KSEG0_LARGEST_PHYS) { - va = MIPS_PHYS_TO_CACHED(pa); + va = MIPS_PHYS_TO_KSEG0(pa); } else { int cpu; struct local_sysmaps *sysm; @@ -2289,7 +2333,7 @@ pmap_zero_page(vm_page_t m) #endif if (phys < MIPS_KSEG0_LARGEST_PHYS) { - va = MIPS_PHYS_TO_CACHED(phys); + va = MIPS_PHYS_TO_KSEG0(phys); bzero((caddr_t)va, PAGE_SIZE); mips_dcache_wbinv_range(va, PAGE_SIZE); @@ -2347,7 +2391,7 @@ pmap_zero_page_area(vm_page_t m, int off, int size) } else #endif if (phys < MIPS_KSEG0_LARGEST_PHYS) { - va = MIPS_PHYS_TO_CACHED(phys); + va = MIPS_PHYS_TO_KSEG0(phys); bzero((char *)(caddr_t)va + off, size); mips_dcache_wbinv_range(va + off, size); } else { @@ -2388,7 +2432,7 @@ pmap_zero_page_idle(vm_page_t m) } else #endif if (phys < MIPS_KSEG0_LARGEST_PHYS) { - va = MIPS_PHYS_TO_CACHED(phys); + va = MIPS_PHYS_TO_KSEG0(phys); bzero((caddr_t)va, PAGE_SIZE); mips_dcache_wbinv_range(va, PAGE_SIZE); } else { @@ -2463,9 +2507,9 @@ pmap_copy_page(vm_page_t src, vm_page_t dst) */ pmap_flush_pvcache(src); mips_dcache_wbinv_range_index( - MIPS_PHYS_TO_CACHED(phy_dst), NBPG); - va_src = MIPS_PHYS_TO_CACHED(phy_src); - va_dst = MIPS_PHYS_TO_CACHED(phy_dst); + MIPS_PHYS_TO_KSEG0(phy_dst), NBPG); + va_src = MIPS_PHYS_TO_KSEG0(phy_src); + va_dst = MIPS_PHYS_TO_KSEG0(phy_dst); bcopy((caddr_t)va_src, (caddr_t)va_dst, PAGE_SIZE); mips_dcache_wbinv_range(va_dst, PAGE_SIZE); } else { @@ -2479,14 +2523,14 @@ pmap_copy_page(vm_page_t src, vm_page_t dst) int_level = disableintr(); if (phy_src < MIPS_KSEG0_LARGEST_PHYS) { /* one side needs mapping - dest */ - va_src = MIPS_PHYS_TO_CACHED(phy_src); + va_src = MIPS_PHYS_TO_KSEG0(phy_src); sysm->CMAP2 = mips_paddr_to_tlbpfn(phy_dst) | PTE_RW | PTE_V | PTE_G | PTE_W | PTE_CACHE; pmap_TLB_update_kernel((vm_offset_t)sysm->CADDR2, sysm->CMAP2); sysm->valid2 = 1; va_dst = (vm_offset_t)sysm->CADDR2; } else if (phy_dst < MIPS_KSEG0_LARGEST_PHYS) { /* one side needs mapping - src */ - va_dst = MIPS_PHYS_TO_CACHED(phy_dst); + va_dst = MIPS_PHYS_TO_KSEG0(phy_dst); sysm->CMAP1 = mips_paddr_to_tlbpfn(phy_src) | PTE_RW | PTE_V | PTE_G | PTE_W | PTE_CACHE; pmap_TLB_update_kernel((vm_offset_t)sysm->CADDR1, sysm->CMAP1); va_src = (vm_offset_t)sysm->CADDR1; @@ -3168,18 +3212,6 @@ pmap_asid_alloc(pmap) pmap->pm_asid[PCPU_GET(cpuid)].gen = PCPU_GET(asid_generation); PCPU_SET(next_asid, PCPU_GET(next_asid) + 1); } - -#ifdef DEBUG - if (pmapdebug & (PDB_FOLLOW | PDB_TLBPID)) { - if (curproc) - printf("pmap_asid_alloc: curproc %d '%s' ", - curproc->p_pid, curproc->p_comm); - else - printf("pmap_asid_alloc: curproc <none> "); - printf("segtab %p asid %d\n", pmap->pm_segtab, - pmap->pm_asid[PCPU_GET(cpuid)].asid); - } -#endif } int @@ -3248,53 +3280,6 @@ pmap_set_modified(vm_offset_t pa) PHYS_TO_VM_PAGE(pa)->md.pv_flags |= (PV_TABLE_REF | PV_TABLE_MOD); } -#include <machine/db_machdep.h> - -/* - * Dump the translation buffer (TLB) in readable form. - */ - -void -db_dump_tlb(int first, int last) -{ - struct tlb tlb; - int tlbno; - - tlbno = first; - - while (tlbno <= last) { - MachTLBRead(tlbno, &tlb); - if (tlb.tlb_lo0 & PTE_V || tlb.tlb_lo1 & PTE_V) { - printf("TLB %2d vad 0x%08x ", tlbno, (tlb.tlb_hi & 0xffffff00)); - } else { - printf("TLB*%2d vad 0x%08x ", tlbno, (tlb.tlb_hi & 0xffffff00)); - } - printf("0=0x%08x ", pfn_to_vad(tlb.tlb_lo0)); - printf("%c", tlb.tlb_lo0 & PTE_M ? 'M' : ' '); - printf("%c", tlb.tlb_lo0 & PTE_G ? 'G' : ' '); - printf(" atr %x ", (tlb.tlb_lo0 >> 3) & 7); - printf("1=0x%08x ", pfn_to_vad(tlb.tlb_lo1)); - printf("%c", tlb.tlb_lo1 & PTE_M ? 'M' : ' '); - printf("%c", tlb.tlb_lo1 & PTE_G ? 'G' : ' '); - printf(" atr %x ", (tlb.tlb_lo1 >> 3) & 7); - printf(" sz=%x pid=%x\n", tlb.tlb_mask, - (tlb.tlb_hi & 0x000000ff) - ); - tlbno++; - } -} - -#ifdef DDB -#include <sys/kernel.h> -#include <ddb/ddb.h> - -DB_SHOW_COMMAND(tlb, ddb_dump_tlb) -{ - db_dump_tlb(0, num_tlbentries - 1); -} - -#endif - /* * Routine: pmap_kextract * Function: @@ -3306,7 +3291,7 @@ pmap_kextract(vm_offset_t va) { vm_offset_t pa = 0; - if (va < MIPS_CACHED_MEMORY_ADDR) { + if (va < MIPS_KSEG0_START) { /* user virtual address */ pt_entry_t *ptep; @@ -3316,16 +3301,16 @@ pmap_kextract(vm_offset_t va) pa = mips_tlbpfn_to_paddr(*ptep) | (va & PAGE_MASK); } - } else if (va >= MIPS_CACHED_MEMORY_ADDR && - va < MIPS_UNCACHED_MEMORY_ADDR) - pa = MIPS_CACHED_TO_PHYS(va); - else if (va >= MIPS_UNCACHED_MEMORY_ADDR && + } else if (va >= MIPS_KSEG0_START && + va < MIPS_KSEG1_START) + pa = MIPS_KSEG0_TO_PHYS(va); + else if (va >= MIPS_KSEG1_START && va < MIPS_KSEG2_START) - pa = MIPS_UNCACHED_TO_PHYS(va); + pa = MIPS_KSEG1_TO_PHYS(va); #ifdef VM_ALLOC_WIRED_TLB_PG_POOL else if (need_wired_tlb_page_pool && ((va >= VM_MIN_KERNEL_ADDRESS) && (va < (VM_MIN_KERNEL_ADDRESS + VM_KERNEL_ALLOC_OFFSET)))) - pa = MIPS_CACHED_TO_PHYS(va); + pa = MIPS_KSEG0_TO_PHYS(va); #endif else if (va >= MIPS_KSEG2_START && va < VM_MAX_KERNEL_ADDRESS) { pt_entry_t *ptep; @@ -3377,3 +3362,61 @@ pmap_flush_pvcache(vm_page_t m) } } } + +void +pmap_save_tlb(void) +{ + int tlbno, cpu; + + cpu = PCPU_GET(cpuid); + + for (tlbno = 0; tlbno < num_tlbentries; ++tlbno) + MachTLBRead(tlbno, &tlbstash[cpu][tlbno]); +} + +#ifdef DDB +#include <ddb/ddb.h> + +DB_SHOW_COMMAND(tlb, ddb_dump_tlb) +{ + int cpu, tlbno; + struct tlb *tlb; + + if (have_addr) + cpu = ((addr >> 4) % 16) * 10 + (addr % 16); + else + cpu = PCPU_GET(cpuid); + + if (cpu < 0 || cpu >= mp_ncpus) { + db_printf("Invalid CPU %d\n", cpu); + return; + } else + db_printf("CPU %d:\n", cpu); + + if (cpu == PCPU_GET(cpuid)) + pmap_save_tlb(); + + for (tlbno = 0; tlbno < num_tlbentries; ++tlbno) { + tlb = &tlbstash[cpu][tlbno]; + if (tlb->tlb_lo0 & PTE_V || tlb->tlb_lo1 & PTE_V) { + printf("TLB %2d vad 0x%0lx ", + tlbno, (long)(tlb->tlb_hi & 0xffffff00)); + } else { + printf("TLB*%2d vad 0x%0lx ", + tlbno, (long)(tlb->tlb_hi & 0xffffff00)); + } + printf("0=0x%0lx ", pfn_to_vad((long)tlb->tlb_lo0)); + printf("%c", tlb->tlb_lo0 & PTE_V ? 'V' : '-'); + printf("%c", tlb->tlb_lo0 & PTE_M ? 'M' : '-'); + printf("%c", tlb->tlb_lo0 & PTE_G ? 'G' : '-'); + printf(" atr %x ", (tlb->tlb_lo0 >> 3) & 7); + printf("1=0x%0lx ", pfn_to_vad((long)tlb->tlb_lo1)); + printf("%c", tlb->tlb_lo1 & PTE_V ? 'V' : '-'); + printf("%c", tlb->tlb_lo1 & PTE_M ? 'M' : '-'); + printf("%c", tlb->tlb_lo1 & PTE_G ? 'G' : '-'); + printf(" atr %x ", (tlb->tlb_lo1 >> 3) & 7); + printf(" sz=%x pid=%x\n", tlb->tlb_mask, + (tlb->tlb_hi & 0x000000ff)); + } +} +#endif /* DDB */ diff --git a/sys/mips/mips/support.S b/sys/mips/mips/support.S index 6282eb0..2aed3e6 100644 --- a/sys/mips/mips/support.S +++ b/sys/mips/mips/support.S @@ -51,6 +51,38 @@ */ /* + * Copyright (c) 1997 Jonathan Stone (hereinafter referred to as the author) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Jonathan R. Stone for + * the NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* * Contains code that is the first executed at boot time plus * assembly language support routines. */ @@ -61,6 +93,7 @@ #include <machine/asm.h> #include <machine/cpu.h> #include <machine/regnum.h> +#include <machine/cpuregs.h> #include "assym.s" @@ -1586,3 +1619,78 @@ LEAF(octeon_get_control) .set mips0 END(octeon_get_control) #endif + +LEAF(mips3_ld) + .set push + .set noreorder + .set mips64 +#if defined(__mips_o32) + mfc0 t0, MIPS_COP_0_STATUS # turn off interrupts + and t1, t0, ~(MIPS_SR_INT_IE) + mtc0 t1, MIPS_COP_0_STATUS + COP0_SYNC + nop + nop + nop + + ld v0, 0(a0) +#if _BYTE_ORDER == _BIG_ENDIAN + dsll v1, v0, 32 + dsra v1, v1, 32 # low word in v1 + dsra v0, v0, 32 # high word in v0 +#else + dsra v1, v0, 32 # high word in v1 + dsll v0, v0, 32 + dsra v0, v0, 32 # low word in v0 +#endif + + mtc0 t0, MIPS_COP_0_STATUS # restore intr status. + COP0_SYNC + nop +#else /* !__mips_o32 */ + ld v0, 0(a0) +#endif /* !__mips_o32 */ + + jr ra + nop + .set pop +END(mips3_ld) + +LEAF(mips3_sd) + .set push + .set mips64 + .set noreorder +#if defined(__mips_o32) + mfc0 t0, MIPS_COP_0_STATUS # turn off interrupts + and t1, t0, ~(MIPS_SR_INT_IE) + mtc0 t1, MIPS_COP_0_STATUS + COP0_SYNC + nop + nop + nop + + # NOTE: a1 is padding! + +#if _BYTE_ORDER == _BIG_ENDIAN + dsll a2, a2, 32 # high word in a2 + dsll a3, a3, 32 # low word in a3 + dsrl a3, a3, 32 +#else + dsll a2, a2, 32 # low word in a2 + dsrl a2, a2, 32 + dsll a3, a3, 32 # high word in a3 +#endif + or a1, a2, a3 + sd a1, 0(a0) + + mtc0 t0, MIPS_COP_0_STATUS # restore intr status. + COP0_SYNC + nop +#else /* !__mips_o32 */ + sd a1, 0(a0) +#endif /* !__mips_o32 */ + + jr ra + nop + .set pop +END(mips3_sd) diff --git a/sys/mips/mips/swtch.S b/sys/mips/mips/swtch.S index 1248276..dd66ece 100644 --- a/sys/mips/mips/swtch.S +++ b/sys/mips/mips/swtch.S @@ -245,6 +245,14 @@ LEAF(savectx) SAVE_U_PCB_CONTEXT(ra, PREG_RA, a0) SAVE_U_PCB_CONTEXT(v0, PREG_SR, a0) SAVE_U_PCB_CONTEXT(gp, PREG_GP, a0) + + move v0, ra /* save 'ra' before we trash it */ + jal 1f + nop +1: + SAVE_U_PCB_CONTEXT(ra, PREG_PC, a0) + move ra, v0 /* restore 'ra' before returning */ + /* * FREEBSD_DEVELOPERS_FIXME: * In case there are CPU-specific registers that need diff --git a/sys/mips/mips/tick.c b/sys/mips/mips/tick.c index bf147c5..60b3511 100644 --- a/sys/mips/mips/tick.c +++ b/sys/mips/mips/tick.c @@ -54,6 +54,8 @@ __FBSDID("$FreeBSD$"); uint64_t counter_freq; +struct timecounter *platform_timecounter; + static uint64_t cycles_per_tick; static uint64_t cycles_per_usec; static uint64_t cycles_per_hz, cycles_per_stathz, cycles_per_profhz; @@ -61,17 +63,14 @@ static uint64_t cycles_per_hz, cycles_per_stathz, cycles_per_profhz; static u_int32_t counter_upper = 0; static u_int32_t counter_lower_last = 0; -struct clk_ticks -{ +struct clk_ticks { u_long hard_ticks; u_long stat_ticks; u_long prof_ticks; - /* - * pad for cache line alignment of pcpu info - * cache-line-size - number of used bytes - */ - char pad[32-(3*sizeof (u_long))]; -} static pcpu_ticks[MAXCPU]; + uint32_t compare_ticks; +} __aligned(CACHE_LINE_SIZE); + +static struct clk_ticks pcpu_ticks[MAXCPU]; /* * Device methods @@ -103,6 +102,9 @@ platform_initclocks(void) { tc_init(&counter_timecounter); + + if (platform_timecounter != NULL) + tc_init(platform_timecounter); } static uint64_t @@ -255,25 +257,47 @@ clock_intr(void *arg) { struct clk_ticks *cpu_ticks; struct trapframe *tf; - uint32_t ltick; + uint32_t count, compare, delta; + + cpu_ticks = &pcpu_ticks[PCPU_GET(cpuid)]; + /* * Set next clock edge. */ - ltick = mips_rd_count(); - mips_wr_compare(ltick + cycles_per_tick); - cpu_ticks = &pcpu_ticks[PCPU_GET(cpuid)]; + count = mips_rd_count(); + compare = cpu_ticks->compare_ticks; + cpu_ticks->compare_ticks = count + cycles_per_tick; + mips_wr_compare(cpu_ticks->compare_ticks); critical_enter(); - if (ltick < counter_lower_last) { + if (count < counter_lower_last) { counter_upper++; - counter_lower_last = ltick; + counter_lower_last = count; } /* * Magic. Setting up with an arg of NULL means we get passed tf. */ tf = (struct trapframe *)arg; + delta = cycles_per_tick; + + /* + * Account for the "lost time" between when the timer interrupt fired + * and when 'clock_intr' actually started executing. + */ + delta += count - compare; + + /* + * If the COUNT and COMPARE registers are no longer in sync then make + * up some reasonable value for the 'delta'. + * + * This could happen, for e.g., after we resume normal operations after + * exiting the debugger. + */ + if (delta > cycles_per_hz) + delta = cycles_per_hz; + /* Fire hardclock at hz. */ - cpu_ticks->hard_ticks += cycles_per_tick; + cpu_ticks->hard_ticks += delta; if (cpu_ticks->hard_ticks >= cycles_per_hz) { cpu_ticks->hard_ticks -= cycles_per_hz; if (PCPU_GET(cpuid) == 0) @@ -283,14 +307,14 @@ clock_intr(void *arg) } /* Fire statclock at stathz. */ - cpu_ticks->stat_ticks += cycles_per_tick; + cpu_ticks->stat_ticks += delta; if (cpu_ticks->stat_ticks >= cycles_per_stathz) { cpu_ticks->stat_ticks -= cycles_per_stathz; statclock(USERMODE(tf->sr)); } /* Fire profclock at profhz, but only when needed. */ - cpu_ticks->prof_ticks += cycles_per_tick; + cpu_ticks->prof_ticks += delta; if (cpu_ticks->prof_ticks >= cycles_per_profhz) { cpu_ticks->prof_ticks -= cycles_per_profhz; if (profprocs != 0) diff --git a/sys/mips/mips/trap.c b/sys/mips/mips/trap.c index 5fdfabd..124087c 100644 --- a/sys/mips/mips/trap.c +++ b/sys/mips/mips/trap.c @@ -118,8 +118,8 @@ void (*machExceptionTable[]) (void)= { */ MipsKernIntr, /* external interrupt */ MipsKernGenException, /* TLB modification */ - MipsKernTLBInvalidException, /* TLB miss (load or instr. fetch) */ - MipsKernTLBInvalidException, /* TLB miss (store) */ + MipsTLBInvalidException,/* TLB miss (load or instr. fetch) */ + MipsTLBInvalidException,/* TLB miss (store) */ MipsKernGenException, /* address error (load or I-fetch) */ MipsKernGenException, /* address error (store) */ MipsKernGenException, /* bus error (I-fetch) */ @@ -153,8 +153,8 @@ void (*machExceptionTable[]) (void)= { */ MipsUserIntr, /* 0 */ MipsUserGenException, /* 1 */ - MipsUserTLBInvalidException, /* 2 */ - MipsUserTLBInvalidException, /* 3 */ + MipsTLBInvalidException,/* 2 */ + MipsTLBInvalidException,/* 3 */ MipsUserGenException, /* 4 */ MipsUserGenException, /* 5 */ MipsUserGenException, /* 6 */ diff --git a/sys/mips/mips/vm_machdep.c b/sys/mips/mips/vm_machdep.c index f76dc4d..3f8e6cc 100644 --- a/sys/mips/mips/vm_machdep.c +++ b/sys/mips/mips/vm_machdep.c @@ -214,6 +214,16 @@ cpu_thread_swapin(struct thread *td) { pt_entry_t *pte; int i; + vm_offset_t unused_kstack_page; + + /* + * Unmap the unused kstack page. + */ + unused_kstack_page = td->td_kstack; + if (td->td_md.md_realstack == td->td_kstack) + unused_kstack_page += (KSTACK_PAGES - 1) * PAGE_SIZE; + + pmap_kremove(unused_kstack_page); /* * The kstack may be at a different physical address now. @@ -239,13 +249,19 @@ cpu_thread_swapout(struct thread *td) void cpu_thread_alloc(struct thread *td) { + vm_offset_t unused_kstack_page; pt_entry_t *pte; int i; - if(td->td_kstack & (1 << PAGE_SHIFT)) + if (td->td_kstack & (1 << PAGE_SHIFT)) { td->td_md.md_realstack = td->td_kstack + PAGE_SIZE; - else + unused_kstack_page = td->td_kstack; + } else { td->td_md.md_realstack = td->td_kstack; + unused_kstack_page = td->td_kstack + + (KSTACK_PAGES - 1) * PAGE_SIZE; + } + pmap_kremove(unused_kstack_page); td->td_pcb = (struct pcb *)(td->td_md.md_realstack + (td->td_kstack_pages - 1) * PAGE_SIZE) - 1; diff --git a/sys/mips/sibyte/sb_asm.S b/sys/mips/sibyte/sb_asm.S index a822d79..312d3a5 100644 --- a/sys/mips/sibyte/sb_asm.S +++ b/sys/mips/sibyte/sb_asm.S @@ -28,61 +28,11 @@ #include <machine/asm.h> #include <machine/cpuregs.h> -#include <machine/endian.h> - -/* - * We compile a 32-bit kernel to run on the SB-1 processor which is a 64-bit - * processor. It has some registers that must be accessed using 64-bit load - * and store instructions. - * - * So we have to resort to assembly because the compiler does not emit the - * 'ld' and 'sd' instructions since it thinks that it is compiling for a - * 32-bit mips processor. - */ .set mips64 .set noat .set noreorder -/* - * Parameters: uint32_t ptr - * Return value: *(uint64_t *)ptr - */ -LEAF(sb_load64) - ld v1, 0(a0) /* result = *(uint64_t *)ptr */ - move v0, v1 -#if _BYTE_ORDER == _BIG_ENDIAN - dsll32 v1, v1, 0 - dsrl32 v1, v1, 0 /* v1 = lower_uint32(result) */ - jr ra - dsrl32 v0, v0, 0 /* v0 = upper_uint32(result) */ -#else - dsll32 v0, v0, 0 - dsrl32 v0, v0, 0 /* v0 = lower_uint32(result) */ - jr ra - dsrl32 v1, v1, 0 /* v1 = upper_uint32(result) */ -#endif -END(sb_load64) - -/* - * Parameters: uint32_t ptr, uint64_t val - * Return value: void - */ -LEAF(sb_store64) -#if _BYTE_ORDER == _BIG_ENDIAN - dsll32 a2, a2, 0 /* a2 = upper_uint32(val) */ - dsll32 a3, a3, 0 /* a3 = lower_uint32(val) */ - dsrl32 a3, a3, 0 -#else - dsll32 a3, a3, 0 /* a3 = upper_uint32(val) */ - dsll32 a2, a2, 0 /* a2 = lower_uint32(val) */ - dsrl32 a2, a2, 0 -#endif - or t0, a2, a3 - jr ra - sd t0, 0(a0) -END(sb_store64) - #ifdef SMP /* * This function must be implemented in assembly because it is called early diff --git a/sys/mips/sibyte/sb_machdep.c b/sys/mips/sibyte/sb_machdep.c index 8f59815..dca2869 100644 --- a/sys/mips/sibyte/sb_machdep.c +++ b/sys/mips/sibyte/sb_machdep.c @@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysent.h> #include <sys/sysproto.h> #include <sys/user.h> +#include <sys/timetc.h> #include <vm/vm.h> #include <vm/vm_object.h> @@ -364,6 +365,32 @@ platform_start_ap(int cpuid) } #endif /* SMP */ +static u_int +sb_get_timecount(struct timecounter *tc) +{ + + return ((u_int)sb_zbbus_cycle_count()); +} + +static void +sb_timecounter_init(void) +{ + static struct timecounter sb_timecounter = { + sb_get_timecount, + NULL, + ~0u, + 0, + "sibyte_zbbus_counter", + 2000 + }; + + /* + * The ZBbus cycle counter runs at half the cpu frequency. + */ + sb_timecounter.tc_frequency = sb_cpu_speed() / 2; + platform_timecounter = &sb_timecounter; +} + void platform_start(__register_t a0, __register_t a1, __register_t a2, __register_t a3) @@ -378,6 +405,7 @@ platform_start(__register_t a0, __register_t a1, __register_t a2, mips_postboot_fixup(); sb_intr_init(0); + sb_timecounter_init(); /* Initialize pcpu stuff */ mips_pcpu0_init(); @@ -400,4 +428,6 @@ platform_start(__register_t a0, __register_t a1, __register_t a2, mips_init(); mips_timer_init_params(sb_cpu_speed(), 0); + + set_cputicker(sb_zbbus_cycle_count, sb_cpu_speed() / 2, 1); } diff --git a/sys/mips/sibyte/sb_scd.c b/sys/mips/sibyte/sb_scd.c index 007e149..bfaa8d4 100644 --- a/sys/mips/sibyte/sb_scd.c +++ b/sys/mips/sibyte/sb_scd.c @@ -38,8 +38,15 @@ __FBSDID("$FreeBSD$"); #include "sb_scd.h" -extern void sb_store64(uint32_t addr, uint64_t val); -extern uint64_t sb_load64(uint32_t addr); +/* + * We compile a 32-bit kernel to run on the SB-1 processor which is a 64-bit + * processor. It has some registers that must be accessed using 64-bit load + * and store instructions. + * + * We use the mips_ld() and mips_sd() functions to do this for us. + */ +#define sb_store64(addr, val) mips3_sd((uint64_t *)(addr), (val)) +#define sb_load64(addr) mips3_ld((uint64_t *)(addr)) /* * System Control and Debug (SCD) unit on the Sibyte ZBbus. @@ -56,6 +63,8 @@ extern uint64_t sb_load64(uint32_t addr); #define SYSCFG_ADDR MIPS_PHYS_TO_KSEG1(0x10020008) #define SYSCFG_PLLDIV(x) GET_VAL_64((x), 7, 5) +#define ZBBUS_CYCLE_COUNT_ADDR MIPS_PHYS_TO_KSEG1(0x10030000) + #define INTSRC_MASK_ADDR(cpu) \ (MIPS_PHYS_TO_KSEG1(0x10020028) | ((cpu) << 13)) @@ -83,6 +92,13 @@ sb_write_syscfg(uint64_t val) } uint64_t +sb_zbbus_cycle_count(void) +{ + + return (sb_load64(ZBBUS_CYCLE_COUNT_ADDR)); +} + +uint64_t sb_cpu_speed(void) { int plldiv; diff --git a/sys/mips/sibyte/sb_scd.h b/sys/mips/sibyte/sb_scd.h index 03d2681..f8bb6e4 100644 --- a/sys/mips/sibyte/sb_scd.h +++ b/sys/mips/sibyte/sb_scd.h @@ -31,6 +31,7 @@ #define NUM_INTSRC 64 /* total number of interrupt sources */ +uint64_t sb_zbbus_cycle_count(void); uint64_t sb_cpu_speed(void); void sb_system_reset(void); |