diff options
author | Taku Izumi <izumi.taku@jp.fujitsu.com> | 2015-08-21 11:29:19 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-08-25 00:06:33 +0300 |
commit | a18aaec21ec8f4d2a4e09ad590437777a1ebf691 (patch) | |
tree | 4ef93fddc3c7671f382c30cb62150d22f66ec646 /drivers/net/fjes/fjes_hw.c | |
parent | 8cdc3f6c5d22dd059fe8127be7b5cae113e79afb (diff) | |
download | linux-a18aaec21ec8f4d2a4e09ad590437777a1ebf691.tar.xz |
fjes: Hardware cleanup routine
This patch adds hardware cleanup routine to be
invoked at driver's .remove routine.
Signed-off-by: Taku Izumi <izumi.taku@jp.fujitsu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/fjes/fjes_hw.c')
-rw-r--r-- | drivers/net/fjes/fjes_hw.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c index ae2663876605..757cece85387 100644 --- a/drivers/net/fjes/fjes_hw.c +++ b/drivers/net/fjes/fjes_hw.c @@ -56,6 +56,12 @@ static u8 *fjes_hw_iomap(struct fjes_hw *hw) return base; } +static void fjes_hw_iounmap(struct fjes_hw *hw) +{ + iounmap(hw->base); + release_mem_region(hw->hw_res.start, hw->hw_res.size); +} + int fjes_hw_reset(struct fjes_hw *hw) { union REG_DCTL dctl; @@ -109,6 +115,12 @@ static int fjes_hw_alloc_shared_status_region(struct fjes_hw *hw) return 0; } +static void fjes_hw_free_shared_status_region(struct fjes_hw *hw) +{ + kfree(hw->hw_info.share); + hw->hw_info.share = NULL; +} + static int fjes_hw_alloc_epbuf(struct epbuf_handler *epbh) { void *mem; @@ -126,6 +138,18 @@ static int fjes_hw_alloc_epbuf(struct epbuf_handler *epbh) return 0; } +static void fjes_hw_free_epbuf(struct epbuf_handler *epbh) +{ + if (epbh->buffer) + vfree(epbh->buffer); + + epbh->buffer = NULL; + epbh->size = 0; + + epbh->info = NULL; + epbh->ring = NULL; +} + void fjes_hw_setup_epbuf(struct epbuf_handler *epbh, u8 *mac_addr, u32 mtu) { union ep_buffer_info *info = epbh->info; @@ -258,6 +282,32 @@ static int fjes_hw_setup(struct fjes_hw *hw) return 0; } +static void fjes_hw_cleanup(struct fjes_hw *hw) +{ + int epidx; + + if (!hw->ep_shm_info) + return; + + fjes_hw_free_shared_status_region(hw); + + kfree(hw->hw_info.req_buf); + hw->hw_info.req_buf = NULL; + + kfree(hw->hw_info.res_buf); + hw->hw_info.res_buf = NULL; + + for (epidx = 0; epidx < hw->max_epid ; epidx++) { + if (epidx == hw->my_epid) + continue; + fjes_hw_free_epbuf(&hw->ep_shm_info[epidx].tx); + fjes_hw_free_epbuf(&hw->ep_shm_info[epidx].rx); + } + + kfree(hw->ep_shm_info); + hw->ep_shm_info = NULL; +} + int fjes_hw_init(struct fjes_hw *hw) { int ret; @@ -285,6 +335,22 @@ int fjes_hw_init(struct fjes_hw *hw) return ret; } +void fjes_hw_exit(struct fjes_hw *hw) +{ + int ret; + + if (hw->base) { + ret = fjes_hw_reset(hw); + if (ret) + pr_err("%s: reset error", __func__); + + fjes_hw_iounmap(hw); + hw->base = NULL; + } + + fjes_hw_cleanup(hw); +} + void fjes_hw_set_irqmask(struct fjes_hw *hw, enum REG_ICTL_MASK intr_mask, bool mask) { |