diff options
Diffstat (limited to 'drivers/net/cassini.c')
-rw-r--r-- | drivers/net/cassini.c | 56 |
1 files changed, 49 insertions, 7 deletions
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index f1936d51b458..86909cfb14de 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c | |||
@@ -74,6 +74,7 @@ | |||
74 | #include <linux/slab.h> | 74 | #include <linux/slab.h> |
75 | #include <linux/delay.h> | 75 | #include <linux/delay.h> |
76 | #include <linux/init.h> | 76 | #include <linux/init.h> |
77 | #include <linux/vmalloc.h> | ||
77 | #include <linux/ioport.h> | 78 | #include <linux/ioport.h> |
78 | #include <linux/pci.h> | 79 | #include <linux/pci.h> |
79 | #include <linux/mm.h> | 80 | #include <linux/mm.h> |
@@ -91,6 +92,7 @@ | |||
91 | #include <linux/ip.h> | 92 | #include <linux/ip.h> |
92 | #include <linux/tcp.h> | 93 | #include <linux/tcp.h> |
93 | #include <linux/mutex.h> | 94 | #include <linux/mutex.h> |
95 | #include <linux/firmware.h> | ||
94 | 96 | ||
95 | #include <net/checksum.h> | 97 | #include <net/checksum.h> |
96 | 98 | ||
@@ -197,6 +199,7 @@ static int link_mode; | |||
197 | MODULE_AUTHOR("Adrian Sun (asun@darksunrising.com)"); | 199 | MODULE_AUTHOR("Adrian Sun (asun@darksunrising.com)"); |
198 | MODULE_DESCRIPTION("Sun Cassini(+) ethernet driver"); | 200 | MODULE_DESCRIPTION("Sun Cassini(+) ethernet driver"); |
199 | MODULE_LICENSE("GPL"); | 201 | MODULE_LICENSE("GPL"); |
202 | MODULE_FIRMWARE("sun/cassini.bin"); | ||
200 | module_param(cassini_debug, int, 0); | 203 | module_param(cassini_debug, int, 0); |
201 | MODULE_PARM_DESC(cassini_debug, "Cassini bitmapped debugging message enable value"); | 204 | MODULE_PARM_DESC(cassini_debug, "Cassini bitmapped debugging message enable value"); |
202 | module_param(link_mode, int, 0); | 205 | module_param(link_mode, int, 0); |
@@ -812,9 +815,44 @@ static int cas_reset_mii_phy(struct cas *cp) | |||
812 | return (limit <= 0); | 815 | return (limit <= 0); |
813 | } | 816 | } |
814 | 817 | ||
818 | static int cas_saturn_firmware_init(struct cas *cp) | ||
819 | { | ||
820 | const struct firmware *fw; | ||
821 | const char fw_name[] = "sun/cassini.bin"; | ||
822 | int err; | ||
823 | |||
824 | if (PHY_NS_DP83065 != cp->phy_id) | ||
825 | return 0; | ||
826 | |||
827 | err = request_firmware(&fw, fw_name, &cp->pdev->dev); | ||
828 | if (err) { | ||
829 | printk(KERN_ERR "cassini: Failed to load firmware \"%s\"\n", | ||
830 | fw_name); | ||
831 | return err; | ||
832 | } | ||
833 | if (fw->size < 2) { | ||
834 | printk(KERN_ERR "cassini: bogus length %zu in \"%s\"\n", | ||
835 | fw->size, fw_name); | ||
836 | err = -EINVAL; | ||
837 | goto out; | ||
838 | } | ||
839 | cp->fw_load_addr= fw->data[1] << 8 | fw->data[0]; | ||
840 | cp->fw_size = fw->size - 2; | ||
841 | cp->fw_data = vmalloc(cp->fw_size); | ||
842 | if (!cp->fw_data) { | ||
843 | err = -ENOMEM; | ||
844 | printk(KERN_ERR "cassini: \"%s\" Failed %d\n", fw_name, err); | ||
845 | goto out; | ||
846 | } | ||
847 | memcpy(cp->fw_data, &fw->data[2], cp->fw_size); | ||
848 | out: | ||
849 | release_firmware(fw); | ||
850 | return err; | ||
851 | } | ||
852 | |||
815 | static void cas_saturn_firmware_load(struct cas *cp) | 853 | static void cas_saturn_firmware_load(struct cas *cp) |
816 | { | 854 | { |
817 | cas_saturn_patch_t *patch = cas_saturn_patch; | 855 | int i; |
818 | 856 | ||
819 | cas_phy_powerdown(cp); | 857 | cas_phy_powerdown(cp); |
820 | 858 | ||
@@ -833,11 +871,9 @@ static void cas_saturn_firmware_load(struct cas *cp) | |||
833 | 871 | ||
834 | /* download new firmware */ | 872 | /* download new firmware */ |
835 | cas_phy_write(cp, DP83065_MII_MEM, 0x1); | 873 | cas_phy_write(cp, DP83065_MII_MEM, 0x1); |
836 | cas_phy_write(cp, DP83065_MII_REGE, patch->addr); | 874 | cas_phy_write(cp, DP83065_MII_REGE, cp->fw_load_addr); |
837 | while (patch->addr) { | 875 | for (i = 0; i < cp->fw_size; i++) |
838 | cas_phy_write(cp, DP83065_MII_REGD, patch->val); | 876 | cas_phy_write(cp, DP83065_MII_REGD, cp->fw_data[i]); |
839 | patch++; | ||
840 | } | ||
841 | 877 | ||
842 | /* enable firmware */ | 878 | /* enable firmware */ |
843 | cas_phy_write(cp, DP83065_MII_REGE, 0x8ff8); | 879 | cas_phy_write(cp, DP83065_MII_REGE, 0x8ff8); |
@@ -2182,7 +2218,7 @@ static inline void cas_rx_flow_pkt(struct cas *cp, const u64 *words, | |||
2182 | * do any additional locking here. stick the buffer | 2218 | * do any additional locking here. stick the buffer |
2183 | * at the end. | 2219 | * at the end. |
2184 | */ | 2220 | */ |
2185 | __skb_insert(skb, flow->prev, (struct sk_buff *) flow, flow); | 2221 | __skb_queue_tail(flow, skb); |
2186 | if (words[0] & RX_COMP1_RELEASE_FLOW) { | 2222 | if (words[0] & RX_COMP1_RELEASE_FLOW) { |
2187 | while ((skb = __skb_dequeue(flow))) { | 2223 | while ((skb = __skb_dequeue(flow))) { |
2188 | cas_skb_release(skb); | 2224 | cas_skb_release(skb); |
@@ -5108,6 +5144,9 @@ static int __devinit cas_init_one(struct pci_dev *pdev, | |||
5108 | cas_reset(cp, 0); | 5144 | cas_reset(cp, 0); |
5109 | if (cas_check_invariants(cp)) | 5145 | if (cas_check_invariants(cp)) |
5110 | goto err_out_iounmap; | 5146 | goto err_out_iounmap; |
5147 | if (cp->cas_flags & CAS_FLAG_SATURN) | ||
5148 | if (cas_saturn_firmware_init(cp)) | ||
5149 | goto err_out_iounmap; | ||
5111 | 5150 | ||
5112 | cp->init_block = (struct cas_init_block *) | 5151 | cp->init_block = (struct cas_init_block *) |
5113 | pci_alloc_consistent(pdev, sizeof(struct cas_init_block), | 5152 | pci_alloc_consistent(pdev, sizeof(struct cas_init_block), |
@@ -5217,6 +5256,9 @@ static void __devexit cas_remove_one(struct pci_dev *pdev) | |||
5217 | cp = netdev_priv(dev); | 5256 | cp = netdev_priv(dev); |
5218 | unregister_netdev(dev); | 5257 | unregister_netdev(dev); |
5219 | 5258 | ||
5259 | if (cp->fw_data) | ||
5260 | vfree(cp->fw_data); | ||
5261 | |||
5220 | mutex_lock(&cp->pm_mutex); | 5262 | mutex_lock(&cp->pm_mutex); |
5221 | flush_scheduled_work(); | 5263 | flush_scheduled_work(); |
5222 | if (cp->hw_running) | 5264 | if (cp->hw_running) |