--- hlh_card/rtsx.c 2019-12-12 09:56:40.340022000 +0100 +++ hlh_card/rtsx.c 2019-12-12 11:00:45.126132000 +0100 @@ -46,7 +46,10 @@ #include #include +#include #include +#include +#include #include #include @@ -59,7 +62,7 @@ #include "mmcbr_if.h" -#include +#include "rtsxreg.h" #define RTSX_NREG ((0XFDAE - 0XFDA0) + (0xFD69 - 0xFD32) + (0xFE34 - 0xFE20)) #define SDMMC_MAXNSEGS ((MAXPHYS / PAGE_SIZE) + 1) @@ -82,6 +85,10 @@ device_t rtsx_dev; /* device */ int rtsx_flags; /* device flags */ device_t rtsx_mmc_dev; /* device of mmc bus */ + /* for card insert/remove - from dwmmc.c */ + struct task card_task; /* Card presence check task */ + struct timeout_task card_delayed_task;/* Card insert delayed task */ + int rtsx_irq_res_id; /* bus IRQ resource id */ struct resource *rtsx_irq_res; /* bus IRQ resource */ void *rtsx_irq_cookie; /* bus IRQ resource cookie */ @@ -135,8 +142,7 @@ static void rtsx_dma_free(struct rtsx_softc *sc); static void rtsx_intr(void *arg); static int rtsx_init(struct rtsx_softc *sc); -static void rtsx_start(struct rtsx_softc *sc); -static void rtsx_stop(struct rtsx_softc *sc); +static int rtsx_stop(struct rtsx_softc *sc); static int rtsx_read(struct rtsx_softc *, uint16_t, uint8_t *); static int rtsx_read_cfg(struct rtsx_softc *sc, uint8_t func, uint16_t addr, uint32_t *val); static int rtsx_write(struct rtsx_softc *, uint16_t, uint8_t, uint8_t); @@ -148,8 +154,11 @@ static int rtsx_bus_power_up(struct rtsx_softc *sc); static int rtsx_bus_power_on(struct rtsx_softc *sc); static int rtsx_is_card_present(struct rtsx_softc *sc); +#if 0 /* done in task */ +static void rtsx_start(struct rtsx_softc *sc); static void rtsx_card_insert(struct rtsx_softc *sc); static void rtsx_card_remove(struct rtsx_softc *sc); +#endif static int rtsx_led_enable(struct rtsx_softc *sc); static int rtsx_led_disable(struct rtsx_softc *sc); @@ -185,6 +194,8 @@ static int rtsx_mmcbr_get_ro(device_t bus, device_t child __unused); static int rtsx_mmcbr_acquire_host(device_t bus, device_t child __unused); static int rtsx_mmcbr_release_host(device_t bus, device_t child __unused); +static void rtsx_card_task(void *arg, int pending __unused); +static void rtsx_handle_card_present(struct rtsx_softc *sc); #define RTSX_LOCK_INIT(_sc) mtx_init(&(_sc)->rtsx_mtx, \ device_get_nameunit(sc->rtsx_dev), "rtsx", MTX_DEF) @@ -411,7 +422,66 @@ } } +/* from dwmmc.c */ +/* called from the IRQ handler */ static void +rtsx_handle_card_present(struct rtsx_softc *sc) +{ + bool was_present; + bool is_present; + + was_present = sc->rtsx_mmc_dev != NULL; + is_present = (rtsx_is_card_present(sc) != 0); + + if (!was_present && is_present) { + /* small delay for the controller */ + taskqueue_enqueue_timeout(taskqueue_swi_giant, + &sc->card_delayed_task, -(hz / 2)); + } else if (was_present && !is_present) { + taskqueue_enqueue(taskqueue_swi_giant, &sc->card_task); + } +} + +/* this is called at startup */ +static void +rtsx_card_task(void *arg, int pending __unused) +{ + struct rtsx_softc *sc = arg; + + RTSX_LOCK(sc); + + if (rtsx_is_card_present(sc) != 0) { + sc->rtsx_flags |= RTSX_F_CARD_PRESENT; + /* Card is present, attach if necessary */ + if (sc->rtsx_mmc_dev == NULL) { + if (bootverbose) + device_printf(sc->rtsx_dev, "Card inserted\n"); + + sc->rtsx_mmc_dev = device_add_child(sc->rtsx_dev, "mmc", -1); + RTSX_UNLOCK(sc); + if (sc->rtsx_mmc_dev != NULL) { + device_set_ivars(sc->rtsx_mmc_dev, sc); + (void)device_probe_and_attach(sc->rtsx_mmc_dev); + } + } else + RTSX_UNLOCK(sc); + + } else { + sc->rtsx_flags &= ~RTSX_F_CARD_PRESENT; + /* Card isn't present, detach if necessary */ + if (sc->rtsx_mmc_dev != NULL) { + if (bootverbose) + device_printf(sc->rtsx_dev, "Card removed\n"); + + RTSX_UNLOCK(sc); + device_delete_child(sc->rtsx_dev, sc->rtsx_mmc_dev); + sc->rtsx_mmc_dev = NULL; + } else + RTSX_UNLOCK(sc); + } +} + +static void rtsx_intr(void *arg) { struct rtsx_softc *sc = arg; @@ -428,20 +498,34 @@ WRITE4(sc, RTSX_BIPR, status); if (((enabled & status) == 0) || status == 0xffffffff) { +device_printf(sc->rtsx_dev, "FLAGS\n"); RTSX_UNLOCK(sc); return; } + + /* start task to handle SD card status change */ + /* from dwmmc.c */ + if (status & RTSX_SD_INT) { +device_printf(sc->rtsx_dev, "A\n"); + rtsx_handle_card_present(sc); + } if (sc->rtsx_req == NULL) { +device_printf(sc->rtsx_dev, "B\n"); +#if 0 /* might have been SD int */ device_printf(sc->rtsx_dev, "Spurious interrupt - no active request\n"); +#endif RTSX_UNLOCK(sc); return; } if (status & (RTSX_TRANS_OK_INT | RTSX_TRANS_FAIL_INT)) { sc->rtsx_intr_status |= status; wakeup(&sc->rtsx_intr_status); - } + } else + device_printf(sc->rtsx_dev, "NODMA\n"); + RTSX_UNLOCK(sc); + /*--- See taskqueue_enqueue_timeout() if (status & RTSX_SD_INT) { @@ -600,6 +684,7 @@ return (0); } +#if 0 /* done in task */ static void rtsx_start(struct rtsx_softc *sc) { @@ -608,15 +693,18 @@ else rtsx_card_remove(sc); } +#endif -static void +static int rtsx_stop(struct rtsx_softc *sc) { - if (sc->rtsx_mmc_dev != NULL) { - /* detach mmc bus */ - device_delete_child(sc->rtsx_dev, sc->rtsx_mmc_dev); - sc->rtsx_mmc_dev = NULL; - } + int ret = 0; + + /* automatically deletes any children */ + ret = device_delete_children(sc->rtsx_dev); + sc->rtsx_mmc_dev = NULL; + + return (ret); } static int @@ -1049,6 +1137,7 @@ return (status & RTSX_SD_EXIST); } +#if 0 /* done in the task */ static void rtsx_card_insert(struct rtsx_softc *sc) { @@ -1097,6 +1186,7 @@ } rtsx_led_disable(sc); } +#endif static int rtsx_led_enable(struct rtsx_softc *sc) @@ -1948,7 +2038,7 @@ struct rtsx_softc *sc; if (bootverbose) - device_printf(bus, "rtsx_mmcbr_acquite_host()\n"); + device_printf(bus, "rtsx_mmcbr_acquire_host()\n"); sc = device_get_softc(bus); RTSX_LOCK(sc); @@ -2101,9 +2191,23 @@ if (error) { goto destroy_rtsx_irq; } +#if 0 /* done in task */ /* Start device */ rtsx_start(sc); +#else + /* from dwmmc.c */ + TASK_INIT(&sc->card_task, 0, rtsx_card_task, sc); + /* really giant? */ + TIMEOUT_TASK_INIT(taskqueue_swi_giant, &sc->card_delayed_task, 0, + rtsx_card_task, sc); + /* + * Schedule a card detection as we won't get an interrupt + * if the card is inserted when we attach + */ + rtsx_card_task(sc, 0); +#endif + if (bootverbose) device_printf(dev, "Device attached\n"); @@ -2127,14 +2231,20 @@ rtsx_detach(device_t dev) { struct rtsx_softc *sc = device_get_softc(dev); + int err; if (bootverbose) device_printf(dev, "Detach - Vendor ID: 0x%x - Device ID: 0x%x\n", pci_get_vendor(dev), pci_get_device(dev)); /* Stop device */ - rtsx_stop(sc); + err = rtsx_stop(sc); + if (err != 0) + return err; + taskqueue_drain(taskqueue_swi_giant, &sc->card_task); + taskqueue_drain_timeout(taskqueue_swi_giant, &sc->card_delayed_task); + /* Teardown the state in our softc created in our attach routine. */ rtsx_dma_free(sc); if (sc->rtsx_res != NULL) @@ -2148,6 +2258,7 @@ pci_release_msi(dev); } RTSX_LOCK_DESTROY(sc); + return (0); }