1 | #include <stdint.h> |
---|
2 | #include <stdio.h> |
---|
3 | #include <errno.h> |
---|
4 | #include <gpxe/if_ether.h> |
---|
5 | #include <gpxe/netdevice.h> |
---|
6 | #include <gpxe/ethernet.h> |
---|
7 | #include <gpxe/iobuf.h> |
---|
8 | #include <nic.h> |
---|
9 | |
---|
10 | /* |
---|
11 | * Quick and dirty compatibility layer |
---|
12 | * |
---|
13 | * This should allow old-API PCI drivers to at least function until |
---|
14 | * they are updated. It will not help non-PCI drivers. |
---|
15 | * |
---|
16 | * No drivers should rely on this code. It will be removed asap. |
---|
17 | * |
---|
18 | */ |
---|
19 | |
---|
20 | FILE_LICENCE ( GPL2_OR_LATER ); |
---|
21 | |
---|
22 | struct nic nic; |
---|
23 | |
---|
24 | static int legacy_registered = 0; |
---|
25 | |
---|
26 | static int legacy_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { |
---|
27 | struct nic *nic = netdev->priv; |
---|
28 | struct ethhdr *ethhdr; |
---|
29 | |
---|
30 | DBG ( "Transmitting %zd bytes\n", iob_len ( iobuf ) ); |
---|
31 | iob_pad ( iobuf, ETH_ZLEN ); |
---|
32 | ethhdr = iobuf->data; |
---|
33 | iob_pull ( iobuf, sizeof ( *ethhdr ) ); |
---|
34 | nic->nic_op->transmit ( nic, ( const char * ) ethhdr->h_dest, |
---|
35 | ntohs ( ethhdr->h_protocol ), |
---|
36 | iob_len ( iobuf ), iobuf->data ); |
---|
37 | netdev_tx_complete ( netdev, iobuf ); |
---|
38 | return 0; |
---|
39 | } |
---|
40 | |
---|
41 | static void legacy_poll ( struct net_device *netdev ) { |
---|
42 | struct nic *nic = netdev->priv; |
---|
43 | struct io_buffer *iobuf; |
---|
44 | |
---|
45 | iobuf = alloc_iob ( ETH_FRAME_LEN ); |
---|
46 | if ( ! iobuf ) |
---|
47 | return; |
---|
48 | |
---|
49 | nic->packet = iobuf->data; |
---|
50 | if ( nic->nic_op->poll ( nic, 1 ) ) { |
---|
51 | DBG ( "Received %d bytes\n", nic->packetlen ); |
---|
52 | iob_put ( iobuf, nic->packetlen ); |
---|
53 | netdev_rx ( netdev, iobuf ); |
---|
54 | } else { |
---|
55 | free_iob ( iobuf ); |
---|
56 | } |
---|
57 | } |
---|
58 | |
---|
59 | static int legacy_open ( struct net_device *netdev __unused ) { |
---|
60 | /* Nothing to do */ |
---|
61 | return 0; |
---|
62 | } |
---|
63 | |
---|
64 | static void legacy_close ( struct net_device *netdev __unused ) { |
---|
65 | /* Nothing to do */ |
---|
66 | } |
---|
67 | |
---|
68 | static void legacy_irq ( struct net_device *netdev __unused, int enable ) { |
---|
69 | struct nic *nic = netdev->priv; |
---|
70 | |
---|
71 | nic->nic_op->irq ( nic, ( enable ? ENABLE : DISABLE ) ); |
---|
72 | } |
---|
73 | |
---|
74 | static struct net_device_operations legacy_operations = { |
---|
75 | .open = legacy_open, |
---|
76 | .close = legacy_close, |
---|
77 | .transmit = legacy_transmit, |
---|
78 | .poll = legacy_poll, |
---|
79 | .irq = legacy_irq, |
---|
80 | }; |
---|
81 | |
---|
82 | int legacy_probe ( void *hwdev, |
---|
83 | void ( * set_drvdata ) ( void *hwdev, void *priv ), |
---|
84 | struct device *dev, |
---|
85 | int ( * probe ) ( struct nic *nic, void *hwdev ), |
---|
86 | void ( * disable ) ( struct nic *nic, void *hwdev ) ) { |
---|
87 | struct net_device *netdev; |
---|
88 | int rc; |
---|
89 | |
---|
90 | if ( legacy_registered ) |
---|
91 | return -EBUSY; |
---|
92 | |
---|
93 | netdev = alloc_etherdev ( 0 ); |
---|
94 | if ( ! netdev ) |
---|
95 | return -ENOMEM; |
---|
96 | netdev_init ( netdev, &legacy_operations ); |
---|
97 | netdev->priv = &nic; |
---|
98 | memset ( &nic, 0, sizeof ( nic ) ); |
---|
99 | set_drvdata ( hwdev, netdev ); |
---|
100 | netdev->dev = dev; |
---|
101 | |
---|
102 | nic.node_addr = netdev->hw_addr; |
---|
103 | nic.irqno = dev->desc.irq; |
---|
104 | |
---|
105 | if ( ! probe ( &nic, hwdev ) ) { |
---|
106 | rc = -ENODEV; |
---|
107 | goto err_probe; |
---|
108 | } |
---|
109 | |
---|
110 | /* Overwrite the IRQ number. Some legacy devices set |
---|
111 | * nic->irqno to 0 in the probe routine to indicate that they |
---|
112 | * don't support interrupts; doing this allows the timer |
---|
113 | * interrupt to be used instead. |
---|
114 | */ |
---|
115 | dev->desc.irq = nic.irqno; |
---|
116 | |
---|
117 | /* Mark as link up; legacy devices don't handle link state */ |
---|
118 | netdev_link_up ( netdev ); |
---|
119 | |
---|
120 | if ( ( rc = register_netdev ( netdev ) ) != 0 ) |
---|
121 | goto err_register; |
---|
122 | |
---|
123 | /* Do not remove this message */ |
---|
124 | printf ( "WARNING: Using legacy NIC wrapper on %s\n", |
---|
125 | netdev->ll_protocol->ntoa ( nic.node_addr ) ); |
---|
126 | |
---|
127 | legacy_registered = 1; |
---|
128 | return 0; |
---|
129 | |
---|
130 | err_register: |
---|
131 | disable ( &nic, hwdev ); |
---|
132 | err_probe: |
---|
133 | netdev_nullify ( netdev ); |
---|
134 | netdev_put ( netdev ); |
---|
135 | return rc; |
---|
136 | } |
---|
137 | |
---|
138 | void legacy_remove ( void *hwdev, |
---|
139 | void * ( * get_drvdata ) ( void *hwdev ), |
---|
140 | void ( * disable ) ( struct nic *nic, void *hwdev ) ) { |
---|
141 | struct net_device *netdev = get_drvdata ( hwdev ); |
---|
142 | struct nic *nic = netdev->priv; |
---|
143 | |
---|
144 | unregister_netdev ( netdev ); |
---|
145 | disable ( nic, hwdev ); |
---|
146 | netdev_nullify ( netdev ); |
---|
147 | netdev_put ( netdev ); |
---|
148 | legacy_registered = 0; |
---|
149 | } |
---|
150 | |
---|
151 | int dummy_connect ( struct nic *nic __unused ) { |
---|
152 | return 1; |
---|
153 | } |
---|
154 | |
---|
155 | void dummy_irq ( struct nic *nic __unused, irq_action_t irq_action __unused ) { |
---|
156 | return; |
---|
157 | } |
---|