diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2009-11-29 10:10:44 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-29 20:23:54 -0500 |
commit | 76884835684411264cda2f15585261eb02183541 (patch) | |
tree | 585b42235745acf3bf161838b14682428175e670 /drivers/net/sfc | |
parent | c1c4f453b61463df4df16f7aa5782fc0cfe05b9e (diff) |
sfc: Extend MTD driver for use with new NICs
In new NICs flash is managed by firmware and we will use high-level
operations on partitions rather than direct SPI commands. Add support
for multiple MTD partitions per flash device and remove the direct
link between MTD and SPI devices. Maintain a list of MTD partitions
in struct efx_nic.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sfc')
-rw-r--r-- | drivers/net/sfc/efx.c | 3 | ||||
-rw-r--r-- | drivers/net/sfc/ethtool.c | 6 | ||||
-rw-r--r-- | drivers/net/sfc/falcon.c | 32 | ||||
-rw-r--r-- | drivers/net/sfc/mtd.c | 312 | ||||
-rw-r--r-- | drivers/net/sfc/net_driver.h | 8 | ||||
-rw-r--r-- | drivers/net/sfc/spi.h | 18 |
6 files changed, 255 insertions, 124 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 75dcaaedc3e8..4fe6d635ef3b 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c | |||
@@ -1977,6 +1977,9 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, | |||
1977 | spin_lock_init(&efx->biu_lock); | 1977 | spin_lock_init(&efx->biu_lock); |
1978 | mutex_init(&efx->mdio_lock); | 1978 | mutex_init(&efx->mdio_lock); |
1979 | mutex_init(&efx->spi_lock); | 1979 | mutex_init(&efx->spi_lock); |
1980 | #ifdef CONFIG_SFC_MTD | ||
1981 | INIT_LIST_HEAD(&efx->mtd_list); | ||
1982 | #endif | ||
1980 | INIT_WORK(&efx->reset_work, efx_reset_work); | 1983 | INIT_WORK(&efx->reset_work, efx_reset_work); |
1981 | INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor); | 1984 | INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor); |
1982 | efx->pci_dev = pci_dev; | 1985 | efx->pci_dev = pci_dev; |
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 4fe874052e3e..08a9db993743 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c | |||
@@ -567,7 +567,8 @@ static int efx_ethtool_get_eeprom(struct net_device *net_dev, | |||
567 | rc = mutex_lock_interruptible(&efx->spi_lock); | 567 | rc = mutex_lock_interruptible(&efx->spi_lock); |
568 | if (rc) | 568 | if (rc) |
569 | return rc; | 569 | return rc; |
570 | rc = falcon_spi_read(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, | 570 | rc = falcon_spi_read(efx, spi, |
571 | eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, | ||
571 | eeprom->len, &len, buf); | 572 | eeprom->len, &len, buf); |
572 | mutex_unlock(&efx->spi_lock); | 573 | mutex_unlock(&efx->spi_lock); |
573 | 574 | ||
@@ -590,7 +591,8 @@ static int efx_ethtool_set_eeprom(struct net_device *net_dev, | |||
590 | rc = mutex_lock_interruptible(&efx->spi_lock); | 591 | rc = mutex_lock_interruptible(&efx->spi_lock); |
591 | if (rc) | 592 | if (rc) |
592 | return rc; | 593 | return rc; |
593 | rc = falcon_spi_write(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, | 594 | rc = falcon_spi_write(efx, spi, |
595 | eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, | ||
594 | eeprom->len, &len, buf); | 596 | eeprom->len, &len, buf); |
595 | mutex_unlock(&efx->spi_lock); | 597 | mutex_unlock(&efx->spi_lock); |
596 | 598 | ||
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 29d45376e4c9..950de847d22b 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c | |||
@@ -1640,11 +1640,10 @@ static int falcon_spi_wait(struct efx_nic *efx) | |||
1640 | } | 1640 | } |
1641 | } | 1641 | } |
1642 | 1642 | ||
1643 | int falcon_spi_cmd(const struct efx_spi_device *spi, | 1643 | int falcon_spi_cmd(struct efx_nic *efx, const struct efx_spi_device *spi, |
1644 | unsigned int command, int address, | 1644 | unsigned int command, int address, |
1645 | const void *in, void *out, size_t len) | 1645 | const void *in, void *out, size_t len) |
1646 | { | 1646 | { |
1647 | struct efx_nic *efx = spi->efx; | ||
1648 | bool addressed = (address >= 0); | 1647 | bool addressed = (address >= 0); |
1649 | bool reading = (out != NULL); | 1648 | bool reading = (out != NULL); |
1650 | efx_oword_t reg; | 1649 | efx_oword_t reg; |
@@ -1713,15 +1712,15 @@ efx_spi_munge_command(const struct efx_spi_device *spi, | |||
1713 | } | 1712 | } |
1714 | 1713 | ||
1715 | /* Wait up to 10 ms for buffered write completion */ | 1714 | /* Wait up to 10 ms for buffered write completion */ |
1716 | int falcon_spi_wait_write(const struct efx_spi_device *spi) | 1715 | int |
1716 | falcon_spi_wait_write(struct efx_nic *efx, const struct efx_spi_device *spi) | ||
1717 | { | 1717 | { |
1718 | struct efx_nic *efx = spi->efx; | ||
1719 | unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 100); | 1718 | unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 100); |
1720 | u8 status; | 1719 | u8 status; |
1721 | int rc; | 1720 | int rc; |
1722 | 1721 | ||
1723 | for (;;) { | 1722 | for (;;) { |
1724 | rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, | 1723 | rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, |
1725 | &status, sizeof(status)); | 1724 | &status, sizeof(status)); |
1726 | if (rc) | 1725 | if (rc) |
1727 | return rc; | 1726 | return rc; |
@@ -1737,8 +1736,8 @@ int falcon_spi_wait_write(const struct efx_spi_device *spi) | |||
1737 | } | 1736 | } |
1738 | } | 1737 | } |
1739 | 1738 | ||
1740 | int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, | 1739 | int falcon_spi_read(struct efx_nic *efx, const struct efx_spi_device *spi, |
1741 | size_t len, size_t *retlen, u8 *buffer) | 1740 | loff_t start, size_t len, size_t *retlen, u8 *buffer) |
1742 | { | 1741 | { |
1743 | size_t block_len, pos = 0; | 1742 | size_t block_len, pos = 0; |
1744 | unsigned int command; | 1743 | unsigned int command; |
@@ -1748,7 +1747,7 @@ int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, | |||
1748 | block_len = min(len - pos, FALCON_SPI_MAX_LEN); | 1747 | block_len = min(len - pos, FALCON_SPI_MAX_LEN); |
1749 | 1748 | ||
1750 | command = efx_spi_munge_command(spi, SPI_READ, start + pos); | 1749 | command = efx_spi_munge_command(spi, SPI_READ, start + pos); |
1751 | rc = falcon_spi_cmd(spi, command, start + pos, NULL, | 1750 | rc = falcon_spi_cmd(efx, spi, command, start + pos, NULL, |
1752 | buffer + pos, block_len); | 1751 | buffer + pos, block_len); |
1753 | if (rc) | 1752 | if (rc) |
1754 | break; | 1753 | break; |
@@ -1767,8 +1766,9 @@ int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, | |||
1767 | return rc; | 1766 | return rc; |
1768 | } | 1767 | } |
1769 | 1768 | ||
1770 | int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, | 1769 | int |
1771 | size_t len, size_t *retlen, const u8 *buffer) | 1770 | falcon_spi_write(struct efx_nic *efx, const struct efx_spi_device *spi, |
1771 | loff_t start, size_t len, size_t *retlen, const u8 *buffer) | ||
1772 | { | 1772 | { |
1773 | u8 verify_buffer[FALCON_SPI_MAX_LEN]; | 1773 | u8 verify_buffer[FALCON_SPI_MAX_LEN]; |
1774 | size_t block_len, pos = 0; | 1774 | size_t block_len, pos = 0; |
@@ -1776,24 +1776,24 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, | |||
1776 | int rc = 0; | 1776 | int rc = 0; |
1777 | 1777 | ||
1778 | while (pos < len) { | 1778 | while (pos < len) { |
1779 | rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); | 1779 | rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); |
1780 | if (rc) | 1780 | if (rc) |
1781 | break; | 1781 | break; |
1782 | 1782 | ||
1783 | block_len = min(len - pos, | 1783 | block_len = min(len - pos, |
1784 | falcon_spi_write_limit(spi, start + pos)); | 1784 | falcon_spi_write_limit(spi, start + pos)); |
1785 | command = efx_spi_munge_command(spi, SPI_WRITE, start + pos); | 1785 | command = efx_spi_munge_command(spi, SPI_WRITE, start + pos); |
1786 | rc = falcon_spi_cmd(spi, command, start + pos, | 1786 | rc = falcon_spi_cmd(efx, spi, command, start + pos, |
1787 | buffer + pos, NULL, block_len); | 1787 | buffer + pos, NULL, block_len); |
1788 | if (rc) | 1788 | if (rc) |
1789 | break; | 1789 | break; |
1790 | 1790 | ||
1791 | rc = falcon_spi_wait_write(spi); | 1791 | rc = falcon_spi_wait_write(efx, spi); |
1792 | if (rc) | 1792 | if (rc) |
1793 | break; | 1793 | break; |
1794 | 1794 | ||
1795 | command = efx_spi_munge_command(spi, SPI_READ, start + pos); | 1795 | command = efx_spi_munge_command(spi, SPI_READ, start + pos); |
1796 | rc = falcon_spi_cmd(spi, command, start + pos, | 1796 | rc = falcon_spi_cmd(efx, spi, command, start + pos, |
1797 | NULL, verify_buffer, block_len); | 1797 | NULL, verify_buffer, block_len); |
1798 | if (memcmp(verify_buffer, buffer + pos, block_len)) { | 1798 | if (memcmp(verify_buffer, buffer + pos, block_len)) { |
1799 | rc = -EIO; | 1799 | rc = -EIO; |
@@ -2352,7 +2352,7 @@ falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) | |||
2352 | nvconfig = region + FALCON_NVCONFIG_OFFSET; | 2352 | nvconfig = region + FALCON_NVCONFIG_OFFSET; |
2353 | 2353 | ||
2354 | mutex_lock(&efx->spi_lock); | 2354 | mutex_lock(&efx->spi_lock); |
2355 | rc = falcon_spi_read(spi, 0, FALCON_NVCONFIG_END, NULL, region); | 2355 | rc = falcon_spi_read(efx, spi, 0, FALCON_NVCONFIG_END, NULL, region); |
2356 | mutex_unlock(&efx->spi_lock); | 2356 | mutex_unlock(&efx->spi_lock); |
2357 | if (rc) { | 2357 | if (rc) { |
2358 | EFX_ERR(efx, "Failed to read %s\n", | 2358 | EFX_ERR(efx, "Failed to read %s\n", |
@@ -2710,8 +2710,6 @@ static int falcon_spi_device_init(struct efx_nic *efx, | |||
2710 | spi_device->block_size = | 2710 | spi_device->block_size = |
2711 | 1 << SPI_DEV_TYPE_FIELD(device_type, | 2711 | 1 << SPI_DEV_TYPE_FIELD(device_type, |
2712 | SPI_DEV_TYPE_BLOCK_SIZE); | 2712 | SPI_DEV_TYPE_BLOCK_SIZE); |
2713 | |||
2714 | spi_device->efx = efx; | ||
2715 | } else { | 2713 | } else { |
2716 | spi_device = NULL; | 2714 | spi_device = NULL; |
2717 | } | 2715 | } |
diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c index 820c233c3ea0..3121e242d82e 100644 --- a/drivers/net/sfc/mtd.c +++ b/drivers/net/sfc/mtd.c | |||
@@ -11,26 +11,58 @@ | |||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/mtd/mtd.h> | 12 | #include <linux/mtd/mtd.h> |
13 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
14 | #include <linux/rtnetlink.h> | ||
14 | 15 | ||
15 | #define EFX_DRIVER_NAME "sfc_mtd" | 16 | #define EFX_DRIVER_NAME "sfc_mtd" |
16 | #include "net_driver.h" | 17 | #include "net_driver.h" |
17 | #include "spi.h" | 18 | #include "spi.h" |
18 | #include "efx.h" | 19 | #include "efx.h" |
20 | #include "falcon.h" | ||
19 | 21 | ||
20 | #define EFX_SPI_VERIFY_BUF_LEN 16 | 22 | #define EFX_SPI_VERIFY_BUF_LEN 16 |
21 | 23 | ||
22 | struct efx_mtd { | 24 | struct efx_mtd_partition { |
23 | const struct efx_spi_device *spi; | ||
24 | struct mtd_info mtd; | 25 | struct mtd_info mtd; |
26 | size_t offset; | ||
27 | const char *type_name; | ||
25 | char name[IFNAMSIZ + 20]; | 28 | char name[IFNAMSIZ + 20]; |
26 | }; | 29 | }; |
27 | 30 | ||
31 | struct efx_mtd_ops { | ||
32 | int (*read)(struct mtd_info *mtd, loff_t start, size_t len, | ||
33 | size_t *retlen, u8 *buffer); | ||
34 | int (*erase)(struct mtd_info *mtd, loff_t start, size_t len); | ||
35 | int (*write)(struct mtd_info *mtd, loff_t start, size_t len, | ||
36 | size_t *retlen, const u8 *buffer); | ||
37 | int (*sync)(struct mtd_info *mtd); | ||
38 | }; | ||
39 | |||
40 | struct efx_mtd { | ||
41 | struct list_head node; | ||
42 | struct efx_nic *efx; | ||
43 | const struct efx_spi_device *spi; | ||
44 | const char *name; | ||
45 | const struct efx_mtd_ops *ops; | ||
46 | size_t n_parts; | ||
47 | struct efx_mtd_partition part[0]; | ||
48 | }; | ||
49 | |||
50 | #define efx_for_each_partition(part, efx_mtd) \ | ||
51 | for ((part) = &(efx_mtd)->part[0]; \ | ||
52 | (part) != &(efx_mtd)->part[(efx_mtd)->n_parts]; \ | ||
53 | (part)++) | ||
54 | |||
55 | #define to_efx_mtd_partition(mtd) \ | ||
56 | container_of(mtd, struct efx_mtd_partition, mtd) | ||
57 | |||
58 | static int falcon_mtd_probe(struct efx_nic *efx); | ||
59 | |||
28 | /* SPI utilities */ | 60 | /* SPI utilities */ |
29 | 61 | ||
30 | static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) | 62 | static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) |
31 | { | 63 | { |
32 | const struct efx_spi_device *spi = efx_mtd->spi; | 64 | const struct efx_spi_device *spi = efx_mtd->spi; |
33 | struct efx_nic *efx = spi->efx; | 65 | struct efx_nic *efx = efx_mtd->efx; |
34 | u8 status; | 66 | u8 status; |
35 | int rc, i; | 67 | int rc, i; |
36 | 68 | ||
@@ -39,7 +71,7 @@ static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) | |||
39 | __set_current_state(uninterruptible ? | 71 | __set_current_state(uninterruptible ? |
40 | TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE); | 72 | TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE); |
41 | schedule_timeout(HZ / 10); | 73 | schedule_timeout(HZ / 10); |
42 | rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, | 74 | rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, |
43 | &status, sizeof(status)); | 75 | &status, sizeof(status)); |
44 | if (rc) | 76 | if (rc) |
45 | return rc; | 77 | return rc; |
@@ -52,32 +84,35 @@ static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) | |||
52 | return -ETIMEDOUT; | 84 | return -ETIMEDOUT; |
53 | } | 85 | } |
54 | 86 | ||
55 | static int efx_spi_unlock(const struct efx_spi_device *spi) | 87 | static int |
88 | efx_spi_unlock(struct efx_nic *efx, const struct efx_spi_device *spi) | ||
56 | { | 89 | { |
57 | const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 | | 90 | const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 | |
58 | SPI_STATUS_BP0); | 91 | SPI_STATUS_BP0); |
59 | u8 status; | 92 | u8 status; |
60 | int rc; | 93 | int rc; |
61 | 94 | ||
62 | rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, &status, sizeof(status)); | 95 | rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, |
96 | &status, sizeof(status)); | ||
63 | if (rc) | 97 | if (rc) |
64 | return rc; | 98 | return rc; |
65 | 99 | ||
66 | if (!(status & unlock_mask)) | 100 | if (!(status & unlock_mask)) |
67 | return 0; /* already unlocked */ | 101 | return 0; /* already unlocked */ |
68 | 102 | ||
69 | rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); | 103 | rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); |
70 | if (rc) | 104 | if (rc) |
71 | return rc; | 105 | return rc; |
72 | rc = falcon_spi_cmd(spi, SPI_SST_EWSR, -1, NULL, NULL, 0); | 106 | rc = falcon_spi_cmd(efx, spi, SPI_SST_EWSR, -1, NULL, NULL, 0); |
73 | if (rc) | 107 | if (rc) |
74 | return rc; | 108 | return rc; |
75 | 109 | ||
76 | status &= ~unlock_mask; | 110 | status &= ~unlock_mask; |
77 | rc = falcon_spi_cmd(spi, SPI_WRSR, -1, &status, NULL, sizeof(status)); | 111 | rc = falcon_spi_cmd(efx, spi, SPI_WRSR, -1, &status, |
112 | NULL, sizeof(status)); | ||
78 | if (rc) | 113 | if (rc) |
79 | return rc; | 114 | return rc; |
80 | rc = falcon_spi_wait_write(spi); | 115 | rc = falcon_spi_wait_write(efx, spi); |
81 | if (rc) | 116 | if (rc) |
82 | return rc; | 117 | return rc; |
83 | 118 | ||
@@ -87,6 +122,7 @@ static int efx_spi_unlock(const struct efx_spi_device *spi) | |||
87 | static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) | 122 | static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) |
88 | { | 123 | { |
89 | const struct efx_spi_device *spi = efx_mtd->spi; | 124 | const struct efx_spi_device *spi = efx_mtd->spi; |
125 | struct efx_nic *efx = efx_mtd->efx; | ||
90 | unsigned pos, block_len; | 126 | unsigned pos, block_len; |
91 | u8 empty[EFX_SPI_VERIFY_BUF_LEN]; | 127 | u8 empty[EFX_SPI_VERIFY_BUF_LEN]; |
92 | u8 buffer[EFX_SPI_VERIFY_BUF_LEN]; | 128 | u8 buffer[EFX_SPI_VERIFY_BUF_LEN]; |
@@ -98,13 +134,14 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) | |||
98 | if (spi->erase_command == 0) | 134 | if (spi->erase_command == 0) |
99 | return -EOPNOTSUPP; | 135 | return -EOPNOTSUPP; |
100 | 136 | ||
101 | rc = efx_spi_unlock(spi); | 137 | rc = efx_spi_unlock(efx, spi); |
102 | if (rc) | 138 | if (rc) |
103 | return rc; | 139 | return rc; |
104 | rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); | 140 | rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); |
105 | if (rc) | 141 | if (rc) |
106 | return rc; | 142 | return rc; |
107 | rc = falcon_spi_cmd(spi, spi->erase_command, start, NULL, NULL, 0); | 143 | rc = falcon_spi_cmd(efx, spi, spi->erase_command, start, NULL, |
144 | NULL, 0); | ||
108 | if (rc) | 145 | if (rc) |
109 | return rc; | 146 | return rc; |
110 | rc = efx_spi_slow_wait(efx_mtd, false); | 147 | rc = efx_spi_slow_wait(efx_mtd, false); |
@@ -113,7 +150,8 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) | |||
113 | memset(empty, 0xff, sizeof(empty)); | 150 | memset(empty, 0xff, sizeof(empty)); |
114 | for (pos = 0; pos < len; pos += block_len) { | 151 | for (pos = 0; pos < len; pos += block_len) { |
115 | block_len = min(len - pos, sizeof(buffer)); | 152 | block_len = min(len - pos, sizeof(buffer)); |
116 | rc = falcon_spi_read(spi, start + pos, block_len, NULL, buffer); | 153 | rc = falcon_spi_read(efx, spi, start + pos, block_len, |
154 | NULL, buffer); | ||
117 | if (rc) | 155 | if (rc) |
118 | return rc; | 156 | return rc; |
119 | if (memcmp(empty, buffer, block_len)) | 157 | if (memcmp(empty, buffer, block_len)) |
@@ -130,140 +168,228 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) | |||
130 | 168 | ||
131 | /* MTD interface */ | 169 | /* MTD interface */ |
132 | 170 | ||
133 | static int efx_mtd_read(struct mtd_info *mtd, loff_t start, size_t len, | 171 | static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) |
134 | size_t *retlen, u8 *buffer) | 172 | { |
173 | struct efx_mtd *efx_mtd = mtd->priv; | ||
174 | int rc; | ||
175 | |||
176 | rc = efx_mtd->ops->erase(mtd, erase->addr, erase->len); | ||
177 | if (rc == 0) { | ||
178 | erase->state = MTD_ERASE_DONE; | ||
179 | } else { | ||
180 | erase->state = MTD_ERASE_FAILED; | ||
181 | erase->fail_addr = 0xffffffff; | ||
182 | } | ||
183 | mtd_erase_callback(erase); | ||
184 | return rc; | ||
185 | } | ||
186 | |||
187 | static void efx_mtd_sync(struct mtd_info *mtd) | ||
188 | { | ||
189 | struct efx_mtd *efx_mtd = mtd->priv; | ||
190 | struct efx_nic *efx = efx_mtd->efx; | ||
191 | int rc; | ||
192 | |||
193 | rc = efx_mtd->ops->sync(mtd); | ||
194 | if (rc) | ||
195 | EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc); | ||
196 | } | ||
197 | |||
198 | static void efx_mtd_remove_partition(struct efx_mtd_partition *part) | ||
199 | { | ||
200 | int rc; | ||
201 | |||
202 | for (;;) { | ||
203 | rc = del_mtd_device(&part->mtd); | ||
204 | if (rc != -EBUSY) | ||
205 | break; | ||
206 | ssleep(1); | ||
207 | } | ||
208 | WARN_ON(rc); | ||
209 | } | ||
210 | |||
211 | static void efx_mtd_remove_device(struct efx_mtd *efx_mtd) | ||
212 | { | ||
213 | struct efx_mtd_partition *part; | ||
214 | |||
215 | efx_for_each_partition(part, efx_mtd) | ||
216 | efx_mtd_remove_partition(part); | ||
217 | list_del(&efx_mtd->node); | ||
218 | kfree(efx_mtd); | ||
219 | } | ||
220 | |||
221 | static void efx_mtd_rename_device(struct efx_mtd *efx_mtd) | ||
222 | { | ||
223 | struct efx_mtd_partition *part; | ||
224 | |||
225 | efx_for_each_partition(part, efx_mtd) | ||
226 | snprintf(part->name, sizeof(part->name), | ||
227 | "%s %s", efx_mtd->efx->name, | ||
228 | part->type_name); | ||
229 | } | ||
230 | |||
231 | static int efx_mtd_probe_device(struct efx_nic *efx, struct efx_mtd *efx_mtd) | ||
232 | { | ||
233 | struct efx_mtd_partition *part; | ||
234 | |||
235 | efx_mtd->efx = efx; | ||
236 | |||
237 | efx_mtd_rename_device(efx_mtd); | ||
238 | |||
239 | efx_for_each_partition(part, efx_mtd) { | ||
240 | part->mtd.writesize = 1; | ||
241 | |||
242 | part->mtd.owner = THIS_MODULE; | ||
243 | part->mtd.priv = efx_mtd; | ||
244 | part->mtd.name = part->name; | ||
245 | part->mtd.erase = efx_mtd_erase; | ||
246 | part->mtd.read = efx_mtd->ops->read; | ||
247 | part->mtd.write = efx_mtd->ops->write; | ||
248 | part->mtd.sync = efx_mtd_sync; | ||
249 | |||
250 | if (add_mtd_device(&part->mtd)) | ||
251 | goto fail; | ||
252 | } | ||
253 | |||
254 | list_add(&efx_mtd->node, &efx->mtd_list); | ||
255 | return 0; | ||
256 | |||
257 | fail: | ||
258 | while (part != &efx_mtd->part[0]) { | ||
259 | --part; | ||
260 | efx_mtd_remove_partition(part); | ||
261 | } | ||
262 | /* add_mtd_device() returns 1 if the MTD table is full */ | ||
263 | return -ENOMEM; | ||
264 | } | ||
265 | |||
266 | void efx_mtd_remove(struct efx_nic *efx) | ||
135 | { | 267 | { |
268 | struct efx_mtd *efx_mtd, *next; | ||
269 | |||
270 | WARN_ON(efx_dev_registered(efx)); | ||
271 | |||
272 | list_for_each_entry_safe(efx_mtd, next, &efx->mtd_list, node) | ||
273 | efx_mtd_remove_device(efx_mtd); | ||
274 | } | ||
275 | |||
276 | void efx_mtd_rename(struct efx_nic *efx) | ||
277 | { | ||
278 | struct efx_mtd *efx_mtd; | ||
279 | |||
280 | ASSERT_RTNL(); | ||
281 | |||
282 | list_for_each_entry(efx_mtd, &efx->mtd_list, node) | ||
283 | efx_mtd_rename_device(efx_mtd); | ||
284 | } | ||
285 | |||
286 | int efx_mtd_probe(struct efx_nic *efx) | ||
287 | { | ||
288 | return falcon_mtd_probe(efx); | ||
289 | } | ||
290 | |||
291 | /* Implementation of MTD operations for Falcon */ | ||
292 | |||
293 | static int falcon_mtd_read(struct mtd_info *mtd, loff_t start, | ||
294 | size_t len, size_t *retlen, u8 *buffer) | ||
295 | { | ||
296 | struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); | ||
136 | struct efx_mtd *efx_mtd = mtd->priv; | 297 | struct efx_mtd *efx_mtd = mtd->priv; |
137 | const struct efx_spi_device *spi = efx_mtd->spi; | 298 | const struct efx_spi_device *spi = efx_mtd->spi; |
138 | struct efx_nic *efx = spi->efx; | 299 | struct efx_nic *efx = efx_mtd->efx; |
139 | int rc; | 300 | int rc; |
140 | 301 | ||
141 | rc = mutex_lock_interruptible(&efx->spi_lock); | 302 | rc = mutex_lock_interruptible(&efx->spi_lock); |
142 | if (rc) | 303 | if (rc) |
143 | return rc; | 304 | return rc; |
144 | rc = falcon_spi_read(spi, FALCON_FLASH_BOOTCODE_START + start, | 305 | rc = falcon_spi_read(efx, spi, part->offset + start, len, |
145 | len, retlen, buffer); | 306 | retlen, buffer); |
146 | mutex_unlock(&efx->spi_lock); | 307 | mutex_unlock(&efx->spi_lock); |
147 | return rc; | 308 | return rc; |
148 | } | 309 | } |
149 | 310 | ||
150 | static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) | 311 | static int falcon_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len) |
151 | { | 312 | { |
313 | struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); | ||
152 | struct efx_mtd *efx_mtd = mtd->priv; | 314 | struct efx_mtd *efx_mtd = mtd->priv; |
153 | struct efx_nic *efx = efx_mtd->spi->efx; | 315 | struct efx_nic *efx = efx_mtd->efx; |
154 | int rc; | 316 | int rc; |
155 | 317 | ||
156 | rc = mutex_lock_interruptible(&efx->spi_lock); | 318 | rc = mutex_lock_interruptible(&efx->spi_lock); |
157 | if (rc) | 319 | if (rc) |
158 | return rc; | 320 | return rc; |
159 | rc = efx_spi_erase(efx_mtd, FALCON_FLASH_BOOTCODE_START + erase->addr, | 321 | rc = efx_spi_erase(efx_mtd, part->offset + start, len); |
160 | erase->len); | ||
161 | mutex_unlock(&efx->spi_lock); | 322 | mutex_unlock(&efx->spi_lock); |
162 | |||
163 | if (rc == 0) { | ||
164 | erase->state = MTD_ERASE_DONE; | ||
165 | } else { | ||
166 | erase->state = MTD_ERASE_FAILED; | ||
167 | erase->fail_addr = 0xffffffff; | ||
168 | } | ||
169 | mtd_erase_callback(erase); | ||
170 | return rc; | 323 | return rc; |
171 | } | 324 | } |
172 | 325 | ||
173 | static int efx_mtd_write(struct mtd_info *mtd, loff_t start, | 326 | static int falcon_mtd_write(struct mtd_info *mtd, loff_t start, |
174 | size_t len, size_t *retlen, const u8 *buffer) | 327 | size_t len, size_t *retlen, const u8 *buffer) |
175 | { | 328 | { |
329 | struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); | ||
176 | struct efx_mtd *efx_mtd = mtd->priv; | 330 | struct efx_mtd *efx_mtd = mtd->priv; |
177 | const struct efx_spi_device *spi = efx_mtd->spi; | 331 | const struct efx_spi_device *spi = efx_mtd->spi; |
178 | struct efx_nic *efx = spi->efx; | 332 | struct efx_nic *efx = efx_mtd->efx; |
179 | int rc; | 333 | int rc; |
180 | 334 | ||
181 | rc = mutex_lock_interruptible(&efx->spi_lock); | 335 | rc = mutex_lock_interruptible(&efx->spi_lock); |
182 | if (rc) | 336 | if (rc) |
183 | return rc; | 337 | return rc; |
184 | rc = falcon_spi_write(spi, FALCON_FLASH_BOOTCODE_START + start, | 338 | rc = falcon_spi_write(efx, spi, part->offset + start, len, |
185 | len, retlen, buffer); | 339 | retlen, buffer); |
186 | mutex_unlock(&efx->spi_lock); | 340 | mutex_unlock(&efx->spi_lock); |
187 | return rc; | 341 | return rc; |
188 | } | 342 | } |
189 | 343 | ||
190 | static void efx_mtd_sync(struct mtd_info *mtd) | 344 | static int falcon_mtd_sync(struct mtd_info *mtd) |
191 | { | 345 | { |
192 | struct efx_mtd *efx_mtd = mtd->priv; | 346 | struct efx_mtd *efx_mtd = mtd->priv; |
193 | struct efx_nic *efx = efx_mtd->spi->efx; | 347 | struct efx_nic *efx = efx_mtd->efx; |
194 | int rc; | 348 | int rc; |
195 | 349 | ||
196 | mutex_lock(&efx->spi_lock); | 350 | mutex_lock(&efx->spi_lock); |
197 | rc = efx_spi_slow_wait(efx_mtd, true); | 351 | rc = efx_spi_slow_wait(efx_mtd, true); |
198 | mutex_unlock(&efx->spi_lock); | 352 | mutex_unlock(&efx->spi_lock); |
199 | 353 | return rc; | |
200 | if (rc) | ||
201 | EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc); | ||
202 | return; | ||
203 | } | ||
204 | |||
205 | void efx_mtd_remove(struct efx_nic *efx) | ||
206 | { | ||
207 | if (efx->spi_flash && efx->spi_flash->mtd) { | ||
208 | struct efx_mtd *efx_mtd = efx->spi_flash->mtd; | ||
209 | int rc; | ||
210 | |||
211 | for (;;) { | ||
212 | rc = del_mtd_device(&efx_mtd->mtd); | ||
213 | if (rc != -EBUSY) | ||
214 | break; | ||
215 | ssleep(1); | ||
216 | } | ||
217 | WARN_ON(rc); | ||
218 | kfree(efx_mtd); | ||
219 | } | ||
220 | } | 354 | } |
221 | 355 | ||
222 | void efx_mtd_rename(struct efx_nic *efx) | 356 | static struct efx_mtd_ops falcon_mtd_ops = { |
223 | { | 357 | .read = falcon_mtd_read, |
224 | if (efx->spi_flash && efx->spi_flash->mtd) { | 358 | .erase = falcon_mtd_erase, |
225 | struct efx_mtd *efx_mtd = efx->spi_flash->mtd; | 359 | .write = falcon_mtd_write, |
226 | snprintf(efx_mtd->name, sizeof(efx_mtd->name), | 360 | .sync = falcon_mtd_sync, |
227 | "%s sfc_flash_bootrom", efx->name); | 361 | }; |
228 | } | ||
229 | } | ||
230 | 362 | ||
231 | int efx_mtd_probe(struct efx_nic *efx) | 363 | static int falcon_mtd_probe(struct efx_nic *efx) |
232 | { | 364 | { |
233 | struct efx_spi_device *spi = efx->spi_flash; | 365 | struct efx_spi_device *spi = efx->spi_flash; |
234 | struct efx_mtd *efx_mtd; | 366 | struct efx_mtd *efx_mtd; |
367 | int rc; | ||
368 | |||
369 | ASSERT_RTNL(); | ||
235 | 370 | ||
236 | if (!spi || spi->size <= FALCON_FLASH_BOOTCODE_START) | 371 | if (!spi || spi->size <= FALCON_FLASH_BOOTCODE_START) |
237 | return -ENODEV; | 372 | return -ENODEV; |
238 | 373 | ||
239 | efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL); | 374 | efx_mtd = kzalloc(sizeof(*efx_mtd) + sizeof(efx_mtd->part[0]), |
375 | GFP_KERNEL); | ||
240 | if (!efx_mtd) | 376 | if (!efx_mtd) |
241 | return -ENOMEM; | 377 | return -ENOMEM; |
242 | 378 | ||
243 | efx_mtd->spi = spi; | 379 | efx_mtd->spi = spi; |
244 | spi->mtd = efx_mtd; | 380 | efx_mtd->name = "flash"; |
245 | 381 | efx_mtd->ops = &falcon_mtd_ops; | |
246 | efx_mtd->mtd.type = MTD_NORFLASH; | 382 | |
247 | efx_mtd->mtd.flags = MTD_CAP_NORFLASH; | 383 | efx_mtd->n_parts = 1; |
248 | efx_mtd->mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START; | 384 | efx_mtd->part[0].mtd.type = MTD_NORFLASH; |
249 | efx_mtd->mtd.erasesize = spi->erase_size; | 385 | efx_mtd->part[0].mtd.flags = MTD_CAP_NORFLASH; |
250 | efx_mtd->mtd.writesize = 1; | 386 | efx_mtd->part[0].mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START; |
251 | efx_mtd_rename(efx); | 387 | efx_mtd->part[0].mtd.erasesize = spi->erase_size; |
252 | 388 | efx_mtd->part[0].offset = FALCON_FLASH_BOOTCODE_START; | |
253 | efx_mtd->mtd.owner = THIS_MODULE; | 389 | efx_mtd->part[0].type_name = "sfc_flash_bootrom"; |
254 | efx_mtd->mtd.priv = efx_mtd; | 390 | |
255 | efx_mtd->mtd.name = efx_mtd->name; | 391 | rc = efx_mtd_probe_device(efx, efx_mtd); |
256 | efx_mtd->mtd.erase = efx_mtd_erase; | 392 | if (rc) |
257 | efx_mtd->mtd.read = efx_mtd_read; | ||
258 | efx_mtd->mtd.write = efx_mtd_write; | ||
259 | efx_mtd->mtd.sync = efx_mtd_sync; | ||
260 | |||
261 | if (add_mtd_device(&efx_mtd->mtd)) { | ||
262 | kfree(efx_mtd); | 393 | kfree(efx_mtd); |
263 | spi->mtd = NULL; | 394 | return rc; |
264 | /* add_mtd_device() returns 1 if the MTD table is full */ | ||
265 | return -ENOMEM; | ||
266 | } | ||
267 | |||
268 | return 0; | ||
269 | } | 395 | } |
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 452f83510b0d..e1534ba6ad79 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h | |||
@@ -674,10 +674,11 @@ union efx_multicast_hash { | |||
674 | * interrupt is handled. It is used by falcon_test_interrupt() | 674 | * interrupt is handled. It is used by falcon_test_interrupt() |
675 | * to verify that an interrupt has occurred. | 675 | * to verify that an interrupt has occurred. |
676 | * @spi_flash: SPI flash device | 676 | * @spi_flash: SPI flash device |
677 | * This field will be %NULL if no flash device is present. | 677 | * This field will be %NULL if no flash device is present (or for Siena). |
678 | * @spi_eeprom: SPI EEPROM device | 678 | * @spi_eeprom: SPI EEPROM device |
679 | * This field will be %NULL if no EEPROM device is present. | 679 | * This field will be %NULL if no EEPROM device is present (or for Siena). |
680 | * @spi_lock: SPI bus lock | 680 | * @spi_lock: SPI bus lock |
681 | * @mtd_list: List of MTDs attached to the NIC | ||
681 | * @n_rx_nodesc_drop_cnt: RX no descriptor drop count | 682 | * @n_rx_nodesc_drop_cnt: RX no descriptor drop count |
682 | * @nic_data: Hardware dependant state | 683 | * @nic_data: Hardware dependant state |
683 | * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, | 684 | * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, |
@@ -759,6 +760,9 @@ struct efx_nic { | |||
759 | struct efx_spi_device *spi_flash; | 760 | struct efx_spi_device *spi_flash; |
760 | struct efx_spi_device *spi_eeprom; | 761 | struct efx_spi_device *spi_eeprom; |
761 | struct mutex spi_lock; | 762 | struct mutex spi_lock; |
763 | #ifdef CONFIG_SFC_MTD | ||
764 | struct list_head mtd_list; | ||
765 | #endif | ||
762 | 766 | ||
763 | unsigned n_rx_nodesc_drop_cnt; | 767 | unsigned n_rx_nodesc_drop_cnt; |
764 | 768 | ||
diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h index 1b1ceb411671..8bf4fce0813a 100644 --- a/drivers/net/sfc/spi.h +++ b/drivers/net/sfc/spi.h | |||
@@ -36,8 +36,6 @@ | |||
36 | 36 | ||
37 | /** | 37 | /** |
38 | * struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device | 38 | * struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device |
39 | * @efx: The Efx controller that owns this device | ||
40 | * @mtd: MTD state | ||
41 | * @device_id: Controller's id for the device | 39 | * @device_id: Controller's id for the device |
42 | * @size: Size (in bytes) | 40 | * @size: Size (in bytes) |
43 | * @addr_len: Number of address bytes in read/write commands | 41 | * @addr_len: Number of address bytes in read/write commands |
@@ -54,10 +52,6 @@ | |||
54 | * Write commands are limited to blocks with this size and alignment. | 52 | * Write commands are limited to blocks with this size and alignment. |
55 | */ | 53 | */ |
56 | struct efx_spi_device { | 54 | struct efx_spi_device { |
57 | struct efx_nic *efx; | ||
58 | #ifdef CONFIG_SFC_MTD | ||
59 | void *mtd; | ||
60 | #endif | ||
61 | int device_id; | 55 | int device_id; |
62 | unsigned int size; | 56 | unsigned int size; |
63 | unsigned int addr_len; | 57 | unsigned int addr_len; |
@@ -67,12 +61,16 @@ struct efx_spi_device { | |||
67 | unsigned int block_size; | 61 | unsigned int block_size; |
68 | }; | 62 | }; |
69 | 63 | ||
70 | int falcon_spi_cmd(const struct efx_spi_device *spi, unsigned int command, | 64 | int falcon_spi_cmd(struct efx_nic *efx, |
65 | const struct efx_spi_device *spi, unsigned int command, | ||
71 | int address, const void* in, void *out, size_t len); | 66 | int address, const void* in, void *out, size_t len); |
72 | int falcon_spi_wait_write(const struct efx_spi_device *spi); | 67 | int falcon_spi_wait_write(struct efx_nic *efx, |
73 | int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, | 68 | const struct efx_spi_device *spi); |
69 | int falcon_spi_read(struct efx_nic *efx, | ||
70 | const struct efx_spi_device *spi, loff_t start, | ||
74 | size_t len, size_t *retlen, u8 *buffer); | 71 | size_t len, size_t *retlen, u8 *buffer); |
75 | int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, | 72 | int falcon_spi_write(struct efx_nic *efx, |
73 | const struct efx_spi_device *spi, loff_t start, | ||
76 | size_t len, size_t *retlen, const u8 *buffer); | 74 | size_t len, size_t *retlen, const u8 *buffer); |
77 | 75 | ||
78 | /* | 76 | /* |